summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_iomap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_iomap.c')
-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 eef047902e70..f07df3b77a22 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) {