diff --git a/fs/btrfs/extent-io-tree.c b/fs/btrfs/extent-io-tree.c index 29a225836e28..83e40c02f62e 100644 --- a/fs/btrfs/extent-io-tree.c +++ b/fs/btrfs/extent-io-tree.c @@ -532,6 +532,16 @@ static struct extent_state *clear_state_bit(struct extent_io_tree *tree, return next; } +/* + * Detect if extent bits request NOWAIT semantics and set the gfp mask accordingly, + * unset the EXTENT_NOWAIT bit. + */ +static void set_gfp_mask_from_bits(u32 *bits, gfp_t *mask) +{ + *mask = (*bits & EXTENT_NOWAIT ? GFP_NOWAIT : GFP_NOFS); + *bits &= EXTENT_NOWAIT - 1; +} + /* * Clear some bits on a range in the tree. This may require splitting or * inserting elements in the tree, so the gfp mask is used to indicate which @@ -557,6 +567,7 @@ int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int wake; int delete = (bits & EXTENT_CLEAR_ALL_BITS); + set_gfp_mask_from_bits(&bits, &mask); btrfs_debug_check_extent_io_range(tree, start, end); trace_btrfs_clear_extent_bit(tree, start, end - start + 1, bits); @@ -979,6 +990,7 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, u64 last_end; u32 exclusive_bits = (bits & EXTENT_LOCKED); + set_gfp_mask_from_bits(&bits, &mask); btrfs_debug_check_extent_io_range(tree, start, end); trace_btrfs_set_extent_bit(tree, start, end - start + 1, bits); diff --git a/fs/btrfs/extent-io-tree.h b/fs/btrfs/extent-io-tree.h index 5a53a4558366..d7f5afeb5ce7 100644 --- a/fs/btrfs/extent-io-tree.h +++ b/fs/btrfs/extent-io-tree.h @@ -43,6 +43,15 @@ enum { * want the extent states to go away. */ ENUM_BIT(EXTENT_CLEAR_ALL_BITS), + + /* + * This must be last. + * + * Bit not representing a state but a request for NOWAIT semantics, + * e.g. when allocating memory, and must be masked out from the other + * bits. + */ + ENUM_BIT(EXTENT_NOWAIT) }; #define EXTENT_DO_ACCOUNTING (EXTENT_CLEAR_META_RESV | \ diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 918ce12ea412..4c8c87524d62 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -365,8 +365,8 @@ static void extent_map_device_set_bits(struct extent_map *em, unsigned bits) struct btrfs_device *device = stripe->dev; set_extent_bit(&device->alloc_state, stripe->physical, - stripe->physical + stripe_size - 1, bits, NULL, - GFP_NOWAIT); + stripe->physical + stripe_size - 1, + bits | EXTENT_NOWAIT, NULL, GFP_NOWAIT); } } @@ -381,7 +381,8 @@ static void extent_map_device_clear_bits(struct extent_map *em, unsigned bits) struct btrfs_device *device = stripe->dev; __clear_extent_bit(&device->alloc_state, stripe->physical, - stripe->physical + stripe_size - 1, bits, + stripe->physical + stripe_size - 1, + bits | EXTENT_NOWAIT, NULL, GFP_NOWAIT, NULL); } } diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index b82a350c4c59..fb90e2b20614 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -1612,7 +1612,7 @@ void btrfs_redirty_list_add(struct btrfs_transaction *trans, set_bit(EXTENT_BUFFER_NO_CHECK, &eb->bflags); set_extent_buffer_dirty(eb); set_extent_bit(&trans->dirty_pages, eb->start, eb->start + eb->len - 1, - EXTENT_DIRTY, NULL, GFP_NOWAIT); + EXTENT_DIRTY | EXTENT_NOWAIT, NULL, GFP_NOWAIT); } bool btrfs_use_zone_append(struct btrfs_bio *bbio)