All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHSET 0/2] xfs: realtime allocator fixes
@ 2021-05-03 21:34 Darrick J. Wong
  2021-05-03 21:34 ` [PATCH 1/2] xfs: adjust rt allocation minlen when extszhint > rtextsize Darrick J. Wong
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Darrick J. Wong @ 2021-05-03 21:34 UTC (permalink / raw)
  To: djwong; +Cc: linux-xfs

Hi all,

This series contains two fixes for bugs I saw in the realtime allocator.

This is an extraordinary way to destroy everything.  Enjoy!
Comments and questions are, as always, welcome.

--D
---
 fs/xfs/xfs_bmap_util.c |   96 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 70 insertions(+), 26 deletions(-)


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] xfs: adjust rt allocation minlen when extszhint > rtextsize
  2021-05-03 21:34 [PATCHSET 0/2] xfs: realtime allocator fixes Darrick J. Wong
@ 2021-05-03 21:34 ` Darrick J. Wong
  2021-05-06  5:26   ` Allison Henderson
  2021-05-03 21:34 ` [PATCH 2/2] xfs: retry allocations when locality-based search fails Darrick J. Wong
  2021-05-03 21:35 ` [PATCH] xfs: test fsx with extent size hints set on a realtime file Darrick J. Wong
  2 siblings, 1 reply; 6+ messages in thread
From: Darrick J. Wong @ 2021-05-03 21:34 UTC (permalink / raw)
  To: djwong; +Cc: linux-xfs

From: Darrick J. Wong <djwong@kernel.org>

xfs_bmap_rtalloc doesn't handle realtime extent files with extent size
hints larger than the rt volume's extent size properly, because
xfs_bmap_extsize_align can adjust the offset/length parameters to try to
fit the extent size hint.

Under these conditions, minlen has to be large enough so that any
allocation returned by xfs_rtallocate_extent will be large enough to
cover at least one of the blocks that the caller asked for.  If the
allocation is too short, bmapi_write will return no mapping for the
requested range, which causes ENOSPC errors in other parts of the
filesystem.

Therefore, adjust minlen upwards to fix this.  This can be found by
running generic/263 (g/127 or g/522) with a realtime extent size hint
that's larger than the rt volume extent size.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/xfs_bmap_util.c |   81 +++++++++++++++++++++++++++++++++---------------
 1 file changed, 56 insertions(+), 25 deletions(-)


diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index a5e9d7d34023..c9381bf4f04b 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -71,18 +71,23 @@ xfs_zero_extent(
 #ifdef CONFIG_XFS_RT
 int
 xfs_bmap_rtalloc(
-	struct xfs_bmalloca	*ap)	/* bmap alloc argument struct */
+	struct xfs_bmalloca	*ap)
 {
-	int		error;		/* error return value */
-	xfs_mount_t	*mp;		/* mount point structure */
-	xfs_extlen_t	prod = 0;	/* product factor for allocators */
-	xfs_extlen_t	mod = 0;	/* product factor for allocators */
-	xfs_extlen_t	ralen = 0;	/* realtime allocation length */
-	xfs_extlen_t	align;		/* minimum allocation alignment */
-	xfs_rtblock_t	rtb;
+	struct xfs_mount	*mp = ap->ip->i_mount;
+	xfs_fileoff_t		orig_offset = ap->offset;
+	xfs_rtblock_t		rtb;
+	xfs_extlen_t		prod = 0;  /* product factor for allocators */
+	xfs_extlen_t		mod = 0;   /* product factor for allocators */
+	xfs_extlen_t		ralen = 0; /* realtime allocation length */
+	xfs_extlen_t		align;     /* minimum allocation alignment */
+	xfs_extlen_t		orig_length = ap->length;
+	xfs_extlen_t		minlen = mp->m_sb.sb_rextsize;
+	xfs_extlen_t		raminlen;
+	bool			rtlocked = false;
+	int			error;
 
-	mp = ap->ip->i_mount;
 	align = xfs_get_extsz_hint(ap->ip);
+retry:
 	prod = align / mp->m_sb.sb_rextsize;
 	error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev,
 					align, 1, ap->eof, 0,
@@ -92,6 +97,15 @@ xfs_bmap_rtalloc(
 	ASSERT(ap->length);
 	ASSERT(ap->length % mp->m_sb.sb_rextsize == 0);
 
+	/*
+	 * If we shifted the file offset downward to satisfy an extent size
+	 * hint, increase minlen by that amount so that the allocator won't
+	 * give us an allocation that's too short to cover at least one of the
+	 * blocks that the caller asked for.
+	 */
+	if (ap->offset != orig_offset)
+		minlen += orig_offset - ap->offset;
+
 	/*
 	 * If the offset & length are not perfectly aligned
 	 * then kill prod, it will just get us in trouble.
@@ -116,10 +130,13 @@ xfs_bmap_rtalloc(
 	/*
 	 * Lock out modifications to both the RT bitmap and summary inodes
 	 */
-	xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL|XFS_ILOCK_RTBITMAP);
-	xfs_trans_ijoin(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
-	xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL|XFS_ILOCK_RTSUM);
-	xfs_trans_ijoin(ap->tp, mp->m_rsumip, XFS_ILOCK_EXCL);
+	if (!rtlocked) {
+		xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL|XFS_ILOCK_RTBITMAP);
+		xfs_trans_ijoin(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
+		xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL|XFS_ILOCK_RTSUM);
+		xfs_trans_ijoin(ap->tp, mp->m_rsumip, XFS_ILOCK_EXCL);
+		rtlocked = true;
+	}
 
 	/*
 	 * If it's an allocation to an empty file at offset 0,
@@ -144,30 +161,44 @@ xfs_bmap_rtalloc(
 	do_div(ap->blkno, mp->m_sb.sb_rextsize);
 	rtb = ap->blkno;
 	ap->length = ralen;
-	error = xfs_rtallocate_extent(ap->tp, ap->blkno, 1, ap->length,
-				&ralen, ap->wasdel, prod, &rtb);
+	raminlen = max_t(xfs_extlen_t, 1, minlen / mp->m_sb.sb_rextsize);
+	error = xfs_rtallocate_extent(ap->tp, ap->blkno, raminlen, ap->length,
+			&ralen, ap->wasdel, prod, &rtb);
 	if (error)
 		return error;
 
-	ap->blkno = rtb;
-	if (ap->blkno != NULLFSBLOCK) {
-		ap->blkno *= mp->m_sb.sb_rextsize;
-		ralen *= mp->m_sb.sb_rextsize;
-		ap->length = ralen;
-		ap->ip->i_nblocks += ralen;
+	if (rtb != NULLRTBLOCK) {
+		ap->blkno = rtb * mp->m_sb.sb_rextsize;
+		ap->length = ralen * mp->m_sb.sb_rextsize;
+		ap->ip->i_nblocks += ap->length;
 		xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
 		if (ap->wasdel)
-			ap->ip->i_delayed_blks -= ralen;
+			ap->ip->i_delayed_blks -= ap->length;
 		/*
 		 * Adjust the disk quota also. This was reserved
 		 * earlier.
 		 */
 		xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
 			ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
-					XFS_TRANS_DQ_RTBCOUNT, (long) ralen);
-	} else {
-		ap->length = 0;
+					XFS_TRANS_DQ_RTBCOUNT, ap->length);
+		return 0;
 	}
+
+	if (align > mp->m_sb.sb_rextsize) {
+		/*
+		 * We previously enlarged the request length to try to satisfy
+		 * an extent size hint.  The allocator didn't return anything,
+		 * so reset the parameters to the original values and try again
+		 * without alignment criteria.
+		 */
+		ap->offset = orig_offset;
+		ap->length = orig_length;
+		minlen = align = mp->m_sb.sb_rextsize;
+		goto retry;
+	}
+
+	ap->blkno = NULLFSBLOCK;
+	ap->length = 0;
 	return 0;
 }
 #endif /* CONFIG_XFS_RT */


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] xfs: retry allocations when locality-based search fails
  2021-05-03 21:34 [PATCHSET 0/2] xfs: realtime allocator fixes Darrick J. Wong
  2021-05-03 21:34 ` [PATCH 1/2] xfs: adjust rt allocation minlen when extszhint > rtextsize Darrick J. Wong
@ 2021-05-03 21:34 ` Darrick J. Wong
  2021-05-06  5:26   ` Allison Henderson
  2021-05-03 21:35 ` [PATCH] xfs: test fsx with extent size hints set on a realtime file Darrick J. Wong
  2 siblings, 1 reply; 6+ messages in thread
From: Darrick J. Wong @ 2021-05-03 21:34 UTC (permalink / raw)
  To: djwong; +Cc: linux-xfs

From: Darrick J. Wong <djwong@kernel.org>

If a realtime allocation fails because we can't find a sufficiently
large free extent satisfying locality rules, relax the locality rules
and try again.  This reduces the occurrence of short writes to realtime
files when the write size is large and the free space is fragmented.

This was originally discovered by running generic/186 with the realtime
reflink patchset and a 128k cow extent size hint, but the same problem
can manifest with a 128k extent size hint, so applies the fix now.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/xfs_bmap_util.c |   15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)


diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index c9381bf4f04b..0936f3a96fe6 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -84,6 +84,7 @@ xfs_bmap_rtalloc(
 	xfs_extlen_t		minlen = mp->m_sb.sb_rextsize;
 	xfs_extlen_t		raminlen;
 	bool			rtlocked = false;
+	bool			ignore_locality = false;
 	int			error;
 
 	align = xfs_get_extsz_hint(ap->ip);
@@ -158,7 +159,10 @@ xfs_bmap_rtalloc(
 	/*
 	 * Realtime allocation, done through xfs_rtallocate_extent.
 	 */
-	do_div(ap->blkno, mp->m_sb.sb_rextsize);
+	if (ignore_locality)
+		ap->blkno = 0;
+	else
+		do_div(ap->blkno, mp->m_sb.sb_rextsize);
 	rtb = ap->blkno;
 	ap->length = ralen;
 	raminlen = max_t(xfs_extlen_t, 1, minlen / mp->m_sb.sb_rextsize);
@@ -197,6 +201,15 @@ xfs_bmap_rtalloc(
 		goto retry;
 	}
 
+	if (!ignore_locality && ap->blkno != 0) {
+		/*
+		 * If we can't allocate near a specific rt extent, try again
+		 * without locality criteria.
+		 */
+		ignore_locality = true;
+		goto retry;
+	}
+
 	ap->blkno = NULLFSBLOCK;
 	ap->length = 0;
 	return 0;


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH] xfs: test fsx with extent size hints set on a realtime file
  2021-05-03 21:34 [PATCHSET 0/2] xfs: realtime allocator fixes Darrick J. Wong
  2021-05-03 21:34 ` [PATCH 1/2] xfs: adjust rt allocation minlen when extszhint > rtextsize Darrick J. Wong
  2021-05-03 21:34 ` [PATCH 2/2] xfs: retry allocations when locality-based search fails Darrick J. Wong
@ 2021-05-03 21:35 ` Darrick J. Wong
  2 siblings, 0 replies; 6+ messages in thread
From: Darrick J. Wong @ 2021-05-03 21:35 UTC (permalink / raw)
  To: linux-xfs

From: Darrick J. Wong <djwong@kernel.org>

This is a regression test for the two realtime allocator bug fixes:

xfs: adjust rt allocation minlen when extszhint > rtextsize
xfs: retry allocations when locality-based search fails

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 tests/xfs/775     |  172 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/775.out |    3 +
 tests/xfs/group   |    1 
 3 files changed, 176 insertions(+)
 create mode 100755 tests/xfs/775
 create mode 100644 tests/xfs/775.out

diff --git a/tests/xfs/775 b/tests/xfs/775
new file mode 100755
index 00000000..b2deed90
--- /dev/null
+++ b/tests/xfs/775
@@ -0,0 +1,172 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2021, Oracle.  All Rights Reserved.
+#
+# FS QA Test No. 775
+#
+# Regression test for two fixes in the realtime allocator:
+#
+# xfs: adjust rt allocation minlen when extszhint > rtextsize
+# xfs: retry allocations when locality-based search fails
+#
+# The first bug occurs when an extent size hint is set on a realtime file.
+# xfs_bmapi_rtalloc adjusts the offset and length of the allocation request to
+# try to satisfy the hint, but doesn't adjust minlen to match.  If the
+# allocator finds free space that isn't large enough to map even a single block
+# of the original request, bmapi_write will return ENOSPC and the write fails
+# even though there's plenty of space.
+#
+# The second bug occurs when an extent size hint is set on a file, we ask to
+# allocate blocks in an empty region immediately adjacent to a previous
+# allocation, and the nearest available free space isn't anywhere near the
+# previous allocation, the near allocator will give up and return ENOSPC, even
+# if there's sufficient free realtime extents to satisfy the allocation
+# request.
+#
+# Both bugs can be exploited by the same user call sequence, so here's a
+# targeted test that runs in less time than the reproducers that are listed in
+# the fix patches themselves.
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+
+# real QA test starts here
+_require_scratch
+_require_realtime
+_require_xfs_io_command "falloc"
+_require_xfs_io_command "fpunch"
+_require_test_program "punch-alternating"
+
+rm -f $seqres.full
+
+fill_rtdev()
+{
+	file=$1
+
+	filesize=`_get_available_space $SCRATCH_MNT`
+	$XFS_IO_PROG -f -c "truncate $filesize" -c "falloc 0 $filesize" $file
+
+	chunks=20
+	chunksizemb=$((filesize / chunks / 1048576))
+	seq 1 $chunks | while read f; do
+		echo "$((f * chunksizemb)) file size $f / 20"
+		$XFS_IO_PROG -fc "falloc -k $(( (f - 1) * chunksizemb))m ${chunksizemb}m" $file
+	done
+
+	chunks=100
+	chunksizemb=$((filesize / chunks / 1048576))
+	seq 80 $chunks | while read f; do
+		echo "$((f * chunksizemb)) file size $f / $chunks"
+		$XFS_IO_PROG -fc "falloc -k $(( (f - 1) * chunksizemb))m ${chunksizemb}m" $file
+	done
+
+	filesizemb=$((filesize / 1048576))
+	$XFS_IO_PROG -fc "falloc -k 0 ${filesizemb}m" $file
+
+	# Try again anyway
+	avail=`_get_available_space $SCRATCH_MNT`
+	$XFS_IO_PROG -fc "pwrite -S 0x65 0 $avail" ${file}
+}
+
+echo "Format and mount"
+_scratch_mkfs > $seqres.full 2>&1
+_scratch_mount >> $seqres.full 2>&1
+
+# This is a test of the rt allocator; force all files to be created realtime
+$XFS_IO_PROG -c 'chattr +t' $SCRATCH_MNT
+
+# Set the extent size hint larger than the realtime extent size.  This is
+# necessary to exercise the minlen constraints on the realtime allocator.
+fsbsize=$($XFS_IO_PROG -c 'statfs' $SCRATCH_MNT | grep geom.bsize | awk '{print $3}')
+rtextsize_blks=$($XFS_IO_PROG -c 'statfs' $SCRATCH_MNT | grep geom.rtextsize | awk '{print $3}')
+extsize=$((2 * rtextsize_blks * fsbsize))
+
+echo "rtextsize_blks=$rtextsize_blks extsize=$extsize" >> $seqres.full
+$XFS_IO_PROG -c 'chattr +t' -c "extsize $extsize" $SCRATCH_MNT
+
+# Compute the geometry of the test files we're going to create.  Realtime
+# volumes are simple, which means that we can control the space allocations
+# exactly to exploit bugs!
+#
+# Since this is a test of the near rt allocator, we need to set up the test to
+# have a victim file with at least one rt extent allocated to it and enough
+# free space to allocate at least one more rt extent at an adjacent file
+# offset.  The free space must not be immediately adjacent to the the first
+# extent that we allocate to the victim file, and it must not be large enough
+# to satisfy the entire allocation request all at once.
+#
+# Our free space fragmentation strategy is the usual fallocate-and-punch swiss
+# cheese file, which means the free space is split into five sections:
+#
+# The first will be remapped into the victim file.
+#
+# The second section exists to prevent the free extents from being adjacent to
+# the first section.  It will be very large, since we allocate all the rt
+# space.
+#
+# The last three sections will have every other rt extent punched out to create
+# some free space.
+remap_sz=$((extsize * 2))
+required_sz=$((5 * remap_sz))
+free_rtspace=$(_get_available_space $SCRATCH_MNT)
+if [ $free_rtspace -lt $required_sz ]; then
+	_notrun "Insufficient free space on rt volume.  Needed $required_sz, saw $free_rtspace."
+fi
+
+# Allocate all the space on the rt volume so that we can control space
+# allocations exactly.
+fill_rtdev $SCRATCH_MNT/bigfile &>> $seqres.full
+
+# We need at least 4 remap sections to proceed
+bigfile_sz=$(stat -c '%s' $SCRATCH_MNT/bigfile)
+if [ $bigfile_sz -lt $required_sz ]; then
+	_notrun "Free space control file needed $required_sz bytes, got $bigfile_sz."
+fi
+
+# Remap the first remap section to a victim file.
+$XFS_IO_PROG -c "fpunch 0 $remap_sz" $SCRATCH_MNT/bigfile
+$XFS_IO_PROG -f -c "truncate $required_sz" -c "falloc 0 $remap_sz" $SCRATCH_MNT/victim
+
+# Punch out every other extent of the last two sections, to fragment free space.
+frag_sz=$((remap_sz * 3))
+punch_off=$((bigfile_sz - frag_sz))
+$here/src/punch-alternating $SCRATCH_MNT/bigfile -o $((punch_off / fsbsize)) -i $((rtextsize_blks * 2)) -s $rtextsize_blks
+
+# Make sure we have some free rtextents.
+free_rtx=$($XFS_IO_PROG -c 'statfs' $SCRATCH_MNT | grep counts.freertx | awk '{print $3}')
+if [ $free_rtx -eq 0 ]; then
+	echo "Expected fragmented free rt space, found none."
+fi
+
+# Try to double the amount of blocks in the victim file.  On a buggy kernel,
+# the rt allocator will fail immediately with ENOSPC even though we left enough
+# free space for the write will complete fully.
+echo "Try to write a bunch of stuff to the fragmented rt space"
+$XFS_IO_PROG -c "pwrite -S 0x63 -b $remap_sz $remap_sz $remap_sz" -c stat $SCRATCH_MNT/victim >> $seqres.full
+
+# The victim file should own at least two sections' worth of blocks.
+victim_sectors=$(stat -c '%b' $SCRATCH_MNT/victim)
+victim_space_usage=$((victim_sectors * 512))
+expected_usage=$((remap_sz * 2))
+
+if [ $victim_space_usage -lt $expected_usage ]; then
+	echo "Victim file should be using at least $expected_usage bytes, saw $victim_space_usage."
+fi
+
+status=0
+exit
diff --git a/tests/xfs/775.out b/tests/xfs/775.out
new file mode 100644
index 00000000..f5a72156
--- /dev/null
+++ b/tests/xfs/775.out
@@ -0,0 +1,3 @@
+QA output created by 775
+Format and mount
+Try to write a bunch of stuff to the fragmented rt space
diff --git a/tests/xfs/group b/tests/xfs/group
index 76e31167..5f1ef5d6 100644
--- a/tests/xfs/group
+++ b/tests/xfs/group
@@ -529,5 +529,6 @@
 538 auto stress
 539 auto quick mount
 757 auto quick attr repair
+775 auto quick rw realtime
 908 auto quick bigtime
 909 auto quick bigtime quota

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] xfs: adjust rt allocation minlen when extszhint > rtextsize
  2021-05-03 21:34 ` [PATCH 1/2] xfs: adjust rt allocation minlen when extszhint > rtextsize Darrick J. Wong
@ 2021-05-06  5:26   ` Allison Henderson
  0 siblings, 0 replies; 6+ messages in thread
From: Allison Henderson @ 2021-05-06  5:26 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/3/21 2:34 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
> 
> xfs_bmap_rtalloc doesn't handle realtime extent files with extent size
> hints larger than the rt volume's extent size properly, because
> xfs_bmap_extsize_align can adjust the offset/length parameters to try to
> fit the extent size hint.
> 
> Under these conditions, minlen has to be large enough so that any
> allocation returned by xfs_rtallocate_extent will be large enough to
> cover at least one of the blocks that the caller asked for.  If the
> allocation is too short, bmapi_write will return no mapping for the
> requested range, which causes ENOSPC errors in other parts of the
> filesystem.
> 
> Therefore, adjust minlen upwards to fix this.  This can be found by
> running generic/263 (g/127 or g/522) with a realtime extent size hint
> that's larger than the rt volume extent size.
> 
> Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Ok, makes sense.  Thanks for the comments
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>

> ---
>   fs/xfs/xfs_bmap_util.c |   81 +++++++++++++++++++++++++++++++++---------------
>   1 file changed, 56 insertions(+), 25 deletions(-)
> 
> 
> diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
> index a5e9d7d34023..c9381bf4f04b 100644
> --- a/fs/xfs/xfs_bmap_util.c
> +++ b/fs/xfs/xfs_bmap_util.c
> @@ -71,18 +71,23 @@ xfs_zero_extent(
>   #ifdef CONFIG_XFS_RT
>   int
>   xfs_bmap_rtalloc(
> -	struct xfs_bmalloca	*ap)	/* bmap alloc argument struct */
> +	struct xfs_bmalloca	*ap)
>   {
> -	int		error;		/* error return value */
> -	xfs_mount_t	*mp;		/* mount point structure */
> -	xfs_extlen_t	prod = 0;	/* product factor for allocators */
> -	xfs_extlen_t	mod = 0;	/* product factor for allocators */
> -	xfs_extlen_t	ralen = 0;	/* realtime allocation length */
> -	xfs_extlen_t	align;		/* minimum allocation alignment */
> -	xfs_rtblock_t	rtb;
> +	struct xfs_mount	*mp = ap->ip->i_mount;
> +	xfs_fileoff_t		orig_offset = ap->offset;
> +	xfs_rtblock_t		rtb;
> +	xfs_extlen_t		prod = 0;  /* product factor for allocators */
> +	xfs_extlen_t		mod = 0;   /* product factor for allocators */
> +	xfs_extlen_t		ralen = 0; /* realtime allocation length */
> +	xfs_extlen_t		align;     /* minimum allocation alignment */
> +	xfs_extlen_t		orig_length = ap->length;
> +	xfs_extlen_t		minlen = mp->m_sb.sb_rextsize;
> +	xfs_extlen_t		raminlen;
> +	bool			rtlocked = false;
> +	int			error;
>   
> -	mp = ap->ip->i_mount;
>   	align = xfs_get_extsz_hint(ap->ip);
> +retry:
>   	prod = align / mp->m_sb.sb_rextsize;
>   	error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev,
>   					align, 1, ap->eof, 0,
> @@ -92,6 +97,15 @@ xfs_bmap_rtalloc(
>   	ASSERT(ap->length);
>   	ASSERT(ap->length % mp->m_sb.sb_rextsize == 0);
>   
> +	/*
> +	 * If we shifted the file offset downward to satisfy an extent size
> +	 * hint, increase minlen by that amount so that the allocator won't
> +	 * give us an allocation that's too short to cover at least one of the
> +	 * blocks that the caller asked for.
> +	 */
> +	if (ap->offset != orig_offset)
> +		minlen += orig_offset - ap->offset;
> +
>   	/*
>   	 * If the offset & length are not perfectly aligned
>   	 * then kill prod, it will just get us in trouble.
> @@ -116,10 +130,13 @@ xfs_bmap_rtalloc(
>   	/*
>   	 * Lock out modifications to both the RT bitmap and summary inodes
>   	 */
> -	xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL|XFS_ILOCK_RTBITMAP);
> -	xfs_trans_ijoin(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
> -	xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL|XFS_ILOCK_RTSUM);
> -	xfs_trans_ijoin(ap->tp, mp->m_rsumip, XFS_ILOCK_EXCL);
> +	if (!rtlocked) {
> +		xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL|XFS_ILOCK_RTBITMAP);
> +		xfs_trans_ijoin(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
> +		xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL|XFS_ILOCK_RTSUM);
> +		xfs_trans_ijoin(ap->tp, mp->m_rsumip, XFS_ILOCK_EXCL);
> +		rtlocked = true;
> +	}
>   
>   	/*
>   	 * If it's an allocation to an empty file at offset 0,
> @@ -144,30 +161,44 @@ xfs_bmap_rtalloc(
>   	do_div(ap->blkno, mp->m_sb.sb_rextsize);
>   	rtb = ap->blkno;
>   	ap->length = ralen;
> -	error = xfs_rtallocate_extent(ap->tp, ap->blkno, 1, ap->length,
> -				&ralen, ap->wasdel, prod, &rtb);
> +	raminlen = max_t(xfs_extlen_t, 1, minlen / mp->m_sb.sb_rextsize);
> +	error = xfs_rtallocate_extent(ap->tp, ap->blkno, raminlen, ap->length,
> +			&ralen, ap->wasdel, prod, &rtb);
>   	if (error)
>   		return error;
>   
> -	ap->blkno = rtb;
> -	if (ap->blkno != NULLFSBLOCK) {
> -		ap->blkno *= mp->m_sb.sb_rextsize;
> -		ralen *= mp->m_sb.sb_rextsize;
> -		ap->length = ralen;
> -		ap->ip->i_nblocks += ralen;
> +	if (rtb != NULLRTBLOCK) {
> +		ap->blkno = rtb * mp->m_sb.sb_rextsize;
> +		ap->length = ralen * mp->m_sb.sb_rextsize;
> +		ap->ip->i_nblocks += ap->length;
>   		xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
>   		if (ap->wasdel)
> -			ap->ip->i_delayed_blks -= ralen;
> +			ap->ip->i_delayed_blks -= ap->length;
>   		/*
>   		 * Adjust the disk quota also. This was reserved
>   		 * earlier.
>   		 */
>   		xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
>   			ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
> -					XFS_TRANS_DQ_RTBCOUNT, (long) ralen);
> -	} else {
> -		ap->length = 0;
> +					XFS_TRANS_DQ_RTBCOUNT, ap->length);
> +		return 0;
>   	}
> +
> +	if (align > mp->m_sb.sb_rextsize) {
> +		/*
> +		 * We previously enlarged the request length to try to satisfy
> +		 * an extent size hint.  The allocator didn't return anything,
> +		 * so reset the parameters to the original values and try again
> +		 * without alignment criteria.
> +		 */
> +		ap->offset = orig_offset;
> +		ap->length = orig_length;
> +		minlen = align = mp->m_sb.sb_rextsize;
> +		goto retry;
> +	}
> +
> +	ap->blkno = NULLFSBLOCK;
> +	ap->length = 0;
>   	return 0;
>   }
>   #endif /* CONFIG_XFS_RT */
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] xfs: retry allocations when locality-based search fails
  2021-05-03 21:34 ` [PATCH 2/2] xfs: retry allocations when locality-based search fails Darrick J. Wong
@ 2021-05-06  5:26   ` Allison Henderson
  0 siblings, 0 replies; 6+ messages in thread
From: Allison Henderson @ 2021-05-06  5:26 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/3/21 2:34 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
> 
> If a realtime allocation fails because we can't find a sufficiently
> large free extent satisfying locality rules, relax the locality rules
> and try again.  This reduces the occurrence of short writes to realtime
> files when the write size is large and the free space is fragmented.
> 
> This was originally discovered by running generic/186 with the realtime
> reflink patchset and a 128k cow extent size hint, but the same problem
> can manifest with a 128k extent size hint, so applies the fix now.
> 
> Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Ok, makes sense.
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>

> ---
>   fs/xfs/xfs_bmap_util.c |   15 ++++++++++++++-
>   1 file changed, 14 insertions(+), 1 deletion(-)
> 
> 
> diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
> index c9381bf4f04b..0936f3a96fe6 100644
> --- a/fs/xfs/xfs_bmap_util.c
> +++ b/fs/xfs/xfs_bmap_util.c
> @@ -84,6 +84,7 @@ xfs_bmap_rtalloc(
>   	xfs_extlen_t		minlen = mp->m_sb.sb_rextsize;
>   	xfs_extlen_t		raminlen;
>   	bool			rtlocked = false;
> +	bool			ignore_locality = false;
>   	int			error;
>   
>   	align = xfs_get_extsz_hint(ap->ip);
> @@ -158,7 +159,10 @@ xfs_bmap_rtalloc(
>   	/*
>   	 * Realtime allocation, done through xfs_rtallocate_extent.
>   	 */
> -	do_div(ap->blkno, mp->m_sb.sb_rextsize);
> +	if (ignore_locality)
> +		ap->blkno = 0;
> +	else
> +		do_div(ap->blkno, mp->m_sb.sb_rextsize);
>   	rtb = ap->blkno;
>   	ap->length = ralen;
>   	raminlen = max_t(xfs_extlen_t, 1, minlen / mp->m_sb.sb_rextsize);
> @@ -197,6 +201,15 @@ xfs_bmap_rtalloc(
>   		goto retry;
>   	}
>   
> +	if (!ignore_locality && ap->blkno != 0) {
> +		/*
> +		 * If we can't allocate near a specific rt extent, try again
> +		 * without locality criteria.
> +		 */
> +		ignore_locality = true;
> +		goto retry;
> +	}
> +
>   	ap->blkno = NULLFSBLOCK;
>   	ap->length = 0;
>   	return 0;
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-05-06  5:26 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-03 21:34 [PATCHSET 0/2] xfs: realtime allocator fixes Darrick J. Wong
2021-05-03 21:34 ` [PATCH 1/2] xfs: adjust rt allocation minlen when extszhint > rtextsize Darrick J. Wong
2021-05-06  5:26   ` Allison Henderson
2021-05-03 21:34 ` [PATCH 2/2] xfs: retry allocations when locality-based search fails Darrick J. Wong
2021-05-06  5:26   ` Allison Henderson
2021-05-03 21:35 ` [PATCH] xfs: test fsx with extent size hints set on a realtime file Darrick J. Wong

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.