summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_inode.c
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2020-02-19 17:02:04 -0800
committerDarrick J. Wong <darrick.wong@oracle.com>2020-06-01 21:16:35 -0700
commit11ccd1f3e71f45a0223b95f1c0640ef688cf96f9 (patch)
tree931ace461b2fe63b24a13660d45ca426a91fd1a7 /fs/xfs/xfs_inode.c
parent72d96707db7e31a622fc27485bdb0a6ed5451ef0 (diff)
xfs: flush speculative space allocations when we run out of quota
If a fs modification (creation, file write, reflink, etc.) is unable to reserve enough quota 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>
Diffstat (limited to 'fs/xfs/xfs_inode.c')
-rw-r--r--fs/xfs/xfs_inode.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 15f36a4a7a45..a22cf9f6fe01 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1125,6 +1125,7 @@ xfs_create(
struct xfs_dquot *gdqp = NULL;
struct xfs_dquot *pdqp = NULL;
struct xfs_trans_res *tres;
+ bool cleared_space = false;
uint resblks;
trace_xfs_create(dp, name);
@@ -1157,6 +1158,7 @@ xfs_create(
* the case we'll drop the one we have and get a more
* appropriate transaction later.
*/
+retry:
error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp);
if (error == -ENOSPC) {
/* flush outstanding delalloc blocks and retry */
@@ -1174,6 +1176,21 @@ xfs_create(
*/
error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
pdqp, resblks, 1, 0);
+ /*
+ * We weren't able to reserve enough quota to handle adding the inode.
+ * Flush any disk space that was being held in the hopes of speeding up
+ * the filesystem.
+ */
+ if ((error == -EDQUOT || error == -ENOSPC) && !cleared_space) {
+ xfs_trans_cancel(tp);
+ if (unlock_dp_on_error)
+ xfs_iunlock(dp, XFS_ILOCK_EXCL);
+ unlock_dp_on_error = false;
+ cleared_space = xfs_inode_free_quota_blocks(dp, true);
+ if (cleared_space)
+ goto retry;
+ goto out_release_inode;
+ }
if (error)
goto out_trans_cancel;