diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_defer.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_defer.c | 50 |
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; +} |