aboutsummaryrefslogtreecommitdiff
path: root/fs/btrfs/super.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-04-10 14:22:02 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-04-10 14:22:02 -0400
commit2932f3ec94ff0212313b8187064f93bcb76ce411 (patch)
tree4cebf7d921162046b5920efc4666261de7832ebe /fs/btrfs/super.c
parent79b2cb1fa6430501907cb1384abbddf074833e45 (diff)
Btrfs: when forced to cow for file_write, get the page uptodate first
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r--fs/btrfs/super.c15
1 files changed, 14 insertions, 1 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index a3183972f31..b93d790e748 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1268,6 +1268,8 @@ static int prepare_pages(struct btrfs_trans_handle *trans,
struct page **pages,
size_t num_pages,
loff_t pos,
+ unsigned long first_index,
+ unsigned long last_index,
size_t write_bytes)
{
int i;
@@ -1289,6 +1291,13 @@ static int prepare_pages(struct btrfs_trans_handle *trans,
}
offset = pos & (PAGE_CACHE_SIZE -1);
this_write = min(PAGE_CACHE_SIZE - offset, write_bytes);
+ if (!PageUptodate(pages[i]) &&
+ (pages[i]->index == first_index ||
+ pages[i]->index == last_index) && pos < isize) {
+ ret = mpage_readpage(pages[i], btrfs_get_block);
+ BUG_ON(ret);
+ lock_page(pages[i]);
+ }
ret = nobh_prepare_write(pages[i], offset,
offset + this_write,
btrfs_get_block);
@@ -1323,6 +1332,8 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
struct inode *inode = file->f_path.dentry->d_inode;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct page *pages[1];
+ unsigned long first_index;
+ unsigned long last_index;
if (file->f_flags & O_DIRECT)
return -EINVAL;
@@ -1340,13 +1351,15 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
goto out;
file_update_time(file);
mutex_lock(&inode->i_mutex);
+ first_index = pos >> PAGE_CACHE_SHIFT;
+ last_index = (pos + count) >> PAGE_CACHE_SHIFT;
while(count > 0) {
size_t offset = pos & (PAGE_CACHE_SIZE - 1);
size_t write_bytes = min(count, PAGE_CACHE_SIZE - offset);
size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT;
ret = prepare_pages(NULL, root, file, pages, num_pages,
- pos, write_bytes);
+ pos, first_index, last_index, write_bytes);
BUG_ON(ret);
ret = btrfs_copy_from_user(pos, num_pages,
write_bytes, pages, buf);