From: Darrick J. Wong <darrick.wong@xxxxxxxxxx> 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@xxxxxxxxxx> --- 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 --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) {