diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-04-10 14:22:02 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-04-10 14:22:02 -0400 |
commit | 2932f3ec94ff0212313b8187064f93bcb76ce411 (patch) | |
tree | 4cebf7d921162046b5920efc4666261de7832ebe /fs/btrfs/super.c | |
parent | 79b2cb1fa6430501907cb1384abbddf074833e45 (diff) | |
download | kernel_goldelico_gta04-2932f3ec94ff0212313b8187064f93bcb76ce411.zip kernel_goldelico_gta04-2932f3ec94ff0212313b8187064f93bcb76ce411.tar.gz kernel_goldelico_gta04-2932f3ec94ff0212313b8187064f93bcb76ce411.tar.bz2 |
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.c | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index a318397..b93d790 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); |