diff mbox series

[3/6] xfs: don't stall cowblocks scan if we can't take locks

Message ID 161040737263.1582114.4973977520111925461.stgit@magnolia (mailing list archive)
State Superseded
Headers show
Series xfs: try harder to reclaim space when we run out | expand

Commit Message

Darrick J. Wong Jan. 11, 2021, 11:22 p.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

Don't stall the cowblocks scan on a locked inode if we possibly can.
We'd much rather the background scanner keep moving.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/xfs_icache.c |   21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

Comments

Christoph Hellwig Jan. 13, 2021, 2:43 p.m. UTC | #1
On Mon, Jan 11, 2021 at 03:22:52PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
> 
> Don't stall the cowblocks scan on a locked inode if we possibly can.
> We'd much rather the background scanner keep moving.

Wouldn't it make more sense to move the logic to ignore the -EAGAIN
for not-sync calls into xfs_inode_walk_ag?
Darrick J. Wong Jan. 14, 2021, 9:54 p.m. UTC | #2
On Wed, Jan 13, 2021 at 03:43:57PM +0100, Christoph Hellwig wrote:
> On Mon, Jan 11, 2021 at 03:22:52PM -0800, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> > 
> > Don't stall the cowblocks scan on a locked inode if we possibly can.
> > We'd much rather the background scanner keep moving.
> 
> Wouldn't it make more sense to move the logic to ignore the -EAGAIN
> for not-sync calls into xfs_inode_walk_ag?

I'm not sure what you're asking here?  _free_cowblocks only returns
EAGAIN for sync calls.  Locking failure for a not-sync call results in a
return 0, which means that _walk_ag just moves on to the next inode.

--D
Christoph Hellwig Jan. 18, 2021, 5:34 p.m. UTC | #3
On Thu, Jan 14, 2021 at 01:54:53PM -0800, Darrick J. Wong wrote:
> On Wed, Jan 13, 2021 at 03:43:57PM +0100, Christoph Hellwig wrote:
> > On Mon, Jan 11, 2021 at 03:22:52PM -0800, Darrick J. Wong wrote:
> > > From: Darrick J. Wong <djwong@kernel.org>
> > > 
> > > Don't stall the cowblocks scan on a locked inode if we possibly can.
> > > We'd much rather the background scanner keep moving.
> > 
> > Wouldn't it make more sense to move the logic to ignore the -EAGAIN
> > for not-sync calls into xfs_inode_walk_ag?
> 
> I'm not sure what you're asking here?  _free_cowblocks only returns
> EAGAIN for sync calls.  Locking failure for a not-sync call results in a
> return 0, which means that _walk_ag just moves on to the next inode.

What I mean is:

 - always return -EAGAIN when taking the locks fails
 - don't exit early on -EAGAIN in xfs_inode_walk at least for sync
   calls, although thinking loud I see no good reason to exit early
   even for non-sync invocations
Darrick J. Wong Jan. 18, 2021, 7:37 p.m. UTC | #4
On Mon, Jan 18, 2021 at 05:34:12PM +0000, Christoph Hellwig wrote:
> On Thu, Jan 14, 2021 at 01:54:53PM -0800, Darrick J. Wong wrote:
> > On Wed, Jan 13, 2021 at 03:43:57PM +0100, Christoph Hellwig wrote:
> > > On Mon, Jan 11, 2021 at 03:22:52PM -0800, Darrick J. Wong wrote:
> > > > From: Darrick J. Wong <djwong@kernel.org>
> > > > 
> > > > Don't stall the cowblocks scan on a locked inode if we possibly can.
> > > > We'd much rather the background scanner keep moving.
> > > 
> > > Wouldn't it make more sense to move the logic to ignore the -EAGAIN
> > > for not-sync calls into xfs_inode_walk_ag?
> > 
> > I'm not sure what you're asking here?  _free_cowblocks only returns
> > EAGAIN for sync calls.  Locking failure for a not-sync call results in a
> > return 0, which means that _walk_ag just moves on to the next inode.
> 
> What I mean is:
> 
>  - always return -EAGAIN when taking the locks fails
>  - don't exit early on -EAGAIN in xfs_inode_walk at least for sync
>    calls, although thinking loud I see no good reason to exit early
>    even for non-sync invocations

Ah, I see, you're asking why don't I make xfs_inode_walk responsible for
deciding what to do about EAGAIN, instead of open-coding that in the
->execute function.  That would be a nice cleanup since the walk
function already has special casing for EFSCORRUPTED.

If I read you correctly, the relevant part of xfs_inode_walk becomes:

	error = execute(batch[i]...);
	xfs_irele(batch[i]);
	if (error == -EAGAIN) {
		if (args->flags & EOF_SYNC)
			skipped++;
		continue;
	}

and the relevant part of xfs_inode_free_eofblocks becomes:

	if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL))
		return -EAGAIN;

I think that would work, and afaict it won't cause any serious problems
with the deferred inactivation series.

--D
Christoph Hellwig Jan. 18, 2021, 7:39 p.m. UTC | #5
On Mon, Jan 18, 2021 at 11:37:18AM -0800, Darrick J. Wong wrote:
> Ah, I see, you're asking why don't I make xfs_inode_walk responsible for
> deciding what to do about EAGAIN, instead of open-coding that in the
> ->execute function.  That would be a nice cleanup since the walk
> function already has special casing for EFSCORRUPTED.
> 
> If I read you correctly, the relevant part of xfs_inode_walk becomes:
> 
> 	error = execute(batch[i]...);
> 	xfs_irele(batch[i]);
> 	if (error == -EAGAIN) {
> 		if (args->flags & EOF_SYNC)
> 			skipped++;
> 		continue;
> 	}
> 
> and the relevant part of xfs_inode_free_eofblocks becomes:
> 
> 	if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL))
> 		return -EAGAIN;
> 
> I think that would work, and afaict it won't cause any serious problems
> with the deferred inactivation series.

Exactly!
Darrick J. Wong Jan. 18, 2021, 7:44 p.m. UTC | #6
On Mon, Jan 18, 2021 at 07:39:58PM +0000, Christoph Hellwig wrote:
> On Mon, Jan 18, 2021 at 11:37:18AM -0800, Darrick J. Wong wrote:
> > Ah, I see, you're asking why don't I make xfs_inode_walk responsible for
> > deciding what to do about EAGAIN, instead of open-coding that in the
> > ->execute function.  That would be a nice cleanup since the walk
> > function already has special casing for EFSCORRUPTED.
> > 
> > If I read you correctly, the relevant part of xfs_inode_walk becomes:
> > 
> > 	error = execute(batch[i]...);
> > 	xfs_irele(batch[i]);
> > 	if (error == -EAGAIN) {
> > 		if (args->flags & EOF_SYNC)
> > 			skipped++;
> > 		continue;
> > 	}
> > 
> > and the relevant part of xfs_inode_free_eofblocks becomes:
> > 
> > 	if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL))
> > 		return -EAGAIN;
> > 
> > I think that would work, and afaict it won't cause any serious problems
> > with the deferred inactivation series.
> 
> Exactly!

D'oh.  I tried making that change, but ran into the problem that *args
isn't necessarily an eofb structure, and xfs_qm_dqrele_all_inodes passes
a uint pointer.  I could define a new XFS_INODE_WALK_SYNC flag and
update the blockgc callers to set that if EOF_FLAGS_SYNC is set...

--D
Christoph Hellwig Jan. 18, 2021, 7:51 p.m. UTC | #7
On Mon, Jan 18, 2021 at 11:44:22AM -0800, Darrick J. Wong wrote:
> D'oh.  I tried making that change, but ran into the problem that *args
> isn't necessarily an eofb structure, and xfs_qm_dqrele_all_inodes passes
> a uint pointer.  I could define a new XFS_INODE_WALK_SYNC flag and
> update the blockgc callers to set that if EOF_FLAGS_SYNC is set...

That does actually sound cleaner to me, but I don't want to burden that
work on you.  Feel free to stick to the current version and we can
clean this up later.
diff mbox series

Patch

diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 66af84c578b5..4e226827b33d 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -1624,17 +1624,31 @@  xfs_inode_free_cowblocks(
 	void			*args)
 {
 	struct xfs_eofblocks	*eofb = args;
+	bool			wait;
 	int			ret = 0;
 
+	wait = eofb && (eofb->eof_flags & XFS_EOF_FLAGS_SYNC);
+
 	if (!xfs_prep_free_cowblocks(ip))
 		return 0;
 
 	if (!xfs_inode_matches_eofb(ip, eofb))
 		return 0;
 
-	/* Free the CoW blocks */
-	xfs_ilock(ip, XFS_IOLOCK_EXCL);
-	xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
+	/*
+	 * If the caller is waiting, return -EAGAIN to keep the background
+	 * scanner moving and revisit the inode in a subsequent pass.
+	 */
+	if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
+		if (wait)
+			return -EAGAIN;
+		return 0;
+	}
+	if (!xfs_ilock_nowait(ip, XFS_MMAPLOCK_EXCL)) {
+		if (wait)
+			ret = -EAGAIN;
+		goto out_iolock;
+	}
 
 	/*
 	 * Check again, nobody else should be able to dirty blocks or change
@@ -1644,6 +1658,7 @@  xfs_inode_free_cowblocks(
 		ret = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF, false);
 
 	xfs_iunlock(ip, XFS_MMAPLOCK_EXCL);
+out_iolock:
 	xfs_iunlock(ip, XFS_IOLOCK_EXCL);
 
 	return ret;