Commit 2d3d0c53 authored by Dave Chinner's avatar Dave Chinner Committed by Dave Chinner

xfs: lobotomise xfs_trans_read_buf_map()

There's a case in that code where it checks for a buffer match in a
transaction where the buffer is not marked done. i.e. trying to
catch a buffer we have locked in the transaction but have not
completed IO on.

The only way we can find a buffer that has not had IO completed on
it is if it had readahead issued on it, but we never do readahead on
buffers that we have already joined into a transaction. Hence this
condition cannot occur, and buffers locked and joined into a
transaction should always be marked done and not under IO.

Remove this code and re-order xfs_trans_read_buf_map() to remove
duplicated IO dispatch and error handling code.
Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent cdc9cec7
...@@ -229,13 +229,6 @@ xfs_trans_getsb(xfs_trans_t *tp, ...@@ -229,13 +229,6 @@ xfs_trans_getsb(xfs_trans_t *tp,
return bp; return bp;
} }
#ifdef DEBUG
xfs_buftarg_t *xfs_error_target;
int xfs_do_error;
int xfs_req_num;
int xfs_error_mod = 33;
#endif
/* /*
* Get and lock the buffer for the caller if it is not already * Get and lock the buffer for the caller if it is not already
* locked within the given transaction. If it has not yet been * locked within the given transaction. If it has not yet been
...@@ -257,46 +250,11 @@ xfs_trans_read_buf_map( ...@@ -257,46 +250,11 @@ xfs_trans_read_buf_map(
struct xfs_buf **bpp, struct xfs_buf **bpp,
const struct xfs_buf_ops *ops) const struct xfs_buf_ops *ops)
{ {
xfs_buf_t *bp; struct xfs_buf *bp = NULL;
xfs_buf_log_item_t *bip; struct xfs_buf_log_item *bip;
int error; int error;
*bpp = NULL; *bpp = NULL;
if (!tp) {
bp = xfs_buf_read_map(target, map, nmaps, flags, ops);
if (!bp)
return (flags & XBF_TRYLOCK) ?
-EAGAIN : -ENOMEM;
if (bp->b_error) {
error = bp->b_error;
xfs_buf_ioerror_alert(bp, __func__);
XFS_BUF_UNDONE(bp);
xfs_buf_stale(bp);
xfs_buf_relse(bp);
/* bad CRC means corrupted metadata */
if (error == -EFSBADCRC)
error = -EFSCORRUPTED;
return error;
}
#ifdef DEBUG
if (xfs_do_error) {
if (xfs_error_target == target) {
if (((xfs_req_num++) % xfs_error_mod) == 0) {
xfs_buf_relse(bp);
xfs_debug(mp, "Returning error!");
return -EIO;
}
}
}
#endif
if (XFS_FORCED_SHUTDOWN(mp))
goto shutdown_abort;
*bpp = bp;
return 0;
}
/* /*
* If we find the buffer in the cache with this transaction * If we find the buffer in the cache with this transaction
* pointer in its b_fsprivate2 field, then we know we already * pointer in its b_fsprivate2 field, then we know we already
...@@ -305,49 +263,24 @@ xfs_trans_read_buf_map( ...@@ -305,49 +263,24 @@ xfs_trans_read_buf_map(
* If the buffer is not yet read in, then we read it in, increment * If the buffer is not yet read in, then we read it in, increment
* the lock recursion count, and return it to the caller. * the lock recursion count, and return it to the caller.
*/ */
bp = xfs_trans_buf_item_match(tp, target, map, nmaps); if (tp)
if (bp != NULL) { bp = xfs_trans_buf_item_match(tp, target, map, nmaps);
if (bp) {
ASSERT(xfs_buf_islocked(bp)); ASSERT(xfs_buf_islocked(bp));
ASSERT(bp->b_transp == tp); ASSERT(bp->b_transp == tp);
ASSERT(bp->b_fspriv != NULL); ASSERT(bp->b_fspriv != NULL);
ASSERT(!bp->b_error); ASSERT(!bp->b_error);
if (!(XFS_BUF_ISDONE(bp))) { ASSERT(bp->b_flags & XBF_DONE);
trace_xfs_trans_read_buf_io(bp, _RET_IP_);
ASSERT(!XFS_BUF_ISASYNC(bp));
ASSERT(bp->b_iodone == NULL);
XFS_BUF_READ(bp);
bp->b_ops = ops;
error = xfs_buf_submit_wait(bp);
if (error) {
if (!XFS_FORCED_SHUTDOWN(mp))
xfs_buf_ioerror_alert(bp, __func__);
xfs_buf_relse(bp);
/*
* We can gracefully recover from most read
* errors. Ones we can't are those that happen
* after the transaction's already dirty.
*/
if (tp->t_flags & XFS_TRANS_DIRTY)
xfs_force_shutdown(tp->t_mountp,
SHUTDOWN_META_IO_ERROR);
/* bad CRC means corrupted metadata */
if (error == -EFSBADCRC)
error = -EFSCORRUPTED;
return error;
}
}
/* /*
* We never locked this buf ourselves, so we shouldn't * We never locked this buf ourselves, so we shouldn't
* brelse it either. Just get out. * brelse it either. Just get out.
*/ */
if (XFS_FORCED_SHUTDOWN(mp)) { if (XFS_FORCED_SHUTDOWN(mp)) {
trace_xfs_trans_read_buf_shut(bp, _RET_IP_); trace_xfs_trans_read_buf_shut(bp, _RET_IP_);
*bpp = NULL;
return -EIO; return -EIO;
} }
bip = bp->b_fspriv; bip = bp->b_fspriv;
bip->bli_recur++; bip->bli_recur++;
...@@ -358,17 +291,29 @@ xfs_trans_read_buf_map( ...@@ -358,17 +291,29 @@ xfs_trans_read_buf_map(
} }
bp = xfs_buf_read_map(target, map, nmaps, flags, ops); bp = xfs_buf_read_map(target, map, nmaps, flags, ops);
if (bp == NULL) { if (!bp) {
*bpp = NULL; if (!(flags & XBF_TRYLOCK))
return (flags & XBF_TRYLOCK) ? return -ENOMEM;
0 : -ENOMEM; return tp ? 0 : -EAGAIN;
} }
/*
* If we've had a read error, then the contents of the buffer are
* invalid and should not be used. To ensure that a followup read tries
* to pull the buffer from disk again, we clear the XBF_DONE flag and
* mark the buffer stale. This ensures that anyone who has a current
* reference to the buffer will interpret it's contents correctly and
* future cache lookups will also treat it as an empty, uninitialised
* buffer.
*/
if (bp->b_error) { if (bp->b_error) {
error = bp->b_error; error = bp->b_error;
if (!XFS_FORCED_SHUTDOWN(mp))
xfs_buf_ioerror_alert(bp, __func__);
bp->b_flags &= ~XBF_DONE;
xfs_buf_stale(bp); xfs_buf_stale(bp);
XFS_BUF_DONE(bp);
xfs_buf_ioerror_alert(bp, __func__); if (tp && (tp->t_flags & XFS_TRANS_DIRTY))
if (tp->t_flags & XFS_TRANS_DIRTY)
xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR); xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR);
xfs_buf_relse(bp); xfs_buf_relse(bp);
...@@ -377,33 +322,19 @@ xfs_trans_read_buf_map( ...@@ -377,33 +322,19 @@ xfs_trans_read_buf_map(
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
return error; return error;
} }
#ifdef DEBUG
if (xfs_do_error && !(tp->t_flags & XFS_TRANS_DIRTY)) { if (XFS_FORCED_SHUTDOWN(mp)) {
if (xfs_error_target == target) { xfs_buf_relse(bp);
if (((xfs_req_num++) % xfs_error_mod) == 0) { trace_xfs_trans_read_buf_shut(bp, _RET_IP_);
xfs_force_shutdown(tp->t_mountp, return -EIO;
SHUTDOWN_META_IO_ERROR);
xfs_buf_relse(bp);
xfs_debug(mp, "Returning trans error!");
return -EIO;
}
}
} }
#endif
if (XFS_FORCED_SHUTDOWN(mp))
goto shutdown_abort;
_xfs_trans_bjoin(tp, bp, 1); if (tp)
_xfs_trans_bjoin(tp, bp, 1);
trace_xfs_trans_read_buf(bp->b_fspriv); trace_xfs_trans_read_buf(bp->b_fspriv);
*bpp = bp; *bpp = bp;
return 0; return 0;
shutdown_abort:
trace_xfs_trans_read_buf_shut(bp, _RET_IP_);
xfs_buf_relse(bp);
*bpp = NULL;
return -EIO;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment