summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2019-08-30 15:45:10 -0700
committerDarrick J. Wong <darrick.wong@oracle.com>2019-10-09 09:39:24 -0700
commit4ec4b2586685b32e1b69bd39a1c193fd4a21d121 (patch)
tree624d5fe52cf69fabd441fdbe3d33f622b27bc1e7
parent310f9e7a3ee2d06f41921ca1a0c05000932e0f9e (diff)
xfs: force inode inactivation and retry fs writes when there isn't space
Any time we try to modify a file's contents and it 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>
-rw-r--r--fs/xfs/xfs_iomap.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 7fd65b43b0b2..5325f343eaba 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -572,6 +572,7 @@ xfs_file_iomap_begin_delay(
struct xfs_iext_cursor icur, ccur;
xfs_fsblock_t prealloc_blocks = 0;
bool eof = false, cow_eof = false, shared = false;
+ bool cleared_space = false;
int whichfork = XFS_DATA_FORK;
int error = 0;
@@ -579,7 +580,7 @@ xfs_file_iomap_begin_delay(
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),
@@ -724,6 +725,19 @@ retry:
break;
case -ENOSPC:
case -EDQUOT:
+ /*
+ * If the delalloc reservation failed due to a lack of space,
+ * try to flush inactive inodes to free some space.
+ */
+ if (!cleared_space) {
+ cleared_space = true;
+ whichfork = XFS_DATA_FORK;
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ xfs_inactive_force(mp);
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+ error = 0;
+ goto start_over;
+ }
/* retry without any preallocation */
trace_xfs_delalloc_enospc(ip, offset, count);
if (prealloc_blocks) {