diff options
-rw-r--r-- | fs/btrfs/file.c | 31 |
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); |
2512 | out_free: | 2521 | out_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); |
2518 | out_only_mutex: | 2527 | out_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; |