Merge tag 'xfs-4.13-merge-5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[muen/linux.git] / fs / xfs / xfs_buf.c
index 438505f395e76b2f1cf2299a8b77a668ecdbec70..72f038492ba8cdb2bd609fd19949d96b95c8ede0 100644 (file)
@@ -1194,7 +1194,7 @@ xfs_buf_ioerror_alert(
 {
        xfs_alert(bp->b_target->bt_mount,
 "metadata I/O error: block 0x%llx (\"%s\") error %d numblks %d",
-               (__uint64_t)XFS_BUF_ADDR(bp), func, -bp->b_error, bp->b_length);
+               (uint64_t)XFS_BUF_ADDR(bp), func, -bp->b_error, bp->b_length);
 }
 
 int
@@ -2050,6 +2050,66 @@ xfs_buf_delwri_submit(
        return error;
 }
 
+/*
+ * Push a single buffer on a delwri queue.
+ *
+ * The purpose of this function is to submit a single buffer of a delwri queue
+ * and return with the buffer still on the original queue. The waiting delwri
+ * buffer submission infrastructure guarantees transfer of the delwri queue
+ * buffer reference to a temporary wait list. We reuse this infrastructure to
+ * transfer the buffer back to the original queue.
+ *
+ * Note the buffer transitions from the queued state, to the submitted and wait
+ * listed state and back to the queued state during this call. The buffer
+ * locking and queue management logic between _delwri_pushbuf() and
+ * _delwri_queue() guarantee that the buffer cannot be queued to another list
+ * before returning.
+ */
+int
+xfs_buf_delwri_pushbuf(
+       struct xfs_buf          *bp,
+       struct list_head        *buffer_list)
+{
+       LIST_HEAD               (submit_list);
+       int                     error;
+
+       ASSERT(bp->b_flags & _XBF_DELWRI_Q);
+
+       trace_xfs_buf_delwri_pushbuf(bp, _RET_IP_);
+
+       /*
+        * Isolate the buffer to a new local list so we can submit it for I/O
+        * independently from the rest of the original list.
+        */
+       xfs_buf_lock(bp);
+       list_move(&bp->b_list, &submit_list);
+       xfs_buf_unlock(bp);
+
+       /*
+        * Delwri submission clears the DELWRI_Q buffer flag and returns with
+        * the buffer on the wait list with an associated reference. Rather than
+        * bounce the buffer from a local wait list back to the original list
+        * after I/O completion, reuse the original list as the wait list.
+        */
+       xfs_buf_delwri_submit_buffers(&submit_list, buffer_list);
+
+       /*
+        * The buffer is now under I/O and wait listed as during typical delwri
+        * submission. Lock the buffer to wait for I/O completion. Rather than
+        * remove the buffer from the wait list and release the reference, we
+        * want to return with the buffer queued to the original list. The
+        * buffer already sits on the original list with a wait list reference,
+        * however. If we let the queue inherit that wait list reference, all we
+        * need to do is reset the DELWRI_Q flag.
+        */
+       xfs_buf_lock(bp);
+       error = bp->b_error;
+       bp->b_flags |= _XBF_DELWRI_Q;
+       xfs_buf_unlock(bp);
+
+       return error;
+}
+
 int __init
 xfs_buf_init(void)
 {