summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2019-08-30 15:45:05 -0700
committerDarrick J. Wong <darrick.wong@oracle.com>2019-10-19 10:39:11 -0700
commit99117c70e1e95d6b3a6017e7346c1a4355de888f (patch)
tree2011a6d97b8a5eea903dfa354b6f118206228519
parent0eb7dd4e4e25147ec47adc54e30fda87d071ab27 (diff)
xfs: flush speculative space allocations when we run out of spacereclaim-space-harder_2019-10-19
If a fs modification (creation, file write, reflink, etc.) is unable to reserve enough space to handle the modification, try clearing whatever space the filesystem might have been hanging onto in the hopes of speeding up the filesystem. The flushing behavior will become particularly important when we add deferred inode inactivation because that will increase the amount of space that isn't actively tied to user data. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r--fs/xfs/xfs_bmap_util.c12
-rw-r--r--fs/xfs/xfs_file.c9
-rw-r--r--fs/xfs/xfs_icache.c30
-rw-r--r--fs/xfs/xfs_icache.h1
-rw-r--r--fs/xfs/xfs_inode.c11
-rw-r--r--fs/xfs/xfs_iomap.c12
-rw-r--r--fs/xfs/xfs_reflink.c21
-rw-r--r--fs/xfs/xfs_trace.h1
8 files changed, 85 insertions, 12 deletions
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index b8e2bff30704..8251ae1fe14e 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -946,7 +946,17 @@ xfs_alloc_file_space(
retry:
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks,
resrtextents, 0, &tp);
-
+ /*
+ * We weren't able to reserve enough space to handle fallocate.
+ * Flush any disk space that was being held in the hopes of
+ * speeding up the filesystem. We hold the IOLOCK so we cannot
+ * do a synchronous scan.
+ */
+ if (error == -ENOSPC && !cleared_space) {
+ cleared_space = true;
+ xfs_inode_free_blocks(ip->i_mount, false);
+ goto retry;
+ }
/*
* Check for running out of space
*/
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index b196c00efa7a..a0b2af9f98e3 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -661,15 +661,10 @@ write_retry:
goto write_retry;
iolock = 0;
} else if (ret == -ENOSPC && !cleared_space) {
- struct xfs_eofblocks eofb = {0};
-
- cleared_space = true;
xfs_flush_inodes(ip->i_mount);
-
xfs_iunlock(ip, iolock);
- eofb.eof_flags = XFS_EOF_FLAGS_SYNC;
- xfs_icache_free_eofblocks(ip->i_mount, &eofb);
- xfs_icache_free_cowblocks(ip->i_mount, &eofb);
+ cleared_space = true;
+ xfs_inode_free_blocks(ip->i_mount, true);
goto write_retry;
}
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 6fc5cb54914f..b7f8ad93b14b 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -1524,6 +1524,15 @@ xfs_icache_free_eofblocks(
XFS_ICI_EOFBLOCKS_TAG);
}
+static inline void
+xfs_inode_free_scan(
+ struct xfs_mount *mp,
+ struct xfs_eofblocks *eofb)
+{
+ xfs_icache_free_eofblocks(mp, eofb);
+ xfs_icache_free_cowblocks(mp, eofb);
+}
+
/*
* 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
@@ -1579,11 +1588,28 @@ xfs_inode_free_quota_blocks(
trace_xfs_inode_free_quota_blocks(ip->i_mount, &eofb, _RET_IP_);
- xfs_icache_free_eofblocks(ip->i_mount, &eofb);
- xfs_icache_free_cowblocks(ip->i_mount, &eofb);
+ xfs_inode_free_scan(ip->i_mount, &eofb);
return true;
}
+/*
+ * Try to free space in the filesystem by purging eofblocks and cowblocks.
+ */
+void
+xfs_inode_free_blocks(
+ struct xfs_mount *mp,
+ bool sync)
+{
+ struct xfs_eofblocks eofb = {0};
+
+ if (sync)
+ eofb.eof_flags |= XFS_EOF_FLAGS_SYNC;
+
+ trace_xfs_inode_free_blocks(mp, &eofb, _RET_IP_);
+
+ xfs_inode_free_scan(mp, &eofb);
+}
+
static inline unsigned long
xfs_iflag_for_tag(
int tag)
diff --git a/fs/xfs/xfs_icache.h b/fs/xfs/xfs_icache.h
index a42a682cec0b..738417c3568b 100644
--- a/fs/xfs/xfs_icache.h
+++ b/fs/xfs/xfs_icache.h
@@ -58,6 +58,7 @@ 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, bool sync);
+void xfs_inode_free_blocks(struct xfs_mount *mp, bool sync);
void xfs_inode_set_eofblocks_tag(struct xfs_inode *ip);
void xfs_inode_clear_eofblocks_tag(struct xfs_inode *ip);
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index a96e2ce6a5c5..163b1b0a96fb 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1171,10 +1171,17 @@ xfs_create(
*/
retry:
error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp);
- if (error == -ENOSPC) {
+ /*
+ * We weren't able to reserve enough space to add the inode. Flush
+ * any disk space that was being held in the hopes of speeding up the
+ * filesystem.
+ */
+ if (error == -ENOSPC && !cleared_space) {
+ cleared_space = true;
/* flush outstanding delalloc blocks and retry */
xfs_flush_inodes(mp);
- error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp);
+ xfs_inode_free_blocks(mp, true);
+ goto retry;
}
if (error)
goto out_release_inode;
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index cf63fc22079e..3436e20cc3c6 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -262,6 +262,18 @@ xfs_iomap_write_direct(
retry:
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, resrtextents,
tflags, &tp);
+ /*
+ * We weren't able to reserve enough space for the direct write. Flush
+ * any disk space that was being held in the hopes of speeding up the
+ * filesystem. Historically, we expected callers to have preallocated
+ * all the space before a direct write, but this is not an absolute
+ * requirement. We still hold the IOLOCK so we cannot do a sync scan.
+ */
+ if (error == -ENOSPC && !cleared_space) {
+ cleared_space = true;
+ xfs_inode_free_blocks(ip->i_mount, false);
+ goto retry;
+ }
if (error)
return error;
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 4ab483483a31..c62bf4a35de3 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -381,6 +381,17 @@ xfs_reflink_allocate_cow(
xfs_iunlock(ip, *lockmode);
retry:
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp);
+ /*
+ * We weren't able to reserve enough space to handle copy on write.
+ * Flush any disk space that was being held in the hopes of speeding up
+ * the filesystem. We potentially hold the IOLOCK so we cannot do a
+ * synchronous scan.
+ */
+ if (error == -ENOSPC && !cleared_space) {
+ cleared_space = true;
+ xfs_inode_free_blocks(ip->i_mount, false);
+ goto retry;
+ }
*lockmode = XFS_ILOCK_EXCL;
xfs_ilock(ip, *lockmode);
@@ -1043,6 +1054,16 @@ xfs_reflink_remap_extent(
resblks = XFS_EXTENTADD_SPACE_RES(ip->i_mount, XFS_DATA_FORK);
retry:
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp);
+ /*
+ * We weren't able to reserve enough space for the remapping. Flush
+ * any disk space that was being held in the hopes of speeding up the
+ * filesystem. We still hold the IOLOCK so we cannot do a sync scan.
+ */
+ if (error == -ENOSPC && !cleared_space) {
+ cleared_space = true;
+ xfs_inode_free_blocks(mp, false);
+ goto retry;
+ }
if (error)
goto out;
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 37dbcef4f5c9..096fd8618f32 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -3794,6 +3794,7 @@ DEFINE_EVENT(xfs_eofblocks_class, name, \
TP_ARGS(mp, eofb, caller_ip))
DEFINE_EOFBLOCKS_EVENT(xfs_ioc_free_eofblocks);
DEFINE_EOFBLOCKS_EVENT(xfs_inode_free_quota_blocks);
+DEFINE_EOFBLOCKS_EVENT(xfs_inode_free_blocks);
#endif /* _TRACE_XFS_H */