Commit bf1570fe authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ramdisk: fix PageUptodate() handling

When a filesystem does getblk() to get a buffer_head against the ramdisk the
VFS will allocate a new not-uptodate pagecache page and will attach buffers to
it.

The filesystem will then bring certain buffer_heads uptodate.  But not the
whole page.

Later, various ramdisk a_ops see the not-uptodate page and wipe the whole
thing out, including the parts to which the filesystem wrote!

Fix that up by only zapping those parts of the page which are covered by
non-uptodate buffers.
parent 5e86fee4
...@@ -96,16 +96,33 @@ int rd_blocksize = BLOCK_SIZE; /* blocksize of the RAM disks */ ...@@ -96,16 +96,33 @@ int rd_blocksize = BLOCK_SIZE; /* blocksize of the RAM disks */
* 2000 Transmeta Corp. * 2000 Transmeta Corp.
* aops copied from ramfs. * aops copied from ramfs.
*/ */
static int ramdisk_readpage(struct file *file, struct page *page)
{
if (!PageUptodate(page)) {
void *kaddr = kmap_atomic(page, KM_USER0);
memset(kaddr, 0, PAGE_CACHE_SIZE); /*
flush_dcache_page(page); * If a ramdisk page has buffers, some may be uptodate and some may be not.
kunmap_atomic(kaddr, KM_USER0); * To bring the page uptodate we zero out the non-uptodate buffers. The
SetPageUptodate(page); * page must be locked.
*/
static void make_page_uptodate(struct page *page)
{
if (page_has_buffers(page)) {
struct buffer_head *bh = page_buffers(page);
struct buffer_head *head = bh;
do {
if (!buffer_uptodate(bh))
memset(bh->b_data, 0, bh->b_size);
} while ((bh = bh->b_this_page) != head);
} else {
memset(page_address(page), 0, PAGE_CACHE_SIZE);
} }
flush_dcache_page(page);
SetPageUptodate(page);
}
static int ramdisk_readpage(struct file *file, struct page *page)
{
if (!PageUptodate(page))
make_page_uptodate(page);
unlock_page(page); unlock_page(page);
return 0; return 0;
} }
...@@ -113,14 +130,8 @@ static int ramdisk_readpage(struct file *file, struct page *page) ...@@ -113,14 +130,8 @@ static int ramdisk_readpage(struct file *file, struct page *page)
static int ramdisk_prepare_write(struct file *file, struct page *page, static int ramdisk_prepare_write(struct file *file, struct page *page,
unsigned offset, unsigned to) unsigned offset, unsigned to)
{ {
if (!PageUptodate(page)) { if (!PageUptodate(page))
void *kaddr = kmap_atomic(page, KM_USER0); make_page_uptodate(page);
memset(kaddr, 0, PAGE_CACHE_SIZE);
flush_dcache_page(page);
kunmap_atomic(kaddr, KM_USER0);
SetPageUptodate(page);
}
return 0; return 0;
} }
...@@ -140,7 +151,9 @@ static int ramdisk_commit_write(struct file *file, struct page *page, ...@@ -140,7 +151,9 @@ static int ramdisk_commit_write(struct file *file, struct page *page,
*/ */
static int ramdisk_writepage(struct page *page, struct writeback_control *wbc) static int ramdisk_writepage(struct page *page, struct writeback_control *wbc)
{ {
redirty_page_for_writepage(wbc, page); if (!PageUptodate(page))
make_page_uptodate(page);
SetPageDirty(page);
if (wbc->for_reclaim) if (wbc->for_reclaim)
return WRITEPAGE_ACTIVATE; return WRITEPAGE_ACTIVATE;
unlock_page(page); unlock_page(page);
...@@ -191,10 +204,8 @@ static int rd_blkdev_pagecache_IO(int rw, struct bio_vec *vec, sector_t sector, ...@@ -191,10 +204,8 @@ static int rd_blkdev_pagecache_IO(int rw, struct bio_vec *vec, sector_t sector,
goto out; goto out;
} }
if (!PageUptodate(page)) { if (!PageUptodate(page))
clear_highpage(page); make_page_uptodate(page);
SetPageUptodate(page);
}
index++; index++;
......
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