diff options
author | Dave Chinner <dchinner@redhat.com> | 2014-12-03 17:43:13 -0500 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2014-12-03 17:43:13 -0500 |
commit | 2d3d0c53df99587e1d58759f805c3aae79fac453 (patch) | |
tree | 0ee91663769ac5c8b3e67d833a596efa1a15b72d /fs/xfs | |
parent | cdc9cec7c0ff521edf8c0e9c9432bf8fdccfc702 (diff) |
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: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_trans_buf.c | 135 |
1 files changed, 33 insertions, 102 deletions
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index e2b2216b1635..2f363cdd1e14 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c | |||
@@ -229,13 +229,6 @@ xfs_trans_getsb(xfs_trans_t *tp, | |||
229 | return bp; | 229 | return bp; |
230 | } | 230 | } |
231 | 231 | ||
232 | #ifdef DEBUG | ||
233 | xfs_buftarg_t *xfs_error_target; | ||
234 | int xfs_do_error; | ||
235 | int xfs_req_num; | ||
236 | int xfs_error_mod = 33; | ||
237 | #endif | ||
238 | |||
239 | /* | 232 | /* |
240 | * Get and lock the buffer for the caller if it is not already | 233 | * Get and lock the buffer for the caller if it is not already |
241 | * locked within the given transaction. If it has not yet been | 234 | * locked within the given transaction. If it has not yet been |
@@ -257,46 +250,11 @@ xfs_trans_read_buf_map( | |||
257 | struct xfs_buf **bpp, | 250 | struct xfs_buf **bpp, |
258 | const struct xfs_buf_ops *ops) | 251 | const struct xfs_buf_ops *ops) |
259 | { | 252 | { |
260 | xfs_buf_t *bp; | 253 | struct xfs_buf *bp = NULL; |
261 | xfs_buf_log_item_t *bip; | 254 | struct xfs_buf_log_item *bip; |
262 | int error; | 255 | int error; |
263 | 256 | ||
264 | *bpp = NULL; | 257 | *bpp = NULL; |
265 | if (!tp) { | ||
266 | bp = xfs_buf_read_map(target, map, nmaps, flags, ops); | ||
267 | if (!bp) | ||
268 | return (flags & XBF_TRYLOCK) ? | ||
269 | -EAGAIN : -ENOMEM; | ||
270 | |||
271 | if (bp->b_error) { | ||
272 | error = bp->b_error; | ||
273 | xfs_buf_ioerror_alert(bp, __func__); | ||
274 | XFS_BUF_UNDONE(bp); | ||
275 | xfs_buf_stale(bp); | ||
276 | xfs_buf_relse(bp); | ||
277 | |||
278 | /* bad CRC means corrupted metadata */ | ||
279 | if (error == -EFSBADCRC) | ||
280 | error = -EFSCORRUPTED; | ||
281 | return error; | ||
282 | } | ||
283 | #ifdef DEBUG | ||
284 | if (xfs_do_error) { | ||
285 | if (xfs_error_target == target) { | ||
286 | if (((xfs_req_num++) % xfs_error_mod) == 0) { | ||
287 | xfs_buf_relse(bp); | ||
288 | xfs_debug(mp, "Returning error!"); | ||
289 | return -EIO; | ||
290 | } | ||
291 | } | ||
292 | } | ||
293 | #endif | ||
294 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
295 | goto shutdown_abort; | ||
296 | *bpp = bp; | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | /* | 258 | /* |
301 | * If we find the buffer in the cache with this transaction | 259 | * If we find the buffer in the cache with this transaction |
302 | * pointer in its b_fsprivate2 field, then we know we already | 260 | * pointer in its b_fsprivate2 field, then we know we already |
@@ -305,49 +263,24 @@ xfs_trans_read_buf_map( | |||
305 | * If the buffer is not yet read in, then we read it in, increment | 263 | * If the buffer is not yet read in, then we read it in, increment |
306 | * the lock recursion count, and return it to the caller. | 264 | * the lock recursion count, and return it to the caller. |
307 | */ | 265 | */ |
308 | bp = xfs_trans_buf_item_match(tp, target, map, nmaps); | 266 | if (tp) |
309 | if (bp != NULL) { | 267 | bp = xfs_trans_buf_item_match(tp, target, map, nmaps); |
268 | if (bp) { | ||
310 | ASSERT(xfs_buf_islocked(bp)); | 269 | ASSERT(xfs_buf_islocked(bp)); |
311 | ASSERT(bp->b_transp == tp); | 270 | ASSERT(bp->b_transp == tp); |
312 | ASSERT(bp->b_fspriv != NULL); | 271 | ASSERT(bp->b_fspriv != NULL); |
313 | ASSERT(!bp->b_error); | 272 | ASSERT(!bp->b_error); |
314 | if (!(XFS_BUF_ISDONE(bp))) { | 273 | ASSERT(bp->b_flags & XBF_DONE); |
315 | trace_xfs_trans_read_buf_io(bp, _RET_IP_); | 274 | |
316 | ASSERT(!XFS_BUF_ISASYNC(bp)); | ||
317 | ASSERT(bp->b_iodone == NULL); | ||
318 | XFS_BUF_READ(bp); | ||
319 | bp->b_ops = ops; | ||
320 | |||
321 | error = xfs_buf_submit_wait(bp); | ||
322 | if (error) { | ||
323 | if (!XFS_FORCED_SHUTDOWN(mp)) | ||
324 | xfs_buf_ioerror_alert(bp, __func__); | ||
325 | xfs_buf_relse(bp); | ||
326 | /* | ||
327 | * We can gracefully recover from most read | ||
328 | * errors. Ones we can't are those that happen | ||
329 | * after the transaction's already dirty. | ||
330 | */ | ||
331 | if (tp->t_flags & XFS_TRANS_DIRTY) | ||
332 | xfs_force_shutdown(tp->t_mountp, | ||
333 | SHUTDOWN_META_IO_ERROR); | ||
334 | /* bad CRC means corrupted metadata */ | ||
335 | if (error == -EFSBADCRC) | ||
336 | error = -EFSCORRUPTED; | ||
337 | return error; | ||
338 | } | ||
339 | } | ||
340 | /* | 275 | /* |
341 | * We never locked this buf ourselves, so we shouldn't | 276 | * We never locked this buf ourselves, so we shouldn't |
342 | * brelse it either. Just get out. | 277 | * brelse it either. Just get out. |
343 | */ | 278 | */ |
344 | if (XFS_FORCED_SHUTDOWN(mp)) { | 279 | if (XFS_FORCED_SHUTDOWN(mp)) { |
345 | trace_xfs_trans_read_buf_shut(bp, _RET_IP_); | 280 | trace_xfs_trans_read_buf_shut(bp, _RET_IP_); |
346 | *bpp = NULL; | ||
347 | return -EIO; | 281 | return -EIO; |
348 | } | 282 | } |
349 | 283 | ||
350 | |||
351 | bip = bp->b_fspriv; | 284 | bip = bp->b_fspriv; |
352 | bip->bli_recur++; | 285 | bip->bli_recur++; |
353 | 286 | ||
@@ -358,17 +291,29 @@ xfs_trans_read_buf_map( | |||
358 | } | 291 | } |
359 | 292 | ||
360 | bp = xfs_buf_read_map(target, map, nmaps, flags, ops); | 293 | bp = xfs_buf_read_map(target, map, nmaps, flags, ops); |
361 | if (bp == NULL) { | 294 | if (!bp) { |
362 | *bpp = NULL; | 295 | if (!(flags & XBF_TRYLOCK)) |
363 | return (flags & XBF_TRYLOCK) ? | 296 | return -ENOMEM; |
364 | 0 : -ENOMEM; | 297 | return tp ? 0 : -EAGAIN; |
365 | } | 298 | } |
299 | |||
300 | /* | ||
301 | * If we've had a read error, then the contents of the buffer are | ||
302 | * invalid and should not be used. To ensure that a followup read tries | ||
303 | * to pull the buffer from disk again, we clear the XBF_DONE flag and | ||
304 | * mark the buffer stale. This ensures that anyone who has a current | ||
305 | * reference to the buffer will interpret it's contents correctly and | ||
306 | * future cache lookups will also treat it as an empty, uninitialised | ||
307 | * buffer. | ||
308 | */ | ||
366 | if (bp->b_error) { | 309 | if (bp->b_error) { |
367 | error = bp->b_error; | 310 | error = bp->b_error; |
311 | if (!XFS_FORCED_SHUTDOWN(mp)) | ||
312 | xfs_buf_ioerror_alert(bp, __func__); | ||
313 | bp->b_flags &= ~XBF_DONE; | ||
368 | xfs_buf_stale(bp); | 314 | xfs_buf_stale(bp); |
369 | XFS_BUF_DONE(bp); | 315 | |
370 | xfs_buf_ioerror_alert(bp, __func__); | 316 | if (tp && (tp->t_flags & XFS_TRANS_DIRTY)) |
371 | if (tp->t_flags & XFS_TRANS_DIRTY) | ||
372 | xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR); | 317 | xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR); |
373 | xfs_buf_relse(bp); | 318 | xfs_buf_relse(bp); |
374 | 319 | ||
@@ -377,33 +322,19 @@ xfs_trans_read_buf_map( | |||
377 | error = -EFSCORRUPTED; | 322 | error = -EFSCORRUPTED; |
378 | return error; | 323 | return error; |
379 | } | 324 | } |
380 | #ifdef DEBUG | 325 | |
381 | if (xfs_do_error && !(tp->t_flags & XFS_TRANS_DIRTY)) { | 326 | if (XFS_FORCED_SHUTDOWN(mp)) { |
382 | if (xfs_error_target == target) { | 327 | xfs_buf_relse(bp); |
383 | if (((xfs_req_num++) % xfs_error_mod) == 0) { | 328 | trace_xfs_trans_read_buf_shut(bp, _RET_IP_); |
384 | xfs_force_shutdown(tp->t_mountp, | 329 | return -EIO; |
385 | SHUTDOWN_META_IO_ERROR); | ||
386 | xfs_buf_relse(bp); | ||
387 | xfs_debug(mp, "Returning trans error!"); | ||
388 | return -EIO; | ||
389 | } | ||
390 | } | ||
391 | } | 330 | } |
392 | #endif | ||
393 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
394 | goto shutdown_abort; | ||
395 | 331 | ||
396 | _xfs_trans_bjoin(tp, bp, 1); | 332 | if (tp) |
333 | _xfs_trans_bjoin(tp, bp, 1); | ||
397 | trace_xfs_trans_read_buf(bp->b_fspriv); | 334 | trace_xfs_trans_read_buf(bp->b_fspriv); |
398 | |||
399 | *bpp = bp; | 335 | *bpp = bp; |
400 | return 0; | 336 | return 0; |
401 | 337 | ||
402 | shutdown_abort: | ||
403 | trace_xfs_trans_read_buf_shut(bp, _RET_IP_); | ||
404 | xfs_buf_relse(bp); | ||
405 | *bpp = NULL; | ||
406 | return -EIO; | ||
407 | } | 338 | } |
408 | 339 | ||
409 | /* | 340 | /* |