]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
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 e8bbd4d80161d5b96b2c47030c6a6e1e1740e2f8..cb59b69d2af14359b3486b159c33fb4e7d4fa8e0 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 012c96de47012e9cb52dbca1da49b3d0c6926239..f93d2695e423b04ca626c47d2f2ba24a620837f5 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 0163ca637a96fa5af2b42e541946dae67cb9b4d3..4f21daa3dbc7b306804d49a021e0fcae4f749b3e 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 23777021b331617fba3e5dddf182c9cb4d35590e..ca69fb35a2ccb0723ef1af8d7df7c276c6557234 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 7e76d5e917867c84fa96ddfecaa66a827137ba08..78867a0844286881546b7ab3a96ba09f7a3e95b4 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 aab7d30eed55eeb86ca30905b3d1aa4639c58911..1a2350fd68bebd73c96743b0714548c5326276eb 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 0ebca9dba5ab5dcf6c74323fb433d855538c848b..2ece3a030a66df069ca332bf7fae5601f155be1b 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 11cafc520b47bf8b17d0f3e8eca990ae558da4b7..1c2d418dda6a58ae6e3d22a1bc37c68e464a15c2 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 7002cc3315daf71902592916fff97b830c806c5a..a5e56a678af28862233ba4e0888089d3a9050408 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 4809272f50632f163d127e04650573cfb69b5cc1..29895ffa470dae98a88fb1725e7c758b0758d167 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