diff options
Diffstat (limited to 'fs/reiserfs')
-rw-r--r-- | fs/reiserfs/journal.c | 42 |
1 files changed, 32 insertions, 10 deletions
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index ca8d9e86571f..6c1d0c35f9e9 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c | |||
@@ -615,6 +615,31 @@ static int journal_list_still_alive(struct super_block *s, | |||
615 | return 0; | 615 | return 0; |
616 | } | 616 | } |
617 | 617 | ||
618 | /* | ||
619 | * If page->mapping was null, we failed to truncate this page for | ||
620 | * some reason. Most likely because it was truncated after being | ||
621 | * logged via data=journal. | ||
622 | * | ||
623 | * This does a check to see if the buffer belongs to one of these | ||
624 | * lost pages before doing the final put_bh. If page->mapping was | ||
625 | * null, it tries to free buffers on the page, which should make the | ||
626 | * final page_cache_release drop the page from the lru. | ||
627 | */ | ||
628 | static void release_buffer_page(struct buffer_head *bh) | ||
629 | { | ||
630 | struct page *page = bh->b_page; | ||
631 | if (!page->mapping && !TestSetPageLocked(page)) { | ||
632 | page_cache_get(page); | ||
633 | put_bh(bh); | ||
634 | if (!page->mapping) | ||
635 | try_to_free_buffers(page); | ||
636 | unlock_page(page); | ||
637 | page_cache_release(page); | ||
638 | } else { | ||
639 | put_bh(bh); | ||
640 | } | ||
641 | } | ||
642 | |||
618 | static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate) | 643 | static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate) |
619 | { | 644 | { |
620 | char b[BDEVNAME_SIZE]; | 645 | char b[BDEVNAME_SIZE]; |
@@ -628,8 +653,9 @@ static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate) | |||
628 | set_buffer_uptodate(bh); | 653 | set_buffer_uptodate(bh); |
629 | else | 654 | else |
630 | clear_buffer_uptodate(bh); | 655 | clear_buffer_uptodate(bh); |
656 | |||
631 | unlock_buffer(bh); | 657 | unlock_buffer(bh); |
632 | put_bh(bh); | 658 | release_buffer_page(bh); |
633 | } | 659 | } |
634 | 660 | ||
635 | static void reiserfs_end_ordered_io(struct buffer_head *bh, int uptodate) | 661 | static void reiserfs_end_ordered_io(struct buffer_head *bh, int uptodate) |
@@ -1547,9 +1573,10 @@ static int flush_journal_list(struct super_block *s, | |||
1547 | BUG_ON(!test_clear_buffer_journal_dirty | 1573 | BUG_ON(!test_clear_buffer_journal_dirty |
1548 | (cn->bh)); | 1574 | (cn->bh)); |
1549 | 1575 | ||
1550 | /* undo the inc from journal_mark_dirty */ | 1576 | /* drop one ref for us */ |
1551 | put_bh(cn->bh); | 1577 | put_bh(cn->bh); |
1552 | brelse(cn->bh); | 1578 | /* drop one ref for journal_mark_dirty */ |
1579 | release_buffer_page(cn->bh); | ||
1553 | } | 1580 | } |
1554 | cn = cn->next; | 1581 | cn = cn->next; |
1555 | } | 1582 | } |
@@ -3709,13 +3736,8 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th, | |||
3709 | } | 3736 | } |
3710 | } | 3737 | } |
3711 | 3738 | ||
3712 | if (bh) { | 3739 | if (bh) |
3713 | put_bh(bh); /* get_hash grabs the buffer */ | 3740 | release_buffer_page(bh); /* get_hash grabs the buffer */ |
3714 | if (atomic_read(&(bh->b_count)) < 0) { | ||
3715 | reiserfs_warning(p_s_sb, | ||
3716 | "journal-2165: bh->b_count < 0"); | ||
3717 | } | ||
3718 | } | ||
3719 | return 0; | 3741 | return 0; |
3720 | } | 3742 | } |
3721 | 3743 | ||