Commit 5ade3f9f authored by Christian Borntraeger's avatar Christian Borntraeger Committed by Greg Kroah-Hartman

Future of Linux 2.6.22.y series

commit 5d0360ee upstream.

We have seen ramdisk based install systems, where some pages of mapped
libraries and programs were suddendly zeroed under memory pressure. This
should not happen, as the ramdisk avoids freeing its pages by keeping
them dirty all the time.

It turns out that there is a case, where the VM makes a ramdisk page
clean, without telling the ramdisk driver.  On memory pressure
shrink_zone runs and it starts to run shrink_active_list.  There is a
check for buffer_heads_over_limit, and if true, pagevec_strip is called.
pagevec_strip calls try_to_release_page. If the mapping has no
releasepage callback, try_to_free_buffers is called. try_to_free_buffers
has now a special logic for some file systems to make a dirty page
clean, if all buffers are clean. Thats what happened in our test case.

The simplest solution is to provide a noop-releasepage callback for the
ramdisk driver. This avoids try_to_free_buffers for ramdisk pages.
Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Acked-by: default avatarNick Piggin <npiggin@suse.de>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 992a69a7
...@@ -189,6 +189,18 @@ static int ramdisk_set_page_dirty(struct page *page) ...@@ -189,6 +189,18 @@ static int ramdisk_set_page_dirty(struct page *page)
return 0; return 0;
} }
/*
* releasepage is called by pagevec_strip/try_to_release_page if
* buffers_heads_over_limit is true. Without a releasepage function
* try_to_free_buffers is called instead. That can unset the dirty
* bit of our ram disk pages, which will be eventually freed, even
* if the page is still in use.
*/
static int ramdisk_releasepage(struct page *page, gfp_t dummy)
{
return 0;
}
static const struct address_space_operations ramdisk_aops = { static const struct address_space_operations ramdisk_aops = {
.readpage = ramdisk_readpage, .readpage = ramdisk_readpage,
.prepare_write = ramdisk_prepare_write, .prepare_write = ramdisk_prepare_write,
...@@ -196,6 +208,7 @@ static const struct address_space_operations ramdisk_aops = { ...@@ -196,6 +208,7 @@ static const struct address_space_operations ramdisk_aops = {
.writepage = ramdisk_writepage, .writepage = ramdisk_writepage,
.set_page_dirty = ramdisk_set_page_dirty, .set_page_dirty = ramdisk_set_page_dirty,
.writepages = ramdisk_writepages, .writepages = ramdisk_writepages,
.releasepage = ramdisk_releasepage,
}; };
static int rd_blkdev_pagecache_IO(int rw, struct bio_vec *vec, sector_t sector, static int rd_blkdev_pagecache_IO(int rw, struct bio_vec *vec, sector_t sector,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment