summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs/xfs_defer.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/libxfs/xfs_defer.c')
-rw-r--r--fs/xfs/libxfs/xfs_defer.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c
index 1964ebbe21d3..853983b7eac5 100644
--- a/fs/xfs/libxfs/xfs_defer.c
+++ b/fs/xfs/libxfs/xfs_defer.c
@@ -16,6 +16,7 @@
#include "xfs_inode.h"
#include "xfs_inode_item.h"
#include "xfs_trace.h"
+#include "xfs_icache.h"
/*
* Deferred Operations in XFS
@@ -582,9 +583,20 @@ xfs_defer_continue(
struct xfs_defer_capture *dfc,
struct xfs_trans *tp)
{
+ int i;
+
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
ASSERT(!(tp->t_flags & XFS_TRANS_DIRTY));
+ /* Re-acquire the inode locks. */
+ for (i = 0; i < XFS_DEFER_CAPTURE_INODES; i++) {
+ if (!dfc->dfc_inodes[i])
+ break;
+
+ dfc->dfc_ilocks[i] = XFS_ILOCK_EXCL;
+ xfs_ilock(dfc->dfc_inodes[i], dfc->dfc_ilocks[i]);
+ }
+
/* Add the dfops items to the transaction. */
list_splice_init(&dfc->dfc_dfops, &tp->t_dfops);
tp->t_flags |= dfc->dfc_tpflags;
@@ -597,5 +609,43 @@ xfs_defer_capture_free(
struct xfs_defer_capture *dfc)
{
xfs_defer_cancel_list(mp, &dfc->dfc_dfops);
+ xfs_defer_capture_irele(dfc);
kmem_free(dfc);
}
+
+/*
+ * Capture an inode along with the deferred ops freezer. Callers must hold
+ * ILOCK_EXCL, which will be dropped and reacquired when we're ready to
+ * continue replaying the deferred ops.
+ */
+int
+xfs_defer_capture_inode(
+ struct xfs_defer_capture *dfc,
+ struct xfs_inode *ip)
+{
+ unsigned int i;
+
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+
+ for (i = 0; i < XFS_DEFER_CAPTURE_INODES; i++) {
+ if (dfc->dfc_inodes[i] == ip)
+ goto out;
+ if (dfc->dfc_inodes[i] == NULL)
+ break;
+ }
+
+ if (i == XFS_DEFER_CAPTURE_INODES) {
+ ASSERT(0);
+ return -EFSCORRUPTED;
+ }
+
+ /*
+ * Attach this inode to the freezer and drop its ILOCK because we
+ * assume the caller will need to allocate a transaction.
+ */
+ dfc->dfc_inodes[i] = ip;
+ dfc->dfc_ilocks[i] = 0;
+out:
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ return 0;
+}