aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/file.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index e4090259569b..b476e5645034 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -2276,6 +2276,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
2276 bool same_page; 2276 bool same_page;
2277 bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES); 2277 bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES);
2278 u64 ino_size; 2278 u64 ino_size;
2279 bool truncated_page = false;
2280 bool updated_inode = false;
2279 2281
2280 ret = btrfs_wait_ordered_range(inode, offset, len); 2282 ret = btrfs_wait_ordered_range(inode, offset, len);
2281 if (ret) 2283 if (ret)
@@ -2307,13 +2309,18 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
2307 * entire page. 2309 * entire page.
2308 */ 2310 */
2309 if (same_page && len < PAGE_CACHE_SIZE) { 2311 if (same_page && len < PAGE_CACHE_SIZE) {
2310 if (offset < ino_size) 2312 if (offset < ino_size) {
2313 truncated_page = true;
2311 ret = btrfs_truncate_page(inode, offset, len, 0); 2314 ret = btrfs_truncate_page(inode, offset, len, 0);
2315 } else {
2316 ret = 0;
2317 }
2312 goto out_only_mutex; 2318 goto out_only_mutex;
2313 } 2319 }
2314 2320
2315 /* zero back part of the first page */ 2321 /* zero back part of the first page */
2316 if (offset < ino_size) { 2322 if (offset < ino_size) {
2323 truncated_page = true;
2317 ret = btrfs_truncate_page(inode, offset, 0, 0); 2324 ret = btrfs_truncate_page(inode, offset, 0, 0);
2318 if (ret) { 2325 if (ret) {
2319 mutex_unlock(&inode->i_mutex); 2326 mutex_unlock(&inode->i_mutex);
@@ -2349,6 +2356,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
2349 if (!ret) { 2356 if (!ret) {
2350 /* zero the front end of the last page */ 2357 /* zero the front end of the last page */
2351 if (tail_start + tail_len < ino_size) { 2358 if (tail_start + tail_len < ino_size) {
2359 truncated_page = true;
2352 ret = btrfs_truncate_page(inode, 2360 ret = btrfs_truncate_page(inode,
2353 tail_start + tail_len, 0, 1); 2361 tail_start + tail_len, 0, 1);
2354 if (ret) 2362 if (ret)
@@ -2358,8 +2366,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
2358 } 2366 }
2359 2367
2360 if (lockend < lockstart) { 2368 if (lockend < lockstart) {
2361 mutex_unlock(&inode->i_mutex); 2369 ret = 0;
2362 return 0; 2370 goto out_only_mutex;
2363 } 2371 }
2364 2372
2365 while (1) { 2373 while (1) {
@@ -2507,6 +2515,7 @@ out_trans:
2507 2515
2508 trans->block_rsv = &root->fs_info->trans_block_rsv; 2516 trans->block_rsv = &root->fs_info->trans_block_rsv;
2509 ret = btrfs_update_inode(trans, root, inode); 2517 ret = btrfs_update_inode(trans, root, inode);
2518 updated_inode = true;
2510 btrfs_end_transaction(trans, root); 2519 btrfs_end_transaction(trans, root);
2511 btrfs_btree_balance_dirty(root); 2520 btrfs_btree_balance_dirty(root);
2512out_free: 2521out_free:
@@ -2516,6 +2525,22 @@ out:
2516 unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, 2525 unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
2517 &cached_state, GFP_NOFS); 2526 &cached_state, GFP_NOFS);
2518out_only_mutex: 2527out_only_mutex:
2528 if (!updated_inode && truncated_page && !ret && !err) {
2529 /*
2530 * If we only end up zeroing part of a page, we still need to
2531 * update the inode item, so that all the time fields are
2532 * updated as well as the necessary btrfs inode in memory fields
2533 * for detecting, at fsync time, if the inode isn't yet in the
2534 * log tree or it's there but not up to date.
2535 */
2536 trans = btrfs_start_transaction(root, 1);
2537 if (IS_ERR(trans)) {
2538 err = PTR_ERR(trans);
2539 } else {
2540 err = btrfs_update_inode(trans, root, inode);
2541 ret = btrfs_end_transaction(trans, root);
2542 }
2543 }
2519 mutex_unlock(&inode->i_mutex); 2544 mutex_unlock(&inode->i_mutex);
2520 if (ret && !err) 2545 if (ret && !err)
2521 err = ret; 2546 err = ret;