diff options
-rw-r--r-- | fs/xfs/libxfs/xfs_defer.c | 50 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_defer.h | 10 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_item.c | 7 | ||||
-rw-r--r-- | fs/xfs/xfs_icache.c | 19 |
4 files changed, 83 insertions, 3 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; +} diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h index 4ea287fa2226..51dd5038e730 100644 --- a/fs/xfs/libxfs/xfs_defer.h +++ b/fs/xfs/libxfs/xfs_defer.h @@ -76,6 +76,11 @@ struct xfs_defer_capture { /* Deferred ops state saved from the transaction. */ struct list_head dfc_dfops; unsigned int dfc_tpflags; + + /* Inodes to hold when we want to finish the deferred work items. */ +#define XFS_DEFER_CAPTURE_INODES 2 + unsigned int dfc_ilocks[XFS_DEFER_CAPTURE_INODES]; + struct xfs_inode *dfc_inodes[XFS_DEFER_CAPTURE_INODES]; }; /* @@ -86,5 +91,10 @@ int xfs_defer_capture(struct xfs_trans *tp, struct xfs_defer_capture **dfcp); void xfs_defer_continue(struct xfs_defer_capture *dfc, struct xfs_trans *tp); void xfs_defer_capture_free(struct xfs_mount *mp, struct xfs_defer_capture *dfc); +int xfs_defer_capture_inode(struct xfs_defer_capture *dfc, + struct xfs_inode *ip); + +/* These functions must be provided by the xfs implementation. */ +void xfs_defer_capture_irele(struct xfs_defer_capture *dfc); #endif /* __XFS_DEFER_H__ */ diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index fd56f354cf20..b9bcdb84bdfe 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -530,12 +530,13 @@ xfs_bui_item_recover( } error = xlog_recover_trans_commit(tp, dfcp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - xfs_irele(ip); - return error; + if (error) + goto err_rele; + return xfs_defer_capture_inode(*dfcp, ip); err_inode: xfs_trans_cancel(tp); +err_rele: if (ip) { xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_irele(ip); diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 922a29032e37..87804e841312 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -12,6 +12,7 @@ #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_inode.h" +#include "xfs_defer.h" #include "xfs_trans.h" #include "xfs_trans_priv.h" #include "xfs_inode_item.h" @@ -1847,3 +1848,21 @@ xfs_start_block_reaping( xfs_queue_eofblocks(mp); xfs_queue_cowblocks(mp); } + +/* Release all the inode resources attached to this dfops capture device. */ +void +xfs_defer_capture_irele( + struct xfs_defer_capture *dfc) +{ + unsigned int i; + + for (i = 0; i < XFS_DEFER_CAPTURE_INODES; i++) { + if (!dfc->dfc_inodes[i]) + break; + + if (dfc->dfc_ilocks[i]) + xfs_iunlock(dfc->dfc_inodes[i], dfc->dfc_ilocks[i]); + xfs_irele(dfc->dfc_inodes[i]); + dfc->dfc_inodes[i] = NULL; + } +} |