Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6
[cascardo/linux.git] / fs / xfs / xfs_buf_item.c
index 2686d0d..ed2b65f 100644 (file)
@@ -142,7 +142,7 @@ xfs_buf_item_log_check(
 #endif
 
 STATIC void    xfs_buf_error_relse(xfs_buf_t *bp);
-STATIC void    xfs_buf_do_callbacks(xfs_buf_t *bp, xfs_log_item_t *lip);
+STATIC void    xfs_buf_do_callbacks(struct xfs_buf *bp);
 
 /*
  * This returns the number of log iovecs needed to log the
@@ -450,7 +450,7 @@ xfs_buf_item_unpin(
                 * xfs_trans_ail_delete() drops the AIL lock.
                 */
                if (bip->bli_flags & XFS_BLI_STALE_INODE) {
-                       xfs_buf_do_callbacks(bp, (xfs_log_item_t *)bip);
+                       xfs_buf_do_callbacks(bp);
                        XFS_BUF_SET_FSPRIVATE(bp, NULL);
                        XFS_BUF_CLR_IODONE_FUNC(bp);
                } else {
@@ -918,15 +918,26 @@ xfs_buf_attach_iodone(
        XFS_BUF_SET_IODONE_FUNC(bp, xfs_buf_iodone_callbacks);
 }
 
+/*
+ * We can have many callbacks on a buffer. Running the callbacks individually
+ * can cause a lot of contention on the AIL lock, so we allow for a single
+ * callback to be able to scan the remaining lip->li_bio_list for other items
+ * of the same type and callback to be processed in the first call.
+ *
+ * As a result, the loop walking the callback list below will also modify the
+ * list. it removes the first item from the list and then runs the callback.
+ * The loop then restarts from the new head of the list. This allows the
+ * callback to scan and modify the list attached to the buffer and we don't
+ * have to care about maintaining a next item pointer.
+ */
 STATIC void
 xfs_buf_do_callbacks(
-       xfs_buf_t       *bp,
-       xfs_log_item_t  *lip)
+       struct xfs_buf          *bp)
 {
-       xfs_log_item_t  *nlip;
+       struct xfs_log_item     *lip;
 
-       while (lip != NULL) {
-               nlip = lip->li_bio_list;
+       while ((lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *)) != NULL) {
+               XFS_BUF_SET_FSPRIVATE(bp, lip->li_bio_list);
                ASSERT(lip->li_cb != NULL);
                /*
                 * Clear the next pointer so we don't have any
@@ -936,7 +947,6 @@ xfs_buf_do_callbacks(
                 */
                lip->li_bio_list = NULL;
                lip->li_cb(bp, lip);
-               lip = nlip;
        }
 }
 
@@ -970,7 +980,7 @@ xfs_buf_iodone_callbacks(
                        ASSERT(XFS_BUF_TARGET(bp) == mp->m_ddev_targp);
                        XFS_BUF_SUPER_STALE(bp);
                        trace_xfs_buf_item_iodone(bp, _RET_IP_);
-                       xfs_buf_do_callbacks(bp, lip);
+                       xfs_buf_do_callbacks(bp);
                        XFS_BUF_SET_FSPRIVATE(bp, NULL);
                        XFS_BUF_CLR_IODONE_FUNC(bp);
                        xfs_buf_ioend(bp, 0);
@@ -1029,7 +1039,7 @@ xfs_buf_iodone_callbacks(
                return;
        }
 
-       xfs_buf_do_callbacks(bp, lip);
+       xfs_buf_do_callbacks(bp);
        XFS_BUF_SET_FSPRIVATE(bp, NULL);
        XFS_BUF_CLR_IODONE_FUNC(bp);
        xfs_buf_ioend(bp, 0);
@@ -1063,7 +1073,7 @@ xfs_buf_error_relse(
         * We have to unpin the pinned buffers so do the
         * callbacks.
         */
-       xfs_buf_do_callbacks(bp, lip);
+       xfs_buf_do_callbacks(bp);
        XFS_BUF_SET_FSPRIVATE(bp, NULL);
        XFS_BUF_CLR_IODONE_FUNC(bp);
        XFS_BUF_SET_BRELSE_FUNC(bp,NULL);