diff mbox series

[09/12] xfs: retry fs writes when there isn't space

Message ID 154630906634.16693.14439684008416608580.stgit@magnolia (mailing list archive)
State Deferred, archived
Headers show
Series xfs: deferred inode inactivation | expand

Commit Message

Darrick J. Wong Jan. 1, 2019, 2:17 a.m. UTC
From: Darrick J. Wong <darrick.wong@oracle.com>

Any time we try a file write that fails due to ENOSPC or EDQUOT, force
inactivation work to free up some resources and try one more time.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/xfs_file.c  |   11 +++++++++++
 fs/xfs/xfs_inode.c |    1 +
 fs/xfs/xfs_iomap.c |   10 +++++++++-
 3 files changed, 21 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index e47425071e65..7ba3b799702d 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -652,6 +652,9 @@  xfs_file_buffered_aio_write(
 		if (enospc)
 			goto write_retry;
 		enospc = xfs_inode_free_quota_cowblocks(ip);
+		if (enospc)
+			goto write_retry;
+		enospc = xfs_inactive_free_quota(ip);
 		if (enospc)
 			goto write_retry;
 		iolock = 0;
@@ -665,6 +668,7 @@  xfs_file_buffered_aio_write(
 		eofb.eof_flags = XFS_EOF_FLAGS_SYNC;
 		xfs_icache_free_eofblocks(ip->i_mount, &eofb);
 		xfs_icache_free_cowblocks(ip->i_mount, &eofb);
+		xfs_inactive_force(ip->i_mount);
 		goto write_retry;
 	}
 
@@ -936,6 +940,7 @@  xfs_file_remap_range(
 	struct xfs_mount	*mp = src->i_mount;
 	loff_t			remapped = 0;
 	xfs_extlen_t		cowextsize;
+	bool			can_retry = true;
 	int			ret;
 
 	if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
@@ -955,8 +960,14 @@  xfs_file_remap_range(
 
 	trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out);
 
+retry:
 	ret = xfs_reflink_remap_blocks(src, pos_in, dest, pos_out, len,
 			&remapped);
+	if ((ret == -EDQUOT || ret == -ENOSPC) && can_retry) {
+		can_retry = false;
+		xfs_inactive_force(mp);
+		goto retry;
+	}
 	if (ret)
 		goto out_unlock;
 
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 26c8181f5760..2c7f8aeffa92 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1181,6 +1181,7 @@  xfs_create(
 	if (error == -ENOSPC) {
 		/* flush outstanding delalloc blocks and retry */
 		xfs_flush_inodes(mp);
+		xfs_inactive_force(mp);
 		error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp);
 	}
 	if (error)
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 59772a7c7586..302ba859dd32 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -532,12 +532,13 @@  xfs_file_iomap_begin_delay(
 	struct xfs_bmbt_irec	got;
 	struct xfs_iext_cursor	icur;
 	xfs_fsblock_t		prealloc_blocks = 0;
+	bool			flush_inactive = true;
 
 	ASSERT(!XFS_IS_REALTIME_INODE(ip));
 	ASSERT(!xfs_get_extsz_hint(ip));
 
 	xfs_ilock(ip, XFS_ILOCK_EXCL);
-
+start_over:
 	if (unlikely(XFS_TEST_ERROR(
 	    (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS &&
 	     XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE),
@@ -632,6 +633,13 @@  xfs_file_iomap_begin_delay(
 		break;
 	case -ENOSPC:
 	case -EDQUOT:
+		if (flush_inactive) {
+			flush_inactive = false;
+			xfs_iunlock(ip, XFS_ILOCK_EXCL);
+			xfs_inactive_force(mp);
+			xfs_ilock(ip, XFS_ILOCK_EXCL);
+			goto start_over;
+		}
 		/* retry without any preallocation */
 		trace_xfs_delalloc_enospc(ip, offset, count);
 		if (prealloc_blocks) {