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) |
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 a3183972f310..b93d790e7484 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -1268,6 +1268,8 @@ static int prepare_pages(struct btrfs_trans_handle *trans, | |||
1268 | struct page **pages, | 1268 | struct page **pages, |
1269 | size_t num_pages, | 1269 | size_t num_pages, |
1270 | loff_t pos, | 1270 | loff_t pos, |
1271 | unsigned long first_index, | ||
1272 | unsigned long last_index, | ||
1271 | size_t write_bytes) | 1273 | size_t write_bytes) |
1272 | { | 1274 | { |
1273 | int i; | 1275 | int i; |
@@ -1289,6 +1291,13 @@ static int prepare_pages(struct btrfs_trans_handle *trans, | |||
1289 | } | 1291 | } |
1290 | offset = pos & (PAGE_CACHE_SIZE -1); | 1292 | offset = pos & (PAGE_CACHE_SIZE -1); |
1291 | this_write = min(PAGE_CACHE_SIZE - offset, write_bytes); | 1293 | this_write = min(PAGE_CACHE_SIZE - offset, write_bytes); |
1294 | if (!PageUptodate(pages[i]) && | ||
1295 | (pages[i]->index == first_index || | ||
1296 | pages[i]->index == last_index) && pos < isize) { | ||
1297 | ret = mpage_readpage(pages[i], btrfs_get_block); | ||
1298 | BUG_ON(ret); | ||
1299 | lock_page(pages[i]); | ||
1300 | } | ||
1292 | ret = nobh_prepare_write(pages[i], offset, | 1301 | ret = nobh_prepare_write(pages[i], offset, |
1293 | offset + this_write, | 1302 | offset + this_write, |
1294 | btrfs_get_block); | 1303 | btrfs_get_block); |
@@ -1323,6 +1332,8 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1323 | struct inode *inode = file->f_path.dentry->d_inode; | 1332 | struct inode *inode = file->f_path.dentry->d_inode; |
1324 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1333 | struct btrfs_root *root = BTRFS_I(inode)->root; |
1325 | struct page *pages[1]; | 1334 | struct page *pages[1]; |
1335 | unsigned long first_index; | ||
1336 | unsigned long last_index; | ||
1326 | 1337 | ||
1327 | if (file->f_flags & O_DIRECT) | 1338 | if (file->f_flags & O_DIRECT) |
1328 | return -EINVAL; | 1339 | return -EINVAL; |
@@ -1340,13 +1351,15 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1340 | goto out; | 1351 | goto out; |
1341 | file_update_time(file); | 1352 | file_update_time(file); |
1342 | mutex_lock(&inode->i_mutex); | 1353 | mutex_lock(&inode->i_mutex); |
1354 | first_index = pos >> PAGE_CACHE_SHIFT; | ||
1355 | last_index = (pos + count) >> PAGE_CACHE_SHIFT; | ||
1343 | while(count > 0) { | 1356 | while(count > 0) { |
1344 | size_t offset = pos & (PAGE_CACHE_SIZE - 1); | 1357 | size_t offset = pos & (PAGE_CACHE_SIZE - 1); |
1345 | size_t write_bytes = min(count, PAGE_CACHE_SIZE - offset); | 1358 | size_t write_bytes = min(count, PAGE_CACHE_SIZE - offset); |
1346 | size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >> | 1359 | size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >> |
1347 | PAGE_CACHE_SHIFT; | 1360 | PAGE_CACHE_SHIFT; |
1348 | ret = prepare_pages(NULL, root, file, pages, num_pages, | 1361 | ret = prepare_pages(NULL, root, file, pages, num_pages, |
1349 | pos, write_bytes); | 1362 | pos, first_index, last_index, write_bytes); |
1350 | BUG_ON(ret); | 1363 | BUG_ON(ret); |
1351 | ret = btrfs_copy_from_user(pos, num_pages, | 1364 | ret = btrfs_copy_from_user(pos, num_pages, |
1352 | write_bytes, pages, buf); | 1365 | write_bytes, pages, buf); |