Skip to content

Commit 7e2a595

Browse files
josefbacikkdave
authored andcommitted
btrfs: introduce EXTENT_DIO_LOCKED
In order to support dropping the extent lock during a read we need a way to make sure that direct reads and direct writes for overlapping ranges are protected from each other. To accomplish this introduce another lock bit specifically for direct io. Subsequent patches will utilize this to protect direct IO operations. Signed-off-by: Josef Bacik <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent df2825e commit 7e2a595

File tree

2 files changed

+58
-35
lines changed

2 files changed

+58
-35
lines changed

fs/btrfs/extent-io-tree.c

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ void extent_io_tree_init(struct btrfs_fs_info *fs_info,
126126
* Empty an io tree, removing and freeing every extent state record from the
127127
* tree. This should be called once we are sure no other task can access the
128128
* tree anymore, so no tree updates happen after we empty the tree and there
129-
* aren't any waiters on any extent state record (EXTENT_LOCKED bit is never
129+
* aren't any waiters on any extent state record (EXTENT_LOCK_BITS are never
130130
* set on any extent state when calling this function).
131131
*/
132132
void extent_io_tree_release(struct extent_io_tree *tree)
@@ -141,7 +141,7 @@ void extent_io_tree_release(struct extent_io_tree *tree)
141141
rbtree_postorder_for_each_entry_safe(state, tmp, &root, rb_node) {
142142
/* Clear node to keep free_extent_state() happy. */
143143
RB_CLEAR_NODE(&state->rb_node);
144-
ASSERT(!(state->state & EXTENT_LOCKED));
144+
ASSERT(!(state->state & EXTENT_LOCK_BITS));
145145
/*
146146
* No need for a memory barrier here, as we are holding the tree
147147
* lock and we only change the waitqueue while holding that lock
@@ -399,7 +399,7 @@ static void merge_next_state(struct extent_io_tree *tree, struct extent_state *s
399399
*/
400400
static void merge_state(struct extent_io_tree *tree, struct extent_state *state)
401401
{
402-
if (state->state & (EXTENT_LOCKED | EXTENT_BOUNDARY))
402+
if (state->state & (EXTENT_LOCK_BITS | EXTENT_BOUNDARY))
403403
return;
404404

405405
merge_prev_state(tree, state);
@@ -445,7 +445,7 @@ static struct extent_state *insert_state(struct extent_io_tree *tree,
445445
struct rb_node *parent = NULL;
446446
const u64 start = state->start - 1;
447447
const u64 end = state->end + 1;
448-
const bool try_merge = !(bits & (EXTENT_LOCKED | EXTENT_BOUNDARY));
448+
const bool try_merge = !(bits & (EXTENT_LOCK_BITS | EXTENT_BOUNDARY));
449449

450450
set_state_bits(tree, state, bits, changeset);
451451

@@ -616,9 +616,6 @@ static void set_gfp_mask_from_bits(u32 *bits, gfp_t *mask)
616616
* inserting elements in the tree, so the gfp mask is used to indicate which
617617
* allocations or sleeping are allowed.
618618
*
619-
* Pass 'wake' == 1 to kick any sleepers, and 'delete' == 1 to remove the given
620-
* range from the tree regardless of state (ie for truncate).
621-
*
622619
* The range [start, end] is inclusive.
623620
*
624621
* This takes the tree lock, and returns 0 on success and < 0 on error.
@@ -647,8 +644,8 @@ int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
647644
if (bits & EXTENT_DELALLOC)
648645
bits |= EXTENT_NORESERVE;
649646

650-
wake = (bits & EXTENT_LOCKED) ? 1 : 0;
651-
if (bits & (EXTENT_LOCKED | EXTENT_BOUNDARY))
647+
wake = ((bits & EXTENT_LOCK_BITS) ? 1 : 0);
648+
if (bits & (EXTENT_LOCK_BITS | EXTENT_BOUNDARY))
652649
clear = 1;
653650
again:
654651
if (!prealloc) {
@@ -861,8 +858,7 @@ static void cache_state_if_flags(struct extent_state *state,
861858
static void cache_state(struct extent_state *state,
862859
struct extent_state **cached_ptr)
863860
{
864-
return cache_state_if_flags(state, cached_ptr,
865-
EXTENT_LOCKED | EXTENT_BOUNDARY);
861+
return cache_state_if_flags(state, cached_ptr, EXTENT_LOCK_BITS | EXTENT_BOUNDARY);
866862
}
867863

868864
/*
@@ -1063,7 +1059,7 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
10631059
int ret = 0;
10641060
u64 last_start;
10651061
u64 last_end;
1066-
u32 exclusive_bits = (bits & EXTENT_LOCKED);
1062+
u32 exclusive_bits = (bits & EXTENT_LOCK_BITS);
10671063
gfp_t mask;
10681064

10691065
set_gfp_mask_from_bits(&bits, &mask);
@@ -1812,12 +1808,11 @@ int set_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
18121808
u32 bits, struct extent_changeset *changeset)
18131809
{
18141810
/*
1815-
* We don't support EXTENT_LOCKED yet, as current changeset will
1816-
* record any bits changed, so for EXTENT_LOCKED case, it will
1817-
* either fail with -EEXIST or changeset will record the whole
1818-
* range.
1811+
* We don't support EXTENT_LOCK_BITS yet, as current changeset will
1812+
* record any bits changed, so for EXTENT_LOCK_BITS case, it will either
1813+
* fail with -EEXIST or changeset will record the whole range.
18191814
*/
1820-
ASSERT(!(bits & EXTENT_LOCKED));
1815+
ASSERT(!(bits & EXTENT_LOCK_BITS));
18211816

18221817
return __set_extent_bit(tree, start, end, bits, NULL, NULL, NULL, changeset);
18231818
}
@@ -1826,26 +1821,25 @@ int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
18261821
u32 bits, struct extent_changeset *changeset)
18271822
{
18281823
/*
1829-
* Don't support EXTENT_LOCKED case, same reason as
1824+
* Don't support EXTENT_LOCK_BITS case, same reason as
18301825
* set_record_extent_bits().
18311826
*/
1832-
ASSERT(!(bits & EXTENT_LOCKED));
1827+
ASSERT(!(bits & EXTENT_LOCK_BITS));
18331828

18341829
return __clear_extent_bit(tree, start, end, bits, NULL, changeset);
18351830
}
18361831

1837-
int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
1838-
struct extent_state **cached)
1832+
bool __try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end, u32 bits,
1833+
struct extent_state **cached)
18391834
{
18401835
int err;
18411836
u64 failed_start;
18421837

1843-
err = __set_extent_bit(tree, start, end, EXTENT_LOCKED, &failed_start,
1838+
err = __set_extent_bit(tree, start, end, bits, &failed_start,
18441839
NULL, cached, NULL);
18451840
if (err == -EEXIST) {
18461841
if (failed_start > start)
1847-
clear_extent_bit(tree, start, failed_start - 1,
1848-
EXTENT_LOCKED, cached);
1842+
clear_extent_bit(tree, start, failed_start - 1, bits, cached);
18491843
return 0;
18501844
}
18511845
return 1;
@@ -1855,23 +1849,22 @@ int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
18551849
* Either insert or lock state struct between start and end use mask to tell
18561850
* us if waiting is desired.
18571851
*/
1858-
int lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
1859-
struct extent_state **cached_state)
1852+
int __lock_extent(struct extent_io_tree *tree, u64 start, u64 end, u32 bits,
1853+
struct extent_state **cached_state)
18601854
{
18611855
struct extent_state *failed_state = NULL;
18621856
int err;
18631857
u64 failed_start;
18641858

1865-
err = __set_extent_bit(tree, start, end, EXTENT_LOCKED, &failed_start,
1859+
err = __set_extent_bit(tree, start, end, bits, &failed_start,
18661860
&failed_state, cached_state, NULL);
18671861
while (err == -EEXIST) {
18681862
if (failed_start != start)
18691863
clear_extent_bit(tree, start, failed_start - 1,
1870-
EXTENT_LOCKED, cached_state);
1864+
bits, cached_state);
18711865

1872-
wait_extent_bit(tree, failed_start, end, EXTENT_LOCKED,
1873-
&failed_state);
1874-
err = __set_extent_bit(tree, start, end, EXTENT_LOCKED,
1866+
wait_extent_bit(tree, failed_start, end, bits, &failed_state);
1867+
err = __set_extent_bit(tree, start, end, bits,
18751868
&failed_start, &failed_state,
18761869
cached_state, NULL);
18771870
}

fs/btrfs/extent-io-tree.h

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ enum {
1919
ENUM_BIT(EXTENT_DIRTY),
2020
ENUM_BIT(EXTENT_UPTODATE),
2121
ENUM_BIT(EXTENT_LOCKED),
22+
ENUM_BIT(EXTENT_DIO_LOCKED),
2223
ENUM_BIT(EXTENT_NEW),
2324
ENUM_BIT(EXTENT_DELALLOC),
2425
ENUM_BIT(EXTENT_DEFRAG),
@@ -67,6 +68,8 @@ enum {
6768
EXTENT_ADD_INODE_BYTES | \
6869
EXTENT_CLEAR_ALL_BITS)
6970

71+
#define EXTENT_LOCK_BITS (EXTENT_LOCKED | EXTENT_DIO_LOCKED)
72+
7073
/*
7174
* Redefined bits above which are used only in the device allocation tree,
7275
* shouldn't be using EXTENT_LOCKED / EXTENT_BOUNDARY / EXTENT_CLEAR_META_RESV
@@ -134,12 +137,22 @@ const struct btrfs_fs_info *extent_io_tree_to_fs_info(const struct extent_io_tre
134137
void extent_io_tree_init(struct btrfs_fs_info *fs_info,
135138
struct extent_io_tree *tree, unsigned int owner);
136139
void extent_io_tree_release(struct extent_io_tree *tree);
140+
int __lock_extent(struct extent_io_tree *tree, u64 start, u64 end, u32 bits,
141+
struct extent_state **cached);
142+
bool __try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end, u32 bits,
143+
struct extent_state **cached);
137144

138-
int lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
139-
struct extent_state **cached);
145+
static inline int lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
146+
struct extent_state **cached)
147+
{
148+
return __lock_extent(tree, start, end, EXTENT_LOCKED, cached);
149+
}
140150

141-
int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
142-
struct extent_state **cached);
151+
static inline bool try_lock_extent(struct extent_io_tree *tree, u64 start,
152+
u64 end, struct extent_state **cached)
153+
{
154+
return __try_lock_extent(tree, start, end, EXTENT_LOCKED, cached);
155+
}
143156

144157
int __init extent_state_init_cachep(void);
145158
void __cold extent_state_free_cachep(void);
@@ -212,5 +225,22 @@ int find_contiguous_extent_bit(struct extent_io_tree *tree, u64 start,
212225
bool btrfs_find_delalloc_range(struct extent_io_tree *tree, u64 *start,
213226
u64 *end, u64 max_bytes,
214227
struct extent_state **cached_state);
228+
static inline int lock_dio_extent(struct extent_io_tree *tree, u64 start,
229+
u64 end, struct extent_state **cached)
230+
{
231+
return __lock_extent(tree, start, end, EXTENT_DIO_LOCKED, cached);
232+
}
233+
234+
static inline bool try_lock_dio_extent(struct extent_io_tree *tree, u64 start,
235+
u64 end, struct extent_state **cached)
236+
{
237+
return __try_lock_extent(tree, start, end, EXTENT_DIO_LOCKED, cached);
238+
}
239+
240+
static inline int unlock_dio_extent(struct extent_io_tree *tree, u64 start,
241+
u64 end, struct extent_state **cached)
242+
{
243+
return __clear_extent_bit(tree, start, end, EXTENT_DIO_LOCKED, cached, NULL);
244+
}
215245

216246
#endif /* BTRFS_EXTENT_IO_TREE_H */

0 commit comments

Comments
 (0)