Btrfs: move definition of the function btrfs_find_new_delalloc_bytes
PATCH v2 1/2 Btrfs: move definition of the function btrfs_find_new_delalloc_bytes
From: Filipe Manana <[email protected]>
Move the definition of the function btrfs_find_new_delalloc_bytes() closer to the function btrfs_dirty_pages(), because in a future commit it will be used exclusively by btrfs_dirty_pages(). This just moves the function's definition, with no functional changes at all.
---
V2: It's actually the first version of the patch, since the patch
following this one is a v2 (its v1 splitted into two patches).
fs/btrfs/file.c | 83 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 41 deletions(-)
fs/btrfs/file.c +42 -41
@@ -477,6 +477,48 @@ static void btrfs_drop_pages(struct page **pages, size_t num_pages) } } + +static int btrfs_find_new_delalloc_bytes (struct btrfs_inode *inode, +const u64 start, +const u64 len, +struct extent_state **cached_state) +{ +u64 search_start = start; +const u64 end = start + len -1 ; + +while (search_start < end) { +const u64 search_len = end - search_start +1 ; +struct extent_map *em; +u64 em_len; +int ret =0 ; + + em =btrfs_get_extent (inode,NULL ,0 , search_start, + search_len,0 ); +if (IS_ERR (em)) +return PTR_ERR (em); + +if (em->block_start !=EXTENT_MAP_HOLE ) + goto next; + + em_len = em->len; +if (em->start < search_start) + em_len -= search_start - em->start; +if (em_len > search_len) + em_len = search_len; + + ret =set_extent_bit (&inode->io_tree, search_start, + search_start + em_len -1 , +EXTENT_DELALLOC_NEW , +NULL , cached_state,GFP_NOFS ); +next: + search_start =extent_map_end (em); +free_extent_map (em); +if (ret) +return ret; + } +return 0 ; +} +/* * after copy_from_user, pages need to be dirtied and we need to make * sure holes are created between the current EOF and the start of
@@ -1404,47 +1446,6 @@ static noinline int prepare_pages(struct inode *inode, struct page **pages, } -static int btrfs_find_new_delalloc_bytes (struct btrfs_inode *inode, -const u64 start, -const u64 len, -struct extent_state **cached_state) -{ -u64 search_start = start; -const u64 end = start + len -1 ; - -while (search_start < end) { -const u64 search_len = end - search_start +1 ; -struct extent_map *em; -u64 em_len; -int ret =0 ; - - em =btrfs_get_extent (inode,NULL ,0 , search_start, - search_len,0 ); -if (IS_ERR (em)) -return PTR_ERR (em); - -if (em->block_start !=EXTENT_MAP_HOLE ) - goto next; - - em_len = em->len; -if (em->start < search_start) - em_len -= search_start - em->start; -if (em_len > search_len) - em_len = search_len; - - ret =set_extent_bit (&inode->io_tree, search_start, - search_start + em_len -1 , -EXTENT_DELALLOC_NEW , -NULL , cached_state,GFP_NOFS ); -next: - search_start =extent_map_end (em); -free_extent_map (em); -if (ret) -return ret; - } -return 0 ; -} -/* * This function locks the extent and properly waits for data=ordered extents * to finish before allowing the pages to be modified if need.
Signature · 1 line
2.11.0
PATCH v2 2/2 Btrfs: fix reported number of inode blocks after buffered append writes
From: Filipe Manana <[email protected]>
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
---
V2: Splitted patch into two, no other changes.
fs/btrfs/ctree.h | 1 + fs/btrfs/extent_io.h | 5 +++-- fs/btrfs/file.c | 43 ++++++++++++++++++++++++---------------- fs/btrfs/inode.c | 9 +++++---- fs/btrfs/relocation.c | 3 ++- fs/btrfs/tests/extent-io-tests.c | 6 +++--- fs/btrfs/tests/inode-tests.c | 12 +++++------ 7 files changed, 46 insertions(+), 33 deletions(-)
fs/btrfs/ctree.h +1 -0
@@ -3174,6 +3174,7 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);int btrfs_start_delalloc_roots (struct btrfs_fs_info *fs_info,int delay_iput,int nr);int btrfs_set_extent_delalloc (struct inode *inode,u64 start,u64 end, +unsigned int extra_bits,struct extent_state **cached_state,int dedupe); int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, struct btrfs_root *new_root,
fs/btrfs/extent_io.h +3 -2
@@ -365,10 +365,11 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, struct extent_state **cached_state);static inline int set_extent_delalloc (struct extent_io_tree *tree,u64 start, -u64 end,struct extent_state **cached_state) +u64 end,unsigned int extra_bits, +struct extent_state **cached_state) {return set_extent_bit (tree, start, end, -EXTENT_DELALLOC |EXTENT_UPTODATE , +EXTENT_DELALLOC |EXTENT_UPTODATE | extra_bits,NULL , cached_state,GFP_NOFS ); }
fs/btrfs/file.c +26 -17
69 lines not on this page · raw message
fs/btrfs/inode.c +5 -4
@@ -2036,11 +2036,12 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans, }int btrfs_set_extent_delalloc (struct inode *inode,u64 start,u64 end, +unsigned int extra_bits,struct extent_state **cached_state,int dedupe) {WARN_ON ((end & (PAGE_SIZE -1 )) ==0 );return set_extent_delalloc (&BTRFS_I (inode)->io_tree, start, end, - cached_state); + extra_bits, cached_state); }/* see btrfs_writepage_start_hook for details on why this is required */
@@ -2101,7 +2102,7 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work) goto out; } -btrfs_set_extent_delalloc (inode, page_start, page_end, &cached_state, +btrfs_set_extent_delalloc (inode, page_start, page_end,0 , &cached_state,0 );ClearPageChecked (page);set_page_dirty (page);
@@ -4853,7 +4854,7 @@ int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len,EXTENT_DO_ACCOUNTING |EXTENT_DEFRAG , 0, 0, &cached_state, GFP_NOFS); - ret =btrfs_set_extent_delalloc (inode, block_start, block_end, + ret =btrfs_set_extent_delalloc (inode, block_start, block_end,0 , &cached_state,0 );if (ret) { unlock_extent_cached(io_tree, block_start, block_end,
@@ -9252,7 +9253,7 @@ int btrfs_page_mkwrite(struct vm_fault *vmf)EXTENT_DO_ACCOUNTING |EXTENT_DEFRAG , 0, 0, &cached_state, GFP_NOFS); - ret =btrfs_set_extent_delalloc (inode, page_start, end, + ret =btrfs_set_extent_delalloc (inode, page_start, end,0 , &cached_state,0 );if (ret) { unlock_extent_cached(io_tree, page_start, page_end,
fs/btrfs/relocation.c +2 -1
@@ -3266,7 +3266,8 @@ static int relocate_file_extent_cluster(struct inode *inode, nr++; } -btrfs_set_extent_delalloc (inode, page_start, page_end,NULL ,0 ); +btrfs_set_extent_delalloc (inode, page_start, page_end,0 ,NULL , +0 );set_page_dirty (page); unlock_extent(&BTRFS_I(inode)->io_tree,
fs/btrfs/tests/extent-io-tests.c +3 -3
@@ -114,7 +114,7 @@ static int test_find_delalloc(u32 sectorsize)* |--- delalloc ---| * |--- search ---| */ -set_extent_delalloc (&tmp,0 , sectorsize -1 ,NULL ); +set_extent_delalloc (&tmp,0 , sectorsize -1 ,0 ,NULL ); start =0 ; end =0 ; found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
@@ -145,7 +145,7 @@ static int test_find_delalloc(u32 sectorsize)test_msg ("Couldn't find the locked page\n" ); goto out_bits; } -set_extent_delalloc (&tmp, sectorsize, max_bytes -1 ,NULL ); +set_extent_delalloc (&tmp, sectorsize, max_bytes -1 ,0 ,NULL ); start = test_start; end =0 ; found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
@@ -200,7 +200,7 @@ static int test_find_delalloc(u32 sectorsize)* * We are re-using our test_start from above since it works out well. */ -set_extent_delalloc (&tmp, max_bytes, total_dirty -1 ,NULL ); +set_extent_delalloc (&tmp, max_bytes, total_dirty -1 ,0 ,NULL ); start = test_start; end =0 ; found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
fs/btrfs/tests/inode-tests.c +6 -6
@@ -969,7 +969,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)/* [BTRFS_MAX_EXTENT_SIZE] */ BTRFS_I (inode)->outstanding_extents++; - ret =btrfs_set_extent_delalloc (inode,0 ,BTRFS_MAX_EXTENT_SIZE -1 , + ret =btrfs_set_extent_delalloc (inode,0 ,BTRFS_MAX_EXTENT_SIZE -1 ,0 ,NULL ,0 );if (ret) {test_msg ("btrfs_set_extent_delalloc returned %d\n" , ret);
@@ -986,7 +986,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)BTRFS_I (inode)->outstanding_extents++; ret =btrfs_set_extent_delalloc (inode,BTRFS_MAX_EXTENT_SIZE ,BTRFS_MAX_EXTENT_SIZE + sectorsize -1 , -NULL ,0 ); +0 ,NULL ,0 );if (ret) {test_msg ("btrfs_set_extent_delalloc returned %d\n" , ret); goto out;
@@ -1021,7 +1021,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize) ret =btrfs_set_extent_delalloc (inode,BTRFS_MAX_EXTENT_SIZE >>1 , (BTRFS_MAX_EXTENT_SIZE >>1 ) + sectorsize -1 , -NULL ,0 ); +0 ,NULL ,0 );if (ret) {test_msg ("btrfs_set_extent_delalloc returned %d\n" , ret); goto out;
@@ -1044,7 +1044,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize) ret =btrfs_set_extent_delalloc (inode,BTRFS_MAX_EXTENT_SIZE +2 * sectorsize, (BTRFS_MAX_EXTENT_SIZE <<1 ) +3 * sectorsize -1 , -NULL ,0 ); +0 ,NULL ,0 );if (ret) {test_msg ("btrfs_set_extent_delalloc returned %d\n" , ret); goto out;
@@ -1062,7 +1062,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)BTRFS_I (inode)->outstanding_extents++; ret =btrfs_set_extent_delalloc (inode,BTRFS_MAX_EXTENT_SIZE + sectorsize, -BTRFS_MAX_EXTENT_SIZE +2 * sectorsize -1 ,NULL ,0 ); +BTRFS_MAX_EXTENT_SIZE +2 * sectorsize -1 ,0 ,NULL ,0 );if (ret) {test_msg ("btrfs_set_extent_delalloc returned %d\n" , ret); goto out;
@@ -1099,7 +1099,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)BTRFS_I (inode)->outstanding_extents++; ret =btrfs_set_extent_delalloc (inode,BTRFS_MAX_EXTENT_SIZE + sectorsize, -BTRFS_MAX_EXTENT_SIZE +2 * sectorsize -1 ,NULL ,0 ); +BTRFS_MAX_EXTENT_SIZE +2 * sectorsize -1 ,0 ,NULL ,0 );if (ret) {test_msg ("btrfs_set_extent_delalloc returned %d\n" , ret); goto out;
Signature · 1 line
2.11.0
Re: [PATCH v2 2/2] Btrfs: fix reported number of inode blocks after buffered append writes
Quoted 27 lines · On Sat, Nov 04, 2017 at 04:20:07AM +0000, [email protected] wrote:
From: Filipe Manana <[email protected]>
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 foobarThe 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 atbtrfs_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().
Quoted 7 lines
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 /mntFixes a7e3b975a0f9 ("Btrfs: fix reported number of inode blocks")Signed-off-by Filipe Manana <[email protected]>
FYI, I'm going to add the two patches to a 4.15 queue.