@@ -721,7 +721,7 @@ static int ftw_add_inode(const char *full_path, const struct stat *st,
parent = rootdir_path_last(¤t_path);
root = parent->root;
- /* For non-directory inode, check if there is already any hard link. */
+ /* Check if there is already a hard link record for this. */
if (have_hard_links) {
struct hardlink_entry *found;
@@ -767,6 +767,7 @@ static int ftw_add_inode(const char *full_path, const struct stat *st,
error("failed to insert inode item %llu for '%s': %m", ino, full_path);
return ret;
}
+
ret = btrfs_add_link(g_trans, root, ino, parent->ino,
full_path + ftwbuf->base,
strlen(full_path) - ftwbuf->base,
@@ -778,10 +779,7 @@ static int ftw_add_inode(const char *full_path, const struct stat *st,
return ret;
}
- /*
- * Found a possible hard link, add it into the hard link rb tree for
- * future detection.
- */
+ /* Record this new hard link. */
if (have_hard_links) {
ret = add_hard_link(root, ino, st);
if (ret < 0) {
@@ -11,23 +11,75 @@ prepare_test_dev
tmp=$(_mktemp_dir mkfs-rootdir)
-run_check touch "$tmp/foo"
-run_check mkdir "$tmp/dir"
-run_check mkdir "$tmp/dir/subvol"
-run_check touch "$tmp/dir/subvol/bar"
+basic()
+{
+ run_check touch "$tmp/foo"
+ run_check mkdir "$tmp/dir"
+ run_check mkdir "$tmp/dir/subvol"
+ run_check touch "$tmp/dir/subvol/bar"
-run_check_mkfs_test_dev --rootdir "$tmp" --subvol dir/subvol
-run_check $SUDO_HELPER "$TOP/btrfs" check "$TEST_DEV"
+ run_check_mkfs_test_dev --rootdir "$tmp" --subvol dir/subvol
+ run_check $SUDO_HELPER "$TOP/btrfs" check "$TEST_DEV"
-run_check_mount_test_dev
-run_check_stdout $SUDO_HELPER "$TOP/btrfs" subvolume list "$TEST_MNT" | \
+ run_check_mount_test_dev
+ run_check_stdout $SUDO_HELPER "$TOP/btrfs" subvolume list "$TEST_MNT" | \
cut -d\ -f9 > "$tmp/output"
-run_check_umount_test_dev
+ run_check_umount_test_dev
-result=$(cat "$tmp/output")
+ result=$(cat "$tmp/output")
-if [ "$result" != "dir/subvol" ]; then
- _fail "dir/subvol not in subvolume list"
-fi
+ if [ "$result" != "dir/subvol" ]; then
+ _fail "dir/subvol not in subvolume list"
+ fi
+ rm -rf -- "$tmp/foo" "$tmp/dir"
+}
+basic_hardlinks()
+{
+ run_check touch "$tmp/hl1"
+ run_check ln "$tmp/hl1" "$tmp/hl2"
+ run_check mkdir "$tmp/dir"
+ run_check ln "$tmp/hl1" "$tmp/dir/hl3"
+
+ run_check_mkfs_test_dev --rootdir "$tmp"
+ run_check $SUDO_HELPER "$TOP/btrfs" check "$TEST_DEV"
+
+ run_check_mount_test_dev
+ nr_hardlink=$(run_check_stdout $SUDO_HELPER stat -c "%h" "$TEST_MNT/hl1")
+
+ if [ "$nr_hardlink" -ne 3 ]; then
+ _fail "hard link number incorrect, has ${nr_hardlink} expect 3"
+ fi
+ run_check_umount_test_dev
+ rm -rf -- "$tmp/hl1" "$tmp/hl2" "$tmp/dir"
+}
+
+split_by_subvolume_hardlinks()
+{
+ run_check touch "$tmp/hl1"
+ run_check ln "$tmp/hl1" "$tmp/hl2"
+ run_check mkdir "$tmp/subv"
+ run_check ln "$tmp/hl1" "$tmp/subv/hl3"
+
+ run_check_mkfs_test_dev --rootdir "$tmp" --subvol subv
+ run_check $SUDO_HELPER "$TOP/btrfs" check "$TEST_DEV"
+
+ run_check_mount_test_dev
+ nr_hardlink=$(run_check_stdout $SUDO_HELPER stat -c "%h" "$TEST_MNT/hl1")
+
+ if [ $nr_hardlink -ne 2 ]; then
+ _fail "hard link number incorrect for hl1, has ${nr_hardlink} expect 2"
+ fi
+
+ nr_hardlink=$(run_check_stdout $SUDO_HELPER stat -c "%h" "$TEST_MNT/subv/hl3")
+ if [ $nr_hardlink -ne 1 ]; then
+ _fail "hard link number incorrect for subv/hl3, has ${nr_hardlink} expect 1"
+ fi
+ run_check_umount_test_dev
+ rm -rf -- "$tmp/hl1" "$tmp/hl2" "$tmp/dir"
+}
+
+basic
+basic_hardlinks
+split_by_subvolume_hardlinks
rm -rf -- "$tmp"
This introduces two new cases: - 3 hardlinks without any subvolume This should results 3 hard links inside the btrfs. - 3 hardlinks, but a subvolume will split 2 of them Then the 2 inside the same subvolume should still report 2 nlinks, but the lone one inside the new subvolume can only report 1 nlink. Signed-off-by: Qu Wenruo <wqu@suse.com> --- mkfs/rootdir.c | 8 +-- tests/mkfs-tests/036-rootdir-subvol/test.sh | 78 +++++++++++++++++---- 2 files changed, 68 insertions(+), 18 deletions(-)