diff options
Diffstat (limited to 'fs/xfs/xfs_buf.c')
| -rw-r--r-- | fs/xfs/xfs_buf.c | 62 | 
1 files changed, 61 insertions, 1 deletions
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 438505f395e7..72f038492ba8 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -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)  {  | 
