diff options
| -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); |
