Also clean up various little things. I've got rid of the comment from akpm, because now that make_page_uptodate is only called from 2 places, it is pretty easy to see that the buffers are in an uptodate state at the time of the call. Actually, it was OK before my patch as well, because the memset is equivalent to reading from disk of course... however it is more explicit where the updates come from now. Cc: Linux Filesystems <linux-fsdevel@xxxxxxxxxxxxxxx> Signed-off-by: Nick Piggin <npiggin@xxxxxxx> drivers/block/rd.c | 125 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 52 deletions(-) Index: linux-2.6/drivers/block/rd.c =================================================================== --- linux-2.6.orig/drivers/block/rd.c +++ linux-2.6/drivers/block/rd.c @@ -104,50 +104,60 @@ static void make_page_uptodate(struct pa struct buffer_head *head = bh; do { - if (!buffer_uptodate(bh)) { - memset(bh->b_data, 0, bh->b_size); - /* - * akpm: I'm totally undecided about this. The - * buffer has just been magically brought "up to - * date", but nobody should want to be reading - * it anyway, because it hasn't been used for - * anything yet. It is still in a "not read - * from disk yet" state. - * - * But non-uptodate buffers against an uptodate - * page are against the rules. So do it anyway. - */ + if (!buffer_uptodate(bh)) set_buffer_uptodate(bh); - } } 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)) + if (!PageUptodate(page)) { + memclear_highpage_flush(page, 0, PAGE_CACHE_SIZE); make_page_uptodate(page); + } unlock_page(page); return 0; } -static int ramdisk_prepare_write(struct file *file, struct page *page, - unsigned offset, unsigned to) -{ - if (!PageUptodate(page)) - make_page_uptodate(page); +static int ramdisk_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + struct page *page; + pgoff_t index = pos >> PAGE_CACHE_SHIFT; + + page = __grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + *pagep = page; return 0; } -static int ramdisk_commit_write(struct file *file, struct page *page, - unsigned offset, unsigned to) -{ +static int ramdisk_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + if (!PageUptodate(page)) { + if (copied != PAGE_CACHE_SIZE) { + void *dst; + unsigned from = pos & (PAGE_CACHE_SIZE - 1); + unsigned to = from + copied; + + dst = kmap_atomic(page, KM_USER0); + memset(dst, 0, from); + memset(dst + to, 0, PAGE_CACHE_SIZE - to); + flush_dcache_page(page); + kunmap_atomic(dst, KM_USER0); + } + make_page_uptodate(page); + } + set_page_dirty(page); - return 0; + unlock_page(page); + page_cache_release(page); + return copied; } /* @@ -191,8 +201,8 @@ static int ramdisk_set_page_dirty(struct static const struct address_space_operations ramdisk_aops = { .readpage = ramdisk_readpage, - .prepare_write = ramdisk_prepare_write, - .commit_write = ramdisk_commit_write, + .write_begin = ramdisk_write_begin, + .write_end = ramdisk_write_end, .writepage = ramdisk_writepage, .set_page_dirty = ramdisk_set_page_dirty, .writepages = ramdisk_writepages, @@ -201,13 +211,14 @@ static const struct address_space_operat static int rd_blkdev_pagecache_IO(int rw, struct bio_vec *vec, sector_t sector, struct address_space *mapping) { - pgoff_t index = sector >> (PAGE_CACHE_SHIFT - 9); + loff_t pos = sector << 9; unsigned int vec_offset = vec->bv_offset; - int offset = (sector << 9) & ~PAGE_CACHE_MASK; int size = vec->bv_len; int err = 0; do { + pgoff_t index = pos >> PAGE_CACHE_SHIFT; + unsigned offset = pos & ~PAGE_CACHE_MASK; int count; struct page *page; char *src; @@ -216,40 +227,50 @@ static int rd_blkdev_pagecache_IO(int rw count = PAGE_CACHE_SIZE - offset; if (count > size) count = size; - size -= count; - - page = grab_cache_page(mapping, index); - if (!page) { - err = -ENOMEM; - goto out; - } - if (!PageUptodate(page)) - make_page_uptodate(page); + if (rw == WRITE) { + err = pagecache_write_begin(NULL, mapping, pos, count, + 0, &page, NULL); + if (err) + goto out; - index++; + src = kmap_atomic(vec->bv_page, KM_USER0) + vec_offset; + dst = kmap_atomic(page, KM_USER1) + offset; + } else { +again: + page = __grab_cache_page(mapping, index); + if (!page) { + err = -ENOMEM; + goto out; + } + if (!PageUptodate(page)) { + mapping->a_ops->readpage(NULL, page); + goto again; + } - if (rw == READ) { src = kmap_atomic(page, KM_USER0) + offset; dst = kmap_atomic(vec->bv_page, KM_USER1) + vec_offset; - } else { - src = kmap_atomic(vec->bv_page, KM_USER0) + vec_offset; - dst = kmap_atomic(page, KM_USER1) + offset; } - offset = 0; - vec_offset += count; + memcpy(dst, src, count); kunmap_atomic(src, KM_USER0); kunmap_atomic(dst, KM_USER1); - if (rw == READ) + if (rw == READ) { flush_dcache_page(vec->bv_page); - else - set_page_dirty(page); - unlock_page(page); - put_page(page); + unlock_page(page); + page_cache_release(page); + } else { + flush_dcache_page(page); + pagecache_write_end(NULL, mapping, pos, count, + count, page, NULL); + } + + pos += count; + vec_offset += count; + size -= count; } while (size); out: -- - To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html