Stress test folio splits by using the debugfs interface to a target a new smaller folio order. This is dangerous at the moment as its using a debugfs API which requires two out of tree fixes [0] [1] which will be posted shortly. With these patches applied no crash is possible yet. However, this test was designed to try to exacerbate races with folio splits and writeback, at least running generic/447 twice ends up producing a crash only if large folio splits with minimum folio order is enabled. With the known fixes for the debugfs interface, this test produces no crashes even after 3 hour soaking for 4k and LBS. We should enhance this test a bit more so to reproduce the issues observed by running generic/447 twice. This also begs the question if something like MADV_NOHUGEPAGE might be desirable from userspace, so to enable userspace to request splits when possible. If inspecting more closely, you'll want to enable on your kernel boot: dyndbg='file mm/huge_memory.c +p' [0] https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git/commit/?h=20240424-lbs&id=80f6df5037fd0ad560526af45bd7f4d779fe03f6 [1] https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git/commit/?h=20240424-lbs&id=38f6fac5b4283ea48b1876fc56728f062168f8c3 Signed-off-by: Luis Chamberlain <mcgrof@xxxxxxxxxx> --- For those that want to help stress test folio splits to an order, hopefully this will help start to enable this. Perhaps there are better ways to create more easy targets to stress test folio splits, and in particular try to reproduce the issue which so far is only possible by running generic/447 twice on LBS. The issue with generic/447 on LBS is not observed on 4k, and this test produces no crashes on LBS... common/rc | 20 +++++++++ tests/generic/745 | 97 +++++++++++++++++++++++++++++++++++++++++++ tests/generic/745.out | 2 + 3 files changed, 119 insertions(+) create mode 100755 tests/generic/745 create mode 100644 tests/generic/745.out diff --git a/common/rc b/common/rc index d4432f5ce259..1eefb53aa84b 100644 --- a/common/rc +++ b/common/rc @@ -127,6 +127,26 @@ _require_compaction() _notrun "Need compaction enabled CONFIG_COMPACTION=y" fi } + +# Requires CONFIG_DEBUGFS and truncation knobs +SPLIT_DEBUGFS="/sys/kernel/debug/split_huge_pages" +_require_split_debugfs() +{ + if [ ! -f $SPLIT_DEBUGFS ]; then + _notrun "Needs CONFIG_DEBUGFS and split_huge_pages" + fi +} + +_split_huge_pages_file_full() +{ + local file=$1 + local offset="0x0" + local len=$(printf "%x" $(stat --format='%s' $file)) + local order="0" + local split_cmd="$file,$offset,0x${len},$order" + echo $split_cmd > $SPLIT_DEBUGFS +} + # Get hugepagesize in bytes _get_hugepagesize() { diff --git a/tests/generic/745 b/tests/generic/745 new file mode 100755 index 000000000000..0a30dbee35bd --- /dev/null +++ b/tests/generic/745 @@ -0,0 +1,97 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2024 Luis Chamberlain. All Rights Reserved. +# +# FS QA Test No. 734 +# +# Run fsstress in a loop, and in the background force some writeback and +# folio splits for every file. If you're enabling this and want to check +# underneath the hood you may want to enable: +# +# dyndbg='file mm/huge_memory.c +p' +. ./common/preamble +_begin_fstest long_rw stress soak smoketest dangerous_fuzzers + +# Override the default cleanup function. +_cleanup() +{ + cd / + rm -f $tmp.* + $KILLALL_PROG -9 fsstress > /dev/null 2>&1 +} + +# Import common functions. +. ./common/filter + +# real QA test starts here +_supported_fs generic +_require_test +_require_scratch +_require_split_debugfs +_require_command "$KILLALL_PROG" "killall" + +echo "Silence is golden" + +_scratch_mkfs >>$seqres.full 2>&1 +_scratch_mount >> $seqres.full 2>&1 + +nr_cpus=$((LOAD_FACTOR * 4)) +nr_ops=$((25000 * nr_cpus * TIME_FACTOR)) + +fsstress_args=(-w -d $SCRATCH_MNT/test -n $nr_ops -p $nr_cpus) + +# used to let our loops know when to stop +runfile="$tmp.keep.running.loop" +touch $runfile + +# The background ops are out of bounds, the goal is to race with fsstress. + +# Force folio split if possible, this seems to be screaming for MADV_NOHUGEPAGE +# for large folios. +while [ -e $runfile ]; do + for i in $(find $SCRATCH_MNT/test \( -type f \) 2>/dev/null); do + _split_huge_pages_file_full $i >/dev/null 2>&1 + done + sleep 2 +done & +split_huge_pages_files_pid=$! + +blocksize=$(_get_file_block_size $SCRATCH_MNT) +export XFS_DIO_MIN=$((blocksize * 2)) + +test -n "$SOAK_DURATION" && fsstress_args+=(--duration="$SOAK_DURATION") + +# Our general goal here is to race with ops which can stress folio addition, +# removal, edits, and writeback. + +# zero frequencies for write ops to minimize writeback +fsstress_args+=(-R) + +# XXX: we can improve this, so to increase the chances to allow more +# folio splits. Also running generic/447 twice triggers a corner case we can't +# capture here on folio splits and write_cache_pages, increasing the chances of +# this test to cover that same corner case would be ideal. +# +# https://gist.github.com/mcgrof/d12f586ec6ebe32b2472b5d634c397df +fsstress_args+=(-f creat=1) +fsstress_args+=(-f write=1) +fsstress_args+=(-f dwrite=1) +fsstress_args+=(-f truncate=1) +fsstress_args+=(-f zero=1) +fsstress_args+=(-f unlink=1) +fsstress_args+=(-f fsync=1) +fsstress_args+=(-f punch=2) +fsstress_args+=(-f copyrange=4) +fsstress_args+=(-f clonerange=4) + +if [[ "$FSTYP" != "xfs" || "$FSTYP" == "ext4" ]]; then + fsstress_args+=(-f collapse=1) +fi + +$FSSTRESS_PROG $FSSTRESS_AVOID "${fsstress_args[@]}" >> $seqres.full + +rm -f $runfile +wait > /dev/null 2>&1 + +status=0 +exit diff --git a/tests/generic/745.out b/tests/generic/745.out new file mode 100644 index 000000000000..fce6b7f5489d --- /dev/null +++ b/tests/generic/745.out @@ -0,0 +1,2 @@ +QA output created by 745 +Silence is golden -- 2.43.0