Commit a61faa62 authored by Badari Pulavarty's avatar Badari Pulavarty Committed by Linus Torvalds

[PATCH] Add nobh_writepage() support

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 pageout()->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.
Signed-off-by: default avatarBadari Pulavarty <pbadari@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f326c26e
......@@ -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);
......@@ -2508,6 +2509,61 @@ int nobh_commit_write(struct file *file, struct page *page,
}
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().
*/
......
......@@ -626,6 +626,12 @@ ext2_nobh_prepare_write(struct file *file, struct page *page,
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_aops = {
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,
......
......@@ -286,7 +286,7 @@ static int jfs_get_block(struct inode *ip, sector_t lblock,
static int jfs_writepage(struct page *page, struct writeback_control *wbc)
{
return block_write_full_page(page, jfs_get_block, wbc);
return nobh_writepage(page, jfs_get_block, wbc);
}
static int jfs_writepages(struct address_space *mapping,
......
......@@ -386,8 +386,9 @@ 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,
sector_t *last_block_in_bio, int *ret, struct writeback_control *wbc)
__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,
writepage_t writepage_fn)
{
struct address_space *mapping = page->mapping;
struct inode *inode = page->mapping->host;
......@@ -580,7 +581,13 @@ mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
confused:
if (bio)
bio = mpage_bio_submit(WRITE, bio);
*ret = page->mapping->a_ops->writepage(page, wbc);
if (writepage_fn) {
*ret = (*writepage_fn)(page, wbc);
} else {
*ret = -EAGAIN;
goto out;
}
/*
* The caller has a ref on the inode, so *mapping is stable
*/
......@@ -706,8 +713,9 @@ mpage_writepages(struct address_space *mapping,
&mapping->flags);
}
} else {
bio = mpage_writepage(bio, page, get_block,
&last_block_in_bio, &ret, wbc);
bio = __mpage_writepage(bio, page, get_block,
&last_block_in_bio, &ret, wbc,
page->mapping->a_ops->writepage);
}
if (ret || (--(wbc->nr_to_write) <= 0))
done = 1;
......@@ -735,3 +743,19 @@ mpage_writepages(struct address_space *mapping,
return ret;
}
EXPORT_SYMBOL(mpage_writepages);
int mpage_writepage(struct page *page, get_block_t get_block,
struct writeback_control *wbc)
{
int ret = 0;
struct bio *bio;
sector_t last_block_in_bio = 0;
bio = __mpage_writepage(NULL, page, get_block,
&last_block_in_bio, &ret, wbc, NULL);
if (bio)
mpage_bio_submit(WRITE, bio);
return ret;
}
EXPORT_SYMBOL(mpage_writepage);
......@@ -203,6 +203,9 @@ int file_fsync(struct file *, struct dentry *, int);
int nobh_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
int nobh_commit_write(struct file *, struct page *, unsigned, unsigned);
int nobh_truncate_page(struct address_space *, loff_t);
int nobh_writepage(struct page *page, get_block_t *get_block,
struct writeback_control *wbc);
/*
* inline definitions
......
......@@ -11,12 +11,15 @@
*/
struct writeback_control;
typedef int (writepage_t)(struct page *page, struct writeback_control *wbc);
int mpage_readpages(struct address_space *mapping, struct list_head *pages,
unsigned nr_pages, get_block_t get_block);
int mpage_readpage(struct page *page, get_block_t get_block);
int mpage_writepages(struct address_space *mapping,
struct writeback_control *wbc, get_block_t get_block);
int mpage_writepage(struct page *page, get_block_t *get_block,
struct writeback_control *wbc);
static inline int
generic_writepages(struct address_space *mapping, struct writeback_control *wbc)
......
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