summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2010-06-04 11:29:57 +0200
committerAl Viro <viro@zeniv.linux.org.uk>2010-08-09 16:47:32 -0400
commit6e1db88d536adcbbfe562b2d4b7d6425784fff12 (patch)
tree8cfcb5a6190722db6249b2e4978f39247975abcf
parentf4e420dc423148fba637af1ab618fa8896dfb2d6 (diff)
downloadlwn-6e1db88d536adcbbfe562b2d4b7d6425784fff12.tar.gz
lwn-6e1db88d536adcbbfe562b2d4b7d6425784fff12.zip
introduce __block_write_begin
Split up the block_write_begin implementation - __block_write_begin is a new trivial wrapper for block_prepare_write that always takes an already allocated page and can be either called from block_write_begin or filesystem code that already has a page allocated. Remove the handling of already allocated pages from block_write_begin after switching all callers that do it to __block_write_begin. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/buffer.c69
-rw-r--r--fs/ext2/dir.c3
-rw-r--r--fs/ext3/inode.c3
-rw-r--r--fs/ext4/inode.c11
-rw-r--r--fs/minix/inode.c3
-rw-r--r--fs/nilfs2/dir.c3
-rw-r--r--fs/reiserfs/inode.c3
-rw-r--r--fs/sysv/itree.c3
-rw-r--r--fs/ufs/inode.c3
-rw-r--r--include/linux/buffer_head.h2
10 files changed, 39 insertions, 64 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index 14529ec759b9..c319c49da511 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1833,9 +1833,10 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to)
}
EXPORT_SYMBOL(page_zero_new_buffers);
-static int __block_prepare_write(struct inode *inode, struct page *page,
- unsigned from, unsigned to, get_block_t *get_block)
+int block_prepare_write(struct page *page, unsigned from, unsigned to,
+ get_block_t *get_block)
{
+ struct inode *inode = page->mapping->host;
unsigned block_start, block_end;
sector_t block;
int err = 0;
@@ -1908,10 +1909,13 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
if (!buffer_uptodate(*wait_bh))
err = -EIO;
}
- if (unlikely(err))
+ if (unlikely(err)) {
page_zero_new_buffers(page, from, to);
+ ClearPageUptodate(page);
+ }
return err;
}
+EXPORT_SYMBOL(block_prepare_write);
static int __block_commit_write(struct inode *inode, struct page *page,
unsigned from, unsigned to)
@@ -1948,6 +1952,15 @@ static int __block_commit_write(struct inode *inode, struct page *page,
return 0;
}
+int __block_write_begin(struct page *page, loff_t pos, unsigned len,
+ get_block_t *get_block)
+{
+ unsigned start = pos & (PAGE_CACHE_SIZE - 1);
+
+ return block_prepare_write(page, start, start + len, get_block);
+}
+EXPORT_SYMBOL(__block_write_begin);
+
/*
* Filesystems implementing the new truncate sequence should use the
* _newtrunc postfix variant which won't incorrectly call vmtruncate.
@@ -1958,41 +1971,22 @@ int block_write_begin_newtrunc(struct file *file, struct address_space *mapping,
struct page **pagep, void **fsdata,
get_block_t *get_block)
{
- struct inode *inode = mapping->host;
- int status = 0;
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
struct page *page;
- pgoff_t index;
- unsigned start, end;
- int ownpage = 0;
+ int status;
- index = pos >> PAGE_CACHE_SHIFT;
- start = pos & (PAGE_CACHE_SIZE - 1);
- end = start + len;
-
- page = *pagep;
- if (page == NULL) {
- ownpage = 1;
- page = grab_cache_page_write_begin(mapping, index, flags);
- if (!page) {
- status = -ENOMEM;
- goto out;
- }
- *pagep = page;
- } else
- BUG_ON(!PageLocked(page));
+ page = grab_cache_page_write_begin(mapping, index, flags);
+ if (!page)
+ return -ENOMEM;
- status = __block_prepare_write(inode, page, start, end, get_block);
+ status = __block_write_begin(page, pos, len, get_block);
if (unlikely(status)) {
- ClearPageUptodate(page);
-
- if (ownpage) {
- unlock_page(page);
- page_cache_release(page);
- *pagep = NULL;
- }
+ unlock_page(page);
+ page_cache_release(page);
+ page = NULL;
}
-out:
+ *pagep = page;
return status;
}
EXPORT_SYMBOL(block_write_begin_newtrunc);
@@ -2379,17 +2373,6 @@ out:
}
EXPORT_SYMBOL(cont_write_begin);
-int block_prepare_write(struct page *page, unsigned from, unsigned to,
- get_block_t *get_block)
-{
- struct inode *inode = page->mapping->host;
- int err = __block_prepare_write(inode, page, from, to, get_block);
- if (err)
- ClearPageUptodate(page);
- return err;
-}
-EXPORT_SYMBOL(block_prepare_write);
-
int block_commit_write(struct page *page, unsigned from, unsigned to)
{
struct inode *inode = page->mapping->host;
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 6b946bae11cf..764109886ec0 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -450,8 +450,7 @@ ino_t ext2_inode_by_name(struct inode *dir, struct qstr *child)
static int ext2_prepare_chunk(struct page *page, loff_t pos, unsigned len)
{
- return block_write_begin_newtrunc(NULL, page->mapping, pos, len, 0,
- &page, NULL, ext2_get_block);
+ return __block_write_begin(page, pos, len, ext2_get_block);
}
/* Releases the page */
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index a66f3fe33672..5c6f07eefa4a 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1196,8 +1196,7 @@ retry:
ret = PTR_ERR(handle);
goto out;
}
- ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
- ext3_get_block);
+ ret = __block_write_begin(page, pos, len, ext3_get_block);
if (ret)
goto write_begin_failed;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index d6a7701018a6..3da3c9646e5e 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1578,11 +1578,9 @@ retry:
*pagep = page;
if (ext4_should_dioread_nolock(inode))
- ret = block_write_begin(file, mapping, pos, len, flags, pagep,
- fsdata, ext4_get_block_write);
+ ret = __block_write_begin(page, pos, len, ext4_get_block_write);
else
- ret = block_write_begin(file, mapping, pos, len, flags, pagep,
- fsdata, ext4_get_block);
+ ret = __block_write_begin(page, pos, len, ext4_get_block);
if (!ret && ext4_should_journal_data(inode)) {
ret = walk_page_buffers(handle, page_buffers(page),
@@ -1593,7 +1591,7 @@ retry:
unlock_page(page);
page_cache_release(page);
/*
- * block_write_begin may have instantiated a few blocks
+ * __block_write_begin may have instantiated a few blocks
* outside i_size. Trim these off again. Don't need
* i_size_read because we hold i_mutex.
*
@@ -3185,8 +3183,7 @@ retry:
}
*pagep = page;
- ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
- ext4_da_get_block_prep);
+ ret = __block_write_begin(page, pos, len, ext4_da_get_block_prep);
if (ret < 0) {
unlock_page(page);
ext4_journal_stop(handle);
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index f4abe45229bb..6b29e73f0ca6 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -359,8 +359,7 @@ static int minix_readpage(struct file *file, struct page *page)
int minix_prepare_chunk(struct page *page, loff_t pos, unsigned len)
{
- return block_write_begin_newtrunc(NULL, page->mapping, pos, len, 0,
- &page, NULL, minix_get_block);
+ return __block_write_begin(page, pos, len, minix_get_block);
}
static int minix_write_begin(struct file *file, struct address_space *mapping,
diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c
index fc2bcfa599a3..d14e3b94d81f 100644
--- a/fs/nilfs2/dir.c
+++ b/fs/nilfs2/dir.c
@@ -83,8 +83,7 @@ static unsigned nilfs_last_byte(struct inode *inode, unsigned long page_nr)
static int nilfs_prepare_chunk(struct page *page, unsigned from, unsigned to)
{
loff_t pos = page_offset(page) + from;
- return block_write_begin_newtrunc(NULL, page->mapping, pos, to - from,
- 0, &page, NULL, nilfs_get_block);
+ return __block_write_begin(page, pos, to - from, nilfs_get_block);
}
static void nilfs_commit_chunk(struct page *page,
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 4c1fb548ab64..045729f5674a 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -2585,8 +2585,7 @@ static int reiserfs_write_begin(struct file *file,
old_ref = th->t_refcount;
th->t_refcount++;
}
- ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
- reiserfs_get_block);
+ ret = __block_write_begin(page, pos, len, reiserfs_get_block);
if (ret && reiserfs_transaction_running(inode->i_sb)) {
struct reiserfs_transaction_handle *th = current->journal_info;
/* this gets a little ugly. If reiserfs_get_block returned an
diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c
index 4068f485cfd6..82a005c3d7eb 100644
--- a/fs/sysv/itree.c
+++ b/fs/sysv/itree.c
@@ -461,8 +461,7 @@ static int sysv_readpage(struct file *file, struct page *page)
int sysv_prepare_chunk(struct page *page, loff_t pos, unsigned len)
{
- return block_write_begin_newtrunc(NULL, page->mapping, pos, len, 0,
- &page, NULL, get_block);
+ return __block_write_begin(page, pos, len, get_block);
}
static int sysv_write_begin(struct file *file, struct address_space *mapping,
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index a9555b1ffd28..45ce32391f8f 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -560,8 +560,7 @@ static int ufs_readpage(struct file *file, struct page *page)
int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len)
{
- return block_write_begin_newtrunc(NULL, page->mapping, pos, len, 0,
- &page, NULL, ufs_getfrag_block);
+ return __block_write_begin(page, pos, len, ufs_getfrag_block);
}
static int ufs_write_begin(struct file *file, struct address_space *mapping,
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 7638647f0424..accc9f81bb63 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -209,6 +209,8 @@ int block_write_begin_newtrunc(struct file *, struct address_space *,
int block_write_begin(struct file *, struct address_space *,
loff_t, unsigned, unsigned,
struct page **, void **, get_block_t*);
+int __block_write_begin(struct page *page, loff_t pos, unsigned len,
+ get_block_t *get_block);
int block_write_end(struct file *, struct address_space *,
loff_t, unsigned, unsigned,
struct page *, void *);