On Tue, 2005-02-15 at 09:54, Andrew Morton wrote:
> Badari Pulavarty <[EMAIL PROTECTED]> wrote:
> >
> > Yep. nobh_prepare_write() doesn't add any bufferheads. But
> > we call block_write_full_page() even for "nobh" case, which
> > does create bufferheads, attaches to the page and operates
> > on them..
>
> hmm, yeah, OK, we'll attach bh's in that case. It's a rare case though -
> when a dirty page falls off the end of the LRU. There's no particular
> reason why we cannot have a real mpage_writepage() which doesn't use bh's
> and employ that.
>
> I coulda sworn we used to have one.
Hi Andrew,
Here is my first version of mpage_writepage() patch.
I haven't handle the "confused" case yet - I need to
pass a function pointer to handle it. Just for
initial code review. I am still testing it.
Thanks,
Badari
diff -Narup -X dontdiff linux-2.6.10/fs/ext2/inode.c linux-2.6.10.nobh/fs/ext2/inode.c
--- linux-2.6.10/fs/ext2/inode.c 2004-12-24 13:33:51.000000000 -0800
+++ linux-2.6.10.nobh/fs/ext2/inode.c 2005-02-15 16:17:56.000000000 -0800
@@ -626,6 +626,12 @@ ext2_nobh_prepare_write(struct file *fil
return nobh_prepare_write(page,from,to,ext2_get_block);
}
+static int ext2_nobh_writepage(struct page *page,
+ struct writeback_control *wbc)
+{
+ return mpage_writepage(page, ext2_get_block, wbc);
+}
+
static sector_t ext2_bmap(struct address_space *mapping, sector_t block)
{
return generic_block_bmap(mapping,block,ext2_get_block);
@@ -675,7 +681,7 @@ struct address_space_operations ext2_aop
struct address_space_operations ext2_nobh_aops = {
.readpage = ext2_readpage,
.readpages = ext2_readpages,
- .writepage = ext2_writepage,
+ .writepage = ext2_nobh_writepage,
.sync_page = block_sync_page,
.prepare_write = ext2_nobh_prepare_write,
.commit_write = nobh_commit_write,
diff -Narup -X dontdiff linux-2.6.10/fs/jfs/inode.c linux-2.6.10.nobh/fs/jfs/inode.c
--- linux-2.6.10/fs/jfs/inode.c 2004-12-24 13:33:48.000000000 -0800
+++ linux-2.6.10.nobh/fs/jfs/inode.c 2005-02-15 16:48:32.022885240 -0800
@@ -281,7 +281,7 @@ static int jfs_get_block(struct inode *i
static int jfs_writepage(struct page *page, struct writeback_control *wbc)
{
- return block_write_full_page(page, jfs_get_block, wbc);
+ return mpage_writepage(page, jfs_get_block, wbc);
}
static int jfs_writepages(struct address_space *mapping,
diff -Narup -X dontdiff linux-2.6.10/fs/mpage.c linux-2.6.10.nobh/fs/mpage.c
--- linux-2.6.10/fs/mpage.c 2004-12-24 13:34:26.000000000 -0800
+++ linux-2.6.10.nobh/fs/mpage.c 2005-02-15 16:19:20.000000000 -0800
@@ -386,7 +386,7 @@ EXPORT_SYMBOL(mpage_readpage);
* just allocate full-size (16-page) BIOs.
*/
static struct bio *
-mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
+__mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
sector_t *last_block_in_bio, int *ret, struct writeback_control *wbc)
{
struct address_space *mapping = page->mapping;
@@ -706,7 +706,7 @@ retry:
&mapping->flags);
}
} else {
- bio = mpage_writepage(bio, page, get_block,
+ bio = __mpage_writepage(bio, page, get_block,
&last_block_in_bio, &ret, wbc);
}
if (ret || (--(wbc->nr_to_write) <= 0))
@@ -734,4 +734,59 @@ retry:
mpage_bio_submit(WRITE, bio);
return ret;
}
+
+/*
+ * The generic ->writepage function for address_spaces
+ */
+int mpage_writepage(struct page *page, get_block_t *get_block,
+ struct writeback_control *wbc)
+{
+ struct inode * const inode = page->mapping->host;
+ loff_t i_size = i_size_read(inode);
+ const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
+ unsigned offset;
+ void *kaddr;
+ int ret = 0;
+ struct bio *bio = NULL;
+ sector_t last_block_in_bio = 0;
+
+ /* Is the page fully inside i_size? */
+ if (page->index < end_index) {
+ bio = __mpage_writepage(bio, page, get_block,
+ &last_block_in_bio, &ret, wbc);
+ goto done;
+ }
+
+ /* Is the page fully outside i_size? (truncate in progress) */
+ offset = i_size & (PAGE_CACHE_SIZE-1);
+ if (page->index >= end_index+1 || !offset) {
+ /*
+ * The page may have dirty, unmapped buffers. For example,
+ * they may have been added in ext3_writepage(). Make them
+ * freeable here, so the page does not leak.
+ */
+ block_invalidatepage(page, 0);
+ unlock_page(page);
+ return 0; /* don't care */
+ }
+
+ /*
+ * The page straddles i_size. It must be zeroed out on each and every
+ * writepage invokation because it may be mmapped. "A file is mapped
+ * in multiples of the page size. For a file that is not a multiple of
+ * the page size, the remaining memory is zeroed when mapped, and
+ * writes to that region are not written out to the file."
+ */
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+ bio = __mpage_writepage(bio, page, get_block,
+ &last_block_in_bio, &ret, wbc);
+done:
+ if (bio)
+ mpage_bio_submit(WRITE, bio);
+ return ret;
+}
EXPORT_SYMBOL(mpage_writepages);
+EXPORT_SYMBOL(mpage_writepage);