blob: 00c0f7b0ab8f485553631b1f23bfdffd7201e21e [file] [log] [blame]
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2015 SUSE Linux Products GmbH. All Rights Reserved.
#
# FS QA Test No. 059
#
# This test is motivated by an fsync issue discovered in btrfs.
# The issue was that after punching a hole for a small range, which affected
# only a partial page, an fsync operation would have no effect at all. This was
# because for this particular case the btrfs hole punching implementation did
# not update some btrfs specific inode metadata that is required to determine
# if an fsync operation needs to update the fsync log. For this to happen, it
# was also necessary that in the transaction where the hole punching was
# performed, and before the fsync operation, no other operation that modified
# the file (or its metadata) was performed.
#
# The btrfs issue was fixed by the following linux kernel patch:
#
# Btrfs: add missing inode update when punching hole
#
# Also test the mtime and ctime properties of the file change after punching
# holes with ranges that operate only on a single block of the file.
#
. ./common/preamble
_begin_fstest metadata auto quick punch log
# Override the default cleanup function.
_cleanup()
{
_cleanup_flakey
rm -f $tmp.*
}
# Import common functions.
. ./common/filter
. ./common/dmflakey
# real QA test starts here
_supported_fs generic
_require_scratch
_require_dm_target flakey
_require_xfs_io_command "fpunch"
_scratch_mkfs >> $seqres.full 2>&1
_require_metadata_journaling $SCRATCH_DEV
_init_flakey
_mount_flakey
# Create our test file.
$XFS_IO_PROG -f -c "pwrite -S 0x22 -b 16K 0 16K" \
$SCRATCH_MNT/foo | _filter_xfs_io
# Fsync the file, this makes btrfs update some btrfs inode specific fields
# that are used to track if the inode needs to be written/updated to the fsync
# log or not. After this fsync, the new values for those fields indicate that
# a subsequent fsync does not need to touch the fsync log.
$XFS_IO_PROG -c "fsync" $SCRATCH_MNT/foo
# Force a commit of the current transaction. After this point, any operation
# that modifies the data or metadata of our file, should update those fields in
# the btrfs inode with values that make the next fsync operation write to the
# fsync log.
sync
# Sleep for 1 second, because we want to check that the next punch operations we
# do update the file's mtime and ctime.
sleep 1
mtime_before=$(stat -c %Y $SCRATCH_MNT/foo)
ctime_before=$(stat -c %Z $SCRATCH_MNT/foo)
# Punch a hole in our file. This small range affects only 1 page.
# This made the btrfs hole punching implementation write only some zeroes in
# one page, but it did not update the btrfs inode fields used to determine if
# the next fsync needs to write to the fsync log.
$XFS_IO_PROG -c "fpunch 8000 4K" $SCRATCH_MNT/foo
# Another variation of the previously mentioned case.
$XFS_IO_PROG -c "fpunch 15000 100" $SCRATCH_MNT/foo
# Now fsync the file. This was a no-operation because the previous hole punch
# operation didn't update the inode's fields mentioned before, so they remained
# with the values they had after the first fsync - that is, they indicate that
# it is not needed to write to fsync log.
$XFS_IO_PROG -c "fsync" $SCRATCH_MNT/foo
echo "File content before:"
od -t x1 $SCRATCH_MNT/foo
_flakey_drop_and_remount
# Because the last fsync didn't do anything, here the file content matched what
# it was after the first fsync, before the holes were punched, and not what it
# was after the holes were punched.
echo "File content after:"
od -t x1 $SCRATCH_MNT/foo
mtime_after=$(stat -c %Y $SCRATCH_MNT/foo)
ctime_after=$(stat -c %Z $SCRATCH_MNT/foo)
[ $mtime_after -gt $mtime_before ] || \
echo "mtime did not increase (before: $mtime_before after: $mtime_after"
[ $ctime_after -gt $ctime_before ] || \
echo "ctime did not increase (before: $ctime_before after: $ctime_after"
status=0
exit