Skip to content

Commit 0912b98

Browse files
adam900710gregkh
authored andcommitted
btrfs: check and set EXTENT_DELALLOC_NEW before clearing EXTENT_DELALLOC
commit 95ee223 upstream. [WARNING] When running test cases with injected errors or shutdown, e.g. generic/388 or generic/475, there is a chance that the following kernel warning is triggered: BTRFS info (device dm-2): first mount of filesystem d8a19a28-3232-4809-b0df-38df83e71bff BTRFS info (device dm-2): using crc32c checksum algorithm BTRFS info (device dm-2): checking UUID tree BTRFS info (device dm-2): turning on async discard BTRFS info (device dm-2): enabling free space tree BTRFS critical (device dm-2 state E): emergency shutdown ------------[ cut here ]------------ WARNING: extent_io.c:1742 at extent_writepage_io+0x437/0x520 [btrfs], CPU#2: kworker/u43:2/651591 CPU: 2 UID: 0 PID: 651591 Comm: kworker/u43:2 Tainted: G W OE 7.0.0-rc6-custom+ #365 PREEMPT(full) 5804053f02137e627472d94b5128cc9fcb110e88 RIP: 0010:extent_writepage_io+0x437/0x520 [btrfs] Call Trace: <TASK> extent_write_cache_pages+0x2a5/0x820 [btrfs 70299925d0856939e93b17d480651713b3cbba58] btrfs_writepages+0x74/0x130 [btrfs 70299925d0856939e93b17d480651713b3cbba58] do_writepages+0xd0/0x160 __writeback_single_inode+0x42/0x340 writeback_sb_inodes+0x22d/0x580 wb_writeback+0xc6/0x360 wb_workfn+0xbd/0x470 process_one_work+0x198/0x3b0 worker_thread+0x1c8/0x330 kthread+0xee/0x120 ret_from_fork+0x2a6/0x330 ret_from_fork_asm+0x11/0x20 </TASK> ---[ end trace 0000000000000000 ]--- BTRFS error (device dm-2 state E): root 5 ino 259 folio 1323008 is marked dirty without notifying the fs BTRFS error (device dm-2 state E): failed to submit blocks, root=5 inode=259 folio=1323008 submit_bitmap=0: -117 BTRFS info (device dm-2 state E): last unmount of filesystem d8a19a28-3232-4809-b0df-38df83e71bff [CAUSE] Inside btrfs we have the following pattern in several locations, for example inside btrfs_dirty_folio(): btrfs_clear_extent_bit(&inode->io_tree, start_pos, end_of_last_block, EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, cached); ret = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, extra_bits, cached); if (ret) return ret; However btrfs_set_extent_delalloc() can return IO errors other than -ENOMEM through the following callchain: btrfs_set_extent_delalloc() \- btrfs_find_new_delalloc_bytes() \- btrfs_get_extent() \- btrfs_lookup_file_extent() \- btrfs_search_slot() When such IO error happened, the previous btrfs_clear_extent_bit() has cleared the EXTENT_DELALLOC for the range, and we're expecting btrfs_set_extent_delalloc() to re-set EXTENT_DELALLOC. But since btrfs_set_extent_delalloc() failed before btrfs_set_extent_bit(), EXTENT_DELALLOC flag is no longer present. And if the folio range is dirty before entering btrfs_set_extent_delalloc(), we got a dirty folio but no EXTENT_DELALLOC flag now. Then we hit the folio writeback: extent_writepage() |- writepage_delalloc() | No ordered extent is created, as there is no EXTENT_DELALLOC set | for the folio range. | This also means the folio has no ordered flag set. | |- extent_writepage_io() \- if (unlikely(!folio_test_ordered(folio)) Now we hit the warning. [FIX] Introduce a new helper, btrfs_reset_extent_delalloc() to replace the currently open-coded btrfs_clear_extent_bit() + btrfs_set_extent_delalloc() combination. Instead of calling btrfs_clear_extent_bit() first, update EXTENT_DELALLOC_NEW first, as that part can fail due to metadata IO, meanwhile btrfs_clear_extent_bit() and btrfs_set_extent_bit() won't return any error but retry memory allocation until succeeded. This allows us to fail early without clearing EXTENT_DELALLOC bit, so even if that new btrfs_reset_extent_delalloc() failed before touching EXTENT_DELALLOC, the existing dirty range will still have their old EXTENT_DELALLOC flag present, thus avoid the warning. CC: stable@vger.kernel.org # 6.1+ Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 6d7649c commit 0912b98

4 files changed

Lines changed: 60 additions & 32 deletions

File tree

fs/btrfs/btrfs_inode.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,8 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
575575
int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
576576
unsigned int extra_bits,
577577
struct extent_state **cached_state);
578+
int btrfs_reset_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
579+
unsigned int extra_bits, struct extent_state **cached_state);
578580

579581
struct btrfs_new_inode_args {
580582
/* Input */

fs/btrfs/file.c

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,8 @@ int btrfs_dirty_folio(struct btrfs_inode *inode, struct folio *folio, loff_t pos
9393

9494
end_of_last_block = start_pos + num_bytes - 1;
9595

96-
/*
97-
* The pages may have already been dirty, clear out old accounting so
98-
* we can set things up properly
99-
*/
100-
btrfs_clear_extent_bit(&inode->io_tree, start_pos, end_of_last_block,
101-
EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
102-
cached);
103-
104-
ret = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
105-
extra_bits, cached);
96+
ret = btrfs_reset_extent_delalloc(inode, start_pos, end_of_last_block,
97+
extra_bits, cached);
10698
if (ret)
10799
return ret;
108100

@@ -1962,18 +1954,7 @@ static vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)
19621954
}
19631955
}
19641956

1965-
/*
1966-
* page_mkwrite gets called when the page is firstly dirtied after it's
1967-
* faulted in, but write(2) could also dirty a page and set delalloc
1968-
* bits, thus in this case for space account reason, we still need to
1969-
* clear any delalloc bits within this page range since we have to
1970-
* reserve data&meta space before lock_page() (see above comments).
1971-
*/
1972-
btrfs_clear_extent_bit(io_tree, page_start, end,
1973-
EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING |
1974-
EXTENT_DEFRAG, &cached_state);
1975-
1976-
ret = btrfs_set_extent_delalloc(inode, page_start, end, 0, &cached_state);
1957+
ret = btrfs_reset_extent_delalloc(inode, page_start, end, 0, &cached_state);
19771958
if (ret < 0) {
19781959
btrfs_unlock_extent(io_tree, page_start, page_end, &cached_state);
19791960
goto out_unlock;

fs/btrfs/inode.c

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2720,7 +2720,13 @@ int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
27202720
unsigned int extra_bits,
27212721
struct extent_state **cached_state)
27222722
{
2723-
WARN_ON(PAGE_ALIGNED(end));
2723+
const u32 blocksize = inode->root->fs_info->sectorsize;
2724+
2725+
/* Basic alignment check. */
2726+
ASSERT(IS_ALIGNED(start, blocksize), "start=%llu blocksize=%u",
2727+
start, blocksize);
2728+
ASSERT(IS_ALIGNED(end + 1, blocksize), "inclusive end=%llu blocksize=%u",
2729+
end, blocksize);
27242730

27252731
if (start >= i_size_read(&inode->vfs_inode) &&
27262732
!(inode->flags & BTRFS_INODE_PREALLOC)) {
@@ -2943,6 +2949,52 @@ int btrfs_writepage_cow_fixup(struct folio *folio)
29432949
return -EAGAIN;
29442950
}
29452951

2952+
/*
2953+
* Clear the old accounting flags and set EXTENT_DELALLOC for the range.
2954+
*
2955+
* Return <0 for error, in that case no range has EXTENT_DELALLOC bit cleared or set.
2956+
*/
2957+
int btrfs_reset_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
2958+
unsigned int extra_bits, struct extent_state **cached_state)
2959+
{
2960+
const u32 blocksize = inode->root->fs_info->sectorsize;
2961+
2962+
/* The @extra_bits can only be EXTENT_NORESERVE for now. */
2963+
ASSERT(!(extra_bits & ~EXTENT_NORESERVE), "extra_bits=0x%x", extra_bits);
2964+
2965+
/* Basic alignment check. */
2966+
ASSERT(IS_ALIGNED(start, blocksize), "start=%llu blocksize=%u",
2967+
start, blocksize);
2968+
ASSERT(IS_ALIGNED(end + 1, blocksize), "inclusive end=%llu blocksize=%u",
2969+
end, blocksize);
2970+
2971+
/*
2972+
* Check and set DELALLOC_NEW flag, this needs to search tree thus can
2973+
* fail early. Thus we want to do this before clearing EXTENT_DELALLOC.
2974+
*/
2975+
if (start >= i_size_read(&inode->vfs_inode) &&
2976+
!(inode->flags & BTRFS_INODE_PREALLOC)) {
2977+
/*
2978+
* There can't be any extents following EOF in this case so just
2979+
* set the delalloc new bit for the range directly.
2980+
*/
2981+
extra_bits |= EXTENT_DELALLOC_NEW;
2982+
} else {
2983+
int ret;
2984+
2985+
ret = btrfs_find_new_delalloc_bytes(inode, start, end + 1 - start,
2986+
NULL);
2987+
if (unlikely(ret))
2988+
return ret;
2989+
}
2990+
/* Clear the old accounting as the range may already be dirty. */
2991+
btrfs_clear_extent_bit(&inode->io_tree, start, end,
2992+
EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING |
2993+
EXTENT_DEFRAG, cached_state);
2994+
return btrfs_set_extent_bit(&inode->io_tree, start, end,
2995+
EXTENT_DELALLOC | extra_bits, cached_state);
2996+
}
2997+
29462998
static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
29472999
struct btrfs_inode *inode, u64 file_pos,
29483000
struct btrfs_file_extent_item *stack_fi,
@@ -5053,12 +5105,7 @@ int btrfs_truncate_block(struct btrfs_inode *inode, u64 offset, u64 start, u64 e
50535105
goto again;
50545106
}
50555107

5056-
btrfs_clear_extent_bit(&inode->io_tree, block_start, block_end,
5057-
EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
5058-
&cached_state);
5059-
5060-
ret = btrfs_set_extent_delalloc(inode, block_start, block_end, 0,
5061-
&cached_state);
5108+
ret = btrfs_reset_extent_delalloc(inode, block_start, block_end, 0, &cached_state);
50625109
if (ret) {
50635110
btrfs_unlock_extent(io_tree, block_start, block_end, &cached_state);
50645111
goto out_unlock;

fs/btrfs/reflink.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,7 @@ static int copy_inline_to_page(struct btrfs_inode *inode,
9393
if (ret < 0)
9494
goto out_unlock;
9595

96-
btrfs_clear_extent_bit(&inode->io_tree, file_offset, range_end,
97-
EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, NULL);
98-
ret = btrfs_set_extent_delalloc(inode, file_offset, range_end, 0, NULL);
96+
ret = btrfs_reset_extent_delalloc(inode, file_offset, range_end, 0, NULL);
9997
if (ret)
10098
goto out_unlock;
10199

0 commit comments

Comments
 (0)