Skip to content

Commit

Permalink
[XFS] Use a cursor for AIL traversal.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Chinner authored and Lachlan McIlroy committed Oct 30, 2008
1 parent 82fa901 commit 27d8d5f
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 109 deletions.
4 changes: 2 additions & 2 deletions fs/xfs/xfs_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ xfs_log_move_tail(xfs_mount_t *mp,
int
xfs_log_need_covered(xfs_mount_t *mp)
{
int needed = 0, gen;
int needed = 0;
xlog_t *log = mp->m_log;

if (!xfs_fs_writable(mp))
Expand All @@ -909,7 +909,7 @@ xfs_log_need_covered(xfs_mount_t *mp)
spin_lock(&log->l_icloglock);
if (((log->l_covered_state == XLOG_STATE_COVER_NEED) ||
(log->l_covered_state == XLOG_STATE_COVER_NEED2))
&& !xfs_trans_first_ail(mp, &gen)
&& !xfs_trans_first_ail(mp, NULL)
&& xlog_iclogs_empty(log)) {
if (log->l_covered_state == XLOG_STATE_COVER_NEED)
log->l_covered_state = XLOG_STATE_COVER_DONE;
Expand Down
61 changes: 21 additions & 40 deletions fs/xfs/xfs_log_recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
}

Expand Down Expand Up @@ -3029,33 +3030,6 @@ xlog_recover_process_efi(
return 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
Expand All @@ -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;
}

Expand All @@ -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;
}
Expand Down
Loading

0 comments on commit 27d8d5f

Please sign in to comment.