diff options
| author | Michael Ellerman <mpe@ellerman.id.au> | 2017-07-31 20:20:29 +1000 | 
|---|---|---|
| committer | Michael Ellerman <mpe@ellerman.id.au> | 2017-07-31 20:20:29 +1000 | 
| commit | bb272221e9db79f13d454e1f3fb6b05013be985e (patch) | |
| tree | 36f4acc50e3fabac71fadd34c720c0a6011db470 /fs/xfs/xfs_buf.c | |
| parent | 253fd51e2f533552ae35a0c661705da6c4842c1b (diff) | |
| parent | 5771a8c08880cdca3bfb4a3fc6d309d6bba20877 (diff) | |
Merge tag 'v4.13-rc1' into fixes
The fixes branch is based off a random pre-rc1 commit, because we had
some fixes that needed to go in before rc1 was released.
However we now need to fix some code that went in after that point, but
before rc1, so merge rc1 to get that code into fixes so we can fix it!
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)  {  | 
