diff options
Diffstat (limited to 'fs/reiserfs/journal.c')
| -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 | ||
