From nobody Mon Oct 19 13:24:05 2026 X-Original-To: dev-commits-src-all@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 4j7bqH1bcbz6wXKj for ; Mon, 19 Oct 2026 13:24:11 +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 4j7bqG6f48z3Hn4 for ; Mon, 19 Oct 2026 13:24:10 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792416250; 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=Mgzc6uFfZwQpwv+585042GsOeHoPY37kms/Zu2VLUDegVIM/TCmd6mpm+nxg5bNxuuP1Z4 SrzLBDjDYlsWh73fQK7aIn4GlyBBlfesY9vh4IG1Fqa+snx46xqBFopfR7jP/g4TQjW6IW zVsY86b1c7ugPO2YFaV5KzKw2tQgwFSLRr1OjseEvYUWpaPWwmcTGxZq8B3b73pQCSowoR tA/PNgPJKGZSBd4CVSepELgI9pAQpMhm+oA4NIOHkCUyv9TiNURIXVMeyLQV2+StDcRJU9 j+k44JXISeqZDWIVm0Yr3Qmo52qXDpYoEddAh0pbnsAgSUvhCBOva6wHEf7uNQ== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1792416250; b=NAvbgej0vOB+nUfe3EMvGFWL91g3g/a/WBLTVwT5WqIhXAmDa+WMHPTguOifLrV9ymJZNz csI898vilQInxYXSTSFIgBGtj9INNBjTDfMpexni5LXOnWWRwbOXH5roPs/l6s7/kiszNv IPZnZNEYQbX7nGZqoD3Hnj5Mbi7WZQesE83cQD5OIRM06E7MmtjeJaVNtHMlblmN4i2JEX 6rXyq5Jjm1YKH+AyeR6tIENd8KbjKjF+lJAoyO/bio2g7Jgv5dxZNM8BZzk6bR0MRylsRi U2kg8RB0T+r0LLbv+bkV286QBiD/+I6l7Lgc1ttVexgdzTPSnB7YnfE9UxHAqw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792416250; 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=h9o1jCuADKx6C1IxiNPV2jpCTEE3SunVFK8froAczRV0MW8+XEkzEx35Y/Gz1OBknnTwFL LdaqAAtZ9/NQfJ7T3LUOnHiXP//qXSstUJflMOcjiskENgRoqo5Pj0kfxYrtiJD+Kz4qaj SGm510V8DSXrsoS/NnejCFBHwvMlkwIR90bqZj3xh3vmP1QxWtjmIznUVjoL5be3bHr9DV N+K3tC90ru0dFGe152wavcFcFM/Xw5f301Fs793syCG0PpISVXoi6igaVLjaVmxuaU8f9D 7v5+FmBs6THF7MeaXrLqmx0z6mFTRrIWTf1aoGGuZ4h2NlkUzfvR/r8Yu166fQ== 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 4j7bqG6JYfzM1d for ; Mon, 19 Oct 2026 13:24:10 +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-all X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: Commit messages for all branches of the 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: