Skip to content

Commit aa56b0a

Browse files
josefbacikkdave
authored andcommitted
btrfs: push extent lock down in run_delalloc_nocow
run_delalloc_nocow is a little special because we use the file extents to see if we can nocow a range. We don't actually need the protection of the extent lock to look at the file extents at this point however. We are currently holding the page lock for this range, so we are protected from anybody who would simultaneously be modifying the file extent items for this range. * mmap() - we're holding the page lock. * buffered writes - we're holding the page lock. * direct writes - we're holding the page lock and direct IO has to flush page cache before it's able to continue. * fallocate() - all callers flush the range and wait on ordered extents while holding the inode lock and the mmap lock, so we are again saved by the page lock. We want to use the extent lock to protect 1) The mapping tree for the given range. 2) The ordered extents for the given range. 3) The io_tree for the given range. Push the extent lock down to cover these operations. In the fallback_to_cow() case we simply lock before doing anything and rely on the cow_file_range() helper to handle it's range properly. Reviewed-by: Goldwyn Rodrigues <rgoldwyn@suse.com> Signed-off-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 0ed30c1 commit aa56b0a

File tree

1 file changed

+18
-3
lines changed

1 file changed

+18
-3
lines changed

fs/btrfs/inode.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,6 +1747,8 @@ static int fallback_to_cow(struct btrfs_inode *inode, struct page *locked_page,
17471747
u64 count;
17481748
int ret;
17491749

1750+
lock_extent(io_tree, start, end, NULL);
1751+
17501752
/*
17511753
* If EXTENT_NORESERVE is set it means that when the buffered write was
17521754
* made we had not enough available data space and therefore we did not
@@ -1977,8 +1979,6 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
19771979
*/
19781980
ASSERT(!btrfs_is_zoned(fs_info) || btrfs_is_data_reloc_root(root));
19791981

1980-
lock_extent(&inode->io_tree, start, end, NULL);
1981-
19821982
path = btrfs_alloc_path();
19831983
if (!path) {
19841984
ret = -ENOMEM;
@@ -1994,6 +1994,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
19941994
struct btrfs_key found_key;
19951995
struct btrfs_file_extent_item *fi;
19961996
struct extent_buffer *leaf;
1997+
struct extent_state *cached_state = NULL;
19971998
u64 extent_end;
19981999
u64 ram_bytes;
19992000
u64 nocow_end;
@@ -2131,6 +2132,8 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
21312132
}
21322133

21332134
nocow_end = cur_offset + nocow_args.num_bytes - 1;
2135+
lock_extent(&inode->io_tree, cur_offset, nocow_end, &cached_state);
2136+
21342137
is_prealloc = extent_type == BTRFS_FILE_EXTENT_PREALLOC;
21352138
if (is_prealloc) {
21362139
u64 orig_start = found_key.offset - nocow_args.extent_offset;
@@ -2144,6 +2147,8 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
21442147
ram_bytes, BTRFS_COMPRESS_NONE,
21452148
BTRFS_ORDERED_PREALLOC);
21462149
if (IS_ERR(em)) {
2150+
unlock_extent(&inode->io_tree, cur_offset,
2151+
nocow_end, &cached_state);
21472152
btrfs_dec_nocow_writers(nocow_bg);
21482153
ret = PTR_ERR(em);
21492154
goto error;
@@ -2164,6 +2169,8 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
21642169
btrfs_drop_extent_map_range(inode, cur_offset,
21652170
nocow_end, false);
21662171
}
2172+
unlock_extent(&inode->io_tree, cur_offset,
2173+
nocow_end, &cached_state);
21672174
ret = PTR_ERR(ordered);
21682175
goto error;
21692176
}
@@ -2182,6 +2189,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
21822189
EXTENT_DELALLOC |
21832190
EXTENT_CLEAR_DATA_RESV,
21842191
PAGE_UNLOCK | PAGE_SET_ORDERED);
2192+
free_extent_state(cached_state);
21852193

21862194
cur_offset = extent_end;
21872195

@@ -2217,13 +2225,20 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
22172225
*/
22182226
if (cow_start != (u64)-1)
22192227
cur_offset = cow_start;
2220-
if (cur_offset < end)
2228+
2229+
/*
2230+
* We need to lock the extent here because we're clearing DELALLOC and
2231+
* we're not locked at this point.
2232+
*/
2233+
if (cur_offset < end) {
2234+
lock_extent(&inode->io_tree, cur_offset, end, NULL);
22212235
extent_clear_unlock_delalloc(inode, cur_offset, end,
22222236
locked_page, EXTENT_LOCKED |
22232237
EXTENT_DELALLOC | EXTENT_DEFRAG |
22242238
EXTENT_DO_ACCOUNTING, PAGE_UNLOCK |
22252239
PAGE_START_WRITEBACK |
22262240
PAGE_END_WRITEBACK);
2241+
}
22272242
btrfs_free_path(path);
22282243
return ret;
22292244
}

0 commit comments

Comments
 (0)