xfs
[Top] [All Lists]

[PATCH 03/37] xfs: allow assigning the tail lsn with the AIL lock held

To: xfs@xxxxxxxxxxx
Subject: [PATCH 03/37] xfs: allow assigning the tail lsn with the AIL lock held
From: Dave Chinner <david@xxxxxxxxxxxxx>
Date: Mon, 23 Apr 2012 15:58:33 +1000
In-reply-to: <1335160747-17254-1-git-send-email-david@xxxxxxxxxxxxx>
References: <1335160747-17254-1-git-send-email-david@xxxxxxxxxxxxx>
From: Christoph Hellwig <hch@xxxxxxxxxxxxx>

Provide a variant of xlog_assign_tail_lsn that has the AIL lock already
held.  By doing so we do an additional atomic_read + atomic_set under
the lock, which comes down to two instructions.

Switch xfs_trans_ail_update_bulk and xfs_trans_ail_delete_bulk to the
new version to reduce the number of lock roundtrips, and prepare for
a new addition that would require a third lock roundtrip in
xfs_trans_ail_delete_bulk.  This addition is also the reason for
slightly rearranging the conditionals and relying on xfs_log_space_wake
for checking that the filesystem has been shut down internally.

Signed-off-by: Christoph Hellwig <hch@xxxxxx>
Reviewed-by: Dave Chinner <dchinner@xxxxxxxxxx>
Reviewed-by: Mark Tinguely <tinguely@xxxxxxx>
---
 fs/xfs/xfs_log.c        |   31 +++++++++++++++++++++++--------
 fs/xfs/xfs_log.h        |    1 +
 fs/xfs/xfs_trans_ail.c  |   22 +++++++++++++++-------
 fs/xfs/xfs_trans_priv.h |    1 +
 4 files changed, 40 insertions(+), 15 deletions(-)

diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 6db1fef..418d5d7 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -916,27 +916,42 @@ xfs_log_need_covered(xfs_mount_t *mp)
  * We may be holding the log iclog lock upon entering this routine.
  */
 xfs_lsn_t
-xlog_assign_tail_lsn(
+xlog_assign_tail_lsn_locked(
        struct xfs_mount        *mp)
 {
-       xfs_lsn_t               tail_lsn;
        struct log              *log = mp->m_log;
+       struct xfs_log_item     *lip;
+       xfs_lsn_t               tail_lsn;
+
+       assert_spin_locked(&mp->m_ail->xa_lock);
 
        /*
         * To make sure we always have a valid LSN for the log tail we keep
         * track of the last LSN which was committed in log->l_last_sync_lsn,
-        * and use that when the AIL was empty and xfs_ail_min_lsn returns 0.
-        *
-        * If the AIL has been emptied we also need to wake any process
-        * waiting for this condition.
+        * and use that when the AIL was empty.
         */
-       tail_lsn = xfs_ail_min_lsn(mp->m_ail);
-       if (!tail_lsn)
+       lip = xfs_ail_min(mp->m_ail);
+       if (lip)
+               tail_lsn = lip->li_lsn;
+       else
                tail_lsn = atomic64_read(&log->l_last_sync_lsn);
        atomic64_set(&log->l_tail_lsn, tail_lsn);
        return tail_lsn;
 }
 
+xfs_lsn_t
+xlog_assign_tail_lsn(
+       struct xfs_mount        *mp)
+{
+       xfs_lsn_t               tail_lsn;
+
+       spin_lock(&mp->m_ail->xa_lock);
+       tail_lsn = xlog_assign_tail_lsn_locked(mp);
+       spin_unlock(&mp->m_ail->xa_lock);
+
+       return tail_lsn;
+}
+
 /*
  * Return the space in the log between the tail and the head.  The head
  * is passed in the cycle/bytes formal parms.  In the special case where
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
index 2c622be..748d312 100644
--- a/fs/xfs/xfs_log.h
+++ b/fs/xfs/xfs_log.h
@@ -152,6 +152,7 @@ int   xfs_log_mount(struct xfs_mount        *mp,
                        int                     num_bblocks);
 int      xfs_log_mount_finish(struct xfs_mount *mp);
 xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp);
+xfs_lsn_t xlog_assign_tail_lsn_locked(struct xfs_mount *mp);
 void     xfs_log_space_wake(struct xfs_mount *mp);
 int      xfs_log_notify(struct xfs_mount       *mp,
                         struct xlog_in_core    *iclog,
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index 1dead07..77acc53 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -79,7 +79,7 @@ xfs_ail_check(
  * Return a pointer to the first item in the AIL.  If the AIL is empty, then
  * return NULL.
  */
-static xfs_log_item_t *
+xfs_log_item_t *
 xfs_ail_min(
        struct xfs_ail  *ailp)
 {
@@ -667,11 +667,15 @@ xfs_trans_ail_update_bulk(
 
        if (!list_empty(&tmp))
                xfs_ail_splice(ailp, cur, &tmp, lsn);
-       spin_unlock(&ailp->xa_lock);
 
-       if (mlip_changed && !XFS_FORCED_SHUTDOWN(ailp->xa_mount)) {
-               xlog_assign_tail_lsn(ailp->xa_mount);
+       if (mlip_changed) {
+               if (!XFS_FORCED_SHUTDOWN(ailp->xa_mount))
+                       xlog_assign_tail_lsn_locked(ailp->xa_mount);
+               spin_unlock(&ailp->xa_lock);
+
                xfs_log_space_wake(ailp->xa_mount);
+       } else {
+               spin_unlock(&ailp->xa_lock);
        }
 }
 
@@ -729,11 +733,15 @@ xfs_trans_ail_delete_bulk(
                if (mlip == lip)
                        mlip_changed = 1;
        }
-       spin_unlock(&ailp->xa_lock);
 
-       if (mlip_changed && !XFS_FORCED_SHUTDOWN(ailp->xa_mount)) {
-               xlog_assign_tail_lsn(ailp->xa_mount);
+       if (mlip_changed) {
+               if (!XFS_FORCED_SHUTDOWN(ailp->xa_mount))
+                       xlog_assign_tail_lsn_locked(ailp->xa_mount);
+               spin_unlock(&ailp->xa_lock);
+
                xfs_log_space_wake(ailp->xa_mount);
+       } else {
+               spin_unlock(&ailp->xa_lock);
        }
 }
 
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index 8ab2ced..46a1ebd 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -102,6 +102,7 @@ xfs_trans_ail_delete(
 
 void                   xfs_ail_push(struct xfs_ail *, xfs_lsn_t);
 void                   xfs_ail_push_all(struct xfs_ail *);
+struct xfs_log_item    *xfs_ail_min(struct xfs_ail  *ailp);
 xfs_lsn_t              xfs_ail_min_lsn(struct xfs_ail *ailp);
 
 struct xfs_log_item *  xfs_trans_ail_cursor_first(struct xfs_ail *ailp,
-- 
1.7.9.5

<Prev in Thread] Current Thread [Next in Thread>