From patchwork Wed Jul 13 10:29:34 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: 12916510 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 7AD26C433EF for ; Wed, 13 Jul 2022 10:30:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236013AbiGMKae (ORCPT ); Wed, 13 Jul 2022 06:30:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54256 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235991AbiGMKab (ORCPT ); Wed, 13 Jul 2022 06:30:31 -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 CEECDFC989 for ; Wed, 13 Jul 2022 03:30: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 F18B6800E3; Wed, 13 Jul 2022 06:30:29 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708230; bh=hJwjrkM7sbjKkmMCEskDCEA0B2CaXAXdjO53qmeWx+E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BMsuvbdFlV44QW7ajkwWsFmKO+bE/Bj0GBMNZJ5gadknSTZsie/PUWuBQf5RGMhXj 5+8oNRcw02loucz5tRbTq63slmDc8uygX/MNaWkao49B5TW5wDvBz7ywqVaKMEXPbO 2L+jTgnQjgk+fVv3xSksHdjgeogjZU0MZTBkroI+Vd9H/hMtN1PuxnrdPH2Qne0bMc Eh/Y1ptavT78z4ufcEoV2oZRqsiC57QF6rwa7IWYK3kZmDu+pDwzoVGA2dtCCzUsGQ ECQcl9cd30ZCBl2wRdHbLLLFSbWPkNh0DuYRwv5ApVd9TrTNT1ZMFKtzguyEzj9D+X QNkRtHS2u9lkA== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [RFC ONLY 01/23] btrfs: change btrfs_insert_file_extent() to btrfs_insert_hole_extent() Date: Wed, 13 Jul 2022 06:29:34 -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 btrfs_insert_file_extent() is only ever used to insert holes, so rename it and remove the redundant parameters. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/ctree.h | 9 +++------ fs/btrfs/file-item.c | 21 +++++++++------------ fs/btrfs/file.c | 4 ++-- fs/btrfs/inode.c | 4 ++-- fs/btrfs/tree-log.c | 13 +++++-------- 5 files changed, 21 insertions(+), 30 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 0ae7f6530da1..4c351b96115b 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3260,12 +3260,9 @@ int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset); int btrfs_del_csums(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 len); blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u8 *dst); -int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 objectid, u64 pos, - u64 disk_offset, u64 disk_num_bytes, - u64 num_bytes, u64 offset, u64 ram_bytes, - u8 compression, u8 encryption, u16 other_encoding); +int btrfs_insert_hole_extent(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 objectid, u64 pos, + u64 num_bytes); int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 objectid, diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index c828f971a346..29999686d234 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -129,12 +129,9 @@ static inline u32 max_ordered_sum_bytes(struct btrfs_fs_info *fs_info, return ncsums * fs_info->sectorsize; } -int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, +int btrfs_insert_hole_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, - u64 objectid, u64 pos, - u64 disk_offset, u64 disk_num_bytes, - u64 num_bytes, u64 offset, u64 ram_bytes, - u8 compression, u8 encryption, u16 other_encoding) + u64 objectid, u64 pos, u64 num_bytes) { int ret = 0; struct btrfs_file_extent_item *item; @@ -157,16 +154,16 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, leaf = path->nodes[0]; item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); - btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset); - btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes); - btrfs_set_file_extent_offset(leaf, item, offset); + btrfs_set_file_extent_disk_bytenr(leaf, item, 0); + btrfs_set_file_extent_disk_num_bytes(leaf, item, 0); + btrfs_set_file_extent_offset(leaf, item, 0); btrfs_set_file_extent_num_bytes(leaf, item, num_bytes); - btrfs_set_file_extent_ram_bytes(leaf, item, ram_bytes); + btrfs_set_file_extent_ram_bytes(leaf, item, num_bytes); btrfs_set_file_extent_generation(leaf, item, trans->transid); btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); - btrfs_set_file_extent_compression(leaf, item, compression); - btrfs_set_file_extent_encryption(leaf, item, encryption); - btrfs_set_file_extent_other_encoding(leaf, item, other_encoding); + btrfs_set_file_extent_compression(leaf, item, 0); + btrfs_set_file_extent_encryption(leaf, item, 0); + btrfs_set_file_extent_other_encoding(leaf, item, 0); btrfs_mark_buffer_dirty(leaf); out: diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 1876072dee9d..d0172cb54d9f 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2549,8 +2549,8 @@ static int fill_holes(struct btrfs_trans_handle *trans, } btrfs_release_path(path); - ret = btrfs_insert_file_extent(trans, root, btrfs_ino(inode), - offset, 0, 0, end - offset, 0, end - offset, 0, 0, 0); + ret = btrfs_insert_hole_extent(trans, root, btrfs_ino(inode), offset, + end - offset); if (ret) return ret; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index c4e1d1491c6c..2a9e6675c77e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5027,8 +5027,8 @@ static int maybe_insert_hole(struct btrfs_root *root, struct btrfs_inode *inode, return ret; } - ret = btrfs_insert_file_extent(trans, root, btrfs_ino(inode), - offset, 0, 0, len, 0, len, 0, 0, 0); + ret = btrfs_insert_hole_extent(trans, root, btrfs_ino(inode), offset, + len); if (ret) { btrfs_abort_transaction(trans, ret); } else { diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index d898ba13285f..fa923a9e79c4 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -5219,10 +5219,9 @@ static int btrfs_log_holes(struct btrfs_trans_handle *trans, * leafs from the log root. */ btrfs_release_path(path); - ret = btrfs_insert_file_extent(trans, root->log_root, - ino, prev_extent_end, 0, - 0, hole_len, 0, hole_len, - 0, 0, 0); + ret = btrfs_insert_hole_extent(trans, root->log_root, + ino, prev_extent_end, + hole_len); if (ret < 0) return ret; @@ -5251,10 +5250,8 @@ static int btrfs_log_holes(struct btrfs_trans_handle *trans, btrfs_release_path(path); hole_len = ALIGN(i_size - prev_extent_end, fs_info->sectorsize); - ret = btrfs_insert_file_extent(trans, root->log_root, - ino, prev_extent_end, 0, 0, - hole_len, 0, hole_len, - 0, 0, 0); + ret = btrfs_insert_hole_extent(trans, root->log_root, ino, + prev_extent_end, hole_len); if (ret < 0) return ret; } From patchwork Wed Jul 13 10:29:35 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: 12916511 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 64AFFC43334 for ; Wed, 13 Jul 2022 10:30:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236017AbiGMKah (ORCPT ); Wed, 13 Jul 2022 06:30:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54340 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236014AbiGMKaf (ORCPT ); Wed, 13 Jul 2022 06:30:35 -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 AEC36FB8FD for ; Wed, 13 Jul 2022 03:30:34 -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 E59C780025; Wed, 13 Jul 2022 06:30:33 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708234; bh=m5CcoZNkpurW6kdU2fMVc2AJQxvalyUaUOixOrowN6c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=L5lZwnOoMh6gNQUXQkhHchIgUZkFDlyedBEKPR2xaiSW91zC82++1rYb9hOJDdGLW 7yicBd1s1nbV0EXa+KISbv5dRDrOPazR+RUatM9yWT2p3NG8c63QMXjpRiY7j9jT5m PB74xMI2RdUHXfONfweVRM3R7a/rmb5BtjWB2FoEWtpARRc1V5MHf3rUddYKrzVyPQ 3PnCw80psb0fvsEkJ/azzznfigIFs2yEYMJgb1edVKso+fMZR7JM4e5DzLoHSxZzCF ISOOdwtrvtYEN0MO7NJP66wMZk4XzJg+iyXUojfAZ8WVmpw6XpFvyxTE22u8ZUuRqz vGZt+d4Tdo0lQ== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [RFC ONLY 02/23] btrfs: rename dir_item's dir_type field to dir_flags Date: Wed, 13 Jul 2022 06:29:35 -0400 Message-Id: <932c0b60f3a243d869636cc5782f18d1bf39f267.1657707686.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 The encryption status of the directory is orthogonal to the existing directory types, and there is no room in other fields. Therefore, rename the dir_type field to dir_flags to reflect its new usage. 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 | 5 +++++ 10 files changed, 41 insertions(+), 27 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 4c351b96115b..538a1f357e59 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2105,10 +2105,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, @@ -2116,6 +2116,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 ad4fa8c173fa..ef4655c6a92a 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1403,7 +1403,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; @@ -1435,7 +1435,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); @@ -1753,7 +1753,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 2a9e6675c77e..057744b8815c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5571,7 +5571,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; @@ -6009,6 +6009,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; @@ -6032,13 +6033,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 7def51462f6b..21e25c445fc9 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1075,7 +1075,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 fa923a9e79c4..87a4438b90da 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..15b3f2d43f6c 100644 --- a/include/uapi/linux/btrfs_tree.h +++ b/include/uapi/linux/btrfs_tree.h @@ -360,6 +360,11 @@ enum btrfs_csum_type { #define BTRFS_FT_XATTR 8 #define BTRFS_FT_MAX 9 +static inline __u8 btrfs_dir_flags_to_ftype(__u8 flags) +{ + return flags; +} + /* * The key defines the order in the tree, and so it also defines (optimal) * block layout. From patchwork Wed Jul 13 10:29:36 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: 12916512 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 384C5CCA479 for ; Wed, 13 Jul 2022 10:30:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236030AbiGMKaj (ORCPT ); Wed, 13 Jul 2022 06:30:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54438 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236018AbiGMKai (ORCPT ); Wed, 13 Jul 2022 06:30:38 -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 BF99AFC994 for ; Wed, 13 Jul 2022 03:30: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 E7CFB80025; Wed, 13 Jul 2022 06:30:36 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708237; bh=9fJU7whwY0k3RT5am0IMjorfCIjaTIc+WsQYac7/JLE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZFa2OzLGxz/kUq1WyiJySD2fjAD2r9D3mB2QyHJfGqt8ofDHoMgH9kJQYLlbUZy0n j6aWMMNn8+h0UiCnxFkjmOIwY5WMMRkcFu1HCNlqojj8TR3cBiNLSF0zYVSzZNBHBJ wlP7H3YWMz47TBrP1ZesEZmEzAwcrptD1ErrCCzWfC43d4+00I9Ixa584Y2awph0wz GGm3TA/Nug/Mp7zOvwzCdrSjJuTSMBSaK3+muo3kZofW/ttFrpNVXqH/bMeM+C8Yep F6Zz8mG0oLt7o+G79oeaGsHvKLgfOET51dBJoJDhAUGvoey+W34Z9VvE0jfTp607UJ dFWJVYA6DDbdg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [RFC ONLY 03/23] btrfs: add new FT_FSCRYPT flag for directories. Date: Wed, 13 Jul 2022 06:29:36 -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 The new 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: Sweet Tea Dorminy --- include/uapi/linux/btrfs_tree.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h index 15b3f2d43f6c..428ae75b9f73 100644 --- a/include/uapi/linux/btrfs_tree.h +++ b/include/uapi/linux/btrfs_tree.h @@ -359,10 +359,12 @@ 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; + return flags & ~BTRFS_FT_FSCRYPT_NAME; } /* From patchwork Wed Jul 13 10:29:37 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: 12916513 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 13DF5C43334 for ; Wed, 13 Jul 2022 10:30:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236020AbiGMKao (ORCPT ); Wed, 13 Jul 2022 06:30:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54540 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236034AbiGMKan (ORCPT ); Wed, 13 Jul 2022 06:30:43 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7CD7CFC997 for ; Wed, 13 Jul 2022 03:30: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 8AFE9806E0; Wed, 13 Jul 2022 06:30:41 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708242; bh=KRDfQQ1XpGCjjKVjRpwiQNGfKQ8imAWi4dsTAgZ/0Cc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RAjgSe9Tr3AzSUqx84Sbh5Qw1HnjTbkWQRPEcUVMh3sHd6KZLbUH/ozT8FxwNaGfk Q/IiP4jeMbGyPh8dRGWsBoCelWj1iJ+JlhGbrwbvT8C1NtQaJWWkgCMUCCCFu3qsVT Np9Qim9B8UxAQ3Tn84O1rjhhkSQtxiIfrOBzP/wW+YV4s98QoyeHHjtbA5iU4398ND cDFKVN3lVpNnhPKvCHshZuUM+0tLRU72JLUSO5P8cQBtotrHfe8oOP+nyroApkyk3Y 0h9TliE9yysjT18XN8uvV+t/b4Lwx6f9kj7FqmWSPGEoB8bideZRgFJnNaTz0Zk+C5 n0vCQzSGg4jmg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [RFC ONLY 04/23] btrfs: explicitly keep track of file extent item size. Date: Wed, 13 Jul 2022 06:29:37 -0400 Message-Id: <1683e20a7e9827a8197c15d006c78ea278641182.1657707686.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 Previously, file extents were always of constant size. However, for fscrypt, they will need to store an IV, and this IV varies in length according to the encryption algorithm, making the file extent items also of variable length. Therefore, this begins passing around the actual file extent item size instead of assuming it is merely the size of the item in memory. Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/ctree.h | 1 + fs/btrfs/file.c | 4 ++-- fs/btrfs/inode.c | 1 + fs/btrfs/reflink.c | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 538a1f357e59..ddff384604ee 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1355,6 +1355,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 diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index d0172cb54d9f..a93b205c663b 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2687,14 +2687,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/inode.c b/fs/btrfs/inode.c index 057744b8815c..43ebf37a156e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -9966,6 +9966,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; diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c index 9acf47b11fe6..e5c2616a486e 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, From patchwork Wed Jul 13 10:29:38 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: 12916514 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 6985AC43334 for ; Wed, 13 Jul 2022 10:30:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236023AbiGMKar (ORCPT ); Wed, 13 Jul 2022 06:30:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54690 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236018AbiGMKaq (ORCPT ); Wed, 13 Jul 2022 06:30:46 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8DA38E6837 for ; Wed, 13 Jul 2022 03:30:44 -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 C687680025; Wed, 13 Jul 2022 06:30:43 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708244; bh=UUsWW2H74bRM8CltDA3VrKMB1e9TXdqubzY/rNa+OWg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nO0udH1CEpk1Jt0j0Ebc+0XGAkOAblmDqZBZW/kpPS4C8myYyX3WqMR0V4M8iluk2 D0gHSUfI9hmEtyeXF+RdbjWPeReEAVHMMPATp52n/iY1mQ5HpLU5B5Ib1M5vgStkE7 Mqtqcb6URWgrgM6qhNfDdSuAx0GrZX0FpBW/VituL3xHNR+XCAqxkG6imU0hqWEbpW wJZX23Uj9btC7QVpWeOSwL9fnm0Ue3i5y6tYw61uCxnnnCmRlN5JaAYLEdd/fT3r1M bpPSH+mTg+PdD7IE+BjQsi3FogY6OcF8dL0quLzWwhsf9e/Ud51n9xUnbUWm261Xnp 5ATZXfMrdC4wA== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [RFC ONLY 05/23] btrfs: factor out a memcmp for two extent_buffers. Date: Wed, 13 Jul 2022 06:29:38 -0400 Message-Id: <1597152cf099a878c604106d3db0200f0aceed09.1657707686.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 Tree log has its own implementation of comparing two extent_buffer's contents; pull it out and generalize it into extent_io. Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/extent_io.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/extent_io.h | 4 ++++ fs/btrfs/tree-log.c | 33 +++++++++++------------------ 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 54ed383e7400..754db5fa262b 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -6853,6 +6853,55 @@ int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv, return ret; } +int memcmp_2_extent_buffers(const struct extent_buffer *eb1, + unsigned long start1, + const struct extent_buffer *eb2, + unsigned long start2, unsigned long len) +{ + unsigned long i1, i2; + size_t offset1, offset2; + char *kaddr1, *kaddr2; + int ret = 0; + + if (check_eb_range(eb1, start1, len) || + check_eb_range(eb2, start2, len)) + return -EINVAL; + + if (len == 0) + return ret; + + i1 = get_eb_page_index(start1); + offset1 = get_eb_offset_in_page(eb1, start1); + kaddr1 = page_address(eb1->pages[i1]); + + i2 = get_eb_page_index(start2); + offset2 = get_eb_offset_in_page(eb2, start2); + kaddr2 = page_address(eb2->pages[i2]); + + while (true) { + size_t cur; + + cur = min3(len, PAGE_SIZE - offset1, PAGE_SIZE - offset2); + ret = memcmp(kaddr1 + offset1, kaddr2 + offset2, cur); + if (ret || cur == len) + break; + len -= cur; + offset1 += cur; + if (offset1 == PAGE_SIZE) { + offset1 = 0; + i1++; + kaddr1 = page_address(eb1->pages[i1]); + } + offset2 += cur; + if (offset2 == PAGE_SIZE) { + offset2 = 0; + i2++; + kaddr2 = page_address(eb2->pages[i2]); + } + } + return ret; +} + /* * Check that the extent buffer is uptodate. * diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index a76c6ef74cd3..df0ff1c78998 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -197,6 +197,10 @@ static inline int extent_buffer_uptodate(const struct extent_buffer *eb) int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv, unsigned long start, unsigned long len); +int memcmp_2_extent_buffers(const struct extent_buffer *eb1, + unsigned long start1, + const struct extent_buffer *eb2, + unsigned long start2, unsigned long len); void read_extent_buffer(const struct extent_buffer *eb, void *dst, unsigned long start, unsigned long len); diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 87a4438b90da..dc4bc6b384d5 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -635,11 +635,13 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, u64 start = key->offset; u64 nbytes = 0; struct btrfs_file_extent_item *item; + u32 item_size; struct inode *inode = NULL; unsigned long size; int ret = 0; item = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); + item_size = btrfs_item_size(eb, slot); found_type = btrfs_file_extent_type(eb, item); if (found_type == BTRFS_FILE_EXTENT_REG || @@ -679,29 +681,18 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, if (ret == 0 && (found_type == BTRFS_FILE_EXTENT_REG || - found_type == BTRFS_FILE_EXTENT_PREALLOC)) { - struct btrfs_file_extent_item cmp1; - struct btrfs_file_extent_item cmp2; - struct btrfs_file_extent_item *existing; - struct extent_buffer *leaf; - - leaf = path->nodes[0]; - existing = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - - read_extent_buffer(eb, &cmp1, (unsigned long)item, - sizeof(cmp1)); - read_extent_buffer(leaf, &cmp2, (unsigned long)existing, - sizeof(cmp2)); - + found_type == BTRFS_FILE_EXTENT_PREALLOC) && + btrfs_item_size(path->nodes[0], path->slots[0]) == item_size && + memcmp_2_extent_buffers(eb, (unsigned long)item, path->nodes[0], + btrfs_item_ptr_offset(path->nodes[0], + path->slots[0]), + item_size) == 0) { /* * we already have a pointer to this exact extent, * we don't have to do anything */ - if (memcmp(&cmp1, &cmp2, sizeof(cmp1)) == 0) { - btrfs_release_path(path); - goto out; - } + btrfs_release_path(path); + goto out; } btrfs_release_path(path); @@ -724,13 +715,13 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, goto update_inode; ret = btrfs_insert_empty_item(trans, root, path, key, - sizeof(*item)); + item_size); if (ret) goto out; dest_offset = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]); copy_extent_buffer(path->nodes[0], eb, dest_offset, - (unsigned long)item, sizeof(*item)); + (unsigned long)item, item_size); ins.objectid = btrfs_file_extent_disk_bytenr(eb, item); ins.offset = btrfs_file_extent_disk_num_bytes(eb, item); From patchwork Wed Jul 13 10:29:39 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: 12916515 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 A5DAAC43334 for ; Wed, 13 Jul 2022 10:30:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236033AbiGMKaw (ORCPT ); Wed, 13 Jul 2022 06:30:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54780 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235404AbiGMKau (ORCPT ); Wed, 13 Jul 2022 06:30:50 -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 7B98CE6837 for ; Wed, 13 Jul 2022 03:30:47 -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 5A7B1806E0; Wed, 13 Jul 2022 06:30:46 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708247; bh=YV/voZpLIte0cWOt0wJ9F1r/gDjh0Ba6eyGb1+f4k1U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eKE+BGz5oU9F//xxXYkhd7iUInTou2YVBb2w30xluqUOm16dykDBlsJKxHGF/7wqq MCuudyi9s3WKlloNe/R3JjrfwYFUBv/PVDnrZg4y9NERdkLgnsnpsXdNnR56sQWpVZ HGYaf2846vQwIrWdsDofjx6JgUj47uFPk/zoLwv/I0WxyoNR+RcguhjBochOZHz4tT D/fnTVG9jvcgwtKAlZyyBoRHzifOQHKsKCFLXU0jUqJS+pHuv7vvHXRHIa9Tqh9quT QGUEMA9W+FWKV9OpVKG0puvchJHcISXKdoPf//QHxN/JT7shBmUA5i7OUTYcqvglut gmjU/2G4iUP4w== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [RFC ONLY 06/23] btrfs: use fscrypt_name's instead of name/len everywhere. Date: Wed, 13 Jul 2022 06:29:39 -0400 Message-Id: <79b061dd2ad23db0247c6ae6c0b7e087541c40f3.1657707686.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 | 195 ++++++++++++++++++--------------- 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 | 23 ++-- 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, 529 insertions(+), 400 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index ddff384604ee..7195090dc839 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" @@ -2738,18 +2740,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(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, + 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) @@ -3185,11 +3188,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, + 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, @@ -3218,25 +3221,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); + struct fscrypt_name *fname); +int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, + 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, + 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, 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); + struct fscrypt_name *fname); int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, @@ -3244,17 +3248,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, + 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, + 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); + struct fscrypt_name *name); /* orphan.c */ int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, @@ -3314,10 +3317,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); + 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); @@ -3333,6 +3337,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 ef4655c6a92a..d8ac12fdd991 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1401,7 +1401,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) @@ -1419,7 +1419,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; @@ -1434,9 +1435,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); @@ -1487,7 +1488,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..fcc1a1a7dc2e 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) + 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, + 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, + 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, 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, + 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) + 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, 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) + 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, + 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) + 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..c6b382dd6295 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, + 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, + 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, + 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, + 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..ed3486fe6b68 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, + 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, + 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, + 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 43ebf37a156e..27742237ac7d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3870,11 +3870,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++; @@ -4261,7 +4269,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, + struct fscrypt_name *fname, struct btrfs_rename_ctx *rename_ctx) { struct btrfs_root *root = dir->root; @@ -4279,8 +4287,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; @@ -4308,12 +4315,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; } @@ -4334,10 +4340,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); } /* @@ -4355,7 +4359,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); @@ -4368,10 +4372,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) + 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); @@ -4407,6 +4411,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)) @@ -4416,8 +4424,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; @@ -4442,12 +4449,13 @@ 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(dentry->d_name.name, dentry->d_name.len) + }; if (btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID) { objectid = inode->root->root_key.objectid; @@ -4462,8 +4470,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; @@ -4489,8 +4496,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; @@ -4507,7 +4513,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; @@ -4520,7 +4526,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; @@ -4544,6 +4550,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) @@ -4552,7 +4562,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) { @@ -4791,6 +4801,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; @@ -4820,8 +4833,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); /* @@ -5543,19 +5555,20 @@ 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(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; @@ -5567,7 +5580,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) @@ -6251,6 +6264,14 @@ int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args, if (ret) return ret; + if (!args->orphan) { + const char *name = 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 */ @@ -6324,8 +6345,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; @@ -6426,7 +6445,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); } } @@ -6465,10 +6484,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)); } } @@ -6528,8 +6550,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); @@ -6558,7 +6581,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; @@ -6577,17 +6600,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; @@ -6597,7 +6620,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 @@ -6620,17 +6643,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); } @@ -6713,6 +6737,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(dentry->d_name.name, + dentry->d_name.len) + }; u64 index; int err; int drop_inode = 0; @@ -6749,8 +6777,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; @@ -9141,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(old_dentry->d_name.name, + old_dentry->d_name.len) + }; + struct fscrypt_name new_name = { + .disk_name = FSTR_INIT(new_dentry->d_name.name, + new_dentry->d_name.len) + }; /* * For non-subvolumes allow exchange only within one subvolume, in the @@ -9219,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) @@ -9235,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) { @@ -9272,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)); @@ -9289,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)); @@ -9302,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; @@ -9393,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(old_dentry->d_name.name, + old_dentry->d_name.len) + }; + struct fscrypt_name new_fname = { + .disk_name = FSTR_INIT(new_dentry->d_name.name, + new_dentry->d_name.len) + }; if (btrfs_ino(BTRFS_I(new_dir)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID) return -EPERM; @@ -9409,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) { @@ -9507,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; } @@ -9534,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)); } @@ -9555,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, @@ -9568,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..352f890c53ec 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(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..7fc0a9e6a152 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(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(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..4ce2993a0960 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, + 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 21e25c445fc9..cc14d7eee5ff 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "send.h" #include "ctree.h" @@ -1021,7 +1022,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); @@ -1071,6 +1072,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); @@ -1123,8 +1125,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; @@ -1578,13 +1583,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); @@ -1604,7 +1613,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); @@ -1726,7 +1735,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; @@ -1739,7 +1748,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; @@ -1829,7 +1838,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; @@ -1843,12 +1852,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); @@ -1866,7 +1875,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; @@ -1898,7 +1907,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; @@ -1939,7 +1948,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; @@ -1966,7 +1975,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; @@ -2014,7 +2023,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; @@ -2026,8 +2035,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); @@ -2158,6 +2171,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 @@ -2222,8 +2236,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) { @@ -3490,6 +3507,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; @@ -3500,7 +3520,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) { @@ -3510,8 +3530,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; @@ -3992,6 +4011,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; @@ -4005,14 +4028,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) { @@ -4258,9 +4279,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) { @@ -4602,7 +4627,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; @@ -4612,7 +4637,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); @@ -4624,7 +4650,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; @@ -4633,7 +4659,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); @@ -4643,7 +4670,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; @@ -4652,7 +4679,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(); @@ -4665,8 +4692,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); @@ -4679,7 +4708,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); @@ -4687,7 +4716,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; @@ -4702,7 +4731,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); @@ -4726,20 +4755,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); @@ -4753,14 +4783,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; @@ -4782,7 +4811,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) { @@ -4792,15 +4821,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; @@ -4812,7 +4841,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) { @@ -4820,9 +4849,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; @@ -5484,13 +5513,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; @@ -5516,8 +5548,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 0a50d5746f6f..4ef6299af949 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1600,8 +1600,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; @@ -1611,7 +1612,7 @@ 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; @@ -1623,6 +1624,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(pending->dentry->d_name.name, + pending->dentry->d_name.len) + }; ASSERT(pending->path); path = pending->path; @@ -1678,8 +1683,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; @@ -1774,7 +1778,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; @@ -1806,8 +1810,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); @@ -1816,8 +1819,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 dc4bc6b384d5..118ab4f5bb11 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -892,12 +892,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) + 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; /* @@ -929,6 +928,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]; @@ -941,6 +941,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; @@ -951,8 +955,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); @@ -969,14 +972,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) + 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; @@ -989,7 +992,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; @@ -1016,7 +1019,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; @@ -1037,11 +1040,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; @@ -1054,7 +1057,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; @@ -1091,6 +1095,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); @@ -1101,10 +1106,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; @@ -1112,8 +1119,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; @@ -1134,7 +1141,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)) { @@ -1149,6 +1156,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); @@ -1162,14 +1170,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; @@ -1183,9 +1192,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); @@ -1204,7 +1211,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) { @@ -1216,7 +1223,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) { @@ -1230,20 +1237,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); @@ -1254,18 +1265,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); @@ -1307,16 +1322,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) @@ -1324,11 +1338,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; @@ -1337,20 +1351,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 @@ -1363,8 +1377,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; @@ -1380,7 +1393,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) @@ -1391,10 +1404,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); @@ -1402,8 +1415,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; @@ -1418,7 +1431,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; @@ -1439,8 +1452,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; /* @@ -1450,8 +1463,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); @@ -1476,8 +1489,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; @@ -1521,8 +1532,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 @@ -1535,7 +1547,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) @@ -1543,7 +1555,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) { @@ -1561,7 +1573,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) @@ -1579,12 +1591,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 @@ -1597,8 +1609,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; @@ -1608,9 +1619,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; @@ -1634,7 +1644,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; @@ -1906,7 +1915,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; @@ -1923,8 +1932,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 */ @@ -1998,6 +2007,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) @@ -2013,6 +2023,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); @@ -2023,7 +2036,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; @@ -2040,7 +2053,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; @@ -2068,7 +2081,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) { @@ -2081,8 +2094,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) { @@ -2093,7 +2105,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) @@ -2276,6 +2288,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 @@ -2296,6 +2309,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; @@ -2303,7 +2319,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; @@ -2328,8 +2344,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 @@ -2389,6 +2405,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) { @@ -2397,15 +2414,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); @@ -3577,7 +3597,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, + struct fscrypt_name *fname, u64 index) { struct btrfs_dir_item *di; @@ -3587,7 +3607,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) @@ -3624,7 +3644,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, + struct fscrypt_name *fname, struct btrfs_inode *dir, u64 index) { struct btrfs_path *path; @@ -3651,7 +3671,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); @@ -3663,7 +3683,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, + struct fscrypt_name *fname, struct btrfs_inode *inode, u64 dirid) { struct btrfs_root *log; @@ -3684,7 +3704,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) @@ -5318,6 +5338,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; @@ -5351,8 +5372,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; @@ -7008,6 +7033,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(old_dentry->d_name.name, + old_dentry->d_name.len) + }; ASSERT(old_dir_index >= BTRFS_DIR_START_INDEX); @@ -7038,8 +7067,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..981349233041 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, + 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, + 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..fd6d854d0657 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(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(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 Wed Jul 13 10:29:40 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: 12916516 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 566B4CCA479 for ; Wed, 13 Jul 2022 10:30:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236042AbiGMKa4 (ORCPT ); Wed, 13 Jul 2022 06:30:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54822 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236034AbiGMKax (ORCPT ); Wed, 13 Jul 2022 06:30:53 -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 90CBBFC989 for ; Wed, 13 Jul 2022 03:30: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 8F1D28111E; Wed, 13 Jul 2022 06:30:49 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708251; bh=4uqpGo8qy3Bvwxt2inUNeCmG/GdZeE2uhg525J81V0A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cYOpfLxBLOLSR9zAoT2dhOO8YO85yDvHPb05f+XrSvHNhJ6ZU3/Uo9im0lNPYtLz0 9uWYr4LACkxgxVYSH8lGQ4XDXcXE6ybp6P4OdLmrZd4TM0g9VeMGUup1usWwwmGGOs +cDAe0CeGKO0yBdviM1A8jO7l2EhECPI4Ut2hFAa3aXeBjDUzO3DK8Ve00jXO0lKlk wWYaOqA5h/agdQfzAdANCvnYOfGw7X5RHMjpP70bQQaO51U4+oATSWLGqUvjzy1u8g 7MfxZr6hhz/50wHh/E7IG0adwtjz7Oh9AktZsapMGB8SO6Szv+vzwaGLTB8O5CSi8n TBwTEGCQBt7Dg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [RFC ONLY 07/23] btrfs: setup fscrypt_names from dentrys using helper Date: Wed, 13 Jul 2022 06:29:40 -0400 Message-Id: <8386fc3358d47243a7fbbf7cb957bc7ed8f342b5.1657707687.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 | 151 ++++++++++++++++++++++++++--------------- fs/btrfs/transaction.c | 26 +++++-- fs/btrfs/tree-log.c | 12 ++-- 3 files changed, 123 insertions(+), 66 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 27742237ac7d..ad556e8d5dac 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4411,14 +4411,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); @@ -4435,6 +4438,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; @@ -4453,9 +4457,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(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; @@ -4463,12 +4469,15 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, objectid = inode->location.objectid; } else { WARN_ON(1); + fscrypt_free_fname(&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)) { @@ -4535,6 +4544,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; } @@ -4801,9 +4811,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; @@ -4816,9 +4824,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); @@ -4852,7 +4866,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; } @@ -5547,7 +5563,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. @@ -5559,14 +5575,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(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)) { @@ -5586,6 +5604,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; } @@ -5606,9 +5625,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; @@ -5654,6 +5679,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; } @@ -6260,16 +6286,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_fname(&args->fname); return ret; - - if (!args->orphan) { - const char *name = 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 */ @@ -6310,6 +6337,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); } /* @@ -6737,10 +6765,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(dentry->d_name.name, - dentry->d_name.len) - }; + struct fscrypt_name fname; u64 index; int err; int drop_inode = 0; @@ -6752,6 +6777,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; @@ -6802,6 +6831,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 +9199,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(old_dentry->d_name.name, - old_dentry->d_name.len) - }; - struct fscrypt_name new_name = { - .disk_name = FSTR_INIT(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 +9211,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 +9288,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 +9301,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 +9335,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 +9350,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 +9361,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 +9411,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 +9452,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(old_dentry->d_name.name, - old_dentry->d_name.len) - }; - struct fscrypt_name new_fname = { - .disk_name = FSTR_INIT(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 +9469,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 +9487,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 +9665,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 4ef6299af949..ac3121068461 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -1624,10 +1625,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(pending->dentry->d_name.name, - pending->dentry->d_name.len) - }; + unsigned int mem_flags; + struct fscrypt_name fname; ASSERT(pending->path); path = pending->path; @@ -1635,9 +1634,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 @@ -1852,7 +1864,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 118ab4f5bb11..4959e8ecc99a 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -7033,13 +7033,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(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 @@ -7052,6 +7052,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; } @@ -7081,6 +7082,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 Wed Jul 13 10:29:41 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: 12916517 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 7E055C433EF for ; Wed, 13 Jul 2022 10:31:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236018AbiGMKa5 (ORCPT ); Wed, 13 Jul 2022 06:30:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54842 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236038AbiGMKay (ORCPT ); Wed, 13 Jul 2022 06:30:54 -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 788F0FACBF for ; Wed, 13 Jul 2022 03:30: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 B826C806E0; Wed, 13 Jul 2022 06:30:52 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708253; bh=tCTgXhrOCsldrPfdEEqUzU2aDbxjbpNkvnMAH89GXs8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fQ+2HeIBCe0xt+vAYKW+sg7ew1vmcWpZYM57lcDnprHZzM92JoacZDWBsXNj6MjCf fhC4w4AZ71EFXAX3SKvPyjIIBnCRuSa2TFDo+pABZetV4kkVdX84rpXGJINx1mYrNo rxbYVXIYykrsy3NtU7okgg7iNOUjz4o+b4hrte20cmEC9fOJaDxrZp9yZRpS1CdrXo 7KWSRNgxuhUvZCB4RHrYe7ZaLJ9pQZeoQhAzvp/5kPK6oRRVeV0IMDi74v6um4uCGW vX8dF+50E8DRuNDRm5V61INsL5zVwvNOACGjnv4SARlQTBPHKKy+QDcYQEyrQ4/y2d zANrcsYhlQyCQ== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [RFC ONLY 08/23] fscrypt: expose fscrypt_nokey_name Date: Wed, 13 Jul 2022 06:29:41 -0400 Message-Id: <5cc23c462a05f60b8193385de35d030155426506.1657707687.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 btrfs needs to deal with matching names using its own methods, as it uses methods on a struct extent_buffer for comparison of names instead of working against a raw byte array. Thus, it needs to deal in nokey_names just as fscrypt does, and cannot do that unless the structure is exposed. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/fname.c | 39 +-------------------------------------- include/linux/fscrypt.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 14e0ef5e9a20..5d5c26d827fd 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "fscrypt_private.h" @@ -26,43 +25,7 @@ #define FSCRYPT_FNAME_MIN_MSG_LEN 16 /* - * struct fscrypt_nokey_name - identifier for directory entry when key is absent - * - * When userspace lists an encrypted directory without access to the key, the - * filesystem must present a unique "no-key name" for each filename that allows - * it to find the directory entry again if requested. Naively, that would just - * mean using the ciphertext filenames. However, since the ciphertext filenames - * can contain illegal characters ('\0' and '/'), they must be encoded in some - * way. We use base64url. But that can cause names to exceed NAME_MAX (255 - * bytes), so we also need to use a strong hash to abbreviate long names. - * - * The filesystem may also need another kind of hash, the "dirhash", to quickly - * find the directory entry. Since filesystems normally compute the dirhash - * over the on-disk filename (i.e. the ciphertext), it's not computable from - * no-key names that abbreviate the ciphertext using the strong hash to fit in - * NAME_MAX. It's also not computable if it's a keyed hash taken over the - * plaintext (but it may still be available in the on-disk directory entry); - * casefolded directories use this type of dirhash. At least in these cases, - * each no-key name must include the name's dirhash too. - * - * To meet all these requirements, we base64url-encode the following - * variable-length structure. It contains the dirhash, or 0's if the filesystem - * didn't provide one; up to 149 bytes of the ciphertext name; and for - * ciphertexts longer than 149 bytes, also the SHA-256 of the remaining bytes. - * - * This ensures that each no-key name contains everything needed to find the - * directory entry again, contains only legal characters, doesn't exceed - * NAME_MAX, is unambiguous unless there's a SHA-256 collision, and that we only - * take the performance hit of SHA-256 on very long filenames (which are rare). - */ -struct fscrypt_nokey_name { - u32 dirhash[2]; - u8 bytes[149]; - u8 sha256[SHA256_DIGEST_SIZE]; -}; /* 189 bytes => 252 bytes base64url-encoded, which is <= NAME_MAX (255) */ - -/* - * Decoded size of max-size no-key name, i.e. a name that was abbreviated using + * Decoded size of max-size nokey name, i.e. a name that was abbreviated using * the strong hash and thus includes the 'sha256' field. This isn't simply * sizeof(struct fscrypt_nokey_name), as the padding at the end isn't included. */ diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index e60d57c99cb6..6020b738c3b2 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -16,6 +16,7 @@ #include #include #include +#include #include /* @@ -54,6 +55,42 @@ struct fscrypt_name { #define fname_name(p) ((p)->disk_name.name) #define fname_len(p) ((p)->disk_name.len) +/* + * struct fscrypt_nokey_name - identifier for directory entry when key is absent + * + * When userspace lists an encrypted directory without access to the key, the + * filesystem must present a unique "no-key name" for each filename that allows + * it to find the directory entry again if requested. Naively, that would just + * mean using the ciphertext filenames. However, since the ciphertext filenames + * can contain illegal characters ('\0' and '/'), they must be encoded in some + * way. We use base64url. But that can cause names to exceed NAME_MAX (255 + * bytes), so we also need to use a strong hash to abbreviate long names. + * + * The filesystem may also need another kind of hash, the "dirhash", to quickly + * find the directory entry. Since filesystems normally compute the dirhash + * over the on-disk filename (i.e. the ciphertext), it's not computable from + * no-key names that abbreviate the ciphertext using the strong hash to fit in + * NAME_MAX. It's also not computable if it's a keyed hash taken over the + * plaintext (but it may still be available in the on-disk directory entry); + * casefolded directories use this type of dirhash. At least in these cases, + * each no-key name must include the name's dirhash too. + * + * To meet all these requirements, we base64url-encode the following + * variable-length structure. It contains the dirhash, or 0's if the filesystem + * didn't provide one; up to 149 bytes of the ciphertext name; and for + * ciphertexts longer than 149 bytes, also the SHA-256 of the remaining bytes. + * + * This ensures that each no-key name contains everything needed to find the + * directory entry again, contains only legal characters, doesn't exceed + * NAME_MAX, is unambiguous unless there's a SHA-256 collision, and that we only + * take the performance hit of SHA-256 on very long filenames (which are rare). + */ +struct fscrypt_nokey_name { + u32 dirhash[2]; + u8 bytes[149]; + u8 sha256[SHA256_DIGEST_SIZE]; +}; /* 189 bytes => 252 bytes base64url-encoded, which is <= NAME_MAX (255) */ + /* Maximum value for the third parameter of fscrypt_operations.set_context(). */ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 40 From patchwork Wed Jul 13 10:29:42 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: 12916518 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 64565CCA482 for ; Wed, 13 Jul 2022 10:31:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235893AbiGMKbA (ORCPT ); Wed, 13 Jul 2022 06:31:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54896 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236054AbiGMKa5 (ORCPT ); Wed, 13 Jul 2022 06:30:57 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 62DCBFACBF for ; Wed, 13 Jul 2022 03:30: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 77BDB81120; Wed, 13 Jul 2022 06:30:55 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708256; bh=wJnakAvjl3P7TtHWy2P8/6E0Lx1dy9AUQMDU0nlsjKk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AoYrfRkqosBIcBimcP0Yefa2y30NIE9vbHIQohlPfJNYKx/TE4KhAECJwWoygcECb UdquJ7pBpZlAdF7zLVhFxpUouU/qoimV2q0+67VA/tjBml4tenBEFX6IiNsShMMcrf 24Lf4vrpivfeUnQLaG2mlRFLrtiJ6/g03gygxymo8i4aZt3ULd4ZbYHULPm3xVj13+ NimDatuWfWFfEUBz0lQKDsX75C2qk3AL0IJswgamzxivTeWVScKkIFLIX5HbKhtzwX 8k1/+iw/Tt6DBL9Sdpb5y/bHjkiX0wYtD2Jx8nDi5/+wRNPUXl5ih7TA5Mnr6tCxxV uC/f+1PHoy9VQ== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [RFC ONLY 09/23] fscrypt: expose a method to check whether a fscrypt_name is encrypted. Date: Wed, 13 Jul 2022 06:29:42 -0400 Message-Id: <22804364662428bb541c6829da8dfa2a7d19d5b0.1657707687.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 Btrfs, having both encrypted and unencrypted names in the same directory, will need to check whether a fscrypt_name to insert or search for is encrypted, since the directory's encryption status is insufficient for this. Signed-off-by: Sweet Tea Dorminy --- include/linux/fscrypt.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 6020b738c3b2..70d8a710ad39 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -55,6 +55,12 @@ struct fscrypt_name { #define fname_name(p) ((p)->disk_name.name) #define fname_len(p) ((p)->disk_name.len) +static inline bool fname_encrypted(const struct fscrypt_name *fname) +{ + /* This buffer is only allocated if the user name is different */ + return fname->crypto_buf.name != NULL; +} + /* * struct fscrypt_nokey_name - identifier for directory entry when key is absent * From patchwork Wed Jul 13 10:29:43 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: 12916519 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 D1229C43334 for ; Wed, 13 Jul 2022 10:31:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236046AbiGMKbD (ORCPT ); Wed, 13 Jul 2022 06:31:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55002 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236044AbiGMKbA (ORCPT ); Wed, 13 Jul 2022 06:31:00 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D55BFFC9B4 for ; Wed, 13 Jul 2022 03:30:59 -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 C27AD806E0; Wed, 13 Jul 2022 06:30:58 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708259; bh=wfJAp9HbHzQyL6WasEVQ6cipcRmyFeFPpV+4jX8St8o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PQa0WzJnD+hPtYNRGwY2bp7znYcp4jXnH2NJOfnTEoUA8mPyzbIBuMYi3PzkKfX7W cZ441SYwBtfWEjmoYIRrbJawAEntVEglFzg64O1ZdE/ZAgw/sfpZbZhcFr8x3AQhbL YW3zCQVI+n048h4WVG8pzQAjEw9RYBUzGKw+rre1WRsujq2EDxM4XUqe7zJzSNhlju pExXfvfafri0zF5U4U7IyXDEAh9beznTb6pO1ja28MkPwn/nutm6x/MNcqwN7pm8Bc mL+2YKBxeFs4PTvSjOcP8gfK2kt+DU20h66RhaSvEmsMinNjJoX18qjs7O8a8p97nZ hY/nCGiYbbq1Q== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [RFC ONLY 10/23] btrfs: factor a fscrypt_name matching method Date: Wed, 13 Jul 2022 06:29:43 -0400 Message-Id: <4ac9eadd8048579957c16ca3acafa77f72f60667.1657707687.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: 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 | 10 +++++----- fs/btrfs/inode.c | 11 ++++------- fs/btrfs/root-tree.c | 7 ++++--- 9 files changed, 117 insertions(+), 20 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 fcc1a1a7dc2e..e1d769e37ac1 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 754db5fa262b..235f9612676a 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 @@ -7016,6 +7017,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 df0ff1c78998..6bede5cee1a1 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -226,6 +226,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 c6b382dd6295..7f4a1fe4241d 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); @@ -100,7 +100,7 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - const struct fscrypt_name *fname, + struct fscrypt_name *fname, u64 inode_objectid, u64 ref_objectid, u64 *index) { diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ad556e8d5dac..9c9f640be636 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; @@ -5654,14 +5655,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 4ce2993a0960..270721ea2b00 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 Wed Jul 13 10:29:44 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: 12916520 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 B8C01CCA479 for ; Wed, 13 Jul 2022 10:31:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235950AbiGMKbF (ORCPT ); Wed, 13 Jul 2022 06:31:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55030 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236038AbiGMKbD (ORCPT ); Wed, 13 Jul 2022 06:31:03 -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 F191BFC9A9 for ; Wed, 13 Jul 2022 03:31: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 15F9F81123; Wed, 13 Jul 2022 06:31:01 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708262; bh=6MCJ+e5/PWfvm4utkrpeR7F142iqBtAIuLdFWHDFdkM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZLk1vdq6kzC10JsSdwFbBizpuDmz/7xfl9YT6Y1/S1D49+KdDv9CAAEi9iqf3TXlz +gzstzehPvHiVXdV/FWpgl97YHY3ivIugB6/qLQTBjX7qaw+TirERVHIJCAh0ACjnD igDjY/JoM32ZLX9kc9RfzhhLuA4ybj9b2nwXIUumdQXXAI1fgsTNipXesslsTdE7bC HsW2HIkv+puc8sPow3DTNZfG9pULEzORBuL+i1cPLndx3wVSvCeUfxsbn7kzHiKlTy lfrPmDor9FN20DoNHuKYFDeuQpEPUOk1c2Azz9mQn95NAgx8pLY8mECtEniUHbG1UP dx6QFwfGKsQYQ== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [RFC ONLY 11/23] fscrypt: add fscrypt_have_same_policy() to check inode's compatibility Date: Wed, 13 Jul 2022 06:29:44 -0400 Message-Id: <98d767bfecf4c88b2cf40d2ad202ae89a2663811.1657707687.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 btrfs will have the possibility of encrypted and unencrypted files in the same directory, and it's important to not allow these two files to become linked together. Therefore, add a function which allows checking the encryption policies of two inodes to ensure they are compatible. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/policy.c | 26 ++++++++++++++++++++++++++ include/linux/fscrypt.h | 1 + 2 files changed, 27 insertions(+) diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 5f858cee1e3b..5763462af9e8 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -407,6 +407,32 @@ static int fscrypt_get_policy(struct inode *inode, union fscrypt_policy *policy) return fscrypt_policy_from_context(policy, &ctx, ret); } +/** + * fscrypt_have_same_policy() - check whether two inodes have the same policy + * @inode1: the first inode + * @inode2: the second inode + * + * Return: %true if equal, else %false + */ +int fscrypt_have_same_policy(struct inode *inode1, struct inode *inode2) +{ + union fscrypt_policy policy1, policy2; + int err; + + if (!IS_ENCRYPTED(inode1) && !IS_ENCRYPTED(inode2)) + return true; + else if (!IS_ENCRYPTED(inode1) || !IS_ENCRYPTED(inode2)) + return false; + err = fscrypt_get_policy(inode1, &policy1); + if (err) + return err; + err = fscrypt_get_policy(inode2, &policy2); + if (err) + return err; + return fscrypt_policies_equal(&policy1, &policy2); +} +EXPORT_SYMBOL(fscrypt_have_same_policy); + static int set_encryption_policy(struct inode *inode, const union fscrypt_policy *policy) { diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 70d8a710ad39..f3d1f5438a6c 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -322,6 +322,7 @@ static inline struct page *fscrypt_pagecache_page(struct page *bounce_page) void fscrypt_free_bounce_page(struct page *bounce_page); /* policy.c */ +int fscrypt_have_same_policy(struct inode *inode1, struct inode *inode2); int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg); int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg); int fscrypt_ioctl_get_policy_ex(struct file *filp, void __user *arg); From patchwork Wed Jul 13 10:29:45 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: 12916521 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 0E8CAC43334 for ; Wed, 13 Jul 2022 10:31:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232249AbiGMKbI (ORCPT ); Wed, 13 Jul 2022 06:31:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55172 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235924AbiGMKbG (ORCPT ); Wed, 13 Jul 2022 06:31:06 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CAB2CFD20A for ; Wed, 13 Jul 2022 03:31:05 -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 0BE8A806E0; Wed, 13 Jul 2022 06:31:04 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708265; bh=A8wOZurZEFQYcXGlEqjcrduwleL7s3DN80L89WW+Pyk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sOvcpUkB9XA8dweNvraJ+O0xIWkMYNfDU4pY0YgiIrxI8wzU5F+m17PAUdH1zgJYd tS8bbrEYcxmBwt8QIEnRqt71Y/SoxBDpy/KpVPh9OZYvy2onqURNgsmCiifgoERmCp 7u5aQyz3C1HcJ1BcKetq18ouesF2OQFjAJCfKhUDPmdsGvQ16Q7aA+J8B+oPxvSqAg ldpFxZ2+/R1I4ADwqvBT/9PdayXqX6r5hspA+iH/oXD8cfqvuo7XWeMn8V5Mecras/ T1RqZu6+xtnM+qyZkRsPD08+O9mkMCtxzRpP0unR6IGmW6RDW2pm15atxfxTxRtDXC kpquvDlH5OsEA== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [RFC ONLY 12/23] btrfs: disable various operations on encrypted inodes Date: Wed, 13 Jul 2022 06:29:45 -0400 Message-Id: <74b127c255c1c166acabd3db01acb1e85aa691a9.1657707687.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: 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 a93b205c663b..31cd95bed301 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1923,7 +1923,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; } @@ -3772,7 +3772,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 9c9f640be636..7c856ce965f9 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 e5c2616a486e..466dfccba094 100644 --- a/fs/btrfs/reflink.c +++ b/fs/btrfs/reflink.c @@ -806,6 +806,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 Wed Jul 13 10:29: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: 12916522 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 10C7DC43334 for ; Wed, 13 Jul 2022 10:31:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235716AbiGMKbO (ORCPT ); Wed, 13 Jul 2022 06:31:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55300 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234888AbiGMKbK (ORCPT ); Wed, 13 Jul 2022 06:31:10 -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 ED66AFB8DD for ; Wed, 13 Jul 2022 03:31:08 -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 21A27806E0; Wed, 13 Jul 2022 06:31:07 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708268; bh=76m7XqeFwSYU/5SFiP7vimnMTtvT/a0hy+gLNau89is=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=n273QGxN3dN9eQvRkBT+QNTVUAybUOGXk/g2TjTw4dFlFBpE4/n6eKGSmx6G49xPv NttIBWf8ZPie2MnHa0ZiCmh10Zrb5u7zRhlvgivh9zp5UGWj0wyMRNcyIRIEIS9Ssc 0SwGW+DZWyeguGxOhgQXqQMbju27xCbSAs80+BVJRoZOvd1xwuoAq1aZkr23gS3ZtL jSl7xfNySmaGSrmJvJKzcMTY8l9fuiuUL0dyDUfysBK73NFsRUj9OjfmrxSV4sCEa7 JHtNCW8a0zS1AeulYoHJ6EaYVzCZtGrioLQTh7WzNFNgdHJGVy3RNcvW7sr9o4KVdk KCnqBfVg+NasQ== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [RFC ONLY 13/23] btrfs: add fscrypt operation table to superblock Date: Wed, 13 Jul 2022 06:29:46 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org To use fscrypt_prepare_new_inode(), the superblock must have fscrypt operations registered. 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 Wed Jul 13 10:29: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: 12916523 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 30818C433EF for ; Wed, 13 Jul 2022 10:31:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235158AbiGMKbQ (ORCPT ); Wed, 13 Jul 2022 06:31:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55366 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229613AbiGMKbM (ORCPT ); Wed, 13 Jul 2022 06:31:12 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ADD09FD201 for ; Wed, 13 Jul 2022 03:31:11 -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 EE6EE806E0; Wed, 13 Jul 2022 06:31:10 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708271; bh=35ztYJJzBbGPBLHnP8aYKKG4/+hwS33FJ9xDfweEmJQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XLboo0MuR2E4geCKThy2uoCUJy1pNoljEtMk5CeIEZbPD4gbHR4ipYwtiZl5gqnmR xHeeCzHTis9nqHBxFRMt3OC7nDA96XLW70GblmDo5aOOkuvBl11nyqM55GsXpxWM/B /b8IEvvjw/6aCgne7RGriJ+PbImPcFqZBR9oL+uoKyTu/bKu+tD4dFamslJUJL6xB0 +Ag7df7B6kXz2XCYd9fhtAYklBay+s1CMX0KsS6GHyYesP1gHxu/4nMsE7JsfpGLEm XnfBG0EyyRHLrvwkerNu/2XKDBY1SvkWjlGOe5905sT+Z7FihA60c6FX9Fmp0IBqCx x9dx66jLvYBmQ== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [RFC ONLY 14/23] btrfs: start using fscrypt hooks. Date: Wed, 13 Jul 2022 06:29:47 -0400 Message-Id: <4d9e93b95f9eaef224a47ca7d81b1f298d46dea7.1657707687.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 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: Sweet Tea Dorminy --- fs/btrfs/ctree.h | 1 + fs/btrfs/file.c | 3 ++ fs/btrfs/inode.c | 88 ++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 78 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 7195090dc839..b01030cbe79b 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3347,6 +3347,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 31cd95bed301..9f426905be20 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -3738,6 +3738,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 7c856ce965f9..b043342f2820 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4471,7 +4471,7 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, objectid = inode->location.objectid; } else { WARN_ON(1); - fscrypt_free_fname(&fname); + fscrypt_free_filename(&fname); return -EINVAL; } @@ -5458,6 +5458,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; @@ -5559,6 +5560,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); } @@ -6293,10 +6295,14 @@ int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args, ret = posix_acl_create(dir, &inode->i_mode, &args->default_acl, &args->acl); if (ret) { - fscrypt_free_fname(&args->fname); + fscrypt_free_filename(&args->fname); 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 */ @@ -6775,9 +6781,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) @@ -9004,6 +9014,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)); } @@ -9063,8 +9074,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) @@ -9678,6 +9688,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); @@ -9897,15 +9912,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) @@ -9914,8 +9936,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); @@ -9945,7 +9967,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) { @@ -9964,10 +9986,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); @@ -9984,6 +10018,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, @@ -11573,7 +11630,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, @@ -11583,4 +11640,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 Wed Jul 13 10:29: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: 12916524 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 CC92DCCA479 for ; Wed, 13 Jul 2022 10:31:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235894AbiGMKbS (ORCPT ); Wed, 13 Jul 2022 06:31:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55422 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236044AbiGMKbO (ORCPT ); Wed, 13 Jul 2022 06:31:14 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0FA2CFD201 for ; Wed, 13 Jul 2022 03:31:14 -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 7378E802A1; Wed, 13 Jul 2022 06:31:13 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708273; bh=Jhp3EeqXeQ/hn0KkcWLpurzUsu4MN1pA7hs7J5X3df0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=g8pJtpuZmjy+nCcF7meQOFWpFKOGcHiXakjxR1nEojjKll8kuyYfdrN/7xraOfDRn eDFwbmtMFSV8SaX3zkyDyFe7u2XMv+Ote/avC0N1RYcuq1i5PHBpX+PNe1b1qNymQT tqEg3EMcJ7M7Lf7Y5G1MXZNMqwiPvqJ3e1eEgpcwxtO1XZ/tJWBfqp9dQIeUKnWWhu 8HzLxvzuMuSUpYbW02nJS+wvd635xBh5sj6gvCy6xJI4MaM++2HQDHWnvo33MllkgV FGJzTHdLxGe3XKVpSILCY61ADrRqyAt+PrbH+baym3JP82D8Rq2dlX2Xmatuz3L/E2 sFUkh2fHwJZHg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [RFC ONLY 15/23] btrfs: add a subvolume flag for whole-volume encryption Date: Wed, 13 Jul 2022 06:29:48 -0400 Message-Id: <9b7039604b577a36ff2e49e0470b21c3d2aa2ed0.1657707687.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 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: Sweet Tea Dorminy --- fs/btrfs/ctree.h | 3 + fs/btrfs/fscrypt.c | 158 ++++++++++++++++++++++++++++++++ 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, 219 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index b01030cbe79b..a1fea2833bff 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" @@ -1589,6 +1590,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) @@ -1605,6 +1607,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..cffe63e18ef4 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,158 @@ 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; + 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; + } + + struct extent_buffer *leaf = path->nodes[0]; + unsigned long 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, 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 b043342f2820..a74b0d326baa 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6286,6 +6286,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); @@ -6319,6 +6347,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)++; @@ -6572,6 +6602,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 352f890c53ec..9d3d447f58ad 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 Wed Jul 13 10:29: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: 12916525 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 0EF3DC43334 for ; Wed, 13 Jul 2022 10:31:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235401AbiGMKbS (ORCPT ); Wed, 13 Jul 2022 06:31:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55442 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229613AbiGMKbR (ORCPT ); Wed, 13 Jul 2022 06:31:17 -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 D557BFD204 for ; Wed, 13 Jul 2022 03:31:16 -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 7749981120; Wed, 13 Jul 2022 06:31:15 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708276; bh=YF0eZzef2DDGBsEfzktAfjuY6iCob9oE6T5l5oX/ujU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=K3IYaUWbZfng5JIimYuhmOO0HW3klIVX9yYQ35GS7mkIJWDukMDJfQQbd4ap9tDji 0MF9x89nNcmNZ6vJkNz4q0tVMlVbQY7/ngWcGK1pnPvtL20YgYzBwOihoqZbSC3Tt1 HZAFT9dTk/aEn6asCUeeG15l71o9adFMLVFFpzzFX+uU203sgrdkKj68s1llJQFu7Q 50weoabYxYAH2OAYgo4TdxLxFZPjtILB/Y5BRPQJ5nEjWoyNGTu6lJ0bD0XLOR7Wbk mJBW5gUgMbHuh5tEvwR9XojiQFhMABhksBdOJP/YiKN2v4RUpoYfDAM/XjDLlQE1jP KaftBqsaHnDDA== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [RFC ONLY 16/23] btrfs: translate btrfs encryption flags and encrypted inode flag. Date: Wed, 13 Jul 2022 06:29:49 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org 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: 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 9d3d447f58ad..c980a3025cf9 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 Wed Jul 13 10:29: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: 12916526 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 BE074C43334 for ; Wed, 13 Jul 2022 10:31:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235198AbiGMKbW (ORCPT ); Wed, 13 Jul 2022 06:31:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55532 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235029AbiGMKbU (ORCPT ); Wed, 13 Jul 2022 06:31: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 07F46FD204 for ; Wed, 13 Jul 2022 03:31: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 57891802A1; Wed, 13 Jul 2022 06:31:18 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708278; bh=LYkopNIK/2hwMIJB11zpRVXHzS56/xAM/+TjbaJIjrM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MjWFI38ndzoHaQ2+blJMeKzIHbpOF3o0h+sf4B9G6xJSSaP4kDqABedpcQlKrdgt4 4/LOauXHTN8pb+UtLHVS9Ox6P6GHnAGodGEZb+CtHTO5MkrtrYVJ/7cZWgWyllGp8M DjJAhvbAcypDPe3A2qIOW+QvTxWF69j1TFMoUrEyBXc3eCeNSTqmtsWe4mtiEX1Nd1 Qe3nJLOP7D7N/VRvuh97UJjVbBqfm4QvLiJCTUTOZJFLxOr1RHZ6IDZXPJP+WZg0Ja o30M/CmDlD1Wfr9foFwcyxO0q3AqNf/6VoVNIgS7ivNMYXZZh1cdy8f+/Kb55A3hVh mBj9eBRkpGrUw== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [RFC ONLY 17/23] fscrypt: Add new encryption policy for btrfs. Date: Wed, 13 Jul 2022 06:29:50 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Certain filesystems want to generate an IV for a particular block in some way other than by inode number plus block number. In particular, btrfs can change the block number for a particular piece of data, and can have multiple inodes using the same block, so to use a IV generated from the inode or the block number would interfere with normal filesystem operation. In order to prevent needing to plumb arbitrary methods of IV generation into fscrypt, this change adds a new policy, IV_FROM_FS. If this policy is used, the filesystem is required to provide an operation function pointer, get_fs_derived_iv, which takes the inode and the offset of the block within the inode and fills in the IV buffer itself. Such a filesystem is expected to appropriately generate and store a persistent random IV for each block of data. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/crypto.c | 28 ++++++++++++++++++++++++++-- fs/crypto/fname.c | 17 ++++++++++++++++- fs/crypto/fscrypt_private.h | 4 ++-- fs/crypto/inline_crypt.c | 20 ++++++++++++++------ fs/crypto/keysetup.c | 6 ++++++ fs/crypto/policy.c | 8 +++++++- include/linux/fscrypt.h | 23 ++++++++++++++++++++++- include/uapi/linux/fscrypt.h | 1 + 8 files changed, 94 insertions(+), 13 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index e78be66bbf01..e1dee6f27f69 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -69,6 +69,20 @@ void fscrypt_free_bounce_page(struct page *bounce_page) } EXPORT_SYMBOL(fscrypt_free_bounce_page); +int fscrypt_mode_ivsize(struct inode *inode) +{ + struct fscrypt_info *ci; + + if (!fscrypt_needs_contents_encryption(inode)) + return 0; + + ci = inode->i_crypt_info; + if (WARN_ON_ONCE(!ci)) + return 0; + return ci->ci_mode->ivsize; +} +EXPORT_SYMBOL(fscrypt_mode_ivsize); + /* * Generate the IV for the given logical block number within the given file. * For filenames encryption, lblk_num == 0. @@ -81,13 +95,23 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, const struct fscrypt_info *ci) { u8 flags = fscrypt_policy_flags(&ci->ci_policy); + struct inode *inode = ci->ci_inode; memset(iv, 0, ci->ci_mode->ivsize); + if (flags & FSCRYPT_POLICY_FLAG_IV_FROM_FS) { + struct fscrypt_operations *s_cop = inode->i_sb->s_cop; + /* Provide the nonce in case the filesystem wants to use it */ + memcpy(iv->nonce, ci->ci_nonce, FSCRYPT_FILE_NONCE_SIZE); + s_cop->get_fs_defined_iv(iv->raw, ci->ci_mode->ivsize, inode, + lblk_num); + return; + } + if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { WARN_ON_ONCE(lblk_num > U32_MAX); - WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX); - lblk_num |= (u64)ci->ci_inode->i_ino << 32; + WARN_ON_ONCE(inode->i_ino > U32_MAX); + lblk_num |= (u64)inode->i_ino << 32; } else if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { WARN_ON_ONCE(lblk_num > U32_MAX); lblk_num = (u32)(ci->ci_hashed_ino + lblk_num); diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 5d5c26d827fd..c5dd19c1d19e 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -389,6 +389,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, fname->usr_fname = iname; if (!IS_ENCRYPTED(dir) || fscrypt_is_dot_dotdot(iname)) { +unencrypted: fname->disk_name.name = (unsigned char *)iname->name; fname->disk_name.len = iname->len; return 0; @@ -424,8 +425,16 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, * user-supplied name */ - if (iname->len > FSCRYPT_NOKEY_NAME_MAX_ENCODED) + if (iname->len > FSCRYPT_NOKEY_NAME_MAX_ENCODED) { + /* + * This isn't a valid nokey name, but it could be an unencrypted + * name if the filesystem allows partially encrypted + * directories. + */ + if (dir->i_sb->s_cop->flags & FS_CFLG_ALLOW_PARTIAL) + goto unencrypted; return -ENOENT; + } fname->crypto_buf.name = kmalloc(FSCRYPT_NOKEY_NAME_MAX, GFP_KERNEL); if (fname->crypto_buf.name == NULL) @@ -436,6 +445,12 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, if (ret < (int)offsetof(struct fscrypt_nokey_name, bytes[1]) || (ret > offsetof(struct fscrypt_nokey_name, sha256) && ret != FSCRYPT_NOKEY_NAME_MAX)) { + /* Again, this could be an unencrypted name. */ + if (dir->i_sb->s_cop->flags & FS_CFLG_ALLOW_PARTIAL) { + kfree(fname->crypto_buf.name); + fname->crypto_buf.name = NULL; + goto unencrypted; + } ret = -ENOENT; goto errout; } diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 6b4c8094cc7b..084c6ba1e766 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -279,8 +279,6 @@ fscrypt_msg(const struct inode *inode, const char *level, const char *fmt, ...); #define fscrypt_err(inode, fmt, ...) \ fscrypt_msg((inode), KERN_ERR, fmt, ##__VA_ARGS__) -#define FSCRYPT_MAX_IV_SIZE 32 - union fscrypt_iv { struct { /* logical block number within the file */ @@ -326,6 +324,7 @@ int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key, #define HKDF_CONTEXT_DIRHASH_KEY 5 /* info=file_nonce */ #define HKDF_CONTEXT_IV_INO_LBLK_32_KEY 6 /* info=mode_num||fs_uuid */ #define HKDF_CONTEXT_INODE_HASH_KEY 7 /* info= */ +#define HKDF_CONTEXT_IV_FROM_FS_KEY 8 /* info=mode_num */ int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context, const u8 *info, unsigned int infolen, @@ -498,6 +497,7 @@ struct fscrypt_master_key { struct fscrypt_prepared_key mk_direct_keys[FSCRYPT_MODE_MAX + 1]; struct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[FSCRYPT_MODE_MAX + 1]; struct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[FSCRYPT_MODE_MAX + 1]; + struct fscrypt_prepared_key mk_iv_from_fs_keys[FSCRYPT_MODE_MAX + 1]; /* Hash key for inode numbers. Initialized only when needed. */ siphash_key_t mk_ino_hash_key; diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 90f3e68f166e..8a8330caadfa 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -476,14 +476,22 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks) return nr_blocks; ci = inode->i_crypt_info; - if (!(fscrypt_policy_flags(&ci->ci_policy) & - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) - return nr_blocks; - /* With IV_INO_LBLK_32, the DUN can wrap around from U32_MAX to 0. */ + if (fscrypt_policy_flags(&ci->ci_policy) & + FSCRYPT_POLICY_FLAG_IV_FROM_FS) { + return 1; + } - dun = ci->ci_hashed_ino + lblk; + if ((fscrypt_policy_flags(&ci->ci_policy) & + FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) { + /* + * With IV_INO_LBLK_32, the DUN can wrap around from U32_MAX to + * 0. + */ + dun = ci->ci_hashed_ino + lblk; + return min_t(u64, nr_blocks, (u64)U32_MAX + 1 - dun); + } - return min_t(u64, nr_blocks, (u64)U32_MAX + 1 - dun); + return nr_blocks; } EXPORT_SYMBOL_GPL(fscrypt_limit_io_blocks); diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index c35711896bd4..fa4c1951f9bf 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -323,6 +323,12 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, */ err = setup_per_mode_enc_key(ci, mk, mk->mk_direct_keys, HKDF_CONTEXT_DIRECT_KEY, false); + } else if ((ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAG_IV_FROM_FS) && + S_ISREG(ci->ci_inode->i_mode)) { + err = setup_per_mode_enc_key(ci, mk, + mk->mk_iv_from_fs_keys, + HKDF_CONTEXT_IV_FROM_FS_KEY, + false); } else if (ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { /* diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 5763462af9e8..0c2066098211 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -199,7 +199,8 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy, if (policy->flags & ~(FSCRYPT_POLICY_FLAGS_PAD_MASK | FSCRYPT_POLICY_FLAG_DIRECT_KEY | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 | - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) { + FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 | + FSCRYPT_POLICY_FLAG_IV_FROM_FS)) { fscrypt_warn(inode, "Unsupported encryption flags (0x%02x)", policy->flags); return false; @@ -208,6 +209,7 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy, count += !!(policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY); count += !!(policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64); count += !!(policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32); + count += !!(policy->flags & FSCRYPT_POLICY_FLAG_IV_FROM_FS); if (count > 1) { fscrypt_warn(inode, "Mutually exclusive encryption flags (0x%02x)", policy->flags); @@ -235,6 +237,10 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy, 32, 32)) return false; + if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_FROM_FS) && + !inode->i_sb->s_cop->get_fs_defined_iv) + return false; + if (memchr_inv(policy->__reserved, 0, sizeof(policy->__reserved))) { fscrypt_warn(inode, "Reserved bits set in encryption policy"); return false; diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index f3d1f5438a6c..3eab327960ca 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -100,6 +100,12 @@ struct fscrypt_nokey_name { /* Maximum value for the third parameter of fscrypt_operations.set_context(). */ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 40 +/* + * Maximum size needed for an IV. Defines the size of the buffer passed to a + * get_fs_defined_iv() function. + */ +#define FSCRYPT_MAX_IV_SIZE 32 + #ifdef CONFIG_FS_ENCRYPTION /* @@ -108,6 +114,8 @@ struct fscrypt_nokey_name { * pages for writes and therefore won't need the fscrypt bounce page pool. */ #define FS_CFLG_OWN_PAGES (1U << 1) +/* The filesystem allows partially encrypted directories/files. */ +#define FS_CFLG_ALLOW_PARTIAL (1U << 2) /* Crypto operations for filesystems */ struct fscrypt_operations { @@ -202,7 +210,13 @@ struct fscrypt_operations { */ void (*get_ino_and_lblk_bits)(struct super_block *sb, int *ino_bits_ret, int *lblk_bits_ret); - + /* + * Generate an IV for a given inode and lblk number, for filesystems + * where additional filesystem-internal information is necessary to + * keep the IV stable. + */ + void (*get_fs_defined_iv)(u8 *iv, int ivsize, struct inode *inode, + u64 lblk_num); /* * Return the number of block devices to which the filesystem may write * encrypted file contents. @@ -321,6 +335,8 @@ static inline struct page *fscrypt_pagecache_page(struct page *bounce_page) void fscrypt_free_bounce_page(struct page *bounce_page); +int fscrypt_mode_ivsize(struct inode *inode); + /* policy.c */ int fscrypt_have_same_policy(struct inode *inode1, struct inode *inode2); int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg); @@ -496,6 +512,11 @@ static inline void fscrypt_free_bounce_page(struct page *bounce_page) { } +static inline int fscrypt_mode_ivsize(struct inode *inode) +{ + return 0; +} + /* policy.c */ static inline int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) diff --git a/include/uapi/linux/fscrypt.h b/include/uapi/linux/fscrypt.h index 9f4428be3e36..3fbde7668b07 100644 --- a/include/uapi/linux/fscrypt.h +++ b/include/uapi/linux/fscrypt.h @@ -20,6 +20,7 @@ #define FSCRYPT_POLICY_FLAG_DIRECT_KEY 0x04 #define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 0x08 #define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 0x10 +#define FSCRYPT_POLICY_FLAG_IV_FROM_FS 0x20 /* Encryption algorithms */ #define FSCRYPT_MODE_AES_256_XTS 1 From patchwork Wed Jul 13 10:29: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: 12916528 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 EC7D2C43334 for ; Wed, 13 Jul 2022 10:31:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236049AbiGMKb2 (ORCPT ); Wed, 13 Jul 2022 06:31:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55636 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236032AbiGMKbX (ORCPT ); Wed, 13 Jul 2022 06:31:23 -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 A65D4FC9B9 for ; Wed, 13 Jul 2022 03:31:21 -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 E1FBC81123; Wed, 13 Jul 2022 06:31:20 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708281; bh=Rua5M38ap98O348HnTFS2NkJBnKjiZEx6pmuTPO3Ia0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TGV6w/1eWHVvHLaxSx9QxUQlmXHpPJuNQhfWFvUao8l5qRkBkxbaa1jF7HeGId+MC HljBQa2o/VYJ58ViE2X37sj0SkZ8jgG7n+bmJ188x1C22omVBgU/AyYfBZwPUZm6Nx E4PBnp6xB4dwC6F6xY/lR37WnkNHr4nvUV7GjuQi/Z67R6cWWpoMtrgOPKVSXn3/uJ MqYyn4gks54DJTDICnHA/XT5LYdutoc4KY/3Xx+Kx8RXLNSSaCpmIuVP8NXttrmyoY o7+yRbY+A0AUoRyuC+zRDSViwrrUdB/vauNoMYnoXNhQEpwTM0b8KjS6UKETZQR+3G 1VZzOiG+ATcLg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [RFC ONLY 18/23] btrfs: add iv generation function Date: Wed, 13 Jul 2022 06:29:51 -0400 Message-Id: <83ff2c3196e3fed1d37fe6a8477aa7b6300ab2c4.1657707687.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 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. However, for filenames (and later for simple, non-block data), generating the IV from the inode number and logical block number suffices, since these encrypted datum are not shared between inodes. Begin implementing the IV_FROM_FS policy with a simple IV generation function that imitates the IV_INO_LBLK_64 policy. Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/ctree.h | 28 ++++++++++++++ fs/btrfs/extent_map.h | 8 ++++ fs/btrfs/file-item.c | 11 ++++++ fs/btrfs/fscrypt.c | 12 ++++++ fs/btrfs/fscrypt.h | 23 +++++++++++ fs/btrfs/inode.c | 68 +++++++++++++++++++++++++-------- fs/btrfs/ordered-data.c | 12 +++++- fs/btrfs/ordered-data.h | 3 +- fs/btrfs/tree-checker.c | 36 +++++++++++++---- fs/btrfs/tree-log.c | 9 +++++ include/uapi/linux/btrfs_tree.h | 9 +++++ 11 files changed, 192 insertions(+), 27 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index a1fea2833bff..bed27b91d69e 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; @@ -2594,6 +2595,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) @@ -2626,6 +2636,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, + 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/fscrypt.c b/fs/btrfs/fscrypt.c index cffe63e18ef4..82eb9654f60f 100644 --- a/fs/btrfs/fscrypt.c +++ b/fs/btrfs/fscrypt.c @@ -185,9 +185,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, }; 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 a74b0d326baa..1ee8eca5a88f 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; } @@ -3047,6 +3049,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) { @@ -3062,6 +3065,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) @@ -3080,7 +3084,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; @@ -3091,7 +3095,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; } @@ -3100,6 +3104,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); @@ -3176,7 +3185,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 @@ -3190,6 +3204,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); } @@ -7100,8 +7115,24 @@ 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; @@ -7330,7 +7361,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); @@ -9956,6 +9987,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 @@ -10021,7 +10053,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 */ @@ -10102,16 +10136,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; @@ -11076,7 +11112,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/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 4959e8ecc99a..51aed5667964 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -4749,6 +4749,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)) @@ -4770,6 +4773,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) @@ -4809,6 +4813,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 Wed Jul 13 10:29: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: 12916527 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 9AD74C433EF for ; Wed, 13 Jul 2022 10:31:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236054AbiGMKb3 (ORCPT ); Wed, 13 Jul 2022 06:31:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55652 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235029AbiGMKb0 (ORCPT ); Wed, 13 Jul 2022 06:31:26 -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 112A2FD20A for ; Wed, 13 Jul 2022 03:31: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 14AC9806E0; Wed, 13 Jul 2022 06:31:23 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708284; bh=VtZ50HmDcmXm/QENpNiEoK7dz/Zvw7+K+TVEVAw66c0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LgZdISPAUoCu4wtJbqlYPwSpspPk9papq9BuPYwh1k4iB8TMmtG2wGUifBXow6yA7 DihteQ5N93dzjzABRLIOCC5ZG9f/YN2bPpmF3A0VcDHGEHuyZEujH9kKRorUP5YmfW u8NY4x4bnDhq3OsxmvQLYZgvF7joiKrzVQVuKblGieBzXrPB9frI7p2nTpdPLQxT9D rNLF/qL5x1RZE+T/yY82x7/Y+gkj+LPd0FBIQ3PZKqEj4pFeevVL/JFoXteoEpq30v U8x+cLzmJJnF9eeBm02QtWq8SKLAgDfjzJEX65iUG4ZG2B0Y8dmY460xQ5pOjxmx4M OYGV6CVLK/Agw== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [RFC ONLY 19/23] btrfs: Add new FEATURE_INCOMPAT_FSCRYPT feature flag. Date: Wed, 13 Jul 2022 06:29:52 -0400 Message-Id: <8584ff55685ae522c65b19e8904db51f16dd964b.1657707687.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 As fscrypt files will be incompatible with older filesystem versions, new filesystems should be created with an incompat flag for fscrypt. 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 bed27b91d69e..522bb3452768 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 Wed Jul 13 10:29: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: 12916529 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 3FA16CCA479 for ; Wed, 13 Jul 2022 10:31:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235915AbiGMKba (ORCPT ); Wed, 13 Jul 2022 06:31:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55766 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236051AbiGMKb2 (ORCPT ); Wed, 13 Jul 2022 06:31:28 -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 A3FC4FD20A for ; Wed, 13 Jul 2022 03:31: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 E59D0802A1; Wed, 13 Jul 2022 06:31:26 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708287; bh=tBxdg+R0rmQtLfQGtJYt9PMrVuz4BaRzfoygAJm/H8o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=V4eRCMNKttN58u1UDOGWB2LOs399Se4jX/B+MqmF7Bj3PP1QmNrvPHDS72IdPYtt5 lieUR8dDBvr7iLtvFe4WuooznJgtmbtJ66kPLdpiH7Q55BtPV7VABfXvB4LtgGLKoU Fhb6vlK/cMqDO/+4SV1B1eiuxc8t7NnvPsWOS6l5ku5yHq8/8sk5jU8nmLsgAndktH zj4kecqY8UcuMTL9en5Yk3rzQSHatdKGP7VEFygJktcZKtyVrVvyJJ4KuIyA7BInhe KMhU6S2bXnaEdI07vY/sPFusv7HrecP7BLiCO8Xc9qcpYN5muQYqyQQQPLUgTw775/ 52Fjx4CS7H+Vg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [RFC ONLY 20/23] btrfs: reuse encrypted filename hash when possible. Date: Wed, 13 Jul 2022 06:29:53 -0400 Message-Id: <059bd4813915c875104c188a7c7b0bccd4b7da4b.1657707687.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 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: 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 522bb3452768..2c6baf6cd718 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2775,7 +2775,10 @@ static inline void btrfs_crc32c_final(u32 crc, u8 *result) static inline u64 btrfs_name_hash(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); } /* @@ -2784,8 +2787,20 @@ static inline u64 btrfs_name_hash(struct fscrypt_name *name) static inline u64 btrfs_extref_hash(u64 parent_objectid, 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 Wed Jul 13 10:29: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: 12916530 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 21780C43334 for ; Wed, 13 Jul 2022 10:31:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236044AbiGMKbc (ORCPT ); Wed, 13 Jul 2022 06:31:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55804 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236032AbiGMKba (ORCPT ); Wed, 13 Jul 2022 06:31: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 D24E0FC9AB for ; Wed, 13 Jul 2022 03:31:29 -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 15C33806E0; Wed, 13 Jul 2022 06:31:28 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708289; bh=fXHnE4YWvPFIskIwYBS2PzIAnd0/r8H8NjXwo0rZc6k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wwNnSb3xvigC8b9VughZiKpEHGNqLfbpaON01l5Oc9twD8O7PsdsYBZb822ePg4J8 T5gQrFg1D6IUVqjMAR/hvr/iRr4PFKF3v2Gfk85gFJ4ZOGfGzhM9kWN0+P7pL0YYYW 2MoZU7ldKbGHBKcSZbwBNEhU+zu8fOZoozrd31X9OOXuHaFZD/puvjXXrw/Yo5agrK qFEC7tumuKuaABTiOjTTqrBPbFR2lAgIgYi85FxATe5IF7BLDAnJNzHXIxnqUihgT3 mZflj4iRK/ESMegmgkeC+qNzvbNxBw0HlG+K9YURsD7I6c2JnjKCZdzwBHh7GBk4h/ w5vO5snmCJAcg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [RFC ONLY 21/23] btrfs: implement fscrypt ioctls Date: Wed, 13 Jul 2022 06:29:54 -0400 Message-Id: <6cee3ee979b53a64da1f435c822966b91502dfb0.1657707687.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: 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 c980a3025cf9..f5c8f21e6f47 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: From patchwork Wed Jul 13 10:29: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: 12916531 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 F1F3FC43334 for ; Wed, 13 Jul 2022 10:31:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236051AbiGMKbf (ORCPT ); Wed, 13 Jul 2022 06:31:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55850 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235138AbiGMKbd (ORCPT ); Wed, 13 Jul 2022 06:31:33 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1F8E2FD220 for ; Wed, 13 Jul 2022 03:31:31 -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 543E7802A1; Wed, 13 Jul 2022 06:31:31 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708291; bh=H9gUVx9+NnmwDAa/bAVzgK4742gY93CbU6l2ZAEEVfs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ofciH1KpbxZoc7uJkJKsgyrqUTnFsDGVK2ywoFepL+GKBSaP5ugiAQlT9OZKs14Z0 duT3F5tSaamRIhRFPogD6IH8MPZ7ysDqsWse45YnI2RSrk0BWsM3HVJY75JF6SQlQ/ ywQh1CBKE+b5yEEKqv3bbwWARckHETW+xfNXhMFu3YQ7dJGnJeUiTVGHB81SlG9PhP +6fP1X26BaYCg15ahg941gbjybbyuQrOnatx38+yKZR9B8/XI1xECHmmG1YSEzjeYg IXRpeZd68ru9K1yvVgSmdUerzuxOXFmgJ1JvGWppAif556B+4HzsJgigFC5IdI+pfy gYHNteTbu/17A== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [RFC ONLY 22/23] btrfs: adapt directory read and lookup to potentially encrypted filenames Date: Wed, 13 Jul 2022 06:29:55 -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 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: Sweet Tea Dorminy --- fs/btrfs/delayed-inode.c | 32 +++++++++++++--- fs/btrfs/delayed-inode.h | 4 +- fs/btrfs/dir-item.c | 18 +++++++++ fs/btrfs/inode.c | 81 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 121 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index d8ac12fdd991..9d8c88081b41 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1486,9 +1486,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(); @@ -1721,7 +1721,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; @@ -1731,6 +1733,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; @@ -1758,8 +1761,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 e1d769e37ac1..7ff158b546cb 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_encrypted(fname)) + type |= BTRFS_FT_FSCRYPT_NAME; + key.objectid = btrfs_ino(dir); key.type = BTRFS_DIR_ITEM_KEY; key.offset = btrfs_name_hash(fname); @@ -214,7 +217,9 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, { struct btrfs_key key; struct btrfs_dir_item *di; + struct fscrypt_name unencrypted_fname; +again: key.objectid = dir; key.type = BTRFS_DIR_ITEM_KEY; key.offset = btrfs_name_hash(fname); @@ -223,6 +228,19 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, if (IS_ERR(di) && PTR_ERR(di) == -ENOENT) return NULL; + if (!di && fname_encrypted(fname)) { + unencrypted_fname = (struct fscrypt_name){ + .usr_fname = fname->usr_fname, + .disk_name = { + .name = (unsigned char *)fname->usr_fname->name, + .len = fname->usr_fname->len, + }, + }; + fname = &unencrypted_fname; + btrfs_release_path(path); + goto again; + } + return di; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 1ee8eca5a88f..7898e0873cb4 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5888,12 +5888,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(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); @@ -6035,18 +6048,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; @@ -6063,7 +6090,9 @@ 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]; + int slot; u8 di_flags; + u32 nokey_len; if (found_key.objectid != key.objectid) break; @@ -6075,8 +6104,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) @@ -6090,8 +6124,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)), @@ -6113,7 +6175,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; @@ -6144,6 +6207,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 Wed Jul 13 10:29: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: 12916532 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 9880CC433EF for ; Wed, 13 Jul 2022 10:31:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235138AbiGMKbg (ORCPT ); Wed, 13 Jul 2022 06:31:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55896 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236056AbiGMKbf (ORCPT ); Wed, 13 Jul 2022 06:31:35 -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 0F522FD231 for ; Wed, 13 Jul 2022 03:31:34 -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 740548112C; Wed, 13 Jul 2022 06:31:33 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1657708293; bh=AQ/C3FoEQ+BKCBP1r64DSKtSDuzhJ+2thZq33EtEhVw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ApjJexIiaOHxgYZH8KO9gORc/5BJVyWEA86SsYaEViPeh+BEdpSURKhSvCYVquBbf FgIbHoZGRjgodxx2aAZDS9pOWXjZAbgfeYrQFL2zvMo7Ez6jWMNM4hfp8pTtUDEAwb 93q4F4EZU3eSEM3AwHuRXymqo0/XmQzSoWjZDmzUpFxXlbqrq2AlWVevOWQzOMbphL yMppG+ZWNFxqLiOaMJpjw4lMU5yoU0PnizlF9IGaFLOk6p5E1mpwausX+c7rCDUgcq /C1RHdYLHdxKlHiv1/llQgK0Q8LbQQFHQ0pzTESoXFci4mO059Ez75Ia0IH7qWQcah f6geNUtbj1Evw== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [RFC ONLY 23/23] btrfs: enable encryption for normal file extent data Date: Wed, 13 Jul 2022 06:29:56 -0400 Message-Id: <46f91ad6f27527dcb54d4cf9896544c6ecb55a40.1657707687.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 Add in the necessary calls to encrypt and decrypt data to achieve encryption of normal data. Signed-off-by: Sweet Tea Dorminy --- fs/btrfs/extent_io.c | 53 +++++++++++++++++++++++++++++++++++++---- fs/btrfs/file-item.c | 9 +++++-- fs/btrfs/fscrypt.c | 27 +++++++++++++++++---- fs/btrfs/tree-checker.c | 11 ++++++--- 4 files changed, 85 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 235f9612676a..b0ceee84d81c 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -190,7 +190,11 @@ static void submit_one_bio(struct btrfs_bio_ctrl *bio_ctrl) return; bio = bio_ctrl->bio; - inode = bio_first_page_all(bio)->mapping->host; + struct page *first_page = bio_first_page_all(bio); + if (fscrypt_is_bounce_page(first_page)) + inode = fscrypt_pagecache_page(first_page)->mapping->host; + else + inode = bio_first_page_all(bio)->mapping->host; mirror_num = bio_ctrl->mirror_num; /* Caller should ensure the bio has at least some range added */ @@ -2869,9 +2873,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)) @@ -2892,7 +2906,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); } @@ -3089,6 +3103,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; @@ -3442,11 +3467,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 82eb9654f60f..1a211734c28e 100644 --- a/fs/btrfs/fscrypt.c +++ b/fs/btrfs/fscrypt.c @@ -188,11 +188,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 */