From patchwork Sun Jul 24 00:53:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927392 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5F1D2C433EF for ; Sun, 24 Jul 2022 00:54:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239146AbiGXAyW (ORCPT ); Sat, 23 Jul 2022 20:54:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38394 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230417AbiGXAyU (ORCPT ); Sat, 23 Jul 2022 20:54:20 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 25D6C15824; Sat, 23 Jul 2022 17:54:19 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 8105B80BB8; Sat, 23 Jul 2022 20:54:18 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624058; bh=TpLOCkXHMouq9y78vW+mS1Z8y3byzWM3GN/g5tKzBuo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aE5T48/8RYWdzSCMs5iJhUkGL1JnCl/yHfXs/++qhd1+z6vi7LDjcVJEgkz9dGyJr XFreTu4mF2P9guBoI/6OR3eF3L7qdUUsiz+DQjr51XML3xwTLEMRyookxD7Dbdcqvz gV9S3ogLD5hWJsmozsTHHQ76U/XDIwnv1I6V7v4JNxaeyNAFANPDDj9fGxJCSRlpvu QSnty1gRdpEJ+3EydKYgoiAt6iGqPSWpdQd02sSGKpESfRKPJhqTIj49OjJUWlTsmP g+lEsvWWqb+YKsi47BrX2xHq5YEQz0XmzjUtTWeUccmJK0WIe59WQLgqSETE2BB7Vc twrbjR3QY2EaA== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 01/16] btrfs: store directorys' encryption state Date: Sat, 23 Jul 2022 20:53:46 -0400 Message-Id: <5415d42d58f1d922e94cf74e7707bf2291b899c6.1658623319.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval 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_FSCRYPT, indicates a (perhaps partially) encrypted directory, which is orthogonal to file type; therefore, add the new flag, and make conversion from directory type to file type strip the flag. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/ctree.h | 10 ++++++++-- fs/btrfs/delayed-inode.c | 6 +++--- fs/btrfs/delayed-inode.h | 2 +- fs/btrfs/dir-item.c | 4 ++-- fs/btrfs/inode.c | 15 +++++++++------ fs/btrfs/print-tree.c | 4 ++-- fs/btrfs/send.c | 2 +- fs/btrfs/tree-checker.c | 2 +- fs/btrfs/tree-log.c | 18 +++++++++--------- include/uapi/linux/btrfs_tree.h | 7 +++++++ 10 files changed, 43 insertions(+), 27 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 3482eea0f1b8..826d8bcb0435 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2103,10 +2103,10 @@ 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, @@ -2114,6 +2114,12 @@ BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item, 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 void btrfs_dir_item_key(const struct extent_buffer *eb, const struct btrfs_dir_item *item, struct btrfs_disk_key *key) diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 823aa05b3e38..fed11004cfe7 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1410,7 +1410,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; @@ -1442,7 +1442,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); @@ -1760,7 +1760,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, diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h index 9795dc295a18..c565f15e7af5 100644 --- a/fs/btrfs/delayed-inode.h +++ b/fs/btrfs/delayed-inode.h @@ -99,7 +99,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, diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index 72fb2c518a2b..e37b075afa96 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c @@ -81,7 +81,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,7 +140,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, 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); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f2c83ef8d4aa..89869e2b1931 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5566,7 +5566,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: btrfs_free_path(path); return ret; @@ -6004,6 +6004,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx) btrfs_for_each_slot(root, &key, &found_key, path, ret) { struct dir_entry *entry; struct extent_buffer *leaf = path->nodes[0]; + u8 di_flags; if (found_key.objectid != key.objectid) break; @@ -6027,13 +6028,15 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx) goto again; } + di_flags = 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(btrfs_dir_flags_to_ftype(di_flags)), + &entry->type); btrfs_dir_item_key_to_cpu(leaf, di, &location); put_unaligned(location.objectid, &entry->ino); put_unaligned(found_key.offset, &entry->offset); diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index dd8777872143..6d9d99bf3536 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -240,9 +240,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); diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index e7671afcee4f..b02e991b2c06 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1077,7 +1077,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; diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index 9e0e0ae2288c..dd3218c2ca51 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -528,7 +528,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)", diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index f99fd0a08902..2762b57bd4de 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1947,7 +1947,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; @@ -1957,7 +1957,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; /* @@ -2002,7 +2002,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; @@ -2019,7 +2019,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, goto out; } - log_type = btrfs_dir_type(eb, di); + log_flags = btrfs_dir_flags(eb, di); read_extent_buffer(eb, name, (unsigned long)(di + 1), name_len); @@ -2038,8 +2038,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); @@ -2056,7 +2056,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); @@ -2166,7 +2166,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; @@ -6181,7 +6181,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans, goto next_dir_inode; 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); diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h index d4117152d907..428ae75b9f73 100644 --- a/include/uapi/linux/btrfs_tree.h +++ b/include/uapi/linux/btrfs_tree.h @@ -359,6 +359,13 @@ enum btrfs_csum_type { #define BTRFS_FT_SYMLINK 7 #define BTRFS_FT_XATTR 8 #define BTRFS_FT_MAX 9 +/* Name is encrypted. */ +#define BTRFS_FT_FSCRYPT_NAME 0x80 + +static inline __u8 btrfs_dir_flags_to_ftype(__u8 flags) +{ + return flags & ~BTRFS_FT_FSCRYPT_NAME; +} /* * The key defines the order in the tree, and so it also defines (optimal) From patchwork Sun Jul 24 00:53:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927396 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 50BEBC433EF for ; Sun, 24 Jul 2022 00:54:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239229AbiGXAye (ORCPT ); Sat, 23 Jul 2022 20:54:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38480 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239065AbiGXAy1 (ORCPT ); Sat, 23 Jul 2022 20:54:27 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EFC7D15A20; Sat, 23 Jul 2022 17:54:24 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id A4839807A4; Sat, 23 Jul 2022 20:54:20 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624064; bh=mGNd2JueKchW2MX6Z5fFSJHndSk+sBC5ZeljPENk53Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pbkX/vfRqnceyO83HsUZtO2N2UN0F7/iwkHMk1lN+cQJCjGuJ/EZQ5oUjzjtAGiqW KRjzqxF+/HCmhx0DOXHLj188QBg0AYtdehLeXiRrj5J8VwKlgcBzDOMlOuwVYkR6eC e+8NTK10sAmdI2n2xb0GwviLu1+zCmXcknRNrBDIyPARaCY+AWCGIaXywQ6qLSZuRV biUxevCKV8KRYNjlSd33PgSZIQL/qdqxa9ho+NtKlPKDPtuTkC3lG2V6E0kJ5r/l/K KyooLHXDU+YYxlPAVfeEdX+bGaAOXAS1DFhBOsu9scYgGg54GSdLdRd9EDX+jQe9k6 U/oen3t2BvAUg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 02/16] btrfs: use fscrypt_name's instead of name/len everywhere. Date: Sat, 23 Jul 2022 20:53:47 -0400 Message-Id: <8506102cced3b35e49f406f7514305296931bdc5.1658623319.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org For encryption, the plaintext filenames provided by the VFS will need to be translated to ciphertext filenames on disk. Fscrypt provides a struct to encapsulate a potentially encrypted filename, struct fscrypt_name. This change converts every (name, len) pair to be a struct fscrypt_name, statically initialized, for ease of review and uniformity. Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/ctree.h | 49 +++++---- fs/btrfs/delayed-inode.c | 12 +- fs/btrfs/delayed-inode.h | 3 +- fs/btrfs/dir-item.c | 87 +++++++-------- fs/btrfs/inode-item.c | 82 +++++++------- fs/btrfs/inode-item.h | 14 +-- fs/btrfs/inode.c | 197 ++++++++++++++++++--------------- fs/btrfs/ioctl.c | 29 +++-- fs/btrfs/props.c | 11 +- fs/btrfs/root-tree.c | 19 ++-- fs/btrfs/send.c | 139 ++++++++++++++--------- fs/btrfs/super.c | 5 +- fs/btrfs/transaction.c | 25 +++-- fs/btrfs/tree-checker.c | 6 +- fs/btrfs/tree-log.c | 230 ++++++++++++++++++++++----------------- fs/btrfs/tree-log.h | 4 +- fs/btrfs/xattr.c | 21 ++-- 17 files changed, 531 insertions(+), 402 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 826d8bcb0435..975d1244cc35 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -21,11 +21,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include "extent-io-tree.h" @@ -2735,18 +2737,19 @@ static inline void btrfs_crc32c_final(u32 crc, u8 *result) put_unaligned_le32(~crc, result); } -static inline u64 btrfs_name_hash(const char *name, int len) +static inline u64 btrfs_name_hash(const struct fscrypt_name *name) { - return crc32c((u32)~1, name, len); + return crc32c((u32)~1, fname_name(name), fname_len(name)); } /* * Figure the key offset of an extended inode ref */ -static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name, - int len) +static inline u64 btrfs_extref_hash(u64 parent_objectid, + const struct fscrypt_name *name) { - return (u64) crc32c(parent_objectid, name, len); + return (u64) crc32c(parent_objectid, fname_name(name), + fname_len(name)); } static inline gfp_t btrfs_alloc_write_mask(struct address_space *mapping) @@ -3182,11 +3185,11 @@ static inline void btrfs_clear_sb_rdonly(struct super_block *sb) /* root-item.c */ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id, - u64 ref_id, u64 dirid, u64 sequence, const char *name, - int name_len); + u64 ref_id, u64 dirid, u64 sequence, + const struct fscrypt_name *fname); int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id, - u64 ref_id, u64 dirid, u64 *sequence, const char *name, - int name_len); + u64 ref_id, u64 dirid, u64 *sequence, + const struct fscrypt_name *fname); 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, @@ -3215,25 +3218,26 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info); /* dir-item.c */ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, - const char *name, int name_len); -int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, - int name_len, struct btrfs_inode *dir, - struct btrfs_key *location, u8 type, u64 index); + const struct fscrypt_name *fname); +int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, + const struct fscrypt_name *fname, + struct btrfs_inode *dir, struct btrfs_key *location, + u8 type, u64 index); struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, - const char *name, int name_len, + const struct fscrypt_name *fname, int mod); struct btrfs_dir_item * btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, - u64 index, const char *name, int name_len, + u64 index, const struct fscrypt_name *fname, int mod); struct btrfs_dir_item * btrfs_search_dir_index_item(struct btrfs_root *root, struct btrfs_path *path, u64 dirid, - const char *name, int name_len); + const struct fscrypt_name *fname); int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, @@ -3241,17 +3245,16 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 objectid, - const char *name, u16 name_len, + const struct fscrypt_name *fname, const void *data, u16 data_len); struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, - const char *name, u16 name_len, + const struct fscrypt_name *fname, int mod); struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info, struct btrfs_path *path, - const char *name, - int name_len); + const struct fscrypt_name *name); /* orphan.c */ int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, @@ -3315,10 +3318,11 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry); int btrfs_set_inode_index(struct btrfs_inode *dir, u64 *index); int btrfs_unlink_inode(struct btrfs_trans_handle *trans, struct btrfs_inode *dir, struct btrfs_inode *inode, - const char *name, int name_len); + const struct fscrypt_name *fname); int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_inode *parent_inode, struct btrfs_inode *inode, - const char *name, int name_len, int add_backref, u64 index); + const struct fscrypt_name *fname, int add_backref, + u64 index); int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry); int btrfs_truncate_block(struct btrfs_inode *inode, loff_t from, loff_t len, int front); @@ -3334,6 +3338,7 @@ struct btrfs_new_inode_args { struct inode *dir; struct dentry *dentry; struct inode *inode; + struct fscrypt_name fname; bool orphan; bool subvol; diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index fed11004cfe7..84ae3cf9a9ee 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1408,7 +1408,7 @@ void btrfs_balance_delayed_items(struct btrfs_fs_info *fs_info) /* Will return 0 or -ENOMEM */ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, - const char *name, int name_len, + const struct fscrypt_name *fname, struct btrfs_inode *dir, struct btrfs_disk_key *disk_key, u8 flags, u64 index) @@ -1426,7 +1426,8 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, if (IS_ERR(delayed_node)) return PTR_ERR(delayed_node); - delayed_item = btrfs_alloc_delayed_item(sizeof(*dir_item) + name_len); + delayed_item = btrfs_alloc_delayed_item(sizeof(*dir_item) + + fname_len(fname)); if (!delayed_item) { ret = -ENOMEM; goto release_node; @@ -1441,9 +1442,9 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, dir_item->location = *disk_key; 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_name_len(dir_item, fname_len(fname)); btrfs_set_stack_dir_flags(dir_item, flags); - memcpy((char *)(dir_item + 1), name, name_len); + memcpy((char *)(dir_item + 1), fname_name(fname), fname_len(fname)); data_len = delayed_item->data_len + sizeof(struct btrfs_item); @@ -1494,7 +1495,8 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, if (unlikely(ret)) { btrfs_err(trans->fs_info, "err add delayed dir index item(name: %.*s) into the insertion tree of the delayed node(root id: %llu, inode id: %llu, errno: %d)", - name_len, name, delayed_node->root->root_key.objectid, + fname_len(fname), fname_name(fname), + delayed_node->root->root_key.objectid, delayed_node->inode_id, ret); BUG(); } diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h index c565f15e7af5..968461b3c350 100644 --- a/fs/btrfs/delayed-inode.h +++ b/fs/btrfs/delayed-inode.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "ctree.h" @@ -97,7 +98,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, + const struct fscrypt_name *fname, struct btrfs_inode *dir, struct btrfs_disk_key *disk_key, u8 flags, u64 index); diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index e37b075afa96..b4c1e2a40401 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c @@ -21,8 +21,7 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle struct btrfs_path *path, struct btrfs_key *cpu_key, u32 data_size, - const char *name, - int name_len) + const struct fscrypt_name *fname) { struct btrfs_fs_info *fs_info = root->fs_info; int ret; @@ -32,7 +31,7 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); if (ret == -EEXIST) { struct btrfs_dir_item *di; - di = btrfs_match_dir_item_name(fs_info, path, name, name_len); + di = btrfs_match_dir_item_name(fs_info, path, fname); if (di) return ERR_PTR(-EEXIST); btrfs_extend_item(path, data_size); @@ -53,7 +52,7 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 objectid, - const char *name, u16 name_len, + const struct fscrypt_name *fname, const void *data, u16 data_len) { int ret = 0; @@ -64,16 +63,16 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, struct extent_buffer *leaf; u32 data_size; - if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root->fs_info)) + if (fname_len(fname) + data_len > BTRFS_MAX_XATTR_SIZE(root->fs_info)) return -ENOSPC; key.objectid = objectid; key.type = BTRFS_XATTR_ITEM_KEY; - key.offset = btrfs_name_hash(name, name_len); + key.offset = btrfs_name_hash(fname); - data_size = sizeof(*dir_item) + name_len + data_len; + data_size = sizeof(*dir_item) + fname_len(fname) + data_len; dir_item = insert_with_overflow(trans, root, path, &key, data_size, - name, name_len); + fname); if (IS_ERR(dir_item)) return PTR_ERR(dir_item); memset(&location, 0, sizeof(location)); @@ -82,13 +81,14 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, btrfs_cpu_key_to_disk(&disk_key, &location); btrfs_set_dir_item_key(leaf, dir_item, &disk_key); btrfs_set_dir_flags(leaf, dir_item, BTRFS_FT_XATTR); - btrfs_set_dir_name_len(leaf, dir_item, name_len); + btrfs_set_dir_name_len(leaf, dir_item, fname_len(fname)); btrfs_set_dir_transid(leaf, dir_item, trans->transid); btrfs_set_dir_data_len(leaf, dir_item, data_len); name_ptr = (unsigned long)(dir_item + 1); - data_ptr = (unsigned long)((char *)name_ptr + name_len); + data_ptr = (unsigned long)((char *)name_ptr + fname_len(fname)); - write_extent_buffer(leaf, name, name_ptr, name_len); + write_extent_buffer(leaf, fname_name(fname), name_ptr, + fname_len(fname)); write_extent_buffer(leaf, data, data_ptr, data_len); btrfs_mark_buffer_dirty(path->nodes[0]); @@ -103,9 +103,10 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, * to use for the second index (if one is created). * Will return 0 or -ENOMEM */ -int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, - int name_len, struct btrfs_inode *dir, - struct btrfs_key *location, u8 type, u64 index) +int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, + const struct fscrypt_name *fname, + struct btrfs_inode *dir, struct btrfs_key *location, + u8 type, u64 index) { int ret = 0; int ret2 = 0; @@ -120,7 +121,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, key.objectid = btrfs_ino(dir); key.type = BTRFS_DIR_ITEM_KEY; - key.offset = btrfs_name_hash(name, name_len); + key.offset = btrfs_name_hash(fname); path = btrfs_alloc_path(); if (!path) @@ -128,9 +129,9 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, btrfs_cpu_key_to_disk(&disk_key, location); - data_size = sizeof(*dir_item) + name_len; + data_size = sizeof(*dir_item) + fname_len(fname); dir_item = insert_with_overflow(trans, root, path, &key, data_size, - name, name_len); + fname); if (IS_ERR(dir_item)) { ret = PTR_ERR(dir_item); if (ret == -EEXIST) @@ -142,11 +143,12 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, btrfs_set_dir_item_key(leaf, dir_item, &disk_key); 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_name_len(leaf, dir_item, fname_len(fname)); btrfs_set_dir_transid(leaf, dir_item, trans->transid); name_ptr = (unsigned long)(dir_item + 1); - write_extent_buffer(leaf, name, name_ptr, name_len); + write_extent_buffer(leaf, fname_name(fname), name_ptr, + fname_len(fname)); btrfs_mark_buffer_dirty(leaf); second_insert: @@ -157,7 +159,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, } btrfs_release_path(path); - ret2 = btrfs_insert_delayed_dir_index(trans, name, name_len, dir, + ret2 = btrfs_insert_delayed_dir_index(trans, fname, dir, &disk_key, type, index); out_free: btrfs_free_path(path); @@ -171,8 +173,8 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, static struct btrfs_dir_item *btrfs_lookup_match_dir( struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, - struct btrfs_key *key, const char *name, - int name_len, int mod) + struct btrfs_key *key, const struct fscrypt_name *fname, + int mod) { const int ins_len = (mod < 0 ? -1 : 0); const int cow = (mod != 0); @@ -184,7 +186,7 @@ static struct btrfs_dir_item *btrfs_lookup_match_dir( if (ret > 0) return ERR_PTR(-ENOENT); - return btrfs_match_dir_item_name(root->fs_info, path, name, name_len); + return btrfs_match_dir_item_name(root->fs_info, path, fname); } /* @@ -206,7 +208,7 @@ static struct btrfs_dir_item *btrfs_lookup_match_dir( struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, - const char *name, int name_len, + const struct fscrypt_name *fname, int mod) { struct btrfs_key key; @@ -214,9 +216,9 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, key.objectid = dir; key.type = BTRFS_DIR_ITEM_KEY; - key.offset = btrfs_name_hash(name, name_len); + key.offset = btrfs_name_hash(fname); - di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod); + di = btrfs_lookup_match_dir(trans, root, path, &key, fname, mod); if (IS_ERR(di) && PTR_ERR(di) == -ENOENT) return NULL; @@ -224,7 +226,7 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, } int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, - const char *name, int name_len) + const struct fscrypt_name *fname) { int ret; struct btrfs_key key; @@ -240,9 +242,9 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, key.objectid = dir; key.type = BTRFS_DIR_ITEM_KEY; - key.offset = btrfs_name_hash(name, name_len); + key.offset = btrfs_name_hash(fname); - di = btrfs_lookup_match_dir(NULL, root, path, &key, name, name_len, 0); + di = btrfs_lookup_match_dir(NULL, root, path, &key, fname, 0); if (IS_ERR(di)) { ret = PTR_ERR(di); /* Nothing found, we're safe */ @@ -266,7 +268,7 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, * see if there is room in the item to insert this * name */ - data_size = sizeof(*di) + name_len; + data_size = sizeof(*di) + fname_len(fname); leaf = path->nodes[0]; slot = path->slots[0]; if (data_size + btrfs_item_size(leaf, slot) + @@ -303,7 +305,7 @@ struct btrfs_dir_item * btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, - u64 index, const char *name, int name_len, + u64 index, const struct fscrypt_name *fname, int mod) { struct btrfs_dir_item *di; @@ -313,7 +315,7 @@ btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, key.type = BTRFS_DIR_INDEX_KEY; key.offset = index; - di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod); + di = btrfs_lookup_match_dir(trans, root, path, &key, fname, mod); if (di == ERR_PTR(-ENOENT)) return NULL; @@ -323,7 +325,7 @@ btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, struct btrfs_dir_item * btrfs_search_dir_index_item(struct btrfs_root *root, struct btrfs_path *path, u64 dirid, - const char *name, int name_len) + const struct fscrypt_name *fname) { struct btrfs_dir_item *di; struct btrfs_key key; @@ -337,8 +339,7 @@ btrfs_search_dir_index_item(struct btrfs_root *root, if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY) break; - di = btrfs_match_dir_item_name(root->fs_info, path, - name, name_len); + di = btrfs_match_dir_item_name(root->fs_info, path, fname); if (di) return di; } @@ -352,7 +353,7 @@ btrfs_search_dir_index_item(struct btrfs_root *root, struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, - const char *name, u16 name_len, + const struct fscrypt_name *fname, int mod) { struct btrfs_key key; @@ -360,9 +361,9 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, key.objectid = dir; key.type = BTRFS_XATTR_ITEM_KEY; - key.offset = btrfs_name_hash(name, name_len); + key.offset = btrfs_name_hash(fname); - di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod); + di = btrfs_lookup_match_dir(trans, root, path, &key, fname, mod); if (IS_ERR(di) && PTR_ERR(di) == -ENOENT) return NULL; @@ -376,10 +377,9 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, */ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info, struct btrfs_path *path, - const char *name, int name_len) + const struct fscrypt_name *fname) { struct btrfs_dir_item *dir_item; - unsigned long name_ptr; u32 total_len; u32 cur = 0; u32 this_len; @@ -390,13 +390,14 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info, total_len = btrfs_item_size(leaf, path->slots[0]); while (cur < total_len) { + unsigned long name_ptr = (unsigned long)(dir_item + 1); this_len = sizeof(*dir_item) + btrfs_dir_name_len(leaf, dir_item) + btrfs_dir_data_len(leaf, dir_item); - name_ptr = (unsigned long)(dir_item + 1); - if (btrfs_dir_name_len(leaf, dir_item) == name_len && - memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) + if (btrfs_dir_name_len(leaf, dir_item) == fname_len(fname) && + memcmp_extent_buffer(leaf, fname_name(fname), name_ptr, + fname_len(fname)) == 0) return dir_item; cur += this_len; diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c index 0eeb5ea87894..78053eb9589c 100644 --- a/fs/btrfs/inode-item.c +++ b/fs/btrfs/inode-item.c @@ -3,15 +3,16 @@ * Copyright (C) 2007 Oracle. All rights reserved. */ +#include #include "ctree.h" #include "inode-item.h" #include "disk-io.h" #include "transaction.h" #include "print-tree.h" -struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf, - int slot, const char *name, - int name_len) +struct btrfs_inode_ref * +btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot, + const struct fscrypt_name *fname) { struct btrfs_inode_ref *ref; unsigned long ptr; @@ -27,9 +28,10 @@ struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf, len = btrfs_inode_ref_name_len(leaf, ref); name_ptr = (unsigned long)(ref + 1); cur_offset += len + sizeof(*ref); - if (len != name_len) + if (len != fname_len(fname)) continue; - if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) + if (memcmp_extent_buffer(leaf, fname_name(fname), name_ptr, + fname_len(fname)) == 0) return ref; } return NULL; @@ -37,7 +39,7 @@ struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf, struct btrfs_inode_extref *btrfs_find_name_in_ext_backref( struct extent_buffer *leaf, int slot, u64 ref_objectid, - const char *name, int name_len) + const struct fscrypt_name *fname) { struct btrfs_inode_extref *extref; unsigned long ptr; @@ -60,9 +62,10 @@ struct btrfs_inode_extref *btrfs_find_name_in_ext_backref( name_ptr = (unsigned long)(&extref->name); ref_name_len = btrfs_inode_extref_name_len(leaf, extref); - if (ref_name_len == name_len && + if (ref_name_len == fname_len(fname) && btrfs_inode_extref_parent(leaf, extref) == ref_objectid && - (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)) + (memcmp_extent_buffer(leaf, fname_name(fname), name_ptr, + fname_len(fname)) == 0)) return extref; cur_offset += ref_name_len + sizeof(*extref); @@ -75,7 +78,7 @@ struct btrfs_inode_extref * btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, - const char *name, int name_len, + const struct fscrypt_name *fname, u64 inode_objectid, u64 ref_objectid, int ins_len, int cow) { @@ -84,7 +87,7 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, key.objectid = inode_objectid; key.type = BTRFS_INODE_EXTREF_KEY; - key.offset = btrfs_extref_hash(ref_objectid, name, name_len); + key.offset = btrfs_extref_hash(ref_objectid, fname); ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); if (ret < 0) @@ -92,13 +95,12 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, if (ret > 0) return NULL; return btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], - ref_objectid, name, name_len); - + ref_objectid, fname); } static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - const char *name, int name_len, + const struct fscrypt_name *fname, u64 inode_objectid, u64 ref_objectid, u64 *index) { @@ -107,14 +109,14 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, struct btrfs_inode_extref *extref; struct extent_buffer *leaf; int ret; - int del_len = name_len + sizeof(*extref); + int del_len = fname_len(fname) + sizeof(*extref); unsigned long ptr; unsigned long item_start; u32 item_size; key.objectid = inode_objectid; key.type = BTRFS_INODE_EXTREF_KEY; - key.offset = btrfs_extref_hash(ref_objectid, name, name_len); + key.offset = btrfs_extref_hash(ref_objectid, fname); path = btrfs_alloc_path(); if (!path) @@ -132,7 +134,7 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, * readonly. */ extref = btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], - ref_objectid, name, name_len); + ref_objectid, fname); if (!extref) { btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL); ret = -EROFS; @@ -169,7 +171,7 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - const char *name, int name_len, + const struct fscrypt_name *fname, u64 inode_objectid, u64 ref_objectid, u64 *index) { struct btrfs_path *path; @@ -182,7 +184,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, u32 sub_item_len; int ret; int search_ext_refs = 0; - int del_len = name_len + sizeof(*ref); + int del_len = fname_len(fname) + sizeof(*ref); key.objectid = inode_objectid; key.offset = ref_objectid; @@ -201,8 +203,8 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, goto out; } - ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], name, - name_len); + ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], + fname); if (!ref) { ret = -ENOENT; search_ext_refs = 1; @@ -219,7 +221,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, goto out; } ptr = (unsigned long)ref; - sub_item_len = name_len + sizeof(*ref); + sub_item_len = fname_len(fname) + sizeof(*ref); item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, item_size - (ptr + sub_item_len - item_start)); @@ -233,8 +235,9 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, * name in our ref array. Find and remove the extended * inode ref then. */ - return btrfs_del_inode_extref(trans, root, name, name_len, - inode_objectid, ref_objectid, index); + return btrfs_del_inode_extref(trans, root, fname, + inode_objectid, ref_objectid, + index); } return ret; @@ -247,12 +250,12 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, */ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - const char *name, int name_len, + const struct fscrypt_name *fname, u64 inode_objectid, u64 ref_objectid, u64 index) { struct btrfs_inode_extref *extref; int ret; - int ins_len = name_len + sizeof(*extref); + int ins_len = fname_len(fname) + sizeof(*extref); unsigned long ptr; struct btrfs_path *path; struct btrfs_key key; @@ -260,7 +263,7 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, key.objectid = inode_objectid; key.type = BTRFS_INODE_EXTREF_KEY; - key.offset = btrfs_extref_hash(ref_objectid, name, name_len); + key.offset = btrfs_extref_hash(ref_objectid, fname); path = btrfs_alloc_path(); if (!path) @@ -272,7 +275,7 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, if (btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], ref_objectid, - name, name_len)) + fname)) goto out; btrfs_extend_item(path, ins_len); @@ -286,12 +289,13 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, ptr += btrfs_item_size(leaf, path->slots[0]) - ins_len; extref = (struct btrfs_inode_extref *)ptr; - btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len); + btrfs_set_inode_extref_name_len(path->nodes[0], extref, fname_len(fname)); btrfs_set_inode_extref_index(path->nodes[0], extref, index); btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid); ptr = (unsigned long)&extref->name; - write_extent_buffer(path->nodes[0], name, ptr, name_len); + write_extent_buffer(path->nodes[0], fname_name(fname), ptr, + fname_len(fname)); btrfs_mark_buffer_dirty(path->nodes[0]); out: @@ -302,7 +306,7 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, /* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - const char *name, int name_len, + const struct fscrypt_name *fname, u64 inode_objectid, u64 ref_objectid, u64 index) { struct btrfs_fs_info *fs_info = root->fs_info; @@ -311,7 +315,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_inode_ref *ref; unsigned long ptr; int ret; - int ins_len = name_len + sizeof(*ref); + int ins_len = fname_len(fname) + sizeof(*ref); key.objectid = inode_objectid; key.offset = ref_objectid; @@ -327,7 +331,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, if (ret == -EEXIST) { u32 old_size; ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], - name, name_len); + fname); if (ref) goto out; @@ -336,7 +340,8 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, ref = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_ref); ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size); - btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); + btrfs_set_inode_ref_name_len(path->nodes[0], ref, + fname_len(fname)); btrfs_set_inode_ref_index(path->nodes[0], ref, index); ptr = (unsigned long)(ref + 1); ret = 0; @@ -344,7 +349,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, if (ret == -EOVERFLOW) { if (btrfs_find_name_in_backref(path->nodes[0], path->slots[0], - name, name_len)) + fname)) ret = -EEXIST; else ret = -EMLINK; @@ -353,11 +358,13 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, } else { ref = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_ref); - btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); + btrfs_set_inode_ref_name_len(path->nodes[0], ref, + fname_len(fname)); btrfs_set_inode_ref_index(path->nodes[0], ref, index); ptr = (unsigned long)(ref + 1); } - write_extent_buffer(path->nodes[0], name, ptr, name_len); + write_extent_buffer(path->nodes[0], fname_name(fname), ptr, + fname_len(fname)); btrfs_mark_buffer_dirty(path->nodes[0]); out: @@ -369,8 +376,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, * add an extended ref. */ if (btrfs_super_incompat_flags(disk_super) & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF) - ret = btrfs_insert_inode_extref(trans, root, name, - name_len, + ret = btrfs_insert_inode_extref(trans, root, fname, inode_objectid, ref_objectid, index); } diff --git a/fs/btrfs/inode-item.h b/fs/btrfs/inode-item.h index a8fc16d0147f..d55f9d6f17dd 100644 --- a/fs/btrfs/inode-item.h +++ b/fs/btrfs/inode-item.h @@ -65,11 +65,11 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, struct btrfs_truncate_control *control); int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - const char *name, int name_len, + const struct fscrypt_name *fname, u64 inode_objectid, u64 ref_objectid, u64 index); int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - const char *name, int name_len, + const struct fscrypt_name *fname, u64 inode_objectid, u64 ref_objectid, u64 *index); int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans, struct btrfs_root *root, @@ -82,15 +82,15 @@ struct btrfs_inode_extref *btrfs_lookup_inode_extref( struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, - const char *name, int name_len, + const struct fscrypt_name *fname, u64 inode_objectid, u64 ref_objectid, int ins_len, int cow); -struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf, - int slot, const char *name, - int name_len); +struct btrfs_inode_ref * +btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot, + const struct fscrypt_name *fname); struct btrfs_inode_extref *btrfs_find_name_in_ext_backref( struct extent_buffer *leaf, int slot, u64 ref_objectid, - const char *name, int name_len); + const struct fscrypt_name *fname); #endif diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 89869e2b1931..5b3406f79db8 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3865,11 +3865,19 @@ static noinline int acls_after_inode_item(struct extent_buffer *leaf, static u64 xattr_default = 0; int scanned = 0; + struct fscrypt_name name_access = { + .disk_name = FSTR_INIT(XATTR_NAME_POSIX_ACL_ACCESS, + strlen(XATTR_NAME_POSIX_ACL_ACCESS)) + }; + + struct fscrypt_name name_default = { + .disk_name = FSTR_INIT(XATTR_NAME_POSIX_ACL_DEFAULT, + strlen(XATTR_NAME_POSIX_ACL_DEFAULT)) + }; + if (!xattr_access) { - xattr_access = btrfs_name_hash(XATTR_NAME_POSIX_ACL_ACCESS, - strlen(XATTR_NAME_POSIX_ACL_ACCESS)); - xattr_default = btrfs_name_hash(XATTR_NAME_POSIX_ACL_DEFAULT, - strlen(XATTR_NAME_POSIX_ACL_DEFAULT)); + xattr_access = btrfs_name_hash(&name_access); + xattr_default = btrfs_name_hash(&name_default); } slot++; @@ -4256,7 +4264,7 @@ int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans, static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, struct btrfs_inode *dir, struct btrfs_inode *inode, - const char *name, int name_len, + const struct fscrypt_name *fname, struct btrfs_rename_ctx *rename_ctx) { struct btrfs_root *root = dir->root; @@ -4274,8 +4282,7 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, goto out; } - di = btrfs_lookup_dir_item(trans, root, path, dir_ino, - name, name_len, -1); + di = btrfs_lookup_dir_item(trans, root, path, dir_ino, fname, -1); if (IS_ERR_OR_NULL(di)) { ret = di ? PTR_ERR(di) : -ENOENT; goto err; @@ -4303,12 +4310,11 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, } } - ret = btrfs_del_inode_ref(trans, root, name, name_len, ino, - dir_ino, &index); + ret = btrfs_del_inode_ref(trans, root, fname, ino, dir_ino, &index); if (ret) { btrfs_info(fs_info, "failed to delete reference to %.*s, inode %llu parent %llu", - name_len, name, ino, dir_ino); + fname_len(fname), fname_name(fname), ino, dir_ino); btrfs_abort_transaction(trans, ret); goto err; } @@ -4329,10 +4335,8 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, * operations on the log tree, increasing latency for applications. */ if (!rename_ctx) { - btrfs_del_inode_ref_in_log(trans, root, name, name_len, inode, - dir_ino); - btrfs_del_dir_entries_in_log(trans, root, name, name_len, dir, - index); + btrfs_del_inode_ref_in_log(trans, root, fname, inode, dir_ino); + btrfs_del_dir_entries_in_log(trans, root, fname, dir, index); } /* @@ -4350,7 +4354,7 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, if (ret) goto out; - btrfs_i_size_write(dir, dir->vfs_inode.i_size - name_len * 2); + btrfs_i_size_write(dir, dir->vfs_inode.i_size - fname_len(fname) * 2); inode_inc_iversion(&inode->vfs_inode); inode_inc_iversion(&dir->vfs_inode); inode->vfs_inode.i_ctime = current_time(&inode->vfs_inode); @@ -4363,10 +4367,10 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, int btrfs_unlink_inode(struct btrfs_trans_handle *trans, struct btrfs_inode *dir, struct btrfs_inode *inode, - const char *name, int name_len) + const struct fscrypt_name *fname) { int ret; - ret = __btrfs_unlink_inode(trans, dir, inode, name, name_len, NULL); + ret = __btrfs_unlink_inode(trans, dir, inode, fname, NULL); if (!ret) { drop_nlink(&inode->vfs_inode); ret = btrfs_update_inode(trans, inode->root, inode); @@ -4402,6 +4406,10 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) struct btrfs_trans_handle *trans; struct inode *inode = d_inode(dentry); int ret; + struct fscrypt_name fname = { + .disk_name = FSTR_INIT((unsigned char *)dentry->d_name.name, dentry->d_name.len) + }; + trans = __unlink_start_trans(dir); if (IS_ERR(trans)) @@ -4411,8 +4419,7 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) 0); ret = btrfs_unlink_inode(trans, BTRFS_I(dir), - BTRFS_I(d_inode(dentry)), dentry->d_name.name, - dentry->d_name.len); + BTRFS_I(d_inode(dentry)), &fname); if (ret) goto out; @@ -4437,12 +4444,14 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, struct extent_buffer *leaf; struct btrfs_dir_item *di; struct btrfs_key key; - const char *name = dentry->d_name.name; - int name_len = dentry->d_name.len; u64 index; int ret; u64 objectid; u64 dir_ino = btrfs_ino(BTRFS_I(dir)); + struct fscrypt_name fname = { + .disk_name = FSTR_INIT((char *) dentry->d_name.name, + dentry->d_name.len) + }; if (btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID) { objectid = inode->root->root_key.objectid; @@ -4457,8 +4466,7 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, if (!path) return -ENOMEM; - di = btrfs_lookup_dir_item(trans, root, path, dir_ino, - name, name_len, -1); + di = btrfs_lookup_dir_item(trans, root, path, dir_ino, &fname, -1); if (IS_ERR_OR_NULL(di)) { ret = di ? PTR_ERR(di) : -ENOENT; goto out; @@ -4484,8 +4492,7 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, * call btrfs_del_root_ref, and it _shouldn't_ fail. */ if (btrfs_ino(inode) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID) { - di = btrfs_search_dir_index_item(root, path, dir_ino, - name, name_len); + di = btrfs_search_dir_index_item(root, path, dir_ino, &fname); if (IS_ERR_OR_NULL(di)) { if (!di) ret = -ENOENT; @@ -4502,7 +4509,7 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, } else { ret = btrfs_del_root_ref(trans, objectid, root->root_key.objectid, dir_ino, - &index, name, name_len); + &index, &fname); if (ret) { btrfs_abort_transaction(trans, ret); goto out; @@ -4515,7 +4522,7 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, goto out; } - btrfs_i_size_write(BTRFS_I(dir), dir->i_size - name_len * 2); + btrfs_i_size_write(BTRFS_I(dir), dir->i_size - fname_len(&fname) * 2); inode_inc_iversion(dir); dir->i_mtime = current_time(dir); dir->i_ctime = dir->i_mtime; @@ -4539,6 +4546,10 @@ static noinline int may_destroy_subvol(struct btrfs_root *root) struct btrfs_key key; u64 dir_id; int ret; + struct fscrypt_name fname = { + .disk_name = FSTR_INIT("default", 7) + }; + path = btrfs_alloc_path(); if (!path) @@ -4547,7 +4558,7 @@ static noinline int may_destroy_subvol(struct btrfs_root *root) /* Make sure this root isn't set as the default subvol */ dir_id = btrfs_super_root_dir(fs_info->super_copy); di = btrfs_lookup_dir_item(NULL, fs_info->tree_root, path, - dir_id, "default", 7, 0); + dir_id, &fname, 0); if (di && !IS_ERR(di)) { btrfs_dir_item_key_to_cpu(path->nodes[0], di, &key); if (key.objectid == root->root_key.objectid) { @@ -4786,6 +4797,9 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) int err = 0; struct btrfs_trans_handle *trans; u64 last_unlink_trans; + struct fscrypt_name fname = { + .disk_name = FSTR_INIT((unsigned char *)dentry->d_name.name, dentry->d_name.len) + }; if (inode->i_size > BTRFS_EMPTY_DIR_SIZE) return -ENOTEMPTY; @@ -4815,8 +4829,7 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) /* now the directory is empty */ err = btrfs_unlink_inode(trans, BTRFS_I(dir), - BTRFS_I(d_inode(dentry)), dentry->d_name.name, - dentry->d_name.len); + BTRFS_I(d_inode(dentry)), &fname); if (!err) { btrfs_i_size_write(BTRFS_I(inode), 0); /* @@ -5538,19 +5551,21 @@ void btrfs_evict_inode(struct inode *inode) static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, struct btrfs_key *location, u8 *type) { - const char *name = dentry->d_name.name; - int namelen = dentry->d_name.len; struct btrfs_dir_item *di; struct btrfs_path *path; struct btrfs_root *root = BTRFS_I(dir)->root; int ret = 0; + struct fscrypt_name fname = { + .disk_name = FSTR_INIT((char *) dentry->d_name.name, + dentry->d_name.len) + }; path = btrfs_alloc_path(); if (!path) return -ENOMEM; di = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(BTRFS_I(dir)), - name, namelen, 0); + &fname, 0); if (IS_ERR_OR_NULL(di)) { ret = di ? PTR_ERR(di) : -ENOENT; goto out; @@ -5562,7 +5577,7 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, ret = -EUCLEAN; btrfs_warn(root->fs_info, "%s gets something invalid in DIR_ITEM (name %s, directory ino %llu, location(%llu %u %llu))", - __func__, name, btrfs_ino(BTRFS_I(dir)), + __func__, fname_name(&fname), btrfs_ino(BTRFS_I(dir)), location->objectid, location->type, location->offset); } if (!ret) @@ -6246,6 +6261,14 @@ int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args, if (ret) return ret; + if (!args->orphan) { + char *name = (char *) args->dentry->d_name.name; + int name_len = args->dentry->d_name.len; + args->fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(name, name_len), + }; + } + /* 1 to add inode item */ *trans_num_items = 1; /* 1 to add compression property */ @@ -6319,8 +6342,6 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans, { struct inode *dir = args->dir; struct inode *inode = args->inode; - const char *name = args->orphan ? NULL : args->dentry->d_name.name; - int name_len = args->orphan ? 0 : args->dentry->d_name.len; struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); struct btrfs_root *root; struct btrfs_inode_item *inode_item; @@ -6421,7 +6442,7 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans, sizes[1] = 2 + sizeof(*ref); } else { key[1].offset = btrfs_ino(BTRFS_I(dir)); - sizes[1] = name_len + sizeof(*ref); + sizes[1] = fname_len(&args->fname) + sizeof(*ref); } } @@ -6460,10 +6481,13 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans, btrfs_set_inode_ref_index(path->nodes[0], ref, 0); write_extent_buffer(path->nodes[0], "..", ptr, 2); } else { - btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); + btrfs_set_inode_ref_name_len(path->nodes[0], ref, + fname_len(&args->fname)); btrfs_set_inode_ref_index(path->nodes[0], ref, BTRFS_I(inode)->dir_index); - write_extent_buffer(path->nodes[0], name, ptr, name_len); + write_extent_buffer(path->nodes[0], + fname_name(&args->fname), ptr, + fname_len(&args->fname)); } } @@ -6523,8 +6547,9 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans, if (args->orphan) { ret = btrfs_orphan_add(trans, BTRFS_I(inode)); } else { - ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), name, - name_len, 0, BTRFS_I(inode)->dir_index); + ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), + &args->fname, 0, + BTRFS_I(inode)->dir_index); } if (ret) { btrfs_abort_transaction(trans, ret); @@ -6553,7 +6578,7 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans, */ int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_inode *parent_inode, struct btrfs_inode *inode, - const char *name, int name_len, int add_backref, u64 index) + const struct fscrypt_name *fname, int add_backref, u64 index) { int ret = 0; struct btrfs_key key; @@ -6572,17 +6597,17 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) { ret = btrfs_add_root_ref(trans, key.objectid, root->root_key.objectid, parent_ino, - index, name, name_len); + index, fname); } else if (add_backref) { - ret = btrfs_insert_inode_ref(trans, root, name, name_len, ino, - parent_ino, index); + ret = btrfs_insert_inode_ref(trans, root, fname, ino, parent_ino, + index); } /* Nothing to clean up yet */ if (ret) return ret; - ret = btrfs_insert_dir_item(trans, name, name_len, parent_inode, &key, + ret = btrfs_insert_dir_item(trans, fname, parent_inode, &key, btrfs_inode_type(&inode->vfs_inode), index); if (ret == -EEXIST || ret == -EOVERFLOW) goto fail_dir_item; @@ -6592,7 +6617,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, } btrfs_i_size_write(parent_inode, parent_inode->vfs_inode.i_size + - name_len * 2); + fname_len(fname) * 2); inode_inc_iversion(&parent_inode->vfs_inode); /* * If we are replaying a log tree, we do not want to update the mtime @@ -6615,17 +6640,18 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) { u64 local_index; int err; + err = btrfs_del_root_ref(trans, key.objectid, root->root_key.objectid, parent_ino, - &local_index, name, name_len); + &local_index, fname); if (err) btrfs_abort_transaction(trans, err); } else if (add_backref) { u64 local_index; int err; - err = btrfs_del_inode_ref(trans, root, name, name_len, - ino, parent_ino, &local_index); + err = btrfs_del_inode_ref(trans, root, fname, ino, + parent_ino, &local_index); if (err) btrfs_abort_transaction(trans, err); } @@ -6708,6 +6734,10 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, struct btrfs_root *root = BTRFS_I(dir)->root; struct inode *inode = d_inode(old_dentry); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + struct fscrypt_name fname = { + .disk_name = FSTR_INIT((char *) dentry->d_name.name, + dentry->d_name.len) + }; u64 index; int err; int drop_inode = 0; @@ -6744,8 +6774,8 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, ihold(inode); set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags); - err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), - dentry->d_name.name, dentry->d_name.len, 1, index); + err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), &fname, 1, + index); if (err) { drop_inode = 1; @@ -9139,6 +9169,14 @@ static int btrfs_rename_exchange(struct inode *old_dir, int ret; int ret2; bool need_abort = false; + struct fscrypt_name old_name = { + .disk_name = FSTR_INIT((char *) old_dentry->d_name.name, + old_dentry->d_name.len) + }; + struct fscrypt_name new_name = { + .disk_name = FSTR_INIT((char *) new_dentry->d_name.name, + new_dentry->d_name.len) + }; /* * For non-subvolumes allow exchange only within one subvolume, in the @@ -9217,10 +9255,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, /* force full log commit if subvolume involved. */ btrfs_set_log_full_commit(trans); } else { - ret = btrfs_insert_inode_ref(trans, dest, - new_dentry->d_name.name, - new_dentry->d_name.len, - old_ino, + ret = btrfs_insert_inode_ref(trans, dest, &new_name, old_ino, btrfs_ino(BTRFS_I(new_dir)), old_idx); if (ret) @@ -9233,10 +9268,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, /* force full log commit if subvolume involved. */ btrfs_set_log_full_commit(trans); } else { - ret = btrfs_insert_inode_ref(trans, root, - old_dentry->d_name.name, - old_dentry->d_name.len, - new_ino, + ret = btrfs_insert_inode_ref(trans, root, &old_name, new_ino, btrfs_ino(BTRFS_I(old_dir)), new_idx); if (ret) { @@ -9270,9 +9302,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, ret = btrfs_unlink_subvol(trans, old_dir, old_dentry); } else { /* src is an inode */ ret = __btrfs_unlink_inode(trans, BTRFS_I(old_dir), - BTRFS_I(old_dentry->d_inode), - old_dentry->d_name.name, - old_dentry->d_name.len, + BTRFS_I(old_dentry->d_inode), &old_name, &old_rename_ctx); if (!ret) ret = btrfs_update_inode(trans, root, BTRFS_I(old_inode)); @@ -9287,9 +9317,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, ret = btrfs_unlink_subvol(trans, new_dir, new_dentry); } else { /* dest is an inode */ ret = __btrfs_unlink_inode(trans, BTRFS_I(new_dir), - BTRFS_I(new_dentry->d_inode), - new_dentry->d_name.name, - new_dentry->d_name.len, + BTRFS_I(new_dentry->d_inode), &new_name, &new_rename_ctx); if (!ret) ret = btrfs_update_inode(trans, dest, BTRFS_I(new_inode)); @@ -9300,16 +9328,14 @@ static int btrfs_rename_exchange(struct inode *old_dir, } ret = btrfs_add_link(trans, BTRFS_I(new_dir), BTRFS_I(old_inode), - new_dentry->d_name.name, - new_dentry->d_name.len, 0, old_idx); + &new_name, 0, old_idx); if (ret) { btrfs_abort_transaction(trans, ret); goto out_fail; } ret = btrfs_add_link(trans, BTRFS_I(old_dir), BTRFS_I(new_inode), - old_dentry->d_name.name, - old_dentry->d_name.len, 0, new_idx); + &old_name, 0, new_idx); if (ret) { btrfs_abort_transaction(trans, ret); goto out_fail; @@ -9391,6 +9417,14 @@ static int btrfs_rename(struct user_namespace *mnt_userns, int ret; int ret2; u64 old_ino = btrfs_ino(BTRFS_I(old_inode)); + struct fscrypt_name old_fname = { + .disk_name = FSTR_INIT((char *)old_dentry->d_name.name, + old_dentry->d_name.len) + }; + struct fscrypt_name new_fname = { + .disk_name = FSTR_INIT((char *)new_dentry->d_name.name, + new_dentry->d_name.len) + }; if (btrfs_ino(BTRFS_I(new_dir)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID) return -EPERM; @@ -9407,11 +9441,8 @@ static int btrfs_rename(struct user_namespace *mnt_userns, new_inode->i_size > BTRFS_EMPTY_DIR_SIZE) return -ENOTEMPTY; - /* check for collisions, even if the name isn't there */ - ret = btrfs_check_dir_item_collision(dest, new_dir->i_ino, - new_dentry->d_name.name, - new_dentry->d_name.len); + ret = btrfs_check_dir_item_collision(dest, new_dir->i_ino, &new_fname); if (ret) { if (ret == -EEXIST) { @@ -9505,11 +9536,9 @@ static int btrfs_rename(struct user_namespace *mnt_userns, /* force full log commit if subvolume involved. */ btrfs_set_log_full_commit(trans); } else { - ret = btrfs_insert_inode_ref(trans, dest, - new_dentry->d_name.name, - new_dentry->d_name.len, - old_ino, - btrfs_ino(BTRFS_I(new_dir)), index); + ret = btrfs_insert_inode_ref(trans, dest, &new_fname, old_ino, + btrfs_ino(BTRFS_I(new_dir)), + index); if (ret) goto out_fail; } @@ -9532,9 +9561,7 @@ static int btrfs_rename(struct user_namespace *mnt_userns, } else { ret = __btrfs_unlink_inode(trans, BTRFS_I(old_dir), BTRFS_I(d_inode(old_dentry)), - old_dentry->d_name.name, - old_dentry->d_name.len, - &rename_ctx); + &old_fname, &rename_ctx); if (!ret) ret = btrfs_update_inode(trans, root, BTRFS_I(old_inode)); } @@ -9553,8 +9580,7 @@ static int btrfs_rename(struct user_namespace *mnt_userns, } else { ret = btrfs_unlink_inode(trans, BTRFS_I(new_dir), BTRFS_I(d_inode(new_dentry)), - new_dentry->d_name.name, - new_dentry->d_name.len); + &new_fname); } if (!ret && new_inode->i_nlink == 0) ret = btrfs_orphan_add(trans, @@ -9566,8 +9592,7 @@ static int btrfs_rename(struct user_namespace *mnt_userns, } ret = btrfs_add_link(trans, BTRFS_I(new_dir), BTRFS_I(old_inode), - new_dentry->d_name.name, - new_dentry->d_name.len, 0, index); + &new_fname, 0, index); if (ret) { btrfs_abort_transaction(trans, ret); goto out_fail; diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index fe0cc816b4eb..10b8db56edda 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -941,7 +941,7 @@ static inline int btrfs_may_create(struct user_namespace *mnt_userns, */ static noinline int btrfs_mksubvol(const struct path *parent, struct user_namespace *mnt_userns, - const char *name, int namelen, + struct fscrypt_name *fname, struct btrfs_root *snap_src, bool readonly, struct btrfs_qgroup_inherit *inherit) @@ -955,7 +955,8 @@ static noinline int btrfs_mksubvol(const struct path *parent, if (error == -EINTR) return error; - dentry = lookup_one(mnt_userns, name, parent->dentry, namelen); + dentry = lookup_one(mnt_userns, fname_name(fname), parent->dentry, + fname_len(fname)); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out_unlock; @@ -969,8 +970,7 @@ static noinline int btrfs_mksubvol(const struct path *parent, * check for them now when we can safely fail */ error = btrfs_check_dir_item_collision(BTRFS_I(dir)->root, - dir->i_ino, name, - namelen); + dir->i_ino, fname); if (error) goto out_dput; @@ -997,7 +997,7 @@ static noinline int btrfs_mksubvol(const struct path *parent, static noinline int btrfs_mksnapshot(const struct path *parent, struct user_namespace *mnt_userns, - const char *name, int namelen, + struct fscrypt_name *fname, struct btrfs_root *root, bool readonly, struct btrfs_qgroup_inherit *inherit) @@ -1026,7 +1026,7 @@ static noinline int btrfs_mksnapshot(const struct path *parent, btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1); - ret = btrfs_mksubvol(parent, mnt_userns, name, namelen, + ret = btrfs_mksubvol(parent, mnt_userns, fname, root, readonly, inherit); out: if (snapshot_force_cow) @@ -2138,6 +2138,7 @@ static noinline int __btrfs_ioctl_snap_create(struct file *file, { int namelen; int ret = 0; + struct fscrypt_name fname; if (!S_ISDIR(file_inode(file)->i_mode)) return -ENOTDIR; @@ -2158,9 +2159,12 @@ static noinline int __btrfs_ioctl_snap_create(struct file *file, goto out_drop_write; } + fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT((char *) name, namelen) + }; if (subvol) { - ret = btrfs_mksubvol(&file->f_path, mnt_userns, name, - namelen, NULL, readonly, inherit); + ret = btrfs_mksubvol(&file->f_path, mnt_userns, &fname, + NULL, readonly, inherit); } else { struct fd src = fdget(fd); struct inode *src_inode; @@ -2182,8 +2186,7 @@ static noinline int __btrfs_ioctl_snap_create(struct file *file, ret = -EPERM; } else { ret = btrfs_mksnapshot(&file->f_path, mnt_userns, - name, namelen, - BTRFS_I(src_inode)->root, + &fname, BTRFS_I(src_inode)->root, readonly, inherit); } fdput(src); @@ -3777,6 +3780,10 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) u64 objectid = 0; u64 dir_id; int ret; + struct fscrypt_name fname = { + .disk_name = FSTR_INIT("default", 7) + }; + if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -3817,7 +3824,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) dir_id = btrfs_super_root_dir(fs_info->super_copy); di = btrfs_lookup_dir_item(trans, fs_info->tree_root, path, - dir_id, "default", 7, 1); + dir_id, &fname, 1); if (IS_ERR_OR_NULL(di)) { btrfs_release_path(path); btrfs_end_transaction(trans); diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c index a2ec8ecae8de..0df607fcb21d 100644 --- a/fs/btrfs/props.c +++ b/fs/btrfs/props.c @@ -43,7 +43,10 @@ find_prop_handler(const char *name, struct prop_handler *h; if (!handlers) { - u64 hash = btrfs_name_hash(name, strlen(name)); + struct fscrypt_name fname = { + .disk_name = FSTR_INIT((char *) name, strlen(name)), + }; + u64 hash = btrfs_name_hash(&fname); handlers = find_prop_handlers_by_hash(hash); if (!handlers) @@ -462,7 +465,11 @@ void __init btrfs_props_init(void) for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) { struct prop_handler *p = &prop_handlers[i]; - u64 h = btrfs_name_hash(p->xattr_name, strlen(p->xattr_name)); + struct fscrypt_name fname = { + .disk_name = FSTR_INIT((char *)p->xattr_name, + strlen(p->xattr_name)), + }; + u64 h = btrfs_name_hash(&fname); hash_add(prop_handlers_ht, &p->node, h); } diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index a64b26b16904..8eb6cbe19326 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -327,8 +327,8 @@ 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 char *name, - int name_len) + u64 ref_id, u64 dirid, u64 *sequence, + const struct fscrypt_name *fname) { struct btrfs_root *tree_root = trans->fs_info->tree_root; @@ -357,8 +357,9 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id, struct btrfs_root_ref); ptr = (unsigned long)(ref + 1); if ((btrfs_root_ref_dirid(leaf, ref) != dirid) || - (btrfs_root_ref_name_len(leaf, ref) != name_len) || - memcmp_extent_buffer(leaf, name, ptr, name_len)) { + (btrfs_root_ref_name_len(leaf, ref) != fname_len(fname)) || + memcmp_extent_buffer(leaf, fname_name(fname), ptr, + fname_len(fname))) { err = -ENOENT; goto out; } @@ -401,8 +402,8 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id, * Will return 0, -ENOMEM, or anything from the CoW path */ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id, - u64 ref_id, u64 dirid, u64 sequence, const char *name, - int name_len) + u64 ref_id, u64 dirid, u64 sequence, + const struct fscrypt_name *fname) { struct btrfs_root *tree_root = trans->fs_info->tree_root; struct btrfs_key key; @@ -421,7 +422,7 @@ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id, key.offset = ref_id; again: ret = btrfs_insert_empty_item(trans, tree_root, path, &key, - sizeof(*ref) + name_len); + sizeof(*ref) + fname_len(fname)); if (ret) { btrfs_abort_transaction(trans, ret); btrfs_free_path(path); @@ -432,9 +433,9 @@ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id, ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); btrfs_set_root_ref_dirid(leaf, ref, dirid); btrfs_set_root_ref_sequence(leaf, ref, sequence); - btrfs_set_root_ref_name_len(leaf, ref, name_len); + btrfs_set_root_ref_name_len(leaf, ref, fname_len(fname)); ptr = (unsigned long)(ref + 1); - write_extent_buffer(leaf, name, ptr, name_len); + write_extent_buffer(leaf, fname_name(fname), ptr, fname_len(fname)); btrfs_mark_buffer_dirty(leaf); if (key.type == BTRFS_ROOT_BACKREF_KEY) { diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index b02e991b2c06..061dbfeccbeb 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "send.h" #include "ctree.h" @@ -1023,7 +1024,7 @@ static int iterate_inode_ref(struct btrfs_root *root, struct btrfs_path *path, } typedef int (*iterate_dir_item_t)(int num, struct btrfs_key *di_key, - const char *name, int name_len, + struct fscrypt_name *fname, const char *data, int data_len, void *ctx); @@ -1073,6 +1074,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path, num = 0; while (cur < total) { + struct fscrypt_name fname; name_len = btrfs_dir_name_len(eb, di); data_len = btrfs_dir_data_len(eb, di); btrfs_dir_item_key_to_cpu(eb, di, &di_key); @@ -1125,8 +1127,11 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path, len = sizeof(*di) + name_len + data_len; di = (struct btrfs_dir_item *)((char *)di + len); cur += len; + fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(buf, name_len) + }; - ret = iterate(num, &di_key, buf, name_len, buf + name_len, + ret = iterate(num, &di_key, &fname, buf + name_len, data_len, ctx); if (ret < 0) goto out; @@ -1580,13 +1585,17 @@ static int gen_unique_name(struct send_ctx *sctx, return -ENOMEM; while (1) { + struct fscrypt_name fname; len = snprintf(tmp, sizeof(tmp), "o%llu-%llu-%llu", ino, gen, idx); ASSERT(len < sizeof(tmp)); + fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(tmp, strlen(tmp)),//len) + }; di = btrfs_lookup_dir_item(NULL, sctx->send_root, path, BTRFS_FIRST_FREE_OBJECTID, - tmp, strlen(tmp), 0); + &fname, 0); btrfs_release_path(path); if (IS_ERR(di)) { ret = PTR_ERR(di); @@ -1606,7 +1615,7 @@ static int gen_unique_name(struct send_ctx *sctx, di = btrfs_lookup_dir_item(NULL, sctx->parent_root, path, BTRFS_FIRST_FREE_OBJECTID, - tmp, strlen(tmp), 0); + &fname, 0); btrfs_release_path(path); if (IS_ERR(di)) { ret = PTR_ERR(di); @@ -1728,7 +1737,7 @@ static int is_inode_existent(struct send_ctx *sctx, u64 ino, u64 gen) * Helper function to lookup a dir item in a dir. */ static int lookup_dir_item_inode(struct btrfs_root *root, - u64 dir, const char *name, int name_len, + u64 dir, struct fscrypt_name *fname, u64 *found_inode) { int ret = 0; @@ -1741,7 +1750,7 @@ static int lookup_dir_item_inode(struct btrfs_root *root, return -ENOMEM; di = btrfs_lookup_dir_item(NULL, root, path, - dir, name, name_len, 0); + dir, fname, 0); if (IS_ERR_OR_NULL(di)) { ret = di ? PTR_ERR(di) : -ENOENT; goto out; @@ -1831,7 +1840,7 @@ static int get_first_ref(struct btrfs_root *root, u64 ino, static int is_first_ref(struct btrfs_root *root, u64 ino, u64 dir, - const char *name, int name_len) + struct fscrypt_name *fname) { int ret; struct fs_path *tmp_name; @@ -1845,12 +1854,12 @@ static int is_first_ref(struct btrfs_root *root, if (ret < 0) goto out; - if (dir != tmp_dir || name_len != fs_path_len(tmp_name)) { + if (dir != tmp_dir || fname_len(fname) != fs_path_len(tmp_name)) { ret = 0; goto out; } - ret = !memcmp(tmp_name->start, name, name_len); + ret = !memcmp(tmp_name->start, fname_name(fname), fname_len(fname)); out: fs_path_free(tmp_name); @@ -1868,7 +1877,7 @@ static int is_first_ref(struct btrfs_root *root, * orphanizing is really required. */ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, - const char *name, int name_len, + struct fscrypt_name *fname, u64 *who_ino, u64 *who_gen, u64 *who_mode) { int ret = 0; @@ -1900,7 +1909,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, goto out; } - ret = lookup_dir_item_inode(sctx->parent_root, dir, name, name_len, + ret = lookup_dir_item_inode(sctx->parent_root, dir, fname, &other_inode); if (ret < 0 && ret != -ENOENT) goto out; @@ -1941,7 +1950,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, static int did_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, u64 ino, u64 ino_gen, - const char *name, int name_len) + struct fscrypt_name *fname) { int ret = 0; u64 gen; @@ -1968,7 +1977,7 @@ static int did_overwrite_ref(struct send_ctx *sctx, } /* check if the ref was overwritten by another ref */ - ret = lookup_dir_item_inode(sctx->send_root, dir, name, name_len, + ret = lookup_dir_item_inode(sctx->send_root, dir, fname, &ow_inode); if (ret < 0 && ret != -ENOENT) goto out; @@ -2016,7 +2025,7 @@ static int did_overwrite_first_ref(struct send_ctx *sctx, u64 ino, u64 gen) struct fs_path *name = NULL; u64 dir; u64 dir_gen; - + struct fscrypt_name fname; if (!sctx->parent_root) goto out; @@ -2028,8 +2037,12 @@ static int did_overwrite_first_ref(struct send_ctx *sctx, u64 ino, u64 gen) if (ret < 0) goto out; + fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(name->start, fs_path_len(name)) + }; + ret = did_overwrite_ref(sctx, dir, dir_gen, ino, gen, - name->start, fs_path_len(name)); + &fname); out: fs_path_free(name); @@ -2162,6 +2175,7 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx, int ret; int nce_ret; struct name_cache_entry *nce = NULL; + struct fscrypt_name fname; /* * First check if we already did a call to this function with the same @@ -2226,8 +2240,11 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx, * Check if the ref was overwritten by an inode's ref that was processed * earlier. If yes, treat as orphan and return 1. */ + fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(dest->start, fs_path_len(dest)) + }; ret = did_overwrite_ref(sctx, *parent_ino, *parent_gen, ino, gen, - dest->start, dest->end - dest->start); + &fname); if (ret < 0) goto out; if (ret) { @@ -3494,6 +3511,9 @@ static int wait_for_dest_dir_move(struct send_ctx *sctx, u64 right_gen; int ret = 0; struct waiting_dir_move *wdm; + struct fscrypt_name fname = { + .disk_name = FSTR_INIT(parent_ref->name, parent_ref->name_len) + }; if (RB_EMPTY_ROOT(&sctx->waiting_dir_moves)) return 0; @@ -3504,7 +3524,7 @@ static int wait_for_dest_dir_move(struct send_ctx *sctx, key.objectid = parent_ref->dir; key.type = BTRFS_DIR_ITEM_KEY; - key.offset = btrfs_name_hash(parent_ref->name, parent_ref->name_len); + key.offset = btrfs_name_hash(&fname); ret = btrfs_search_slot(NULL, sctx->parent_root, &key, path, 0, 0); if (ret < 0) { @@ -3514,8 +3534,7 @@ static int wait_for_dest_dir_move(struct send_ctx *sctx, goto out; } - di = btrfs_match_dir_item_name(fs_info, path, parent_ref->name, - parent_ref->name_len); + di = btrfs_match_dir_item_name(fs_info, path, &fname); if (!di) { ret = 0; goto out; @@ -3996,6 +4015,10 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move) * "testdir_2". */ list_for_each_entry(cur, &sctx->new_refs, list) { + struct fscrypt_name fname = { + .disk_name = FSTR_INIT(cur->name, cur->name_len) + }; + ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen); if (ret < 0) goto out; @@ -4009,14 +4032,12 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move) * simply unlink it. */ ret = will_overwrite_ref(sctx, cur->dir, cur->dir_gen, - cur->name, cur->name_len, - &ow_inode, &ow_gen, &ow_mode); + &fname, &ow_inode, &ow_gen, &ow_mode); if (ret < 0) goto out; if (ret) { ret = is_first_ref(sctx->parent_root, - ow_inode, cur->dir, cur->name, - cur->name_len); + ow_inode, cur->dir, &fname); if (ret < 0) goto out; if (ret) { @@ -4262,9 +4283,13 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move) * inodes. */ list_for_each_entry(cur, &sctx->deleted_refs, list) { + struct fscrypt_name fname = { + .disk_name = FSTR_INIT(cur->name, cur->name_len) + }; + ret = did_overwrite_ref(sctx, cur->dir, cur->dir_gen, sctx->cur_ino, sctx->cur_inode_gen, - cur->name, cur->name_len); + &fname); if (ret < 0) goto out; if (!ret) { @@ -4606,7 +4631,7 @@ static int process_all_refs(struct send_ctx *sctx, static int send_set_xattr(struct send_ctx *sctx, struct fs_path *path, - const char *name, int name_len, + struct fscrypt_name *fname, const char *data, int data_len) { int ret = 0; @@ -4616,7 +4641,8 @@ static int send_set_xattr(struct send_ctx *sctx, goto out; TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, path); - TLV_PUT_STRING(sctx, BTRFS_SEND_A_XATTR_NAME, name, name_len); + TLV_PUT_STRING(sctx, BTRFS_SEND_A_XATTR_NAME, fname_name(fname), + fname_len(fname)); TLV_PUT(sctx, BTRFS_SEND_A_XATTR_DATA, data, data_len); ret = send_cmd(sctx); @@ -4628,7 +4654,7 @@ static int send_set_xattr(struct send_ctx *sctx, static int send_remove_xattr(struct send_ctx *sctx, struct fs_path *path, - const char *name, int name_len) + struct fscrypt_name *fname) { int ret = 0; @@ -4637,7 +4663,8 @@ static int send_remove_xattr(struct send_ctx *sctx, goto out; TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, path); - TLV_PUT_STRING(sctx, BTRFS_SEND_A_XATTR_NAME, name, name_len); + TLV_PUT_STRING(sctx, BTRFS_SEND_A_XATTR_NAME, fname_name(fname), + fname_len(fname)); ret = send_cmd(sctx); @@ -4647,7 +4674,7 @@ static int send_remove_xattr(struct send_ctx *sctx, } static int __process_new_xattr(int num, struct btrfs_key *di_key, - const char *name, int name_len, const char *data, + struct fscrypt_name *fname, const char *data, int data_len, void *ctx) { int ret; @@ -4656,7 +4683,7 @@ static int __process_new_xattr(int num, struct btrfs_key *di_key, struct posix_acl_xattr_header dummy_acl; /* Capabilities are emitted by finish_inode_if_needed */ - if (!strncmp(name, XATTR_NAME_CAPS, name_len)) + if (!strncmp(fname_name(fname), XATTR_NAME_CAPS, fname_len(fname))) return 0; p = fs_path_alloc(); @@ -4669,8 +4696,10 @@ static int __process_new_xattr(int num, struct btrfs_key *di_key, * acls will fail later. To fix this, we send a dummy acl list that * only contains the version number and no entries. */ - if (!strncmp(name, XATTR_NAME_POSIX_ACL_ACCESS, name_len) || - !strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT, name_len)) { + if (!strncmp(fname_name(fname), XATTR_NAME_POSIX_ACL_ACCESS, + fname_len(fname)) || + !strncmp(fname_name(fname), XATTR_NAME_POSIX_ACL_DEFAULT, + fname_len(fname))) { if (data_len == 0) { dummy_acl.a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); @@ -4683,7 +4712,7 @@ static int __process_new_xattr(int num, struct btrfs_key *di_key, if (ret < 0) goto out; - ret = send_set_xattr(sctx, p, name, name_len, data, data_len); + ret = send_set_xattr(sctx, p, fname, data, data_len); out: fs_path_free(p); @@ -4691,7 +4720,7 @@ static int __process_new_xattr(int num, struct btrfs_key *di_key, } static int __process_deleted_xattr(int num, struct btrfs_key *di_key, - const char *name, int name_len, + struct fscrypt_name *fname, const char *data, int data_len, void *ctx) { int ret; @@ -4706,7 +4735,7 @@ static int __process_deleted_xattr(int num, struct btrfs_key *di_key, if (ret < 0) goto out; - ret = send_remove_xattr(sctx, p, name, name_len); + ret = send_remove_xattr(sctx, p, fname); out: fs_path_free(p); @@ -4730,20 +4759,21 @@ static int process_deleted_xattr(struct send_ctx *sctx) } struct find_xattr_ctx { - const char *name; - int name_len; + struct fscrypt_name *fname; int found_idx; char *found_data; int found_data_len; }; -static int __find_xattr(int num, struct btrfs_key *di_key, const char *name, - int name_len, const char *data, int data_len, void *vctx) +static int __find_xattr(int num, struct btrfs_key *di_key, + struct fscrypt_name *fname, + const char *data, int data_len, void *vctx) { struct find_xattr_ctx *ctx = vctx; - if (name_len == ctx->name_len && - strncmp(name, ctx->name, name_len) == 0) { + if (fname_len(fname) == fname_len(ctx->fname) && + strncmp(fname_name(fname), fname_name(ctx->fname), + fname_len(fname)) == 0) { ctx->found_idx = num; ctx->found_data_len = data_len; ctx->found_data = kmemdup(data, data_len, GFP_KERNEL); @@ -4757,14 +4787,13 @@ static int __find_xattr(int num, struct btrfs_key *di_key, const char *name, static int find_xattr(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *key, - const char *name, int name_len, + struct fscrypt_name *fname, char **data, int *data_len) { int ret; struct find_xattr_ctx ctx; - ctx.name = name; - ctx.name_len = name_len; + ctx.fname = fname; ctx.found_idx = -1; ctx.found_data = NULL; ctx.found_data_len = 0; @@ -4786,7 +4815,7 @@ static int find_xattr(struct btrfs_root *root, static int __process_changed_new_xattr(int num, struct btrfs_key *di_key, - const char *name, int name_len, + struct fscrypt_name *fname, const char *data, int data_len, void *ctx) { @@ -4796,15 +4825,15 @@ static int __process_changed_new_xattr(int num, struct btrfs_key *di_key, int found_data_len = 0; ret = find_xattr(sctx->parent_root, sctx->right_path, - sctx->cmp_key, name, name_len, &found_data, + sctx->cmp_key, fname, &found_data, &found_data_len); if (ret == -ENOENT) { - ret = __process_new_xattr(num, di_key, name, name_len, data, + ret = __process_new_xattr(num, di_key, fname, data, data_len, ctx); } else if (ret >= 0) { if (data_len != found_data_len || memcmp(data, found_data, data_len)) { - ret = __process_new_xattr(num, di_key, name, name_len, + ret = __process_new_xattr(num, di_key, fname, data, data_len, ctx); } else { ret = 0; @@ -4816,7 +4845,7 @@ static int __process_changed_new_xattr(int num, struct btrfs_key *di_key, } static int __process_changed_deleted_xattr(int num, struct btrfs_key *di_key, - const char *name, int name_len, + struct fscrypt_name *fname, const char *data, int data_len, void *ctx) { @@ -4824,9 +4853,9 @@ static int __process_changed_deleted_xattr(int num, struct btrfs_key *di_key, struct send_ctx *sctx = ctx; ret = find_xattr(sctx->send_root, sctx->left_path, sctx->cmp_key, - name, name_len, NULL, NULL); + fname, NULL, NULL); if (ret == -ENOENT) - ret = __process_deleted_xattr(num, di_key, name, name_len, data, + ret = __process_deleted_xattr(num, di_key, fname, data, data_len, ctx); else if (ret >= 0) ret = 0; @@ -5488,13 +5517,16 @@ static int send_capabilities(struct send_ctx *sctx) char *buf = NULL; int buf_len; int ret = 0; + struct fscrypt_name fname = { + .disk_name = FSTR_INIT(XATTR_NAME_CAPS, strlen(XATTR_NAME_CAPS)) + }; path = alloc_path_for_send(); if (!path) return -ENOMEM; di = btrfs_lookup_xattr(NULL, sctx->send_root, path, sctx->cur_ino, - XATTR_NAME_CAPS, strlen(XATTR_NAME_CAPS), 0); + &fname, 0); if (!di) { /* There is no xattr for this inode */ goto out; @@ -5520,8 +5552,7 @@ static int send_capabilities(struct send_ctx *sctx) data_ptr = (unsigned long)(di + 1) + btrfs_dir_name_len(leaf, di); read_extent_buffer(leaf, buf, data_ptr, buf_len); - ret = send_set_xattr(sctx, fspath, XATTR_NAME_CAPS, - strlen(XATTR_NAME_CAPS), buf, buf_len); + ret = send_set_xattr(sctx, fspath, &fname, buf, buf_len); out: kfree(buf); fs_path_free(fspath); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 4c7089b1681b..55af04fae075 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1390,6 +1390,9 @@ static int get_default_subvol_objectid(struct btrfs_fs_info *fs_info, u64 *objec struct btrfs_path *path; struct btrfs_key location; u64 dir_id; + struct fscrypt_name fname = { + .disk_name = FSTR_INIT("default", 7), + }; path = btrfs_alloc_path(); if (!path) @@ -1401,7 +1404,7 @@ static int get_default_subvol_objectid(struct btrfs_fs_info *fs_info, u64 *objec * to mount. */ dir_id = btrfs_super_root_dir(fs_info->super_copy); - di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0); + di = btrfs_lookup_dir_item(NULL, root, path, dir_id, &fname, 0); if (IS_ERR(di)) { btrfs_free_path(path); return PTR_ERR(di); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 0bec10740ad3..fe705e3a615e 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1614,8 +1614,9 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, * happens, we should return the error number. If the error which just affect * the creation of the pending snapshots, just return 0. */ -static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, - struct btrfs_pending_snapshot *pending) +static noinline int +create_pending_snapshot(struct btrfs_trans_handle *trans, + struct btrfs_pending_snapshot *pending) { struct btrfs_fs_info *fs_info = trans->fs_info; @@ -1625,10 +1626,9 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root *root = pending->root; struct btrfs_root *parent_root; struct btrfs_block_rsv *rsv; - struct inode *parent_inode; + struct inode *parent_inode = pending->dir; struct btrfs_path *path; struct btrfs_dir_item *dir_item; - struct dentry *dentry; struct extent_buffer *tmp; struct extent_buffer *old; struct timespec64 cur_time; @@ -1637,6 +1637,10 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, u64 index = 0; u64 objectid; u64 root_flags; + struct fscrypt_name fname = { + .disk_name = FSTR_INIT((char *) pending->dentry->d_name.name, + pending->dentry->d_name.len) + }; ASSERT(pending->path); path = pending->path; @@ -1675,7 +1679,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, trace_btrfs_space_reservation(fs_info, "transaction", trans->transid, trans->bytes_reserved, 1); - dentry = pending->dentry; parent_inode = pending->dir; parent_root = BTRFS_I(parent_inode)->root; ret = record_root_in_trans(trans, parent_root, 0); @@ -1692,8 +1695,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, /* check if there is a file/dir which has the same name. */ dir_item = btrfs_lookup_dir_item(NULL, parent_root, path, btrfs_ino(BTRFS_I(parent_inode)), - dentry->d_name.name, - dentry->d_name.len, 0); + &fname, 0); if (dir_item != NULL && !IS_ERR(dir_item)) { pending->error = -EEXIST; goto dir_item_existed; @@ -1788,7 +1790,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ret = btrfs_add_root_ref(trans, objectid, parent_root->root_key.objectid, btrfs_ino(BTRFS_I(parent_inode)), index, - dentry->d_name.name, dentry->d_name.len); + &fname); if (ret) { btrfs_abort_transaction(trans, ret); goto fail; @@ -1820,8 +1822,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, if (ret < 0) goto fail; - ret = btrfs_insert_dir_item(trans, dentry->d_name.name, - dentry->d_name.len, BTRFS_I(parent_inode), + ret = btrfs_insert_dir_item(trans, &fname, BTRFS_I(parent_inode), &key, BTRFS_FT_DIR, index); /* We have check then name at the beginning, so it is impossible. */ BUG_ON(ret == -EEXIST || ret == -EOVERFLOW); @@ -1830,8 +1831,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, goto fail; } - btrfs_i_size_write(BTRFS_I(parent_inode), parent_inode->i_size + - dentry->d_name.len * 2); + btrfs_i_size_write(BTRFS_I(parent_inode), + parent_inode->i_size + fname_len(&fname) * 2); parent_inode->i_mtime = current_time(parent_inode); parent_inode->i_ctime = parent_inode->i_mtime; ret = btrfs_update_inode_fallback(trans, parent_root, BTRFS_I(parent_inode)); diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index dd3218c2ca51..f861cc52be41 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -595,10 +595,14 @@ static int check_dir_item(struct extent_buffer *leaf, if (key->type == BTRFS_DIR_ITEM_KEY || key->type == BTRFS_XATTR_ITEM_KEY) { char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)]; + struct fscrypt_name fname; read_extent_buffer(leaf, namebuf, (unsigned long)(di + 1), name_len); - name_hash = btrfs_name_hash(namebuf, name_len); + fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(namebuf, name_len) + }; + name_hash = btrfs_name_hash(&fname); if (unlikely(key->offset != name_hash)) { dir_item_err(leaf, slot, "name hash mismatch with key, have 0x%016x expect 0x%016llx", diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 2762b57bd4de..51a706e84e00 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -901,12 +901,11 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, static int unlink_inode_for_log_replay(struct btrfs_trans_handle *trans, struct btrfs_inode *dir, struct btrfs_inode *inode, - const char *name, - int name_len) + const struct fscrypt_name *fname) { int ret; - ret = btrfs_unlink_inode(trans, dir, inode, name, name_len); + ret = btrfs_unlink_inode(trans, dir, inode, fname); if (ret) return ret; /* @@ -938,6 +937,7 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans, struct extent_buffer *leaf; struct btrfs_key location; int ret; + struct fscrypt_name fname; leaf = path->nodes[0]; @@ -950,6 +950,10 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans, read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len); btrfs_release_path(path); + fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(name, name_len) + }; + inode = read_one_inode(root, location.objectid); if (!inode) { ret = -EIO; @@ -960,8 +964,7 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans, if (ret) goto out; - ret = unlink_inode_for_log_replay(trans, dir, BTRFS_I(inode), name, - name_len); + ret = unlink_inode_for_log_replay(trans, dir, BTRFS_I(inode), &fname); out: kfree(name); iput(inode); @@ -978,14 +981,14 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans, static noinline int inode_in_dir(struct btrfs_root *root, struct btrfs_path *path, u64 dirid, u64 objectid, u64 index, - const char *name, int name_len) + const struct fscrypt_name *fname) { struct btrfs_dir_item *di; struct btrfs_key location; int ret = 0; di = btrfs_lookup_dir_index_item(NULL, root, path, dirid, - index, name, name_len, 0); + index, fname, 0); if (IS_ERR(di)) { ret = PTR_ERR(di); goto out; @@ -998,7 +1001,7 @@ static noinline int inode_in_dir(struct btrfs_root *root, } btrfs_release_path(path); - di = btrfs_lookup_dir_item(NULL, root, path, dirid, name, name_len, 0); + di = btrfs_lookup_dir_item(NULL, root, path, dirid, fname, 0); if (IS_ERR(di)) { ret = PTR_ERR(di); goto out; @@ -1025,7 +1028,7 @@ static noinline int inode_in_dir(struct btrfs_root *root, static noinline int backref_in_log(struct btrfs_root *log, struct btrfs_key *key, u64 ref_objectid, - const char *name, int namelen) + struct fscrypt_name *fname) { struct btrfs_path *path; int ret; @@ -1046,11 +1049,11 @@ static noinline int backref_in_log(struct btrfs_root *log, ret = !!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], ref_objectid, - name, namelen); + fname); else ret = !!btrfs_find_name_in_backref(path->nodes[0], path->slots[0], - name, namelen); + fname); out: btrfs_free_path(path); return ret; @@ -1063,7 +1066,8 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_inode *dir, struct btrfs_inode *inode, u64 inode_objectid, u64 parent_objectid, - u64 ref_index, char *name, int namelen, + u64 ref_index, + struct fscrypt_name *fname, int *search_done) { int ret; @@ -1100,6 +1104,7 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); ptr_end = ptr + btrfs_item_size(leaf, path->slots[0]); while (ptr < ptr_end) { + struct fscrypt_name victim_fname; victim_ref = (struct btrfs_inode_ref *)ptr; victim_name_len = btrfs_inode_ref_name_len(leaf, victim_ref); @@ -1110,10 +1115,12 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, read_extent_buffer(leaf, victim_name, (unsigned long)(victim_ref + 1), victim_name_len); + victim_fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(victim_name, victim_name_len) + }; ret = backref_in_log(log_root, &search_key, - parent_objectid, victim_name, - victim_name_len); + parent_objectid, &victim_fname); if (ret < 0) { kfree(victim_name); return ret; @@ -1121,8 +1128,8 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, inc_nlink(&inode->vfs_inode); btrfs_release_path(path); - ret = unlink_inode_for_log_replay(trans, dir, inode, - victim_name, victim_name_len); + ret = unlink_inode_for_log_replay(trans, + dir, inode, &victim_fname); kfree(victim_name); if (ret) return ret; @@ -1143,7 +1150,7 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, btrfs_release_path(path); /* Same search but for extended refs */ - extref = btrfs_lookup_inode_extref(NULL, root, path, name, namelen, + extref = btrfs_lookup_inode_extref(NULL, root, path, fname, inode_objectid, parent_objectid, 0, 0); if (!IS_ERR_OR_NULL(extref)) { @@ -1158,6 +1165,7 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, base = btrfs_item_ptr_offset(leaf, path->slots[0]); while (cur_offset < item_size) { + struct fscrypt_name victim_fname; extref = (struct btrfs_inode_extref *)(base + cur_offset); victim_name_len = btrfs_inode_extref_name_len(leaf, extref); @@ -1171,14 +1179,15 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, read_extent_buffer(leaf, victim_name, (unsigned long)&extref->name, victim_name_len); + victim_fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(victim_name, victim_name_len), + }; + search_key.objectid = inode_objectid; search_key.type = BTRFS_INODE_EXTREF_KEY; - search_key.offset = btrfs_extref_hash(parent_objectid, - victim_name, - victim_name_len); + search_key.offset = btrfs_extref_hash(parent_objectid, &victim_fname); ret = backref_in_log(log_root, &search_key, - parent_objectid, victim_name, - victim_name_len); + parent_objectid, &victim_fname); if (ret < 0) { kfree(victim_name); return ret; @@ -1192,9 +1201,7 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, ret = unlink_inode_for_log_replay(trans, BTRFS_I(victim_parent), - inode, - victim_name, - victim_name_len); + inode, &victim_fname); } iput(victim_parent); kfree(victim_name); @@ -1213,7 +1220,7 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, /* look for a conflicting sequence number */ di = btrfs_lookup_dir_index_item(trans, root, path, btrfs_ino(dir), - ref_index, name, namelen, 0); + ref_index, fname, 0); if (IS_ERR(di)) { return PTR_ERR(di); } else if (di) { @@ -1225,7 +1232,7 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, /* look for a conflicting name */ di = btrfs_lookup_dir_item(trans, root, path, btrfs_ino(dir), - name, namelen, 0); + fname, 0); if (IS_ERR(di)) { return PTR_ERR(di); } else if (di) { @@ -1239,20 +1246,24 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans, } static int extref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr, - u32 *namelen, char **name, u64 *index, + struct fscrypt_name *fname, u64 *index, u64 *parent_objectid) { struct btrfs_inode_extref *extref; - + u32 namelen; + char *name; extref = (struct btrfs_inode_extref *)ref_ptr; - *namelen = btrfs_inode_extref_name_len(eb, extref); - *name = kmalloc(*namelen, GFP_NOFS); - if (*name == NULL) + namelen = btrfs_inode_extref_name_len(eb, extref); + name = kmalloc(namelen, GFP_NOFS); + if (name == NULL) return -ENOMEM; - read_extent_buffer(eb, *name, (unsigned long)&extref->name, - *namelen); + read_extent_buffer(eb, name, (unsigned long)&extref->name, + namelen); + *fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(name, namelen) + }; if (index) *index = btrfs_inode_extref_index(eb, extref); @@ -1263,18 +1274,22 @@ static int extref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr, } static int ref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr, - u32 *namelen, char **name, u64 *index) + struct fscrypt_name *fname, u64 *index) { struct btrfs_inode_ref *ref; - + u32 namelen; + char *name; ref = (struct btrfs_inode_ref *)ref_ptr; - *namelen = btrfs_inode_ref_name_len(eb, ref); - *name = kmalloc(*namelen, GFP_NOFS); - if (*name == NULL) + namelen = btrfs_inode_ref_name_len(eb, ref); + name = kmalloc(namelen, GFP_NOFS); + if (name == NULL) return -ENOMEM; - read_extent_buffer(eb, *name, (unsigned long)(ref + 1), *namelen); + read_extent_buffer(eb, name, (unsigned long)(ref + 1), namelen); + *fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(name, namelen) + }; if (index) *index = btrfs_inode_ref_index(eb, ref); @@ -1316,16 +1331,15 @@ static int unlink_old_inode_refs(struct btrfs_trans_handle *trans, ref_ptr = btrfs_item_ptr_offset(eb, path->slots[0]); ref_end = ref_ptr + btrfs_item_size(eb, path->slots[0]); while (ref_ptr < ref_end) { - char *name = NULL; - int namelen; u64 parent_id; + struct fscrypt_name fname; if (key->type == BTRFS_INODE_EXTREF_KEY) { - ret = extref_get_fields(eb, ref_ptr, &namelen, &name, + ret = extref_get_fields(eb, ref_ptr, &fname, NULL, &parent_id); } else { parent_id = key->offset; - ret = ref_get_fields(eb, ref_ptr, &namelen, &name, + ret = ref_get_fields(eb, ref_ptr, &fname, NULL); } if (ret) @@ -1333,11 +1347,11 @@ static int unlink_old_inode_refs(struct btrfs_trans_handle *trans, if (key->type == BTRFS_INODE_EXTREF_KEY) ret = !!btrfs_find_name_in_ext_backref(log_eb, log_slot, - parent_id, name, - namelen); + parent_id, + &fname); else ret = !!btrfs_find_name_in_backref(log_eb, log_slot, - name, namelen); + &fname); if (!ret) { struct inode *dir; @@ -1346,20 +1360,20 @@ static int unlink_old_inode_refs(struct btrfs_trans_handle *trans, dir = read_one_inode(root, parent_id); if (!dir) { ret = -ENOENT; - kfree(name); + kfree(fname_name(&fname)); goto out; } ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), - inode, name, namelen); - kfree(name); + inode, &fname); + kfree(fname_name(&fname)); iput(dir); if (ret) goto out; goto again; } - kfree(name); - ref_ptr += namelen; + kfree(fname_name(&fname)); + ref_ptr += fname_len(&fname); if (key->type == BTRFS_INODE_EXTREF_KEY) ref_ptr += sizeof(struct btrfs_inode_extref); else @@ -1372,8 +1386,7 @@ static int unlink_old_inode_refs(struct btrfs_trans_handle *trans, } static int btrfs_inode_ref_exists(struct inode *inode, struct inode *dir, - const u8 ref_type, const char *name, - const int namelen) + const u8 ref_type, struct fscrypt_name *fname) { struct btrfs_key key; struct btrfs_path *path; @@ -1389,7 +1402,7 @@ static int btrfs_inode_ref_exists(struct inode *inode, struct inode *dir, if (key.type == BTRFS_INODE_REF_KEY) key.offset = parent_id; else - key.offset = btrfs_extref_hash(parent_id, name, namelen); + key.offset = btrfs_extref_hash(parent_id, fname); ret = btrfs_search_slot(NULL, BTRFS_I(inode)->root, &key, path, 0, 0); if (ret < 0) @@ -1400,10 +1413,10 @@ static int btrfs_inode_ref_exists(struct inode *inode, struct inode *dir, } if (key.type == BTRFS_INODE_EXTREF_KEY) ret = !!btrfs_find_name_in_ext_backref(path->nodes[0], - path->slots[0], parent_id, name, namelen); + path->slots[0], parent_id, fname); else ret = !!btrfs_find_name_in_backref(path->nodes[0], path->slots[0], - name, namelen); + fname); out: btrfs_free_path(path); @@ -1411,8 +1424,8 @@ static int btrfs_inode_ref_exists(struct inode *inode, struct inode *dir, } static int add_link(struct btrfs_trans_handle *trans, - struct inode *dir, struct inode *inode, const char *name, - int namelen, u64 ref_index) + struct inode *dir, struct inode *inode, + struct fscrypt_name *fname, u64 ref_index) { struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_dir_item *dir_item; @@ -1427,7 +1440,7 @@ static int add_link(struct btrfs_trans_handle *trans, dir_item = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(BTRFS_I(dir)), - name, namelen, 0); + fname, 0); if (!dir_item) { btrfs_release_path(path); goto add_link; @@ -1448,8 +1461,8 @@ static int add_link(struct btrfs_trans_handle *trans, ret = -ENOENT; goto out; } - ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), BTRFS_I(other_inode), - name, namelen); + ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), + BTRFS_I(other_inode), fname); if (ret) goto out; /* @@ -1459,8 +1472,8 @@ static int add_link(struct btrfs_trans_handle *trans, if (other_inode->i_nlink == 0) inc_nlink(other_inode); add_link: - ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), - name, namelen, 0, ref_index); + ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), fname, 0, + ref_index); out: iput(other_inode); btrfs_free_path(path); @@ -1485,8 +1498,6 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, struct inode *inode = NULL; unsigned long ref_ptr; unsigned long ref_end; - char *name = NULL; - int namelen; int ret; int search_done = 0; int log_ref_ver = 0; @@ -1530,8 +1541,9 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, } while (ref_ptr < ref_end) { + struct fscrypt_name fname; if (log_ref_ver) { - ret = extref_get_fields(eb, ref_ptr, &namelen, &name, + ret = extref_get_fields(eb, ref_ptr, &fname, &ref_index, &parent_objectid); /* * parent object can change from one array @@ -1544,7 +1556,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, goto out; } } else { - ret = ref_get_fields(eb, ref_ptr, &namelen, &name, + ret = ref_get_fields(eb, ref_ptr, &fname, &ref_index); } if (ret) @@ -1552,7 +1564,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ret = inode_in_dir(root, path, btrfs_ino(BTRFS_I(dir)), btrfs_ino(BTRFS_I(inode)), ref_index, - name, namelen); + &fname); if (ret < 0) { goto out; } else if (ret == 0) { @@ -1570,7 +1582,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, BTRFS_I(inode), inode_objectid, parent_objectid, - ref_index, name, namelen, + ref_index, &fname, &search_done); if (ret) { if (ret == 1) @@ -1588,12 +1600,12 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, * -EEXIST returned from btrfs_add_link() below. */ ret = btrfs_inode_ref_exists(inode, dir, key->type, - name, namelen); + &fname); if (ret > 0) { ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), BTRFS_I(inode), - name, namelen); + &fname); /* * If we dropped the link count to 0, bump it so * that later the iput() on the inode will not @@ -1606,8 +1618,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, goto out; /* insert our name */ - ret = add_link(trans, dir, inode, name, namelen, - ref_index); + ret = add_link(trans, dir, inode, &fname, ref_index); if (ret) goto out; @@ -1617,9 +1628,8 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, } /* Else, ret == 1, we already have a perfect match, we're done. */ - ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + namelen; - kfree(name); - name = NULL; + ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + fname_len(&fname); + kfree(fname_name(&fname)); if (log_ref_ver) { iput(dir); dir = NULL; @@ -1643,7 +1653,6 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ret = overwrite_item(trans, root, path, eb, slot, key); out: btrfs_release_path(path); - kfree(name); iput(dir); iput(inode); return ret; @@ -1915,7 +1924,7 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans, static noinline int insert_one_name(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 dirid, u64 index, - char *name, int name_len, + struct fscrypt_name *fname, struct btrfs_key *location) { struct inode *inode; @@ -1932,8 +1941,8 @@ static noinline int insert_one_name(struct btrfs_trans_handle *trans, return -EIO; } - ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), name, - name_len, 1, index); + ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), fname, 1, + index); /* FIXME, put inode into FIXUP list */ @@ -2007,6 +2016,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, int ret; bool update_size = true; bool name_added = false; + struct fscrypt_name fname; dir = read_one_inode(root, key->objectid); if (!dir) @@ -2022,6 +2032,9 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, log_flags = btrfs_dir_flags(eb, di); read_extent_buffer(eb, name, (unsigned long)(di + 1), name_len); + fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(name, name_len) + }; btrfs_dir_item_key_to_cpu(eb, di, &log_key); ret = btrfs_lookup_inode(trans, root, path, &log_key, 0); @@ -2032,7 +2045,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, ret = 0; dir_dst_di = btrfs_lookup_dir_item(trans, root, path, key->objectid, - name, name_len, 1); + &fname, 1); if (IS_ERR(dir_dst_di)) { ret = PTR_ERR(dir_dst_di); goto out; @@ -2049,7 +2062,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, index_dst_di = btrfs_lookup_dir_index_item(trans, root, path, key->objectid, key->offset, - name, name_len, 1); + &fname, 1); if (IS_ERR(index_dst_di)) { ret = PTR_ERR(index_dst_di); goto out; @@ -2077,7 +2090,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, search_key.objectid = log_key.objectid; search_key.type = BTRFS_INODE_REF_KEY; search_key.offset = key->objectid; - ret = backref_in_log(root->log_root, &search_key, 0, name, name_len); + ret = backref_in_log(root->log_root, &search_key, 0, &fname); if (ret < 0) { goto out; } else if (ret) { @@ -2090,8 +2103,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, search_key.objectid = log_key.objectid; search_key.type = BTRFS_INODE_EXTREF_KEY; search_key.offset = key->objectid; - ret = backref_in_log(root->log_root, &search_key, key->objectid, name, - name_len); + ret = backref_in_log(root->log_root, &search_key, key->objectid, &fname); if (ret < 0) { goto out; } else if (ret) { @@ -2102,7 +2114,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, } btrfs_release_path(path); ret = insert_one_name(trans, root, key->objectid, key->offset, - name, name_len, &log_key); + &fname, &log_key); if (ret && ret != -ENOENT && ret != -EEXIST) goto out; if (!ret) @@ -2285,6 +2297,7 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans, char *name; struct inode *inode = NULL; struct btrfs_key location; + struct fscrypt_name fname; /* * Currently we only log dir index keys. Even if we replay a log created @@ -2305,6 +2318,9 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans, } read_extent_buffer(eb, name, (unsigned long)(di + 1), name_len); + fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(name, name_len) + }; if (log) { struct btrfs_dir_item *log_di; @@ -2312,7 +2328,7 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans, log_di = btrfs_lookup_dir_index_item(trans, log, log_path, dir_key->objectid, dir_key->offset, - name, name_len, 0); + &fname, 0); if (IS_ERR(log_di)) { ret = PTR_ERR(log_di); goto out; @@ -2337,8 +2353,8 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans, goto out; inc_nlink(inode); - ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), BTRFS_I(inode), - name, name_len); + ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), + BTRFS_I(inode), &fname); /* * Unlike dir item keys, dir index keys can only have one name (entry) in * them, as there are no key collisions since each key has a unique offset @@ -2398,6 +2414,7 @@ static int replay_xattr_deletes(struct btrfs_trans_handle *trans, u16 data_len = btrfs_dir_data_len(path->nodes[0], di); u32 this_len = sizeof(*di) + name_len + data_len; char *name; + struct fscrypt_name fname; name = kmalloc(name_len, GFP_NOFS); if (!name) { @@ -2406,15 +2423,18 @@ static int replay_xattr_deletes(struct btrfs_trans_handle *trans, } read_extent_buffer(path->nodes[0], name, (unsigned long)(di + 1), name_len); + fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(name, name_len) + }; log_di = btrfs_lookup_xattr(NULL, log, log_path, ino, - name, name_len, 0); + &fname, 0); btrfs_release_path(log_path); if (!log_di) { /* Doesn't exist in log tree, so delete it. */ btrfs_release_path(path); di = btrfs_lookup_xattr(trans, root, path, ino, - name, name_len, -1); + &fname, -1); kfree(name); if (IS_ERR(di)) { ret = PTR_ERR(di); @@ -3586,7 +3606,7 @@ static int del_logged_dentry(struct btrfs_trans_handle *trans, struct btrfs_root *log, struct btrfs_path *path, u64 dir_ino, - const char *name, int name_len, + const struct fscrypt_name *fname, u64 index) { struct btrfs_dir_item *di; @@ -3596,7 +3616,7 @@ static int del_logged_dentry(struct btrfs_trans_handle *trans, * for dir item keys. */ di = btrfs_lookup_dir_index_item(trans, log, path, dir_ino, - index, name, name_len, -1); + index, fname, -1); if (IS_ERR(di)) return PTR_ERR(di); else if (!di) @@ -3633,7 +3653,7 @@ static int del_logged_dentry(struct btrfs_trans_handle *trans, */ void btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, struct btrfs_root *root, - const char *name, int name_len, + const struct fscrypt_name *fname, struct btrfs_inode *dir, u64 index) { struct btrfs_path *path; @@ -3660,7 +3680,7 @@ void btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, } ret = del_logged_dentry(trans, root->log_root, path, btrfs_ino(dir), - name, name_len, index); + fname, index); btrfs_free_path(path); out_unlock: mutex_unlock(&dir->log_mutex); @@ -3672,7 +3692,7 @@ void btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, /* see comments for btrfs_del_dir_entries_in_log */ void btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans, struct btrfs_root *root, - const char *name, int name_len, + const struct fscrypt_name *fname, struct btrfs_inode *inode, u64 dirid) { struct btrfs_root *log; @@ -3693,7 +3713,7 @@ void btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans, log = root->log_root; mutex_lock(&inode->log_mutex); - ret = btrfs_del_inode_ref(trans, log, name, name_len, btrfs_ino(inode), + ret = btrfs_del_inode_ref(trans, log, fname, btrfs_ino(inode), dirid, &index); mutex_unlock(&inode->log_mutex); if (ret < 0 && ret != -ENOENT) @@ -5327,6 +5347,7 @@ static int btrfs_check_ref_name_override(struct extent_buffer *eb, u32 this_len; unsigned long name_ptr; struct btrfs_dir_item *di; + struct fscrypt_name fname; if (key->type == BTRFS_INODE_REF_KEY) { struct btrfs_inode_ref *iref; @@ -5360,8 +5381,12 @@ static int btrfs_check_ref_name_override(struct extent_buffer *eb, } read_extent_buffer(eb, name, name_ptr, this_name_len); + fname = (struct fscrypt_name) { + .disk_name = FSTR_INIT(name, this_name_len) + }; + di = btrfs_lookup_dir_item(NULL, inode->root, search_path, - parent, name, this_name_len, 0); + parent, &fname, 0); if (di && !IS_ERR(di)) { struct btrfs_key di_key; @@ -7017,6 +7042,10 @@ void btrfs_log_new_name(struct btrfs_trans_handle *trans, if (old_dir && old_dir->logged_trans == trans->transid) { struct btrfs_root *log = old_dir->root->log_root; struct btrfs_path *path; + struct fscrypt_name fname = { + .disk_name = FSTR_INIT((char *) old_dentry->d_name.name, + old_dentry->d_name.len) + }; ASSERT(old_dir_index >= BTRFS_DIR_START_INDEX); @@ -7054,8 +7083,7 @@ void btrfs_log_new_name(struct btrfs_trans_handle *trans, */ mutex_lock(&old_dir->log_mutex); ret = del_logged_dentry(trans, log, path, btrfs_ino(old_dir), - old_dentry->d_name.name, - old_dentry->d_name.len, old_dir_index); + &fname, old_dir_index); if (ret > 0) { /* * The dentry does not exist in the log, so record its diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h index 57ab5f3b8dc7..76ec8d353a05 100644 --- a/fs/btrfs/tree-log.h +++ b/fs/btrfs/tree-log.h @@ -78,11 +78,11 @@ int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, struct btrfs_log_ctx *ctx); void btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, struct btrfs_root *root, - const char *name, int name_len, + const struct fscrypt_name *name, struct btrfs_inode *dir, u64 index); void btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans, struct btrfs_root *root, - const char *name, int name_len, + const struct fscrypt_name *name, struct btrfs_inode *inode, u64 dirid); void btrfs_end_log_trans(struct btrfs_root *root); void btrfs_pin_log_trans(struct btrfs_root *root); diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index 7421abcf325a..d2d484aaaca9 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c @@ -21,7 +21,7 @@ #include "locking.h" int btrfs_getxattr(struct inode *inode, const char *name, - void *buffer, size_t size) + void *buffer, size_t size) { struct btrfs_dir_item *di; struct btrfs_root *root = BTRFS_I(inode)->root; @@ -29,6 +29,9 @@ int btrfs_getxattr(struct inode *inode, const char *name, struct extent_buffer *leaf; int ret = 0; unsigned long data_ptr; + struct fscrypt_name fname = { + .disk_name = FSTR_INIT((char *) name, strlen(name)) + }; path = btrfs_alloc_path(); if (!path) @@ -36,7 +39,7 @@ int btrfs_getxattr(struct inode *inode, const char *name, /* lookup the xattr by name */ di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(BTRFS_I(inode)), - name, strlen(name), 0); + &fname, 0); if (!di) { ret = -ENODATA; goto out; @@ -85,6 +88,10 @@ int btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, struct btrfs_path *path; size_t name_len = strlen(name); int ret = 0; + struct fscrypt_name fname = { + .disk_name = FSTR_INIT((char *) name, name_len) + }; + ASSERT(trans); @@ -98,7 +105,7 @@ int btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, if (!value) { di = btrfs_lookup_xattr(trans, root, path, - btrfs_ino(BTRFS_I(inode)), name, name_len, -1); + btrfs_ino(BTRFS_I(inode)), &fname, -1); if (!di && (flags & XATTR_REPLACE)) ret = -ENODATA; else if (IS_ERR(di)) @@ -118,7 +125,7 @@ int btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, if (flags & XATTR_REPLACE) { ASSERT(inode_is_locked(inode)); di = btrfs_lookup_xattr(NULL, root, path, - btrfs_ino(BTRFS_I(inode)), name, name_len, 0); + btrfs_ino(BTRFS_I(inode)), &fname, 0); if (!di) ret = -ENODATA; else if (IS_ERR(di)) @@ -130,7 +137,7 @@ int btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, } ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(BTRFS_I(inode)), - name, name_len, value, size); + &fname, value, size); if (ret == -EOVERFLOW) { /* * We have an existing item in a leaf, split_leaf couldn't @@ -139,14 +146,14 @@ int btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, */ ret = 0; btrfs_assert_tree_write_locked(path->nodes[0]); - di = btrfs_match_dir_item_name(fs_info, path, name, name_len); + di = btrfs_match_dir_item_name(fs_info, path, &fname); if (!di && !(flags & XATTR_REPLACE)) { ret = -ENOSPC; goto out; } } else if (ret == -EEXIST) { ret = 0; - di = btrfs_match_dir_item_name(fs_info, path, name, name_len); + di = btrfs_match_dir_item_name(fs_info, path, &fname); ASSERT(di); /* logic error */ } else if (ret) { goto out; From patchwork Sun Jul 24 00:53:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927393 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2930CC43334 for ; Sun, 24 Jul 2022 00:54:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239204AbiGXAyd (ORCPT ); Sat, 23 Jul 2022 20:54:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38518 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239205AbiGXAyb (ORCPT ); Sat, 23 Jul 2022 20:54:31 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F2EF015A31; Sat, 23 Jul 2022 17:54:27 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 3231380BB8; Sat, 23 Jul 2022 20:54:26 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624067; bh=KMwdQ6jAOvtGoMIPsbcGzqZbBHsSZvYnkfyOv2An2yw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WmDUj6qv6wKQsNL7DT3Gcnqv+XG4UD9MfaQDcSyDEoclpMYezUhjOmyj4YwYcoili ffdM2364z8PXr42UgtmTatL7h2vyC5vhaGkWtPhk1vNKHYw8rvHAudVGyqwVV+/fMM hUlfrvvknupOQQvo0btze4zkZJ4OcvydOTDNVH1D61XFk0jqqoWzUNOoUmE2uiD5hD 56+PY8kjz7GfsPquCCkW+kN3gQ/zesxHhoM6ZusWKOSfSVUGVDTIjThNBLHNd+yJeX Qy50fJVbd1tjUJ/ziaAsBOg1tGbD+gGzunCfFlMZlhNbFUwJ8tqbS6XJscqJt9jEHM c97GpxqY5Sccw== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 03/16] btrfs: setup fscrypt_names from dentrys using helper Date: Sat, 23 Jul 2022 20:53:48 -0400 Message-Id: <2ecf66c3f7e99bb6cfa0da31a29638efeb8233f4.1658623319.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Most places that we create fscrypt_names, we are doing so from a dentry. Fscrypt provides a helper for this common pattern: fscrypt_setup_filename() initializes a filename to search for from a dentry, performing encryption of the plaintext if it can and should be done. This converts each setup of a fscrypt_name from a dentry to use this helper; at present, since there are no encrypted directories, nothing goes down the filename encryption paths. Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/inode.c | 153 ++++++++++++++++++++++++++--------------- fs/btrfs/transaction.c | 26 +++++-- fs/btrfs/tree-log.c | 12 ++-- 3 files changed, 123 insertions(+), 68 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5b3406f79db8..3d2e8d9e2fd2 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4406,14 +4406,17 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) struct btrfs_trans_handle *trans; struct inode *inode = d_inode(dentry); int ret; - struct fscrypt_name fname = { - .disk_name = FSTR_INIT((unsigned char *)dentry->d_name.name, dentry->d_name.len) - }; + struct fscrypt_name fname; + ret = fscrypt_setup_filename(dir, &dentry->d_name, 1, &fname); + if (ret) + return ret; trans = __unlink_start_trans(dir); - if (IS_ERR(trans)) - return PTR_ERR(trans); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out; + } btrfs_record_unlink_dir(trans, BTRFS_I(dir), BTRFS_I(d_inode(dentry)), 0); @@ -4430,6 +4433,7 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) } out: + fscrypt_free_filename(&fname); btrfs_end_transaction(trans); btrfs_btree_balance_dirty(BTRFS_I(dir)->root->fs_info); return ret; @@ -4448,10 +4452,11 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, int ret; u64 objectid; u64 dir_ino = btrfs_ino(BTRFS_I(dir)); - struct fscrypt_name fname = { - .disk_name = FSTR_INIT((char *) dentry->d_name.name, - dentry->d_name.len) - }; + struct fscrypt_name fname; + + ret = fscrypt_setup_filename(dir, &dentry->d_name, 1, &fname); + if (ret) + return ret; if (btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID) { objectid = inode->root->root_key.objectid; @@ -4459,12 +4464,15 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, objectid = inode->location.objectid; } else { WARN_ON(1); + fscrypt_free_filename(&fname); return -EINVAL; } path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; + if (!path) { + ret = -ENOMEM; + goto out; + } di = btrfs_lookup_dir_item(trans, root, path, dir_ino, &fname, -1); if (IS_ERR_OR_NULL(di)) { @@ -4531,6 +4539,7 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, btrfs_abort_transaction(trans, ret); out: btrfs_free_path(path); + fscrypt_free_filename(&fname); return ret; } @@ -4797,9 +4806,7 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) int err = 0; struct btrfs_trans_handle *trans; u64 last_unlink_trans; - struct fscrypt_name fname = { - .disk_name = FSTR_INIT((unsigned char *)dentry->d_name.name, dentry->d_name.len) - }; + struct fscrypt_name fname; if (inode->i_size > BTRFS_EMPTY_DIR_SIZE) return -ENOTEMPTY; @@ -4812,9 +4819,15 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) return btrfs_delete_subvolume(dir, dentry); } + err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &fname); + if (err) + return err; + trans = __unlink_start_trans(dir); - if (IS_ERR(trans)) - return PTR_ERR(trans); + if (IS_ERR(trans)) { + err = PTR_ERR(trans); + goto out_notrans; + } if (unlikely(btrfs_ino(BTRFS_I(inode)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) { err = btrfs_unlink_subvol(trans, dir, dentry); @@ -4848,7 +4861,9 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) } out: btrfs_end_transaction(trans); +out_notrans: btrfs_btree_balance_dirty(fs_info); + fscrypt_free_filename(&fname); return err; } @@ -5543,7 +5558,7 @@ void btrfs_evict_inode(struct inode *inode) /* * Return the key found in the dir entry in the location pointer, fill @type - * with BTRFS_FT_*, and return 0. + * with BTRFS_FT_*, and return 0. Used only for lookups, not removals. * * If no dir entries were found, returns -ENOENT. * If found a corrupted location in dir entry, returns -EUCLEAN. @@ -5555,15 +5570,16 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, struct btrfs_path *path; struct btrfs_root *root = BTRFS_I(dir)->root; int ret = 0; - struct fscrypt_name fname = { - .disk_name = FSTR_INIT((char *) dentry->d_name.name, - dentry->d_name.len) - }; + struct fscrypt_name fname; path = btrfs_alloc_path(); if (!path) return -ENOMEM; + ret = fscrypt_setup_filename(dir, &dentry->d_name, 1, &fname); + if (ret) + goto out; + di = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(BTRFS_I(dir)), &fname, 0); if (IS_ERR_OR_NULL(di)) { @@ -5583,6 +5599,7 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, if (!ret) *type = btrfs_dir_ftype(path->nodes[0], di); out: + fscrypt_free_filename(&fname); btrfs_free_path(path); return ret; } @@ -5603,9 +5620,15 @@ static int fixup_tree_root_location(struct btrfs_fs_info *fs_info, struct btrfs_root_ref *ref; struct extent_buffer *leaf; struct btrfs_key key; + struct fscrypt_name fname; int ret; int err = 0; + ret = fscrypt_setup_filename(dir, &dentry->d_name, 0, + &fname); + if (ret) + return ret; + path = btrfs_alloc_path(); if (!path) { err = -ENOMEM; @@ -5651,6 +5674,7 @@ static int fixup_tree_root_location(struct btrfs_fs_info *fs_info, err = 0; out: btrfs_free_path(path); + fscrypt_free_filename(&fname); return err; } @@ -6257,16 +6281,17 @@ int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args, struct inode *inode = args->inode; int ret; + if (!args->orphan) { + ret = fscrypt_setup_filename(dir, &args->dentry->d_name, 0, + &args->fname); + if (ret) + return ret; + } + ret = posix_acl_create(dir, &inode->i_mode, &args->default_acl, &args->acl); - if (ret) + if (ret) { + fscrypt_free_filename(&args->fname); return ret; - - if (!args->orphan) { - char *name = (char *) args->dentry->d_name.name; - int name_len = args->dentry->d_name.len; - args->fname = (struct fscrypt_name) { - .disk_name = FSTR_INIT(name, name_len), - }; } /* 1 to add inode item */ @@ -6307,6 +6332,7 @@ void btrfs_new_inode_args_destroy(struct btrfs_new_inode_args *args) { posix_acl_release(args->acl); posix_acl_release(args->default_acl); + fscrypt_free_filename(&args->fname); } /* @@ -6734,10 +6760,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, struct btrfs_root *root = BTRFS_I(dir)->root; struct inode *inode = d_inode(old_dentry); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); - struct fscrypt_name fname = { - .disk_name = FSTR_INIT((char *) dentry->d_name.name, - dentry->d_name.len) - }; + struct fscrypt_name fname; u64 index; int err; int drop_inode = 0; @@ -6749,6 +6772,10 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, if (inode->i_nlink >= BTRFS_LINK_MAX) return -EMLINK; + err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &fname); + if (err) + goto fail; + err = btrfs_set_inode_index(BTRFS_I(dir), &index); if (err) goto fail; @@ -6799,6 +6826,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, } fail: + fscrypt_free_filename(&fname); if (trans) btrfs_end_transaction(trans); if (drop_inode) { @@ -9169,14 +9197,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, int ret; int ret2; bool need_abort = false; - struct fscrypt_name old_name = { - .disk_name = FSTR_INIT((char *) old_dentry->d_name.name, - old_dentry->d_name.len) - }; - struct fscrypt_name new_name = { - .disk_name = FSTR_INIT((char *) new_dentry->d_name.name, - new_dentry->d_name.len) - }; + struct fscrypt_name old_fname, new_fname; /* * For non-subvolumes allow exchange only within one subvolume, in the @@ -9188,6 +9209,16 @@ static int btrfs_rename_exchange(struct inode *old_dir, new_ino != BTRFS_FIRST_FREE_OBJECTID)) return -EXDEV; + ret = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &old_fname); + if (ret) + return ret; + + ret = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &new_fname); + if (ret) { + fscrypt_free_filename(&old_fname); + return ret; + } + /* close the race window with snapshot create/destroy ioctl */ if (old_ino == BTRFS_FIRST_FREE_OBJECTID || new_ino == BTRFS_FIRST_FREE_OBJECTID) @@ -9255,7 +9286,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, /* force full log commit if subvolume involved. */ btrfs_set_log_full_commit(trans); } else { - ret = btrfs_insert_inode_ref(trans, dest, &new_name, old_ino, + ret = btrfs_insert_inode_ref(trans, dest, &new_fname, old_ino, btrfs_ino(BTRFS_I(new_dir)), old_idx); if (ret) @@ -9268,7 +9299,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, /* force full log commit if subvolume involved. */ btrfs_set_log_full_commit(trans); } else { - ret = btrfs_insert_inode_ref(trans, root, &old_name, new_ino, + ret = btrfs_insert_inode_ref(trans, root, &old_fname, new_ino, btrfs_ino(BTRFS_I(old_dir)), new_idx); if (ret) { @@ -9302,7 +9333,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, ret = btrfs_unlink_subvol(trans, old_dir, old_dentry); } else { /* src is an inode */ ret = __btrfs_unlink_inode(trans, BTRFS_I(old_dir), - BTRFS_I(old_dentry->d_inode), &old_name, + BTRFS_I(old_dentry->d_inode), &old_fname, &old_rename_ctx); if (!ret) ret = btrfs_update_inode(trans, root, BTRFS_I(old_inode)); @@ -9317,7 +9348,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, ret = btrfs_unlink_subvol(trans, new_dir, new_dentry); } else { /* dest is an inode */ ret = __btrfs_unlink_inode(trans, BTRFS_I(new_dir), - BTRFS_I(new_dentry->d_inode), &new_name, + BTRFS_I(new_dentry->d_inode), &new_fname, &new_rename_ctx); if (!ret) ret = btrfs_update_inode(trans, dest, BTRFS_I(new_inode)); @@ -9328,14 +9359,14 @@ static int btrfs_rename_exchange(struct inode *old_dir, } ret = btrfs_add_link(trans, BTRFS_I(new_dir), BTRFS_I(old_inode), - &new_name, 0, old_idx); + &new_fname, 0, old_idx); if (ret) { btrfs_abort_transaction(trans, ret); goto out_fail; } ret = btrfs_add_link(trans, BTRFS_I(old_dir), BTRFS_I(new_inode), - &old_name, 0, new_idx); + &old_fname, 0, new_idx); if (ret) { btrfs_abort_transaction(trans, ret); goto out_fail; @@ -9378,6 +9409,8 @@ static int btrfs_rename_exchange(struct inode *old_dir, old_ino == BTRFS_FIRST_FREE_OBJECTID) up_read(&fs_info->subvol_sem); + fscrypt_free_filename(&new_fname); + fscrypt_free_filename(&old_fname); return ret; } @@ -9417,14 +9450,7 @@ static int btrfs_rename(struct user_namespace *mnt_userns, int ret; int ret2; u64 old_ino = btrfs_ino(BTRFS_I(old_inode)); - struct fscrypt_name old_fname = { - .disk_name = FSTR_INIT((char *)old_dentry->d_name.name, - old_dentry->d_name.len) - }; - struct fscrypt_name new_fname = { - .disk_name = FSTR_INIT((char *)new_dentry->d_name.name, - new_dentry->d_name.len) - }; + struct fscrypt_name old_fname, new_fname; if (btrfs_ino(BTRFS_I(new_dir)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID) return -EPERM; @@ -9441,6 +9467,16 @@ static int btrfs_rename(struct user_namespace *mnt_userns, new_inode->i_size > BTRFS_EMPTY_DIR_SIZE) return -ENOTEMPTY; + ret = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &old_fname); + if (ret) + return ret; + + ret = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &new_fname); + if (ret) { + fscrypt_free_filename(&old_fname); + return ret; + } + /* check for collisions, even if the name isn't there */ ret = btrfs_check_dir_item_collision(dest, new_dir->i_ino, &new_fname); @@ -9449,11 +9485,11 @@ static int btrfs_rename(struct user_namespace *mnt_userns, /* we shouldn't get * eexist without a new_inode */ if (WARN_ON(!new_inode)) { - return ret; + goto out_fscrypt_names; } } else { /* maybe -EOVERFLOW */ - return ret; + goto out_fscrypt_names; } } ret = 0; @@ -9627,6 +9663,9 @@ static int btrfs_rename(struct user_namespace *mnt_userns, out_whiteout_inode: if (flags & RENAME_WHITEOUT) iput(whiteout_args.inode); +out_fscrypt_names: + fscrypt_free_filename(&old_fname); + fscrypt_free_filename(&new_fname); return ret; } diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index fe705e3a615e..f6cceeee138f 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -1637,10 +1638,8 @@ create_pending_snapshot(struct btrfs_trans_handle *trans, u64 index = 0; u64 objectid; u64 root_flags; - struct fscrypt_name fname = { - .disk_name = FSTR_INIT((char *) pending->dentry->d_name.name, - pending->dentry->d_name.len) - }; + unsigned int mem_flags; + struct fscrypt_name fname; ASSERT(pending->path); path = pending->path; @@ -1648,9 +1647,22 @@ create_pending_snapshot(struct btrfs_trans_handle *trans, ASSERT(pending->root_item); new_root_item = pending->root_item; + /* + * Since this is during btrfs_commit_transaction() and more items + * joining the transaction at this point would be bad, use NOFS + * allocations so that no new writes are kicked off. + */ + mem_flags = memalloc_nofs_save(); + pending->error = fscrypt_setup_filename(parent_inode, + &pending->dentry->d_name, 0, + &fname); + memalloc_nofs_restore(mem_flags); + if (pending->error) + goto free_pending; + pending->error = btrfs_get_free_objectid(tree_root, &objectid); if (pending->error) - goto no_free_objectid; + goto free_fname; /* * Make qgroup to skip current new snapshot's qgroupid, as it is @@ -1864,7 +1876,9 @@ create_pending_snapshot(struct btrfs_trans_handle *trans, trans->bytes_reserved = 0; clear_skip_qgroup: btrfs_clear_skip_qgroup(trans); -no_free_objectid: +free_fname: + fscrypt_free_filename(&fname); +free_pending: kfree(new_root_item); pending->root_item = NULL; btrfs_free_path(path); diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 51a706e84e00..d73238254274 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -7042,13 +7042,13 @@ void btrfs_log_new_name(struct btrfs_trans_handle *trans, if (old_dir && old_dir->logged_trans == trans->transid) { struct btrfs_root *log = old_dir->root->log_root; struct btrfs_path *path; - struct fscrypt_name fname = { - .disk_name = FSTR_INIT((char *) old_dentry->d_name.name, - old_dentry->d_name.len) - }; - + struct fscrypt_name fname; ASSERT(old_dir_index >= BTRFS_DIR_START_INDEX); + ret = fscrypt_setup_filename(&old_dir->vfs_inode, + &old_dentry->d_name, 0, &fname); + if (ret) + goto out; /* * We have two inodes to update in the log, the old directory and * the inode that got renamed, so we must pin the log to prevent @@ -7068,6 +7068,7 @@ void btrfs_log_new_name(struct btrfs_trans_handle *trans, path = btrfs_alloc_path(); if (!path) { ret = -ENOMEM; + fscrypt_free_filename(&fname); goto out; } @@ -7097,6 +7098,7 @@ void btrfs_log_new_name(struct btrfs_trans_handle *trans, mutex_unlock(&old_dir->log_mutex); btrfs_free_path(path); + fscrypt_free_filename(&fname); if (ret < 0) goto out; } From patchwork Sun Jul 24 00:53:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927394 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ADC3AC43334 for ; Sun, 24 Jul 2022 00:54:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239242AbiGXAyf (ORCPT ); Sat, 23 Jul 2022 20:54:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38524 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239213AbiGXAyc (ORCPT ); Sat, 23 Jul 2022 20:54:32 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DFD6A15FFA; Sat, 23 Jul 2022 17:54:30 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 2CAFC807A4; Sat, 23 Jul 2022 20:54:29 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624070; bh=JMLmOEgEuK0HDJdJ98l5Tg/2HyaXv6kM+j59B2n59E0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CTxFNpylrYNe1QYEaXWOegd0iBL20TsXc8G5GB8E99i+dKtQkPq1XDxuUNnbnSc7C /fabSnsE+zNa8OPDmiM0zNmP29BAYGZNsgY2ezN2hC2kxcGMyfZfw0HirsIMhF7T77 zLVUfiCQQkxvfbUyPbprg9tiVkEZKVd41zzbO0xhiFiNB40U5NrT08CfdAymF5pNSf ZSTnCzoL+8WApJ5f7ZCHaCQW4rJgzG8v+NzpNa+nCWx8Z8J0xnB+G7SYI1RineWP+s RH6mYv5QQLbXnoQnaDW7rliXkk0PWf8jJ0tz9lDUnTAwHPhwSOAdkW4fyysGaYUYTB CwE/WUnFcPyQg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 04/16] btrfs: factor a fscrypt_name matching method Date: Sat, 23 Jul 2022 20:53:49 -0400 Message-Id: <408b97201b827f25e6d55548b5d7cfc6e379c2b1.1658623319.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval Now that everything in btrfs is dealing in fscrypt_names, fscrypt has a useful function, fscrypt_match_name(), to check whether a fscrypt_name matches a provided buffer. However, btrfs buffers are struct extent_buffer rather than a raw char array, so we need to implement our own imitation of fscrypt_match_name() that deals in extent_buffers, falling back to a simple memcpy if fscrypt isn't compiled. We can then use this matching method in btrfs_match_dir_item_name() and other locations. This also provides a useful occasion to introduce the new fscrypt file for btrfs, handling the fscrypt-specific functions needed. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/Makefile | 1 + fs/btrfs/dir-item.c | 12 +++++++----- fs/btrfs/extent_io.c | 37 +++++++++++++++++++++++++++++++++++++ fs/btrfs/extent_io.h | 2 ++ fs/btrfs/fscrypt.c | 32 ++++++++++++++++++++++++++++++++ fs/btrfs/fscrypt.h | 25 +++++++++++++++++++++++++ fs/btrfs/inode-item.c | 8 ++++---- fs/btrfs/inode.c | 11 ++++------- fs/btrfs/root-tree.c | 7 ++++--- 9 files changed, 116 insertions(+), 19 deletions(-) create mode 100644 fs/btrfs/fscrypt.c create mode 100644 fs/btrfs/fscrypt.h diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index 99f9995670ea..b6444490cdbc 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile @@ -38,6 +38,7 @@ btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o btrfs-$(CONFIG_BTRFS_FS_REF_VERIFY) += ref-verify.o btrfs-$(CONFIG_BLK_DEV_ZONED) += zoned.o btrfs-$(CONFIG_FS_VERITY) += verity.o +btrfs-$(CONFIG_FS_ENCRYPTION) += fscrypt.o btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \ tests/extent-buffer-tests.o tests/btrfs-tests.o \ diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index b4c1e2a40401..5af5c7af333f 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c @@ -5,6 +5,7 @@ #include "ctree.h" #include "disk-io.h" +#include "fscrypt.h" #include "transaction.h" /* @@ -390,15 +391,16 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info, total_len = btrfs_item_size(leaf, path->slots[0]); while (cur < total_len) { - unsigned long name_ptr = (unsigned long)(dir_item + 1); - this_len = sizeof(*dir_item) + - btrfs_dir_name_len(leaf, dir_item) + + int dir_name_len = btrfs_dir_name_len(leaf, dir_item); + this_len = sizeof(*dir_item) + dir_name_len + btrfs_dir_data_len(leaf, dir_item); if (btrfs_dir_name_len(leaf, dir_item) == fname_len(fname) && - memcmp_extent_buffer(leaf, fname_name(fname), name_ptr, - fname_len(fname)) == 0) + btrfs_fscrypt_match_name(fname, leaf, + (unsigned long)(dir_item + 1), + dir_name_len)) { return dir_item; + } cur += this_len; dir_item = (struct btrfs_dir_item *)((char *)dir_item + diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index b290bd1b38b0..d9b924d6f73f 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include #include #include @@ -6947,6 +6948,42 @@ void memzero_extent_buffer(const struct extent_buffer *eb, unsigned long start, } } +void extent_buffer_sha256(const struct extent_buffer *eb, unsigned long start, + unsigned long len, u8 *out) +{ + size_t cur; + size_t offset; + struct page *page; + char *kaddr; + unsigned long i = get_eb_page_index(start); + struct sha256_state sctx; + + if (check_eb_range(eb, start, len)) + return; + + offset = get_eb_offset_in_page(eb, start); + + /* + * TODO: This should maybe be using the crypto API, not the fallback, + * but fscrypt uses the fallback and this is only used in emulation of + * fscrypt's buffer sha256 method. + */ + sha256_init(&sctx); + while (len > 0) { + page = eb->pages[i]; + assert_eb_page_uptodate(eb, page); + + cur = min(len, PAGE_SIZE - offset); + kaddr = page_address(page); + sha256_update(&sctx, (u8 *)(kaddr + offset), cur); + + len -= cur; + offset = 0; + i++; + } + sha256_final(&sctx, out); +} + void copy_extent_buffer_full(const struct extent_buffer *dst, const struct extent_buffer *src) { diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 4bc72a87b9a9..b239f6ae2c80 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -223,6 +223,8 @@ void memmove_extent_buffer(const struct extent_buffer *dst, unsigned long len); void memzero_extent_buffer(const struct extent_buffer *eb, unsigned long start, unsigned long len); +void extent_buffer_sha256(const struct extent_buffer *eb, unsigned long start, + unsigned long len, u8 *out); int extent_buffer_test_bit(const struct extent_buffer *eb, unsigned long start, unsigned long pos); void extent_buffer_bitmap_set(const struct extent_buffer *eb, unsigned long start, diff --git a/fs/btrfs/fscrypt.c b/fs/btrfs/fscrypt.c new file mode 100644 index 000000000000..2ed844dd61d0 --- /dev/null +++ b/fs/btrfs/fscrypt.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Facebook + */ + +#include "ctree.h" +#include "fscrypt.h" + +/* fscrypt_match_name() but for an extent_buffer. */ +bool btrfs_fscrypt_match_name(const struct fscrypt_name *fname, + struct extent_buffer *leaf, unsigned long de_name, + u32 de_name_len) +{ + const struct fscrypt_nokey_name *nokey_name = + (const void *)fname->crypto_buf.name; + u8 digest[SHA256_DIGEST_SIZE]; + + if (likely(fname->disk_name.name)) { + if (de_name_len != fname->disk_name.len) + return false; + return !memcmp_extent_buffer(leaf, fname->disk_name.name, + de_name, de_name_len); + } + if (de_name_len <= sizeof(nokey_name->bytes)) + return false; + if (memcmp_extent_buffer(leaf, nokey_name->bytes, de_name, + sizeof(nokey_name->bytes))) + return false; + extent_buffer_sha256(leaf, de_name + sizeof(nokey_name->bytes), + de_name_len - sizeof(nokey_name->bytes), digest); + return !memcmp(digest, nokey_name->sha256, sizeof(digest)); +} diff --git a/fs/btrfs/fscrypt.h b/fs/btrfs/fscrypt.h new file mode 100644 index 000000000000..7f24d12e6ee0 --- /dev/null +++ b/fs/btrfs/fscrypt.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef BTRFS_FSCRYPT_H +#define BTRFS_FSCRYPT_H + +#include + +#ifdef CONFIG_FS_ENCRYPTION +bool btrfs_fscrypt_match_name(const struct fscrypt_name *fname, + struct extent_buffer *leaf, + unsigned long de_name, u32 de_name_len); + +#else +static bool btrfs_fscrypt_match_name(const struct fscrypt_name *fname, + struct extent_buffer *leaf, + unsigned long de_name, u32 de_name_len) +{ + if (de_name_len != fname->disk_name.len) + return false; + return !memcmp_extent_buffer(leaf, fname->disk_name.name, + de_name, de_name_len); +} +#endif + +#endif /* BTRFS_FSCRYPT_H */ diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c index 78053eb9589c..4ad75f9573aa 100644 --- a/fs/btrfs/inode-item.c +++ b/fs/btrfs/inode-item.c @@ -7,6 +7,7 @@ #include "ctree.h" #include "inode-item.h" #include "disk-io.h" +#include "fscrypt.h" #include "transaction.h" #include "print-tree.h" @@ -62,10 +63,9 @@ struct btrfs_inode_extref *btrfs_find_name_in_ext_backref( name_ptr = (unsigned long)(&extref->name); ref_name_len = btrfs_inode_extref_name_len(leaf, extref); - if (ref_name_len == fname_len(fname) && - btrfs_inode_extref_parent(leaf, extref) == ref_objectid && - (memcmp_extent_buffer(leaf, fname_name(fname), name_ptr, - fname_len(fname)) == 0)) + if (btrfs_inode_extref_parent(leaf, extref) == ref_objectid && + btrfs_fscrypt_match_name(fname, leaf, name_ptr, + ref_name_len)) return extref; cur_offset += ref_name_len + sizeof(*extref); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3d2e8d9e2fd2..12381c87177e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -55,6 +55,7 @@ #include "zoned.h" #include "subpage.h" #include "inode-item.h" +#include "fscrypt.h" struct btrfs_iget_args { u64 ino; @@ -5649,14 +5650,10 @@ static int fixup_tree_root_location(struct btrfs_fs_info *fs_info, leaf = path->nodes[0]; ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); - if (btrfs_root_ref_dirid(leaf, ref) != btrfs_ino(BTRFS_I(dir)) || - btrfs_root_ref_name_len(leaf, ref) != dentry->d_name.len) + if (btrfs_root_ref_dirid(leaf, ref) != btrfs_ino(BTRFS_I(dir))) goto out; - - ret = memcmp_extent_buffer(leaf, dentry->d_name.name, - (unsigned long)(ref + 1), - dentry->d_name.len); - if (ret) + if (!btrfs_fscrypt_match_name(&fname, leaf, (unsigned long)(ref + 1), + btrfs_root_ref_name_len(leaf, ref))) goto out; btrfs_release_path(path); diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 8eb6cbe19326..47c5572df8b1 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -8,6 +8,7 @@ #include "ctree.h" #include "transaction.h" #include "disk-io.h" +#include "fscrypt.h" #include "print-tree.h" #include "qgroup.h" #include "space-info.h" @@ -352,14 +353,14 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id, if (ret < 0) goto out; 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) != fname_len(fname)) || - memcmp_extent_buffer(leaf, fname_name(fname), ptr, - fname_len(fname))) { + !btrfs_fscrypt_match_name(fname, leaf, ptr, name_len)) { err = -ENOENT; goto out; } From patchwork Sun Jul 24 00:53:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927395 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5CDE5CCA48A for ; Sun, 24 Jul 2022 00:54:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239248AbiGXAyg (ORCPT ); Sat, 23 Jul 2022 20:54:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38542 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239230AbiGXAye (ORCPT ); Sat, 23 Jul 2022 20:54:34 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5A3E614D3B; Sat, 23 Jul 2022 17:54:33 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id B0E6480BB8; Sat, 23 Jul 2022 20:54:32 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624073; bh=Tcq2bnL7jZeUTtV/zMFhKPN5qxzKJGbsGbjP0h8/bsY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=B8bzyEJRbAWDO1uvBY5yJtfbqFa1tmoqO6UFGhYgjgVoyD/FL+vCW2ApvTejiCiZb 5tNZ6UYFcXh2oG2lVGay3k5f5Ag5KZG2i1u9JZeGEx2ZOIBJN0bopsGeaXii33hp/v rF9oHMUR0p3moTLLx25mV2R4F5WSgbSrQMgeDckzn2tO7DQ0Tajp2KUmozcrwOrJxk XOE3/XbZGZ0j17ooXNLYpk4sYosNhWwnlQkMH4+RawV9O7JYfjWrZFCRIMfYn/VnNT s3haCRBrAXeT1HZfOffz552znBiF5GwrVejUdJ/9n4z8e8iulIDfANp43P8pJoFprr 2lyZSbrx6z71Q== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 05/16] btrfs: disable various operations on encrypted inodes Date: Sat, 23 Jul 2022 20:53:50 -0400 Message-Id: <58760cc4416ca2e3903c962cc02b9bc4a251a0e9.1658623319.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval Initially, only normal data extents, using the normal (non-direct) IO path, will be encrypted. This change forbids various other bits: - allows reflinking only if both inodes have the same encryption status - disables compressing encrypted inodes - disables direct IO on encrypted inodes - disable inline data on encrypted inodes Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/btrfs_inode.h | 3 +++ fs/btrfs/file.c | 4 ++-- fs/btrfs/inode.c | 3 ++- fs/btrfs/reflink.c | 7 +++++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index b160b8e124e0..ff668686717b 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -400,6 +400,9 @@ static inline bool btrfs_inode_in_log(struct btrfs_inode *inode, u64 generation) */ static inline bool btrfs_inode_can_compress(const struct btrfs_inode *inode) { + if (IS_ENCRYPTED(&inode->vfs_inode)) + return false; + if (inode->flags & BTRFS_INODE_NODATACOW || inode->flags & BTRFS_INODE_NODATASUM) return false; diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index d199275adfa4..1fa0fe9f122f 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1896,7 +1896,7 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from) goto relock; } - if (check_direct_IO(fs_info, from, pos)) { + if (IS_ENCRYPTED(inode) || check_direct_IO(fs_info, from, pos)) { btrfs_inode_unlock(inode, ilock_flags); goto buffered; } @@ -3743,7 +3743,7 @@ static ssize_t btrfs_direct_read(struct kiocb *iocb, struct iov_iter *to) ssize_t read = 0; ssize_t ret; - if (fsverity_active(inode)) + if (IS_ENCRYPTED(inode) || fsverity_active(inode)) return 0; if (check_direct_read(btrfs_sb(inode->i_sb), to, iocb->ki_pos)) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 12381c87177e..2faa0ddfedf9 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -409,7 +409,8 @@ static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 size, * compressed) data fits in a leaf and the configured maximum inline * size. */ - if (size < i_size_read(&inode->vfs_inode) || + if (IS_ENCRYPTED(&inode->vfs_inode) || + size < i_size_read(&inode->vfs_inode) || size > fs_info->sectorsize || data_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info) || data_len > fs_info->max_inline) diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c index 9acf47b11fe6..d22086e1cbc8 100644 --- a/fs/btrfs/reflink.c +++ b/fs/btrfs/reflink.c @@ -805,6 +805,13 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in, ASSERT(inode_in->i_sb == inode_out->i_sb); } + /* + * Can only reflink encrypted files if both files are encrypted. + */ + if (!fscrypt_have_same_policy(inode_in, inode_out)) { + return -EINVAL; + } + /* Don't make the dst file partly checksummed */ if ((BTRFS_I(inode_in)->flags & BTRFS_INODE_NODATASUM) != (BTRFS_I(inode_out)->flags & BTRFS_INODE_NODATASUM)) { From patchwork Sun Jul 24 00:53:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927397 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4EBF1CCA489 for ; Sun, 24 Jul 2022 00:54:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239291AbiGXAyk (ORCPT ); Sat, 23 Jul 2022 20:54:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38598 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239257AbiGXAyg (ORCPT ); Sat, 23 Jul 2022 20:54:36 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BE62B167C1; Sat, 23 Jul 2022 17:54:35 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 09E71807A4; Sat, 23 Jul 2022 20:54:34 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624075; bh=COQBy9pOcpCvnrHMZE0Cv+NvvD5RaLx8uFecu+F6YvM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fCvubZAl+wjui1LUJYulFHf5hUb22aD3J9T8q8zI7F3j6hVmPS6MypQJb7IYknFNG hPfvqLWn2bnW6JAbCwQ/2X2d3RRE620yRbbwXZFe/+zEicOECn7nNV0OgI8mJv5cKw iv5j3Qcqq8NXBjwnyutBgJ/qZ3RByWUg+PTVskrBgP12pLTLQVd7uyzS4vZgvn/4pZ b4DCdcpcbJopFmb0RXuYzYYeW7Y5ZuAPyJL5ZlwmvuX7YicEz5JN3ZGcA4wcLQNYv1 hyIT+LIC1/4iQq3qdZV+eOpgTIoDv/4o96FY+tStQ+p8YhpUJDwBJhfVWfUHAZfEIK x3Hsb4qreRSeg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 06/16] btrfs: add fscrypt operation table to superblock Date: Sat, 23 Jul 2022 20:53:51 -0400 Message-Id: <95482e35f5ea655d1d09172c24245fc416698463.1658623319.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval To use fscrypt_prepare_new_inode(), the superblock must have fscrypt operations registered. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/fscrypt.c | 3 +++ fs/btrfs/fscrypt.h | 1 + fs/btrfs/super.c | 3 +++ 3 files changed, 7 insertions(+) diff --git a/fs/btrfs/fscrypt.c b/fs/btrfs/fscrypt.c index 2ed844dd61d0..9829d280a6bc 100644 --- a/fs/btrfs/fscrypt.c +++ b/fs/btrfs/fscrypt.c @@ -30,3 +30,6 @@ bool btrfs_fscrypt_match_name(const struct fscrypt_name *fname, de_name_len - sizeof(nokey_name->bytes), digest); return !memcmp(digest, nokey_name->sha256, sizeof(digest)); } + +const struct fscrypt_operations btrfs_fscrypt_ops = { +}; diff --git a/fs/btrfs/fscrypt.h b/fs/btrfs/fscrypt.h index 7f24d12e6ee0..07884206c8a1 100644 --- a/fs/btrfs/fscrypt.h +++ b/fs/btrfs/fscrypt.h @@ -22,4 +22,5 @@ static bool btrfs_fscrypt_match_name(const struct fscrypt_name *fname, } #endif +extern const struct fscrypt_operations btrfs_fscrypt_ops; #endif /* BTRFS_FSCRYPT_H */ diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 55af04fae075..e017e976c679 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -47,6 +47,8 @@ #include "tests/btrfs-tests.h" #include "block-group.h" #include "discard.h" +#include "fscrypt.h" + #include "qgroup.h" #include "raid56.h" #define CREATE_TRACE_POINTS @@ -1443,6 +1445,7 @@ static int btrfs_fill_super(struct super_block *sb, sb->s_vop = &btrfs_verityops; #endif sb->s_xattr = btrfs_xattr_handlers; + fscrypt_set_ops(sb, &btrfs_fscrypt_ops); sb->s_time_gran = 1; #ifdef CONFIG_BTRFS_FS_POSIX_ACL sb->s_flags |= SB_POSIXACL; From patchwork Sun Jul 24 00:53:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927398 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 35F02C433EF for ; Sun, 24 Jul 2022 00:54:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239213AbiGXAyl (ORCPT ); Sat, 23 Jul 2022 20:54:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38634 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239268AbiGXAyi (ORCPT ); Sat, 23 Jul 2022 20:54:38 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E2CBE17070; Sat, 23 Jul 2022 17:54:37 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 4E89080BB8; Sat, 23 Jul 2022 20:54:37 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624077; bh=Iy0d2gisAUTYAuKe7iepIG8DQrNRfWIMthYb/KNwd7U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AootJOy+OGTNIMlpeCMZrPZI687DfMYmSFNoibw7AwbPKdt5oM/9M6/3N8Tb+p7K5 5s2yjBVrQV7ZEyEGAUsJDXFSSawUMe9d7OzIvFXaKDLLeNkNWohJZS+0Tj7xDIylSn I6qM53b1V3KVx3HXMyVx1dYGhSF2aQKTBzXD7uqElr3Dk3iDXQcR438S/oeFeU3ADX f8ZFk/lpsuix3+tDvllJcQKJzSJmYWGpY2J40aOa2YN9FrQHFHb6kxrXlO/5lBqyYU 34/HR/3/zCqpm84O1vzX3wRlGRdsz4XOHyJuh/A0HguA7VXTiAawKLJnQ7ll4nNmMR Vq/wLjGsFUjCA== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 07/16] btrfs: start using fscrypt hooks. Date: Sat, 23 Jul 2022 20:53:52 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval In order to appropriately encrypt, create, open, rename, and various symlink operations must call fscrypt hooks. These determine whether the inode should be encrypted and do other preparatory actions. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/ctree.h | 1 + fs/btrfs/file.c | 3 ++ fs/btrfs/inode.c | 84 +++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 76 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 975d1244cc35..ac6b8973a273 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3348,6 +3348,7 @@ struct btrfs_new_inode_args { */ struct posix_acl *default_acl; struct posix_acl *acl; + bool encrypt; }; int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args, unsigned int *trans_num_items); diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 1fa0fe9f122f..876fc1c647ef 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -3709,6 +3709,9 @@ static int btrfs_file_open(struct inode *inode, struct file *filp) int ret; filp->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC; + ret = fscrypt_file_open(inode, filp); + if (ret) + return ret; ret = fsverity_file_open(inode, filp); if (ret) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2faa0ddfedf9..638943ea3471 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5453,6 +5453,7 @@ void btrfs_evict_inode(struct inode *inode) trace_btrfs_inode_evict(inode); if (!root) { + fscrypt_put_encryption_info(inode); fsverity_cleanup_inode(inode); clear_inode(inode); return; @@ -5554,6 +5555,7 @@ void btrfs_evict_inode(struct inode *inode) * to retry these periodically in the future. */ btrfs_remove_delayed_node(BTRFS_I(inode)); + fscrypt_put_encryption_info(inode); fsverity_cleanup_inode(inode); clear_inode(inode); } @@ -6292,6 +6294,10 @@ int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args, return ret; } + ret = fscrypt_prepare_new_inode(dir, inode, &args->encrypt); + if (ret) + return ret; + /* 1 to add inode item */ *trans_num_items = 1; /* 1 to add compression property */ @@ -6770,9 +6776,13 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, if (inode->i_nlink >= BTRFS_LINK_MAX) return -EMLINK; + err = fscrypt_prepare_link(old_dentry, dir, dentry); + if (err) + return err; + err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &fname); if (err) - goto fail; + return err; err = btrfs_set_inode_index(BTRFS_I(dir), &index); if (err) @@ -9002,6 +9012,7 @@ void btrfs_test_destroy_inode(struct inode *inode) void btrfs_free_inode(struct inode *inode) { + fscrypt_free_inode(inode); kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); } @@ -9061,8 +9072,7 @@ int btrfs_drop_inode(struct inode *inode) /* the snap/subvol tree is on deleting */ if (btrfs_root_refs(&root->root_item) == 0) return 1; - else - return generic_drop_inode(inode); + return generic_drop_inode(inode) || fscrypt_drop_inode(inode); } static void init_once(void *foo) @@ -9676,6 +9686,11 @@ static int btrfs_rename2(struct user_namespace *mnt_userns, struct inode *old_di if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) return -EINVAL; + ret = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry, + flags); + if (ret) + return ret; + if (flags & RENAME_EXCHANGE) ret = btrfs_rename_exchange(old_dir, old_dentry, new_dir, new_dentry); @@ -9895,15 +9910,22 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, }; unsigned int trans_num_items; int err; - int name_len; int datasize; unsigned long ptr; struct btrfs_file_extent_item *ei; struct extent_buffer *leaf; + struct fscrypt_str disk_link; + u32 name_len = strlen(symname); - name_len = strlen(symname); - if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info)) - return -ENAMETOOLONG; + /* + * fscrypt sets disk_link.len to be len + 1, including a NULL terminator, but we + * don't store that NULL. + */ + err = fscrypt_prepare_symlink(dir, symname, name_len, + BTRFS_MAX_INLINE_DATA_SIZE(fs_info) + 1, + &disk_link); + if (err) + return err; inode = new_inode(dir->i_sb); if (!inode) @@ -9912,8 +9934,8 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, inode->i_op = &btrfs_symlink_inode_operations; inode_nohighmem(inode); inode->i_mapping->a_ops = &btrfs_aops; - btrfs_i_size_write(BTRFS_I(inode), name_len); - inode_set_bytes(inode, name_len); + btrfs_i_size_write(BTRFS_I(inode), disk_link.len - 1); + inode_set_bytes(inode, disk_link.len - 1); new_inode_args.inode = inode; err = btrfs_new_inode_prepare(&new_inode_args, &trans_num_items); @@ -9943,7 +9965,7 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, key.objectid = btrfs_ino(BTRFS_I(inode)); key.offset = 0; key.type = BTRFS_EXTENT_DATA_KEY; - datasize = btrfs_file_extent_calc_inline_size(name_len); + datasize = btrfs_file_extent_calc_inline_size(disk_link.len - 1); err = btrfs_insert_empty_item(trans, root, path, &key, datasize); if (err) { @@ -9962,10 +9984,22 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, btrfs_set_file_extent_encryption(leaf, ei, 0); btrfs_set_file_extent_compression(leaf, ei, 0); btrfs_set_file_extent_other_encoding(leaf, ei, 0); + /* ram size is the unencrypted size */ btrfs_set_file_extent_ram_bytes(leaf, ei, name_len); ptr = btrfs_file_extent_inline_start(ei); - write_extent_buffer(leaf, symname, ptr, name_len); + if (IS_ENCRYPTED(inode)) { + err = fscrypt_encrypt_symlink(inode, symname, name_len, + &disk_link); + if (err) { + btrfs_abort_transaction(trans, err); + btrfs_free_path(path); + discard_new_inode(inode); + inode = NULL; + goto out; + } + } + write_extent_buffer(leaf, disk_link.name, ptr, disk_link.len - 1); btrfs_mark_buffer_dirty(leaf); btrfs_free_path(path); @@ -9982,6 +10016,29 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, return err; } +static const char *btrfs_get_link(struct dentry *dentry, struct inode *inode, + struct delayed_call *done) +{ + struct page *cpage; + const char *paddr; + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + + if (!IS_ENCRYPTED(inode)) + return page_get_link(dentry, inode, done); + + if (!dentry) + return ERR_PTR(-ECHILD); + + cpage = read_mapping_page(inode->i_mapping, 0, NULL); + if (IS_ERR(cpage)) + return ERR_CAST(cpage); + + paddr = fscrypt_get_symlink(inode, page_address(cpage), + BTRFS_MAX_INLINE_DATA_SIZE(fs_info), done); + put_page(cpage); + return paddr; +} + static struct btrfs_trans_handle *insert_prealloc_file_extent( struct btrfs_trans_handle *trans_in, struct btrfs_inode *inode, @@ -11568,7 +11625,7 @@ static const struct inode_operations btrfs_special_inode_operations = { .update_time = btrfs_update_time, }; static const struct inode_operations btrfs_symlink_inode_operations = { - .get_link = page_get_link, + .get_link = btrfs_get_link, .getattr = btrfs_getattr, .setattr = btrfs_setattr, .permission = btrfs_permission, @@ -11578,4 +11635,7 @@ static const struct inode_operations btrfs_symlink_inode_operations = { const struct dentry_operations btrfs_dentry_operations = { .d_delete = btrfs_dentry_delete, +#ifdef CONFIG_FS_ENCRYPTION + .d_revalidate = fscrypt_d_revalidate, +#endif }; From patchwork Sun Jul 24 00:53:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927399 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 18689C43334 for ; Sun, 24 Jul 2022 00:54:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239412AbiGXAyz (ORCPT ); Sat, 23 Jul 2022 20:54:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38708 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239330AbiGXAyn (ORCPT ); Sat, 23 Jul 2022 20:54:43 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 56F3614D3B; Sat, 23 Jul 2022 17:54:40 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id A854E807A4; Sat, 23 Jul 2022 20:54:39 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624080; bh=H09wRzRdnVbe5aQ6GhHltPGBSjyeA7RClzHlhNEwV60=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cber+TG8gZXbPOdexIZP/4rMr/R033ZlB96fEUBt0RgF7NbgtPahm8ezHXSjRwDJH K+PrnuX7j9psDkXrGxSvfXj5TC+gxkw0EVF7yWAhCMhRd6zVjKSZai+e+T1ks5ibL8 vagnFol/fwuofq8KsAPR5blDoyYOaLcu5v9mxRhItiao7EWbklu6I4udwZ4zO1lAZ+ Q/U9Il/u8O3b+1kr5tC1AIptljJbGsZMjG1p0WYUKMW6XZ1zQyaSLlr2kdA8hui1gI t3smedM6WcwiF+St2y7iOepUkGfjF3RZMa1QLv8G+RTG4zdpLtIUxElAugO9s0VPSP GfApMwUiDGkkw== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 08/16] btrfs: add a subvolume flag for whole-volume encryption Date: Sat, 23 Jul 2022 20:53:53 -0400 Message-Id: <17d05cf8a58bd2afc5c0ea7c3b9ebeb069aa57c8.1658623319.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval In many cases, we will want to encrypt all of a subvolume; adding a subvolume flag allows this. However, since an unencrypted subvolume would be unable to read encrypted data, encrypted subvolumes should only be snapshottable to other encrypted subvolumes. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/ctree.h | 3 + fs/btrfs/fscrypt.c | 160 ++++++++++++++++++++++++++++++++ fs/btrfs/inode.c | 38 ++++++++ fs/btrfs/ioctl.c | 10 +- fs/btrfs/tree-checker.c | 1 + include/uapi/linux/btrfs_tree.h | 10 ++ 6 files changed, 221 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index ac6b8973a273..cb7ded64fee6 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -33,6 +33,7 @@ #include "extent-io-tree.h" #include "extent_io.h" #include "extent_map.h" +#include "fscrypt.h" #include "async-thread.h" #include "block-rsv.h" #include "locking.h" @@ -1586,6 +1587,7 @@ do { \ #define BTRFS_INODE_NOATIME (1U << 9) #define BTRFS_INODE_DIRSYNC (1U << 10) #define BTRFS_INODE_COMPRESS (1U << 11) +#define BTRFS_INODE_FSCRYPT_CONTEXT (1U << 12) #define BTRFS_INODE_ROOT_ITEM_INIT (1U << 31) @@ -1602,6 +1604,7 @@ do { \ BTRFS_INODE_NOATIME | \ BTRFS_INODE_DIRSYNC | \ BTRFS_INODE_COMPRESS | \ + BTRFS_INODE_FSCRYPT_CONTEXT | \ BTRFS_INODE_ROOT_ITEM_INIT) #define BTRFS_INODE_RO_VERITY (1U << 0) diff --git a/fs/btrfs/fscrypt.c b/fs/btrfs/fscrypt.c index 9829d280a6bc..0e92acdac6d7 100644 --- a/fs/btrfs/fscrypt.c +++ b/fs/btrfs/fscrypt.c @@ -3,8 +3,13 @@ * Copyright (C) 2020 Facebook */ +#include #include "ctree.h" +#include "btrfs_inode.h" +#include "disk-io.h" #include "fscrypt.h" +#include "transaction.h" +#include "xattr.h" /* fscrypt_match_name() but for an extent_buffer. */ bool btrfs_fscrypt_match_name(const struct fscrypt_name *fname, @@ -31,5 +36,160 @@ bool btrfs_fscrypt_match_name(const struct fscrypt_name *fname, return !memcmp(digest, nokey_name->sha256, sizeof(digest)); } +static int btrfs_fscrypt_get_context(struct inode *inode, void *ctx, size_t len) +{ + struct btrfs_root *root = BTRFS_I(inode)->root; + struct inode *put_inode = NULL; + struct btrfs_key key; + struct btrfs_path *path; + struct extent_buffer *leaf; + unsigned long ptr; + int ret; + + if (S_ISREG(inode->i_mode) && + (btrfs_root_flags(&root->root_item) & BTRFS_ROOT_SUBVOL_FSCRYPT)) { + /* TODO: maybe cache the item */ + inode = btrfs_iget(inode->i_sb, BTRFS_FIRST_FREE_OBJECTID, + root); + if (IS_ERR(inode)) + return PTR_ERR(inode); + put_inode = inode; + } + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key = (struct btrfs_key) { + .objectid = btrfs_ino(BTRFS_I(inode)), + .type = BTRFS_FSCRYPT_CTXT_ITEM_KEY, + .offset = 0, + }; + + ret = btrfs_search_slot(NULL, BTRFS_I(inode)->root, &key, path, 0, 0); + if (ret) { + len = -EINVAL; + goto out; + } + + leaf = path->nodes[0]; + ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); + /* fscrypt provides max context length, but it could be less */ + len = min_t(size_t, len, btrfs_item_size(leaf, path->slots[0])); + read_extent_buffer(leaf, ctx, ptr, len); + +out: + btrfs_free_path(path); + iput(put_inode); + return len; +} + +static int btrfs_fscrypt_set_context(struct inode *inode, const void *ctx, + size_t len, void *fs_data) +{ + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_trans_handle *trans; + int is_subvolume = inode->i_ino == BTRFS_FIRST_FREE_OBJECTID; + int ret; + struct btrfs_path *path; + struct btrfs_key key = { + .objectid = btrfs_ino(BTRFS_I(inode)), + .type = BTRFS_FSCRYPT_CTXT_ITEM_KEY, + .offset = 0, + }; + + /* + * If the whole subvolume is encrypted, we can get the policy for + * regular files from the root inode. + */ + if (S_ISREG(inode->i_mode) && + (btrfs_root_flags(&root->root_item) & BTRFS_ROOT_SUBVOL_FSCRYPT)) + return 0; + + if (fs_data) { + /* + * We are setting the context as part of an existing + * transaction. This happens when we are inheriting the context + * for a new inode. + */ + trans = fs_data; + } else { + /* + * 1 for the inode item + * 1 for the root item if the inode is a subvolume + */ + trans = btrfs_start_transaction(root, 1 + is_subvolume); + if (IS_ERR(trans)) + return PTR_ERR(trans); + } + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + ret = btrfs_search_slot(trans, BTRFS_I(inode)->root, &key, path, 0, 1); + if (ret == 0) { + struct extent_buffer *leaf = path->nodes[0]; + unsigned long ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); + len = min_t(size_t, len, btrfs_item_size(leaf, path->slots[0])); + write_extent_buffer(leaf, ctx, ptr, len); + btrfs_mark_buffer_dirty(leaf); + btrfs_free_path(path); + goto out; + } else if (ret < 0) { + goto out; + } + btrfs_free_path(path); + + ret = btrfs_insert_item(trans, BTRFS_I(inode)->root, &key, (void *) ctx, len); + if (ret) + goto out; + + BTRFS_I(inode)->flags |= BTRFS_INODE_FSCRYPT_CONTEXT; + btrfs_sync_inode_flags_to_i_flags(inode); + if (!fs_data) { + inode_inc_iversion(inode); + inode->i_ctime = current_time(inode); + ret = btrfs_update_inode(trans, root, BTRFS_I(inode)); + if (ret) + goto out; + /* + * For new subvolumes, the root item is already initialized with + * the BTRFS_ROOT_SUBVOL_FSCRYPT flag. + */ + if (is_subvolume) { + u64 root_flags = btrfs_root_flags(&root->root_item); + + btrfs_set_root_flags(&root->root_item, + root_flags | + BTRFS_ROOT_SUBVOL_FSCRYPT); + ret = btrfs_update_root(trans, root->fs_info->tree_root, + &root->root_key, + &root->root_item); + } + } +out: + if (fs_data) + return ret; + + if (ret) + btrfs_abort_transaction(trans, ret); + else + btrfs_end_transaction(trans); + return ret; +} + +static bool btrfs_fscrypt_empty_dir(struct inode *inode) +{ + /* + * We don't care about turning on encryption on a non-empty directory + * so we always return true. + */ + return true; +} + const struct fscrypt_operations btrfs_fscrypt_ops = { + .key_prefix = "btrfs:", + .get_context = btrfs_fscrypt_get_context, + .set_context = btrfs_fscrypt_set_context, + .empty_dir = btrfs_fscrypt_empty_dir, }; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 638943ea3471..4f1382de515c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6281,6 +6281,34 @@ int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args, struct inode *inode = args->inode; int ret; + if (fscrypt_is_nokey_name(args->dentry)) + return -ENOKEY; + + if (IS_ENCRYPTED(dir) && + !(BTRFS_I(dir)->flags & BTRFS_INODE_FSCRYPT_CONTEXT)) { + struct inode *root_inode; + bool encrypt; + + root_inode = btrfs_iget(inode->i_sb, BTRFS_FIRST_FREE_OBJECTID, + BTRFS_I(dir)->root); + if (IS_ERR(root_inode)) + return PTR_ERR(root_inode); + /* + * TODO: perhaps instead of faking making a new dir to get a + * new context, it would be better to expose + * fscrypt_setup_encryption_info() for our use. + */ + ret = fscrypt_prepare_new_inode(root_inode, dir, &encrypt); + if (!ret) { + ret = fscrypt_set_context(dir, NULL); + if (ret) + fscrypt_put_encryption_info(dir); + } + iput(root_inode); + if (ret) + return ret; + } + if (!args->orphan) { ret = fscrypt_setup_filename(dir, &args->dentry->d_name, 0, &args->fname); @@ -6314,6 +6342,8 @@ int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args, if (dir->i_security) (*trans_num_items)++; #endif + if (args->encrypt) + (*trans_num_items)++; /* 1 to add fscrypt item */ if (args->orphan) { /* 1 to add orphan item */ (*trans_num_items)++; @@ -6567,6 +6597,14 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans, } } + if (args->encrypt) { + ret = fscrypt_set_context(inode, trans); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto discard; + } + } + inode_tree_add(inode); trace_btrfs_inode_new(inode); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 10b8db56edda..8f5b65c43c8d 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -658,7 +658,8 @@ static noinline int create_subvol(struct user_namespace *mnt_userns, fs_info->nodesize); btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755); - btrfs_set_root_flags(root_item, 0); + btrfs_set_root_flags(root_item, new_inode_args.encrypt ? + BTRFS_ROOT_SUBVOL_FSCRYPT : 0); btrfs_set_root_limit(root_item, 0); btrfs_set_stack_inode_flags(inode_item, BTRFS_INODE_ROOT_ITEM_INIT); @@ -787,6 +788,13 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, return -ETXTBSY; } + if ((btrfs_root_flags(&root->root_item) & BTRFS_ROOT_SUBVOL_FSCRYPT) && + !IS_ENCRYPTED(dir)) { + btrfs_warn(fs_info, + "cannot snapshot encrypted volume to unencrypted destination"); + return -EXDEV; + } + pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_KERNEL); if (!pending_snapshot) return -ENOMEM; diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index f861cc52be41..6f8e53d0cd6e 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -1124,6 +1124,7 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key, struct btrfs_fs_info *fs_info = leaf->fs_info; struct btrfs_root_item ri = { 0 }; const u64 valid_root_flags = BTRFS_ROOT_SUBVOL_RDONLY | + BTRFS_ROOT_SUBVOL_FSCRYPT | BTRFS_ROOT_SUBVOL_DEAD; int ret; diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h index 428ae75b9f73..da44d3355385 100644 --- a/include/uapi/linux/btrfs_tree.h +++ b/include/uapi/linux/btrfs_tree.h @@ -144,6 +144,8 @@ #define BTRFS_VERITY_DESC_ITEM_KEY 36 #define BTRFS_VERITY_MERKLE_ITEM_KEY 37 +#define BTRFS_FSCRYPT_CTXT_ITEM_KEY 41 + #define BTRFS_ORPHAN_ITEM_KEY 48 /* reserve 2-15 close to the inode for later flexibility */ @@ -633,6 +635,8 @@ struct btrfs_dir_item { } __attribute__ ((__packed__)); #define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0) +/* Top-level subvolume directory is encrypted with fscrypt. */ +#define BTRFS_ROOT_SUBVOL_FSCRYPT (1ULL << 1) /* * Internal in-memory flag that a subvolume has been marked for deletion but @@ -788,6 +792,12 @@ enum { BTRFS_NR_FILE_EXTENT_TYPES = 3, }; +enum { + BTRFS_ENCRYPTION_NONE, + BTRFS_ENCRYPTION_FSCRYPT, + BTRFS_NR_ENCRYPTION_TYPES, +}; + struct btrfs_file_extent_item { /* * transaction id that created this extent From patchwork Sun Jul 24 00:53:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927400 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 93B41C43334 for ; Sun, 24 Jul 2022 00:55:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239446AbiGXAzF (ORCPT ); Sat, 23 Jul 2022 20:55:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38710 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239331AbiGXAyn (ORCPT ); Sat, 23 Jul 2022 20:54:43 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 03EAB15A20; Sat, 23 Jul 2022 17:54:42 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 3D29E80BB8; Sat, 23 Jul 2022 20:54:42 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624082; bh=AgDYp0BiOtfI423w4RuFeYp4IwenEY64iE6iTJOoayc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jo9PimxW1WAvkkJJz/rgxg7uH3nmtl6rKZVegJYJ55yvfxSoqqSzlOUFHPn61xoSY 5YJtxfTPh8cFdAbHmVs6Xlj3sYyeYJZR9D1s0YBsJcv3eeglVK6hCxT8I/k4tVBnij 9ZsdYTcygIgzoe4W5AlFKJR06bevJCBpm11fYqS9b4Mmvl2z+wTAkYVeWYynch7tTK hAtX3X9lDZSLBhydnLXMu/YIzGhzCVt9jZY6TPykcN1xwfXHm98DinwijddqHMBpS0 1pZvH7KSyeH9HCKC1VtxK5fvxbxpklrdSKV6KVOCSX7MUmxo9GcwCRs/dSb3zxLYFp 4vFsMGB25JZWg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 09/16] btrfs: translate btrfs encryption flags and encrypted inode flag. Date: Sat, 23 Jul 2022 20:53:54 -0400 Message-Id: <3f8eaa2ac5226dba403197398ebbd5208ccd9cc0.1658623319.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval In btrfs, a file can be encrypted either if its directory is encrypted or its root subvolume is encrypted, so translate both to the standard flags. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/ioctl.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 8f5b65c43c8d..708e514aca25 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -147,6 +148,10 @@ static unsigned int btrfs_inode_flags_to_fsflags(struct btrfs_inode *binode) iflags |= FS_NOCOW_FL; if (ro_flags & BTRFS_INODE_RO_VERITY) iflags |= FS_VERITY_FL; + if ((binode->flags & BTRFS_INODE_FSCRYPT_CONTEXT) || + (btrfs_root_flags(&binode->root->root_item) & + BTRFS_ROOT_SUBVOL_FSCRYPT)) + iflags |= FS_ENCRYPT_FL; if (flags & BTRFS_INODE_NOCOMPRESS) iflags |= FS_NOCOMP_FL; @@ -176,10 +181,14 @@ void btrfs_sync_inode_flags_to_i_flags(struct inode *inode) new_fl |= S_DIRSYNC; if (binode->ro_flags & BTRFS_INODE_RO_VERITY) new_fl |= S_VERITY; + if ((binode->flags & BTRFS_INODE_FSCRYPT_CONTEXT) || + (btrfs_root_flags(&binode->root->root_item) & + BTRFS_ROOT_SUBVOL_FSCRYPT)) + new_fl |= S_ENCRYPTED; set_mask_bits(&inode->i_flags, S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | S_DIRSYNC | - S_VERITY, new_fl); + S_VERITY | S_ENCRYPTED, new_fl); } /* @@ -192,7 +201,7 @@ static int check_fsflags(unsigned int old_flags, unsigned int flags) FS_NOATIME_FL | FS_NODUMP_FL | \ FS_SYNC_FL | FS_DIRSYNC_FL | \ FS_NOCOMP_FL | FS_COMPR_FL | - FS_NOCOW_FL)) + FS_NOCOW_FL | FS_ENCRYPT_FL)) return -EOPNOTSUPP; /* COMPR and NOCOMP on new/old are valid */ From patchwork Sun Jul 24 00:53:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927401 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 199A4C433EF for ; Sun, 24 Jul 2022 00:55:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239379AbiGXAzF (ORCPT ); Sat, 23 Jul 2022 20:55:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38748 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239341AbiGXAyq (ORCPT ); Sat, 23 Jul 2022 20:54:46 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C184517583; Sat, 23 Jul 2022 17:54:45 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 19CBC807A4; Sat, 23 Jul 2022 20:54:44 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624085; bh=TAg5/4aHXU1bFAJanLoEe80cY8bgO/5Yu5sEPkM7Jno=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jWemjfEfq8jOBAcylvbkDmQ2OAhLtO6W4TJskVpS7u4NqIsRPpQGn7YUTAz4jVokM 9kTJG1ACiKra2pMoeLt0FYj9vA7l/fBF+4NrbGalTO4jwyRXKEJSH3qAJzOnJgGD/+ yXTRGYUEH4qnvt/bSg29sgCY5ha2Rv1JC3wjx95NQ/Xv3FvnQm0dFnu0EgnouB/H32 JbGni79XQUiawrak35iPm7SDSR+ptCKJTy7Xe/4m2rGgEjYi6kbAGkBcdAhVjHTHow ywU/ZEwoZsXl09y/qaR6Y0jcB3lWXiSc14qUAHktuytNLTg83r6nMakdX5+uHJy3WE dwNEeJOyTzNBA== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 10/16] btrfs: add iv generation function for fscrypt Date: Sat, 23 Jul 2022 20:53:55 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org As btrfs cannot use the standard inode or logical block based encryption for data block encryption, it must provide a IV generation function and users must use the IV_FROM_FS policy. For filenames, we can just use the nonce that fscrypt stores per-inode, since these encrypted datum are not shared between inodes; later on, we will store an IV per file extent, and return it in this function for data encryption. Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/fscrypt.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fs/btrfs/fscrypt.c b/fs/btrfs/fscrypt.c index 0e92acdac6d7..a11bf78c2a33 100644 --- a/fs/btrfs/fscrypt.c +++ b/fs/btrfs/fscrypt.c @@ -187,9 +187,21 @@ static bool btrfs_fscrypt_empty_dir(struct inode *inode) return true; } +static void btrfs_fscrypt_get_iv(u8 *iv, int ivsize, struct inode *inode, + u64 lblk_num) +{ + /* + * For encryption that doesn't involve extent data, juse use the + * nonce already loaded into the iv buffer. + */ + return; +} + const struct fscrypt_operations btrfs_fscrypt_ops = { + .flags = FS_CFLG_ALLOW_PARTIAL, .key_prefix = "btrfs:", .get_context = btrfs_fscrypt_get_context, .set_context = btrfs_fscrypt_set_context, .empty_dir = btrfs_fscrypt_empty_dir, + .get_fs_defined_iv = btrfs_fscrypt_get_iv, }; From patchwork Sun Jul 24 00:53:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927403 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BBE7DC433EF for ; Sun, 24 Jul 2022 00:55:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239548AbiGXAzJ (ORCPT ); Sat, 23 Jul 2022 20:55:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38866 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239394AbiGXAyw (ORCPT ); Sat, 23 Jul 2022 20:54:52 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8E7C415A31; Sat, 23 Jul 2022 17:54:48 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id DB61D80BB8; Sat, 23 Jul 2022 20:54:47 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624088; bh=kUagk1vzMMoikUsFje5DO09XQkW8tRiKFwRl/Sed8Q4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HxYh70b8+jNo9Bb4Zit6w4TjtT6GW11u4c8lTDmp0zvUrfTHltcd2olQ7qNDufIkd 43sxDj0XGaUe7lEZ91Cni3JBnJwzAa04Mz83uBhZKEJPw78Pc5Oz63OnKckvqnl/q2 MYNfpfOrUANhzkOT6sTDGNHv1nsHgukzv9Gkw+pVfIYQ/hdGWYM6ai2EZXN/UrYXzD cOwWC6l3mgBO0oGXFZ8mmkINzKwdhWdiqjgoaY4/iM+TYCuMnFLqB4HjrfwdXqm1Pd vcq94kgjngvlvWbJyZeUmGL/yNSnrC6ioIjIayb8YdWkFJFpcX8jBQZwpL2SGT0+Uu v7VZAl1L1BKVg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 11/16] btrfs: store an IV per encrypted normal file extent Date: Sat, 23 Jul 2022 20:53:56 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval In order to encrypt data, each file extent must have its own persistent random IV, which is then provided to fscrypt upon request. This IV is only needed for encrypted extents and is of variable size on disk, so file extents must additionally keep track of their actual length. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/ctree.h | 29 ++++++++++++++ fs/btrfs/extent_map.h | 8 ++++ fs/btrfs/file-item.c | 11 ++++++ fs/btrfs/file.c | 4 +- fs/btrfs/fscrypt.h | 23 +++++++++++ fs/btrfs/inode.c | 70 +++++++++++++++++++++++++-------- fs/btrfs/ordered-data.c | 12 +++++- fs/btrfs/ordered-data.h | 3 +- fs/btrfs/reflink.c | 1 + fs/btrfs/tree-checker.c | 36 +++++++++++++---- fs/btrfs/tree-log.c | 9 +++++ include/uapi/linux/btrfs_tree.h | 9 +++++ 12 files changed, 186 insertions(+), 29 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index cb7ded64fee6..bd8855da2e54 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -37,6 +37,7 @@ #include "async-thread.h" #include "block-rsv.h" #include "locking.h" +#include "fscrypt.h" struct btrfs_trans_handle; struct btrfs_transaction; @@ -1356,6 +1357,7 @@ struct btrfs_replace_extent_info { u64 file_offset; /* Pointer to a file extent item of type regular or prealloc. */ char *extent_buf; + u32 extent_buf_size; /* * Set to true when attempting to replace a file range with a new extent * described by this structure, set to false when attempting to clone an @@ -2591,6 +2593,15 @@ BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_num_bytes, struct btrfs_file_extent_item, disk_num_bytes, 64); BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression, struct btrfs_file_extent_item, compression, 8); +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_encryption, + struct btrfs_file_extent_item, encryption, 8); + +static inline u8 btrfs_stack_file_extent_encryption_ivsize(struct btrfs_file_extent_item *e) +{ + u8 ivsize; + btrfs_unpack_encryption(e->encryption, NULL, &ivsize); + return ivsize; +} static inline unsigned long btrfs_file_extent_inline_start(const struct btrfs_file_extent_item *e) @@ -2623,6 +2634,24 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item, BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item, other_encoding, 16); +static inline u8 +btrfs_file_extent_encryption_ivsize(const struct extent_buffer *eb, + struct btrfs_file_extent_item *e) +{ + u8 ivsize; + btrfs_unpack_encryption(btrfs_file_extent_encryption(eb, e), + NULL, &ivsize); + return ivsize; +} + +static inline u8 +btrfs_file_extent_ivsize_from_item(const struct extent_buffer *leaf, + const struct btrfs_path *path) +{ + return (btrfs_item_size(leaf, path->slots[0]) - + sizeof(struct btrfs_file_extent_item)); +} + /* * this returns the number of bytes used by the item on disk, minus the * size of any extent headers. If a file is compressed on disk, this is diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index d2fa32ffe304..cc077d15062b 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h @@ -5,6 +5,7 @@ #include #include +#include "fscrypt.h" #define EXTENT_MAP_LAST_BYTE ((u64)-4) #define EXTENT_MAP_HOLE ((u64)-3) @@ -27,6 +28,8 @@ enum { EXTENT_FLAG_FS_MAPPING, /* This em is merged from two or more physically adjacent ems */ EXTENT_FLAG_MERGED, + /* This em has a iv */ + EXTENT_FLAG_ENCRYPTED, }; struct extent_map { @@ -50,6 +53,11 @@ struct extent_map { */ u64 generation; unsigned long flags; + /* + * TODO: could either make FSCRYPT_MAX_IV_SIZE public or allocate this + * separately, of size 16 if applicable to the specific policy. + */ + u8 iv[FSCRYPT_MAX_IV_SIZE]; /* Used for chunk mappings, flag EXTENT_FLAG_FS_MAPPING must be set */ struct map_lookup *map_lookup; refcount_t refs; diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 29999686d234..066d59707408 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -1216,6 +1216,7 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode, em->generation = btrfs_file_extent_generation(leaf, fi); if (type == BTRFS_FILE_EXTENT_REG || type == BTRFS_FILE_EXTENT_PREALLOC) { + u8 ivsize; em->start = extent_start; em->len = extent_end - extent_start; em->orig_start = extent_start - @@ -1231,6 +1232,10 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode, em->compress_type = compress_type; em->block_start = bytenr; em->block_len = em->orig_block_len; + } else if (btrfs_file_extent_encryption(leaf, fi)) { + set_bit(EXTENT_FLAG_ENCRYPTED, &em->flags); + em->block_start = bytenr; + em->block_len = em->orig_block_len; } else { bytenr += btrfs_file_extent_offset(leaf, fi); em->block_start = bytenr; @@ -1238,6 +1243,12 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode, if (type == BTRFS_FILE_EXTENT_PREALLOC) set_bit(EXTENT_FLAG_PREALLOC, &em->flags); } + + ivsize = btrfs_file_extent_ivsize_from_item(leaf, path); + ASSERT(ivsize == btrfs_file_extent_encryption_ivsize(leaf, fi)); + + read_extent_buffer(leaf, em->iv, (unsigned long)fi->iv, + ivsize); } else if (type == BTRFS_FILE_EXTENT_INLINE) { em->block_start = EXTENT_MAP_INLINE; em->start = extent_start; diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 876fc1c647ef..bb0373194b94 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2658,14 +2658,14 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans, key.type = BTRFS_EXTENT_DATA_KEY; key.offset = extent_info->file_offset; ret = btrfs_insert_empty_item(trans, root, path, &key, - sizeof(struct btrfs_file_extent_item)); + extent_info->extent_buf_size); if (ret) return ret; leaf = path->nodes[0]; slot = path->slots[0]; write_extent_buffer(leaf, extent_info->extent_buf, btrfs_item_ptr_offset(leaf, slot), - sizeof(struct btrfs_file_extent_item)); + extent_info->extent_buf_size); extent = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); ASSERT(btrfs_file_extent_type(leaf, extent) != BTRFS_FILE_EXTENT_INLINE); btrfs_set_file_extent_offset(leaf, extent, extent_info->data_offset); diff --git a/fs/btrfs/fscrypt.h b/fs/btrfs/fscrypt.h index 07884206c8a1..52646bd84e43 100644 --- a/fs/btrfs/fscrypt.h +++ b/fs/btrfs/fscrypt.h @@ -5,6 +5,9 @@ #include +#define BTRFS_ENCRYPTION_POLICY_MASK 0x0f +#define BTRFS_ENCRYPTION_IVSIZE_MASK 0xf0 + #ifdef CONFIG_FS_ENCRYPTION bool btrfs_fscrypt_match_name(const struct fscrypt_name *fname, struct extent_buffer *leaf, @@ -22,5 +25,25 @@ static bool btrfs_fscrypt_match_name(const struct fscrypt_name *fname, } #endif +static inline void btrfs_unpack_encryption(u8 encryption, + u8 *policy, + u8 *ivsize) +{ + if (policy) + *policy = encryption & BTRFS_ENCRYPTION_POLICY_MASK; + if (ivsize) { + u8 transformed_ivsize = + (encryption & BTRFS_ENCRYPTION_IVSIZE_MASK) >> 4; + *ivsize = (transformed_ivsize ? + (1 << (transformed_ivsize - 1)) : 0); + } +} + +static inline u8 btrfs_pack_encryption(u8 policy, u8 ivsize) +{ + u8 transformed_ivsize = ivsize ? ilog2(ivsize) + 1 : 0; + return policy | (transformed_ivsize << 4); +} + extern const struct fscrypt_operations btrfs_fscrypt_ops; #endif /* BTRFS_FSCRYPT_H */ diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 4f1382de515c..565a2b66d766 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include "misc.h" @@ -1024,7 +1025,7 @@ static int submit_one_async_extent(struct btrfs_inode *inode, ins.offset, /* disk_num_bytes */ 0, /* offset */ 1 << BTRFS_ORDERED_COMPRESSED, - async_extent->compress_type); + async_extent->compress_type, NULL); if (ret) { btrfs_drop_extent_cache(inode, start, end, 0); goto out_free_reserve; @@ -1302,7 +1303,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode, ret = btrfs_add_ordered_extent(inode, start, ram_size, ram_size, ins.objectid, cur_alloc_size, 0, 1 << BTRFS_ORDERED_REGULAR, - BTRFS_COMPRESS_NONE); + BTRFS_COMPRESS_NONE, NULL); if (ret) goto out_drop_extent_cache; @@ -2100,7 +2101,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, nocow_args.disk_bytenr, nocow_args.num_bytes, 0, 1 << BTRFS_ORDERED_PREALLOC, - BTRFS_COMPRESS_NONE); + BTRFS_COMPRESS_NONE, NULL); if (ret) { btrfs_drop_extent_cache(inode, cur_offset, nocow_end, 0); @@ -2114,7 +2115,8 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, nocow_args.num_bytes, 0, 1 << BTRFS_ORDERED_NOCOW, - BTRFS_COMPRESS_NONE); + BTRFS_COMPRESS_NONE, + NULL); if (ret) goto error; } @@ -3050,6 +3052,7 @@ int btrfs_writepage_cow_fixup(struct page *page) static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, u64 file_pos, struct btrfs_file_extent_item *stack_fi, + const u8 *iv, const bool update_inode_bytes, u64 qgroup_reserved) { @@ -3065,6 +3068,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, u64 ram_bytes = btrfs_stack_file_extent_ram_bytes(stack_fi); struct btrfs_drop_extents_args drop_args = { 0 }; int ret; + int ivsize = fscrypt_mode_ivsize(&inode->vfs_inode); path = btrfs_alloc_path(); if (!path) @@ -3083,7 +3087,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, drop_args.start = file_pos; drop_args.end = file_pos + num_bytes; drop_args.replace_extent = true; - drop_args.extent_item_size = sizeof(*stack_fi); + drop_args.extent_item_size = sizeof(*stack_fi) + ivsize; ret = btrfs_drop_extents(trans, root, inode, &drop_args); if (ret) goto out; @@ -3094,7 +3098,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, ins.type = BTRFS_EXTENT_DATA_KEY; ret = btrfs_insert_empty_item(trans, root, path, &ins, - sizeof(*stack_fi)); + sizeof(*stack_fi) + ivsize); if (ret) goto out; } @@ -3103,6 +3107,11 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, write_extent_buffer(leaf, stack_fi, btrfs_item_ptr_offset(leaf, path->slots[0]), sizeof(struct btrfs_file_extent_item)); + if (ivsize) + write_extent_buffer(leaf, iv, + btrfs_item_ptr_offset(leaf, path->slots[0]) + + sizeof(struct btrfs_file_extent_item), + ivsize); btrfs_mark_buffer_dirty(leaf); btrfs_release_path(path); @@ -3179,7 +3188,12 @@ static int insert_ordered_extent_file_extent(struct btrfs_trans_handle *trans, btrfs_set_stack_file_extent_num_bytes(&stack_fi, num_bytes); btrfs_set_stack_file_extent_ram_bytes(&stack_fi, ram_bytes); btrfs_set_stack_file_extent_compression(&stack_fi, oe->compress_type); - /* Encryption and other encoding is reserved and all 0 */ + if (IS_ENCRYPTED(oe->inode)) { + u8 encryption = btrfs_pack_encryption(BTRFS_ENCRYPTION_FSCRYPT, + fscrypt_mode_ivsize(oe->inode)); + btrfs_set_stack_file_extent_encryption(&stack_fi, encryption); + } + /* Other encoding is reserved and always 0 */ /* * For delalloc, when completing an ordered extent we update the inode's @@ -3193,6 +3207,7 @@ static int insert_ordered_extent_file_extent(struct btrfs_trans_handle *trans, return insert_reserved_file_extent(trans, BTRFS_I(oe->inode), oe->file_offset, &stack_fi, + oe->iv, update_inode_bytes, oe->qgroup_rsv); } @@ -7095,8 +7110,25 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, btrfs_extent_item_to_extent_map(inode, path, item, !page, em); - if (extent_type == BTRFS_FILE_EXTENT_REG || - extent_type == BTRFS_FILE_EXTENT_PREALLOC) { + if (extent_type == BTRFS_FILE_EXTENT_REG) { + u8 ivsize = btrfs_file_extent_ivsize_from_item(leaf, path); + u8 encryption = btrfs_file_extent_encryption(leaf, item); + u8 policy, item_ivsize; + btrfs_unpack_encryption(encryption, &policy, &item_ivsize); + + if (policy == BTRFS_ENCRYPTION_FSCRYPT) { + u8 inode_ivsize = fscrypt_mode_ivsize(&inode->vfs_inode); + + if (ivsize != inode_ivsize || ivsize != item_ivsize) { + btrfs_crit(fs_info, + "invalid encryption IV size for inode %llu: itemsize %d item %d inode %d", + btrfs_ino(inode), ivsize, item_ivsize, inode_ivsize); + ret = -EUCLEAN; + goto out; + } + } + goto insert; + } else if (extent_type == BTRFS_FILE_EXTENT_PREALLOC) { goto insert; } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { unsigned long ptr; @@ -7325,7 +7357,7 @@ static struct extent_map *btrfs_create_dio_extent(struct btrfs_inode *inode, block_len, 0, (1 << type) | (1 << BTRFS_ORDERED_DIRECT), - BTRFS_COMPRESS_NONE); + BTRFS_COMPRESS_NONE, NULL); if (ret) { if (em) { free_extent_map(em); @@ -9954,6 +9986,7 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, struct extent_buffer *leaf; struct fscrypt_str disk_link; u32 name_len = strlen(symname); + u8 encryption; /* * fscrypt sets disk_link.len to be len + 1, including a NULL terminator, but we @@ -10019,7 +10052,9 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, btrfs_set_file_extent_generation(leaf, ei, trans->transid); btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE); - btrfs_set_file_extent_encryption(leaf, ei, 0); + encryption = btrfs_pack_encryption(IS_ENCRYPTED(inode) ? + BTRFS_ENCRYPTION_FSCRYPT : 0, 0); + btrfs_set_file_extent_encryption(leaf, ei, encryption); btrfs_set_file_extent_compression(leaf, ei, 0); btrfs_set_file_extent_other_encoding(leaf, ei, 0); /* ram size is the unencrypted size */ @@ -10100,16 +10135,18 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent( btrfs_set_stack_file_extent_num_bytes(&stack_fi, len); btrfs_set_stack_file_extent_ram_bytes(&stack_fi, len); btrfs_set_stack_file_extent_compression(&stack_fi, BTRFS_COMPRESS_NONE); - /* Encryption and other encoding is reserved and all 0 */ + btrfs_set_stack_file_extent_encryption(&stack_fi, + BTRFS_ENCRYPTION_NONE); + /* Other encoding is reserved and always 0 */ qgroup_released = btrfs_qgroup_release_data(inode, file_offset, len); if (qgroup_released < 0) return ERR_PTR(qgroup_released); if (trans) { - ret = insert_reserved_file_extent(trans, inode, - file_offset, &stack_fi, - true, qgroup_released); + ret = insert_reserved_file_extent(trans, inode, file_offset, + &stack_fi, NULL, true, + qgroup_released); if (ret) goto free_qgroup; return trans; @@ -10121,6 +10158,7 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent( extent_info.data_len = len; extent_info.file_offset = file_offset; extent_info.extent_buf = (char *)&stack_fi; + extent_info.extent_buf_size = sizeof(stack_fi); extent_info.is_new_extent = true; extent_info.update_times = true; extent_info.qgroup_reserved = qgroup_released; @@ -11071,7 +11109,7 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from, encoded->unencoded_offset, (1 << BTRFS_ORDERED_ENCODED) | (1 << BTRFS_ORDERED_COMPRESSED), - compression); + compression, NULL); if (ret) { btrfs_drop_extent_cache(inode, start, end, 0); goto out_free_reserved; diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 1952ac85222c..8e7d4a3cc661 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include "misc.h" @@ -164,13 +165,14 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree, int btrfs_add_ordered_extent(struct btrfs_inode *inode, u64 file_offset, u64 num_bytes, u64 ram_bytes, u64 disk_bytenr, u64 disk_num_bytes, u64 offset, unsigned flags, - int compress_type) + int compress_type, u8 *iv) { struct btrfs_root *root = inode->root; struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_ordered_inode_tree *tree = &inode->ordered_tree; struct rb_node *node; struct btrfs_ordered_extent *entry; + const u8 ivsize = fscrypt_mode_ivsize(&inode->vfs_inode); int ret; if (flags & @@ -199,6 +201,12 @@ int btrfs_add_ordered_extent(struct btrfs_inode *inode, u64 file_offset, entry->disk_bytenr = disk_bytenr; entry->disk_num_bytes = disk_num_bytes; entry->offset = offset; + if (ivsize) { + if (iv == NULL) + get_random_bytes(entry->iv, ivsize); + else + memcpy(entry->iv, iv, ivsize); + } entry->bytes_left = num_bytes; entry->inode = igrab(&inode->vfs_inode); entry->compress_type = compress_type; @@ -1059,7 +1067,7 @@ static int clone_ordered_extent(struct btrfs_ordered_extent *ordered, u64 pos, WARN_ON_ONCE(flags & (1 << BTRFS_ORDERED_COMPRESSED)); return btrfs_add_ordered_extent(BTRFS_I(inode), file_offset, len, len, disk_bytenr, len, 0, flags, - ordered->compress_type); + ordered->compress_type, ordered->iv); } int btrfs_split_ordered_extent(struct btrfs_ordered_extent *ordered, u64 pre, diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 87792f85e2c4..e738ecb70a89 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -99,6 +99,7 @@ struct btrfs_ordered_extent { u64 disk_bytenr; u64 disk_num_bytes; u64 offset; + u8 iv[FSCRYPT_MAX_IV_SIZE]; /* number of bytes that still need writing */ u64 bytes_left; @@ -194,7 +195,7 @@ bool btrfs_dec_test_ordered_pending(struct btrfs_inode *inode, int btrfs_add_ordered_extent(struct btrfs_inode *inode, u64 file_offset, u64 num_bytes, u64 ram_bytes, u64 disk_bytenr, u64 disk_num_bytes, u64 offset, unsigned flags, - int compress_type); + int compress_type, u8 *iv); void btrfs_add_ordered_sum(struct btrfs_ordered_extent *entry, struct btrfs_ordered_sum *sum); struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct btrfs_inode *inode, diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c index d22086e1cbc8..466dfccba094 100644 --- a/fs/btrfs/reflink.c +++ b/fs/btrfs/reflink.c @@ -495,6 +495,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, clone_info.data_len = datal; clone_info.file_offset = new_key.offset; clone_info.extent_buf = buf; + clone_info.extent_buf_size = size; clone_info.is_new_extent = false; clone_info.update_times = !no_time_update; ret = btrfs_replace_file_extents(BTRFS_I(inode), path, diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index 6f8e53d0cd6e..458877442ce5 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -204,6 +204,7 @@ static int check_extent_data_item(struct extent_buffer *leaf, u32 sectorsize = fs_info->sectorsize; u32 item_size = btrfs_item_size(leaf, slot); u64 extent_end; + u8 policy; if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) { file_extent_err(leaf, slot, @@ -255,10 +256,12 @@ static int check_extent_data_item(struct extent_buffer *leaf, BTRFS_NR_COMPRESS_TYPES - 1); return -EUCLEAN; } - if (unlikely(btrfs_file_extent_encryption(leaf, fi))) { + btrfs_unpack_encryption(btrfs_file_extent_encryption(leaf, fi), + &policy, NULL); + if (unlikely(policy >= BTRFS_NR_ENCRYPTION_TYPES)) { file_extent_err(leaf, slot, - "invalid encryption for file extent, have %u expect 0", - btrfs_file_extent_encryption(leaf, fi)); + "invalid encryption for file extent, have %u expect range [0, %u]", + policy, BTRFS_NR_ENCRYPTION_TYPES - 1); return -EUCLEAN; } if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) { @@ -287,12 +290,29 @@ static int check_extent_data_item(struct extent_buffer *leaf, return 0; } - /* Regular or preallocated extent has fixed item size */ - if (unlikely(item_size != sizeof(*fi))) { - file_extent_err(leaf, slot, + if (policy == BTRFS_ENCRYPTION_FSCRYPT) { + u8 ivsize = btrfs_file_extent_encryption_ivsize(leaf, fi); + if (unlikely(item_size != sizeof(*fi) + ivsize)) { + file_extent_err(leaf, slot, + "invalid item size for encrypted file extent, have %u expect = %zu + iv of size %u", + item_size, sizeof(*fi), ivsize); + return -EUCLEAN; + } + /* Only regular extents should be encrypted. */ + if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG) { + file_extent_err(leaf, slot, + "invalid type for encrypted file extent, have %u expect %u", + btrfs_file_extent_type(leaf, fi), + BTRFS_FILE_EXTENT_REG); + return -EUCLEAN; + } + } else { + if (unlikely(item_size != sizeof(*fi))) { + file_extent_err(leaf, slot, "invalid item size for reg/prealloc file extent, have %u expect %zu", - item_size, sizeof(*fi)); - return -EUCLEAN; + item_size, sizeof(*fi)); + return -EUCLEAN; + } } if (unlikely(CHECK_FE_ALIGNED(leaf, slot, fi, ram_bytes, sectorsize) || CHECK_FE_ALIGNED(leaf, slot, fi, disk_bytenr, sectorsize) || diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index d73238254274..292a71be956b 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -4758,6 +4758,9 @@ static int log_one_extent(struct btrfs_trans_handle *trans, u64 extent_offset = em->start - em->orig_start; u64 block_len; int ret; + u8 ivsize = fscrypt_mode_ivsize(&inode->vfs_inode); + u8 encryption = btrfs_pack_encryption(IS_ENCRYPTED(&inode->vfs_inode) ? + BTRFS_ENCRYPTION_FSCRYPT : 0, ivsize); btrfs_set_stack_file_extent_generation(&fi, trans->transid); if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) @@ -4779,6 +4782,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans, btrfs_set_stack_file_extent_num_bytes(&fi, em->len); btrfs_set_stack_file_extent_ram_bytes(&fi, em->ram_bytes); btrfs_set_stack_file_extent_compression(&fi, em->compress_type); + btrfs_set_stack_file_extent_encryption(&fi, encryption); ret = log_extent_csums(trans, inode, log, em, ctx); if (ret) @@ -4818,6 +4822,11 @@ static int log_one_extent(struct btrfs_trans_handle *trans, write_extent_buffer(leaf, &fi, btrfs_item_ptr_offset(leaf, path->slots[0]), sizeof(fi)); + if (ivsize) + write_extent_buffer(leaf, em->iv, + btrfs_item_ptr_offset(leaf, path->slots[0]) + + sizeof(fi), ivsize); + btrfs_mark_buffer_dirty(leaf); btrfs_release_path(path); diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h index da44d3355385..6a2a37edd326 100644 --- a/include/uapi/linux/btrfs_tree.h +++ b/include/uapi/linux/btrfs_tree.h @@ -820,6 +820,10 @@ struct btrfs_file_extent_item { * but not for stat. */ __u8 compression; + /* + * This field contains 4 bits of encryption type in the lower bits, + * 4 bits of ivsize in the upper bits. The unencrypted value is 0. + */ __u8 encryption; __le16 other_encoding; /* spare for later use */ @@ -848,6 +852,11 @@ struct btrfs_file_extent_item { */ __le64 num_bytes; + /* + * Encryption initialization vector. Only present if extent is + * encrypted (stored in the encryption field). + */ + __u8 iv[0]; } __attribute__ ((__packed__)); struct btrfs_csum_item { From patchwork Sun Jul 24 00:53:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927402 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E85BBC433EF for ; Sun, 24 Jul 2022 00:55:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239331AbiGXAzI (ORCPT ); Sat, 23 Jul 2022 20:55:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38710 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238939AbiGXAzE (ORCPT ); Sat, 23 Jul 2022 20:55:04 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 57D3B17073; Sat, 23 Jul 2022 17:54:51 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 92E02807A4; Sat, 23 Jul 2022 20:54:50 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624091; bh=GiNt0PiqutMpQFHFI25vL2YG7APA8wUW6glHUztY2D4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sbZnAR4+O/W0ahYzCGzzcXp8fPHvWIxofC+5oDPtbVc5qpvjJEgXM6byGBWajuAfM 5/N6kzrrZYvOFUPfONH+xYPxDeHHV3AwAaxg0GhKaG3pPfIiICwL2EP+VwcnXFdKCu s/xEn79BY8lkOhDOehYqv2owge4rEdKwn65lT0JwuRXIZjV+O0o9TBgGn6JdIG2dXh eFMf5wb86BTRrLADENiMB8a0w6pfEW/zZFbkIKhUWmrZh7/CrX4rqKyFSyD4OIx5mN IySef6+GLYADgHqzluxdURpXGJKurOSqHdu1HDhC9+6dS1iMo7DedKdhFE2ZE6lSXG 0BXQ+z2JR/3Nw== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 12/16] btrfs: Add new FEATURE_INCOMPAT_FSCRYPT feature flag. Date: Sat, 23 Jul 2022 20:53:57 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval As fscrypt files will be incompatible with older filesystem versions, new filesystems should be created with an incompat flag for fscrypt. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/ctree.h | 6 ++++-- include/uapi/linux/btrfs.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index bd8855da2e54..9fab4d33a326 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -334,7 +334,8 @@ static_assert(sizeof(struct btrfs_super_block) == BTRFS_SUPER_INFO_SIZE); BTRFS_FEATURE_INCOMPAT_METADATA_UUID | \ BTRFS_FEATURE_INCOMPAT_RAID1C34 | \ BTRFS_FEATURE_INCOMPAT_ZONED | \ - BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2) + BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2 | \ + BTRFS_FEATURE_INCOMPAT_FSCRYPT) #else #define BTRFS_FEATURE_INCOMPAT_SUPP \ (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ @@ -349,7 +350,8 @@ static_assert(sizeof(struct btrfs_super_block) == BTRFS_SUPER_INFO_SIZE); BTRFS_FEATURE_INCOMPAT_NO_HOLES | \ BTRFS_FEATURE_INCOMPAT_METADATA_UUID | \ BTRFS_FEATURE_INCOMPAT_RAID1C34 | \ - BTRFS_FEATURE_INCOMPAT_ZONED) + BTRFS_FEATURE_INCOMPAT_ZONED | \ + BTRFS_FEATURE_INCOMPAT_FSCRYPT) #endif #define BTRFS_FEATURE_INCOMPAT_SAFE_SET \ diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index f54dc91e4025..b19fc3725769 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h @@ -310,6 +310,7 @@ struct btrfs_ioctl_fs_info_args { #define BTRFS_FEATURE_INCOMPAT_RAID1C34 (1ULL << 11) #define BTRFS_FEATURE_INCOMPAT_ZONED (1ULL << 12) #define BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2 (1ULL << 13) +#define BTRFS_FEATURE_INCOMPAT_FSCRYPT (1ULL << 14) struct btrfs_ioctl_feature_flags { __u64 compat_flags; From patchwork Sun Jul 24 00:53:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927404 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 89615C43334 for ; Sun, 24 Jul 2022 00:55:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239479AbiGXAzM (ORCPT ); Sat, 23 Jul 2022 20:55:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38784 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239460AbiGXAzF (ORCPT ); Sat, 23 Jul 2022 20:55:05 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DAB1F1A3B9; Sat, 23 Jul 2022 17:54:53 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 20B9980BB8; Sat, 23 Jul 2022 20:54:52 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624093; bh=tQkA6kJ/fCFGZgvfYo9gPeiRaxwV0FytgcRAx/xmXQ4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=K407mVNVxWm2FHWCSlWISp7jXve+ywEy0YTTGzp+IFTXp8JHnmGpbT5KU5vjKRlD8 AsvvOs34OZXjZ6w3658tqnGgq9QWxcT0WmwqXdY79vaoeO3MWuBRDLqN8cnxgoZZbR j6y40xoDbc49XcdrFE2fFwuog2sXHeputxqTCZQX9tBDEupOyIQfdO1LsOQfspUj7d HaH7GSIDjNzBb2eUy0vWxxDaas9ZiKfaNbXV2oGt26jSGzyJQ00yo9JNm1lEztQu3s 5cT59UrfJkmL9vAPqv+RQOJaB0MBPCENaKMQm3TPh8ggODzaC5Cx4RiA3zl/0bGJ8C sgcqj9Z7vVNcQ== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 13/16] btrfs: reuse encrypted filename hash when possible. Date: Sat, 23 Jul 2022 20:53:58 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval For encrypted fscrypt_names, we can reuse fscrypt's precomputed hash of the encrypted name to generate our own hash, instead of rehashing the unencrypted name (which may not be possible if it's a nokey name). Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/ctree.h | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 9fab4d33a326..30f390c01943 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2773,7 +2773,10 @@ static inline void btrfs_crc32c_final(u32 crc, u8 *result) static inline u64 btrfs_name_hash(const struct fscrypt_name *name) { - return crc32c((u32)~1, fname_name(name), fname_len(name)); + if (fname_name(name)) + return crc32c((u32)~1, fname_name(name), fname_len(name)); + else + return name->hash | ((u64)name->minor_hash << 32); } /* @@ -2782,8 +2785,20 @@ static inline u64 btrfs_name_hash(const struct fscrypt_name *name) static inline u64 btrfs_extref_hash(u64 parent_objectid, const struct fscrypt_name *name) { - return (u64) crc32c(parent_objectid, fname_name(name), - fname_len(name)); + /* + * If the name is encrypted and we don't have the key, we can use the + * fscrypt-provided hash instead of the normal name, and do the steps + * of crc32c() manually. Else, just hash the name, parent objectid, + * and name length. + */ + if (fname_name(name)) + return (u64) crc32c(parent_objectid, fname_name(name), + fname_len(name)); + else + return (__crc32c_le_combine(parent_objectid, + name->hash, + fname_len(name)) ^ + __crc32c_le_shift(~1, fname_len(name))); } static inline gfp_t btrfs_alloc_write_mask(struct address_space *mapping) From patchwork Sun Jul 24 00:53:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927405 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AF61AC43334 for ; Sun, 24 Jul 2022 00:55:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239537AbiGXAze (ORCPT ); Sat, 23 Jul 2022 20:55:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39558 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239531AbiGXAzI (ORCPT ); Sat, 23 Jul 2022 20:55:08 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2A93B1A3B5; Sat, 23 Jul 2022 17:54:56 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 0E378807A4; Sat, 23 Jul 2022 20:54:55 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624096; bh=irSd7yOHrw/HMKBM4LnThweijHbsccg1b+8ogE+gARE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OaV6waLdyq1FKtL7B15kUzqk1tedgdM8R/DSzl8/A2WB6bBRvaG4BuXH7zT1c4bcD wP+MKMQlIckYsVV/unXFr7zPnFaJxEJ42ouUWQ5a9zlKj65DGlq/zuGE+k96yW2X84 GYebD5/NckXhqKUqzeZoZUSENbFAJhV18awmPXSWWoJ/tsgFNKNsmj4D0LW+tg7CT2 bbZBUzQhEIf8Gqnmq859m8EeUqMBQadfNXnd85gAeK0uN8y5OMbbGMw/m+oLvQeqec c8/TIbjv2e46W9YVTMk+y0BDC/166AMCNRCqUDO53c2/L/mF+1jE97+hLy8jEE5ONM UQ6NrWxhcHoKw== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 14/16] btrfs: adapt directory read and lookup to potentially encrypted filenames Date: Sat, 23 Jul 2022 20:53:59 -0400 Message-Id: <1815605d9c69c3ea33b1bcfb7ae9830cc6ca8258.1658623319.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval When filenames can be encrypted, if we don't initially match a desired filename, we have to try decrypting it with the directory key to see if it matches in plaintext. Similarly, for readdir, we need to read encrypted directory items as well as unencrypted. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/delayed-inode.c | 32 +++++++++++++--- fs/btrfs/delayed-inode.h | 4 +- fs/btrfs/dir-item.c | 23 ++++++++++++ fs/btrfs/inode.c | 80 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 125 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 84ae3cf9a9ee..a966dc3c5bf2 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1493,9 +1493,9 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, ret = __btrfs_add_delayed_item(delayed_node, delayed_item); if (unlikely(ret)) { + // TODO: It would be nice to print the base64encoded name here maybe? btrfs_err(trans->fs_info, - "err add delayed dir index item(name: %.*s) into the insertion tree of the delayed node(root id: %llu, inode id: %llu, errno: %d)", - fname_len(fname), fname_name(fname), + "err add delayed dir index item into the insertion tree of the delayed node (root id: %llu, inode id: %llu, errno: %d)", delayed_node->root->root_key.objectid, delayed_node->inode_id, ret); BUG(); @@ -1728,7 +1728,9 @@ int btrfs_should_delete_dir_index(struct list_head *del_list, * btrfs_readdir_delayed_dir_index - read dir info stored in the delayed tree * */ -int btrfs_readdir_delayed_dir_index(struct dir_context *ctx, +int btrfs_readdir_delayed_dir_index(struct inode *inode, + struct fscrypt_str *fstr, + struct dir_context *ctx, struct list_head *ins_list) { struct btrfs_dir_item *di; @@ -1738,6 +1740,7 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx, int name_len; int over = 0; unsigned char d_type; + size_t fstr_len = fstr->len; if (list_empty(ins_list)) return 0; @@ -1765,8 +1768,27 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx, 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, - location.objectid, d_type); + if (di->type & BTRFS_FT_FSCRYPT_NAME) { + int ret; + struct fscrypt_str iname = FSTR_INIT(name, name_len); + fstr->len = fstr_len; + /* + * The hash is only used when the encryption key is not + * available. But if we have delayed insertions, then we + * must have the encryption key available or we wouldn't + * have been able to create entries in the directory. + * So, we don't calculate the hash. + */ + ret = fscrypt_fname_disk_to_usr(inode, 0, 0, &iname, + fstr); + if (ret) + return ret; + over = !dir_emit(ctx, fstr->name, fstr->len, + location.objectid, d_type); + } else { + over = !dir_emit(ctx, name, name_len, location.objectid, + d_type); + } if (refcount_dec_and_test(&curr->refs)) kfree(curr); diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h index 968461b3c350..aa3c67d572e4 100644 --- a/fs/btrfs/delayed-inode.h +++ b/fs/btrfs/delayed-inode.h @@ -142,7 +142,9 @@ void btrfs_readdir_put_delayed_items(struct inode *inode, struct list_head *del_list); int btrfs_should_delete_dir_index(struct list_head *del_list, u64 index); -int btrfs_readdir_delayed_dir_index(struct dir_context *ctx, +int btrfs_readdir_delayed_dir_index(struct inode *inode, + struct fscrypt_str *fstr, + struct dir_context *ctx, struct list_head *ins_list); /* for init */ diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index 5af5c7af333f..2dfc0d29f6c6 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c @@ -120,6 +120,9 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_disk_key disk_key; u32 data_size; + if (fname->crypto_buf.name) + type |= BTRFS_FT_FSCRYPT_NAME; + key.objectid = btrfs_ino(dir); key.type = BTRFS_DIR_ITEM_KEY; key.offset = btrfs_name_hash(fname); @@ -385,6 +388,18 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info, u32 cur = 0; u32 this_len; struct extent_buffer *leaf; + bool encrypted = (fname->crypto_buf.name != NULL); + struct fscrypt_name unencrypted_fname; + + if (encrypted) { + unencrypted_fname = (struct fscrypt_name){ + .usr_fname = fname->usr_fname, + .disk_name = { + .name = (unsigned char *)fname->usr_fname->name, + .len = fname->usr_fname->len, + }, + }; + } leaf = path->nodes[0]; dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); @@ -402,6 +417,14 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info, return dir_item; } + if (encrypted && + btrfs_dir_name_len(leaf, dir_item) == fname_len(&unencrypted_fname) && + btrfs_fscrypt_match_name(&unencrypted_fname, leaf, + (unsigned long)(dir_item + 1), + dir_name_len)) { + return dir_item; + } + cur += this_len; dir_item = (struct btrfs_dir_item *)((char *)dir_item + this_len); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 565a2b66d766..068e9701a2f4 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5883,12 +5883,25 @@ 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); + if (BTRFS_I(dir)->flags & BTRFS_INODE_FSCRYPT_CONTEXT) { + ret = fscrypt_prepare_lookup(dir, dentry, &fname); + if (ret) + return ERR_PTR(ret); + } else { + fname = (struct fscrypt_name) { + .usr_fname = &dentry->d_name, + .disk_name = FSTR_INIT((char *) dentry->d_name.name, + dentry->d_name.len), + }; + } + ret = btrfs_inode_by_name(dir, dentry, &location, &di_type); if (ret < 0) return ERR_PTR(ret); @@ -6030,18 +6043,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_FSCRYPT_CONTEXT) { + 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; @@ -6059,6 +6086,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 di_flags; + u32 nokey_len; if (found_key.objectid != key.objectid) break; @@ -6070,8 +6098,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) @@ -6085,8 +6118,36 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx) di_flags = 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 (di_flags & BTRFS_FT_FSCRYPT_NAME) { + 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. + */ + if (!fscrypt_has_encryption_key(inode)) { + struct fscrypt_name fname = { + .disk_name = oname, + }; + u64 name_hash = btrfs_name_hash(&fname); + 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(btrfs_dir_flags_to_ftype(di_flags)), @@ -6108,7 +6169,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; @@ -6139,6 +6201,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; } From patchwork Sun Jul 24 00:54:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927406 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EE780C433EF for ; Sun, 24 Jul 2022 00:55:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239611AbiGXAzh (ORCPT ); Sat, 23 Jul 2022 20:55:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38708 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239497AbiGXAzS (ORCPT ); Sat, 23 Jul 2022 20:55:18 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A03391ADB7; Sat, 23 Jul 2022 17:55:00 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id CC84680BB8; Sat, 23 Jul 2022 20:54:58 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624099; bh=otwv5bBYWXt+KfSPuzurzl6xT3sEMYqE9TpfS6zqEu8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WzMJJA4aJYHeCCWtTN23YDurbKSqUSsLgFKE68zMur9y0mrdzHdFnnJdAc5CYFiVH 1vfxUDc2YDI8OufkQN/kCp4VGM77Wxl5cfjyn9+7O5m13azSpOSO3CMoQCa0WVz0sv OofCCum+pK1gdU11dN53Q6d2qrwpFLP/+kdBWa/LBKzltyb9eqGj6cVKOac77IgbLn A7tjBdYMSuHyjfDluePImvNcXgaeMwK50vHsmc/tisbODCpGQ4rUGRgvQ1L4bQ5Gdj O6FBRn9BFmkHAVRp6pbW6joDMyDeW+5jk7ymm/3+iVa+lkn61anOb24Lkompv6RG1e T9lii1mNR+3FQ== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 15/16] btrfs: encrypt normal file extent data if appropriate Date: Sat, 23 Jul 2022 20:54:00 -0400 Message-Id: <8685022a83df3cb910d1e78003650a263dfe862d.1658623319.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval Add in the necessary calls to encrypt and decrypt data to achieve encryption of normal data. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/extent_io.c | 56 ++++++++++++++++++++++++++++++++++++----- fs/btrfs/file-item.c | 9 +++++-- fs/btrfs/fscrypt.c | 27 ++++++++++++++++---- fs/btrfs/tree-checker.c | 11 +++++--- 4 files changed, 87 insertions(+), 16 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index d9b924d6f73f..7e1be83ccabf 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -184,6 +184,7 @@ static void submit_one_bio(struct btrfs_bio_ctrl *bio_ctrl) { struct bio *bio; struct bio_vec *bv; + struct page *first_page; struct inode *inode; int mirror_num; @@ -192,13 +193,17 @@ static void submit_one_bio(struct btrfs_bio_ctrl *bio_ctrl) bio = bio_ctrl->bio; bv = bio_first_bvec_all(bio); - inode = bv->bv_page->mapping->host; + first_page = bio_first_page_all(bio); + if (fscrypt_is_bounce_page(first_page)) + inode = fscrypt_pagecache_page(first_page)->mapping->host; + else + inode = first_page->mapping->host; mirror_num = bio_ctrl->mirror_num; /* Caller should ensure the bio has at least some range added */ ASSERT(bio->bi_iter.bi_size); - btrfs_bio(bio)->file_offset = page_offset(bv->bv_page) + bv->bv_offset; + btrfs_bio(bio)->file_offset = page_offset(first_page) + bv->bv_offset; if (!is_data_inode(inode)) btrfs_submit_metadata_bio(inode, bio, mirror_num); @@ -2836,9 +2841,19 @@ static void end_bio_extent_writepage(struct bio *bio) ASSERT(!bio_flagged(bio, BIO_CLONED)); bio_for_each_segment_all(bvec, bio, iter_all) { struct page *page = bvec->bv_page; - struct inode *inode = page->mapping->host; - struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); - const u32 sectorsize = fs_info->sectorsize; + struct inode *inode; + struct btrfs_fs_info *fs_info; + u32 sectorsize; + struct page *bounce_page = NULL; + + if (fscrypt_is_bounce_page(page)) { + bounce_page = page; + page = fscrypt_pagecache_page(bounce_page); + } + + inode = page->mapping->host; + fs_info = btrfs_sb(inode->i_sb); + sectorsize = fs_info->sectorsize; /* Our read/write should always be sector aligned. */ if (!IS_ALIGNED(bvec->bv_offset, sectorsize)) @@ -2859,7 +2874,7 @@ static void end_bio_extent_writepage(struct bio *bio) } end_extent_writepage(page, error, start, end); - + fscrypt_free_bounce_page(bounce_page); btrfs_page_clear_writeback(fs_info, page, start, bvec->bv_len); } @@ -3058,6 +3073,17 @@ static void end_bio_extent_readpage(struct bio *bio) } } + if (likely(uptodate)) { + if (fscrypt_inode_uses_fs_layer_crypto(inode)) { + int ret = fscrypt_decrypt_pagecache_blocks(page, + bvec->bv_len, + bvec->bv_offset); + if (ret) { + error_bitmap = (unsigned int) -1; + uptodate = false; + } + } + } if (likely(uptodate)) { loff_t i_size = i_size_read(inode); pgoff_t end_index = i_size >> PAGE_SHIFT; @@ -3415,11 +3441,29 @@ static int submit_extent_page(unsigned int opf, bool force_bio_submit) { int ret = 0; + struct page *bounce_page = NULL; struct btrfs_inode *inode = BTRFS_I(page->mapping->host); unsigned int cur = pg_offset; ASSERT(bio_ctrl); + if ((opf & REQ_OP_MASK) == REQ_OP_WRITE && + fscrypt_inode_uses_fs_layer_crypto(&inode->vfs_inode)) { + gfp_t gfp_flags = GFP_NOFS; + + if (bio_ctrl->bio) + gfp_flags = GFP_NOWAIT | __GFP_NOWARN; + else + gfp_flags = GFP_NOFS; + bounce_page = fscrypt_encrypt_pagecache_blocks(page, size, + pg_offset, + gfp_flags); + if (IS_ERR(bounce_page)) + return PTR_ERR(bounce_page); + page = bounce_page; + pg_offset = 0; + } + ASSERT(pg_offset < PAGE_SIZE && size <= PAGE_SIZE && pg_offset + size <= PAGE_SIZE); if (force_bio_submit) diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 066d59707408..c3780eacdd35 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -663,8 +663,13 @@ blk_status_t btrfs_csum_one_bio(struct btrfs_inode *inode, struct bio *bio, shash->tfm = fs_info->csum_shash; bio_for_each_segment(bvec, bio, iter) { - if (use_page_offsets) - offset = page_offset(bvec.bv_page) + bvec.bv_offset; + if (use_page_offsets) { + struct page *page = bvec.bv_page; + + if (fscrypt_is_bounce_page(page)) + page = fscrypt_pagecache_page(page); + offset = page_offset(page) + bvec.bv_offset; + } if (!ordered) { ordered = btrfs_lookup_ordered_extent(inode, offset); diff --git a/fs/btrfs/fscrypt.c b/fs/btrfs/fscrypt.c index a11bf78c2a33..d4fba4c581c7 100644 --- a/fs/btrfs/fscrypt.c +++ b/fs/btrfs/fscrypt.c @@ -190,11 +190,28 @@ static bool btrfs_fscrypt_empty_dir(struct inode *inode) static void btrfs_fscrypt_get_iv(u8 *iv, int ivsize, struct inode *inode, u64 lblk_num) { - /* - * For encryption that doesn't involve extent data, juse use the - * nonce already loaded into the iv buffer. - */ - return; + u64 offset = lblk_num << inode->i_blkbits; + struct extent_map *em; + + if (lblk_num == 0) { + /* Must be a filename or a symlink. Just use the nonce. */ + return; + } + + /* Since IO must be in progress on this extent, this must succeed */ + em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, PAGE_SIZE); + ASSERT(!IS_ERR(em) && em); + if (em) { + __le64 *iv_64 = (__le64 *)iv; + memcpy(iv, em->iv, ivsize); + /* + * Add the lblk_num to the low bits of the IV to ensure + * the IV changes for every page + */ + *iv_64 = cpu_to_le64(le64_to_cpu(*iv_64) + lblk_num); + free_extent_map(em); + return; + } } const struct fscrypt_operations btrfs_fscrypt_ops = { diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index 458877442ce5..6908dcb5d737 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -273,9 +273,14 @@ static int check_extent_data_item(struct extent_buffer *leaf, return -EUCLEAN; } - /* Compressed inline extent has no on-disk size, skip it */ - if (btrfs_file_extent_compression(leaf, fi) != - BTRFS_COMPRESS_NONE) + /* + * Compressed inline extent has no on-disk size; encrypted has + * variable size; skip them + */ + if ((btrfs_file_extent_compression(leaf, fi) != + BTRFS_COMPRESS_NONE) || + (btrfs_file_extent_encryption(leaf, fi) != + BTRFS_ENCRYPTION_NONE)) return 0; /* Uncompressed inline extent size must match item size */ From patchwork Sun Jul 24 00:54:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 12927407 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B34FEC43334 for ; Sun, 24 Jul 2022 00:55:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239744AbiGXAzu (ORCPT ); Sat, 23 Jul 2022 20:55:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39284 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239645AbiGXAza (ORCPT ); Sat, 23 Jul 2022 20:55:30 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C482A1AF0D; Sat, 23 Jul 2022 17:55:02 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 96322807A4; Sat, 23 Jul 2022 20:55:01 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1658624102; bh=eVguuHHegnTXNgvA1tG76WR6VpqBsMJVZtUKyb1tRVw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RRcRnkwRtoTWoAd7/i4fqTHDWN86KcAT1TZ5cBeaMlOJ5w2W1hZuBkabwYjTbeKse XsdMf07AkcEWhnOr9e5f6a6Qpt9GNTOMW9+QaVDknqzmf2NT2ylHS+faHtOLRu6cCI y+BQXiDC1t5UTNHNK8oQbRcZ3SiYHncTzKUTJbfDDaN572k5PTkUwSHFPwDeOZKu+b /9lShn7XHc+Q14ppDYAMCIctgJ1XAYlDmWGLnRUapurow1k3mpFlviRHvvWe59fDP9 nraXqo1x5lRZsKU/jjkJb7NpcjP/fsY8LhNkYttYYAJ6U+c1wbx0XT20weMqvEN3pH M4nvmaQpIS9kA== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, osandov@osandov.com, kernel-team@fb.com Cc: Sweet Tea Dorminy Subject: [PATCH RFC v2 16/16] btrfs: implement fscrypt ioctls Date: Sat, 23 Jul 2022 20:54:01 -0400 Message-Id: <0f50c0da5b20c80dfd415ae03ec98c8939ec1454.1658623319.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org From: Omar Sandoval These ioctls allow encryption to be set up. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/ioctl.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 708e514aca25..2f91abb62a1d 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -5457,6 +5457,34 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_get_fslabel(fs_info, argp); case FS_IOC_SETFSLABEL: return btrfs_ioctl_set_fslabel(file, argp); + case FS_IOC_SET_ENCRYPTION_POLICY: { + if (!IS_ENABLED(CONFIG_FS_ENCRYPTION)) + return -EOPNOTSUPP; + if (sb_rdonly(fs_info->sb)) + return -EOPNOTSUPP; + /* + * If we crash before we commit, nothing encrypted could have + * been written so it doesn't matter whether the encrypted + * state persists. + */ + btrfs_set_fs_incompat(fs_info, FSCRYPT); + return fscrypt_ioctl_set_policy(file, (const void __user *)arg); + } + case FS_IOC_GET_ENCRYPTION_POLICY: + return fscrypt_ioctl_get_policy(file, (void __user *)arg); + case FS_IOC_GET_ENCRYPTION_POLICY_EX: + return fscrypt_ioctl_get_policy_ex(file, (void __user *)arg); + case FS_IOC_ADD_ENCRYPTION_KEY: + return fscrypt_ioctl_add_key(file, (void __user *)arg); + case FS_IOC_REMOVE_ENCRYPTION_KEY: + return fscrypt_ioctl_remove_key(file, (void __user *)arg); + case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS: + return fscrypt_ioctl_remove_key_all_users(file, + (void __user *)arg); + case FS_IOC_GET_ENCRYPTION_KEY_STATUS: + return fscrypt_ioctl_get_key_status(file, (void __user *)arg); + case FS_IOC_GET_ENCRYPTION_NONCE: + return fscrypt_ioctl_get_nonce(file, (void __user *)arg); case FITRIM: return btrfs_ioctl_fitrim(fs_info, argp); case BTRFS_IOC_SNAP_CREATE: