Commit a636b1d1 authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: trigger all block gc scans when low on quota space



The functions to run an eof/cowblocks scan to try to reduce quota usage
are kind of a mess -- the logic repeatedly initializes an eofb structure
and there are logic bugs in the code that result in the cowblocks scan
never actually happening.

Replace all three functions with a single function that fills out an
eofb and runs both eof and cowblocks scans.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
parent 2a4bdfa8
Loading
Loading
Loading
Loading
+6 −9
Original line number Diff line number Diff line
@@ -672,7 +672,7 @@ xfs_file_buffered_aio_write(
	struct inode		*inode = mapping->host;
	struct xfs_inode	*ip = XFS_I(inode);
	ssize_t			ret;
	int			enospc = 0;
	bool			cleared_space = false;
	int			iolock;

	if (iocb->ki_flags & IOCB_NOWAIT)
@@ -704,19 +704,16 @@ xfs_file_buffered_aio_write(
	 * also behaves as a filter to prevent too many eofblocks scans from
	 * running at the same time.
	 */
	if (ret == -EDQUOT && !enospc) {
	if (ret == -EDQUOT && !cleared_space) {
		xfs_iunlock(ip, iolock);
		enospc = xfs_inode_free_quota_eofblocks(ip);
		if (enospc)
			goto write_retry;
		enospc = xfs_inode_free_quota_cowblocks(ip);
		if (enospc)
		cleared_space = xfs_inode_free_quota_blocks(ip);
		if (cleared_space)
			goto write_retry;
		iolock = 0;
	} else if (ret == -ENOSPC && !enospc) {
	} else if (ret == -ENOSPC && !cleared_space) {
		struct xfs_eofblocks eofb = {0};

		enospc = 1;
		cleared_space = true;
		xfs_flush_inodes(ip->i_mount);

		xfs_iunlock(ip, iolock);
+16 −30
Original line number Diff line number Diff line
@@ -1397,20 +1397,18 @@ xfs_icache_free_eofblocks(
}

/*
 * Run eofblocks scans on the quotas applicable to the inode. For inodes with
 * multiple quotas, we don't know exactly which quota caused an allocation
 * Run cow/eofblocks scans on the quotas applicable to the inode. For inodes
 * with multiple quotas, we don't know exactly which quota caused an allocation
 * failure. We make a best effort by including each quota under low free space
 * conditions (less than 1% free space) in the scan.
 */
static int
__xfs_inode_free_quota_eofblocks(
	struct xfs_inode	*ip,
	int			(*execute)(struct xfs_mount *mp,
					   struct xfs_eofblocks	*eofb))
bool
xfs_inode_free_quota_blocks(
	struct xfs_inode	*ip)
{
	int scan = 0;
	struct xfs_eofblocks	eofb = {0};
	struct xfs_dquot	*dq;
	bool			do_work = false;

	/*
	 * Run a sync scan to increase effectiveness and use the union filter to
@@ -1423,7 +1421,7 @@ __xfs_inode_free_quota_eofblocks(
		if (dq && xfs_dquot_lowsp(dq)) {
			eofb.eof_uid = VFS_I(ip)->i_uid;
			eofb.eof_flags |= XFS_EOF_FLAGS_UID;
			scan = 1;
			do_work = true;
		}
	}

@@ -1432,21 +1430,16 @@ __xfs_inode_free_quota_eofblocks(
		if (dq && xfs_dquot_lowsp(dq)) {
			eofb.eof_gid = VFS_I(ip)->i_gid;
			eofb.eof_flags |= XFS_EOF_FLAGS_GID;
			scan = 1;
			do_work = true;
		}
	}

	if (scan)
		execute(ip->i_mount, &eofb);

	return scan;
}
	if (!do_work)
		return false;

int
xfs_inode_free_quota_eofblocks(
	struct xfs_inode *ip)
{
	return __xfs_inode_free_quota_eofblocks(ip, xfs_icache_free_eofblocks);
	xfs_icache_free_eofblocks(ip->i_mount, &eofb);
	xfs_icache_free_cowblocks(ip->i_mount, &eofb);
	return true;
}

static inline unsigned long
@@ -1646,13 +1639,6 @@ xfs_icache_free_cowblocks(
			XFS_ICI_COWBLOCKS_TAG);
}

int
xfs_inode_free_quota_cowblocks(
	struct xfs_inode *ip)
{
	return __xfs_inode_free_quota_eofblocks(ip, xfs_icache_free_cowblocks);
}

void
xfs_inode_set_cowblocks_tag(
	xfs_inode_t	*ip)
+2 −2
Original line number Diff line number Diff line
@@ -54,17 +54,17 @@ long xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan);

void xfs_inode_set_reclaim_tag(struct xfs_inode *ip);

bool xfs_inode_free_quota_blocks(struct xfs_inode *ip);

void xfs_inode_set_eofblocks_tag(struct xfs_inode *ip);
void xfs_inode_clear_eofblocks_tag(struct xfs_inode *ip);
int xfs_icache_free_eofblocks(struct xfs_mount *, struct xfs_eofblocks *);
int xfs_inode_free_quota_eofblocks(struct xfs_inode *ip);
void xfs_eofblocks_worker(struct work_struct *);
void xfs_queue_eofblocks(struct xfs_mount *);

void xfs_inode_set_cowblocks_tag(struct xfs_inode *ip);
void xfs_inode_clear_cowblocks_tag(struct xfs_inode *ip);
int xfs_icache_free_cowblocks(struct xfs_mount *, struct xfs_eofblocks *);
int xfs_inode_free_quota_cowblocks(struct xfs_inode *ip);
void xfs_cowblocks_worker(struct work_struct *);
void xfs_queue_cowblocks(struct xfs_mount *);