]> git-server-git.apps.pok.os.sepia.ceph.com Git - xfstests-dev.git/commitdiff
scrub: test correction of directory tree corruptions
authorDarrick J. Wong <djwong@kernel.org>
Thu, 20 Jun 2024 21:00:19 +0000 (14:00 -0700)
committerZorro Lang <zlang@kernel.org>
Sun, 23 Jun 2024 15:04:36 +0000 (23:04 +0800)
Make sure that we can fix directory tree loops and multiply-owned dirs.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Zorro Lang <zlang@kernel.org>
12 files changed:
tests/xfs/623 [new file with mode: 0755]
tests/xfs/623.out [new file with mode: 0644]
tests/xfs/624 [new file with mode: 0755]
tests/xfs/624.out [new file with mode: 0644]
tests/xfs/625 [new file with mode: 0755]
tests/xfs/625.out [new file with mode: 0644]
tests/xfs/626 [new file with mode: 0755]
tests/xfs/626.out [new file with mode: 0644]
tests/xfs/627 [new file with mode: 0755]
tests/xfs/627.out [new file with mode: 0644]
tests/xfs/628 [new file with mode: 0755]
tests/xfs/628.out [new file with mode: 0644]

diff --git a/tests/xfs/623 b/tests/xfs/623
new file mode 100755 (executable)
index 0000000..59952f6
--- /dev/null
@@ -0,0 +1,122 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023-2024 Oracle.  All Rights Reserved.
+#
+# FS QA Test No. 623
+#
+# Functional testing for online fsck of a directory loop that is not accessible
+# from the root directory.
+#
+. ./common/preamble
+_begin_fstest auto online_repair
+
+# Import common functions.
+. ./common/filter
+. ./common/inject
+. ./common/fuzzy
+. ./common/populate
+
+# real QA test starts here
+
+# Modify as appropriate.
+_supported_fs xfs
+_require_xfs_db_command "link"
+_require_xfs_db_command "unlink"
+_require_scratch
+_require_xfs_stress_online_repair
+
+prepare_fs() {
+       _scratch_mkfs >> $seqres.full
+       _scratch_mount
+       __stress_scrub_check_commands "%dir%" '' '' 'scrub dirtree'
+
+       # Begin by creating the following directory tree:
+       # root["A"]->A
+       # A["B"]->B
+       # B["C"]->C
+       mkdir -p "$SCRATCH_MNT/A/B/C"
+
+       root_inum="$(stat -c '%i' "$SCRATCH_MNT/")"
+       a_inum="$(stat -c '%i' "$SCRATCH_MNT/A")"
+       b_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B")"
+       c_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B/C")"
+
+       echo "root: $root_inum; a: $a_inum; b: $b_inum; c: $c_inum" >> $seqres.full
+
+       # Next, we complete the loop by creating C["A"]->A and deleting root["A"]->A.
+       # Directory tree is now:
+       # A["B"]->B
+       # B["C"]->C
+       # C["A"]->A
+       _scratch_unmount
+
+       root_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $root_inum")
+       a_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $a_inum")
+       b_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $b_inum")
+       c_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $c_inum")
+
+       _scratch_xfs_db \
+               -c "echo before root $root_inum" -c "inode $root_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before C $c_inum" -c "inode $c_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before A $a_inum" -c "inode $a_inum" -c 'print core.nlinkv2' -c "parent" \
+               >> $seqres.full
+
+       _scratch_xfs_db -x \
+               -c "inode $c_inum" -c "link -i $a_inum A" \
+               -c "inode $root_inum" -c "unlink A" \
+               >> $seqres.full
+
+       _scratch_xfs_db \
+               -c "echo after root $root_inum" -c "inode $root_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo after C $c_inum" -c "inode $c_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo after A $a_inum" -c "inode $a_inum" -c 'print core.nlinkv2' -c "parent" \
+               >> $seqres.full
+}
+
+simple_online_repair() {
+       echo "check root"
+       $XFS_IO_PROG -c "scrub dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "check A"
+       $XFS_IO_PROG -c "scrub dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "check B"
+       $XFS_IO_PROG -c "scrub dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "check C"
+       $XFS_IO_PROG -c "scrub dirtree $c_inum $c_gen" $SCRATCH_MNT
+
+       echo "repair root"
+       $XFS_IO_PROG -x -c "repair dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "repair A"
+       $XFS_IO_PROG -x -c "repair dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "repair B"
+       $XFS_IO_PROG -x -c "repair dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "repair C"
+       $XFS_IO_PROG -x -c "repair dirtree $c_inum $c_gen" $SCRATCH_MNT
+
+       echo "check root"
+       $XFS_IO_PROG -c "scrub dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "check A"
+       $XFS_IO_PROG -c "scrub dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "check B"
+       $XFS_IO_PROG -c "scrub dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "check C"
+       $XFS_IO_PROG -c "scrub dirtree $c_inum $c_gen" $SCRATCH_MNT
+}
+
+# Part 1: Use raw ioctls to detect the loop and fix it.
+prepare_fs
+_scratch_mount
+simple_online_repair
+_check_scratch_fs
+_scratch_unmount
+
+# Part 2: Use xfs_scrub to detect the loop and fix it.
+prepare_fs
+_scratch_mount
+_scratch_scrub &>> $seqres.full
+echo "xfs_scrub returned $?" >> $seqres.full
+_check_scratch_fs
+_scratch_unmount
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/623.out b/tests/xfs/623.out
new file mode 100644 (file)
index 0000000..2a8cd67
--- /dev/null
@@ -0,0 +1,19 @@
+QA output created by 623
+check root
+check A
+Corruption detected.
+check B
+Corruption detected.
+check C
+Corruption detected.
+repair root
+Metadata did not need repair or optimization.
+repair A
+repair B
+Metadata did not need repair or optimization.
+repair C
+Metadata did not need repair or optimization.
+check root
+check A
+check B
+check C
diff --git a/tests/xfs/624 b/tests/xfs/624
new file mode 100755 (executable)
index 0000000..707e886
--- /dev/null
@@ -0,0 +1,133 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023-2024 Oracle.  All Rights Reserved.
+#
+# FS QA Test No. 624
+#
+# Functional testing for online fsck of a directory loop that is accessible
+# from the root directory.
+#
+. ./common/preamble
+_begin_fstest auto online_repair
+
+# Import common functions.
+. ./common/filter
+. ./common/inject
+. ./common/fuzzy
+. ./common/populate
+
+# real QA test starts here
+
+# Modify as appropriate.
+_supported_fs xfs
+_require_xfs_db_command "link"
+_require_xfs_db_command "unlink"
+_require_scratch
+_require_xfs_stress_online_repair
+
+prepare_fs() {
+       _scratch_mkfs >> $seqres.full
+       _scratch_mount
+       __stress_scrub_check_commands "%dir%" '' '' 'scrub dirtree'
+
+       # Begin by creating the following directory tree:
+       # root["A"]->A
+       # A["B"]->B
+       # B["C"]->C
+       # C["D"]->D
+       mkdir -p "$SCRATCH_MNT/A/B/C/D"
+
+       root_inum="$(stat -c '%i' "$SCRATCH_MNT/")"
+       a_inum="$(stat -c '%i' "$SCRATCH_MNT/A")"
+       b_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B")"
+       c_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B/C")"
+       d_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B/C/D")"
+
+       echo "root: $root_inum; a: $a_inum; b: $b_inum; c: $c_inum; d: $d_inum" >> $seqres.full
+
+       # Next, we complete the loop by creating D["B1"]->B.  Directory tree is now:
+       # root["A"]->A
+       # A["B"]->B
+       # B["C"]->C
+       # C["D"]->D
+       # D["B1"]->B
+       _scratch_unmount
+
+       root_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $root_inum")
+       a_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $a_inum")
+       b_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $b_inum")
+       c_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $c_inum")
+       d_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $d_inum")
+
+       _scratch_xfs_db \
+               -c "echo before root $root_inum" -c "inode $root_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before D $d_inum" -c "inode $d_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before B $b_inum" -c "inode $b_inum" -c 'print core.nlinkv2' -c "parent" \
+               >> $seqres.full
+
+       _scratch_xfs_db -x \
+               -c "inode $d_inum" -c "link -i $b_inum B1" \
+               >> $seqres.full
+
+       _scratch_xfs_db \
+               -c "echo after root $root_inum" -c "inode $root_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo after D $c_inum" -c "inode $d_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo after B $a_inum" -c "inode $b_inum" -c 'print core.nlinkv2' -c "parent" \
+               >> $seqres.full
+}
+
+simple_online_repair() {
+       echo "check root"
+       $XFS_IO_PROG -c "scrub dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "check A"
+       $XFS_IO_PROG -c "scrub dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "check B"
+       $XFS_IO_PROG -c "scrub dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "check C"
+       $XFS_IO_PROG -c "scrub dirtree $c_inum $c_gen" $SCRATCH_MNT
+       echo "check D"
+       $XFS_IO_PROG -c "scrub dirtree $d_inum $d_gen" $SCRATCH_MNT
+
+       echo "repair root"
+       $XFS_IO_PROG -x -c "repair dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "repair A"
+       $XFS_IO_PROG -x -c "repair dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "repair D"
+       $XFS_IO_PROG -x -c "repair dirtree $d_inum $d_gen" $SCRATCH_MNT
+       echo "repair B"
+       $XFS_IO_PROG -x -c "repair dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "repair C"
+       $XFS_IO_PROG -x -c "repair dirtree $c_inum $c_gen" $SCRATCH_MNT
+       echo "repair D"
+       $XFS_IO_PROG -x -c "repair dirtree $d_inum $d_gen" $SCRATCH_MNT
+
+       echo "check root"
+       $XFS_IO_PROG -c "scrub dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "check A"
+       $XFS_IO_PROG -c "scrub dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "check B"
+       $XFS_IO_PROG -c "scrub dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "check C"
+       $XFS_IO_PROG -c "scrub dirtree $c_inum $c_gen" $SCRATCH_MNT
+       echo "check D"
+       $XFS_IO_PROG -c "scrub dirtree $d_inum $d_gen" $SCRATCH_MNT
+}
+
+# Part 1: Use raw ioctls to detect the loop and fix it.
+prepare_fs
+_scratch_mount
+simple_online_repair
+_check_scratch_fs
+_scratch_unmount
+
+# Part 2: Use xfs_scrub to detect the loop and fix it.
+prepare_fs
+_scratch_mount
+_scratch_scrub &>> $seqres.full
+echo "xfs_scrub returned $?" >> $seqres.full
+_check_scratch_fs
+_scratch_unmount
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/624.out b/tests/xfs/624.out
new file mode 100644 (file)
index 0000000..2c295ee
--- /dev/null
@@ -0,0 +1,25 @@
+QA output created by 624
+check root
+check A
+check B
+Corruption detected.
+check C
+Corruption detected during cross-referencing.
+check D
+Corruption detected during cross-referencing.
+repair root
+Metadata did not need repair or optimization.
+repair A
+Metadata did not need repair or optimization.
+repair D
+Corruption still detected during cross-referencing.
+repair B
+repair C
+Metadata did not need repair or optimization.
+repair D
+Metadata did not need repair or optimization.
+check root
+check A
+check B
+check C
+check D
diff --git a/tests/xfs/625 b/tests/xfs/625
new file mode 100755 (executable)
index 0000000..05225ca
--- /dev/null
@@ -0,0 +1,121 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023-2024 Oracle.  All Rights Reserved.
+#
+# FS QA Test No. 625
+#
+# Functional testing for online fsck of a directory chain that is not
+# accessible from the root directory.
+#
+. ./common/preamble
+_begin_fstest auto online_repair
+
+# Import common functions.
+. ./common/filter
+. ./common/inject
+. ./common/fuzzy
+. ./common/populate
+
+# real QA test starts here
+
+# Modify as appropriate.
+_supported_fs xfs
+_require_xfs_db_command "link"
+_require_xfs_db_command "unlink"
+_require_scratch
+_require_xfs_stress_online_repair
+
+prepare_fs() {
+       _scratch_mkfs >> $seqres.full
+       _scratch_mount
+       __stress_scrub_check_commands "%dir%" '' '' 'scrub dirtree'
+
+       # Begin by creating the following directory tree:
+       # root["A"]->A
+       # A["B"]->B
+       # B["C"]->C
+       mkdir -p "$SCRATCH_MNT/A/B/C"
+
+       root_inum="$(stat -c '%i' "$SCRATCH_MNT/")"
+       a_inum="$(stat -c '%i' "$SCRATCH_MNT/A")"
+       b_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B")"
+       c_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B/C")"
+
+       echo "root: $root_inum; a: $a_inum; b: $b_inum; c: $c_inum" >> $seqres.full
+
+       # Next, we sever the tree by deleting root["A"]->A.  Directory tree is now:
+       # A["B"]->B
+       # B["C"]->C
+       _scratch_unmount
+
+       root_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $root_inum")
+       a_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $a_inum")
+       b_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $b_inum")
+       c_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $c_inum")
+
+       _scratch_xfs_db \
+               -c "echo before root $root_inum" -c "inode $root_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before C $c_inum" -c "inode $c_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before A $a_inum" -c "inode $a_inum" -c 'print core.nlinkv2' -c "parent" \
+               >> $seqres.full
+
+       _scratch_xfs_db -x \
+               -c "inode $root_inum" -c "unlink A" \
+               >> $seqres.full
+
+       _scratch_xfs_db \
+               -c "echo after root $root_inum" -c "inode $root_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo after C $c_inum" -c "inode $c_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo after A $a_inum" -c "inode $a_inum" -c 'print core.nlinkv2' -c "parent" \
+               >> $seqres.full
+}
+
+simple_online_repair() {
+       echo "check root"
+       $XFS_IO_PROG -c "scrub dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "check A"
+       $XFS_IO_PROG -c "scrub dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "check B"
+       $XFS_IO_PROG -c "scrub dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "check C"
+       $XFS_IO_PROG -c "scrub dirtree $c_inum $c_gen" $SCRATCH_MNT
+
+       echo "repair C"
+       $XFS_IO_PROG -x -c "repair dirtree $c_inum $c_gen" $SCRATCH_MNT
+       echo "repair root"
+       $XFS_IO_PROG -x -c "repair dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "repair A"
+       $XFS_IO_PROG -x -c "repair dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "repair B"
+       $XFS_IO_PROG -x -c "repair dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "repair C"
+       $XFS_IO_PROG -x -c "repair dirtree $c_inum $c_gen" $SCRATCH_MNT
+
+       echo "check root"
+       $XFS_IO_PROG -c "scrub dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "check A"
+       $XFS_IO_PROG -c "scrub dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "check B"
+       $XFS_IO_PROG -c "scrub dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "check C"
+       $XFS_IO_PROG -c "scrub dirtree $c_inum $c_gen" $SCRATCH_MNT
+}
+
+# Part 1: Use raw ioctls to detect the chain and fix it.
+prepare_fs
+_scratch_mount
+simple_online_repair
+_check_scratch_fs
+_scratch_unmount
+
+# Part 2: Use xfs_scrub to detect the chain and fix it.
+prepare_fs
+_scratch_mount
+_scratch_scrub &>> $seqres.full
+echo "xfs_scrub returned $?" >> $seqres.full
+_check_scratch_fs
+_scratch_unmount
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/625.out b/tests/xfs/625.out
new file mode 100644 (file)
index 0000000..9ad5478
--- /dev/null
@@ -0,0 +1,21 @@
+QA output created by 625
+check root
+check A
+Corruption detected.
+check B
+Corruption detected during cross-referencing.
+check C
+Corruption detected during cross-referencing.
+repair C
+Corruption still detected during cross-referencing.
+repair root
+Metadata did not need repair or optimization.
+repair A
+repair B
+Metadata did not need repair or optimization.
+repair C
+Metadata did not need repair or optimization.
+check root
+check A
+check B
+check C
diff --git a/tests/xfs/626 b/tests/xfs/626
new file mode 100755 (executable)
index 0000000..e1c28be
--- /dev/null
@@ -0,0 +1,157 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023-2024 Oracle.  All Rights Reserved.
+#
+# FS QA Test No. 626
+#
+# Functional testing for online fsck of a multiply-owned directory that is
+# accessible from the root directory.
+#
+. ./common/preamble
+_begin_fstest auto online_repair
+
+# Import common functions.
+. ./common/filter
+. ./common/inject
+. ./common/fuzzy
+. ./common/populate
+
+# real QA test starts here
+
+# Modify as appropriate.
+_supported_fs xfs
+_require_xfs_db_command "link"
+_require_xfs_db_command "unlink"
+_require_scratch
+_require_xfs_stress_online_repair
+
+prepare_fs() {
+       _scratch_mkfs >> $seqres.full
+       _scratch_mount
+       __stress_scrub_check_commands "%dir%" '' '' 'scrub dirtree'
+
+       # Begin by creating the following directory tree:
+       # root["A"]->A
+       # A["B"]->B
+       # B["C"]->C
+       # C["D"]->D
+       # root["Z"]->Z
+       # Z["Y"]->Y
+       mkdir -p "$SCRATCH_MNT/A/B/C/D" "$SCRATCH_MNT/Z/Y"
+
+       root_inum="$(stat -c '%i' "$SCRATCH_MNT/")"
+       a_inum="$(stat -c '%i' "$SCRATCH_MNT/A")"
+       b_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B")"
+       c_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B/C")"
+       d_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B/C/D")"
+       z_inum="$(stat -c '%i' "$SCRATCH_MNT/Z")"
+       y_inum="$(stat -c '%i' "$SCRATCH_MNT/Z/Y")"
+
+       echo "root: $root_inum; a: $a_inum; b: $b_inum; c: $c_inum; d: $d_inum" >> $seqres.full
+       echo "root: $root_inum; z: $z_inum; y: $y_inum" >> $seqres.full
+
+       # Next, we create the multiply-owned directory by creating Y["C1"]->C.
+       # Directory tree is now:
+       # root["A"]->A
+       # A["B"]->B
+       # B["C"]->C
+       # C["D"]->D
+       # root["Z"]->Z
+       # Z["Y"]->Y
+       # Y["C1"]->C
+       _scratch_unmount
+
+       root_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $root_inum")
+       a_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $a_inum")
+       b_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $b_inum")
+       c_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $c_inum")
+       d_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $d_inum")
+       z_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $z_inum")
+       y_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $y_inum")
+
+       _scratch_xfs_db \
+               -c "echo before root $root_inum" -c "inode $root_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before Y $y_inum" -c "inode $y_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before B $b_inum" -c "inode $b_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before C $c_inum" -c "inode $c_inum" -c 'print core.nlinkv2' -c "parent" \
+               >> $seqres.full
+
+       _scratch_xfs_db -x \
+               -c "inode $y_inum" -c "link -i $c_inum C1" \
+               >> $seqres.full
+
+       _scratch_xfs_db \
+               -c "echo before root $root_inum" -c "inode $root_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before Y $y_inum" -c "inode $y_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before B $b_inum" -c "inode $b_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before C $c_inum" -c "inode $c_inum" -c 'print core.nlinkv2' -c "parent" \
+               >> $seqres.full
+}
+
+simple_online_repair() {
+       echo "check root"
+       $XFS_IO_PROG -c "scrub dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "check A"
+       $XFS_IO_PROG -c "scrub dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "check B"
+       $XFS_IO_PROG -c "scrub dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "check C"
+       $XFS_IO_PROG -c "scrub dirtree $c_inum $c_gen" $SCRATCH_MNT
+       echo "check D"
+       $XFS_IO_PROG -c "scrub dirtree $d_inum $d_gen" $SCRATCH_MNT
+       echo "check Z"
+       $XFS_IO_PROG -c "scrub dirtree $z_inum $z_gen" $SCRATCH_MNT
+       echo "check Y"
+       $XFS_IO_PROG -c "scrub dirtree $y_inum $y_gen" $SCRATCH_MNT
+
+       echo "repair D"
+       $XFS_IO_PROG -x -c "repair dirtree $d_inum $d_gen" $SCRATCH_MNT
+       echo "repair root"
+       $XFS_IO_PROG -x -c "repair dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "repair A"
+       $XFS_IO_PROG -x -c "repair dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "repair B"
+       $XFS_IO_PROG -x -c "repair dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "repair C"
+       $XFS_IO_PROG -x -c "repair dirtree $c_inum $c_gen" $SCRATCH_MNT
+       echo "repair D"
+       $XFS_IO_PROG -x -c "repair dirtree $d_inum $d_gen" $SCRATCH_MNT
+       echo "repair Z"
+       $XFS_IO_PROG -x -c "repair dirtree $z_inum $z_gen" $SCRATCH_MNT
+       echo "repair Y"
+       $XFS_IO_PROG -x -c "repair dirtree $y_inum $y_gen" $SCRATCH_MNT
+
+       echo "check root"
+       $XFS_IO_PROG -c "scrub dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "check A"
+       $XFS_IO_PROG -c "scrub dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "check B"
+       $XFS_IO_PROG -c "scrub dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "check C"
+       $XFS_IO_PROG -c "scrub dirtree $c_inum $c_gen" $SCRATCH_MNT
+       echo "check D"
+       $XFS_IO_PROG -c "scrub dirtree $d_inum $d_gen" $SCRATCH_MNT
+       echo "check Z"
+       $XFS_IO_PROG -c "scrub dirtree $z_inum $z_gen" $SCRATCH_MNT
+       echo "check Y"
+       $XFS_IO_PROG -c "scrub dirtree $y_inum $y_gen" $SCRATCH_MNT
+}
+
+# Part 1: Use raw ioctls to detect the multi-parent dir and fix it.
+prepare_fs
+_scratch_mount
+simple_online_repair
+_check_scratch_fs
+_scratch_unmount
+
+# Part 2: Use xfs_scrub to detect the multi-parent dir and fix it.
+prepare_fs
+_scratch_mount
+_scratch_scrub &>> $seqres.full
+echo "xfs_scrub returned $?" >> $seqres.full
+_check_scratch_fs
+_scratch_unmount
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/626.out b/tests/xfs/626.out
new file mode 100644 (file)
index 0000000..f5dadcb
--- /dev/null
@@ -0,0 +1,32 @@
+QA output created by 626
+check root
+check A
+check B
+check C
+Corruption detected.
+check D
+Corruption detected during cross-referencing.
+check Z
+check Y
+repair D
+Corruption still detected during cross-referencing.
+repair root
+Metadata did not need repair or optimization.
+repair A
+Metadata did not need repair or optimization.
+repair B
+Metadata did not need repair or optimization.
+repair C
+repair D
+Metadata did not need repair or optimization.
+repair Z
+Metadata did not need repair or optimization.
+repair Y
+Metadata did not need repair or optimization.
+check root
+check A
+check B
+check C
+check D
+check Z
+check Y
diff --git a/tests/xfs/627 b/tests/xfs/627
new file mode 100755 (executable)
index 0000000..ff76e58
--- /dev/null
@@ -0,0 +1,146 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023-2024 Oracle.  All Rights Reserved.
+#
+# FS QA Test No. 627
+#
+# Functional testing for online fsck of a directory loop that is inaccessible
+# from the root directory and has subdirectories.
+#
+. ./common/preamble
+_begin_fstest auto online_repair
+
+# Import common functions.
+. ./common/filter
+. ./common/inject
+. ./common/fuzzy
+. ./common/populate
+
+# real QA test starts here
+
+# Modify as appropriate.
+_supported_fs xfs
+_require_xfs_db_command "link"
+_require_xfs_db_command "unlink"
+_require_scratch
+_require_xfs_stress_online_repair
+
+prepare_fs() {
+       _scratch_mkfs >> $seqres.full
+       _scratch_mount
+       __stress_scrub_check_commands "%dir%" '' '' 'scrub dirtree'
+
+       # Begin by creating the following directory tree:
+       # root["A"]->A
+       # A["B"]->B
+       # B["C"]->C
+       # C["D"]->D
+       # D["E"]->E
+       mkdir -p "$SCRATCH_MNT/A/B/C/D/E"
+
+       root_inum="$(stat -c '%i' "$SCRATCH_MNT/")"
+       a_inum="$(stat -c '%i' "$SCRATCH_MNT/A")"
+       b_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B")"
+       c_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B/C")"
+       d_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B/C/D")"
+       e_inum="$(stat -c '%i' "$SCRATCH_MNT/A/B/C/D/E")"
+
+       echo "root: $root_inum; a: $a_inum; b: $b_inum; c: $c_inum; d: $d_inum; e: $e_inum" >> $seqres.full
+
+       # Complete the loop by creating D["B1"]->B and severing A["B"]->B.  Directory
+       # tree is now:
+       # root["A"]->A
+       # B["C"]->C
+       # C["D"]->D
+       # D["E"]->E
+       # D["B1"]->B
+       _scratch_unmount
+
+       root_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $root_inum")
+       a_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $a_inum")
+       b_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $b_inum")
+       c_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $c_inum")
+       d_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $d_inum")
+       e_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $e_inum")
+
+       _scratch_xfs_db \
+               -c "echo before root $root_inum" -c "inode $root_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before A $d_inum" -c "inode $a_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before D $d_inum" -c "inode $d_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before B $b_inum" -c "inode $b_inum" -c 'print core.nlinkv2' -c "parent" \
+               >> $seqres.full
+
+       _scratch_xfs_db -x \
+               -c "inode $d_inum" -c "link -i $b_inum B1" \
+               -c "inode $a_inum" -c "unlink B" \
+               >> $seqres.full
+
+       _scratch_xfs_db \
+               -c "echo before root $root_inum" -c "inode $root_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before A $d_inum" -c "inode $a_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before D $d_inum" -c "inode $d_inum" -c 'print core.nlinkv2' -c "ls" \
+               -c "echo before B $b_inum" -c "inode $b_inum" -c 'print core.nlinkv2' -c "parent" \
+               >> $seqres.full
+}
+
+simple_online_repair() {
+       echo "check root"
+       $XFS_IO_PROG -c "scrub dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "check A"
+       $XFS_IO_PROG -c "scrub dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "check B"
+       $XFS_IO_PROG -c "scrub dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "check C"
+       $XFS_IO_PROG -c "scrub dirtree $c_inum $c_gen" $SCRATCH_MNT
+       echo "check D"
+       $XFS_IO_PROG -c "scrub dirtree $d_inum $d_gen" $SCRATCH_MNT
+       echo "check E"
+       $XFS_IO_PROG -c "scrub dirtree $e_inum $e_gen" $SCRATCH_MNT
+
+       echo "repair root"
+       $XFS_IO_PROG -x -c "repair dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "repair A"
+       $XFS_IO_PROG -x -c "repair dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "repair E"
+       $XFS_IO_PROG -x -c "repair dirtree $e_inum $e_gen" $SCRATCH_MNT
+       echo "repair B"
+       $XFS_IO_PROG -x -c "repair dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "repair C"
+       $XFS_IO_PROG -x -c "repair dirtree $c_inum $c_gen" $SCRATCH_MNT
+       echo "repair D"
+       $XFS_IO_PROG -x -c "repair dirtree $d_inum $d_gen" $SCRATCH_MNT
+       echo "repair E"
+       $XFS_IO_PROG -x -c "repair dirtree $e_inum $e_gen" $SCRATCH_MNT
+
+       echo "check root"
+       $XFS_IO_PROG -c "scrub dirtree $root_inum $root_gen" $SCRATCH_MNT
+       echo "check A"
+       $XFS_IO_PROG -c "scrub dirtree $a_inum $a_gen" $SCRATCH_MNT
+       echo "check B"
+       $XFS_IO_PROG -c "scrub dirtree $b_inum $b_gen" $SCRATCH_MNT
+       echo "check C"
+       $XFS_IO_PROG -c "scrub dirtree $c_inum $c_gen" $SCRATCH_MNT
+       echo "check D"
+       $XFS_IO_PROG -c "scrub dirtree $d_inum $d_gen" $SCRATCH_MNT
+       echo "check E"
+       $XFS_IO_PROG -c "scrub dirtree $e_inum $e_gen" $SCRATCH_MNT
+}
+
+# Part 1: Use raw ioctls to detect the loop and fix it.
+prepare_fs
+_scratch_mount
+simple_online_repair
+_check_scratch_fs
+_scratch_unmount
+
+# Part 2: Use xfs_scrub to detect the loop and fix it.
+prepare_fs
+_scratch_mount
+_scratch_scrub &>> $seqres.full
+echo "xfs_scrub returned $?" >> $seqres.full
+_check_scratch_fs
+_scratch_unmount
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/627.out b/tests/xfs/627.out
new file mode 100644 (file)
index 0000000..3b46768
--- /dev/null
@@ -0,0 +1,30 @@
+QA output created by 627
+check root
+check A
+check B
+Corruption detected.
+check C
+Corruption detected.
+check D
+Corruption detected.
+check E
+Corruption detected during cross-referencing.
+repair root
+Metadata did not need repair or optimization.
+repair A
+Metadata did not need repair or optimization.
+repair E
+Corruption still detected during cross-referencing.
+repair B
+repair C
+Metadata did not need repair or optimization.
+repair D
+Metadata did not need repair or optimization.
+repair E
+Metadata did not need repair or optimization.
+check root
+check A
+check B
+check C
+check D
+check E
diff --git a/tests/xfs/628 b/tests/xfs/628
new file mode 100755 (executable)
index 0000000..145651f
--- /dev/null
@@ -0,0 +1,78 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023-2024 Oracle.  All Rights Reserved.
+#
+# FS QA Test No. 628
+#
+# Race rename and directory tree structure corruption detector for a while to
+# exercise the dirtree code's directory path invalidation and its ability to
+# handle unlinked directories.
+#
+. ./common/preamble
+_begin_fstest scrub dangerous_fsstress_scrub
+
+# Import common functions.
+. ./common/filter
+. ./common/fuzzy
+. ./common/inject
+. ./common/xfs
+
+# real QA test starts here
+_supported_fs xfs
+_require_scratch
+_require_xfs_stress_scrub
+
+_scratch_mkfs > "$seqres.full" 2>&1
+_scratch_mount
+__stress_scrub_check_commands "%dir%" '' '' 'scrub dirtree'
+
+parentA="$SCRATCH_MNT/a"
+parentB="$SCRATCH_MNT/b"
+child="$parentA/c/d/e/f/g/h/i/j/k/l/m/n/o/p"
+unlinked="$SCRATCH_MNT/unlinked"
+
+mkdir -p "$parentA" "$parentB" "$child" "$unlinked"
+
+# Find handle info for the child so that we can scrub by handle
+child_inum="$(stat -c '%i' "$child")"
+_scratch_unmount
+child_gen=$(_scratch_xfs_get_metadata_field core.gen "inode $child_inum")
+_scratch_mount
+
+# Queue up a bunch of scrub requests per invocation
+ioargs=()
+for ((i = 0; i < 100; i++)); do
+       ioargs+=('-c' "scrub dirtree $child_inum $child_gen")
+done
+
+renamer() {
+       # Make sure the scrubber handles unlinked directories correctly
+       # by squatting on an empty directory
+       cd "$unlinked"
+       rm -r -f "$unlinked"
+
+       # Bounce the second level directory between parents to stress the
+       # invalidation detector
+       while [ -e $RUNNING_FILE ]; do
+               mv "$parentA/c" "$parentB/"
+               mv "$parentB/c" "$parentA/"
+       done
+}
+
+RUNNING_FILE="$SCRATCH_MNT/run"
+touch $RUNNING_FILE
+renamer &
+
+# Exercise the directory tree scrubber in two ways -- scrubbing the lowest
+# subdir by handle, and running xfs_scrub on the entire fs.
+while _soak_loop_running $((10 * TIME_FACTOR)); do
+       $XFS_IO_PROG "${ioargs[@]}" "$SCRATCH_MNT"
+       XFS_SCRUB_PHASE=5 _scratch_scrub -n >> $seqres.full
+done
+rm -f $RUNNING_FILE
+wait
+
+# success, all done
+echo Silence is golden
+status=0
+exit
diff --git a/tests/xfs/628.out b/tests/xfs/628.out
new file mode 100644 (file)
index 0000000..06695a8
--- /dev/null
@@ -0,0 +1,2 @@
+QA output created by 628
+Silence is golden