diff options
-rw-r--r-- | fs/xfs/xfs_buf_item.c | 110 |
1 files changed, 50 insertions, 60 deletions
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 240340a4727b..4cd5f615371d 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c | |||
@@ -341,10 +341,15 @@ xfs_buf_item_format( | |||
341 | } | 341 | } |
342 | 342 | ||
343 | /* | 343 | /* |
344 | * This is called to pin the buffer associated with the buf log | 344 | * This is called to pin the buffer associated with the buf log item in memory |
345 | * item in memory so it cannot be written out. Simply call bpin() | 345 | * so it cannot be written out. Simply call bpin() on the buffer to do this. |
346 | * on the buffer to do this. | 346 | * |
347 | * We also always take a reference to the buffer log item here so that the bli | ||
348 | * is held while the item is pinned in memory. This means that we can | ||
349 | * unconditionally drop the reference count a transaction holds when the | ||
350 | * transaction is completed. | ||
347 | */ | 351 | */ |
352 | |||
348 | STATIC void | 353 | STATIC void |
349 | xfs_buf_item_pin( | 354 | xfs_buf_item_pin( |
350 | xfs_buf_log_item_t *bip) | 355 | xfs_buf_log_item_t *bip) |
@@ -356,6 +361,7 @@ xfs_buf_item_pin( | |||
356 | ASSERT(atomic_read(&bip->bli_refcount) > 0); | 361 | ASSERT(atomic_read(&bip->bli_refcount) > 0); |
357 | ASSERT((bip->bli_flags & XFS_BLI_LOGGED) || | 362 | ASSERT((bip->bli_flags & XFS_BLI_LOGGED) || |
358 | (bip->bli_flags & XFS_BLI_STALE)); | 363 | (bip->bli_flags & XFS_BLI_STALE)); |
364 | atomic_inc(&bip->bli_refcount); | ||
359 | trace_xfs_buf_item_pin(bip); | 365 | trace_xfs_buf_item_pin(bip); |
360 | xfs_bpin(bp); | 366 | xfs_bpin(bp); |
361 | } | 367 | } |
@@ -489,20 +495,23 @@ xfs_buf_item_trylock( | |||
489 | } | 495 | } |
490 | 496 | ||
491 | /* | 497 | /* |
492 | * Release the buffer associated with the buf log item. | 498 | * Release the buffer associated with the buf log item. If there is no dirty |
493 | * If there is no dirty logged data associated with the | 499 | * logged data associated with the buffer recorded in the buf log item, then |
494 | * buffer recorded in the buf log item, then free the | 500 | * free the buf log item and remove the reference to it in the buffer. |
495 | * buf log item and remove the reference to it in the | ||
496 | * buffer. | ||
497 | * | 501 | * |
498 | * This call ignores the recursion count. It is only called | 502 | * This call ignores the recursion count. It is only called when the buffer |
499 | * when the buffer should REALLY be unlocked, regardless | 503 | * should REALLY be unlocked, regardless of the recursion count. |
500 | * of the recursion count. | ||
501 | * | 504 | * |
502 | * If the XFS_BLI_HOLD flag is set in the buf log item, then | 505 | * We unconditionally drop the transaction's reference to the log item. If the |
503 | * free the log item if necessary but do not unlock the buffer. | 506 | * item was logged, then another reference was taken when it was pinned, so we |
504 | * This is for support of xfs_trans_bhold(). Make sure the | 507 | * can safely drop the transaction reference now. This also allows us to avoid |
505 | * XFS_BLI_HOLD field is cleared if we don't free the item. | 508 | * potential races with the unpin code freeing the bli by not referencing the |
509 | * bli after we've dropped the reference count. | ||
510 | * | ||
511 | * If the XFS_BLI_HOLD flag is set in the buf log item, then free the log item | ||
512 | * if necessary but do not unlock the buffer. This is for support of | ||
513 | * xfs_trans_bhold(). Make sure the XFS_BLI_HOLD field is cleared if we don't | ||
514 | * free the item. | ||
506 | */ | 515 | */ |
507 | STATIC void | 516 | STATIC void |
508 | xfs_buf_item_unlock( | 517 | xfs_buf_item_unlock( |
@@ -514,73 +523,54 @@ xfs_buf_item_unlock( | |||
514 | 523 | ||
515 | bp = bip->bli_buf; | 524 | bp = bip->bli_buf; |
516 | 525 | ||
517 | /* | 526 | /* Clear the buffer's association with this transaction. */ |
518 | * Clear the buffer's association with this transaction. | ||
519 | */ | ||
520 | XFS_BUF_SET_FSPRIVATE2(bp, NULL); | 527 | XFS_BUF_SET_FSPRIVATE2(bp, NULL); |
521 | 528 | ||
522 | /* | 529 | /* |
523 | * If this is a transaction abort, don't return early. | 530 | * If this is a transaction abort, don't return early. Instead, allow |
524 | * Instead, allow the brelse to happen. | 531 | * the brelse to happen. Normally it would be done for stale |
525 | * Normally it would be done for stale (cancelled) buffers | 532 | * (cancelled) buffers at unpin time, but we'll never go through the |
526 | * at unpin time, but we'll never go through the pin/unpin | 533 | * pin/unpin cycle if we abort inside commit. |
527 | * cycle if we abort inside commit. | ||
528 | */ | 534 | */ |
529 | aborted = (bip->bli_item.li_flags & XFS_LI_ABORTED) != 0; | 535 | aborted = (bip->bli_item.li_flags & XFS_LI_ABORTED) != 0; |
530 | 536 | ||
531 | /* | 537 | /* |
532 | * If the buf item is marked stale, then don't do anything. | 538 | * Before possibly freeing the buf item, determine if we should |
533 | * We'll unlock the buffer and free the buf item when the | 539 | * release the buffer at the end of this routine. |
534 | * buffer is unpinned for the last time. | 540 | */ |
541 | hold = bip->bli_flags & XFS_BLI_HOLD; | ||
542 | |||
543 | /* Clear the per transaction state. */ | ||
544 | bip->bli_flags &= ~(XFS_BLI_LOGGED | XFS_BLI_HOLD); | ||
545 | |||
546 | /* | ||
547 | * If the buf item is marked stale, then don't do anything. We'll | ||
548 | * unlock the buffer and free the buf item when the buffer is unpinned | ||
549 | * for the last time. | ||
535 | */ | 550 | */ |
536 | if (bip->bli_flags & XFS_BLI_STALE) { | 551 | if (bip->bli_flags & XFS_BLI_STALE) { |
537 | bip->bli_flags &= ~XFS_BLI_LOGGED; | ||
538 | trace_xfs_buf_item_unlock_stale(bip); | 552 | trace_xfs_buf_item_unlock_stale(bip); |
539 | ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); | 553 | ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); |
540 | if (!aborted) | 554 | if (!aborted) { |
555 | atomic_dec(&bip->bli_refcount); | ||
541 | return; | 556 | return; |
557 | } | ||
542 | } | 558 | } |
543 | 559 | ||
544 | /* | ||
545 | * Drop the transaction's reference to the log item if | ||
546 | * it was not logged as part of the transaction. Otherwise | ||
547 | * we'll drop the reference in xfs_buf_item_unpin() when | ||
548 | * the transaction is really through with the buffer. | ||
549 | */ | ||
550 | if (!(bip->bli_flags & XFS_BLI_LOGGED)) { | ||
551 | atomic_dec(&bip->bli_refcount); | ||
552 | } else { | ||
553 | /* | ||
554 | * Clear the logged flag since this is per | ||
555 | * transaction state. | ||
556 | */ | ||
557 | bip->bli_flags &= ~XFS_BLI_LOGGED; | ||
558 | } | ||
559 | |||
560 | /* | ||
561 | * Before possibly freeing the buf item, determine if we should | ||
562 | * release the buffer at the end of this routine. | ||
563 | */ | ||
564 | hold = bip->bli_flags & XFS_BLI_HOLD; | ||
565 | trace_xfs_buf_item_unlock(bip); | 560 | trace_xfs_buf_item_unlock(bip); |
566 | 561 | ||
567 | /* | 562 | /* |
568 | * If the buf item isn't tracking any data, free it. | 563 | * If the buf item isn't tracking any data, free it, otherwise drop the |
569 | * Otherwise, if XFS_BLI_HOLD is set clear it. | 564 | * reference we hold to it. |
570 | */ | 565 | */ |
571 | if (xfs_bitmap_empty(bip->bli_format.blf_data_map, | 566 | if (xfs_bitmap_empty(bip->bli_format.blf_data_map, |
572 | bip->bli_format.blf_map_size)) { | 567 | bip->bli_format.blf_map_size)) |
573 | xfs_buf_item_relse(bp); | 568 | xfs_buf_item_relse(bp); |
574 | } else if (hold) { | 569 | else |
575 | bip->bli_flags &= ~XFS_BLI_HOLD; | 570 | atomic_dec(&bip->bli_refcount); |
576 | } | ||
577 | 571 | ||
578 | /* | 572 | if (!hold) |
579 | * Release the buffer if XFS_BLI_HOLD was not set. | ||
580 | */ | ||
581 | if (!hold) { | ||
582 | xfs_buf_relse(bp); | 573 | xfs_buf_relse(bp); |
583 | } | ||
584 | } | 574 | } |
585 | 575 | ||
586 | /* | 576 | /* |