From nobody Mon Oct 19 13:24:05 2026 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4j7bq95khcz6wXnL for ; Mon, 19 Oct 2026 13:24:05 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 4j7bq95B0gz3Hfs for ; Mon, 19 Oct 2026 13:24:05 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792416245; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=OTPPFJiHA9bAXRWUnDGPZ5xtlzX54PhE9k38VLlDOGg=; b=DII5VGrzO0CORDjoK7h54vsWhg4eBg7YOwK6ihn22m4lo/WBHirR4L2bbl6dJb3B8QwONV GY2ugsTj/1IXeE5NOJJvVhwkEl4ljtP01W2ik7m9HQ5qNWZafNndHkSLZXkQXCUJmVkcIM CjT6ZRWagXMuhmpCowIVT5U5qDMoq19ZDrRMbAyc62tjcSKpgXTMwTVkZo6QcvrPjC/4FH FbP/IToY52VksutNlyheU2osBM7tdwpJh5Vv27bB+ksqpGoA3vVQdF6da4rC9xCPbGj/tW 6y+k+rjZGAV4T4wQPN/Z8G4Mi6bKlYuFngniAqel28Qt9UWCyYdNsATogWwkMQ== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1792416245; b=lwwZQ0qr6P6tyMtIsT+q7rLdqoQ32J4jNl1kJnrRraNrvqiaBWg0s7NzIErMUxAD8gL6gf 77SmWhunov5DM2xuW30LWrDuQ6Y4+qwBNyb+2usSMVwcSY4sOw6yYlG1QV5/4ZTdudqygk jn8/T7kbX9cZhmrtF57gPGdHqLlMkyiPNQwE7Sw2uFDMuIqBp4A+QWbHQNngXVHxlitYwr h7NPO4MADrzP7+TLSmEIaE3/iZYFvuO9xL/crQQEr00dVDrNL6Zp115LHaI/RCFNYAj7yL G2x+lIIJI9Kw0csovQ9OdTNkinVU6qBMIDooyrQUAZKdtdYqygvXTWS8yS/Jzg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792416245; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=OTPPFJiHA9bAXRWUnDGPZ5xtlzX54PhE9k38VLlDOGg=; b=fXy3emBfccry2/7C6H/CG4oDEKKymDIkwgXaym1NeLWK57vFXHUVSqjGiPBsbwmo2Jmm6A fcjoCWQO5IY5+yKta4cekXPl6KwHQAmuuOR+T/25/GKnPFkq3UeZyrOIaJH5tT7wq6MxDS veL9uGC0KTUB+CMoWdNoJA/1P0x4qYDgotRMJTckUxhB8Q18LVW//3jicHyz2ydY08fvTS a3XdpaCbTXQozS+21JfOsMwVSGuMlR0qhELY5KtVX9vKoIsRsnzOtx2hyN3iqju3Yhws2Z QnYLVSxlvxIJtt99o5t9tj7poR/ygKbTaiR4l7IleGW9QSdjmoDSE+ZStysU/w== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4j7bq94rPzzLWB for ; Mon, 19 Oct 2026 13:24:05 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 38746 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 19 Oct 2026 13:24:05 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Renato Botelho Subject: git: 7d98cf4cc6c8 - stable/15 - makefs/zfs: count "." in the link count and size of dataset roots List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org List-Id: Commits to the stable branches of the FreeBSD src repository List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: garga X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: 7d98cf4cc6c8fa74a1c0fe650147068cd224e9f3 Auto-Submitted: auto-generated Date: Mon, 19 Oct 2026 13:24:05 +0000 Message-Id: <6ad619f5.38746.3192e6a3@gitrepo.freebsd.org> The branch stable/15 has been updated by garga: URL: https://cgit.FreeBSD.org/src/commit/?id=7d98cf4cc6c8fa74a1c0fe650147068cd224e9f3 commit 7d98cf4cc6c8fa74a1c0fe650147068cd224e9f3 Author: Renato Botelho AuthorDate: 2026-10-07 11:32:45 +0000 Commit: Renato Botelho CommitDate: 2026-10-19 13:23:54 +0000 makefs/zfs: count "." in the link count and size of dataset roots The root directory of a dataset is populated from an fsnode that is the "." entry of the staging directory, and its children are the siblings of that node, so the loop that computes the link count and the size of the directory (which expects "." among the children, as the nodes of the other directories have) never counts it. The link count of the root of every dataset is one less than it should be (1 for an empty dataset instead of 2, 19 instead of 20 for a root with 18 subdirectories), and so is its size. fts(3) trusts the link count of the directories of ZFS when called with FTS_NOSTAT and FTS_PHYSICAL: it stops looking for subdirectories once it has seen as many as the link count says, and does not descend into the ones it did not look at. As a result find(1), and rm(1) when it does not need to stat the entries, silently skip directories of a pool made by makefs. On a root filesystem made by makefs, find / does not list /etc at all. Start the loop at the "." node itself for the roots of datasets, so that it is counted the same way as in every other directory. Add a test that checks the link counts and the sizes of the dataset roots and of the other directories, with nested datasets and a dataset whose mountpoint is not in the staging tree, and that find(1) sees the whole tree. Fixes: 240afd8c1fc ("makefs: Add ZFS support") MFC after: 1 week Approved by: markj Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D60439 (cherry picked from commit 81b5b2265d7734f9c4d4603031b3e8254c7e23d8) --- usr.sbin/makefs/tests/makefs_zfs_tests.sh | 54 +++++++++++++++++++++++++++++++ usr.sbin/makefs/zfs/fs.c | 7 ++-- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/usr.sbin/makefs/tests/makefs_zfs_tests.sh b/usr.sbin/makefs/tests/makefs_zfs_tests.sh index 22adfda00d2b..940461fe2565 100644 --- a/usr.sbin/makefs/tests/makefs_zfs_tests.sh +++ b/usr.sbin/makefs/tests/makefs_zfs_tests.sh @@ -219,6 +219,59 @@ compression_cleanup() common_cleanup } +# +# Make sure that the link count and the size of the directories which are the +# roots of datasets count "." and the directories which are the mountpoints +# of other datasets. fts(3) trusts the link count of the directories of ZFS +# and skips the subdirectories that it does not account for. +# +atf_test_case dataset_link_counts cleanup +dataset_link_counts_body() +{ + local dir entries subdirs + + create_test_dirs + cd $TEST_INPUTS_DIR + + mkdir -p dir1/sub1 dir1/sub2 dir1/dir2/sub3 dir1/dir2/dir3 dir4 + echo a > dir1/a + echo b > dir1/dir2/b + echo c > dir1/sub1/c + echo d > dir1/sub2/d + echo e > dir1/dir2/sub3/e + + cd - + + atf_check $MAKEFS -s 1g -o rootpath=/ -o poolname=$ZFS_POOL_NAME \ + -o fs=${ZFS_POOL_NAME}/dir1 -o fs=${ZFS_POOL_NAME}/dir1/dir2 \ + -o fs=${ZFS_POOL_NAME}/dir1/dir2/dir3 -o fs=${ZFS_POOL_NAME}/dir4 \ + -o fs=${ZFS_POOL_NAME}/dir5 \ + $TEST_IMAGE $TEST_INPUTS_DIR + + import_image + + # find(1) relies on the link counts to decide which entries may be + # directories, so it must see the whole tree. + (cd $TEST_INPUTS_DIR && find dir1 dir4 | sort) > ./expected + atf_check -o file:./expected -x \ + "cd $TEST_MOUNT_DIR && find dir1 dir4 | sort" + + # The link count is the number of directories in the directory plus + # "." and "..", and the size is the number of entries plus the same. + for dir in . dir1 dir1/sub1 dir1/dir2 dir1/dir2/dir3 dir4 dir5; do + subdirs=$(ls -d $TEST_MOUNT_DIR/$dir/*/ 2>/dev/null | wc -l) + entries=$(ls -A $TEST_MOUNT_DIR/$dir | wc -l) + atf_check -o inline:$((subdirs + 2))\\n \ + stat -f %l $TEST_MOUNT_DIR/$dir + atf_check -o inline:$((entries + 2))\\n \ + stat -f %z $TEST_MOUNT_DIR/$dir + done +} +dataset_link_counts_cleanup() +{ + common_cleanup +} + # # Try destroying a dataset that was created by makefs. # @@ -1112,6 +1165,7 @@ atf_init_test_cases() atf_add_test_case autoexpand atf_add_test_case basic atf_add_test_case compression + atf_add_test_case dataset_link_counts atf_add_test_case dataset_removal atf_add_test_case devfs atf_add_test_case empty_dir diff --git a/usr.sbin/makefs/zfs/fs.c b/usr.sbin/makefs/zfs/fs.c index 75f6e30e1500..4e15b4a79f14 100644 --- a/usr.sbin/makefs/zfs/fs.c +++ b/usr.sbin/makefs/zfs/fs.c @@ -389,10 +389,11 @@ fs_populate_sattrs(struct fs_populate_arg *arg, const fsnode *cur, * The size of a ZPL directory is the number of entries * (including "." and ".."), and the link count is the * number of entries which are directories - * (including "." and ".."). + * (including "." and ".."). The root of a dataset is + * the "." node itself, followed by the other entries. */ - for (fsnode *c = - fsnode_isroot(cur) ? cur->next : cur->child; + for (const fsnode *c = + fsnode_isroot(cur) ? cur : cur->child; c != NULL; c = c->next) { switch (c->type) { case S_IFDIR: