bcachefs: Casefold is now a regular opts.h option
authorKent Overstreet <kent.overstreet@linux.dev>
Sun, 20 Apr 2025 16:15:15 +0000 (12:15 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 24 Apr 2025 23:09:00 +0000 (19:09 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bcachefs_format.h
fs/bcachefs/fs.c
fs/bcachefs/inode.h
fs/bcachefs/inode_format.h
fs/bcachefs/namei.c
fs/bcachefs/opts.h
fs/bcachefs/str_hash.h

index 377f04d92a1443ffc67b8334315c929a360c49ff..d6e4a496f02b64a950b6de4188faa98691fb25c6 100644 (file)
@@ -867,6 +867,7 @@ LE64_BITMASK(BCH_SB_VERSION_INCOMPAT_ALLOWED,
 LE64_BITMASK(BCH_SB_SHARD_INUMS_NBITS, struct bch_sb, flags[6],  0,  4);
 LE64_BITMASK(BCH_SB_WRITE_ERROR_TIMEOUT,struct bch_sb, flags[6],  4, 14);
 LE64_BITMASK(BCH_SB_CSUM_ERR_RETRY_NR, struct bch_sb, flags[6], 14, 20);
+LE64_BITMASK(BCH_SB_CASEFOLD,          struct bch_sb, flags[6], 22, 23);
 
 static inline __u64 BCH_SB_COMPRESSION_TYPE(const struct bch_sb *sb)
 {
index e220e3cba29c7355c2bb05cb3da5066f1bcd380a..7c1943c83bf6e95ce1411efc045fdfe2fee507ce 100644 (file)
@@ -53,16 +53,19 @@ static void bch2_vfs_inode_init(struct btree_trans *, subvol_inum,
                                struct bch_subvolume *);
 
 /* Set VFS inode flags from bcachefs inode: */
-static inline void bch2_inode_flags_to_vfs(struct bch_inode_info *inode)
+static inline void bch2_inode_flags_to_vfs(struct bch_fs *c, struct bch_inode_info *inode)
 {
        static const __maybe_unused unsigned bch_flags_to_vfs[] = {
                [__BCH_INODE_sync]              = S_SYNC,
                [__BCH_INODE_immutable]         = S_IMMUTABLE,
                [__BCH_INODE_append]            = S_APPEND,
                [__BCH_INODE_noatime]           = S_NOATIME,
-               [__BCH_INODE_casefolded]        = S_CASEFOLD,
        };
+
        set_flags(bch_flags_to_vfs, inode->ei_inode.bi_flags, inode->v.i_flags);
+
+       if (bch2_inode_casefold(c, &inode->ei_inode))
+               inode->v.i_flags |= S_CASEFOLD;
 }
 
 void bch2_inode_update_after_write(struct btree_trans *trans,
@@ -93,7 +96,7 @@ void bch2_inode_update_after_write(struct btree_trans *trans,
 
        inode->ei_inode         = *bi;
 
-       bch2_inode_flags_to_vfs(inode);
+       bch2_inode_flags_to_vfs(c, inode);
 }
 
 int __must_check bch2_write_inode(struct bch_fs *c,
@@ -1470,7 +1473,6 @@ static const __maybe_unused unsigned bch_flags_to_uflags[] = {
        [__BCH_INODE_append]            = FS_APPEND_FL,
        [__BCH_INODE_nodump]            = FS_NODUMP_FL,
        [__BCH_INODE_noatime]           = FS_NOATIME_FL,
-       [__BCH_INODE_casefolded]        = FS_CASEFOLD_FL,
 };
 
 /* bcachefs inode flags -> FS_IOC_FSGETXATTR: */
@@ -1486,13 +1488,14 @@ static int bch2_fileattr_get(struct dentry *dentry,
                             struct fileattr *fa)
 {
        struct bch_inode_info *inode = to_bch_ei(d_inode(dentry));
+       struct bch_fs *c = inode->v.i_sb->s_fs_info;
 
        fileattr_fill_xflags(fa, map_flags(bch_flags_to_xflags, inode->ei_inode.bi_flags));
 
        if (inode->ei_inode.bi_fields_set & (1 << Inode_opt_project))
                fa->fsx_xflags |= FS_XFLAG_PROJINHERIT;
 
-       if (inode->ei_inode.bi_flags & BCH_INODE_casefolded)
+       if (bch2_inode_casefold(c, &inode->ei_inode))
                fa->flags |= FS_CASEFOLD_FL;
 
        fa->fsx_projid = inode->ei_qid.q[QTYP_PRJ];
@@ -1504,6 +1507,8 @@ struct flags_set {
        unsigned                flags;
        unsigned                projid;
        bool                    set_project;
+       bool                    set_casefold;
+       bool                    casefold;
 };
 
 static int fssetxattr_inode_update_fn(struct btree_trans *trans,
@@ -1518,15 +1523,12 @@ static int fssetxattr_inode_update_fn(struct btree_trans *trans,
         * We're relying on btree locking here for exclusion with other ioctl
         * calls - use the flags in the btree (@bi), not inode->i_flags:
         */
-       unsigned newflags = s->flags;
-       unsigned oldflags = bi->bi_flags & s->mask;
-
        if (!S_ISREG(bi->bi_mode) &&
            !S_ISDIR(bi->bi_mode) &&
-           (newflags & (BCH_INODE_nodump|BCH_INODE_noatime)) != newflags)
+           (s->flags & (BCH_INODE_nodump|BCH_INODE_noatime)) != s->flags)
                return -EINVAL;
 
-       if ((newflags ^ oldflags) & BCH_INODE_casefolded) {
+       if (s->casefold != bch2_inode_casefold(c, bi)) {
 #ifdef CONFIG_UNICODE
                int ret = 0;
                /* Not supported on individual files. */
@@ -1546,6 +1548,10 @@ static int fssetxattr_inode_update_fn(struct btree_trans *trans,
                        return ret;
 
                bch2_check_set_feature(c, BCH_FEATURE_casefolding);
+
+               bi->bi_casefold = s->casefold + 1;
+               bi->bi_fields_set |= BIT(Inode_opt_casefold);
+
 #else
                printk(KERN_ERR "Cannot use casefolding on a kernel without CONFIG_UNICODE\n");
                return -EOPNOTSUPP;
@@ -1558,7 +1564,7 @@ static int fssetxattr_inode_update_fn(struct btree_trans *trans,
        }
 
        bi->bi_flags &= ~s->mask;
-       bi->bi_flags |= newflags;
+       bi->bi_flags |= s->flags;
 
        bi->bi_ctime = timespec_to_bch2_time(c, current_time(&inode->v));
        return 0;
@@ -1598,6 +1604,11 @@ static int bch2_fileattr_set(struct mnt_idmap *idmap,
 
        if (fa->flags_valid) {
                s.mask = map_defined(bch_flags_to_uflags);
+
+               s.set_casefold = true;
+               s.casefold = (fa->flags & FS_CASEFOLD_FL) != 0;
+               fa->flags &= ~FS_CASEFOLD_FL;
+
                s.flags |= map_flags_rev(bch_flags_to_uflags, fa->flags);
                if (fa->flags)
                        return -EOPNOTSUPP;
index f82cfbf460d094c0557e16589410ab62bac5fd4c..c74af15b14f2817a5b98c264950c0ae9e02dda60 100644 (file)
@@ -243,6 +243,14 @@ static inline unsigned bkey_inode_mode(struct bkey_s_c k)
        }
 }
 
+static inline bool bch2_inode_casefold(struct bch_fs *c, const struct bch_inode_unpacked *bi)
+{
+       /* inode apts are stored with a +1 bias: 0 means "unset, use fs opt" */
+       return bi->bi_casefold
+               ? bi->bi_casefold - 1
+               : c->opts.casefold;
+}
+
 /* i_nlink: */
 
 static inline unsigned nlink_bias(umode_t mode)
index 117110af1e3f2a71963bc3e8b754f05d425d23da..87e193e8ed25430d9b5a71a742cf26f7a52d1ba0 100644 (file)
@@ -103,7 +103,8 @@ struct bch_inode_generation {
        x(bi_parent_subvol,             32)     \
        x(bi_nocow,                     8)      \
        x(bi_depth,                     32)     \
-       x(bi_inodes_32bit,              8)
+       x(bi_inodes_32bit,              8)      \
+       x(bi_casefold,                  8)
 
 /* subset of BCH_INODE_FIELDS */
 #define BCH_INODE_OPTS()                       \
@@ -117,7 +118,8 @@ struct bch_inode_generation {
        x(background_target,            16)     \
        x(erasure_code,                 16)     \
        x(nocow,                        8)      \
-       x(inodes_32bit,                 8)
+       x(inodes_32bit,                 8)      \
+       x(casefold,                     8)
 
 enum inode_opt_id {
 #define x(name, ...)                           \
@@ -137,8 +139,7 @@ enum inode_opt_id {
        x(i_sectors_dirty,              6)      \
        x(unlinked,                     7)      \
        x(backptr_untrusted,            8)      \
-       x(has_child_snapshot,           9)      \
-       x(casefolded,                   10)
+       x(has_child_snapshot,           9)
 
 /* bits 20+ reserved for packed fields below: */
 
index 0d65ea96f7a297d93691c1fcf96e0ff9e2dd0b06..46f3c8b100a9529a89cc26b7689bc0328092a0a5 100644 (file)
@@ -47,10 +47,6 @@ int bch2_create_trans(struct btree_trans *trans,
        if (ret)
                goto err;
 
-       /* Inherit casefold state from parent. */
-       if (S_ISDIR(mode))
-               new_inode->bi_flags |= dir_u->bi_flags & BCH_INODE_casefolded;
-
        if (!(flags & BCH_CREATE_SNAPSHOT)) {
                /* Normal create path - allocate a new inode: */
                bch2_inode_init_late(new_inode, now, uid, gid, mode, rdev, dir_u);
index 4d06313076ff659b32f481f47aaa3a3188ab5294..dfb14810124c7c3e94c55288259816b6e5b35100 100644 (file)
@@ -228,6 +228,11 @@ enum fsck_err_opts {
          OPT_BOOL(),                                                   \
          BCH_SB_ERASURE_CODE,          false,                          \
          NULL,         "Enable erasure coding (DO NOT USE YET)")       \
+       x(casefold,                     u8,                             \
+         OPT_FS|OPT_INODE|OPT_FORMAT,                                  \
+         OPT_BOOL(),                                                   \
+         BCH_SB_CASEFOLD,              false,                          \
+         NULL,         "Dirent lookups are casefolded")                \
        x(inodes_32bit,                 u8,                             \
          OPT_FS|OPT_INODE|OPT_FORMAT|OPT_MOUNT|OPT_RUNTIME,            \
          OPT_BOOL(),                                                   \
index 09a354a26c3bd06b3acfe7b3bb7a512b7c78d1b7..0c1a00539bd14ac7b2ef384dafdb131c1e4c4dcd 100644 (file)
@@ -33,7 +33,7 @@ bch2_str_hash_opt_to_type(struct bch_fs *c, enum bch_str_hash_opts opt)
 
 struct bch_hash_info {
        u8                      type;
-       struct unicode_map      *cf_encoding;
+       struct unicode_map      *cf_encoding;
        /*
         * For crc32 or crc64 string hashes the first key value of
         * the siphash_key (k0) is used as the key.
@@ -44,11 +44,10 @@ struct bch_hash_info {
 static inline struct bch_hash_info
 bch2_hash_info_init(struct bch_fs *c, const struct bch_inode_unpacked *bi)
 {
-       /* XXX ick */
        struct bch_hash_info info = {
                .type = INODE_STR_HASH(bi),
 #ifdef CONFIG_UNICODE
-               .cf_encoding = !!(bi->bi_flags & BCH_INODE_casefolded) ? c->cf_encoding : NULL,
+               .cf_encoding = bch2_inode_casefold(c, bi) ? c->cf_encoding : NULL,
 #endif
                .siphash_key = { .k0 = bi->bi_hash_seed }
        };