[PATCH] Add nobh_writepage() support

2005-02-18 Thread Badari Pulavarty
Hi Andrew,

Here is the patch to add nobh_wripage() support for the filesystems
which uses nobh_prepare_write/nobh_commit_write().

Idea here is to reduce unnecessary bufferhead creation/attachment
to the page through block_write_full_page(). nobh_wripage() tries 
to operate by directly creating bios, but it falls back to 
__block_write_full_page() if it can't make progress.

Note that this is not really generic routine and can't be used
for filesystems which uses page->Private for anything other
than buffer heads.

BTW, my next set of patches are to add ext3_writepages() support
for writeback mode and to add "nobh" support for ext3 writeback 
mode - which are based on some of this work (These are already 
discussed on ext2-devel).

And also, this needs some airtime in -mm tree before hitting mainline.

Thanks,
Badari




Signed-off-by: Badari Pulavarty <[EMAIL PROTECTED]>
diff -Narup -X dontdiff linux-2.6.10/fs/buffer.c linux-2.6.10.nobh/fs/buffer.c
--- linux-2.6.10/fs/buffer.c2004-12-24 13:34:58.0 -0800
+++ linux-2.6.10.nobh/fs/buffer.c   2005-02-18 14:52:20.707345056 -0800
@@ -39,6 +39,7 @@
 #include 
 #include 
 #include 
+#include 
 
 static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
 static void invalidate_bh_lrus(void);
@@ -2492,6 +2493,62 @@ int nobh_commit_write(struct file *file,
 EXPORT_SYMBOL(nobh_commit_write);
 
 /*
+ * nobh_writepage() - based on block_full_write_page() except
+ * that it tries to operate without attaching bufferheads to
+ * the page.
+ */
+int nobh_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;
+
+   /* Is the page fully inside i_size? */
+   if (page->index < end_index) {
+   goto out;
+   }
+
+   /* 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.
+*/
+#if 0
+   /* Not really sure about this  - do we need this ? */
+   if (page->mapping->a_ops->invalidatepage)
+   page->mapping->a_ops->invalidatepage(page, offset);
+#endif
+   unlock_page(page);
+   return 0; /* don't care */
+   }
+
+   /*
+* The page straddles i_size.  It must be zeroed out on each and every
+* writepage invocation 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);
+out:
+   ret = mpage_writepage(page, get_block, wbc);
+   if (ret == -EAGAIN)
+   ret = __block_write_full_page(inode, page, get_block, wbc);
+   return ret;
+}
+EXPORT_SYMBOL(nobh_writepage);
+
+/*
  * This function assumes that ->prepare_write() uses nobh_prepare_write().
  */
 int nobh_truncate_page(struct address_space *mapping, loff_t from)
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.c2004-12-24 13:33:51.0 -0800
+++ linux-2.6.10.nobh/fs/ext2/inode.c   2005-02-16 16:27:32.0 -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 nobh_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 

[PATCH] Add nobh_writepage() support

2005-02-18 Thread Badari Pulavarty
Hi Andrew,

Here is the patch to add nobh_wripage() support for the filesystems
which uses nobh_prepare_write/nobh_commit_write().

Idea here is to reduce unnecessary bufferhead creation/attachment
to the page through block_write_full_page(). nobh_wripage() tries 
to operate by directly creating bios, but it falls back to 
__block_write_full_page() if it can't make progress.

Note that this is not really generic routine and can't be used
for filesystems which uses page-Private for anything other
than buffer heads.

BTW, my next set of patches are to add ext3_writepages() support
for writeback mode and to add nobh support for ext3 writeback 
mode - which are based on some of this work (These are already 
discussed on ext2-devel).

And also, this needs some airtime in -mm tree before hitting mainline.

Thanks,
Badari




Signed-off-by: Badari Pulavarty [EMAIL PROTECTED]
diff -Narup -X dontdiff linux-2.6.10/fs/buffer.c linux-2.6.10.nobh/fs/buffer.c
--- linux-2.6.10/fs/buffer.c2004-12-24 13:34:58.0 -0800
+++ linux-2.6.10.nobh/fs/buffer.c   2005-02-18 14:52:20.707345056 -0800
@@ -39,6 +39,7 @@
 #include linux/notifier.h
 #include linux/cpu.h
 #include linux/bitops.h
+#include linux/mpage.h
 
 static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
 static void invalidate_bh_lrus(void);
@@ -2492,6 +2493,62 @@ int nobh_commit_write(struct file *file,
 EXPORT_SYMBOL(nobh_commit_write);
 
 /*
+ * nobh_writepage() - based on block_full_write_page() except
+ * that it tries to operate without attaching bufferheads to
+ * the page.
+ */
+int nobh_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;
+
+   /* Is the page fully inside i_size? */
+   if (page-index  end_index) {
+   goto out;
+   }
+
+   /* 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.
+*/
+#if 0
+   /* Not really sure about this  - do we need this ? */
+   if (page-mapping-a_ops-invalidatepage)
+   page-mapping-a_ops-invalidatepage(page, offset);
+#endif
+   unlock_page(page);
+   return 0; /* don't care */
+   }
+
+   /*
+* The page straddles i_size.  It must be zeroed out on each and every
+* writepage invocation 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);
+out:
+   ret = mpage_writepage(page, get_block, wbc);
+   if (ret == -EAGAIN)
+   ret = __block_write_full_page(inode, page, get_block, wbc);
+   return ret;
+}
+EXPORT_SYMBOL(nobh_writepage);
+
+/*
  * This function assumes that -prepare_write() uses nobh_prepare_write().
  */
 int nobh_truncate_page(struct address_space *mapping, loff_t from)
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.c2004-12-24 13:33:51.0 -0800
+++ linux-2.6.10.nobh/fs/ext2/inode.c   2005-02-16 16:27:32.0 -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 nobh_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
---