summaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2017-11-03 20:16:59 -0400
committerDavid Sterba <dsterba@suse.com>2017-11-15 11:27:46 -0500
commite3b8a4858566a6cc25422fbfdfdd760b13b79280 (patch)
tree96e5ff78992e66e6eb4e114ca84b2542a61d0bf0 /fs/btrfs
parentf48bf66b662e7acd6a32dbc28c4fa38931f8f0a6 (diff)
Btrfs: fix reported number of inode blocks after buffered append writes
The patch from commit a7e3b975a0f9 ("Btrfs: fix reported number of inode blocks") introduced a regression where if we do a buffered write starting at position equal to or greater than the file's size and then stat(2) the file before writeback is triggered, the number of used blocks does not change (unless there's a prealloc/unwritten extent). Example: $ xfs_io -f -c "pwrite -S 0xab 0 64K" foobar $ du -h foobar 0 foobar $ sync $ du -h foobar 64K foobar The first version of that patch didn't had this regression and the second version, which was the one committed, was made only to address some performance regression detected by the intel test robots using fs_mark. This fixes the regression by setting the new delaloc bit in the range, and doing it at btrfs_dirty_pages() while setting the regular dealloc bit as well, so that this way we set both bits at once avoiding navigation of the inode's io tree twice. Doing it at btrfs_dirty_pages() is also the most meaninful place, as we should set the new dellaloc bit when if we set the delalloc bit, which happens only if we copied bytes into the pages at __btrfs_buffered_write(). This was making some of LTP's du tests fail, which can be quickly run using a command line like the following: $ ./runltp -q -p -l /ltp.log -f commands -s du -d /mnt Fixes: a7e3b975a0f9 ("Btrfs: fix reported number of inode blocks") Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/extent_io.h5
-rw-r--r--fs/btrfs/file.c43
-rw-r--r--fs/btrfs/inode.c9
-rw-r--r--fs/btrfs/relocation.c3
-rw-r--r--fs/btrfs/tests/extent-io-tests.c6
-rw-r--r--fs/btrfs/tests/inode-tests.c12
7 files changed, 46 insertions, 33 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index f7df5536ab61..72dcbf19f6ce 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3180,6 +3180,7 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
3180int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput, 3180int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput,
3181 int nr); 3181 int nr);
3182int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end, 3182int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
3183 unsigned int extra_bits,
3183 struct extent_state **cached_state, int dedupe); 3184 struct extent_state **cached_state, int dedupe);
3184int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, 3185int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
3185 struct btrfs_root *new_root, 3186 struct btrfs_root *new_root,
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index d8b27af7101e..2ef824b58e3c 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -365,10 +365,11 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
365 struct extent_state **cached_state); 365 struct extent_state **cached_state);
366 366
367static inline int set_extent_delalloc(struct extent_io_tree *tree, u64 start, 367static inline int set_extent_delalloc(struct extent_io_tree *tree, u64 start,
368 u64 end, struct extent_state **cached_state) 368 u64 end, unsigned int extra_bits,
369 struct extent_state **cached_state)
369{ 370{
370 return set_extent_bit(tree, start, end, 371 return set_extent_bit(tree, start, end,
371 EXTENT_DELALLOC | EXTENT_UPTODATE, 372 EXTENT_DELALLOC | EXTENT_UPTODATE | extra_bits,
372 NULL, cached_state, GFP_NOFS); 373 NULL, cached_state, GFP_NOFS);
373} 374}
374 375
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 47e6ebad78c3..2de7b4f4ca3c 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -538,14 +538,34 @@ int btrfs_dirty_pages(struct inode *inode, struct page **pages,
538 u64 end_of_last_block; 538 u64 end_of_last_block;
539 u64 end_pos = pos + write_bytes; 539 u64 end_pos = pos + write_bytes;
540 loff_t isize = i_size_read(inode); 540 loff_t isize = i_size_read(inode);
541 unsigned int extra_bits = 0;
541 542
542 start_pos = pos & ~((u64) fs_info->sectorsize - 1); 543 start_pos = pos & ~((u64) fs_info->sectorsize - 1);
543 num_bytes = round_up(write_bytes + pos - start_pos, 544 num_bytes = round_up(write_bytes + pos - start_pos,
544 fs_info->sectorsize); 545 fs_info->sectorsize);
545 546
546 end_of_last_block = start_pos + num_bytes - 1; 547 end_of_last_block = start_pos + num_bytes - 1;
548
549 if (!btrfs_is_free_space_inode(BTRFS_I(inode))) {
550 if (start_pos >= isize &&
551 !(BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC)) {
552 /*
553 * There can't be any extents following eof in this case
554 * so just set the delalloc new bit for the range
555 * directly.
556 */
557 extra_bits |= EXTENT_DELALLOC_NEW;
558 } else {
559 err = btrfs_find_new_delalloc_bytes(BTRFS_I(inode),
560 start_pos,
561 num_bytes, cached);
562 if (err)
563 return err;
564 }
565 }
566
547 err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, 567 err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
548 cached, 0); 568 extra_bits, cached, 0);
549 if (err) 569 if (err)
550 return err; 570 return err;
551 571
@@ -1473,10 +1493,8 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages,
1473 + round_up(pos + write_bytes - start_pos, 1493 + round_up(pos + write_bytes - start_pos,
1474 fs_info->sectorsize) - 1; 1494 fs_info->sectorsize) - 1;
1475 1495
1476 if (start_pos < inode->vfs_inode.i_size || 1496 if (start_pos < inode->vfs_inode.i_size) {
1477 (inode->flags & BTRFS_INODE_PREALLOC)) {
1478 struct btrfs_ordered_extent *ordered; 1497 struct btrfs_ordered_extent *ordered;
1479 unsigned int clear_bits;
1480 1498
1481 lock_extent_bits(&inode->io_tree, start_pos, last_pos, 1499 lock_extent_bits(&inode->io_tree, start_pos, last_pos,
1482 cached_state); 1500 cached_state);
@@ -1498,19 +1516,10 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages,
1498 } 1516 }
1499 if (ordered) 1517 if (ordered)
1500 btrfs_put_ordered_extent(ordered); 1518 btrfs_put_ordered_extent(ordered);
1501 ret = btrfs_find_new_delalloc_bytes(inode, start_pos, 1519 clear_extent_bit(&inode->io_tree, start_pos, last_pos,
1502 last_pos - start_pos + 1, 1520 EXTENT_DIRTY | EXTENT_DELALLOC |
1503 cached_state); 1521 EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
1504 clear_bits = EXTENT_DIRTY | EXTENT_DELALLOC | 1522 0, 0, cached_state, GFP_NOFS);
1505 EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG;
1506 if (ret)
1507 clear_bits |= EXTENT_DELALLOC_NEW | EXTENT_LOCKED;
1508 clear_extent_bit(&inode->io_tree, start_pos,
1509 last_pos, clear_bits,
1510 (clear_bits & EXTENT_LOCKED) ? 1 : 0,
1511 0, cached_state, GFP_NOFS);
1512 if (ret)
1513 return ret;
1514 *lockstart = start_pos; 1523 *lockstart = start_pos;
1515 *lockend = last_pos; 1524 *lockend = last_pos;
1516 ret = 1; 1525 ret = 1;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 1131db7a0b28..993061f83067 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2032,11 +2032,12 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
2032} 2032}
2033 2033
2034int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end, 2034int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
2035 unsigned int extra_bits,
2035 struct extent_state **cached_state, int dedupe) 2036 struct extent_state **cached_state, int dedupe)
2036{ 2037{
2037 WARN_ON((end & (PAGE_SIZE - 1)) == 0); 2038 WARN_ON((end & (PAGE_SIZE - 1)) == 0);
2038 return set_extent_delalloc(&BTRFS_I(inode)->io_tree, start, end, 2039 return set_extent_delalloc(&BTRFS_I(inode)->io_tree, start, end,
2039 cached_state); 2040 extra_bits, cached_state);
2040} 2041}
2041 2042
2042/* see btrfs_writepage_start_hook for details on why this is required */ 2043/* see btrfs_writepage_start_hook for details on why this is required */
@@ -2097,7 +2098,7 @@ again:
2097 goto out; 2098 goto out;
2098 } 2099 }
2099 2100
2100 btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state, 2101 btrfs_set_extent_delalloc(inode, page_start, page_end, 0, &cached_state,
2101 0); 2102 0);
2102 ClearPageChecked(page); 2103 ClearPageChecked(page);
2103 set_page_dirty(page); 2104 set_page_dirty(page);
@@ -4797,7 +4798,7 @@ again:
4797 EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 4798 EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
4798 0, 0, &cached_state, GFP_NOFS); 4799 0, 0, &cached_state, GFP_NOFS);
4799 4800
4800 ret = btrfs_set_extent_delalloc(inode, block_start, block_end, 4801 ret = btrfs_set_extent_delalloc(inode, block_start, block_end, 0,
4801 &cached_state, 0); 4802 &cached_state, 0);
4802 if (ret) { 4803 if (ret) {
4803 unlock_extent_cached(io_tree, block_start, block_end, 4804 unlock_extent_cached(io_tree, block_start, block_end,
@@ -9163,7 +9164,7 @@ again:
9163 EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 9164 EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
9164 0, 0, &cached_state, GFP_NOFS); 9165 0, 0, &cached_state, GFP_NOFS);
9165 9166
9166 ret = btrfs_set_extent_delalloc(inode, page_start, end, 9167 ret = btrfs_set_extent_delalloc(inode, page_start, end, 0,
9167 &cached_state, 0); 9168 &cached_state, 0);
9168 if (ret) { 9169 if (ret) {
9169 unlock_extent_cached(io_tree, page_start, page_end, 9170 unlock_extent_cached(io_tree, page_start, page_end,
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 4cf2eb67eba6..f0c3f00e97cb 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -3268,7 +3268,8 @@ static int relocate_file_extent_cluster(struct inode *inode,
3268 nr++; 3268 nr++;
3269 } 3269 }
3270 3270
3271 btrfs_set_extent_delalloc(inode, page_start, page_end, NULL, 0); 3271 btrfs_set_extent_delalloc(inode, page_start, page_end, 0, NULL,
3272 0);
3272 set_page_dirty(page); 3273 set_page_dirty(page);
3273 3274
3274 unlock_extent(&BTRFS_I(inode)->io_tree, 3275 unlock_extent(&BTRFS_I(inode)->io_tree,
diff --git a/fs/btrfs/tests/extent-io-tests.c b/fs/btrfs/tests/extent-io-tests.c
index d06b1c931d05..2e7f64a3b22b 100644
--- a/fs/btrfs/tests/extent-io-tests.c
+++ b/fs/btrfs/tests/extent-io-tests.c
@@ -114,7 +114,7 @@ static int test_find_delalloc(u32 sectorsize)
114 * |--- delalloc ---| 114 * |--- delalloc ---|
115 * |--- search ---| 115 * |--- search ---|
116 */ 116 */
117 set_extent_delalloc(&tmp, 0, sectorsize - 1, NULL); 117 set_extent_delalloc(&tmp, 0, sectorsize - 1, 0, NULL);
118 start = 0; 118 start = 0;
119 end = 0; 119 end = 0;
120 found = find_lock_delalloc_range(inode, &tmp, locked_page, &start, 120 found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
@@ -145,7 +145,7 @@ static int test_find_delalloc(u32 sectorsize)
145 test_msg("Couldn't find the locked page\n"); 145 test_msg("Couldn't find the locked page\n");
146 goto out_bits; 146 goto out_bits;
147 } 147 }
148 set_extent_delalloc(&tmp, sectorsize, max_bytes - 1, NULL); 148 set_extent_delalloc(&tmp, sectorsize, max_bytes - 1, 0, NULL);
149 start = test_start; 149 start = test_start;
150 end = 0; 150 end = 0;
151 found = find_lock_delalloc_range(inode, &tmp, locked_page, &start, 151 found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
@@ -200,7 +200,7 @@ static int test_find_delalloc(u32 sectorsize)
200 * 200 *
201 * We are re-using our test_start from above since it works out well. 201 * We are re-using our test_start from above since it works out well.
202 */ 202 */
203 set_extent_delalloc(&tmp, max_bytes, total_dirty - 1, NULL); 203 set_extent_delalloc(&tmp, max_bytes, total_dirty - 1, 0, NULL);
204 start = test_start; 204 start = test_start;
205 end = 0; 205 end = 0;
206 found = find_lock_delalloc_range(inode, &tmp, locked_page, &start, 206 found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
diff --git a/fs/btrfs/tests/inode-tests.c b/fs/btrfs/tests/inode-tests.c
index f797642c013d..30affb60da51 100644
--- a/fs/btrfs/tests/inode-tests.c
+++ b/fs/btrfs/tests/inode-tests.c
@@ -968,7 +968,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
968 btrfs_test_inode_set_ops(inode); 968 btrfs_test_inode_set_ops(inode);
969 969
970 /* [BTRFS_MAX_EXTENT_SIZE] */ 970 /* [BTRFS_MAX_EXTENT_SIZE] */
971 ret = btrfs_set_extent_delalloc(inode, 0, BTRFS_MAX_EXTENT_SIZE - 1, 971 ret = btrfs_set_extent_delalloc(inode, 0, BTRFS_MAX_EXTENT_SIZE - 1, 0,
972 NULL, 0); 972 NULL, 0);
973 if (ret) { 973 if (ret) {
974 test_msg("btrfs_set_extent_delalloc returned %d\n", ret); 974 test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
@@ -984,7 +984,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
984 /* [BTRFS_MAX_EXTENT_SIZE][sectorsize] */ 984 /* [BTRFS_MAX_EXTENT_SIZE][sectorsize] */
985 ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE, 985 ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE,
986 BTRFS_MAX_EXTENT_SIZE + sectorsize - 1, 986 BTRFS_MAX_EXTENT_SIZE + sectorsize - 1,
987 NULL, 0); 987 0, NULL, 0);
988 if (ret) { 988 if (ret) {
989 test_msg("btrfs_set_extent_delalloc returned %d\n", ret); 989 test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
990 goto out; 990 goto out;
@@ -1018,7 +1018,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
1018 ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE >> 1, 1018 ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE >> 1,
1019 (BTRFS_MAX_EXTENT_SIZE >> 1) 1019 (BTRFS_MAX_EXTENT_SIZE >> 1)
1020 + sectorsize - 1, 1020 + sectorsize - 1,
1021 NULL, 0); 1021 0, NULL, 0);
1022 if (ret) { 1022 if (ret) {
1023 test_msg("btrfs_set_extent_delalloc returned %d\n", ret); 1023 test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
1024 goto out; 1024 goto out;
@@ -1036,7 +1036,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
1036 ret = btrfs_set_extent_delalloc(inode, 1036 ret = btrfs_set_extent_delalloc(inode,
1037 BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize, 1037 BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize,
1038 (BTRFS_MAX_EXTENT_SIZE << 1) + 3 * sectorsize - 1, 1038 (BTRFS_MAX_EXTENT_SIZE << 1) + 3 * sectorsize - 1,
1039 NULL, 0); 1039 0, NULL, 0);
1040 if (ret) { 1040 if (ret) {
1041 test_msg("btrfs_set_extent_delalloc returned %d\n", ret); 1041 test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
1042 goto out; 1042 goto out;
@@ -1053,7 +1053,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
1053 */ 1053 */
1054 ret = btrfs_set_extent_delalloc(inode, 1054 ret = btrfs_set_extent_delalloc(inode,
1055 BTRFS_MAX_EXTENT_SIZE + sectorsize, 1055 BTRFS_MAX_EXTENT_SIZE + sectorsize,
1056 BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1, NULL, 0); 1056 BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1, 0, NULL, 0);
1057 if (ret) { 1057 if (ret) {
1058 test_msg("btrfs_set_extent_delalloc returned %d\n", ret); 1058 test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
1059 goto out; 1059 goto out;
@@ -1089,7 +1089,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
1089 */ 1089 */
1090 ret = btrfs_set_extent_delalloc(inode, 1090 ret = btrfs_set_extent_delalloc(inode,
1091 BTRFS_MAX_EXTENT_SIZE + sectorsize, 1091 BTRFS_MAX_EXTENT_SIZE + sectorsize,
1092 BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1, NULL, 0); 1092 BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1, 0, NULL, 0);
1093 if (ret) { 1093 if (ret) {
1094 test_msg("btrfs_set_extent_delalloc returned %d\n", ret); 1094 test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
1095 goto out; 1095 goto out;