summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_trans.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_trans.c')
-rw-r--r--fs/xfs/xfs_trans.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 67dec11e34c7..4e321bb81991 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -135,6 +135,62 @@ xfs_trans_dup(
}
/*
+ * Try to reserve more blocks for a transaction.
+ *
+ * This is for callers that need to attach resources to a transaction, scan
+ * those resources to determine the space reservation requirements, and then
+ * modify the attached resources. In other words, online repair. This can
+ * fail due to ENOSPC, so the caller must be able to cancel the transaction
+ * without shutting down the fs.
+ */
+int
+xfs_trans_reserve_more(
+ struct xfs_trans *tp,
+ unsigned int blocks,
+ unsigned int rtextents)
+{
+ struct xfs_mount *mp = tp->t_mountp;
+ bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
+ int error = 0;
+
+ ASSERT(!(tp->t_flags & XFS_TRANS_DIRTY));
+
+ /*
+ * Attempt to reserve the needed disk blocks by decrementing
+ * the number needed from the number available. This will
+ * fail if the count would go below zero.
+ */
+ if (blocks > 0) {
+ error = xfs_mod_fdblocks(mp, -((int64_t)blocks), rsvd);
+ if (error)
+ return -ENOSPC;
+ tp->t_blk_res += blocks;
+ }
+
+ /*
+ * Attempt to reserve the needed realtime extents by decrementing
+ * the number needed from the number available. This will
+ * fail if the count would go below zero.
+ */
+ if (rtextents > 0) {
+ error = xfs_mod_frextents(mp, -((int64_t)rtextents));
+ if (error) {
+ error = -ENOSPC;
+ goto out_blocks;
+ }
+ tp->t_rtx_res += rtextents;
+ }
+
+ return 0;
+out_blocks:
+ if (blocks > 0) {
+ xfs_mod_fdblocks(mp, (int64_t)blocks, rsvd);
+ tp->t_blk_res -= blocks;
+ }
+ return error;
+}
+
+/*
* This is called to reserve free disk blocks and log space for the
* given transaction. This must be done before allocating any resources
* within the transaction.
@@ -1080,6 +1136,38 @@ out_cancel:
return error;
}
+
+/* Try to reserve more blocks and file quota for a transaction. */
+int
+xfs_trans_reserve_more_inode(
+ struct xfs_trans *tp,
+ struct xfs_inode *ip,
+ unsigned int dblocks,
+ unsigned int rblocks)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ unsigned int rtx = rblocks / mp->m_sb.sb_rextsize;
+ bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
+ int error;
+
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+
+ error = xfs_trans_reserve_more(tp, dblocks, rtx);
+ if (error)
+ return error;
+
+ error = xfs_trans_reserve_quota_nblks(tp, ip, dblocks, rblocks, rsvd);
+ if (!error)
+ return 0;
+
+ /* Quota failed, give back the new reservation. */
+ xfs_mod_fdblocks(mp, dblocks, rsvd);
+ tp->t_blk_res -= dblocks;
+ xfs_mod_frextents(mp, rtx);
+ tp->t_rtx_res -= rtx;
+ return error;
+}
+
/*
* Allocate an transaction in preparation for inode creation by reserving quota
* against the given dquots. Callers are not required to hold any inode locks.