| #! /bin/bash |
| # SPDX-License-Identifier: GPL-2.0 |
| # Copyright (C) 2015 SUSE Linux Products GmbH. All Rights Reserved. |
| # |
| # FS QA Test No. 039 |
| # |
| # This test is motivated by an fsync issue discovered in btrfs. |
| # The issue was that after fsyncing an inode that got its link count |
| # decremented, and the new link count is greater than zero, after the |
| # fsync log replay the inode's parent directory metadata became |
| # inconsistent - it had a wrong i_size and dangling index entries which |
| # prevented the directory from ever being removed (rmdir always failed |
| # with -ENOTEMPTY, even if the directory had no more child inodes). |
| # |
| # The btrfs issue was fixed by the following linux kernel patch: |
| # |
| # Btrfs: fix directory inconsistency after fsync log replay |
| # |
| . ./common/preamble |
| _begin_fstest metadata auto quick log |
| |
| # Override the default cleanup function. |
| _cleanup() |
| { |
| _cleanup_flakey |
| } |
| |
| # Import common functions. |
| . ./common/filter |
| . ./common/dmflakey |
| |
| # real QA test starts here |
| _supported_fs generic |
| _require_scratch |
| _require_hardlinks |
| _require_dm_target flakey |
| |
| _scratch_mkfs >> $seqres.full 2>&1 |
| _require_metadata_journaling $SCRATCH_DEV |
| _init_flakey |
| _mount_flakey |
| |
| # Create a test file with 2 hard links in the same directory. |
| mkdir -p $SCRATCH_MNT/a/b |
| echo "hello world" > $SCRATCH_MNT/a/b/foo |
| ln $SCRATCH_MNT/a/b/foo $SCRATCH_MNT/a/b/bar |
| |
| # Make sure all metadata and data are durably persisted. |
| sync |
| |
| # Now remove one of the hard links and fsync the inode. |
| rm -f $SCRATCH_MNT/a/b/bar |
| $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/a/b/foo |
| |
| _flakey_drop_and_remount |
| |
| # Remove the last hard link of the file and attempt to remove its parent |
| # directory - this failed in btrfs because the fsync log and replay code |
| # didn't decrement the parent directory's i_size and left dangling directory |
| # index entries - this made the btrfs rmdir implementation always fail with |
| # the error -ENOTEMPTY. |
| # |
| # The dangling directory index entries were visible to user space, but it was |
| # impossible to do anything on them (unlink, open, read, write, stat, etc) |
| # because the inode they pointed to did not exist anymore. |
| # |
| # The parent directory's metadata inconsistency (stale index entries) was |
| # also detected by btrfs' fsck tool, which is run automatically by the fstests |
| # framework when the test finishes. The error message reported by fsck was: |
| # |
| # root 5 inode 259 errors 2001, no inode item, link count wrong |
| # unresolved ref dir 258 index 3 namelen 3 name bar filetype 1 errors 4, no inode ref |
| # |
| rm -f $SCRATCH_MNT/a/b/* |
| rmdir $SCRATCH_MNT/a/b |
| rmdir $SCRATCH_MNT/a |
| |
| echo "Silence is golden" |
| status=0 |
| exit |