Sweet Tea Dorminy <sweettea-kernel@xxxxxxxxxx> writes: > From: Omar Sandoval <osandov@xxxxxxxxxxx> > @@ -5793,13 +5787,18 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) > struct btrfs_root *root = BTRFS_I(dir)->root; > struct btrfs_root *sub_root = root; > struct btrfs_key location; > + struct fscrypt_name fname; > u8 di_type = 0; > int ret = 0; > > if (dentry->d_name.len > BTRFS_NAME_LEN) > return ERR_PTR(-ENAMETOOLONG); > > - ret = btrfs_inode_by_name(BTRFS_I(dir), dentry, &location, &di_type); > + ret = fscrypt_prepare_lookup(dir, dentry, &fname); > + if (ret) > + return ERR_PTR(ret); > + I _think_ these error paths below need to be changed in order to invoke fscrypt_free_lookup(). Cheers, -- Luís > > + ret = btrfs_inode_by_name(BTRFS_I(dir), &fname, &location, &di_type); > if (ret < 0) > return ERR_PTR(ret); > > @@ -5940,18 +5939,32 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx) > struct list_head del_list; > int ret; > char *name_ptr; > - int name_len; > + u32 name_len; > int entries = 0; > int total_len = 0; > bool put = false; > struct btrfs_key location; > + struct fscrypt_str fstr = FSTR_INIT(NULL, 0); > + u32 fstr_len = 0; > > if (!dir_emit_dots(file, ctx)) > return 0; > > + if (BTRFS_I(inode)->flags & BTRFS_INODE_ENCRYPT) { > + ret = fscrypt_prepare_readdir(inode); > + if (ret) > + return ret; > + ret = fscrypt_fname_alloc_buffer(BTRFS_NAME_LEN, &fstr); > + if (ret) > + return ret; > + fstr_len = fstr.len; > + } > + > path = btrfs_alloc_path(); > - if (!path) > - return -ENOMEM; > + if (!path) { > + ret = -ENOMEM; > + goto err_fstr; > + } > > addr = private->filldir_buf; > path->reada = READA_FORWARD; > @@ -5969,6 +5982,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx) > struct dir_entry *entry; > struct extent_buffer *leaf = path->nodes[0]; > u8 ftype; > + u32 nokey_len; > > if (found_key.objectid != key.objectid) > break; > @@ -5980,8 +5994,13 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx) > continue; > di = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); > name_len = btrfs_dir_name_len(leaf, di); > - if ((total_len + sizeof(struct dir_entry) + name_len) >= > - PAGE_SIZE) { > + nokey_len = DIV_ROUND_UP(name_len * 4, 3); > + /* > + * If name is encrypted, and we don't have the key, we could > + * need up to 4/3rds the bytes to print it. > + */ > + if ((total_len + sizeof(struct dir_entry) + nokey_len) > + >= PAGE_SIZE) { > btrfs_release_path(path); > ret = btrfs_filldir(private->filldir_buf, entries, ctx); > if (ret) > @@ -5995,8 +6014,36 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx) > ftype = btrfs_dir_flags_to_ftype(btrfs_dir_flags(leaf, di)); > entry = addr; > name_ptr = (char *)(entry + 1); > - read_extent_buffer(leaf, name_ptr, > - (unsigned long)(di + 1), name_len); > + if (btrfs_dir_flags(leaf, di) & BTRFS_FT_ENCRYPTED) { > + struct fscrypt_str oname = FSTR_INIT(name_ptr, > + nokey_len); > + u32 hash = 0, minor_hash = 0; > + > + read_extent_buffer(leaf, fstr.name, > + (unsigned long)(di + 1), name_len); > + fstr.len = name_len; > + /* > + * We're iterating through DIR_INDEX items, so we don't > + * have the DIR_ITEM hash handy. Only compute it if > + * we'll need it -- the nokey name stores it, so that > + * we can look up the appropriate item by nokey name > + * later on. > + */ > + if (!fscrypt_has_encryption_key(inode)) { > + u64 name_hash = btrfs_name_hash(fstr.name, > + fstr.len); > + hash = name_hash; > + minor_hash = name_hash >> 32; > + } > + ret = fscrypt_fname_disk_to_usr(inode, hash, minor_hash, > + &fstr, &oname); > + if (ret) > + goto err; > + name_len = oname.len; > + } else { > + 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); > @@ -6016,7 +6063,8 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx) > if (ret) > goto nopos; > > - ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list); > + fstr.len = fstr_len; > + ret = btrfs_readdir_delayed_dir_index(inode, &fstr, ctx, &ins_list); > if (ret) > goto nopos; > > @@ -6047,6 +6095,8 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx) > if (put) > btrfs_readdir_put_delayed_items(inode, &ins_list, &del_list); > btrfs_free_path(path); > +err_fstr: > + fscrypt_fname_free_buffer(&fstr); > return ret; > } > > @@ -6555,6 +6605,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, > struct btrfs_root *root = parent_inode->root; > u64 ino = btrfs_ino(inode); > u64 parent_ino = btrfs_ino(parent_inode); > + struct fscrypt_name fname = { .disk_name = *name }; > > if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) { > memcpy(&key, &inode->root->root_key, sizeof(key)); > @@ -6612,7 +6663,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, > int err; > err = btrfs_del_root_ref(trans, key.objectid, > root->root_key.objectid, parent_ino, > - &local_index, name); > + &local_index, &fname); > if (err) > btrfs_abort_transaction(trans, err); > } else if (add_backref) { > @@ -8982,7 +9033,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, > } else { /* src is an inode */ > ret = __btrfs_unlink_inode(trans, BTRFS_I(old_dir), > BTRFS_I(old_dentry->d_inode), > - old_name, &old_rename_ctx); > + &old_fname, &old_rename_ctx); > if (!ret) > ret = btrfs_update_inode(trans, root, BTRFS_I(old_inode)); > } > @@ -8997,7 +9048,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, > } else { /* dest is an inode */ > ret = __btrfs_unlink_inode(trans, BTRFS_I(new_dir), > BTRFS_I(new_dentry->d_inode), > - new_name, &new_rename_ctx); > + &new_fname, &new_rename_ctx); > if (!ret) > ret = btrfs_update_inode(trans, dest, BTRFS_I(new_inode)); > } > @@ -9246,7 +9297,7 @@ static int btrfs_rename(struct mnt_idmap *idmap, > } else { > ret = __btrfs_unlink_inode(trans, BTRFS_I(old_dir), > BTRFS_I(d_inode(old_dentry)), > - &old_fname.disk_name, &rename_ctx); > + &old_fname, &rename_ctx); > if (!ret) > ret = btrfs_update_inode(trans, root, BTRFS_I(old_inode)); > } > @@ -9265,7 +9316,7 @@ static int btrfs_rename(struct mnt_idmap *idmap, > } else { > ret = btrfs_unlink_inode(trans, BTRFS_I(new_dir), > BTRFS_I(d_inode(new_dentry)), > - &new_fname.disk_name); > + &new_fname); > } > if (!ret && new_inode->i_nlink == 0) > ret = btrfs_orphan_add(trans, > diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c > index 859874579456..5fa416ef54ad 100644 > --- a/fs/btrfs/root-tree.c > +++ b/fs/btrfs/root-tree.c > @@ -10,6 +10,7 @@ > #include "messages.h" > #include "transaction.h" > #include "disk-io.h" > +#include "fscrypt.h" > #include "print-tree.h" > #include "qgroup.h" > #include "space-info.h" > @@ -333,7 +334,7 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, > > int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id, > u64 ref_id, u64 dirid, u64 *sequence, > - const struct fscrypt_str *name) > + struct fscrypt_name *name) > { > struct btrfs_root *tree_root = trans->fs_info->tree_root; > struct btrfs_path *path; > @@ -355,13 +356,14 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id, > if (ret < 0) { > goto out; > } else if (ret == 0) { > + u32 name_len; > leaf = path->nodes[0]; > ref = btrfs_item_ptr(leaf, path->slots[0], > struct btrfs_root_ref); > ptr = (unsigned long)(ref + 1); > + name_len = btrfs_root_ref_name_len(leaf, ref); > if ((btrfs_root_ref_dirid(leaf, ref) != dirid) || > - (btrfs_root_ref_name_len(leaf, ref) != name->len) || > - memcmp_extent_buffer(leaf, name->name, ptr, name->len)) { > + !btrfs_fscrypt_match_name(name, leaf, ptr, name_len)) { > ret = -ENOENT; > goto out; > } > diff --git a/fs/btrfs/root-tree.h b/fs/btrfs/root-tree.h > index cbbaca32126e..a57bbf7b0180 100644 > --- a/fs/btrfs/root-tree.h > +++ b/fs/btrfs/root-tree.h > @@ -13,7 +13,7 @@ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id, > const struct fscrypt_str *name); > int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id, > u64 ref_id, u64 dirid, u64 *sequence, > - const struct fscrypt_str *name); > + struct fscrypt_name *name); > int btrfs_del_root(struct btrfs_trans_handle *trans, const struct btrfs_key *key); > int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, > const struct btrfs_key *key, > diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c > index 8ad7e7e38d18..3bf746668e07 100644 > --- a/fs/btrfs/tree-log.c > +++ b/fs/btrfs/tree-log.c > @@ -901,9 +901,10 @@ static int unlink_inode_for_log_replay(struct btrfs_trans_handle *trans, > struct btrfs_inode *inode, > const struct fscrypt_str *name) > { > + struct fscrypt_name fname = { .disk_name = *name, }; > int ret; > > - ret = btrfs_unlink_inode(trans, dir, inode, name); > + ret = btrfs_unlink_inode(trans, dir, inode, &fname); > if (ret) > return ret; > /* > -- > > 2.40.1 >
![]() |