|
@@ -2047,6 +2047,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)
|
|
|
{
|