diff options
Diffstat (limited to 'fs/xfs/xfs_buf.c')
| -rw-r--r-- | fs/xfs/xfs_buf.c | 59 | 
1 files changed, 43 insertions, 16 deletions
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 4b0b8dd1b7b..26673a0b20e 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -569,7 +569,9 @@ found:  	 */  	if (bp->b_flags & XBF_STALE) {  		ASSERT((bp->b_flags & _XBF_DELWRI_Q) == 0); +		ASSERT(bp->b_iodone == NULL);  		bp->b_flags &= _XBF_KMEM | _XBF_PAGES; +		bp->b_ops = NULL;  	}  	trace_xfs_buf_find(bp, flags, _RET_IP_); @@ -654,7 +656,8 @@ xfs_buf_read_map(  	struct xfs_buftarg	*target,  	struct xfs_buf_map	*map,  	int			nmaps, -	xfs_buf_flags_t		flags) +	xfs_buf_flags_t		flags, +	const struct xfs_buf_ops *ops)  {  	struct xfs_buf		*bp; @@ -666,6 +669,7 @@ xfs_buf_read_map(  		if (!XFS_BUF_ISDONE(bp)) {  			XFS_STATS_INC(xb_get_read); +			bp->b_ops = ops;  			_xfs_buf_read(bp, flags);  		} else if (flags & XBF_ASYNC) {  			/* @@ -691,13 +695,14 @@ void  xfs_buf_readahead_map(  	struct xfs_buftarg	*target,  	struct xfs_buf_map	*map, -	int			nmaps) +	int			nmaps, +	const struct xfs_buf_ops *ops)  {  	if (bdi_read_congested(target->bt_bdi))  		return;  	xfs_buf_read_map(target, map, nmaps, -		     XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD); +		     XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD, ops);  }  /* @@ -709,10 +714,10 @@ xfs_buf_read_uncached(  	struct xfs_buftarg	*target,  	xfs_daddr_t		daddr,  	size_t			numblks, -	int			flags) +	int			flags, +	const struct xfs_buf_ops *ops)  { -	xfs_buf_t		*bp; -	int			error; +	struct xfs_buf		*bp;  	bp = xfs_buf_get_uncached(target, numblks, flags);  	if (!bp) @@ -723,13 +728,10 @@ xfs_buf_read_uncached(  	bp->b_bn = daddr;  	bp->b_maps[0].bm_bn = daddr;  	bp->b_flags |= XBF_READ; +	bp->b_ops = ops;  	xfsbdstrat(target->bt_mount, bp); -	error = xfs_buf_iowait(bp); -	if (error) { -		xfs_buf_relse(bp); -		return NULL; -	} +	xfs_buf_iowait(bp);  	return bp;  } @@ -999,27 +1001,37 @@ STATIC void  xfs_buf_iodone_work(  	struct work_struct	*work)  { -	xfs_buf_t		*bp = +	struct xfs_buf		*bp =  		container_of(work, xfs_buf_t, b_iodone_work); +	bool			read = !!(bp->b_flags & XBF_READ); + +	bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_READ_AHEAD); +	if (read && bp->b_ops) +		bp->b_ops->verify_read(bp);  	if (bp->b_iodone)  		(*(bp->b_iodone))(bp);  	else if (bp->b_flags & XBF_ASYNC)  		xfs_buf_relse(bp); +	else { +		ASSERT(read && bp->b_ops); +		complete(&bp->b_iowait); +	}  }  void  xfs_buf_ioend( -	xfs_buf_t		*bp, -	int			schedule) +	struct xfs_buf	*bp, +	int		schedule)  { +	bool		read = !!(bp->b_flags & XBF_READ); +  	trace_xfs_buf_iodone(bp, _RET_IP_); -	bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_READ_AHEAD);  	if (bp->b_error == 0)  		bp->b_flags |= XBF_DONE; -	if ((bp->b_iodone) || (bp->b_flags & XBF_ASYNC)) { +	if (bp->b_iodone || (read && bp->b_ops) || (bp->b_flags & XBF_ASYNC)) {  		if (schedule) {  			INIT_WORK(&bp->b_iodone_work, xfs_buf_iodone_work);  			queue_work(xfslogd_workqueue, &bp->b_iodone_work); @@ -1027,6 +1039,7 @@ xfs_buf_ioend(  			xfs_buf_iodone_work(&bp->b_iodone_work);  		}  	} else { +		bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_READ_AHEAD);  		complete(&bp->b_iowait);  	}  } @@ -1314,6 +1327,20 @@ _xfs_buf_ioapply(  			rw |= REQ_FUA;  		if (bp->b_flags & XBF_FLUSH)  			rw |= REQ_FLUSH; + +		/* +		 * Run the write verifier callback function if it exists. If +		 * this function fails it will mark the buffer with an error and +		 * the IO should not be dispatched. +		 */ +		if (bp->b_ops) { +			bp->b_ops->verify_write(bp); +			if (bp->b_error) { +				xfs_force_shutdown(bp->b_target->bt_mount, +						   SHUTDOWN_CORRUPT_INCORE); +				return; +			} +		}  	} else if (bp->b_flags & XBF_READ_AHEAD) {  		rw = READA;  	} else {  |