aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_buf_item.c24
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);