Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

try to reap reiserfs pages left around by invalidatepage

reiserfs_invalidatepage will refuse to free pages if they have been logged
in data=journal mode, or were pinned down by a data=ordered operation. For
data=journal, this is fairly easy to trigger just with fsx-linux, and it
results in a large number of pages hanging around on the LRUs with
page->mapping == NULL.

Calling try_to_free_buffers when reiserfs decides it is done with the page
allows it to be freed earlier, and with much less VM thrashing. Lock
ordering rules mean that reiserfs can't call lock_page when it is releasing
the buffers, so TestSetPageLocked is used instead. Contention on these
pages should be rare, so it should be sufficient most of the time.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
Cc: "Vladimir V. Saveliev" <vs@namesys.com>
Cc: Jeff Mahoney <jeffm@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Chris Mason and committed by
Linus Torvalds
398c95bd e82ce352

+32 -10
+32 -10
fs/reiserfs/journal.c
··· 615 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 643 static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate) 619 644 { 620 645 char b[BDEVNAME_SIZE]; ··· 653 628 set_buffer_uptodate(bh); 654 629 else 655 630 clear_buffer_uptodate(bh); 631 + 656 632 unlock_buffer(bh); 657 - put_bh(bh); 633 + release_buffer_page(bh); 658 634 } 659 635 660 636 static void reiserfs_end_ordered_io(struct buffer_head *bh, int uptodate) ··· 1573 1547 BUG_ON(!test_clear_buffer_journal_dirty 1574 1548 (cn->bh)); 1575 1549 1576 - /* undo the inc from journal_mark_dirty */ 1550 + /* drop one ref for us */ 1577 1551 put_bh(cn->bh); 1578 - brelse(cn->bh); 1552 + /* drop one ref for journal_mark_dirty */ 1553 + release_buffer_page(cn->bh); 1579 1554 } 1580 1555 cn = cn->next; 1581 1556 } ··· 3736 3709 } 3737 3710 } 3738 3711 3739 - if (bh) { 3740 - put_bh(bh); /* get_hash grabs the buffer */ 3741 - if (atomic_read(&(bh->b_count)) < 0) { 3742 - reiserfs_warning(p_s_sb, 3743 - "journal-2165: bh->b_count < 0"); 3744 - } 3745 - } 3712 + if (bh) 3713 + release_buffer_page(bh); /* get_hash grabs the buffer */ 3746 3714 return 0; 3747 3715 } 3748 3716