blob: b2c2e607d6bba22fd292be968640affb3c094a66 [file] [log] [blame]
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2024 SUSE Linux Products GmbH. All Rights Reserved.
#
# FS QA Test 366
#
# Test if mixed direct read, direct write and buffered write on the same file will
# hang the filesystem.
#
# This is exposed by an incoming btrfs feature, which allows a folio to be
# partial uptodate if the buffered write range is block aligned but not yet
# full folio aligned.
#
# Such behavior makes btrfs to hang reliably under generic/095.
# This is the extracted minimal reproducer for 4k block size and 64K page size.
#
. ./common/preamble
_begin_fstest auto quick rw
. ./common/filter
_require_scratch
_require_odirect 512 # see fio job1 config below
_require_aio
[ "$FSTYP" = "btrfs" ] && _fixed_by_kernel_commit xxxxxxxxxxxx \
"btrfs: avoid deadlock when reading a partial uptodate folio"
iterations=$((32 * LOAD_FACTOR))
fio_config=$tmp.fio
fio_out=$tmp.fio.out
blksz=`$here/src/min_dio_alignment $SCRATCH_MNT $SCRATCH_DEV`
cat >$fio_config <<EOF
[global]
bs=8k
iodepth=1
randrepeat=1
size=256k
directory=$SCRATCH_MNT
numjobs=1
[job1]
ioengine=sync
bs=512
direct=1
rw=randread
filename=file1
[job2]
ioengine=libaio
rw=randwrite
direct=1
filename=file1
[job3]
ioengine=posixaio
rw=randwrite
filename=file1
EOF
_require_fio $fio_config
for (( i = 0; i < $iterations; i++)); do
_scratch_mkfs >>$seqres.full 2>&1
_scratch_mount
# There's a known EIO failure to report collisions between directio and buffered
# writes to userspace, refer to upstream linux 5a9d929d6e13. So ignore EIO error
# at here.
#
# And for btrfs if sector size < page size, if we have a partial
# uptodate folio caused by a buffered write, e.g:
#
# 0 16K 32K 48K 64K
# | |///////////|
# \- sector Uptodate|Dirty
#
# Then writeback happens and finished, but btrfs' ordered extent not
# yet finished.
# In that case, the folio can be released from the page cache (since
# the folio is not under IO/lock).
#
# Then new buffered writes into the folio happened, re-dirty the folio:
# 0 16K 32K 48K 64K
# |//////////| |///////////|
# \- sector Uptodate|Dirty \- No sector flags
# extent map PINNED
# OE still here
#
# Now read is triggered on that folio.
# Btrfs will need to wait for any existing ordered extents in the folio range,
# that wait will also trigger writeback if the folio is dirty.
# That writeback will happen for range [48K, 64K), but since the whole folio
# is locked for read, writeback will also try to lock the same folio, causing
# a deadlock.
$FIO_PROG $fio_config --ignore_error=,EIO --output=$fio_out
# umount before checking dmesg in case umount triggers any WARNING or Oops
_scratch_unmount
_check_dmesg _filter_aiodio_dmesg
echo "=== fio $i/$iterations ===" >> $seqres.full
cat $fio_out >> $seqres.full
done
echo "Silence is golden"
# success, all done
status=0
exit