OSDN Git Service

btrfs: extend btrfs_dir_item type to store encryption status
authorOmar Sandoval <osandov@osandov.com>
Thu, 20 Oct 2022 16:58:28 +0000 (12:58 -0400)
committerDavid Sterba <dsterba@suse.com>
Mon, 5 Dec 2022 17:00:43 +0000 (18:00 +0100)
For directories with encrypted files/filenames, we need to store a flag
indicating this fact. There's no room in other fields, so we'll need to
borrow a bit from dir_type. Since it's now a combination of type and
flags, we rename it to dir_flags to reflect its new usage.

The new flag, FT_ENCRYPTED, indicates a directory containing encrypted
data, which is orthogonal to file type; therefore, add the new
flag, and make conversion from directory type to file type strip the
flag.

As the file types almost never change we can afford to use the bits.
Actual usage will be guarded behind an incompat bit, this patch only
adds the support for later use by fscrypt.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/accessors.h
fs/btrfs/delayed-inode.c
fs/btrfs/delayed-inode.h
fs/btrfs/dir-item.c
fs/btrfs/inode.c
fs/btrfs/print-tree.c
fs/btrfs/send.c
fs/btrfs/tree-checker.c
fs/btrfs/tree-log.c
include/uapi/linux/btrfs_tree.h

index e8bbd4d..cb59b69 100644 (file)
@@ -484,14 +484,25 @@ BTRFS_SETGET_FUNCS(root_ref_name_len, struct btrfs_root_ref, name_len, 16);
 
 /* struct btrfs_dir_item */
 BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
-BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
+BTRFS_SETGET_FUNCS(dir_flags, struct btrfs_dir_item, type, 8);
 BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
 BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_dir_type, struct btrfs_dir_item, type, 8);
+BTRFS_SETGET_STACK_FUNCS(stack_dir_flags, struct btrfs_dir_item, type, 8);
 BTRFS_SETGET_STACK_FUNCS(stack_dir_data_len, struct btrfs_dir_item, data_len, 16);
 BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item, name_len, 16);
 BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item, transid, 64);
 
+static inline u8 btrfs_dir_ftype(const struct extent_buffer *eb,
+                                const struct btrfs_dir_item *item)
+{
+       return btrfs_dir_flags_to_ftype(btrfs_dir_flags(eb, item));
+}
+
+static inline u8 btrfs_stack_dir_ftype(const struct btrfs_dir_item *item)
+{
+       return btrfs_dir_flags_to_ftype(btrfs_stack_dir_flags(item));
+}
+
 static inline void btrfs_dir_item_key(const struct extent_buffer *eb,
                                      const struct btrfs_dir_item *item,
                                      struct btrfs_disk_key *key)
index 012c96d..f93d269 100644 (file)
@@ -1416,7 +1416,7 @@ void btrfs_balance_delayed_items(struct btrfs_fs_info *fs_info)
 int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
                                   const char *name, int name_len,
                                   struct btrfs_inode *dir,
-                                  struct btrfs_disk_key *disk_key, u8 type,
+                                  struct btrfs_disk_key *disk_key, u8 flags,
                                   u64 index)
 {
        struct btrfs_fs_info *fs_info = trans->fs_info;
@@ -1447,7 +1447,7 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
        btrfs_set_stack_dir_transid(dir_item, trans->transid);
        btrfs_set_stack_dir_data_len(dir_item, 0);
        btrfs_set_stack_dir_name_len(dir_item, name_len);
-       btrfs_set_stack_dir_type(dir_item, type);
+       btrfs_set_stack_dir_flags(dir_item, flags);
        memcpy((char *)(dir_item + 1), name, name_len);
 
        data_len = delayed_item->data_len + sizeof(struct btrfs_item);
@@ -1757,7 +1757,7 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
                name = (char *)(di + 1);
                name_len = btrfs_stack_dir_name_len(di);
 
-               d_type = fs_ftype_to_dtype(di->type);
+               d_type = fs_ftype_to_dtype(btrfs_dir_flags_to_ftype(di->type));
                btrfs_disk_key_to_cpu(&location, &di->location);
 
                over = !dir_emit(ctx, name, name_len,
index 0163ca6..4f21daa 100644 (file)
@@ -113,7 +113,7 @@ static inline void btrfs_init_delayed_root(
 int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
                                   const char *name, int name_len,
                                   struct btrfs_inode *dir,
-                                  struct btrfs_disk_key *disk_key, u8 type,
+                                  struct btrfs_disk_key *disk_key, u8 flags,
                                   u64 index);
 
 int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
index 2377702..ca69fb3 100644 (file)
@@ -83,7 +83,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
        leaf = path->nodes[0];
        btrfs_cpu_key_to_disk(&disk_key, &location);
        btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
-       btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
+       btrfs_set_dir_flags(leaf, dir_item, BTRFS_FT_XATTR);
        btrfs_set_dir_name_len(leaf, dir_item, name_len);
        btrfs_set_dir_transid(leaf, dir_item, trans->transid);
        btrfs_set_dir_data_len(leaf, dir_item, data_len);
@@ -140,9 +140,12 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
                goto out_free;
        }
 
+       if (IS_ENCRYPTED(&dir->vfs_inode))
+               type |= BTRFS_FT_ENCRYPTED;
+
        leaf = path->nodes[0];
        btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
-       btrfs_set_dir_type(leaf, dir_item, type);
+       btrfs_set_dir_flags(leaf, dir_item, type);
        btrfs_set_dir_data_len(leaf, dir_item, 0);
        btrfs_set_dir_name_len(leaf, dir_item, name->len);
        btrfs_set_dir_transid(leaf, dir_item, trans->transid);
index 7e76d5e..78867a0 100644 (file)
@@ -5597,7 +5597,7 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
                           location->objectid, location->type, location->offset);
        }
        if (!ret)
-               *type = btrfs_dir_type(path->nodes[0], di);
+               *type = btrfs_dir_ftype(path->nodes[0], di);
 out:
        fscrypt_free_filename(&fname);
        btrfs_free_path(path);
@@ -6046,6 +6046,7 @@ again:
        btrfs_for_each_slot(root, &key, &found_key, path, ret) {
                struct dir_entry *entry;
                struct extent_buffer *leaf = path->nodes[0];
+               u8 ftype;
 
                if (found_key.objectid != key.objectid)
                        break;
@@ -6069,13 +6070,13 @@ again:
                        goto again;
                }
 
+               ftype = btrfs_dir_flags_to_ftype(btrfs_dir_flags(leaf, di));
                entry = addr;
-               put_unaligned(name_len, &entry->name_len);
                name_ptr = (char *)(entry + 1);
-               read_extent_buffer(leaf, name_ptr, (unsigned long)(di + 1),
-                                  name_len);
-               put_unaligned(fs_ftype_to_dtype(btrfs_dir_type(leaf, di)),
-                               &entry->type);
+               read_extent_buffer(leaf, name_ptr,
+                                  (unsigned long)(di + 1), name_len);
+               put_unaligned(name_len, &entry->name_len);
+               put_unaligned(fs_ftype_to_dtype(ftype), &entry->type);
                btrfs_dir_item_key_to_cpu(leaf, di, &location);
                put_unaligned(location.objectid, &entry->ino);
                put_unaligned(found_key.offset, &entry->offset);
index aab7d30..1a2350f 100644 (file)
@@ -242,9 +242,9 @@ void btrfs_print_leaf(struct extent_buffer *l)
                case BTRFS_DIR_ITEM_KEY:
                        di = btrfs_item_ptr(l, i, struct btrfs_dir_item);
                        btrfs_dir_item_key_to_cpu(l, di, &found_key);
-                       pr_info("\t\tdir oid %llu type %u\n",
+                       pr_info("\t\tdir oid %llu flags %u\n",
                                found_key.objectid,
-                               btrfs_dir_type(l, di));
+                               btrfs_dir_flags(l, di));
                        break;
                case BTRFS_ROOT_ITEM_KEY:
                        ri = btrfs_item_ptr(l, i, struct btrfs_root_item);
index 0ebca9d..2ece3a0 100644 (file)
@@ -1094,7 +1094,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
                data_len = btrfs_dir_data_len(eb, di);
                btrfs_dir_item_key_to_cpu(eb, di, &di_key);
 
-               if (btrfs_dir_type(eb, di) == BTRFS_FT_XATTR) {
+               if (btrfs_dir_ftype(eb, di) == BTRFS_FT_XATTR) {
                        if (name_len > XATTR_NAME_MAX) {
                                ret = -ENAMETOOLONG;
                                goto out;
index 11cafc5..1c2d418 100644 (file)
@@ -531,7 +531,7 @@ static int check_dir_item(struct extent_buffer *leaf,
                }
 
                /* dir type check */
-               dir_type = btrfs_dir_type(leaf, di);
+               dir_type = btrfs_dir_ftype(leaf, di);
                if (unlikely(dir_type >= BTRFS_FT_MAX)) {
                        dir_item_err(leaf, slot,
                        "invalid dir item type, have %u expect [0, %u)",
index 7002cc3..a5e56a6 100644 (file)
@@ -1799,7 +1799,7 @@ static int delete_conflicting_dir_entry(struct btrfs_trans_handle *trans,
                                        struct btrfs_path *path,
                                        struct btrfs_dir_item *dst_di,
                                        const struct btrfs_key *log_key,
-                                       u8 log_type,
+                                       u8 log_flags,
                                        bool exists)
 {
        struct btrfs_key found_key;
@@ -1809,7 +1809,7 @@ static int delete_conflicting_dir_entry(struct btrfs_trans_handle *trans,
        if (found_key.objectid == log_key->objectid &&
            found_key.type == log_key->type &&
            found_key.offset == log_key->offset &&
-           btrfs_dir_type(path->nodes[0], dst_di) == log_type)
+           btrfs_dir_flags(path->nodes[0], dst_di) == log_flags)
                return 1;
 
        /*
@@ -1853,7 +1853,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
        struct btrfs_key log_key;
        struct btrfs_key search_key;
        struct inode *dir;
-       u8 log_type;
+       u8 log_flags;
        bool exists;
        int ret;
        bool update_size = true;
@@ -1867,7 +1867,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
        if (ret)
                goto out;
 
-       log_type = btrfs_dir_type(eb, di);
+       log_flags = btrfs_dir_flags(eb, di);
        btrfs_dir_item_key_to_cpu(eb, di, &log_key);
        ret = btrfs_lookup_inode(trans, root, path, &log_key, 0);
        btrfs_release_path(path);
@@ -1883,8 +1883,8 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
                goto out;
        } else if (dir_dst_di) {
                ret = delete_conflicting_dir_entry(trans, BTRFS_I(dir), path,
-                                                  dir_dst_di, &log_key, log_type,
-                                                  exists);
+                                                  dir_dst_di, &log_key,
+                                                  log_flags, exists);
                if (ret < 0)
                        goto out;
                dir_dst_matches = (ret == 1);
@@ -1901,7 +1901,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
        } else if (index_dst_di) {
                ret = delete_conflicting_dir_entry(trans, BTRFS_I(dir), path,
                                                   index_dst_di, &log_key,
-                                                  log_type, exists);
+                                                  log_flags, exists);
                if (ret < 0)
                        goto out;
                index_dst_matches = (ret == 1);
@@ -2010,7 +2010,7 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans,
         * to ever delete the parent directory has it would result in stale
         * dentries that can never be deleted.
         */
-       if (ret == 1 && btrfs_dir_type(eb, di) != BTRFS_FT_DIR) {
+       if (ret == 1 && btrfs_dir_ftype(eb, di) != BTRFS_FT_DIR) {
                struct btrfs_path *fixup_path;
                struct btrfs_key di_key;
 
@@ -5452,7 +5452,7 @@ again:
                        }
 
                        di = btrfs_item_ptr(leaf, i, struct btrfs_dir_item);
-                       type = btrfs_dir_type(leaf, di);
+                       type = btrfs_dir_ftype(leaf, di);
                        if (btrfs_dir_transid(leaf, di) < trans->transid)
                                continue;
                        btrfs_dir_item_key_to_cpu(leaf, di, &di_key);
@@ -6292,7 +6292,7 @@ static int log_new_delayed_dentries(struct btrfs_trans_handle *trans,
                        continue;
                }
 
-               if (btrfs_stack_dir_type(dir_item) == BTRFS_FT_DIR)
+               if (btrfs_stack_dir_ftype(dir_item) == BTRFS_FT_DIR)
                        log_mode = LOG_INODE_ALL;
 
                ctx->log_new_dentries = false;
index 4809272..29895ff 100644 (file)
@@ -376,6 +376,13 @@ enum btrfs_csum_type {
 #define BTRFS_FT_SYMLINK       7
 #define BTRFS_FT_XATTR         8
 #define BTRFS_FT_MAX           9
+/* Directory contains encrypted data */
+#define BTRFS_FT_ENCRYPTED     0x80
+
+static inline __u8 btrfs_dir_flags_to_ftype(__u8 flags)
+{
+       return flags & ~BTRFS_FT_ENCRYPTED;
+}
 
 /*
  * Inode flags