Re: [PATCH] generic: test overwriting file with mmap on a full filesystem

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]



On Thu, Jul 10, 2025 at 5:08 PM Zorro Lang <zlang@xxxxxxxxxx> wrote:
>
> On Thu, Jul 10, 2025 at 12:47:30PM +0100, Filipe Manana wrote:
> > On Thu, Jul 10, 2025 at 8:29 AM Zorro Lang <zlang@xxxxxxxxxx> wrote:
> > >
> > > On Wed, Jul 09, 2025 at 09:53:50AM +0100, fdmanana@xxxxxxxxxx wrote:
> > > > From: Filipe Manana <fdmanana@xxxxxxxx>
> > > >
> > > > Test that overwriting a file with mmap when the filesystem has no more
> > > > space available for data allocation works. The motivation here is to check
> > > > that NOCOW mode of a COW filesystem (such as btrfs) works as expected.
> > > >
> > > > This currently fails with btrfs but it's fixed by a kernel patch that has
> > > > the subject:
> > > >
> > > >    btrfs: fix -ENOSPC mmap write failure on NOCOW files/extents
> > > >
> > > > Signed-off-by: Filipe Manana <fdmanana@xxxxxxxx>
> > > > ---
> > > >  tests/generic/211     | 58 +++++++++++++++++++++++++++++++++++++++++++
> > > >  tests/generic/211.out |  6 +++++
> > > >  2 files changed, 64 insertions(+)
> > > >  create mode 100755 tests/generic/211
> > > >  create mode 100644 tests/generic/211.out
> > > >
> > > > diff --git a/tests/generic/211 b/tests/generic/211
> > > > new file mode 100755
> > > > index 00000000..c77508fe
> > > > --- /dev/null
> > > > +++ b/tests/generic/211
> > > > @@ -0,0 +1,58 @@
> > > > +#! /bin/bash
> > > > +# SPDX-License-Identifier: GPL-2.0
> > > > +# Copyright (c) 2025 SUSE Linux Products GmbH.  All Rights Reserved.
> > > > +#
> > > > +# FS QA Test 211
> > > > +#
> > > > +# Test that overwriting a file with mmap when the filesystem has no more space
> > > > +# available for data allocation works. The motivation here is to check that
> > > > +# NOCOW mode of a COW filesystem (such as btrfs) works as expected.
> > > > +#
> > > > +. ./common/preamble
> > > > +_begin_fstest auto quick rw mmap
> > > > +
> > > > +. ./common/filter
> > > > +
> > > > +_require_scratch
> > > > +
> > > > +[ "$FSTYP" = "btrfs" ] && _fixed_by_kernel_commit xxxxxxxxxxxx \
> > > > +     "btrfs: fix -ENOSPC mmap write failure on NOCOW files/extents"
> > > > +
> > > > +# Use a 512M fs so that it's fast to fill it with data but not too small such
> > > > +# that on btrfs it results in a fs with mixed block groups - we want to have
> > > > +# dedicated block groups for data and metadata, so that after filling all the
> > > > +# data block groups we can do a NOCOW write with mmap (if we have enough free
> > > > +# metadata space available).
> > > > +fs_size=$(_small_fs_size_mb 512)
> > > > +_scratch_mkfs_sized $((fs_size * 1024 * 1024)) >>$seqres.full 2>&1 || \
> > > > +     _fail "mkfs failed"
> > >
> > > _scratch_mkfs_sized calls _notrun if it fails:
> > >
> > >   _scratch_mkfs_sized()
> > >   {
> > >         _try_scratch_mkfs_sized "$@" || _notrun "_scratch_mkfs_sized failed with ($*)"
> > >   }
> > >
> > > So you can let it _notrun:
> > > _scratch_mkfs_sized $((fs_size * 1024 * 1024)) >>$seqres.full 2>&1
> > >
> > > or you'd like to _fail:
> > >
> > > _try_scratch_mkfs_sized $((fs_size * 1024 * 1024)) >>$seqres.full 2>&1 || \
> > >          _fail "mkfs failed"
> >
> > The fail makes more sense to me - having the _scratch_mkfs_sized()
> > calling _notrun doesn't make sense to me at the moment.
>
> OK, so you can use _try_scratch_mkfs_sized.
>
> >
> > >
> > > > +_scratch_mount
> > > > +
> > > > +touch $SCRATCH_MNT/foobar
> > > > +
> > > > +# Set the file to NOCOW mode on btrfs, which must be done while the file is
> > > > +# empty, otherwise it fails.
> > > > +if [ $FSTYP == "btrfs" ]; then
> > > > +     _require_chattr C
> > > > +     $CHATTR_PROG +C $SCRATCH_MNT/foobar
> > > > +fi
> > > > +
> > > > +# Add initial data to the file we will later overwrite with mmap.
> > > > +$XFS_IO_PROG -c "pwrite -S 0xab 0 1M" $SCRATCH_MNT/foobar | _filter_xfs_io
> > > > +
> > > > +# Now fill all the remaining space with data.
> > > > +blksz=$(_get_block_size $SCRATCH_MNT)
> > > > +dd if=/dev/zero of=$SCRATCH_MNT/filler bs=$blksz >>$seqres.full 2>&1
> > >
> > > As this's a generic test case, I'm wondering if the common/populate:_fill_fs()
> > > helps?
> >
> > Because the intention is to exhaust data space and leave enough
> > metadata space free so that the NOCOW write can be done, as Qu already
> > replied before.
> > In btrfs we have space divided in two sections (block groups): one for
> > data and one for metadata.
> > Metadata is always COWed in btrfs by design, data can be NOCOWed
> > (chattr +C or prealloc extents for the first write) - as longs as
> > there's enough metadata space available (every data write requires
> > updating some metadata).
> >
> > If this is too specific or hard to comprehend, I can move the test
> > case into tests/btrfs/ (we have a few similar to this scenario iirc).
> > Let me know if I shall move it into tests/btrfs/.
>
> Thanks for the detailed explanation from you and Qu:) If so, maybe
> _get_file_block_size better than _get_block_size?
>
> I think we can keep this case in generic directory, it's a btrfs bug reproducer
> and it won't break other fs test. If someone fs hopes to change that "fill fs"
> part, we can use if...else... so maybe you can add more comments about why btrfs
> need this dd operation rather than _fill_fs things, to avoid others change this
> part in the future.

Ok, I'll update the comment above dd to be more detailed, about why dd
and not __populate_fill_fs().

Thanks.
>
> Thanks,
> Zorro
>
> >
> > Thanks.
> >
> > >
> > > Thanks,
> > > Zorro
> > >
> > > > +
> > > > +# Overwrite the file with a mmap write. Should succeed.
> > > > +$XFS_IO_PROG -c "mmap -w 0 1M"        \
> > > > +          -c "mwrite -S 0xcd 0 1M" \
> > > > +          -c "munmap"              \
> > > > +          $SCRATCH_MNT/foobar
> > > > +
> > > > +# Cycle mount and dump the file's content. We expect to see the new data.
> > > > +_scratch_cycle_mount
> > > > +_hexdump $SCRATCH_MNT/foobar
> > > > +
> > > > +# success, all done
> > > > +_exit 0
> > > > diff --git a/tests/generic/211.out b/tests/generic/211.out
> > > > new file mode 100644
> > > > index 00000000..71cdf0f8
> > > > --- /dev/null
> > > > +++ b/tests/generic/211.out
> > > > @@ -0,0 +1,6 @@
> > > > +QA output created by 211
> > > > +wrote 1048576/1048576 bytes at offset 0
> > > > +XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
> > > > +000000 cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd  >................<
> > > > +*
> > > > +100000
> > > > --
> > > > 2.47.2
> > > >
> > > >
> > >
> >
>





[Index of Archives]     [Linux Filesystems Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux