xfs: prevent lockdep false positive in xfs_iget_cache_miss
[safe/jmp/linux-2.6] / fs / xfs / xfs_trans_ail.c
index 7b8bfcf..2d47f10 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2008 Dave Chinner
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -50,20 +51,20 @@ STATIC void xfs_ail_check(struct xfs_ail *, xfs_log_item_t *);
  * lsn of the last item in the AIL.
  */
 xfs_lsn_t
-xfs_trans_tail_ail(
-       xfs_mount_t     *mp)
+xfs_trans_ail_tail(
+       struct xfs_ail  *ailp)
 {
        xfs_lsn_t       lsn;
        xfs_log_item_t  *lip;
 
-       spin_lock(&mp->m_ail_lock);
-       lip = xfs_ail_min(mp->m_ail);
+       spin_lock(&ailp->xa_lock);
+       lip = xfs_ail_min(ailp);
        if (lip == NULL) {
                lsn = (xfs_lsn_t)0;
        } else {
                lsn = lip->li_lsn;
        }
-       spin_unlock(&mp->m_ail_lock);
+       spin_unlock(&ailp->xa_lock);
 
        return lsn;
 }
@@ -85,16 +86,16 @@ xfs_trans_tail_ail(
  * any of the objects, so the lock is not needed.
  */
 void
-xfs_trans_push_ail(
-       xfs_mount_t             *mp,
-       xfs_lsn_t               threshold_lsn)
+xfs_trans_ail_push(
+       struct xfs_ail  *ailp,
+       xfs_lsn_t       threshold_lsn)
 {
-       xfs_log_item_t          *lip;
+       xfs_log_item_t  *lip;
 
-       lip = xfs_ail_min(mp->m_ail);
-       if (lip && !XFS_FORCED_SHUTDOWN(mp)) {
-               if (XFS_LSN_CMP(threshold_lsn, mp->m_ail->xa_target) > 0)
-                       xfsaild_wakeup(mp->m_ail, threshold_lsn);
+       lip = xfs_ail_min(ailp);
+       if (lip && !XFS_FORCED_SHUTDOWN(ailp->xa_mount)) {
+               if (XFS_LSN_CMP(threshold_lsn, ailp->xa_target) > 0)
+                       xfsaild_wakeup(ailp, threshold_lsn);
        }
 }
 
@@ -111,7 +112,7 @@ xfs_trans_push_ail(
  * We don't link the push cursor because it is embedded in the struct
  * xfs_ail and hence easily findable.
  */
-void
+STATIC void
 xfs_trans_ail_cursor_init(
        struct xfs_ail          *ailp,
        struct xfs_ail_cursor   *cur)
@@ -143,7 +144,7 @@ xfs_trans_ail_cursor_set(
  * If the cursor was invalidated (inidicated by a lip of 1),
  * restart the traversal.
  */
-STATIC struct xfs_log_item *
+struct xfs_log_item *
 xfs_trans_ail_cursor_next(
        struct xfs_ail          *ailp,
        struct xfs_ail_cursor   *cur)
@@ -157,30 +158,6 @@ xfs_trans_ail_cursor_next(
 }
 
 /*
- * Invalidate any cursor that is pointing to this item. This is
- * called when an item is removed from the AIL. Any cursor pointing
- * to this object is now invalid and the traversal needs to be
- * terminated so it doesn't reference a freed object. We set the
- * cursor item to a value of 1 so we can distinguish between an
- * invalidation and the end of the list when getting the next item
- * from the cursor.
- */
-STATIC void
-xfs_trans_ail_cursor_clear(
-       struct xfs_ail          *ailp,
-       struct xfs_log_item     *lip)
-{
-       struct xfs_ail_cursor   *cur;
-
-       /* need to search all cursors */
-       for (cur = &ailp->xa_cursors; cur; cur = cur->next) {
-               if (cur->item == lip)
-                       cur->item = (struct xfs_log_item *)
-                                       ((__psint_t)cur->item | 1);
-       }
-}
-
-/*
  * Now that the traversal is complete, we need to remove the cursor
  * from the list of traversing cursors. Avoid removing the embedded
  * push cursor, but use the fact it is alway present to make the
@@ -208,31 +185,55 @@ xfs_trans_ail_cursor_done(
 }
 
 /*
+ * Invalidate any cursor that is pointing to this item. This is
+ * called when an item is removed from the AIL. Any cursor pointing
+ * to this object is now invalid and the traversal needs to be
+ * terminated so it doesn't reference a freed object. We set the
+ * cursor item to a value of 1 so we can distinguish between an
+ * invalidation and the end of the list when getting the next item
+ * from the cursor.
+ */
+STATIC void
+xfs_trans_ail_cursor_clear(
+       struct xfs_ail          *ailp,
+       struct xfs_log_item     *lip)
+{
+       struct xfs_ail_cursor   *cur;
+
+       /* need to search all cursors */
+       for (cur = &ailp->xa_cursors; cur; cur = cur->next) {
+               if (cur->item == lip)
+                       cur->item = (struct xfs_log_item *)
+                                       ((__psint_t)cur->item | 1);
+       }
+}
+
+/*
  * Return the item in the AIL with the current lsn.
  * Return the current tree generation number for use
  * in calls to xfs_trans_next_ail().
  */
-STATIC xfs_log_item_t *
-xfs_trans_first_push_ail(
+xfs_log_item_t *
+xfs_trans_ail_cursor_first(
        struct xfs_ail          *ailp,
        struct xfs_ail_cursor   *cur,
        xfs_lsn_t               lsn)
 {
        xfs_log_item_t          *lip;
 
+       xfs_trans_ail_cursor_init(ailp, cur);
        lip = xfs_ail_min(ailp);
-       xfs_trans_ail_cursor_set(ailp, cur, lip);
        if (lsn == 0)
-               return lip;
+               goto out;
 
        list_for_each_entry(lip, &ailp->xa_ail, li_ail) {
-               if (XFS_LSN_CMP(lip->li_lsn, lsn) >= 0) {
-                       xfs_trans_ail_cursor_set(ailp, cur, lip);
-                       return lip;
-               }
+               if (XFS_LSN_CMP(lip->li_lsn, lsn) >= 0)
+                       goto out;
        }
-
-       return NULL;
+       lip = NULL;
+out:
+       xfs_trans_ail_cursor_set(ailp, cur, lip);
+       return lip;
 }
 
 /*
@@ -252,15 +253,15 @@ xfsaild_push(
        xfs_mount_t     *mp = ailp->xa_mount;
        struct xfs_ail_cursor   *cur = &ailp->xa_cursors;
 
-       spin_lock(&mp->m_ail_lock);
+       spin_lock(&ailp->xa_lock);
        xfs_trans_ail_cursor_init(ailp, cur);
-       lip = xfs_trans_first_push_ail(ailp, cur, *last_lsn);
+       lip = xfs_trans_ail_cursor_first(ailp, cur, *last_lsn);
        if (!lip || XFS_FORCED_SHUTDOWN(mp)) {
                /*
                 * AIL is empty or our push has reached the end.
                 */
                xfs_trans_ail_cursor_done(ailp, cur);
-               spin_unlock(&mp->m_ail_lock);
+               spin_unlock(&ailp->xa_lock);
                last_pushed_lsn = 0;
                return tout;
        }
@@ -295,7 +296,7 @@ xfsaild_push(
                 * skip to the next item in the list.
                 */
                lock_result = IOP_TRYLOCK(lip);
-               spin_unlock(&mp->m_ail_lock);
+               spin_unlock(&ailp->xa_lock);
                switch (lock_result) {
                case XFS_ITEM_SUCCESS:
                        XFS_STATS_INC(xs_push_ail_success);
@@ -332,7 +333,7 @@ xfsaild_push(
                        break;
                }
 
-               spin_lock(&mp->m_ail_lock);
+               spin_lock(&ailp->xa_lock);
                /* should we bother continuing? */
                if (XFS_FORCED_SHUTDOWN(mp))
                        break;
@@ -361,7 +362,7 @@ xfsaild_push(
                lsn = lip->li_lsn;
        }
        xfs_trans_ail_cursor_done(ailp, cur);
-       spin_unlock(&mp->m_ail_lock);
+       spin_unlock(&ailp->xa_lock);
 
        if (flush_log) {
                /*
@@ -411,7 +412,7 @@ xfsaild_push(
  */
 void
 xfs_trans_unlocked_item(
-       xfs_mount_t     *mp,
+       struct xfs_ail  *ailp,
        xfs_log_item_t  *lip)
 {
        xfs_log_item_t  *min_lip;
@@ -423,7 +424,7 @@ xfs_trans_unlocked_item(
         * over some potentially valid data.
         */
        if (!(lip->li_flags & XFS_LI_IN_AIL) ||
-           XFS_FORCED_SHUTDOWN(mp)) {
+           XFS_FORCED_SHUTDOWN(ailp->xa_mount)) {
                return;
        }
 
@@ -439,10 +440,10 @@ xfs_trans_unlocked_item(
         * the call to xfs_log_move_tail() doesn't do anything if there's
         * not enough free space to wake people up so we're safe calling it.
         */
-       min_lip = xfs_ail_min(mp->m_ail);
+       min_lip = xfs_ail_min(ailp);
 
        if (min_lip == lip)
-               xfs_log_move_tail(mp, 1);
+               xfs_log_move_tail(ailp->xa_mount, 1);
 }      /* xfs_trans_unlocked_item */
 
 
@@ -459,33 +460,33 @@ xfs_trans_unlocked_item(
  * is dropped before returning.
  */
 void
-xfs_trans_update_ail(
-       xfs_mount_t     *mp,
+xfs_trans_ail_update(
+       struct xfs_ail  *ailp,
        xfs_log_item_t  *lip,
-       xfs_lsn_t       lsn) __releases(mp->m_ail_lock)
+       xfs_lsn_t       lsn) __releases(ailp->xa_lock)
 {
-       xfs_log_item_t          *dlip=NULL;
+       xfs_log_item_t          *dlip = NULL;
        xfs_log_item_t          *mlip;  /* ptr to minimum lip */
 
-       mlip = xfs_ail_min(mp->m_ail);
+       mlip = xfs_ail_min(ailp);
 
        if (lip->li_flags & XFS_LI_IN_AIL) {
-               dlip = xfs_ail_delete(mp->m_ail, lip);
+               dlip = xfs_ail_delete(ailp, lip);
                ASSERT(dlip == lip);
-               xfs_trans_ail_cursor_clear(mp->m_ail, dlip);
+               xfs_trans_ail_cursor_clear(ailp, dlip);
        } else {
                lip->li_flags |= XFS_LI_IN_AIL;
        }
 
        lip->li_lsn = lsn;
-       xfs_ail_insert(mp->m_ail, lip);
+       xfs_ail_insert(ailp, lip);
 
        if (mlip == dlip) {
-               mlip = xfs_ail_min(mp->m_ail);
-               spin_unlock(&mp->m_ail_lock);
-               xfs_log_move_tail(mp, mlip->li_lsn);
+               mlip = xfs_ail_min(ailp);
+               spin_unlock(&ailp->xa_lock);
+               xfs_log_move_tail(ailp->xa_mount, mlip->li_lsn);
        } else {
-               spin_unlock(&mp->m_ail_lock);
+               spin_unlock(&ailp->xa_lock);
        }
 
 
@@ -507,29 +508,30 @@ xfs_trans_update_ail(
  * is dropped before returning.
  */
 void
-xfs_trans_delete_ail(
-       xfs_mount_t     *mp,
-       xfs_log_item_t  *lip) __releases(mp->m_ail_lock)
+xfs_trans_ail_delete(
+       struct xfs_ail  *ailp,
+       xfs_log_item_t  *lip) __releases(ailp->xa_lock)
 {
        xfs_log_item_t          *dlip;
        xfs_log_item_t          *mlip;
 
        if (lip->li_flags & XFS_LI_IN_AIL) {
-               mlip = xfs_ail_min(mp->m_ail);
-               dlip = xfs_ail_delete(mp->m_ail, lip);
+               mlip = xfs_ail_min(ailp);
+               dlip = xfs_ail_delete(ailp, lip);
                ASSERT(dlip == lip);
-               xfs_trans_ail_cursor_clear(mp->m_ail, dlip);
+               xfs_trans_ail_cursor_clear(ailp, dlip);
 
 
                lip->li_flags &= ~XFS_LI_IN_AIL;
                lip->li_lsn = 0;
 
                if (mlip == dlip) {
-                       mlip = xfs_ail_min(mp->m_ail);
-                       spin_unlock(&mp->m_ail_lock);
-                       xfs_log_move_tail(mp, (mlip ? mlip->li_lsn : 0));
+                       mlip = xfs_ail_min(ailp);
+                       spin_unlock(&ailp->xa_lock);
+                       xfs_log_move_tail(ailp->xa_mount,
+                                               (mlip ? mlip->li_lsn : 0));
                } else {
-                       spin_unlock(&mp->m_ail_lock);
+                       spin_unlock(&ailp->xa_lock);
                }
        }
        else {
@@ -537,13 +539,13 @@ xfs_trans_delete_ail(
                 * If the file system is not being shutdown, we are in
                 * serious trouble if we get to this stage.
                 */
-               if (XFS_FORCED_SHUTDOWN(mp))
-                       spin_unlock(&mp->m_ail_lock);
-               else {
+               struct xfs_mount        *mp = ailp->xa_mount;
+
+               spin_unlock(&ailp->xa_lock);
+               if (!XFS_FORCED_SHUTDOWN(mp)) {
                        xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp,
                "%s: attempting to delete a log item that is not in the AIL",
                                        __func__);
-                       spin_unlock(&mp->m_ail_lock);
                        xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
                }
        }
@@ -552,39 +554,6 @@ xfs_trans_delete_ail(
 
 
 /*
- * Return the item in the AIL with the smallest lsn.
- * Return the current tree generation number for use
- * in calls to xfs_trans_next_ail().
- */
-xfs_log_item_t *
-xfs_trans_first_ail(
-       struct xfs_mount        *mp,
-       struct xfs_ail_cursor   *cur)
-{
-       xfs_log_item_t          *lip;
-       struct xfs_ail          *ailp = mp->m_ail;
-
-       lip = xfs_ail_min(ailp);
-       xfs_trans_ail_cursor_set(ailp, cur, lip);
-
-       return lip;
-}
-
-/*
- * Grab the next item in the AIL from the cursor passed in.
- */
-xfs_log_item_t *
-xfs_trans_next_ail(
-       struct xfs_mount        *mp,
-       struct xfs_ail_cursor   *cur)
-{
-       struct xfs_ail          *ailp = mp->m_ail;
-
-       return xfs_trans_ail_cursor_next(ailp, cur);
-}
-
-
-/*
  * The active item list (AIL) is a doubly linked list of log
  * items sorted by ascending lsn.  The base of the list is
  * a forw/back pointer pair embedded in the xfs mount structure.
@@ -611,6 +580,7 @@ xfs_trans_ail_init(
 
        ailp->xa_mount = mp;
        INIT_LIST_HEAD(&ailp->xa_ail);
+       spin_lock_init(&ailp->xa_lock);
        error = xfsaild_start(ailp);
        if (error)
                goto out_free_ailp;