2019-06-20 22:37:44 +03:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
|
|
|
|
#ifndef BTRFS_BLOCK_GROUP_H
|
|
|
|
#define BTRFS_BLOCK_GROUP_H
|
|
|
|
|
2019-08-21 20:57:04 +03:00
|
|
|
#include "free-space-cache.h"
|
|
|
|
|
2019-06-20 22:37:44 +03:00
|
|
|
enum btrfs_disk_cache_state {
|
|
|
|
BTRFS_DC_WRITTEN,
|
|
|
|
BTRFS_DC_ERROR,
|
|
|
|
BTRFS_DC_CLEAR,
|
|
|
|
BTRFS_DC_SETUP,
|
|
|
|
};
|
|
|
|
|
2019-12-14 03:22:16 +03:00
|
|
|
/*
|
|
|
|
* This describes the state of the block_group for async discard. This is due
|
|
|
|
* to the two pass nature of it where extent discarding is prioritized over
|
|
|
|
* bitmap discarding. BTRFS_DISCARD_RESET_CURSOR is set when we are resetting
|
|
|
|
* between lists to prevent contention for discard state variables
|
|
|
|
* (eg. discard_cursor).
|
|
|
|
*/
|
|
|
|
enum btrfs_discard_state {
|
|
|
|
BTRFS_DISCARD_EXTENTS,
|
|
|
|
BTRFS_DISCARD_BITMAPS,
|
|
|
|
BTRFS_DISCARD_RESET_CURSOR,
|
|
|
|
};
|
|
|
|
|
2019-06-20 22:38:04 +03:00
|
|
|
/*
|
|
|
|
* Control flags for do_chunk_alloc's force field CHUNK_ALLOC_NO_FORCE means to
|
|
|
|
* only allocate a chunk if we really need one.
|
|
|
|
*
|
|
|
|
* CHUNK_ALLOC_LIMITED means to only try and allocate one if we have very few
|
|
|
|
* chunks already allocated. This is used as part of the clustering code to
|
|
|
|
* help make sure we have a good pool of storage to cluster in, without filling
|
|
|
|
* the FS with empty chunks
|
|
|
|
*
|
|
|
|
* CHUNK_ALLOC_FORCE means it must try to allocate one
|
2022-03-22 12:11:34 +03:00
|
|
|
*
|
|
|
|
* CHUNK_ALLOC_FORCE_FOR_EXTENT like CHUNK_ALLOC_FORCE but called from
|
|
|
|
* find_free_extent() that also activaes the zone
|
2019-06-20 22:38:04 +03:00
|
|
|
*/
|
|
|
|
enum btrfs_chunk_alloc_enum {
|
|
|
|
CHUNK_ALLOC_NO_FORCE,
|
|
|
|
CHUNK_ALLOC_LIMITED,
|
|
|
|
CHUNK_ALLOC_FORCE,
|
2022-03-22 12:11:34 +03:00
|
|
|
CHUNK_ALLOC_FORCE_FOR_EXTENT,
|
2019-06-20 22:38:04 +03:00
|
|
|
};
|
|
|
|
|
2019-06-20 22:37:44 +03:00
|
|
|
struct btrfs_caching_control {
|
|
|
|
struct list_head list;
|
|
|
|
struct mutex mutex;
|
|
|
|
wait_queue_head_t wait;
|
|
|
|
struct btrfs_work work;
|
2019-10-29 21:20:18 +03:00
|
|
|
struct btrfs_block_group *block_group;
|
2019-06-20 22:37:44 +03:00
|
|
|
u64 progress;
|
|
|
|
refcount_t count;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Once caching_thread() finds this much free space, it will wake up waiters. */
|
|
|
|
#define CACHING_CTL_WAKE_UP SZ_2M
|
|
|
|
|
2019-10-29 21:20:18 +03:00
|
|
|
struct btrfs_block_group {
|
2019-06-20 22:37:44 +03:00
|
|
|
struct btrfs_fs_info *fs_info;
|
|
|
|
struct inode *inode;
|
|
|
|
spinlock_t lock;
|
2019-10-23 19:48:22 +03:00
|
|
|
u64 start;
|
|
|
|
u64 length;
|
2019-06-20 22:37:44 +03:00
|
|
|
u64 pinned;
|
|
|
|
u64 reserved;
|
2019-10-23 19:48:11 +03:00
|
|
|
u64 used;
|
2019-06-20 22:37:44 +03:00
|
|
|
u64 delalloc_bytes;
|
|
|
|
u64 bytes_super;
|
|
|
|
u64 flags;
|
|
|
|
u64 cache_generation;
|
2021-12-15 23:40:08 +03:00
|
|
|
u64 global_root_id;
|
2019-06-20 22:37:44 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the free space extent count exceeds this number, convert the block
|
|
|
|
* group to bitmaps.
|
|
|
|
*/
|
|
|
|
u32 bitmap_high_thresh;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the free space extent count drops below this number, convert the
|
|
|
|
* block group back to extents.
|
|
|
|
*/
|
|
|
|
u32 bitmap_low_thresh;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It is just used for the delayed data space allocation because
|
|
|
|
* only the data space allocation and the relative metadata update
|
|
|
|
* can be done cross the transaction.
|
|
|
|
*/
|
|
|
|
struct rw_semaphore data_rwsem;
|
|
|
|
|
|
|
|
/* For raid56, this is a full stripe, without parity */
|
|
|
|
unsigned long full_stripe_len;
|
|
|
|
|
|
|
|
unsigned int ro;
|
|
|
|
unsigned int iref:1;
|
|
|
|
unsigned int has_caching_ctl:1;
|
|
|
|
unsigned int removed:1;
|
2021-02-04 13:22:11 +03:00
|
|
|
unsigned int to_copy:1;
|
btrfs: zoned: relocate block group to repair IO failure in zoned filesystems
When a bad checksum is found and if the filesystem has a mirror of the
damaged data, we read the correct data from the mirror and writes it to
damaged blocks. This however, violates the sequential write constraints
of a zoned block device.
We can consider three methods to repair an IO failure in zoned filesystems:
(1) Reset and rewrite the damaged zone
(2) Allocate new device extent and replace the damaged device extent to
the new extent
(3) Relocate the corresponding block group
Method (1) is most similar to a behavior done with regular devices.
However, it also wipes non-damaged data in the same device extent, and
so it unnecessary degrades non-damaged data.
Method (2) is much like device replacing but done in the same device. It
is safe because it keeps the device extent until the replacing finish.
However, extending device replacing is non-trivial. It assumes
"src_dev->physical == dst_dev->physical". Also, the extent mapping
replacing function should be extended to support replacing device extent
position in one device.
Method (3) invokes relocation of the damaged block group and is
straightforward to implement. It relocates all the mirrored device
extents, so it potentially is a more costly operation than method (1) or
(2). But it relocates only used extents which reduce the total IO size.
Let's apply method (3) for now. In the future, we can extend device-replace
and apply method (2).
For protecting a block group gets relocated multiple time with multiple
IO errors, this commit introduces "relocating_repair" bit to show it's
now relocating to repair IO failures. Also it uses a new kthread
"btrfs-relocating-repair", not to block IO path with relocating process.
This commit also supports repairing in the scrub process.
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2021-02-04 13:22:16 +03:00
|
|
|
unsigned int relocating_repair:1;
|
btrfs: rework chunk allocation to avoid exhaustion of the system chunk array
Commit eafa4fd0ad0607 ("btrfs: fix exhaustion of the system chunk array
due to concurrent allocations") fixed a problem that resulted in
exhausting the system chunk array in the superblock when there are many
tasks allocating chunks in parallel. Basically too many tasks enter the
first phase of chunk allocation without previous tasks having finished
their second phase of allocation, resulting in too many system chunks
being allocated. That was originally observed when running the fallocate
tests of stress-ng on a PowerPC machine, using a node size of 64K.
However that commit also introduced a deadlock where a task in phase 1 of
the chunk allocation waited for another task that had allocated a system
chunk to finish its phase 2, but that other task was waiting on an extent
buffer lock held by the first task, therefore resulting in both tasks not
making any progress. That change was later reverted by a patch with the
subject "btrfs: fix deadlock with concurrent chunk allocations involving
system chunks", since there is no simple and short solution to address it
and the deadlock is relatively easy to trigger on zoned filesystems, while
the system chunk array exhaustion is not so common.
This change reworks the chunk allocation to avoid the system chunk array
exhaustion. It accomplishes that by making the first phase of chunk
allocation do the updates of the device items in the chunk btree and the
insertion of the new chunk item in the chunk btree. This is done while
under the protection of the chunk mutex (fs_info->chunk_mutex), in the
same critical section that checks for available system space, allocates
a new system chunk if needed and reserves system chunk space. This way
we do not have chunk space reserved until the second phase completes.
The same logic is applied to chunk removal as well, since it keeps
reserved system space long after it is done updating the chunk btree.
For direct allocation of system chunks, the previous behaviour remains,
because otherwise we would deadlock on extent buffers of the chunk btree.
Changes to the chunk btree are by large done by chunk allocation and chunk
removal, which first reserve chunk system space and then later do changes
to the chunk btree. The other remaining cases are uncommon and correspond
to adding a device, removing a device and resizing a device. All these
other cases do not pre-reserve system space, they modify the chunk btree
right away, so they don't hold reserved space for a long period like chunk
allocation and chunk removal do.
The diff of this change is huge, but more than half of it is just addition
of comments describing both how things work regarding chunk allocation and
removal, including both the new behavior and the parts of the old behavior
that did not change.
CC: stable@vger.kernel.org # 5.12+
Tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Tested-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Tested-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2021-06-29 16:43:06 +03:00
|
|
|
unsigned int chunk_item_inserted:1;
|
2021-08-19 15:19:17 +03:00
|
|
|
unsigned int zone_is_active:1;
|
btrfs: zoned: prevent allocation from previous data relocation BG
After commit 5f0addf7b890 ("btrfs: zoned: use dedicated lock for data
relocation"), we observe IO errors on e.g, btrfs/232 like below.
[09.0][T4038707] WARNING: CPU: 3 PID: 4038707 at fs/btrfs/extent-tree.c:2381 btrfs_cross_ref_exist+0xfc/0x120 [btrfs]
<snip>
[09.9][T4038707] Call Trace:
[09.5][T4038707] <TASK>
[09.3][T4038707] run_delalloc_nocow+0x7f1/0x11a0 [btrfs]
[09.6][T4038707] ? test_range_bit+0x174/0x320 [btrfs]
[09.2][T4038707] ? fallback_to_cow+0x980/0x980 [btrfs]
[09.3][T4038707] ? find_lock_delalloc_range+0x33e/0x3e0 [btrfs]
[09.5][T4038707] btrfs_run_delalloc_range+0x445/0x1320 [btrfs]
[09.2][T4038707] ? test_range_bit+0x320/0x320 [btrfs]
[09.4][T4038707] ? lock_downgrade+0x6a0/0x6a0
[09.2][T4038707] ? orc_find.part.0+0x1ed/0x300
[09.5][T4038707] ? __module_address.part.0+0x25/0x300
[09.0][T4038707] writepage_delalloc+0x159/0x310 [btrfs]
<snip>
[09.4][ C3] sd 10:0:1:0: [sde] tag#2620 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_OK cmd_age=0s
[09.5][ C3] sd 10:0:1:0: [sde] tag#2620 Sense Key : Illegal Request [current]
[09.9][ C3] sd 10:0:1:0: [sde] tag#2620 Add. Sense: Unaligned write command
[09.5][ C3] sd 10:0:1:0: [sde] tag#2620 CDB: Write(16) 8a 00 00 00 00 00 02 f3 63 87 00 00 00 2c 00 00
[09.4][ C3] critical target error, dev sde, sector 396041272 op 0x1:(WRITE) flags 0x800 phys_seg 3 prio class 0
[09.9][ C3] BTRFS error (device dm-1): bdev /dev/mapper/dml_102_2 errs: wr 1, rd 0, flush 0, corrupt 0, gen 0
The IO errors occur when we allocate a regular extent in previous data
relocation block group.
On zoned btrfs, we use a dedicated block group to relocate a data
extent. Thus, we allocate relocating data extents (pre-alloc) only from
the dedicated block group and vice versa. Once the free space in the
dedicated block group gets tight, a relocating extent may not fit into
the block group. In that case, we need to switch the dedicated block
group to the next one. Then, the previous one is now freed up for
allocating a regular extent. The BG is already not enough to allocate
the relocating extent, but there is still room to allocate a smaller
extent. Now the problem happens. By allocating a regular extent while
nocow IOs for the relocation is still on-going, we will issue WRITE IOs
(for relocation) and ZONE APPEND IOs (for the regular writes) at the
same time. That mixed IOs confuses the write pointer and arises the
unaligned write errors.
This commit introduces a new bit 'zoned_data_reloc_ongoing' to the
btrfs_block_group. We set this bit before releasing the dedicated block
group, and no extent are allocated from a block group having this bit
set. This bit is similar to setting block_group->ro, but is different from
it by allowing nocow writes to start.
Once all the nocow IO for relocation is done (hooked from
btrfs_finish_ordered_io), we reset the bit to release the block group for
further allocation.
Fixes: c2707a255623 ("btrfs: zoned: add a dedicated data relocation block group")
CC: stable@vger.kernel.org # 5.16+
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2022-06-07 10:08:29 +03:00
|
|
|
unsigned int zoned_data_reloc_ongoing:1;
|
2019-06-20 22:37:44 +03:00
|
|
|
|
|
|
|
int disk_cache_state;
|
|
|
|
|
|
|
|
/* Cache tracking stuff */
|
|
|
|
int cached;
|
|
|
|
struct btrfs_caching_control *caching_ctl;
|
|
|
|
u64 last_byte_to_unpin;
|
|
|
|
|
|
|
|
struct btrfs_space_info *space_info;
|
|
|
|
|
|
|
|
/* Free space cache stuff */
|
|
|
|
struct btrfs_free_space_ctl *free_space_ctl;
|
|
|
|
|
|
|
|
/* Block group cache stuff */
|
|
|
|
struct rb_node cache_node;
|
|
|
|
|
|
|
|
/* For block groups in the same raid type */
|
|
|
|
struct list_head list;
|
|
|
|
|
2020-07-06 16:14:11 +03:00
|
|
|
refcount_t refs;
|
2019-06-20 22:37:44 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* List of struct btrfs_free_clusters for this block group.
|
|
|
|
* Today it will only have one thing on it, but that may change
|
|
|
|
*/
|
|
|
|
struct list_head cluster_list;
|
|
|
|
|
|
|
|
/* For delayed block group creation or deletion of empty block groups */
|
|
|
|
struct list_head bg_list;
|
|
|
|
|
|
|
|
/* For read-only block groups */
|
|
|
|
struct list_head ro_list;
|
|
|
|
|
2020-05-08 13:01:47 +03:00
|
|
|
/*
|
|
|
|
* When non-zero it means the block group's logical address and its
|
|
|
|
* device extents can not be reused for future block group allocations
|
|
|
|
* until the counter goes down to 0. This is to prevent them from being
|
|
|
|
* reused while some task is still using the block group after it was
|
|
|
|
* deleted - we want to make sure they can only be reused for new block
|
|
|
|
* groups after that task is done with the deleted block group.
|
|
|
|
*/
|
|
|
|
atomic_t frozen;
|
|
|
|
|
2019-12-14 03:22:14 +03:00
|
|
|
/* For discard operations */
|
|
|
|
struct list_head discard_list;
|
|
|
|
int discard_index;
|
|
|
|
u64 discard_eligible_time;
|
2019-12-14 03:22:16 +03:00
|
|
|
u64 discard_cursor;
|
|
|
|
enum btrfs_discard_state discard_state;
|
2019-06-20 22:37:44 +03:00
|
|
|
|
|
|
|
/* For dirty block groups */
|
|
|
|
struct list_head dirty_list;
|
|
|
|
struct list_head io_list;
|
|
|
|
|
|
|
|
struct btrfs_io_ctl io_ctl;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Incremented when doing extent allocations and holding a read lock
|
|
|
|
* on the space_info's groups_sem semaphore.
|
|
|
|
* Decremented when an ordered extent that represents an IO against this
|
|
|
|
* block group's range is created (after it's added to its inode's
|
|
|
|
* root's list of ordered extents) or immediately after the allocation
|
|
|
|
* if it's a metadata extent or fallocate extent (for these cases we
|
|
|
|
* don't create ordered extents).
|
|
|
|
*/
|
|
|
|
atomic_t reservations;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Incremented while holding the spinlock *lock* by a task checking if
|
|
|
|
* it can perform a nocow write (incremented if the value for the *ro*
|
|
|
|
* field is 0). Decremented by such tasks once they create an ordered
|
|
|
|
* extent or before that if some error happens before reaching that step.
|
|
|
|
* This is to prevent races between block group relocation and nocow
|
|
|
|
* writes through direct IO.
|
|
|
|
*/
|
|
|
|
atomic_t nocow_writers;
|
|
|
|
|
|
|
|
/* Lock for free space tree operations. */
|
|
|
|
struct mutex free_space_lock;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Does the block group need to be added to the free space tree?
|
|
|
|
* Protected by free_space_lock.
|
|
|
|
*/
|
|
|
|
int needs_free_space;
|
|
|
|
|
2021-02-04 13:22:03 +03:00
|
|
|
/* Flag indicating this block group is placed on a sequential zone */
|
|
|
|
bool seq_zone;
|
|
|
|
|
btrfs: fix race between writes to swap files and scrub
When we active a swap file, at btrfs_swap_activate(), we acquire the
exclusive operation lock to prevent the physical location of the swap
file extents to be changed by operations such as balance and device
replace/resize/remove. We also call there can_nocow_extent() which,
among other things, checks if the block group of a swap file extent is
currently RO, and if it is we can not use the extent, since a write
into it would result in COWing the extent.
However we have no protection against a scrub operation running after we
activate the swap file, which can result in the swap file extents to be
COWed while the scrub is running and operating on the respective block
group, because scrub turns a block group into RO before it processes it
and then back again to RW mode after processing it. That means an attempt
to write into a swap file extent while scrub is processing the respective
block group, will result in COWing the extent, changing its physical
location on disk.
Fix this by making sure that block groups that have extents that are used
by active swap files can not be turned into RO mode, therefore making it
not possible for a scrub to turn them into RO mode. When a scrub finds a
block group that can not be turned to RO due to the existence of extents
used by swap files, it proceeds to the next block group and logs a warning
message that mentions the block group was skipped due to active swap
files - this is the same approach we currently use for balance.
Fixes: ed46ff3d42378 ("Btrfs: support swap files")
CC: stable@vger.kernel.org # 5.4+
Reviewed-by: Anand Jain <anand.jain@oracle.com>
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2021-02-05 15:55:37 +03:00
|
|
|
/*
|
|
|
|
* Number of extents in this block group used for swap files.
|
|
|
|
* All accesses protected by the spinlock 'lock'.
|
|
|
|
*/
|
|
|
|
int swap_extents;
|
|
|
|
|
2019-06-20 22:37:44 +03:00
|
|
|
/* Record locked full stripes for RAID5/6 block group */
|
|
|
|
struct btrfs_full_stripe_locks_tree full_stripe_locks_root;
|
2021-02-04 13:21:50 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocation offset for the block group to implement sequential
|
|
|
|
* allocation. This is used only on a zoned filesystem.
|
|
|
|
*/
|
|
|
|
u64 alloc_offset;
|
2021-02-04 13:21:52 +03:00
|
|
|
u64 zone_unusable;
|
2021-08-19 15:19:08 +03:00
|
|
|
u64 zone_capacity;
|
2021-02-04 13:22:08 +03:00
|
|
|
u64 meta_write_pointer;
|
2021-08-19 15:19:16 +03:00
|
|
|
struct map_lookup *physical_map;
|
2021-08-19 15:19:17 +03:00
|
|
|
struct list_head active_bg_list;
|
2022-05-04 03:48:53 +03:00
|
|
|
struct work_struct zone_finish_work;
|
|
|
|
struct extent_buffer *last_eb;
|
2019-06-20 22:37:44 +03:00
|
|
|
};
|
|
|
|
|
2019-12-14 03:22:14 +03:00
|
|
|
static inline u64 btrfs_block_group_end(struct btrfs_block_group *block_group)
|
|
|
|
{
|
|
|
|
return (block_group->start + block_group->length);
|
|
|
|
}
|
|
|
|
|
2020-01-03 00:26:40 +03:00
|
|
|
static inline bool btrfs_is_block_group_data_only(
|
|
|
|
struct btrfs_block_group *block_group)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* In mixed mode the fragmentation is expected to be high, lowering the
|
|
|
|
* efficiency, so only proper data block groups are considered.
|
|
|
|
*/
|
|
|
|
return (block_group->flags & BTRFS_BLOCK_GROUP_DATA) &&
|
|
|
|
!(block_group->flags & BTRFS_BLOCK_GROUP_METADATA);
|
|
|
|
}
|
|
|
|
|
2019-06-20 22:37:44 +03:00
|
|
|
#ifdef CONFIG_BTRFS_DEBUG
|
|
|
|
static inline int btrfs_should_fragment_free_space(
|
2019-10-29 21:20:18 +03:00
|
|
|
struct btrfs_block_group *block_group)
|
2019-06-20 22:37:44 +03:00
|
|
|
{
|
|
|
|
struct btrfs_fs_info *fs_info = block_group->fs_info;
|
|
|
|
|
|
|
|
return (btrfs_test_opt(fs_info, FRAGMENT_METADATA) &&
|
|
|
|
block_group->flags & BTRFS_BLOCK_GROUP_METADATA) ||
|
|
|
|
(btrfs_test_opt(fs_info, FRAGMENT_DATA) &&
|
|
|
|
block_group->flags & BTRFS_BLOCK_GROUP_DATA);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-10-29 21:20:18 +03:00
|
|
|
struct btrfs_block_group *btrfs_lookup_first_block_group(
|
2019-06-20 22:37:45 +03:00
|
|
|
struct btrfs_fs_info *info, u64 bytenr);
|
2019-10-29 21:20:18 +03:00
|
|
|
struct btrfs_block_group *btrfs_lookup_block_group(
|
2019-06-20 22:37:45 +03:00
|
|
|
struct btrfs_fs_info *info, u64 bytenr);
|
2019-10-29 21:20:18 +03:00
|
|
|
struct btrfs_block_group *btrfs_next_block_group(
|
|
|
|
struct btrfs_block_group *cache);
|
|
|
|
void btrfs_get_block_group(struct btrfs_block_group *cache);
|
|
|
|
void btrfs_put_block_group(struct btrfs_block_group *cache);
|
2019-06-20 22:37:47 +03:00
|
|
|
void btrfs_dec_block_group_reservations(struct btrfs_fs_info *fs_info,
|
|
|
|
const u64 start);
|
2019-10-29 21:20:18 +03:00
|
|
|
void btrfs_wait_block_group_reservations(struct btrfs_block_group *bg);
|
btrfs: avoid double search for block group during NOCOW writes
When doing a NOCOW write, either through direct IO or buffered IO, we do
two lookups for the block group that contains the target extent: once
when we call btrfs_inc_nocow_writers() and then later again when we call
btrfs_dec_nocow_writers() after creating the ordered extent.
The lookups require taking a lock and navigating the red black tree used
to track all block groups, which can take a non-negligible amount of time
for a large filesystem with thousands of block groups, as well as lock
contention and cache line bouncing.
Improve on this by having a single block group search: making
btrfs_inc_nocow_writers() return the block group to its caller and then
have the caller pass that block group to btrfs_dec_nocow_writers().
This is part of a patchset comprised of the following patches:
btrfs: remove search start argument from first_logical_byte()
btrfs: use rbtree with leftmost node cached for tracking lowest block group
btrfs: use a read/write lock for protecting the block groups tree
btrfs: return block group directly at btrfs_next_block_group()
btrfs: avoid double search for block group during NOCOW writes
The following test was used to test these changes from a performance
perspective:
$ cat test.sh
#!/bin/bash
modprobe null_blk nr_devices=0
NULL_DEV_PATH=/sys/kernel/config/nullb/nullb0
mkdir $NULL_DEV_PATH
if [ $? -ne 0 ]; then
echo "Failed to create nullb0 directory."
exit 1
fi
echo 2 > $NULL_DEV_PATH/submit_queues
echo 16384 > $NULL_DEV_PATH/size # 16G
echo 1 > $NULL_DEV_PATH/memory_backed
echo 1 > $NULL_DEV_PATH/power
DEV=/dev/nullb0
MNT=/mnt/nullb0
LOOP_MNT="$MNT/loop"
MOUNT_OPTIONS="-o ssd -o nodatacow"
MKFS_OPTIONS="-R free-space-tree -O no-holes"
cat <<EOF > /tmp/fio-job.ini
[io_uring_writes]
rw=randwrite
fsync=0
fallocate=posix
group_reporting=1
direct=1
ioengine=io_uring
iodepth=64
bs=64k
filesize=1g
runtime=300
time_based
directory=$LOOP_MNT
numjobs=8
thread
EOF
echo performance | \
tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
echo
echo "Using config:"
echo
cat /tmp/fio-job.ini
echo
umount $MNT &> /dev/null
mkfs.btrfs -f $MKFS_OPTIONS $DEV &> /dev/null
mount $MOUNT_OPTIONS $DEV $MNT
mkdir $LOOP_MNT
truncate -s 4T $MNT/loopfile
mkfs.btrfs -f $MKFS_OPTIONS $MNT/loopfile &> /dev/null
mount $MOUNT_OPTIONS $MNT/loopfile $LOOP_MNT
# Trigger the allocation of about 3500 data block groups, without
# actually consuming space on underlying filesystem, just to make
# the tree of block group large.
fallocate -l 3500G $LOOP_MNT/filler
fio /tmp/fio-job.ini
umount $LOOP_MNT
umount $MNT
echo 0 > $NULL_DEV_PATH/power
rmdir $NULL_DEV_PATH
The test was run on a non-debug kernel (Debian's default kernel config),
the result were the following.
Before patchset:
WRITE: bw=1455MiB/s (1526MB/s), 1455MiB/s-1455MiB/s (1526MB/s-1526MB/s), io=426GiB (458GB), run=300006-300006msec
After patchset:
WRITE: bw=1503MiB/s (1577MB/s), 1503MiB/s-1503MiB/s (1577MB/s-1577MB/s), io=440GiB (473GB), run=300006-300006msec
+3.3% write throughput and +3.3% IO done in the same time period.
The test has somewhat limited coverage scope, as with only NOCOW writes
we get less contention on the red black tree of block groups, since we
don't have the extra contention caused by COW writes, namely when
allocating data extents, pinning and unpinning data extents, but on the
hand there's access to tree in the NOCOW path, when incrementing a block
group's number of NOCOW writers.
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2022-04-13 18:20:43 +03:00
|
|
|
struct btrfs_block_group *btrfs_inc_nocow_writers(struct btrfs_fs_info *fs_info,
|
|
|
|
u64 bytenr);
|
|
|
|
void btrfs_dec_nocow_writers(struct btrfs_block_group *bg);
|
2019-10-29 21:20:18 +03:00
|
|
|
void btrfs_wait_nocow_writers(struct btrfs_block_group *bg);
|
|
|
|
void btrfs_wait_block_group_cache_progress(struct btrfs_block_group *cache,
|
2019-06-20 22:37:48 +03:00
|
|
|
u64 num_bytes);
|
2019-10-29 21:20:18 +03:00
|
|
|
int btrfs_wait_block_group_cache_done(struct btrfs_block_group *cache);
|
|
|
|
int btrfs_cache_block_group(struct btrfs_block_group *cache,
|
2019-06-20 22:37:48 +03:00
|
|
|
int load_cache_only);
|
2019-06-20 22:37:50 +03:00
|
|
|
void btrfs_put_caching_control(struct btrfs_caching_control *ctl);
|
|
|
|
struct btrfs_caching_control *btrfs_get_caching_control(
|
2019-10-29 21:20:18 +03:00
|
|
|
struct btrfs_block_group *cache);
|
|
|
|
u64 add_new_free_space(struct btrfs_block_group *block_group,
|
2019-08-06 17:43:19 +03:00
|
|
|
u64 start, u64 end);
|
2019-06-20 22:37:55 +03:00
|
|
|
struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(
|
|
|
|
struct btrfs_fs_info *fs_info,
|
|
|
|
const u64 chunk_offset);
|
|
|
|
int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
|
|
|
|
u64 group_start, struct extent_map *em);
|
|
|
|
void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info);
|
2019-10-29 21:20:18 +03:00
|
|
|
void btrfs_mark_bg_unused(struct btrfs_block_group *bg);
|
2021-04-19 10:41:02 +03:00
|
|
|
void btrfs_reclaim_bgs_work(struct work_struct *work);
|
|
|
|
void btrfs_reclaim_bgs(struct btrfs_fs_info *fs_info);
|
|
|
|
void btrfs_mark_bg_to_reclaim(struct btrfs_block_group *bg);
|
2019-06-20 22:37:57 +03:00
|
|
|
int btrfs_read_block_groups(struct btrfs_fs_info *info);
|
btrfs: rework chunk allocation to avoid exhaustion of the system chunk array
Commit eafa4fd0ad0607 ("btrfs: fix exhaustion of the system chunk array
due to concurrent allocations") fixed a problem that resulted in
exhausting the system chunk array in the superblock when there are many
tasks allocating chunks in parallel. Basically too many tasks enter the
first phase of chunk allocation without previous tasks having finished
their second phase of allocation, resulting in too many system chunks
being allocated. That was originally observed when running the fallocate
tests of stress-ng on a PowerPC machine, using a node size of 64K.
However that commit also introduced a deadlock where a task in phase 1 of
the chunk allocation waited for another task that had allocated a system
chunk to finish its phase 2, but that other task was waiting on an extent
buffer lock held by the first task, therefore resulting in both tasks not
making any progress. That change was later reverted by a patch with the
subject "btrfs: fix deadlock with concurrent chunk allocations involving
system chunks", since there is no simple and short solution to address it
and the deadlock is relatively easy to trigger on zoned filesystems, while
the system chunk array exhaustion is not so common.
This change reworks the chunk allocation to avoid the system chunk array
exhaustion. It accomplishes that by making the first phase of chunk
allocation do the updates of the device items in the chunk btree and the
insertion of the new chunk item in the chunk btree. This is done while
under the protection of the chunk mutex (fs_info->chunk_mutex), in the
same critical section that checks for available system space, allocates
a new system chunk if needed and reserves system chunk space. This way
we do not have chunk space reserved until the second phase completes.
The same logic is applied to chunk removal as well, since it keeps
reserved system space long after it is done updating the chunk btree.
For direct allocation of system chunks, the previous behaviour remains,
because otherwise we would deadlock on extent buffers of the chunk btree.
Changes to the chunk btree are by large done by chunk allocation and chunk
removal, which first reserve chunk system space and then later do changes
to the chunk btree. The other remaining cases are uncommon and correspond
to adding a device, removing a device and resizing a device. All these
other cases do not pre-reserve system space, they modify the chunk btree
right away, so they don't hold reserved space for a long period like chunk
allocation and chunk removal do.
The diff of this change is huge, but more than half of it is just addition
of comments describing both how things work regarding chunk allocation and
removal, including both the new behavior and the parts of the old behavior
that did not change.
CC: stable@vger.kernel.org # 5.12+
Tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Tested-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Tested-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2021-06-29 16:43:06 +03:00
|
|
|
struct btrfs_block_group *btrfs_make_block_group(struct btrfs_trans_handle *trans,
|
|
|
|
u64 bytes_used, u64 type,
|
|
|
|
u64 chunk_offset, u64 size);
|
2019-06-20 22:37:57 +03:00
|
|
|
void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans);
|
btrfs: scrub: Don't check free space before marking a block group RO
[BUG]
When running btrfs/072 with only one online CPU, it has a pretty high
chance to fail:
btrfs/072 12s ... _check_dmesg: something found in dmesg (see xfstests-dev/results//btrfs/072.dmesg)
- output mismatch (see xfstests-dev/results//btrfs/072.out.bad)
--- tests/btrfs/072.out 2019-10-22 15:18:14.008965340 +0800
+++ /xfstests-dev/results//btrfs/072.out.bad 2019-11-14 15:56:45.877152240 +0800
@@ -1,2 +1,3 @@
QA output created by 072
Silence is golden
+Scrub find errors in "-m dup -d single" test
...
And with the following call trace:
BTRFS info (device dm-5): scrub: started on devid 1
------------[ cut here ]------------
BTRFS: Transaction aborted (error -27)
WARNING: CPU: 0 PID: 55087 at fs/btrfs/block-group.c:1890 btrfs_create_pending_block_groups+0x3e6/0x470 [btrfs]
CPU: 0 PID: 55087 Comm: btrfs Tainted: G W O 5.4.0-rc1-custom+ #13
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
RIP: 0010:btrfs_create_pending_block_groups+0x3e6/0x470 [btrfs]
Call Trace:
__btrfs_end_transaction+0xdb/0x310 [btrfs]
btrfs_end_transaction+0x10/0x20 [btrfs]
btrfs_inc_block_group_ro+0x1c9/0x210 [btrfs]
scrub_enumerate_chunks+0x264/0x940 [btrfs]
btrfs_scrub_dev+0x45c/0x8f0 [btrfs]
btrfs_ioctl+0x31a1/0x3fb0 [btrfs]
do_vfs_ioctl+0x636/0xaa0
ksys_ioctl+0x67/0x90
__x64_sys_ioctl+0x43/0x50
do_syscall_64+0x79/0xe0
entry_SYSCALL_64_after_hwframe+0x49/0xbe
---[ end trace 166c865cec7688e7 ]---
[CAUSE]
The error number -27 is -EFBIG, returned from the following call chain:
btrfs_end_transaction()
|- __btrfs_end_transaction()
|- btrfs_create_pending_block_groups()
|- btrfs_finish_chunk_alloc()
|- btrfs_add_system_chunk()
This happens because we have used up all space of
btrfs_super_block::sys_chunk_array.
The root cause is, we have the following bad loop of creating tons of
system chunks:
1. The only SYSTEM chunk is being scrubbed
It's very common to have only one SYSTEM chunk.
2. New SYSTEM bg will be allocated
As btrfs_inc_block_group_ro() will check if we have enough space
after marking current bg RO. If not, then allocate a new chunk.
3. New SYSTEM bg is still empty, will be reclaimed
During the reclaim, we will mark it RO again.
4. That newly allocated empty SYSTEM bg get scrubbed
We go back to step 2, as the bg is already mark RO but still not
cleaned up yet.
If the cleaner kthread doesn't get executed fast enough (e.g. only one
CPU), then we will get more and more empty SYSTEM chunks, using up all
the space of btrfs_super_block::sys_chunk_array.
[FIX]
Since scrub/dev-replace doesn't always need to allocate new extent,
especially chunk tree extent, so we don't really need to do chunk
pre-allocation.
To break above spiral, here we introduce a new parameter to
btrfs_inc_block_group(), @do_chunk_alloc, which indicates whether we
need extra chunk pre-allocation.
For relocation, we pass @do_chunk_alloc=true, while for scrub, we pass
@do_chunk_alloc=false.
This should keep unnecessary empty chunks from popping up for scrub.
Also, since there are two parameters for btrfs_inc_block_group_ro(),
add more comment for it.
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2019-11-15 05:09:00 +03:00
|
|
|
int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
|
|
|
|
bool do_chunk_alloc);
|
2019-10-29 21:20:18 +03:00
|
|
|
void btrfs_dec_block_group_ro(struct btrfs_block_group *cache);
|
2019-06-20 22:38:00 +03:00
|
|
|
int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans);
|
|
|
|
int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans);
|
|
|
|
int btrfs_setup_space_cache(struct btrfs_trans_handle *trans);
|
2019-06-20 22:38:01 +03:00
|
|
|
int btrfs_update_block_group(struct btrfs_trans_handle *trans,
|
2021-10-13 09:05:14 +03:00
|
|
|
u64 bytenr, u64 num_bytes, bool alloc);
|
2019-10-29 21:20:18 +03:00
|
|
|
int btrfs_add_reserved_bytes(struct btrfs_block_group *cache,
|
2019-06-20 22:38:01 +03:00
|
|
|
u64 ram_bytes, u64 num_bytes, int delalloc);
|
2019-10-29 21:20:18 +03:00
|
|
|
void btrfs_free_reserved_bytes(struct btrfs_block_group *cache,
|
2019-06-20 22:38:01 +03:00
|
|
|
u64 num_bytes, int delalloc);
|
2019-06-20 22:38:04 +03:00
|
|
|
int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
|
|
|
|
enum btrfs_chunk_alloc_enum force);
|
|
|
|
int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type);
|
|
|
|
void check_system_chunk(struct btrfs_trans_handle *trans, const u64 type);
|
btrfs: fix deadlock between chunk allocation and chunk btree modifications
When a task is doing some modification to the chunk btree and it is not in
the context of a chunk allocation or a chunk removal, it can deadlock with
another task that is currently allocating a new data or metadata chunk.
These contexts are the following:
* When relocating a system chunk, when we need to COW the extent buffers
that belong to the chunk btree;
* When adding a new device (ioctl), where we need to add a new device item
to the chunk btree;
* When removing a device (ioctl), where we need to remove a device item
from the chunk btree;
* When resizing a device (ioctl), where we need to update a device item in
the chunk btree and may need to relocate a system chunk that lies beyond
the new device size when shrinking a device.
The problem happens due to a sequence of steps like the following:
1) Task A starts a data or metadata chunk allocation and it locks the
chunk mutex;
2) Task B is relocating a system chunk, and when it needs to COW an extent
buffer of the chunk btree, it has locked both that extent buffer as
well as its parent extent buffer;
3) Since there is not enough available system space, either because none
of the existing system block groups have enough free space or because
the only one with enough free space is in RO mode due to the relocation,
task B triggers a new system chunk allocation. It blocks when trying to
acquire the chunk mutex, currently held by task A;
4) Task A enters btrfs_chunk_alloc_add_chunk_item(), in order to insert
the new chunk item into the chunk btree and update the existing device
items there. But in order to do that, it has to lock the extent buffer
that task B locked at step 2, or its parent extent buffer, but task B
is waiting on the chunk mutex, which is currently locked by task A,
therefore resulting in a deadlock.
One example report when the deadlock happens with system chunk relocation:
INFO: task kworker/u9:5:546 blocked for more than 143 seconds.
Not tainted 5.15.0-rc3+ #1
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:kworker/u9:5 state:D stack:25936 pid: 546 ppid: 2 flags:0x00004000
Workqueue: events_unbound btrfs_async_reclaim_metadata_space
Call Trace:
context_switch kernel/sched/core.c:4940 [inline]
__schedule+0xcd9/0x2530 kernel/sched/core.c:6287
schedule+0xd3/0x270 kernel/sched/core.c:6366
rwsem_down_read_slowpath+0x4ee/0x9d0 kernel/locking/rwsem.c:993
__down_read_common kernel/locking/rwsem.c:1214 [inline]
__down_read kernel/locking/rwsem.c:1223 [inline]
down_read_nested+0xe6/0x440 kernel/locking/rwsem.c:1590
__btrfs_tree_read_lock+0x31/0x350 fs/btrfs/locking.c:47
btrfs_tree_read_lock fs/btrfs/locking.c:54 [inline]
btrfs_read_lock_root_node+0x8a/0x320 fs/btrfs/locking.c:191
btrfs_search_slot_get_root fs/btrfs/ctree.c:1623 [inline]
btrfs_search_slot+0x13b4/0x2140 fs/btrfs/ctree.c:1728
btrfs_update_device+0x11f/0x500 fs/btrfs/volumes.c:2794
btrfs_chunk_alloc_add_chunk_item+0x34d/0xea0 fs/btrfs/volumes.c:5504
do_chunk_alloc fs/btrfs/block-group.c:3408 [inline]
btrfs_chunk_alloc+0x84d/0xf50 fs/btrfs/block-group.c:3653
flush_space+0x54e/0xd80 fs/btrfs/space-info.c:670
btrfs_async_reclaim_metadata_space+0x396/0xa90 fs/btrfs/space-info.c:953
process_one_work+0x9df/0x16d0 kernel/workqueue.c:2297
worker_thread+0x90/0xed0 kernel/workqueue.c:2444
kthread+0x3e5/0x4d0 kernel/kthread.c:319
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:295
INFO: task syz-executor:9107 blocked for more than 143 seconds.
Not tainted 5.15.0-rc3+ #1
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:syz-executor state:D stack:23200 pid: 9107 ppid: 7792 flags:0x00004004
Call Trace:
context_switch kernel/sched/core.c:4940 [inline]
__schedule+0xcd9/0x2530 kernel/sched/core.c:6287
schedule+0xd3/0x270 kernel/sched/core.c:6366
schedule_preempt_disabled+0xf/0x20 kernel/sched/core.c:6425
__mutex_lock_common kernel/locking/mutex.c:669 [inline]
__mutex_lock+0xc96/0x1680 kernel/locking/mutex.c:729
btrfs_chunk_alloc+0x31a/0xf50 fs/btrfs/block-group.c:3631
find_free_extent_update_loop fs/btrfs/extent-tree.c:3986 [inline]
find_free_extent+0x25cb/0x3a30 fs/btrfs/extent-tree.c:4335
btrfs_reserve_extent+0x1f1/0x500 fs/btrfs/extent-tree.c:4415
btrfs_alloc_tree_block+0x203/0x1120 fs/btrfs/extent-tree.c:4813
__btrfs_cow_block+0x412/0x1620 fs/btrfs/ctree.c:415
btrfs_cow_block+0x2f6/0x8c0 fs/btrfs/ctree.c:570
btrfs_search_slot+0x1094/0x2140 fs/btrfs/ctree.c:1768
relocate_tree_block fs/btrfs/relocation.c:2694 [inline]
relocate_tree_blocks+0xf73/0x1770 fs/btrfs/relocation.c:2757
relocate_block_group+0x47e/0xc70 fs/btrfs/relocation.c:3673
btrfs_relocate_block_group+0x48a/0xc60 fs/btrfs/relocation.c:4070
btrfs_relocate_chunk+0x96/0x280 fs/btrfs/volumes.c:3181
__btrfs_balance fs/btrfs/volumes.c:3911 [inline]
btrfs_balance+0x1f03/0x3cd0 fs/btrfs/volumes.c:4301
btrfs_ioctl_balance+0x61e/0x800 fs/btrfs/ioctl.c:4137
btrfs_ioctl+0x39ea/0x7b70 fs/btrfs/ioctl.c:4949
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:874 [inline]
__se_sys_ioctl fs/ioctl.c:860 [inline]
__x64_sys_ioctl+0x193/0x200 fs/ioctl.c:860
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x44/0xae
So fix this by making sure that whenever we try to modify the chunk btree
and we are neither in a chunk allocation context nor in a chunk remove
context, we reserve system space before modifying the chunk btree.
Reported-by: Hao Sun <sunhao.th@gmail.com>
Link: https://lore.kernel.org/linux-btrfs/CACkBjsax51i4mu6C0C3vJqQN3NR_iVuucoeG3U1HXjrgzn5FFQ@mail.gmail.com/
Fixes: 79bd37120b1495 ("btrfs: rework chunk allocation to avoid exhaustion of the system chunk array")
CC: stable@vger.kernel.org # 5.14+
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2021-10-13 12:12:49 +03:00
|
|
|
void btrfs_reserve_chunk_metadata(struct btrfs_trans_handle *trans,
|
|
|
|
bool is_item_insertion);
|
2019-06-20 22:38:05 +03:00
|
|
|
u64 btrfs_get_alloc_profile(struct btrfs_fs_info *fs_info, u64 orig_flags);
|
2019-06-20 22:38:06 +03:00
|
|
|
void btrfs_put_block_group_cache(struct btrfs_fs_info *info);
|
|
|
|
int btrfs_free_block_groups(struct btrfs_fs_info *info);
|
2020-10-23 16:58:10 +03:00
|
|
|
void btrfs_wait_space_cache_v1_finished(struct btrfs_block_group *cache,
|
|
|
|
struct btrfs_caching_control *caching_ctl);
|
2021-02-04 13:22:02 +03:00
|
|
|
int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start,
|
|
|
|
struct block_device *bdev, u64 physical, u64 **logical,
|
|
|
|
int *naddrs, int *stripe_len);
|
2019-06-20 22:38:05 +03:00
|
|
|
|
|
|
|
static inline u64 btrfs_data_alloc_profile(struct btrfs_fs_info *fs_info)
|
|
|
|
{
|
|
|
|
return btrfs_get_alloc_profile(fs_info, BTRFS_BLOCK_GROUP_DATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u64 btrfs_metadata_alloc_profile(struct btrfs_fs_info *fs_info)
|
|
|
|
{
|
|
|
|
return btrfs_get_alloc_profile(fs_info, BTRFS_BLOCK_GROUP_METADATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u64 btrfs_system_alloc_profile(struct btrfs_fs_info *fs_info)
|
|
|
|
{
|
|
|
|
return btrfs_get_alloc_profile(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
|
|
|
|
}
|
2019-06-20 22:37:48 +03:00
|
|
|
|
2019-10-29 21:20:18 +03:00
|
|
|
static inline int btrfs_block_group_done(struct btrfs_block_group *cache)
|
2019-06-20 22:37:48 +03:00
|
|
|
{
|
|
|
|
smp_mb();
|
|
|
|
return cache->cached == BTRFS_CACHE_FINISHED ||
|
|
|
|
cache->cached == BTRFS_CACHE_ERROR;
|
|
|
|
}
|
2019-06-20 22:37:45 +03:00
|
|
|
|
2020-05-08 13:01:59 +03:00
|
|
|
void btrfs_freeze_block_group(struct btrfs_block_group *cache);
|
|
|
|
void btrfs_unfreeze_block_group(struct btrfs_block_group *cache);
|
|
|
|
|
btrfs: fix race between writes to swap files and scrub
When we active a swap file, at btrfs_swap_activate(), we acquire the
exclusive operation lock to prevent the physical location of the swap
file extents to be changed by operations such as balance and device
replace/resize/remove. We also call there can_nocow_extent() which,
among other things, checks if the block group of a swap file extent is
currently RO, and if it is we can not use the extent, since a write
into it would result in COWing the extent.
However we have no protection against a scrub operation running after we
activate the swap file, which can result in the swap file extents to be
COWed while the scrub is running and operating on the respective block
group, because scrub turns a block group into RO before it processes it
and then back again to RW mode after processing it. That means an attempt
to write into a swap file extent while scrub is processing the respective
block group, will result in COWing the extent, changing its physical
location on disk.
Fix this by making sure that block groups that have extents that are used
by active swap files can not be turned into RO mode, therefore making it
not possible for a scrub to turn them into RO mode. When a scrub finds a
block group that can not be turned to RO due to the existence of extents
used by swap files, it proceeds to the next block group and logs a warning
message that mentions the block group was skipped due to active swap
files - this is the same approach we currently use for balance.
Fixes: ed46ff3d42378 ("Btrfs: support swap files")
CC: stable@vger.kernel.org # 5.4+
Reviewed-by: Anand Jain <anand.jain@oracle.com>
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2021-02-05 15:55:37 +03:00
|
|
|
bool btrfs_inc_block_group_swap_extents(struct btrfs_block_group *bg);
|
|
|
|
void btrfs_dec_block_group_swap_extents(struct btrfs_block_group *bg, int amount);
|
|
|
|
|
2019-06-20 22:37:44 +03:00
|
|
|
#endif /* BTRFS_BLOCK_GROUP_H */
|