From patchwork Wed Oct 11 20:49:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 13417955 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 4A138CDB47E for ; Wed, 11 Oct 2023 20:49:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235164AbjJKUtu (ORCPT ); Wed, 11 Oct 2023 16:49:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52284 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233360AbjJKUtu (ORCPT ); Wed, 11 Oct 2023 16:49:50 -0400 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 05A989E for ; Wed, 11 Oct 2023 13:49:47 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id A89F71F45F for ; Wed, 11 Oct 2023 20:49:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1697057386; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8yjNpkbDGv1WSdgrer/raX0gZJGhGZIVJmstQL6B2lg=; b=Tmqyp4DCuZvsWdYh6+JgSmfO7IvYOUbxvkbnmlN7rN0hgyYnlQ+cC+V0KLpahkrLeNBb0h jhho2d/surUYIUevnLJkwWiWdOdV7G5JJOs9KBhWeflJeZ5z6+E2Grfj6fc2hUrlv7joNP G+XV55q9Y7g6xdTmjJUg58nRs+EbYuA= Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id D8FBB134F5 for ; Wed, 11 Oct 2023 20:49:45 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id IGCWJWkKJ2XCJAAAMHmgww (envelope-from ) for ; Wed, 11 Oct 2023 20:49:45 +0000 From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH v3 1/2] btrfs-progs: mkfs/rootdir: copy missing attributes for the rootdir inode Date: Thu, 12 Oct 2023 07:19:25 +1030 Message-ID: X-Mailer: git-send-email 2.42.0 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org [BUG] When using "mkfs.btrfs" with "--rootdir" option, the top level inode (rootdir) will not get the same xattr from the source dir: mkdir -p source_dir/ touch source_dir/file setfattr -n user.rootdir_xattr source_dir/ setfattr -n user.regular_xattr source_dir/file mkfs.btrfs -f --rootdir source_dir $dev mount $dev $mnt getfattr $mnt # Nothing <<< getfattr $mnt/file # file: $mnt/file user.regular_xattr <<< [CAUSE] In function traverse_directory(), we only call add_xattr_item() for all the child inodes, not really for the rootdir inode itself, leading to the missing xattr items. Not only xattr, in fact we also miss the uid/gid/timestamps/mode for the rootdir inode. [FIX] Extract a dedicated function, copy_rootdir_inode(), to handle every needed attributes for the rootdir inode, including: - xattr - uid - gid - mode - timestamps Issue: #688 Signed-off-by: Qu Wenruo --- mkfs/rootdir.c | 88 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 21 deletions(-) diff --git a/mkfs/rootdir.c b/mkfs/rootdir.c index a413a31eb2d6..24e26cdf50e0 100644 --- a/mkfs/rootdir.c +++ b/mkfs/rootdir.c @@ -429,6 +429,69 @@ end: return ret; } +static int copy_rootdir_inode(struct btrfs_trans_handle *trans, + struct btrfs_root *root, const char *dir_name) +{ + u64 root_dir_inode_size; + struct btrfs_inode_item *inode_item; + struct btrfs_path path = { 0 }; + struct btrfs_key key; + struct extent_buffer *leaf; + struct stat st; + int ret; + + ret = stat(dir_name, &st); + if (ret < 0) { + ret = -errno; + error("lstat failed for direcotry %s: $m", dir_name); + return ret; + } + + ret = add_xattr_item(trans, root, btrfs_root_dirid(&root->root_item), + dir_name); + if (ret < 0) { + errno = -ret; + error("failed to add xattr item for the top level inode: %m"); + return ret; + } + + key.objectid = btrfs_root_dirid(&root->root_item); + key.offset = 0; + key.type = BTRFS_INODE_ITEM_KEY; + ret = btrfs_lookup_inode(trans, root, &path, &key, 1); + if (ret > 0) + ret = -ENOENT; + if (ret) { + error("failed to lookup root dir: %d", ret); + goto error; + } + + leaf = path.nodes[0]; + inode_item = btrfs_item_ptr(leaf, path.slots[0], + struct btrfs_inode_item); + + root_dir_inode_size = calculate_dir_inode_size(dir_name); + btrfs_set_inode_size(leaf, inode_item, root_dir_inode_size); + + /* Unlike fill_inode_item, we only need to copy part of the attributes. */ + btrfs_set_inode_uid(leaf, inode_item, st.st_uid); + btrfs_set_inode_gid(leaf, inode_item, st.st_gid); + btrfs_set_inode_mode(leaf, inode_item, st.st_mode); + btrfs_set_timespec_sec(leaf, &inode_item->atime, st.st_atime); + btrfs_set_timespec_nsec(leaf, &inode_item->atime, 0); + btrfs_set_timespec_sec(leaf, &inode_item->ctime, st.st_ctime); + btrfs_set_timespec_nsec(leaf, &inode_item->ctime, 0); + btrfs_set_timespec_sec(leaf, &inode_item->mtime, st.st_mtime); + btrfs_set_timespec_nsec(leaf, &inode_item->mtime, 0); + btrfs_set_timespec_sec(leaf, &inode_item->otime, 0); + btrfs_set_timespec_nsec(leaf, &inode_item->otime, 0); + btrfs_mark_buffer_dirty(leaf); + +error: + btrfs_release_path(&path); + return ret; +} + static int traverse_directory(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *dir_name, struct directory_name_entry *dir_head) @@ -436,7 +499,6 @@ static int traverse_directory(struct btrfs_trans_handle *trans, int ret = 0; struct btrfs_inode_item cur_inode; - struct btrfs_inode_item *inode_item; int count, i, dir_index_cnt; struct dirent **files; struct stat st; @@ -445,10 +507,6 @@ static int traverse_directory(struct btrfs_trans_handle *trans, ino_t parent_inum, cur_inum; ino_t highest_inum = 0; const char *parent_dir_name; - struct btrfs_path path = { 0 }; - struct extent_buffer *leaf; - struct btrfs_key root_dir_key; - u64 root_dir_inode_size = 0; /* Add list for source directory */ dir_entry = malloc(sizeof(struct directory_name_entry)); @@ -466,25 +524,13 @@ static int traverse_directory(struct btrfs_trans_handle *trans, dir_entry->inum = parent_inum; list_add_tail(&dir_entry->list, &dir_head->list); - root_dir_key.objectid = btrfs_root_dirid(&root->root_item); - root_dir_key.offset = 0; - root_dir_key.type = BTRFS_INODE_ITEM_KEY; - ret = btrfs_lookup_inode(trans, root, &path, &root_dir_key, 1); - if (ret) { - error("failed to lookup root dir: %d", ret); + ret = copy_rootdir_inode(trans, root, dir_name); + if (ret < 0) { + errno = -ret; + error("failed to copy rootdir inode: %m"); goto fail_no_dir; } - leaf = path.nodes[0]; - inode_item = btrfs_item_ptr(leaf, path.slots[0], - struct btrfs_inode_item); - - root_dir_inode_size = calculate_dir_inode_size(dir_name); - btrfs_set_inode_size(leaf, inode_item, root_dir_inode_size); - btrfs_mark_buffer_dirty(leaf); - - btrfs_release_path(&path); - do { parent_dir_entry = list_entry(dir_head->list.next, struct directory_name_entry, From patchwork Wed Oct 11 20:49:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 13417957 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 0C150CDB47E for ; Wed, 11 Oct 2023 20:49:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233483AbjJKUtx (ORCPT ); Wed, 11 Oct 2023 16:49:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52326 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233424AbjJKUtw (ORCPT ); Wed, 11 Oct 2023 16:49:52 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CB72290 for ; Wed, 11 Oct 2023 13:49:49 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id F356021862 for ; Wed, 11 Oct 2023 20:49:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1697057388; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2QGQlrVMMzwBeslkfOMHYXLguWDXwrMq0x2+Xz+fydM=; b=dXwxogZB5A/5NRwY+f0Aycq0HSq4L1QrBHzUDlhPr0ReqBFJXCrtuVX+c4EYab+l+faxxc EF4efSdH7yfOwLzGsDxjX7PuyRleQDMKnDvWplWXos1sB2lkZfm/9rclrX3MFKYhBEVCsG 4PIodd2nusqwwS5PhdMACAgeSd6W+/Y= Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 2EE4E134F5 for ; Wed, 11 Oct 2023 20:49:46 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id cB6UN2oKJ2XCJAAAMHmgww (envelope-from ) for ; Wed, 11 Oct 2023 20:49:46 +0000 From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH v3 2/2] btrfs-progs: tests/mkfs: make sure rootdir inode got its attributes copied Date: Thu, 12 Oct 2023 07:19:26 +1030 Message-ID: <5a903beeeba5636be0895de0ce2592c483619334.1697057301.git.wqu@suse.com> X-Mailer: git-send-email 2.42.0 In-Reply-To: References: MIME-Version: 1.0 Authentication-Results: smtp-out1.suse.de; none X-Spamd-Result: default: False [3.90 / 50.00]; ARC_NA(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[]; FROM_HAS_DN(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; R_MISSING_CHARSET(2.50)[]; MIME_GOOD(-0.10)[text/plain]; PREVIOUSLY_DELIVERED(0.00)[linux-btrfs@vger.kernel.org]; BROKEN_CONTENT_TYPE(1.50)[]; RCPT_COUNT_ONE(0.00)[1]; TO_DN_NONE(0.00)[]; DKIM_SIGNED(0.00)[suse.com:s=susede1]; NEURAL_HAM_SHORT(-1.00)[-1.000]; MID_CONTAINS_FROM(1.00)[]; FROM_EQ_ENVFROM(0.00)[]; MIME_TRACE(0.00)[0:+]; RCVD_COUNT_TWO(0.00)[2]; RCVD_TLS_ALL(0.00)[] Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org The new test case would: - Prepare two loopback devices One is for storing the source directory (on a btrfs). This is to ensure we can set xattr for the directory, as filesystems like tmpfs (mostly utilized by mktemp) is not supporting xattr. The other one is the real target fs where we call "mkfs.btrfs --rootdir" on. - Create the source directory with the following contents: * rootdir inode attributs: # mode (750) # uid (1000) # gid (1000) # xattr (user.rootdir) * one regular file, with attributes: # xattr (user.foorbar) - Execute "mkfs.btrfs --rootdir" and mount the new fs - Verify the above attributes The target fs should have the same attributes, especially for the rootdir inode. Signed-off-by: Qu Wenruo --- tests/mkfs-tests/027-rootdir-inode/test.sh | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100755 tests/mkfs-tests/027-rootdir-inode/test.sh diff --git a/tests/mkfs-tests/027-rootdir-inode/test.sh b/tests/mkfs-tests/027-rootdir-inode/test.sh new file mode 100755 index 000000000000..e5de1485cc87 --- /dev/null +++ b/tests/mkfs-tests/027-rootdir-inode/test.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# Test if "mkfs.btrfs --rootdir" would properly copy all the attributes of the +# source directory. + +source "$TEST_TOP/common" || exit + +setup_root_helper +# Here we need two devices, one as a temporaray btrfs, storing the source +# directory. As we want to setup xattr, which is not supported by tmpfs +# (most modern distros go tmpfs for /tmp). +# So we have to put the source directory on a fs that supports xattr. +# +# Then the second fs is the real one we mkfs on. +setup_loopdevs 2 +prepare_loopdevs + +tmp_dev=${loopdevs[1]} +real_dev=${loopdevs[2]} + +check_global_prereq setfattr +check_global_prereq getfattr + +# Here we don't want to use /tmp, as it's pretty common /tmp is tmpfs, which +# doesn't support xattr. +# Instead we go $TEST_TOP/btrfs-progs-mkfs-tests-027.XXXXXX/ instead. +run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$tmp_dev" +run_check $SUDO_HELPER mount -t btrfs "$tmp_dev" "$TEST_MNT" + +run_check $SUDO_HELPER mkdir "$TEST_MNT/source_dir/" +run_check $SUDO_HELPER chmod 750 "$TEST_MNT/source_dir/" +run_check $SUDO_HELPER chown 1000:1000 "$TEST_MNT/source_dir/" +run_check $SUDO_HELPER setfattr -n user.rootdir "$TEST_MNT/source_dir/" + +old_mode=$(run_check_stdout $SUDO_HELPER stat "$TEST_MNT/source_dir/" | grep "Uid:") +run_check $SUDO_HELPER touch "$TEST_MNT/source_dir/foobar" +run_check $SUDO_HELPER setfattr -n user.foobar "$TEST_MNT/source_dir/foobar" + +run_check $SUDO_HELPER "$TOP/mkfs.btrfs" --rootdir "$TEST_MNT/source_dir" -f "$real_dev" +run_check $SUDO_HELPER umount "$TEST_MNT" + +run_check $SUDO_HELPER mount -t btrfs "$real_dev" "$TEST_MNT" + +new_mode=$(run_check_stdout $SUDO_HELPER stat "$TEST_MNT/" | grep "Uid:") +new_rootdir_attr=$(run_check_stdout $SUDO_HELPER getfattr -n user.rootdir --absolute-names "$src_dir") +new_foobar_attr=$(run_check_stdout getfattr -n user.foobar --absolute-names "$src_dir/foobar") + +run_check_umount_test_dev "$TEST_MNT" +cleanup_loopdevs + +if ! echo "$new_rootdir_attr" | grep -q "user.rootdir" ; then + _fail "no rootdir xattr found" +fi + +if ! echo "$new_foobar_attr"| grep -q "user.foobar" ; then + _fail "no regular file xattr found" +fi + +if [ "$new_mode" != "$old_mode" ]; then + _fail "mode/uid/gid mismatch" +fi