diff options
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_buf_item.c | 24 |
1 files changed, 19 insertions, 5 deletions
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 3a944b198e35..88c5ea75ebf6 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c | |||
@@ -613,13 +613,27 @@ xfs_buf_item_unlock( | |||
613 | } | 613 | } |
614 | } | 614 | } |
615 | } | 615 | } |
616 | if (clean || aborted) { | 616 | |
617 | if (atomic_dec_and_test(&bip->bli_refcount)) { | 617 | /* |
618 | ASSERT(!aborted || XFS_FORCED_SHUTDOWN(lip->li_mountp)); | 618 | * Clean buffers, by definition, cannot be in the AIL. However, aborted |
619 | * buffers may be dirty and hence in the AIL. Therefore if we are | ||
620 | * aborting a buffer and we've just taken the last refernce away, we | ||
621 | * have to check if it is in the AIL before freeing it. We need to free | ||
622 | * it in this case, because an aborted transaction has already shut the | ||
623 | * filesystem down and this is the last chance we will have to do so. | ||
624 | */ | ||
625 | if (atomic_dec_and_test(&bip->bli_refcount)) { | ||
626 | if (clean) | ||
627 | xfs_buf_item_relse(bp); | ||
628 | else if (aborted) { | ||
629 | ASSERT(XFS_FORCED_SHUTDOWN(lip->li_mountp)); | ||
630 | if (lip->li_flags & XFS_LI_IN_AIL) { | ||
631 | xfs_trans_ail_delete(lip->li_ailp, lip, | ||
632 | SHUTDOWN_LOG_IO_ERROR); | ||
633 | } | ||
619 | xfs_buf_item_relse(bp); | 634 | xfs_buf_item_relse(bp); |
620 | } | 635 | } |
621 | } else | 636 | } |
622 | atomic_dec(&bip->bli_refcount); | ||
623 | 637 | ||
624 | if (!(flags & XFS_BLI_HOLD)) | 638 | if (!(flags & XFS_BLI_HOLD)) |
625 | xfs_buf_relse(bp); | 639 | xfs_buf_relse(bp); |