* [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes
@ 2023-07-14 14:59 Darrick J. Wong
2023-07-14 15:14 ` Bill O'Donnell
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Darrick J. Wong @ 2023-07-14 14:59 UTC (permalink / raw)
To: zlang; +Cc: linux-xfs, fstests, guan, mpatocka
From: Darrick J. Wong <djwong@kernel.org>
Mikulas reported that this test became a forkbomb on his system when he
tested it with bcachefs. Unlike XFS and ext4, which have large inodes
consuming hundreds of bytes, bcachefs has very tiny ones. Therefore, it
reports a large number of free inodes on a freshly mounted 1GB fs (~15
million), which causes this test to try to create 15000 processes.
There's really no reason to do that -- all this test wanted to do was to
exhaust the number of inodes as quickly as possible using all available
CPUs, and then it ran xfs_repair to try to reproduce a bug. Set the
number of subshells to 4x the CPU count and spread the work among them
instead of forking thousands of processes.
Reported-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Tested-by: Mikulas Patocka <mpatocka@redhat.com>
---
tests/generic/558 | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/tests/generic/558 b/tests/generic/558
index 4e22ce656b..de5c28d00d 100755
--- a/tests/generic/558
+++ b/tests/generic/558
@@ -39,15 +39,21 @@ _scratch_mkfs_sized $((1024 * 1024 * 1024)) >>$seqres.full 2>&1
_scratch_mount
i=0
-free_inode=`_get_free_inode $SCRATCH_MNT`
-file_per_dir=1000
-loop=$((free_inode / file_per_dir + 1))
+free_inodes=$(_get_free_inode $SCRATCH_MNT)
+nr_cpus=$(( $($here/src/feature -o) * 4 * LOAD_FACTOR ))
+echo "free inodes: $free_inodes nr_cpus: $nr_cpus" >> $seqres.full
+
+if ((free_inodes <= nr_cpus)); then
+ nr_cpus=1
+ files_per_dir=$free_inodes
+else
+ files_per_dir=$(( (free_inodes + nr_cpus - 1) / nr_cpus ))
+fi
mkdir -p $SCRATCH_MNT/testdir
echo "Create $((loop * file_per_dir)) files in $SCRATCH_MNT/testdir" >>$seqres.full
-while [ $i -lt $loop ]; do
- create_file $SCRATCH_MNT/testdir $file_per_dir $i >>$seqres.full 2>&1 &
- let i=$i+1
+for ((i = 0; i < nr_cpus; i++)); do
+ create_file $SCRATCH_MNT/testdir $files_per_dir $i >>$seqres.full 2>&1 &
done
wait
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes
2023-07-14 14:59 [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes Darrick J. Wong
@ 2023-07-14 15:14 ` Bill O'Donnell
2023-07-17 3:03 ` Zorro Lang
2023-07-18 1:02 ` Darrick J. Wong
2 siblings, 0 replies; 7+ messages in thread
From: Bill O'Donnell @ 2023-07-14 15:14 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: zlang, linux-xfs, fstests, guan, mpatocka
On Fri, Jul 14, 2023 at 07:59:00AM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> Mikulas reported that this test became a forkbomb on his system when he
> tested it with bcachefs. Unlike XFS and ext4, which have large inodes
> consuming hundreds of bytes, bcachefs has very tiny ones. Therefore, it
> reports a large number of free inodes on a freshly mounted 1GB fs (~15
> million), which causes this test to try to create 15000 processes.
>
> There's really no reason to do that -- all this test wanted to do was to
> exhaust the number of inodes as quickly as possible using all available
> CPUs, and then it ran xfs_repair to try to reproduce a bug. Set the
> number of subshells to 4x the CPU count and spread the work among them
> instead of forking thousands of processes.
>
> Reported-by: Mikulas Patocka <mpatocka@redhat.com>
> Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> Tested-by: Mikulas Patocka <mpatocka@redhat.com>
Reviewed-by: Bill O'Donnell <bodonnel@redhat.com>
> ---
> tests/generic/558 | 18 ++++++++++++------
> 1 file changed, 12 insertions(+), 6 deletions(-)
>
> diff --git a/tests/generic/558 b/tests/generic/558
> index 4e22ce656b..de5c28d00d 100755
> --- a/tests/generic/558
> +++ b/tests/generic/558
> @@ -39,15 +39,21 @@ _scratch_mkfs_sized $((1024 * 1024 * 1024)) >>$seqres.full 2>&1
> _scratch_mount
>
> i=0
> -free_inode=`_get_free_inode $SCRATCH_MNT`
> -file_per_dir=1000
> -loop=$((free_inode / file_per_dir + 1))
> +free_inodes=$(_get_free_inode $SCRATCH_MNT)
> +nr_cpus=$(( $($here/src/feature -o) * 4 * LOAD_FACTOR ))
> +echo "free inodes: $free_inodes nr_cpus: $nr_cpus" >> $seqres.full
> +
> +if ((free_inodes <= nr_cpus)); then
> + nr_cpus=1
> + files_per_dir=$free_inodes
> +else
> + files_per_dir=$(( (free_inodes + nr_cpus - 1) / nr_cpus ))
> +fi
> mkdir -p $SCRATCH_MNT/testdir
>
> echo "Create $((loop * file_per_dir)) files in $SCRATCH_MNT/testdir" >>$seqres.full
> -while [ $i -lt $loop ]; do
> - create_file $SCRATCH_MNT/testdir $file_per_dir $i >>$seqres.full 2>&1 &
> - let i=$i+1
> +for ((i = 0; i < nr_cpus; i++)); do
> + create_file $SCRATCH_MNT/testdir $files_per_dir $i >>$seqres.full 2>&1 &
> done
> wait
>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes
2023-07-14 14:59 [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes Darrick J. Wong
2023-07-14 15:14 ` Bill O'Donnell
@ 2023-07-17 3:03 ` Zorro Lang
2023-07-17 15:27 ` Darrick J. Wong
2023-07-18 1:02 ` Darrick J. Wong
2 siblings, 1 reply; 7+ messages in thread
From: Zorro Lang @ 2023-07-17 3:03 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs, fstests, mpatocka
On Fri, Jul 14, 2023 at 07:59:00AM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> Mikulas reported that this test became a forkbomb on his system when he
> tested it with bcachefs. Unlike XFS and ext4, which have large inodes
> consuming hundreds of bytes, bcachefs has very tiny ones. Therefore, it
> reports a large number of free inodes on a freshly mounted 1GB fs (~15
> million), which causes this test to try to create 15000 processes.
>
> There's really no reason to do that -- all this test wanted to do was to
> exhaust the number of inodes as quickly as possible using all available
> CPUs, and then it ran xfs_repair to try to reproduce a bug. Set the
> number of subshells to 4x the CPU count and spread the work among them
> instead of forking thousands of processes.
>
> Reported-by: Mikulas Patocka <mpatocka@redhat.com>
> Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> Tested-by: Mikulas Patocka <mpatocka@redhat.com>
> ---
> tests/generic/558 | 18 ++++++++++++------
> 1 file changed, 12 insertions(+), 6 deletions(-)
>
> diff --git a/tests/generic/558 b/tests/generic/558
> index 4e22ce656b..de5c28d00d 100755
> --- a/tests/generic/558
> +++ b/tests/generic/558
> @@ -39,15 +39,21 @@ _scratch_mkfs_sized $((1024 * 1024 * 1024)) >>$seqres.full 2>&1
> _scratch_mount
>
> i=0
> -free_inode=`_get_free_inode $SCRATCH_MNT`
> -file_per_dir=1000
> -loop=$((free_inode / file_per_dir + 1))
> +free_inodes=$(_get_free_inode $SCRATCH_MNT)
> +nr_cpus=$(( $($here/src/feature -o) * 4 * LOAD_FACTOR ))
> +echo "free inodes: $free_inodes nr_cpus: $nr_cpus" >> $seqres.full
> +
> +if ((free_inodes <= nr_cpus)); then
> + nr_cpus=1
> + files_per_dir=$free_inodes
> +else
> + files_per_dir=$(( (free_inodes + nr_cpus - 1) / nr_cpus ))
> +fi
> mkdir -p $SCRATCH_MNT/testdir
>
> echo "Create $((loop * file_per_dir)) files in $SCRATCH_MNT/testdir" >>$seqres.full
Has the $loop been removed?
> -while [ $i -lt $loop ]; do
> - create_file $SCRATCH_MNT/testdir $file_per_dir $i >>$seqres.full 2>&1 &
> - let i=$i+1
> +for ((i = 0; i < nr_cpus; i++)); do
> + create_file $SCRATCH_MNT/testdir $files_per_dir $i >>$seqres.full 2>&1 &
> done
> wait
>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes
2023-07-17 3:03 ` Zorro Lang
@ 2023-07-17 15:27 ` Darrick J. Wong
0 siblings, 0 replies; 7+ messages in thread
From: Darrick J. Wong @ 2023-07-17 15:27 UTC (permalink / raw)
To: Zorro Lang; +Cc: linux-xfs, fstests, mpatocka
On Mon, Jul 17, 2023 at 11:03:03AM +0800, Zorro Lang wrote:
> On Fri, Jul 14, 2023 at 07:59:00AM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > Mikulas reported that this test became a forkbomb on his system when he
> > tested it with bcachefs. Unlike XFS and ext4, which have large inodes
> > consuming hundreds of bytes, bcachefs has very tiny ones. Therefore, it
> > reports a large number of free inodes on a freshly mounted 1GB fs (~15
> > million), which causes this test to try to create 15000 processes.
> >
> > There's really no reason to do that -- all this test wanted to do was to
> > exhaust the number of inodes as quickly as possible using all available
> > CPUs, and then it ran xfs_repair to try to reproduce a bug. Set the
> > number of subshells to 4x the CPU count and spread the work among them
> > instead of forking thousands of processes.
> >
> > Reported-by: Mikulas Patocka <mpatocka@redhat.com>
> > Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> > Tested-by: Mikulas Patocka <mpatocka@redhat.com>
> > ---
> > tests/generic/558 | 18 ++++++++++++------
> > 1 file changed, 12 insertions(+), 6 deletions(-)
> >
> > diff --git a/tests/generic/558 b/tests/generic/558
> > index 4e22ce656b..de5c28d00d 100755
> > --- a/tests/generic/558
> > +++ b/tests/generic/558
> > @@ -39,15 +39,21 @@ _scratch_mkfs_sized $((1024 * 1024 * 1024)) >>$seqres.full 2>&1
> > _scratch_mount
> >
> > i=0
> > -free_inode=`_get_free_inode $SCRATCH_MNT`
> > -file_per_dir=1000
> > -loop=$((free_inode / file_per_dir + 1))
> > +free_inodes=$(_get_free_inode $SCRATCH_MNT)
> > +nr_cpus=$(( $($here/src/feature -o) * 4 * LOAD_FACTOR ))
> > +echo "free inodes: $free_inodes nr_cpus: $nr_cpus" >> $seqres.full
> > +
> > +if ((free_inodes <= nr_cpus)); then
> > + nr_cpus=1
> > + files_per_dir=$free_inodes
> > +else
> > + files_per_dir=$(( (free_inodes + nr_cpus - 1) / nr_cpus ))
> > +fi
> > mkdir -p $SCRATCH_MNT/testdir
> >
> > echo "Create $((loop * file_per_dir)) files in $SCRATCH_MNT/testdir" >>$seqres.full
>
> Has the $loop been removed?
DOH. v3 on the way. I hate bash.
--D
> > -while [ $i -lt $loop ]; do
> > - create_file $SCRATCH_MNT/testdir $file_per_dir $i >>$seqres.full 2>&1 &
> > - let i=$i+1
> > +for ((i = 0; i < nr_cpus; i++)); do
> > + create_file $SCRATCH_MNT/testdir $files_per_dir $i >>$seqres.full 2>&1 &
> > done
> > wait
> >
> >
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes
2023-07-14 14:59 [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes Darrick J. Wong
2023-07-14 15:14 ` Bill O'Donnell
2023-07-17 3:03 ` Zorro Lang
@ 2023-07-18 1:02 ` Darrick J. Wong
2 siblings, 0 replies; 7+ messages in thread
From: Darrick J. Wong @ 2023-07-18 1:02 UTC (permalink / raw)
To: zlang; +Cc: linux-xfs, fstests, guan, mpatocka
On Fri, Jul 14, 2023 at 07:59:00AM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> Mikulas reported that this test became a forkbomb on his system when he
> tested it with bcachefs. Unlike XFS and ext4, which have large inodes
> consuming hundreds of bytes, bcachefs has very tiny ones. Therefore, it
> reports a large number of free inodes on a freshly mounted 1GB fs (~15
> million), which causes this test to try to create 15000 processes.
>
> There's really no reason to do that -- all this test wanted to do was to
> exhaust the number of inodes as quickly as possible using all available
> CPUs, and then it ran xfs_repair to try to reproduce a bug. Set the
> number of subshells to 4x the CPU count and spread the work among them
> instead of forking thousands of processes.
>
> Reported-by: Mikulas Patocka <mpatocka@redhat.com>
> Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> Tested-by: Mikulas Patocka <mpatocka@redhat.com>
> ---
> tests/generic/558 | 18 ++++++++++++------
> 1 file changed, 12 insertions(+), 6 deletions(-)
>
> diff --git a/tests/generic/558 b/tests/generic/558
> index 4e22ce656b..de5c28d00d 100755
> --- a/tests/generic/558
> +++ b/tests/generic/558
> @@ -39,15 +39,21 @@ _scratch_mkfs_sized $((1024 * 1024 * 1024)) >>$seqres.full 2>&1
> _scratch_mount
>
> i=0
> -free_inode=`_get_free_inode $SCRATCH_MNT`
> -file_per_dir=1000
> -loop=$((free_inode / file_per_dir + 1))
NAK. Here, the old code effectively does:
loop = howmany(free_inode, 1000);
for i in 0...loop:
create_file ... 1000files... &
IOWs, it rounds the number of files to create up to the nearest 1000,
which I overlooked because I was overloaded and words are easier than
resurrecting mathematical concepts from raw formulae.
If, say, the 1G fs claims to have 524,288 free inodes, the test will
start *525* create_file subshells to create 1000 files each, or 525,000
files.
The /new/ code does this instead:
nr_cpus=(cpu count * 4)
files_per_dir = howmany(free_inodes, nr_cpus)
for i in 0..nr_cpus:
create_file ... files_per_dir... &
If nr_cpu is a factor of free_inodes, we don't do /any/ roundup at all.
524,288 free inodes with 4 CPUs gets you 16 threads and 32768 files per
thread.
Apparently this is significant somehow, because on a lark I decided to
revert the referenced commit and the new code doesn't reliably
reproduce the failure when parent pointers are enabled.
Reintroducing the "rounding free_inodes up to the nearest 1000" does
make it trip, though.
Sooooo... I'll have a new version out tomorrow after some testing.
Please do not apply this patch until then, unless you are testing
bcachefs.
--D
> +free_inodes=$(_get_free_inode $SCRATCH_MNT)
> +nr_cpus=$(( $($here/src/feature -o) * 4 * LOAD_FACTOR ))
> +echo "free inodes: $free_inodes nr_cpus: $nr_cpus" >> $seqres.full
> +
> +if ((free_inodes <= nr_cpus)); then
> + nr_cpus=1
> + files_per_dir=$free_inodes
> +else
> + files_per_dir=$(( (free_inodes + nr_cpus - 1) / nr_cpus ))
> +fi
> mkdir -p $SCRATCH_MNT/testdir
>
> echo "Create $((loop * file_per_dir)) files in $SCRATCH_MNT/testdir" >>$seqres.full
> -while [ $i -lt $loop ]; do
> - create_file $SCRATCH_MNT/testdir $file_per_dir $i >>$seqres.full 2>&1 &
> - let i=$i+1
> +for ((i = 0; i < nr_cpus; i++)); do
> + create_file $SCRATCH_MNT/testdir $files_per_dir $i >>$seqres.full 2>&1 &
> done
> wait
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH] xfs: add a couple more tests for ascii-ci problems
@ 2023-07-11 20:25 Darrick J. Wong
2023-07-14 14:56 ` [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes Darrick J. Wong
0 siblings, 1 reply; 7+ messages in thread
From: Darrick J. Wong @ 2023-07-11 20:25 UTC (permalink / raw)
To: zlang; +Cc: linux-xfs, fstests, guan
From: Darrick J. Wong <djwong@kernel.org>
Add some tests to make sure that userspace and the kernel actually
agree on how to do ascii case-insensitive directory lookups, and that
metadump can actually obfuscate such filesystems.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
tests/xfs/859 | 64 ++++++++++++++++++++++++++++++++++
tests/xfs/859.out | 24 +++++++++++++
tests/xfs/860 | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++
tests/xfs/860.out | 9 +++++
tests/xfs/861 | 90 ++++++++++++++++++++++++++++++++++++++++++++++++
tests/xfs/861.out | 2 +
6 files changed, 289 insertions(+)
create mode 100755 tests/xfs/859
create mode 100644 tests/xfs/859.out
create mode 100755 tests/xfs/860
create mode 100644 tests/xfs/860.out
create mode 100755 tests/xfs/861
create mode 100644 tests/xfs/861.out
diff --git a/tests/xfs/859 b/tests/xfs/859
new file mode 100755
index 0000000000..e99619c12f
--- /dev/null
+++ b/tests/xfs/859
@@ -0,0 +1,64 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023 Oracle. All Rights Reserved.
+#
+# FS QA Test 859
+#
+# Make sure that the kernel and userspace agree on which byte sequences are
+# ASCII uppercase letters, and how to convert them.
+#
+. ./common/preamble
+_begin_fstest auto ci dir
+
+# Override the default cleanup function.
+# _cleanup()
+# {
+# cd /
+# rm -r -f $tmp.*
+# }
+
+# Import common functions.
+. ./common/filter
+
+_fixed_by_kernel_commit a9248538facc "xfs: stabilize the dirent name transformation function used for ascii-ci dir hash computation"
+_fixed_by_kernel_commit 9dceccc5822f "xfs: use the directory name hash function for dir scrubbing"
+
+_supported_fs xfs
+_require_scratch
+_require_xfs_mkfs_ciname
+
+_scratch_mkfs -n version=ci > $seqres.full
+_scratch_mount
+
+# Create a two-block directory to force leaf format
+mkdir "$SCRATCH_MNT/lol"
+touch "$SCRATCH_MNT/lol/autoexec.bat"
+i=0
+dblksz=$(_xfs_get_dir_blocksize "$SCRATCH_MNT")
+nr_dirents=$((dblksz * 2 / 256))
+
+for ((i = 0; i < nr_dirents; i++)); do
+ name="$(printf "y%0254d" $i)"
+ ln "$SCRATCH_MNT/lol/autoexec.bat" "$SCRATCH_MNT/lol/$name"
+done
+
+dirsz=$(stat -c '%s' $SCRATCH_MNT/lol)
+test $dirsz -gt $dblksz || echo "dir size $dirsz, expected at least $dblksz?"
+stat $SCRATCH_MNT/lol >> $seqres.full
+
+# Create names with extended ascii characters in them to exploit the fact
+# that the Linux kernel will transform extended ASCII uppercase characters
+# but libc won't. Need to force LANG=C here so that awk doesn't spit out utf8
+# sequences.
+old_lang="$LANG"
+LANG=C
+awk 'END { for (i = 192; i < 247; i++) printf("%c\n", i); }' < /dev/null | while read name; do
+ ln "$SCRATCH_MNT/lol/autoexec.bat" "$SCRATCH_MNT/lol/$name" 2>&1 | _filter_scratch
+done
+
+LANG=$old_lang
+
+# Now just let repair run
+
+status=0
+exit
diff --git a/tests/xfs/859.out b/tests/xfs/859.out
new file mode 100644
index 0000000000..a4939ba670
--- /dev/null
+++ b/tests/xfs/859.out
@@ -0,0 +1,24 @@
+QA output created by 859
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\340': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\341': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\342': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\343': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\344': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\345': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\346': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\347': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\350': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\351': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\352': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\353': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\354': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\355': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\356': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\357': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\360': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\361': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\362': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\363': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\364': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\365': File exists
+ln: failed to create hard link 'SCRATCH_MNT/lol/'$'\366': File exists
diff --git a/tests/xfs/860 b/tests/xfs/860
new file mode 100755
index 0000000000..42f16efe6c
--- /dev/null
+++ b/tests/xfs/860
@@ -0,0 +1,100 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023 Oracle. All Rights Reserved.
+#
+# FS QA Test 860
+#
+# Make sure that metadump obfuscation works for filesystems with ascii-ci
+# enabled.
+#
+. ./common/preamble
+_begin_fstest auto dir ci
+
+_cleanup()
+{
+ cd /
+ rm -r -f $tmp.* $testdir
+}
+
+_fixed_by_git_commit xfsprogs 10a01bcd "xfs_db: fix metadump name obfuscation for ascii-ci filesystems"
+
+_supported_fs xfs
+_require_test
+_require_scratch
+_require_xfs_mkfs_ciname
+
+_scratch_mkfs -n version=ci > $seqres.full
+_scratch_mount
+
+# Create a two-block directory to force leaf format
+mkdir "$SCRATCH_MNT/lol"
+touch "$SCRATCH_MNT/lol/autoexec.bat"
+i=0
+dblksz=$(_xfs_get_dir_blocksize "$SCRATCH_MNT")
+nr_dirents=$((dblksz * 2 / 256))
+
+for ((i = 0; i < nr_dirents; i++)); do
+ name="$(printf "y%0254d" $i)"
+ ln "$SCRATCH_MNT/lol/autoexec.bat" "$SCRATCH_MNT/lol/$name"
+done
+
+dirsz=$(stat -c '%s' $SCRATCH_MNT/lol)
+test $dirsz -gt $dblksz || echo "dir size $dirsz, expected at least $dblksz?"
+stat $SCRATCH_MNT/lol >> $seqres.full
+
+# Create a two-block attr to force leaf format
+i=0
+for ((i = 0; i < nr_dirents; i++)); do
+ name="$(printf "user.%0250d" $i)"
+ $SETFATTR_PROG -n "$name" -v 1 "$SCRATCH_MNT/lol/autoexec.bat"
+done
+stat $SCRATCH_MNT/lol/autoexec.bat >> $seqres.full
+
+_scratch_unmount
+
+testdir=$TEST_DIR/$seq.metadumps
+mkdir -p $testdir
+metadump_file=$testdir/scratch.md
+metadump_file_a=${metadump_file}.a
+metadump_file_o=${metadump_file}.o
+metadump_file_ao=${metadump_file}.ao
+
+echo metadump
+_scratch_xfs_metadump $metadump_file >> $seqres.full
+
+echo metadump a
+_scratch_xfs_metadump $metadump_file_a -a >> $seqres.full
+
+echo metadump o
+_scratch_xfs_metadump $metadump_file_o -o >> $seqres.full
+
+echo metadump ao
+_scratch_xfs_metadump $metadump_file_ao -a -o >> $seqres.full
+
+echo mdrestore
+_scratch_xfs_mdrestore $metadump_file
+_scratch_mount
+_check_scratch_fs
+_scratch_unmount
+
+echo mdrestore a
+_scratch_xfs_mdrestore $metadump_file_a
+_scratch_mount
+_check_scratch_fs
+_scratch_unmount
+
+echo mdrestore o
+_scratch_xfs_mdrestore $metadump_file_o
+_scratch_mount
+_check_scratch_fs
+_scratch_unmount
+
+echo mdrestore ao
+_scratch_xfs_mdrestore $metadump_file_ao
+_scratch_mount
+_check_scratch_fs
+_scratch_unmount
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/860.out b/tests/xfs/860.out
new file mode 100644
index 0000000000..136fc5f7d6
--- /dev/null
+++ b/tests/xfs/860.out
@@ -0,0 +1,9 @@
+QA output created by 860
+metadump
+metadump a
+metadump o
+metadump ao
+mdrestore
+mdrestore a
+mdrestore o
+mdrestore ao
diff --git a/tests/xfs/861 b/tests/xfs/861
new file mode 100755
index 0000000000..7b0a37a3f1
--- /dev/null
+++ b/tests/xfs/861
@@ -0,0 +1,90 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023 Oracle. All Rights Reserved.
+#
+# FS QA Test 861
+#
+# Make sure that the kernel and utilities can handle large numbers of dirhash
+# collisions in both the directory and extended attribute structures.
+#
+# This started as a regression test for the new 'hashcoll' function in xfs_db,
+# but became a regression test for an xfs_repair bug affecting hashval checks
+# applied to the second and higher node levels of a dabtree.
+#
+. ./common/preamble
+_begin_fstest auto dir
+
+_fixed_by_git_commit xfsprogs b7b81f336ac "xfs_repair: fix incorrect dabtree hashval comparison"
+
+_supported_fs xfs
+_require_xfs_db_command "hashcoll"
+_require_xfs_db_command "path"
+_require_scratch
+
+_scratch_mkfs > $seqres.full
+_scratch_mount
+
+crash_dir=$SCRATCH_MNT/lol/
+crash_attrs=$SCRATCH_MNT/hah
+
+mkdir -p "$crash_dir"
+touch "$crash_attrs"
+
+# Create enough dirents to fill two dabtree node blocks with names that all
+# hash to the same value. Each dirent gets its own record in the dabtree,
+# so we must create enough dirents to get a dabtree of at least height 2.
+dblksz=$(_xfs_get_dir_blocksize "$SCRATCH_MNT")
+
+da_records_per_block=$((dblksz / 8)) # 32-bit hash and 32-bit before
+nr_dirents=$((da_records_per_block * 2))
+
+longname="$(mktemp --dry-run "$(perl -e 'print "X" x 255;')" | tr ' ' 'X')"
+echo "creating $nr_dirents dirents from '$longname'" >> $seqres.full
+_scratch_xfs_db -r -c "hashcoll -n $nr_dirents -p $crash_dir $longname"
+
+# Create enough xattrs to fill two dabtree nodes. Each attribute leaf block
+# gets its own record in the dabtree, so we have to create enough attr blocks
+# (each full of attrs) to get a dabtree of at least height 2.
+blksz=$(_get_block_size "$SCRATCH_MNT")
+
+attr_records_per_block=$((blksz / 255))
+da_records_per_block=$((blksz / 8)) # 32-bit hash and 32-bit before
+nr_attrs=$((da_records_per_block * attr_records_per_block * 2))
+
+longname="$(mktemp --dry-run "$(perl -e 'print "X" x 249;')" | tr ' ' 'X')"
+echo "creating $nr_attrs attrs from '$longname'" >> $seqres.full
+_scratch_xfs_db -r -c "hashcoll -a -n $nr_attrs -p $crash_attrs $longname"
+
+_scratch_unmount
+
+# Make sure that there's one hash value dominating the dabtree block.
+# We don't require 100% because directories create dabtree records for dot
+# and dotdot.
+filter_hashvals() {
+ uniq -c | awk -v seqres_full="$seqres.full" \
+ '{print $0 >> seqres_full; tot += $1; if ($1 > biggest) biggest = $1;} END {if (biggest >= (tot - 2)) exit(0); exit(1);}'
+ test "${PIPESTATUS[1]}" -eq 0 || \
+ echo "Scattered dabtree hashes? See seqres.full"
+}
+
+# Did we actually get a two-level dabtree for the directory? Does it contain a
+# long run of hashes?
+echo "dir check" >> $seqres.full
+da_node_block_offset=$(( (2 ** 35) / blksz ))
+dir_db_args=(-c 'path /lol/' -c "dblock $da_node_block_offset" -c 'addr nbtree[0].before')
+dir_count="$(_scratch_xfs_db "${dir_db_args[@]}" -c 'print lhdr.count' | awk '{print $3}')"
+_scratch_xfs_db "${dir_db_args[@]}" -c "print lents[0-$((dir_count - 1))].hashval" | sed -e 's/lents\[[0-9]*\]/lents[NN]/g' | filter_hashvals
+
+# Did we actually get a two-level dabtree for the attrs? Does it contain a
+# long run of hashes?
+echo "attr check" >> $seqres.full
+attr_db_args=(-c 'path /hah' -c "ablock 0" -c 'addr btree[0].before')
+attr_count="$(_scratch_xfs_db "${attr_db_args[@]}" -c 'print hdr.count' | awk '{print $3}')"
+_scratch_xfs_db "${attr_db_args[@]}" -c "print btree[0-$((attr_count - 1))].hashval" | sed -e 's/btree\[[0-9]*\]/btree[NN]/g' | filter_hashvals
+
+# Remount to get some coverage of xfs_scrub before seeing if xfs_repair
+# will trip over the large dabtrees.
+echo Silence is golden
+_scratch_mount
+status=0
+exit
diff --git a/tests/xfs/861.out b/tests/xfs/861.out
new file mode 100644
index 0000000000..d11b76c82e
--- /dev/null
+++ b/tests/xfs/861.out
@@ -0,0 +1,2 @@
+QA output created by 861
+Silence is golden
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes
2023-07-11 20:25 [PATCH] xfs: add a couple more tests for ascii-ci problems Darrick J. Wong
@ 2023-07-14 14:56 ` Darrick J. Wong
2023-07-14 14:58 ` Darrick J. Wong
0 siblings, 1 reply; 7+ messages in thread
From: Darrick J. Wong @ 2023-07-14 14:56 UTC (permalink / raw)
To: zlang; +Cc: linux-xfs, fstests, guan, mpatocka
From: Darrick J. Wong <djwong@kernel.org>
Mikulas reported that this test became a forkbomb on his system when he
tested it with bcachefs. Unlike XFS and ext4, which have large inodes
consuming hundreds of bytes, bcachefs has very tiny ones. Therefore, it
reports a large number of free inodes on a freshly mounted 1GB fs (~15
million), which causes this test to try to create 15000 processes.
There's really no reason to do that -- all this test wanted to do was to
exhaust the number of inodes as quickly as possible using all available
CPUs, and then it ran xfs_repair to try to reproduce a bug. Set the
number of subshells to 4x the CPU count and spread the work among
them instead of forking thousands of processes.
Reported-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Tested-by: Mikulas Patocka <mpatocka@redhat.com>
---
tests/generic/558 | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/tests/generic/558 b/tests/generic/558
index 4e22ce656b..de5c28d00d 100755
--- a/tests/generic/558
+++ b/tests/generic/558
@@ -39,15 +39,21 @@ _scratch_mkfs_sized $((1024 * 1024 * 1024)) >>$seqres.full 2>&1
_scratch_mount
i=0
-free_inode=`_get_free_inode $SCRATCH_MNT`
-file_per_dir=1000
-loop=$((free_inode / file_per_dir + 1))
+free_inodes=$(_get_free_inode $SCRATCH_MNT)
+nr_cpus=$(( $($here/src/feature -o) * 4 * LOAD_FACTOR ))
+echo "free inodes: $free_inodes nr_cpus: $nr_cpus" >> $seqres.full
+
+if ((free_inodes <= nr_cpus)); then
+ nr_cpus=1
+ files_per_dir=$free_inodes
+else
+ files_per_dir=$(( (free_inodes + nr_cpus - 1) / nr_cpus ))
+fi
mkdir -p $SCRATCH_MNT/testdir
echo "Create $((loop * file_per_dir)) files in $SCRATCH_MNT/testdir" >>$seqres.full
-while [ $i -lt $loop ]; do
- create_file $SCRATCH_MNT/testdir $file_per_dir $i >>$seqres.full 2>&1 &
- let i=$i+1
+for ((i = 0; i < nr_cpus; i++)); do
+ create_file $SCRATCH_MNT/testdir $files_per_dir $i >>$seqres.full 2>&1 &
done
wait
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes
2023-07-14 14:56 ` [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes Darrick J. Wong
@ 2023-07-14 14:58 ` Darrick J. Wong
0 siblings, 0 replies; 7+ messages in thread
From: Darrick J. Wong @ 2023-07-14 14:58 UTC (permalink / raw)
To: zlang; +Cc: linux-xfs, fstests, guan, mpatocka
Ooops, I mistakenly sent this as a reply, will try again.
--D
On Fri, Jul 14, 2023 at 07:56:06AM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> Mikulas reported that this test became a forkbomb on his system when he
> tested it with bcachefs. Unlike XFS and ext4, which have large inodes
> consuming hundreds of bytes, bcachefs has very tiny ones. Therefore, it
> reports a large number of free inodes on a freshly mounted 1GB fs (~15
> million), which causes this test to try to create 15000 processes.
>
> There's really no reason to do that -- all this test wanted to do was to
> exhaust the number of inodes as quickly as possible using all available
> CPUs, and then it ran xfs_repair to try to reproduce a bug. Set the
> number of subshells to 4x the CPU count and spread the work among
> them instead of forking thousands of processes.
>
> Reported-by: Mikulas Patocka <mpatocka@redhat.com>
> Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> Tested-by: Mikulas Patocka <mpatocka@redhat.com>
> ---
> tests/generic/558 | 18 ++++++++++++------
> 1 file changed, 12 insertions(+), 6 deletions(-)
>
> diff --git a/tests/generic/558 b/tests/generic/558
> index 4e22ce656b..de5c28d00d 100755
> --- a/tests/generic/558
> +++ b/tests/generic/558
> @@ -39,15 +39,21 @@ _scratch_mkfs_sized $((1024 * 1024 * 1024)) >>$seqres.full 2>&1
> _scratch_mount
>
> i=0
> -free_inode=`_get_free_inode $SCRATCH_MNT`
> -file_per_dir=1000
> -loop=$((free_inode / file_per_dir + 1))
> +free_inodes=$(_get_free_inode $SCRATCH_MNT)
> +nr_cpus=$(( $($here/src/feature -o) * 4 * LOAD_FACTOR ))
> +echo "free inodes: $free_inodes nr_cpus: $nr_cpus" >> $seqres.full
> +
> +if ((free_inodes <= nr_cpus)); then
> + nr_cpus=1
> + files_per_dir=$free_inodes
> +else
> + files_per_dir=$(( (free_inodes + nr_cpus - 1) / nr_cpus ))
> +fi
> mkdir -p $SCRATCH_MNT/testdir
>
> echo "Create $((loop * file_per_dir)) files in $SCRATCH_MNT/testdir" >>$seqres.full
> -while [ $i -lt $loop ]; do
> - create_file $SCRATCH_MNT/testdir $file_per_dir $i >>$seqres.full 2>&1 &
> - let i=$i+1
> +for ((i = 0; i < nr_cpus; i++)); do
> + create_file $SCRATCH_MNT/testdir $files_per_dir $i >>$seqres.full 2>&1 &
> done
> wait
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2023-07-18 1:02 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-07-14 14:59 [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes Darrick J. Wong
2023-07-14 15:14 ` Bill O'Donnell
2023-07-17 3:03 ` Zorro Lang
2023-07-17 15:27 ` Darrick J. Wong
2023-07-18 1:02 ` Darrick J. Wong
-- strict thread matches above, loose matches on Subject: below --
2023-07-11 20:25 [PATCH] xfs: add a couple more tests for ascii-ci problems Darrick J. Wong
2023-07-14 14:56 ` [PATCH] generic/558: avoid forkbombs on filesystems with many free inodes Darrick J. Wong
2023-07-14 14:58 ` Darrick J. Wong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox