diff options
author | Dave Chinner <dchinner@redhat.com> | 2010-05-06 21:04:34 -0400 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-05-24 11:33:31 -0400 |
commit | 64fc35de60da3b1fe970168d10914bf1cf34a3e3 (patch) | |
tree | 150216a336bbb3a0f7066763b675fb6a0e6f3061 | |
parent | 3383ca5780f88bb2c119174045ed77d5ece08072 (diff) |
xfs: modify buffer item reference counting
The buffer log item reference counts used to take referenceѕ for every
transaction, similar to the pin counting. This is symmetric (like the
pin/unpin) with respect to transaction completion, but with dleayed logging
becomes assymetric as the pinning becomes assymetric w.r.t. transaction
completion.
To make both cases the same, allow the buffer pinning to take a reference to
the buffer log item and always drop the reference the transaction has on it
when being unlocked. This is balanced correctly because the unpin operation
always drops a reference to the log item. Hence reference counting becomes
symmetric w.r.t. item pinning as well as w.r.t active transactions and as a
result the reference counting model remain consistent between normal and
delayed logging.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
-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 | /* |