summaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_log_recover.c
diff options
context:
space:
mode:
authorDavid Chinner2008-10-30 07:38:39 +0100
committerLachlan McIlroy2008-10-30 07:38:39 +0100
commit27d8d5fe0ef9daeaafbdd32b14b32a2211930062 (patch)
treee170fd577c1f6e58bee1cabb5cad75ced643c3ac /fs/xfs/xfs_log_recover.c
parent[XFS] Allocate the struct xfs_ail (diff)
downloadkernel-qcow2-linux-27d8d5fe0ef9daeaafbdd32b14b32a2211930062.tar.gz
kernel-qcow2-linux-27d8d5fe0ef9daeaafbdd32b14b32a2211930062.tar.xz
kernel-qcow2-linux-27d8d5fe0ef9daeaafbdd32b14b32a2211930062.zip
[XFS] Use a cursor for AIL traversal.
To replace the current generation number ensuring sanity of the AIL traversal, replace it with an external cursor that is linked to the AIL. Basically, we store the next item in the cursor whenever we want to drop the AIL lock to do something to the current item. When we regain the lock. the current item may already be free, so we can't reference it, but the next item in the traversal is already held in the cursor. When we move or delete an object, we search all the active cursors and if there is an item match we clear the cursor(s) that point to the object. This forces the traversal to restart transparently. We don't invalidate the cursor on insert because the cursor still points to a valid item. If the intem is inserted between the current item and the cursor it does not matter; the traversal is considered to be past the insertion point so it will be picked up in the next traversal. Hence traversal restarts pretty much disappear altogether with this method of traversal, which should substantially reduce the overhead of pushing on a busy AIL. Version 2 o add restart logic o comment cursor interface o minor cleanups SGI-PV: 988143 SGI-Modid: xfs-linux-melb:xfs-kern:32347a Signed-off-by: David Chinner <david@fromorbit.com> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com> Signed-off-by: Christoph Hellwig <hch@infradead.org>
Diffstat (limited to 'fs/xfs/xfs_log_recover.c')
-rw-r--r--fs/xfs/xfs_log_recover.c61
1 files changed, 21 insertions, 40 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 199c8ea36474..37ba4899f3e6 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -54,10 +54,8 @@ STATIC void xlog_recover_insert_item_backq(xlog_recover_item_t **q,
xlog_recover_item_t *item);
#if defined(DEBUG)
STATIC void xlog_recover_check_summary(xlog_t *);
-STATIC void xlog_recover_check_ail(xfs_mount_t *, xfs_log_item_t *, int);
#else
#define xlog_recover_check_summary(log)
-#define xlog_recover_check_ail(mp, lip, gen)
#endif
@@ -2710,8 +2708,8 @@ xlog_recover_do_efd_trans(
xfs_efd_log_format_t *efd_formatp;
xfs_efi_log_item_t *efip = NULL;
xfs_log_item_t *lip;
- int gen;
__uint64_t efi_id;
+ struct xfs_ail_cursor cur;
if (pass == XLOG_RECOVER_PASS1) {
return;
@@ -2730,7 +2728,8 @@ xlog_recover_do_efd_trans(
*/
mp = log->l_mp;
spin_lock(&mp->m_ail_lock);
- lip = xfs_trans_first_ail(mp, &gen);
+ xfs_trans_ail_cursor_init(mp->m_ail, &cur);
+ lip = xfs_trans_first_ail(mp, &cur);
while (lip != NULL) {
if (lip->li_type == XFS_LI_EFI) {
efip = (xfs_efi_log_item_t *)lip;
@@ -2741,11 +2740,13 @@ xlog_recover_do_efd_trans(
*/
xfs_trans_delete_ail(mp, lip);
xfs_efi_item_free(efip);
- return;
+ spin_lock(&mp->m_ail_lock);
+ break;
}
}
- lip = xfs_trans_next_ail(mp, lip, &gen, NULL);
+ lip = xfs_trans_next_ail(mp, &cur);
}
+ xfs_trans_ail_cursor_done(mp->m_ail, &cur);
spin_unlock(&mp->m_ail_lock);
}
@@ -3030,33 +3031,6 @@ abort_error:
}
/*
- * Verify that once we've encountered something other than an EFI
- * in the AIL that there are no more EFIs in the AIL.
- */
-#if defined(DEBUG)
-STATIC void
-xlog_recover_check_ail(
- xfs_mount_t *mp,
- xfs_log_item_t *lip,
- int gen)
-{
- int orig_gen = gen;
-
- do {
- ASSERT(lip->li_type != XFS_LI_EFI);
- lip = xfs_trans_next_ail(mp, lip, &gen, NULL);
- /*
- * The check will be bogus if we restart from the
- * beginning of the AIL, so ASSERT that we don't.
- * We never should since we're holding the AIL lock
- * the entire time.
- */
- ASSERT(gen == orig_gen);
- } while (lip != NULL);
-}
-#endif /* DEBUG */
-
-/*
* When this is called, all of the EFIs which did not have
* corresponding EFDs should be in the AIL. What we do now
* is free the extents associated with each one.
@@ -3080,20 +3054,25 @@ xlog_recover_process_efis(
{
xfs_log_item_t *lip;
xfs_efi_log_item_t *efip;
- int gen;
xfs_mount_t *mp;
int error = 0;
+ struct xfs_ail_cursor cur;
mp = log->l_mp;
spin_lock(&mp->m_ail_lock);
- lip = xfs_trans_first_ail(mp, &gen);
+ xfs_trans_ail_cursor_init(mp->m_ail, &cur);
+ lip = xfs_trans_first_ail(mp, &cur);
while (lip != NULL) {
/*
* We're done when we see something other than an EFI.
+ * There should be no EFIs left in the AIL now.
*/
if (lip->li_type != XFS_LI_EFI) {
- xlog_recover_check_ail(mp, lip, gen);
+#ifdef DEBUG
+ for (; lip; lip = xfs_trans_next_ail(mp, &cur))
+ ASSERT(lip->li_type != XFS_LI_EFI);
+#endif
break;
}
@@ -3102,17 +3081,19 @@ xlog_recover_process_efis(
*/
efip = (xfs_efi_log_item_t *)lip;
if (efip->efi_flags & XFS_EFI_RECOVERED) {
- lip = xfs_trans_next_ail(mp, lip, &gen, NULL);
+ lip = xfs_trans_next_ail(mp, &cur);
continue;
}
spin_unlock(&mp->m_ail_lock);
error = xlog_recover_process_efi(mp, efip);
- if (error)
- return error;
spin_lock(&mp->m_ail_lock);
- lip = xfs_trans_next_ail(mp, lip, &gen, NULL);
+ if (error)
+ goto out;
+ lip = xfs_trans_next_ail(mp, &cur);
}
+out:
+ xfs_trans_ail_cursor_done(mp->m_ail, &cur);
spin_unlock(&mp->m_ail_lock);
return error;
}