Merge tag 'for-6.16-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs updates from David Sterba:
"Apart from numerous cleanups, there are some performance improvements
and one minor mount option update. There's one more radix-tree
conversion (one remaining), and continued work towards enabling large
folios (almost finished).
Performance:
- extent buffer conversion to xarray gains throughput and runtime
improvements on metadata heavy operations doing writeback (sample
test shows +50% throughput, -33% runtime)
- extent io tree cleanups lead to performance improvements by
avoiding unnecessary searches or repeated searches
- more efficient extent unpinning when committing transaction
(estimated run time improvement 3-5%)
User visible changes:
- remove standalone mount option 'nologreplay', deprecated in 5.9,
replacement is 'rescue=nologreplay'
- in scrub, update reporting, add back device stats message after
detected errors (accidentally removed during recent refactoring)
Core:
- convert extent buffer radix tree to xarray
- in subpage mode, move block perfect compression out of experimental
build
- in zoned mode, introduce sub block groups to allow managing special
block groups, like the one for relocation or tree-log, to handle
some corner cases of ENOSPC
- in scrub, simplify bitmaps for block tracking status
- continued preparations for large folios:
- remove assertions for folio order 0
- add support where missing: compression, buffered write, defrag,
hole punching, subpage, send
- fix fsync of files with no hard links not persisting deletion
- reject tree blocks which are not nodesize aligned, a precaution
from 4.9 times
- move transaction abort calls closer to the error sites
- remove usage of some struct bio_vec internals
- simplifications in extent map
- extent IO cleanups and optimizations
- error handling improvements
- enhanced ASSERT() macro with optional format strings
- cleanups:
- remove unused code
- naming unifications, dropped __, added prefix
- merge similar functions
- use common helpers for various data structures"
* tag 'for-6.16-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (198 commits)
btrfs: move misplaced comment of btrfs_path::keep_locks
btrfs: remove standalone "nologreplay" mount option
btrfs: use a single variable to track return value at btrfs_page_mkwrite()
btrfs: don't return VM_FAULT_SIGBUS on failure to set delalloc for mmap write
btrfs: simplify early error checking in btrfs_page_mkwrite()
btrfs: pass true to btrfs_delalloc_release_space() at btrfs_page_mkwrite()
btrfs: fix wrong start offset for delalloc space release during mmap write
btrfs: fix harmless race getting delayed ref head count when running delayed refs
btrfs: log error codes during failures when writing super blocks
btrfs: simplify error return logic when getting folio at prepare_one_folio()
btrfs: return real error from __filemap_get_folio() calls
btrfs: remove superfluous return value check at btrfs_dio_iomap_begin()
btrfs: fix invalid data space release when truncating block in NOCOW mode
btrfs: update Kconfig option descriptions
btrfs: update list of features built under experimental config
btrfs: send: remove btrfs_debug() calls
btrfs: use boolean for delalloc argument to btrfs_free_reserved_extent()
btrfs: use boolean for delalloc argument to btrfs_free_reserved_bytes()
btrfs: fold error checks when allocating ordered extent and update comments
btrfs: check we grabbed inode reference when allocating an ordered extent
...
This commit is contained in:
+22
-10
@@ -52,10 +52,10 @@ config BTRFS_FS_RUN_SANITY_TESTS
|
||||
bool "Btrfs will run sanity tests upon loading"
|
||||
depends on BTRFS_FS
|
||||
help
|
||||
This will run some basic sanity tests on the free space cache
|
||||
code to make sure it is acting as it should. These are mostly
|
||||
regression tests and are only really interesting to btrfs
|
||||
developers.
|
||||
This will run sanity tests for core functionality like free space,
|
||||
extent maps, extent io, extent buffers, inodes, qgroups and others,
|
||||
at module load time. These are mostly regression tests and are only
|
||||
interesting to developers.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
@@ -63,9 +63,12 @@ config BTRFS_DEBUG
|
||||
bool "Btrfs debugging support"
|
||||
depends on BTRFS_FS
|
||||
help
|
||||
Enable run-time debugging support for the btrfs filesystem. This may
|
||||
enable additional and expensive checks with negative impact on
|
||||
performance, or export extra information via sysfs.
|
||||
Enable run-time debugging support for the btrfs filesystem.
|
||||
|
||||
Additional potentially expensive checks, debugging functionality or
|
||||
sysfs exported information is enabled, like leak checks of internal
|
||||
objects, optional forced space fragmentation and /sys/fs/btrfs/debug .
|
||||
This has negative impact on performance.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
@@ -73,8 +76,10 @@ config BTRFS_ASSERT
|
||||
bool "Btrfs assert support"
|
||||
depends on BTRFS_FS
|
||||
help
|
||||
Enable run-time assertion checking. This will result in panics if
|
||||
any of the assertions trip. This is meant for btrfs developers only.
|
||||
Enable run-time assertion checking. Additional safety checks are
|
||||
done, simple enough not to affect performance but verify invariants
|
||||
and assumptions of code to run properly. This may result in panics,
|
||||
and is meant for developers but can be enabled in general.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
@@ -89,7 +94,14 @@ config BTRFS_EXPERIMENTAL
|
||||
|
||||
Current list:
|
||||
|
||||
- extent map shrinker - performance problems with too frequent shrinks
|
||||
- COW fixup worker warning - last warning before removing the
|
||||
functionality catching out-of-band page
|
||||
dirtying, not necessary since 5.8
|
||||
|
||||
- RAID mirror read policy - additional read policies for balancing
|
||||
reading from redundant block group
|
||||
profiles (currently: pid, round-robin,
|
||||
fixed devid)
|
||||
|
||||
- send stream protocol v3 - fs-verity support
|
||||
|
||||
|
||||
@@ -219,8 +219,7 @@ static void run_ordered_work(struct btrfs_workqueue *wq,
|
||||
spin_lock_irqsave(lock, flags);
|
||||
if (list_empty(list))
|
||||
break;
|
||||
work = list_entry(list->next, struct btrfs_work,
|
||||
ordered_list);
|
||||
work = list_first_entry(list, struct btrfs_work, ordered_list);
|
||||
if (!test_bit(WORK_DONE_BIT, &work->flags))
|
||||
break;
|
||||
/*
|
||||
|
||||
+6
-6
@@ -2877,7 +2877,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
|
||||
goto release;
|
||||
}
|
||||
if (path->slots[0] == 0) {
|
||||
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
|
||||
DEBUG_WARN();
|
||||
ret = -EUCLEAN;
|
||||
goto release;
|
||||
}
|
||||
@@ -3134,8 +3134,8 @@ void btrfs_backref_cleanup_node(struct btrfs_backref_cache *cache,
|
||||
return;
|
||||
|
||||
while (!list_empty(&node->upper)) {
|
||||
edge = list_entry(node->upper.next, struct btrfs_backref_edge,
|
||||
list[LOWER]);
|
||||
edge = list_first_entry(&node->upper, struct btrfs_backref_edge,
|
||||
list[LOWER]);
|
||||
list_del(&edge->list[LOWER]);
|
||||
list_del(&edge->list[UPPER]);
|
||||
btrfs_backref_free_edge(cache, edge);
|
||||
@@ -3473,8 +3473,8 @@ int btrfs_backref_add_tree_node(struct btrfs_trans_handle *trans,
|
||||
* type BTRFS_TREE_BLOCK_REF_KEY
|
||||
*/
|
||||
ASSERT(list_is_singular(&cur->upper));
|
||||
edge = list_entry(cur->upper.next, struct btrfs_backref_edge,
|
||||
list[LOWER]);
|
||||
edge = list_first_entry(&cur->upper, struct btrfs_backref_edge,
|
||||
list[LOWER]);
|
||||
ASSERT(list_empty(&edge->list[UPPER]));
|
||||
exist = edge->node[UPPER];
|
||||
/*
|
||||
@@ -3617,7 +3617,7 @@ int btrfs_backref_finish_upper_links(struct btrfs_backref_cache *cache,
|
||||
|
||||
/* Sanity check, we shouldn't have any unchecked nodes */
|
||||
if (!upper->checked) {
|
||||
ASSERT(0);
|
||||
DEBUG_WARN("we should not have any unchecked nodes");
|
||||
return -EUCLEAN;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -423,8 +423,8 @@ struct btrfs_backref_node *btrfs_backref_alloc_node(
|
||||
struct btrfs_backref_edge *btrfs_backref_alloc_edge(
|
||||
struct btrfs_backref_cache *cache);
|
||||
|
||||
#define LINK_LOWER (1 << 0)
|
||||
#define LINK_UPPER (1 << 1)
|
||||
#define LINK_LOWER (1U << 0)
|
||||
#define LINK_UPPER (1U << 1)
|
||||
|
||||
void btrfs_backref_link_edge(struct btrfs_backref_edge *edge,
|
||||
struct btrfs_backref_node *lower,
|
||||
|
||||
+26
-29
@@ -192,7 +192,7 @@ static void btrfs_end_repair_bio(struct btrfs_bio *repair_bbio,
|
||||
btrfs_repair_io_failure(fs_info, btrfs_ino(inode),
|
||||
repair_bbio->file_offset, fs_info->sectorsize,
|
||||
repair_bbio->saved_iter.bi_sector << SECTOR_SHIFT,
|
||||
page_folio(bv->bv_page), bv->bv_offset, mirror);
|
||||
bvec_phys(bv), mirror);
|
||||
} while (mirror != fbio->bbio->mirror_num);
|
||||
|
||||
done:
|
||||
@@ -512,7 +512,7 @@ static void btrfs_submit_bio(struct bio *bio, struct btrfs_io_context *bioc,
|
||||
}
|
||||
}
|
||||
|
||||
static blk_status_t btrfs_bio_csum(struct btrfs_bio *bbio)
|
||||
static int btrfs_bio_csum(struct btrfs_bio *bbio)
|
||||
{
|
||||
if (bbio->bio.bi_opf & REQ_META)
|
||||
return btree_csum_one_bio(bbio);
|
||||
@@ -543,11 +543,11 @@ static void run_one_async_start(struct btrfs_work *work)
|
||||
{
|
||||
struct async_submit_bio *async =
|
||||
container_of(work, struct async_submit_bio, work);
|
||||
blk_status_t ret;
|
||||
int ret;
|
||||
|
||||
ret = btrfs_bio_csum(async->bbio);
|
||||
if (ret)
|
||||
async->bbio->bio.bi_status = ret;
|
||||
async->bbio->bio.bi_status = errno_to_blk_status(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -674,8 +674,8 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num)
|
||||
bool use_append = btrfs_use_zone_append(bbio);
|
||||
struct btrfs_io_context *bioc = NULL;
|
||||
struct btrfs_io_stripe smap;
|
||||
blk_status_t ret;
|
||||
int error;
|
||||
blk_status_t status;
|
||||
int ret;
|
||||
|
||||
if (!bbio->inode || btrfs_is_data_reloc_root(inode->root))
|
||||
smap.rst_search_commit_root = true;
|
||||
@@ -683,10 +683,10 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num)
|
||||
smap.rst_search_commit_root = false;
|
||||
|
||||
btrfs_bio_counter_inc_blocked(fs_info);
|
||||
error = btrfs_map_block(fs_info, btrfs_op(bio), logical, &map_length,
|
||||
&bioc, &smap, &mirror_num);
|
||||
if (error) {
|
||||
ret = errno_to_blk_status(error);
|
||||
ret = btrfs_map_block(fs_info, btrfs_op(bio), logical, &map_length,
|
||||
&bioc, &smap, &mirror_num);
|
||||
if (ret) {
|
||||
status = errno_to_blk_status(ret);
|
||||
btrfs_bio_counter_dec(fs_info);
|
||||
goto end_bbio;
|
||||
}
|
||||
@@ -700,7 +700,7 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num)
|
||||
|
||||
split = btrfs_split_bio(fs_info, bbio, map_length);
|
||||
if (IS_ERR(split)) {
|
||||
ret = errno_to_blk_status(PTR_ERR(split));
|
||||
status = errno_to_blk_status(PTR_ERR(split));
|
||||
btrfs_bio_counter_dec(fs_info);
|
||||
goto end_bbio;
|
||||
}
|
||||
@@ -715,7 +715,8 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num)
|
||||
if (bio_op(bio) == REQ_OP_READ && is_data_bbio(bbio)) {
|
||||
bbio->saved_iter = bio->bi_iter;
|
||||
ret = btrfs_lookup_bio_sums(bbio);
|
||||
if (ret)
|
||||
status = errno_to_blk_status(ret);
|
||||
if (status)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -748,13 +749,15 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num)
|
||||
goto done;
|
||||
|
||||
ret = btrfs_bio_csum(bbio);
|
||||
if (ret)
|
||||
status = errno_to_blk_status(ret);
|
||||
if (status)
|
||||
goto fail;
|
||||
} else if (use_append ||
|
||||
(btrfs_is_zoned(fs_info) && inode &&
|
||||
inode->flags & BTRFS_INODE_NODATASUM)) {
|
||||
ret = btrfs_alloc_dummy_sum(bbio);
|
||||
if (ret)
|
||||
status = errno_to_blk_status(ret);
|
||||
if (status)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -775,10 +778,10 @@ fail:
|
||||
ASSERT(bbio->bio.bi_pool == &btrfs_clone_bioset);
|
||||
ASSERT(remaining);
|
||||
|
||||
btrfs_bio_end_io(remaining, ret);
|
||||
btrfs_bio_end_io(remaining, status);
|
||||
}
|
||||
end_bbio:
|
||||
btrfs_bio_end_io(bbio, ret);
|
||||
btrfs_bio_end_io(bbio, status);
|
||||
/* Do not submit another chunk */
|
||||
return true;
|
||||
}
|
||||
@@ -803,8 +806,7 @@ void btrfs_submit_bbio(struct btrfs_bio *bbio, int mirror_num)
|
||||
* freeing the bio.
|
||||
*/
|
||||
int btrfs_repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start,
|
||||
u64 length, u64 logical, struct folio *folio,
|
||||
unsigned int folio_offset, int mirror_num)
|
||||
u64 length, u64 logical, phys_addr_t paddr, int mirror_num)
|
||||
{
|
||||
struct btrfs_io_stripe smap = { 0 };
|
||||
struct bio_vec bvec;
|
||||
@@ -835,8 +837,7 @@ int btrfs_repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start,
|
||||
|
||||
bio_init(&bio, smap.dev->bdev, &bvec, 1, REQ_OP_WRITE | REQ_SYNC);
|
||||
bio.bi_iter.bi_sector = smap.physical >> SECTOR_SHIFT;
|
||||
ret = bio_add_folio(&bio, folio, length, folio_offset);
|
||||
ASSERT(ret);
|
||||
__bio_add_page(&bio, phys_to_page(paddr), length, offset_in_page(paddr));
|
||||
ret = submit_bio_wait(&bio);
|
||||
if (ret) {
|
||||
/* try to remap that extent elsewhere? */
|
||||
@@ -900,22 +901,18 @@ int __init btrfs_bioset_init(void)
|
||||
return -ENOMEM;
|
||||
if (bioset_init(&btrfs_clone_bioset, BIO_POOL_SIZE,
|
||||
offsetof(struct btrfs_bio, bio), 0))
|
||||
goto out_free_bioset;
|
||||
goto out;
|
||||
if (bioset_init(&btrfs_repair_bioset, BIO_POOL_SIZE,
|
||||
offsetof(struct btrfs_bio, bio),
|
||||
BIOSET_NEED_BVECS))
|
||||
goto out_free_clone_bioset;
|
||||
goto out;
|
||||
if (mempool_init_kmalloc_pool(&btrfs_failed_bio_pool, BIO_POOL_SIZE,
|
||||
sizeof(struct btrfs_failed_bio)))
|
||||
goto out_free_repair_bioset;
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
out_free_repair_bioset:
|
||||
bioset_exit(&btrfs_repair_bioset);
|
||||
out_free_clone_bioset:
|
||||
bioset_exit(&btrfs_clone_bioset);
|
||||
out_free_bioset:
|
||||
bioset_exit(&btrfs_bioset);
|
||||
out:
|
||||
btrfs_bioset_exit();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -110,7 +110,6 @@ void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status);
|
||||
void btrfs_submit_bbio(struct btrfs_bio *bbio, int mirror_num);
|
||||
void btrfs_submit_repair_write(struct btrfs_bio *bbio, int mirror_num, bool dev_replace);
|
||||
int btrfs_repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start,
|
||||
u64 length, u64 logical, struct folio *folio,
|
||||
unsigned int folio_offset, int mirror_num);
|
||||
u64 length, u64 logical, phys_addr_t paddr, int mirror_num);
|
||||
|
||||
#endif
|
||||
|
||||
+116
-80
@@ -525,10 +525,9 @@ int btrfs_add_new_free_space(struct btrfs_block_group *block_group, u64 start,
|
||||
*total_added_ret = 0;
|
||||
|
||||
while (start < end) {
|
||||
if (!find_first_extent_bit(&info->excluded_extents, start,
|
||||
&extent_start, &extent_end,
|
||||
EXTENT_DIRTY | EXTENT_UPTODATE,
|
||||
NULL))
|
||||
if (!btrfs_find_first_extent_bit(&info->excluded_extents, start,
|
||||
&extent_start, &extent_end,
|
||||
EXTENT_DIRTY, NULL))
|
||||
break;
|
||||
|
||||
if (extent_start <= start) {
|
||||
@@ -701,7 +700,7 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)
|
||||
struct btrfs_block_group *block_group = caching_ctl->block_group;
|
||||
struct btrfs_fs_info *fs_info = block_group->fs_info;
|
||||
struct btrfs_root *extent_root;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_key key;
|
||||
u64 total_found = 0;
|
||||
@@ -828,14 +827,13 @@ next:
|
||||
block_group->start + block_group->length,
|
||||
NULL);
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void btrfs_free_excluded_extents(const struct btrfs_block_group *bg)
|
||||
{
|
||||
clear_extent_bits(&bg->fs_info->excluded_extents, bg->start,
|
||||
bg->start + bg->length - 1, EXTENT_UPTODATE);
|
||||
btrfs_clear_extent_bits(&bg->fs_info->excluded_extents, bg->start,
|
||||
bg->start + bg->length - 1, EXTENT_DIRTY);
|
||||
}
|
||||
|
||||
static noinline void caching_thread(struct btrfs_work *work)
|
||||
@@ -1420,9 +1418,8 @@ static bool clean_pinned_extents(struct btrfs_trans_handle *trans,
|
||||
int ret;
|
||||
|
||||
spin_lock(&fs_info->trans_lock);
|
||||
if (trans->transaction->list.prev != &fs_info->trans_list) {
|
||||
prev_trans = list_last_entry(&trans->transaction->list,
|
||||
struct btrfs_transaction, list);
|
||||
if (!list_is_first(&trans->transaction->list, &fs_info->trans_list)) {
|
||||
prev_trans = list_prev_entry(trans->transaction, list);
|
||||
refcount_inc(&prev_trans->use_count);
|
||||
}
|
||||
spin_unlock(&fs_info->trans_lock);
|
||||
@@ -1439,14 +1436,14 @@ static bool clean_pinned_extents(struct btrfs_trans_handle *trans,
|
||||
*/
|
||||
mutex_lock(&fs_info->unused_bg_unpin_mutex);
|
||||
if (prev_trans) {
|
||||
ret = clear_extent_bits(&prev_trans->pinned_extents, start, end,
|
||||
EXTENT_DIRTY);
|
||||
ret = btrfs_clear_extent_bits(&prev_trans->pinned_extents, start, end,
|
||||
EXTENT_DIRTY);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = clear_extent_bits(&trans->transaction->pinned_extents, start, end,
|
||||
EXTENT_DIRTY);
|
||||
ret = btrfs_clear_extent_bits(&trans->transaction->pinned_extents, start, end,
|
||||
EXTENT_DIRTY);
|
||||
out:
|
||||
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
|
||||
if (prev_trans)
|
||||
@@ -2218,9 +2215,9 @@ static int exclude_super_stripes(struct btrfs_block_group *cache)
|
||||
if (cache->start < BTRFS_SUPER_INFO_OFFSET) {
|
||||
stripe_len = BTRFS_SUPER_INFO_OFFSET - cache->start;
|
||||
cache->bytes_super += stripe_len;
|
||||
ret = set_extent_bit(&fs_info->excluded_extents, cache->start,
|
||||
cache->start + stripe_len - 1,
|
||||
EXTENT_UPTODATE, NULL);
|
||||
ret = btrfs_set_extent_bit(&fs_info->excluded_extents, cache->start,
|
||||
cache->start + stripe_len - 1,
|
||||
EXTENT_DIRTY, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -2246,9 +2243,9 @@ static int exclude_super_stripes(struct btrfs_block_group *cache)
|
||||
cache->start + cache->length - logical[nr]);
|
||||
|
||||
cache->bytes_super += len;
|
||||
ret = set_extent_bit(&fs_info->excluded_extents, logical[nr],
|
||||
logical[nr] + len - 1,
|
||||
EXTENT_UPTODATE, NULL);
|
||||
ret = btrfs_set_extent_bit(&fs_info->excluded_extents,
|
||||
logical[nr], logical[nr] + len - 1,
|
||||
EXTENT_DIRTY, NULL);
|
||||
if (ret) {
|
||||
kfree(logical);
|
||||
return ret;
|
||||
@@ -2373,6 +2370,7 @@ static int read_one_block_group(struct btrfs_fs_info *info,
|
||||
cache->commit_used = cache->used;
|
||||
cache->flags = btrfs_stack_block_group_flags(bgi);
|
||||
cache->global_root_id = btrfs_stack_block_group_chunk_objectid(bgi);
|
||||
cache->space_info = btrfs_find_space_info(info, cache->flags);
|
||||
|
||||
set_free_space_tree_thresholds(cache);
|
||||
|
||||
@@ -2451,6 +2449,7 @@ static int read_one_block_group(struct btrfs_fs_info *info,
|
||||
btrfs_remove_free_space_cache(cache);
|
||||
goto error;
|
||||
}
|
||||
|
||||
trace_btrfs_add_block_group(info, cache, 0);
|
||||
btrfs_add_bg_to_space_info(info, cache);
|
||||
|
||||
@@ -2495,6 +2494,7 @@ static int fill_dummy_bgs(struct btrfs_fs_info *fs_info)
|
||||
bg->cached = BTRFS_CACHE_FINISHED;
|
||||
bg->used = map->chunk_len;
|
||||
bg->flags = map->type;
|
||||
bg->space_info = btrfs_find_space_info(fs_info, bg->flags);
|
||||
ret = btrfs_add_block_group_cache(bg);
|
||||
/*
|
||||
* We may have some valid block group cache added already, in
|
||||
@@ -2868,8 +2868,8 @@ static u64 calculate_global_root_id(const struct btrfs_fs_info *fs_info, u64 off
|
||||
}
|
||||
|
||||
struct btrfs_block_group *btrfs_make_block_group(struct btrfs_trans_handle *trans,
|
||||
u64 type,
|
||||
u64 chunk_offset, u64 size)
|
||||
struct btrfs_space_info *space_info,
|
||||
u64 type, u64 chunk_offset, u64 size)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
struct btrfs_block_group *cache;
|
||||
@@ -2923,7 +2923,7 @@ struct btrfs_block_group *btrfs_make_block_group(struct btrfs_trans_handle *tran
|
||||
* assigned to our block group. We want our bg to be added to the rbtree
|
||||
* with its ->space_info set.
|
||||
*/
|
||||
cache->space_info = btrfs_find_space_info(fs_info, cache->flags);
|
||||
cache->space_info = space_info;
|
||||
ASSERT(cache->space_info);
|
||||
|
||||
ret = btrfs_add_block_group_cache(cache);
|
||||
@@ -2968,6 +2968,7 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
|
||||
bool do_chunk_alloc)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = cache->fs_info;
|
||||
struct btrfs_space_info *space_info = cache->space_info;
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_root *root = btrfs_block_group_root(fs_info);
|
||||
u64 alloc_flags;
|
||||
@@ -3020,7 +3021,7 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
|
||||
*/
|
||||
alloc_flags = btrfs_get_alloc_profile(fs_info, cache->flags);
|
||||
if (alloc_flags != cache->flags) {
|
||||
ret = btrfs_chunk_alloc(trans, alloc_flags,
|
||||
ret = btrfs_chunk_alloc(trans, space_info, alloc_flags,
|
||||
CHUNK_ALLOC_FORCE);
|
||||
/*
|
||||
* ENOSPC is allowed here, we may have enough space
|
||||
@@ -3048,15 +3049,15 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
|
||||
(cache->flags & BTRFS_BLOCK_GROUP_SYSTEM))
|
||||
goto unlock_out;
|
||||
|
||||
alloc_flags = btrfs_get_alloc_profile(fs_info, cache->space_info->flags);
|
||||
ret = btrfs_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);
|
||||
alloc_flags = btrfs_get_alloc_profile(fs_info, space_info->flags);
|
||||
ret = btrfs_chunk_alloc(trans, space_info, alloc_flags, CHUNK_ALLOC_FORCE);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
/*
|
||||
* We have allocated a new chunk. We also need to activate that chunk to
|
||||
* grant metadata tickets for zoned filesystem.
|
||||
*/
|
||||
ret = btrfs_zoned_activate_one_bg(fs_info, cache->space_info, true);
|
||||
ret = btrfs_zoned_activate_one_bg(fs_info, space_info, true);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -3738,8 +3739,8 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
|
||||
spin_unlock(&cache->lock);
|
||||
spin_unlock(&space_info->lock);
|
||||
|
||||
set_extent_bit(&trans->transaction->pinned_extents, bytenr,
|
||||
bytenr + num_bytes - 1, EXTENT_DIRTY, NULL);
|
||||
btrfs_set_extent_bit(&trans->transaction->pinned_extents, bytenr,
|
||||
bytenr + num_bytes - 1, EXTENT_DIRTY, NULL);
|
||||
}
|
||||
|
||||
spin_lock(&trans->transaction->dirty_bgs_lock);
|
||||
@@ -3828,17 +3829,17 @@ out:
|
||||
/*
|
||||
* Update the block_group and space info counters.
|
||||
*
|
||||
* @cache: The cache we are manipulating
|
||||
* @num_bytes: The number of bytes in question
|
||||
* @delalloc: The blocks are allocated for the delalloc write
|
||||
* @cache: The cache we are manipulating.
|
||||
* @num_bytes: The number of bytes in question.
|
||||
* @is_delalloc: Whether the blocks are allocated for a delalloc write.
|
||||
*
|
||||
* This is called by somebody who is freeing space that was never actually used
|
||||
* on disk. For example if you reserve some space for a new leaf in transaction
|
||||
* A and before transaction A commits you free that leaf, you call this with
|
||||
* reserve set to 0 in order to clear the reservation.
|
||||
*/
|
||||
void btrfs_free_reserved_bytes(struct btrfs_block_group *cache,
|
||||
u64 num_bytes, int delalloc)
|
||||
void btrfs_free_reserved_bytes(struct btrfs_block_group *cache, u64 num_bytes,
|
||||
bool is_delalloc)
|
||||
{
|
||||
struct btrfs_space_info *space_info = cache->space_info;
|
||||
|
||||
@@ -3852,7 +3853,7 @@ void btrfs_free_reserved_bytes(struct btrfs_block_group *cache,
|
||||
space_info->bytes_reserved -= num_bytes;
|
||||
space_info->max_extent_size = 0;
|
||||
|
||||
if (delalloc)
|
||||
if (is_delalloc)
|
||||
cache->delalloc_bytes -= num_bytes;
|
||||
spin_unlock(&cache->lock);
|
||||
|
||||
@@ -3871,14 +3872,14 @@ static void force_metadata_allocation(struct btrfs_fs_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
static int should_alloc_chunk(const struct btrfs_fs_info *fs_info,
|
||||
const struct btrfs_space_info *sinfo, int force)
|
||||
static bool should_alloc_chunk(const struct btrfs_fs_info *fs_info,
|
||||
const struct btrfs_space_info *sinfo, int force)
|
||||
{
|
||||
u64 bytes_used = btrfs_space_info_used(sinfo, false);
|
||||
u64 thresh;
|
||||
|
||||
if (force == CHUNK_ALLOC_FORCE)
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
/*
|
||||
* in limited mode, we want to have some free space up to
|
||||
@@ -3889,22 +3890,31 @@ static int should_alloc_chunk(const struct btrfs_fs_info *fs_info,
|
||||
thresh = max_t(u64, SZ_64M, mult_perc(thresh, 1));
|
||||
|
||||
if (sinfo->total_bytes - bytes_used < thresh)
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bytes_used + SZ_2M < mult_perc(sinfo->total_bytes, 80))
|
||||
return 0;
|
||||
return 1;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type)
|
||||
{
|
||||
u64 alloc_flags = btrfs_get_alloc_profile(trans->fs_info, type);
|
||||
struct btrfs_space_info *space_info;
|
||||
|
||||
return btrfs_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);
|
||||
space_info = btrfs_find_space_info(trans->fs_info, type);
|
||||
if (!space_info) {
|
||||
DEBUG_WARN();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return btrfs_chunk_alloc(trans, space_info, alloc_flags, CHUNK_ALLOC_FORCE);
|
||||
}
|
||||
|
||||
static struct btrfs_block_group *do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags)
|
||||
static struct btrfs_block_group *do_chunk_alloc(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_space_info *space_info,
|
||||
u64 flags)
|
||||
{
|
||||
struct btrfs_block_group *bg;
|
||||
int ret;
|
||||
@@ -3917,7 +3927,7 @@ static struct btrfs_block_group *do_chunk_alloc(struct btrfs_trans_handle *trans
|
||||
*/
|
||||
check_system_chunk(trans, flags);
|
||||
|
||||
bg = btrfs_create_chunk(trans, flags);
|
||||
bg = btrfs_create_chunk(trans, space_info, flags);
|
||||
if (IS_ERR(bg)) {
|
||||
ret = PTR_ERR(bg);
|
||||
goto out;
|
||||
@@ -3965,8 +3975,16 @@ static struct btrfs_block_group *do_chunk_alloc(struct btrfs_trans_handle *trans
|
||||
if (ret == -ENOSPC) {
|
||||
const u64 sys_flags = btrfs_system_alloc_profile(trans->fs_info);
|
||||
struct btrfs_block_group *sys_bg;
|
||||
struct btrfs_space_info *sys_space_info;
|
||||
|
||||
sys_bg = btrfs_create_chunk(trans, sys_flags);
|
||||
sys_space_info = btrfs_find_space_info(trans->fs_info, sys_flags);
|
||||
if (!sys_space_info) {
|
||||
ret = -EINVAL;
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sys_bg = btrfs_create_chunk(trans, sys_space_info, sys_flags);
|
||||
if (IS_ERR(sys_bg)) {
|
||||
ret = PTR_ERR(sys_bg);
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
@@ -4097,6 +4115,8 @@ out:
|
||||
*
|
||||
* This function, btrfs_chunk_alloc(), belongs to phase 1.
|
||||
*
|
||||
* @space_info: specify which space_info the new chunk should belong to.
|
||||
*
|
||||
* If @force is CHUNK_ALLOC_FORCE:
|
||||
* - return 1 if it successfully allocates a chunk,
|
||||
* - return errors including -ENOSPC otherwise.
|
||||
@@ -4105,11 +4125,11 @@ out:
|
||||
* - return 1 if it successfully allocates a chunk,
|
||||
* - return errors including -ENOSPC otherwise.
|
||||
*/
|
||||
int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
|
||||
int btrfs_chunk_alloc(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_space_info *space_info, u64 flags,
|
||||
enum btrfs_chunk_alloc_enum force)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
struct btrfs_space_info *space_info;
|
||||
struct btrfs_block_group *ret_bg;
|
||||
bool wait_for_alloc = false;
|
||||
bool should_alloc = false;
|
||||
@@ -4148,9 +4168,6 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
|
||||
if (flags & BTRFS_BLOCK_GROUP_SYSTEM)
|
||||
return -ENOSPC;
|
||||
|
||||
space_info = btrfs_find_space_info(fs_info, flags);
|
||||
ASSERT(space_info);
|
||||
|
||||
do {
|
||||
spin_lock(&space_info->lock);
|
||||
if (force < space_info->force_alloc)
|
||||
@@ -4211,7 +4228,7 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
|
||||
force_metadata_allocation(fs_info);
|
||||
}
|
||||
|
||||
ret_bg = do_chunk_alloc(trans, flags);
|
||||
ret_bg = do_chunk_alloc(trans, space_info, flags);
|
||||
trans->allocating_chunk = false;
|
||||
|
||||
if (IS_ERR(ret_bg)) {
|
||||
@@ -4287,6 +4304,10 @@ static void reserve_chunk_space(struct btrfs_trans_handle *trans,
|
||||
if (left < bytes) {
|
||||
u64 flags = btrfs_system_alloc_profile(fs_info);
|
||||
struct btrfs_block_group *bg;
|
||||
struct btrfs_space_info *space_info;
|
||||
|
||||
space_info = btrfs_find_space_info(fs_info, flags);
|
||||
ASSERT(space_info);
|
||||
|
||||
/*
|
||||
* Ignore failure to create system chunk. We might end up not
|
||||
@@ -4294,7 +4315,7 @@ static void reserve_chunk_space(struct btrfs_trans_handle *trans,
|
||||
* the paths we visit in the chunk tree (they were already COWed
|
||||
* or created in the current transaction for example).
|
||||
*/
|
||||
bg = btrfs_create_chunk(trans, flags);
|
||||
bg = btrfs_create_chunk(trans, space_info, flags);
|
||||
if (IS_ERR(bg)) {
|
||||
ret = PTR_ERR(bg);
|
||||
} else {
|
||||
@@ -4402,6 +4423,43 @@ void btrfs_put_block_group_cache(struct btrfs_fs_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
static void check_removing_space_info(struct btrfs_space_info *space_info)
|
||||
{
|
||||
struct btrfs_fs_info *info = space_info->fs_info;
|
||||
|
||||
if (space_info->subgroup_id == BTRFS_SUB_GROUP_PRIMARY) {
|
||||
/* This is a top space_info, proceed with its children first. */
|
||||
for (int i = 0; i < BTRFS_SPACE_INFO_SUB_GROUP_MAX; i++) {
|
||||
if (space_info->sub_group[i]) {
|
||||
check_removing_space_info(space_info->sub_group[i]);
|
||||
kfree(space_info->sub_group[i]);
|
||||
space_info->sub_group[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not hide this behind enospc_debug, this is actually important and
|
||||
* indicates a real bug if this happens.
|
||||
*/
|
||||
if (WARN_ON(space_info->bytes_pinned > 0 || space_info->bytes_may_use > 0))
|
||||
btrfs_dump_space_info(info, space_info, 0, 0);
|
||||
|
||||
/*
|
||||
* If there was a failure to cleanup a log tree, very likely due to an
|
||||
* IO failure on a writeback attempt of one or more of its extent
|
||||
* buffers, we could not do proper (and cheap) unaccounting of their
|
||||
* reserved space, so don't warn on bytes_reserved > 0 in that case.
|
||||
*/
|
||||
if (!(space_info->flags & BTRFS_BLOCK_GROUP_METADATA) ||
|
||||
!BTRFS_FS_LOG_CLEANUP_ERROR(info)) {
|
||||
if (WARN_ON(space_info->bytes_reserved > 0))
|
||||
btrfs_dump_space_info(info, space_info, 0, 0);
|
||||
}
|
||||
|
||||
WARN_ON(space_info->reclaim_size > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called only after stopping all workers, since we could have block
|
||||
* group caching kthreads running, and therefore they could race with us if we
|
||||
@@ -4427,8 +4485,8 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
|
||||
|
||||
write_lock(&info->block_group_cache_lock);
|
||||
while (!list_empty(&info->caching_block_groups)) {
|
||||
caching_ctl = list_entry(info->caching_block_groups.next,
|
||||
struct btrfs_caching_control, list);
|
||||
caching_ctl = list_first_entry(&info->caching_block_groups,
|
||||
struct btrfs_caching_control, list);
|
||||
list_del(&caching_ctl->list);
|
||||
btrfs_put_caching_control(caching_ctl);
|
||||
}
|
||||
@@ -4499,32 +4557,10 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
|
||||
btrfs_release_global_block_rsv(info);
|
||||
|
||||
while (!list_empty(&info->space_info)) {
|
||||
space_info = list_entry(info->space_info.next,
|
||||
struct btrfs_space_info,
|
||||
list);
|
||||
space_info = list_first_entry(&info->space_info,
|
||||
struct btrfs_space_info, list);
|
||||
|
||||
/*
|
||||
* Do not hide this behind enospc_debug, this is actually
|
||||
* important and indicates a real bug if this happens.
|
||||
*/
|
||||
if (WARN_ON(space_info->bytes_pinned > 0 ||
|
||||
space_info->bytes_may_use > 0))
|
||||
btrfs_dump_space_info(info, space_info, 0, 0);
|
||||
|
||||
/*
|
||||
* If there was a failure to cleanup a log tree, very likely due
|
||||
* to an IO failure on a writeback attempt of one or more of its
|
||||
* extent buffers, we could not do proper (and cheap) unaccounting
|
||||
* of their reserved space, so don't warn on bytes_reserved > 0 in
|
||||
* that case.
|
||||
*/
|
||||
if (!(space_info->flags & BTRFS_BLOCK_GROUP_METADATA) ||
|
||||
!BTRFS_FS_LOG_CLEANUP_ERROR(info)) {
|
||||
if (WARN_ON(space_info->bytes_reserved > 0))
|
||||
btrfs_dump_space_info(info, space_info, 0, 0);
|
||||
}
|
||||
|
||||
WARN_ON(space_info->reclaim_size > 0);
|
||||
check_removing_space_info(space_info);
|
||||
list_del(&space_info->list);
|
||||
btrfs_sysfs_remove_space_info(space_info);
|
||||
}
|
||||
|
||||
@@ -326,8 +326,8 @@ void btrfs_reclaim_bgs(struct btrfs_fs_info *fs_info);
|
||||
void btrfs_mark_bg_to_reclaim(struct btrfs_block_group *bg);
|
||||
int btrfs_read_block_groups(struct btrfs_fs_info *info);
|
||||
struct btrfs_block_group *btrfs_make_block_group(struct btrfs_trans_handle *trans,
|
||||
u64 type,
|
||||
u64 chunk_offset, u64 size);
|
||||
struct btrfs_space_info *space_info,
|
||||
u64 type, u64 chunk_offset, u64 size);
|
||||
void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans);
|
||||
int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
|
||||
bool do_chunk_alloc);
|
||||
@@ -340,9 +340,10 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
|
||||
int btrfs_add_reserved_bytes(struct btrfs_block_group *cache,
|
||||
u64 ram_bytes, u64 num_bytes, int delalloc,
|
||||
bool force_wrong_size_class);
|
||||
void btrfs_free_reserved_bytes(struct btrfs_block_group *cache,
|
||||
u64 num_bytes, int delalloc);
|
||||
int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
|
||||
void btrfs_free_reserved_bytes(struct btrfs_block_group *cache, u64 num_bytes,
|
||||
bool is_delalloc);
|
||||
int btrfs_chunk_alloc(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_space_info *space_info, 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);
|
||||
|
||||
@@ -418,6 +418,9 @@ void btrfs_init_root_block_rsv(struct btrfs_root *root)
|
||||
case BTRFS_CHUNK_TREE_OBJECTID:
|
||||
root->block_rsv = &fs_info->chunk_block_rsv;
|
||||
break;
|
||||
case BTRFS_TREE_LOG_OBJECTID:
|
||||
root->block_rsv = &fs_info->treelog_rsv;
|
||||
break;
|
||||
default:
|
||||
root->block_rsv = NULL;
|
||||
break;
|
||||
@@ -438,6 +441,14 @@ void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info)
|
||||
fs_info->delayed_block_rsv.space_info = space_info;
|
||||
fs_info->delayed_refs_rsv.space_info = space_info;
|
||||
|
||||
/* The treelog_rsv uses a dedicated space_info on the zoned mode. */
|
||||
if (!btrfs_is_zoned(fs_info)) {
|
||||
fs_info->treelog_rsv.space_info = space_info;
|
||||
} else {
|
||||
ASSERT(space_info->sub_group[0]->subgroup_id == BTRFS_SUB_GROUP_TREELOG);
|
||||
fs_info->treelog_rsv.space_info = space_info->sub_group[0];
|
||||
}
|
||||
|
||||
btrfs_update_global_block_rsv(fs_info);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ enum btrfs_rsv_type {
|
||||
BTRFS_BLOCK_RSV_CHUNK,
|
||||
BTRFS_BLOCK_RSV_DELOPS,
|
||||
BTRFS_BLOCK_RSV_DELREFS,
|
||||
BTRFS_BLOCK_RSV_TREELOG,
|
||||
BTRFS_BLOCK_RSV_EMPTY,
|
||||
BTRFS_BLOCK_RSV_TEMP,
|
||||
};
|
||||
|
||||
@@ -529,8 +529,8 @@ static inline void btrfs_update_inode_mapping_flags(struct btrfs_inode *inode)
|
||||
#define CSUM_FMT "0x%*phN"
|
||||
#define CSUM_FMT_VALUE(size, bytes) size, bytes
|
||||
|
||||
int btrfs_check_sector_csum(struct btrfs_fs_info *fs_info, struct page *page,
|
||||
u32 pgoff, u8 *csum, const u8 * const csum_expected);
|
||||
int btrfs_check_sector_csum(struct btrfs_fs_info *fs_info, void *kaddr, u8 *csum,
|
||||
const u8 * const csum_expected);
|
||||
bool btrfs_data_csum_ok(struct btrfs_bio *bbio, struct btrfs_device *dev,
|
||||
u32 bio_offset, struct bio_vec *bv);
|
||||
noinline int can_nocow_extent(struct btrfs_inode *inode, u64 offset, u64 *len,
|
||||
@@ -547,8 +547,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_inode *parent_inode, struct btrfs_inode *inode,
|
||||
const struct fscrypt_str *name, int add_backref, u64 index);
|
||||
int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry);
|
||||
int btrfs_truncate_block(struct btrfs_inode *inode, loff_t from, loff_t len,
|
||||
int front);
|
||||
int btrfs_truncate_block(struct btrfs_inode *inode, u64 offset, u64 start, u64 end);
|
||||
|
||||
int btrfs_start_delalloc_snapshot(struct btrfs_root *root, bool in_reclaim_context);
|
||||
int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
|
||||
|
||||
+47
-28
@@ -285,12 +285,12 @@ static noinline void end_compressed_writeback(const struct compressed_bio *cb)
|
||||
unsigned long index = cb->start >> PAGE_SHIFT;
|
||||
unsigned long end_index = (cb->start + cb->len - 1) >> PAGE_SHIFT;
|
||||
struct folio_batch fbatch;
|
||||
const int error = blk_status_to_errno(cb->bbio.bio.bi_status);
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (error)
|
||||
mapping_set_error(inode->i_mapping, error);
|
||||
ret = blk_status_to_errno(cb->bbio.bio.bi_status);
|
||||
if (ret)
|
||||
mapping_set_error(inode->i_mapping, ret);
|
||||
|
||||
folio_batch_init(&fbatch);
|
||||
while (index <= end_index) {
|
||||
@@ -499,9 +499,9 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
||||
}
|
||||
|
||||
page_end = (pg_index << PAGE_SHIFT) + folio_size(folio) - 1;
|
||||
lock_extent(tree, cur, page_end, NULL);
|
||||
btrfs_lock_extent(tree, cur, page_end, NULL);
|
||||
read_lock(&em_tree->lock);
|
||||
em = lookup_extent_mapping(em_tree, cur, page_end + 1 - cur);
|
||||
em = btrfs_lookup_extent_mapping(em_tree, cur, page_end + 1 - cur);
|
||||
read_unlock(&em_tree->lock);
|
||||
|
||||
/*
|
||||
@@ -510,20 +510,20 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
||||
* to this compressed extent on disk.
|
||||
*/
|
||||
if (!em || cur < em->start ||
|
||||
(cur + fs_info->sectorsize > extent_map_end(em)) ||
|
||||
(extent_map_block_start(em) >> SECTOR_SHIFT) !=
|
||||
(cur + fs_info->sectorsize > btrfs_extent_map_end(em)) ||
|
||||
(btrfs_extent_map_block_start(em) >> SECTOR_SHIFT) !=
|
||||
orig_bio->bi_iter.bi_sector) {
|
||||
free_extent_map(em);
|
||||
unlock_extent(tree, cur, page_end, NULL);
|
||||
btrfs_free_extent_map(em);
|
||||
btrfs_unlock_extent(tree, cur, page_end, NULL);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
break;
|
||||
}
|
||||
add_size = min(em->start + em->len, page_end + 1) - cur;
|
||||
free_extent_map(em);
|
||||
unlock_extent(tree, cur, page_end, NULL);
|
||||
btrfs_free_extent_map(em);
|
||||
btrfs_unlock_extent(tree, cur, page_end, NULL);
|
||||
|
||||
if (folio->index == end_index) {
|
||||
if (folio_contains(folio, end_index)) {
|
||||
size_t zero_offset = offset_in_folio(folio, isize);
|
||||
|
||||
if (zero_offset) {
|
||||
@@ -576,19 +576,19 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
|
||||
struct extent_map *em;
|
||||
unsigned long pflags;
|
||||
int memstall = 0;
|
||||
blk_status_t ret;
|
||||
int ret2;
|
||||
blk_status_t status;
|
||||
int ret;
|
||||
|
||||
/* we need the actual starting offset of this extent in the file */
|
||||
read_lock(&em_tree->lock);
|
||||
em = lookup_extent_mapping(em_tree, file_offset, fs_info->sectorsize);
|
||||
em = btrfs_lookup_extent_mapping(em_tree, file_offset, fs_info->sectorsize);
|
||||
read_unlock(&em_tree->lock);
|
||||
if (!em) {
|
||||
ret = BLK_STS_IOERR;
|
||||
status = BLK_STS_IOERR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ASSERT(extent_map_is_compressed(em));
|
||||
ASSERT(btrfs_extent_map_is_compressed(em));
|
||||
compressed_len = em->disk_num_bytes;
|
||||
|
||||
cb = alloc_compressed_bio(inode, file_offset, REQ_OP_READ,
|
||||
@@ -600,21 +600,21 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
|
||||
|
||||
cb->len = bbio->bio.bi_iter.bi_size;
|
||||
cb->compressed_len = compressed_len;
|
||||
cb->compress_type = extent_map_compression(em);
|
||||
cb->compress_type = btrfs_extent_map_compression(em);
|
||||
cb->orig_bbio = bbio;
|
||||
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
cb->nr_folios = DIV_ROUND_UP(compressed_len, PAGE_SIZE);
|
||||
cb->compressed_folios = kcalloc(cb->nr_folios, sizeof(struct folio *), GFP_NOFS);
|
||||
if (!cb->compressed_folios) {
|
||||
ret = BLK_STS_RESOURCE;
|
||||
status = BLK_STS_RESOURCE;
|
||||
goto out_free_bio;
|
||||
}
|
||||
|
||||
ret2 = btrfs_alloc_folio_array(cb->nr_folios, cb->compressed_folios);
|
||||
if (ret2) {
|
||||
ret = BLK_STS_RESOURCE;
|
||||
ret = btrfs_alloc_folio_array(cb->nr_folios, cb->compressed_folios);
|
||||
if (ret) {
|
||||
status = BLK_STS_RESOURCE;
|
||||
goto out_free_compressed_pages;
|
||||
}
|
||||
|
||||
@@ -637,7 +637,7 @@ out_free_compressed_pages:
|
||||
out_free_bio:
|
||||
bio_put(&cb->bbio.bio);
|
||||
out:
|
||||
btrfs_bio_end_io(bbio, ret);
|
||||
btrfs_bio_end_io(bbio, status);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1137,6 +1137,22 @@ void __cold btrfs_exit_compress(void)
|
||||
bioset_exit(&btrfs_compressed_bioset);
|
||||
}
|
||||
|
||||
/*
|
||||
* The bvec is a single page bvec from a bio that contains folios from a filemap.
|
||||
*
|
||||
* Since the folio may be a large one, and if the bv_page is not a head page of
|
||||
* a large folio, then page->index is unreliable.
|
||||
*
|
||||
* Thus we need this helper to grab the proper file offset.
|
||||
*/
|
||||
static u64 file_offset_from_bvec(const struct bio_vec *bvec)
|
||||
{
|
||||
const struct page *page = bvec->bv_page;
|
||||
const struct folio *folio = page_folio(page);
|
||||
|
||||
return (page_pgoff(folio, page) << PAGE_SHIFT) + bvec->bv_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy decompressed data from working buffer to pages.
|
||||
*
|
||||
@@ -1182,13 +1198,14 @@ int btrfs_decompress_buf2page(const char *buf, u32 buf_len,
|
||||
u32 copy_start;
|
||||
/* Offset inside the full decompressed extent */
|
||||
u32 bvec_offset;
|
||||
void *kaddr;
|
||||
|
||||
bvec = bio_iter_iovec(orig_bio, orig_bio->bi_iter);
|
||||
/*
|
||||
* cb->start may underflow, but subtracting that value can still
|
||||
* give us correct offset inside the full decompressed extent.
|
||||
*/
|
||||
bvec_offset = page_offset(bvec.bv_page) + bvec.bv_offset - cb->start;
|
||||
bvec_offset = file_offset_from_bvec(&bvec) - cb->start;
|
||||
|
||||
/* Haven't reached the bvec range, exit */
|
||||
if (decompressed + buf_len <= bvec_offset)
|
||||
@@ -1204,10 +1221,12 @@ int btrfs_decompress_buf2page(const char *buf, u32 buf_len,
|
||||
* @buf + @buf_len.
|
||||
*/
|
||||
ASSERT(copy_start - decompressed < buf_len);
|
||||
memcpy_to_page(bvec.bv_page, bvec.bv_offset,
|
||||
buf + copy_start - decompressed, copy_len);
|
||||
cur_offset += copy_len;
|
||||
|
||||
kaddr = bvec_kmap_local(&bvec);
|
||||
memcpy(kaddr, buf + copy_start - decompressed, copy_len);
|
||||
kunmap_local(kaddr);
|
||||
|
||||
cur_offset += copy_len;
|
||||
bio_advance(orig_bio, copy_len);
|
||||
/* Finished the bio */
|
||||
if (!orig_bio->bi_iter.bi_size)
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include "bio.h"
|
||||
#include "messages.h"
|
||||
|
||||
struct address_space;
|
||||
struct page;
|
||||
@@ -73,11 +75,14 @@ struct compressed_bio {
|
||||
};
|
||||
|
||||
/* @range_end must be exclusive. */
|
||||
static inline u32 btrfs_calc_input_length(u64 range_end, u64 cur)
|
||||
static inline u32 btrfs_calc_input_length(struct folio *folio, u64 range_end, u64 cur)
|
||||
{
|
||||
u64 page_end = round_down(cur, PAGE_SIZE) + PAGE_SIZE;
|
||||
const u64 folio_end = folio_pos(folio) + folio_size(folio);
|
||||
|
||||
return min(range_end, page_end) - cur;
|
||||
/* @cur must be inside the folio. */
|
||||
ASSERT(folio_pos(folio) <= cur);
|
||||
ASSERT(cur < folio_end);
|
||||
return min(range_end, folio_end) - cur;
|
||||
}
|
||||
|
||||
int __init btrfs_init_compress(void);
|
||||
|
||||
+1
-1
@@ -61,7 +61,6 @@ struct btrfs_path {
|
||||
/* if there is real range locking, this locks field will change */
|
||||
u8 locks[BTRFS_MAX_LEVEL];
|
||||
u8 reada;
|
||||
/* keep some upper locks as we walk down */
|
||||
u8 lowest_level;
|
||||
|
||||
/*
|
||||
@@ -69,6 +68,7 @@ struct btrfs_path {
|
||||
* and to force calls to keep space in the nodes
|
||||
*/
|
||||
unsigned int search_for_split:1;
|
||||
/* Keep some upper locks as we walk down. */
|
||||
unsigned int keep_locks:1;
|
||||
unsigned int skip_locking:1;
|
||||
unsigned int search_commit_root:1;
|
||||
|
||||
+75
-66
@@ -105,15 +105,15 @@ static int btrfs_insert_inode_defrag(struct btrfs_inode *inode,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int need_auto_defrag(struct btrfs_fs_info *fs_info)
|
||||
static inline bool need_auto_defrag(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
if (!btrfs_test_opt(fs_info, AUTO_DEFRAG))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
if (btrfs_fs_closing(fs_info))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -191,10 +191,7 @@ static struct inode_defrag *btrfs_pick_defrag_inode(
|
||||
|
||||
if (parent && compare_inode_defrag(&tmp, entry) > 0) {
|
||||
parent = rb_next(parent);
|
||||
if (parent)
|
||||
entry = rb_entry(parent, struct inode_defrag, rb_node);
|
||||
else
|
||||
entry = NULL;
|
||||
entry = rb_entry_safe(parent, struct inode_defrag, rb_node);
|
||||
}
|
||||
out:
|
||||
if (entry)
|
||||
@@ -624,7 +621,7 @@ static struct extent_map *defrag_get_extent(struct btrfs_inode *inode,
|
||||
u64 ino = btrfs_ino(inode);
|
||||
int ret;
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
@@ -734,12 +731,12 @@ next:
|
||||
|
||||
not_found:
|
||||
btrfs_release_path(&path);
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
return NULL;
|
||||
|
||||
err:
|
||||
btrfs_release_path(&path);
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
@@ -756,7 +753,7 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
|
||||
* full extent lock.
|
||||
*/
|
||||
read_lock(&em_tree->lock);
|
||||
em = lookup_extent_mapping(em_tree, start, sectorsize);
|
||||
em = btrfs_lookup_extent_mapping(em_tree, start, sectorsize);
|
||||
read_unlock(&em_tree->lock);
|
||||
|
||||
/*
|
||||
@@ -769,7 +766,7 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
|
||||
* file extent items in the inode's subvolume tree).
|
||||
*/
|
||||
if (em && (em->flags & EXTENT_FLAG_MERGED)) {
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
em = NULL;
|
||||
}
|
||||
|
||||
@@ -779,10 +776,10 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
|
||||
|
||||
/* Get the big lock and read metadata off disk. */
|
||||
if (!locked)
|
||||
lock_extent(io_tree, start, end, &cached);
|
||||
btrfs_lock_extent(io_tree, start, end, &cached);
|
||||
em = defrag_get_extent(BTRFS_I(inode), start, newer_than);
|
||||
if (!locked)
|
||||
unlock_extent(io_tree, start, end, &cached);
|
||||
btrfs_unlock_extent(io_tree, start, end, &cached);
|
||||
|
||||
if (IS_ERR(em))
|
||||
return NULL;
|
||||
@@ -794,7 +791,7 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
|
||||
static u32 get_extent_max_capacity(const struct btrfs_fs_info *fs_info,
|
||||
const struct extent_map *em)
|
||||
{
|
||||
if (extent_map_is_compressed(em))
|
||||
if (btrfs_extent_map_is_compressed(em))
|
||||
return BTRFS_MAX_COMPRESSED;
|
||||
return fs_info->max_extent_size;
|
||||
}
|
||||
@@ -837,7 +834,7 @@ static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em,
|
||||
|
||||
ret = true;
|
||||
out:
|
||||
free_extent_map(next);
|
||||
btrfs_free_extent_map(next);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -857,13 +854,14 @@ static struct folio *defrag_prepare_one_folio(struct btrfs_inode *inode, pgoff_t
|
||||
{
|
||||
struct address_space *mapping = inode->vfs_inode.i_mapping;
|
||||
gfp_t mask = btrfs_alloc_write_mask(mapping);
|
||||
u64 page_start = (u64)index << PAGE_SHIFT;
|
||||
u64 page_end = page_start + PAGE_SIZE - 1;
|
||||
u64 folio_start;
|
||||
u64 folio_end;
|
||||
struct extent_state *cached_state = NULL;
|
||||
struct folio *folio;
|
||||
int ret;
|
||||
|
||||
again:
|
||||
/* TODO: Add order fgp order flags when large folios are fully enabled. */
|
||||
folio = __filemap_get_folio(mapping, index,
|
||||
FGP_LOCK | FGP_ACCESSED | FGP_CREAT, mask);
|
||||
if (IS_ERR(folio))
|
||||
@@ -871,13 +869,16 @@ again:
|
||||
|
||||
/*
|
||||
* Since we can defragment files opened read-only, we can encounter
|
||||
* transparent huge pages here (see CONFIG_READ_ONLY_THP_FOR_FS). We
|
||||
* can't do I/O using huge pages yet, so return an error for now.
|
||||
* transparent huge pages here (see CONFIG_READ_ONLY_THP_FOR_FS).
|
||||
*
|
||||
* The IO for such large folios is not fully tested, thus return
|
||||
* an error to reject such folios unless it's an experimental build.
|
||||
*
|
||||
* Filesystem transparent huge pages are typically only used for
|
||||
* executables that explicitly enable them, so this isn't very
|
||||
* restrictive.
|
||||
*/
|
||||
if (folio_test_large(folio)) {
|
||||
if (!IS_ENABLED(CONFIG_BTRFS_EXPERIMENTAL) && folio_test_large(folio)) {
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
return ERR_PTR(-ETXTBSY);
|
||||
@@ -890,14 +891,15 @@ again:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
folio_start = folio_pos(folio);
|
||||
folio_end = folio_pos(folio) + folio_size(folio) - 1;
|
||||
/* Wait for any existing ordered extent in the range */
|
||||
while (1) {
|
||||
struct btrfs_ordered_extent *ordered;
|
||||
|
||||
lock_extent(&inode->io_tree, page_start, page_end, &cached_state);
|
||||
ordered = btrfs_lookup_ordered_range(inode, page_start, PAGE_SIZE);
|
||||
unlock_extent(&inode->io_tree, page_start, page_end,
|
||||
&cached_state);
|
||||
btrfs_lock_extent(&inode->io_tree, folio_start, folio_end, &cached_state);
|
||||
ordered = btrfs_lookup_ordered_range(inode, folio_start, folio_size(folio));
|
||||
btrfs_unlock_extent(&inode->io_tree, folio_start, folio_end, &cached_state);
|
||||
if (!ordered)
|
||||
break;
|
||||
|
||||
@@ -1027,8 +1029,8 @@ static int defrag_collect_targets(struct btrfs_inode *inode,
|
||||
* very likely resulting in a larger extent after writeback is
|
||||
* triggered (except in a case of free space fragmentation).
|
||||
*/
|
||||
if (test_range_bit_exists(&inode->io_tree, cur, cur + range_len - 1,
|
||||
EXTENT_DELALLOC))
|
||||
if (btrfs_test_range_bit_exists(&inode->io_tree, cur, cur + range_len - 1,
|
||||
EXTENT_DELALLOC))
|
||||
goto next;
|
||||
|
||||
/*
|
||||
@@ -1066,8 +1068,8 @@ static int defrag_collect_targets(struct btrfs_inode *inode,
|
||||
/* Empty target list, no way to merge with last entry */
|
||||
if (list_empty(target_list))
|
||||
goto next;
|
||||
last = list_entry(target_list->prev,
|
||||
struct defrag_target_range, list);
|
||||
last = list_last_entry(target_list,
|
||||
struct defrag_target_range, list);
|
||||
/* Not mergeable with last entry */
|
||||
if (last->start + last->len != cur)
|
||||
goto next;
|
||||
@@ -1077,7 +1079,7 @@ static int defrag_collect_targets(struct btrfs_inode *inode,
|
||||
|
||||
add:
|
||||
last_is_target = true;
|
||||
range_len = min(extent_map_end(em), start + len) - cur;
|
||||
range_len = min(btrfs_extent_map_end(em), start + len) - cur;
|
||||
/*
|
||||
* This one is a good target, check if it can be merged into
|
||||
* last range of the target list.
|
||||
@@ -1085,8 +1087,8 @@ add:
|
||||
if (!list_empty(target_list)) {
|
||||
struct defrag_target_range *last;
|
||||
|
||||
last = list_entry(target_list->prev,
|
||||
struct defrag_target_range, list);
|
||||
last = list_last_entry(target_list,
|
||||
struct defrag_target_range, list);
|
||||
ASSERT(last->start + last->len <= cur);
|
||||
if (last->start + last->len == cur) {
|
||||
/* Mergeable, enlarge the last entry */
|
||||
@@ -1099,7 +1101,7 @@ add:
|
||||
/* Allocate new defrag_target_range */
|
||||
new = kmalloc(sizeof(*new), GFP_NOFS);
|
||||
if (!new) {
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
@@ -1108,8 +1110,8 @@ add:
|
||||
list_add_tail(&new->list, target_list);
|
||||
|
||||
next:
|
||||
cur = extent_map_end(em);
|
||||
free_extent_map(em);
|
||||
cur = btrfs_extent_map_end(em);
|
||||
btrfs_free_extent_map(em);
|
||||
}
|
||||
if (ret < 0) {
|
||||
struct defrag_target_range *entry;
|
||||
@@ -1162,27 +1164,31 @@ static int defrag_one_locked_target(struct btrfs_inode *inode,
|
||||
struct extent_changeset *data_reserved = NULL;
|
||||
const u64 start = target->start;
|
||||
const u64 len = target->len;
|
||||
unsigned long last_index = (start + len - 1) >> PAGE_SHIFT;
|
||||
unsigned long start_index = start >> PAGE_SHIFT;
|
||||
unsigned long first_index = folios[0]->index;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
ASSERT(last_index - first_index + 1 <= nr_pages);
|
||||
|
||||
ret = btrfs_delalloc_reserve_space(inode, &data_reserved, start, len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
clear_extent_bit(&inode->io_tree, start, start + len - 1,
|
||||
EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING |
|
||||
EXTENT_DEFRAG, cached_state);
|
||||
set_extent_bit(&inode->io_tree, start, start + len - 1,
|
||||
EXTENT_DELALLOC | EXTENT_DEFRAG, cached_state);
|
||||
btrfs_clear_extent_bit(&inode->io_tree, start, start + len - 1,
|
||||
EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING |
|
||||
EXTENT_DEFRAG, cached_state);
|
||||
btrfs_set_extent_bit(&inode->io_tree, start, start + len - 1,
|
||||
EXTENT_DELALLOC | EXTENT_DEFRAG, cached_state);
|
||||
|
||||
/* Update the page status */
|
||||
for (i = start_index - first_index; i <= last_index - first_index; i++) {
|
||||
folio_clear_checked(folios[i]);
|
||||
btrfs_folio_clamp_set_dirty(fs_info, folios[i], start, len);
|
||||
/*
|
||||
* Update the page status.
|
||||
* Due to possible large folios, we have to check all folios one by one.
|
||||
*/
|
||||
for (int i = 0; i < nr_pages && folios[i]; i++) {
|
||||
struct folio *folio = folios[i];
|
||||
|
||||
if (!folio)
|
||||
break;
|
||||
if (start >= folio_pos(folio) + folio_size(folio) ||
|
||||
start + len <= folio_pos(folio))
|
||||
continue;
|
||||
btrfs_folio_clamp_clear_checked(fs_info, folio, start, len);
|
||||
btrfs_folio_clamp_set_dirty(fs_info, folio, start, len);
|
||||
}
|
||||
btrfs_delalloc_release_extents(inode, len);
|
||||
extent_changeset_free(data_reserved);
|
||||
@@ -1200,11 +1206,10 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
|
||||
LIST_HEAD(target_list);
|
||||
struct folio **folios;
|
||||
const u32 sectorsize = inode->root->fs_info->sectorsize;
|
||||
u64 last_index = (start + len - 1) >> PAGE_SHIFT;
|
||||
u64 start_index = start >> PAGE_SHIFT;
|
||||
unsigned int nr_pages = last_index - start_index + 1;
|
||||
u64 cur = start;
|
||||
const unsigned int nr_pages = ((start + len - 1) >> PAGE_SHIFT) -
|
||||
(start >> PAGE_SHIFT) + 1;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
ASSERT(nr_pages <= CLUSTER_SIZE / PAGE_SIZE);
|
||||
ASSERT(IS_ALIGNED(start, sectorsize) && IS_ALIGNED(len, sectorsize));
|
||||
@@ -1214,21 +1219,25 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
|
||||
return -ENOMEM;
|
||||
|
||||
/* Prepare all pages */
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
folios[i] = defrag_prepare_one_folio(inode, start_index + i);
|
||||
for (int i = 0; cur < start + len && i < nr_pages; i++) {
|
||||
folios[i] = defrag_prepare_one_folio(inode, cur >> PAGE_SHIFT);
|
||||
if (IS_ERR(folios[i])) {
|
||||
ret = PTR_ERR(folios[i]);
|
||||
nr_pages = i;
|
||||
folios[i] = NULL;
|
||||
goto free_folios;
|
||||
}
|
||||
cur = folio_pos(folios[i]) + folio_size(folios[i]);
|
||||
}
|
||||
for (i = 0; i < nr_pages; i++)
|
||||
for (int i = 0; i < nr_pages; i++) {
|
||||
if (!folios[i])
|
||||
break;
|
||||
folio_wait_writeback(folios[i]);
|
||||
}
|
||||
|
||||
/* We should get at least one folio. */
|
||||
ASSERT(folios[0]);
|
||||
/* Lock the pages range */
|
||||
lock_extent(&inode->io_tree, start_index << PAGE_SHIFT,
|
||||
(last_index << PAGE_SHIFT) + PAGE_SIZE - 1,
|
||||
&cached_state);
|
||||
btrfs_lock_extent(&inode->io_tree, folio_pos(folios[0]), cur - 1, &cached_state);
|
||||
/*
|
||||
* Now we have a consistent view about the extent map, re-check
|
||||
* which range really needs to be defragged.
|
||||
@@ -1254,11 +1263,11 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
|
||||
kfree(entry);
|
||||
}
|
||||
unlock_extent:
|
||||
unlock_extent(&inode->io_tree, start_index << PAGE_SHIFT,
|
||||
(last_index << PAGE_SHIFT) + PAGE_SIZE - 1,
|
||||
&cached_state);
|
||||
btrfs_unlock_extent(&inode->io_tree, folio_pos(folios[0]), cur - 1, &cached_state);
|
||||
free_folios:
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
for (int i = 0; i < nr_pages; i++) {
|
||||
if (!folios[i])
|
||||
break;
|
||||
folio_unlock(folios[i]);
|
||||
folio_put(folios[i]);
|
||||
}
|
||||
|
||||
@@ -111,6 +111,18 @@
|
||||
* making error handling and cleanup easier.
|
||||
*/
|
||||
|
||||
static inline struct btrfs_space_info *data_sinfo_for_inode(const struct btrfs_inode *inode)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||
|
||||
if (btrfs_is_zoned(fs_info) && btrfs_is_data_reloc_root(inode->root)) {
|
||||
ASSERT(fs_info->data_sinfo->sub_group[0]->subgroup_id ==
|
||||
BTRFS_SUB_GROUP_DATA_RELOC);
|
||||
return fs_info->data_sinfo->sub_group[0];
|
||||
}
|
||||
return fs_info->data_sinfo;
|
||||
}
|
||||
|
||||
int btrfs_alloc_data_chunk_ondemand(const struct btrfs_inode *inode, u64 bytes)
|
||||
{
|
||||
struct btrfs_root *root = inode->root;
|
||||
@@ -123,7 +135,7 @@ int btrfs_alloc_data_chunk_ondemand(const struct btrfs_inode *inode, u64 bytes)
|
||||
if (btrfs_is_free_space_inode(inode))
|
||||
flush = BTRFS_RESERVE_FLUSH_FREE_SPACE_INODE;
|
||||
|
||||
return btrfs_reserve_data_bytes(fs_info, bytes, flush);
|
||||
return btrfs_reserve_data_bytes(data_sinfo_for_inode(inode), bytes, flush);
|
||||
}
|
||||
|
||||
int btrfs_check_data_free_space(struct btrfs_inode *inode,
|
||||
@@ -144,14 +156,14 @@ int btrfs_check_data_free_space(struct btrfs_inode *inode,
|
||||
else if (btrfs_is_free_space_inode(inode))
|
||||
flush = BTRFS_RESERVE_FLUSH_FREE_SPACE_INODE;
|
||||
|
||||
ret = btrfs_reserve_data_bytes(fs_info, len, flush);
|
||||
ret = btrfs_reserve_data_bytes(data_sinfo_for_inode(inode), len, flush);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Use new btrfs_qgroup_reserve_data to reserve precious data space. */
|
||||
ret = btrfs_qgroup_reserve_data(inode, reserved, start, len);
|
||||
if (ret < 0) {
|
||||
btrfs_free_reserved_data_space_noquota(fs_info, len);
|
||||
btrfs_free_reserved_data_space_noquota(inode, len);
|
||||
extent_changeset_free(*reserved);
|
||||
*reserved = NULL;
|
||||
} else {
|
||||
@@ -168,15 +180,13 @@ int btrfs_check_data_free_space(struct btrfs_inode *inode,
|
||||
* which we can't sleep and is sure it won't affect qgroup reserved space.
|
||||
* Like clear_bit_hook().
|
||||
*/
|
||||
void btrfs_free_reserved_data_space_noquota(struct btrfs_fs_info *fs_info,
|
||||
u64 len)
|
||||
void btrfs_free_reserved_data_space_noquota(struct btrfs_inode *inode, u64 len)
|
||||
{
|
||||
struct btrfs_space_info *data_sinfo;
|
||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||
|
||||
ASSERT(IS_ALIGNED(len, fs_info->sectorsize));
|
||||
|
||||
data_sinfo = fs_info->data_sinfo;
|
||||
btrfs_space_info_free_bytes_may_use(data_sinfo, len);
|
||||
btrfs_space_info_free_bytes_may_use(data_sinfo_for_inode(inode), len);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -196,7 +206,7 @@ void btrfs_free_reserved_data_space(struct btrfs_inode *inode,
|
||||
round_down(start, fs_info->sectorsize);
|
||||
start = round_down(start, fs_info->sectorsize);
|
||||
|
||||
btrfs_free_reserved_data_space_noquota(fs_info, len);
|
||||
btrfs_free_reserved_data_space_noquota(inode, len);
|
||||
btrfs_qgroup_free_data(inode, reserved, start, len, NULL);
|
||||
}
|
||||
|
||||
@@ -439,6 +449,29 @@ void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes)
|
||||
btrfs_inode_rsv_release(inode, true);
|
||||
}
|
||||
|
||||
/* Shrink a previously reserved extent to a new length. */
|
||||
void btrfs_delalloc_shrink_extents(struct btrfs_inode *inode, u64 reserved_len, u64 new_len)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||
const u32 reserved_num_extents = count_max_extents(fs_info, reserved_len);
|
||||
const u32 new_num_extents = count_max_extents(fs_info, new_len);
|
||||
const int diff_num_extents = new_num_extents - reserved_num_extents;
|
||||
|
||||
ASSERT(new_len <= reserved_len);
|
||||
if (new_num_extents == reserved_num_extents)
|
||||
return;
|
||||
|
||||
spin_lock(&inode->lock);
|
||||
btrfs_mod_outstanding_extents(inode, diff_num_extents);
|
||||
btrfs_calculate_inode_block_rsv_size(fs_info, inode);
|
||||
spin_unlock(&inode->lock);
|
||||
|
||||
if (btrfs_is_testing(fs_info))
|
||||
return;
|
||||
|
||||
btrfs_inode_rsv_release(inode, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reserve data and metadata space for delalloc
|
||||
*
|
||||
|
||||
@@ -18,8 +18,7 @@ void btrfs_free_reserved_data_space(struct btrfs_inode *inode,
|
||||
void btrfs_delalloc_release_space(struct btrfs_inode *inode,
|
||||
struct extent_changeset *reserved,
|
||||
u64 start, u64 len, bool qgroup_free);
|
||||
void btrfs_free_reserved_data_space_noquota(struct btrfs_fs_info *fs_info,
|
||||
u64 len);
|
||||
void btrfs_free_reserved_data_space_noquota(struct btrfs_inode *inode, u64 len);
|
||||
void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
|
||||
bool qgroup_free);
|
||||
int btrfs_delalloc_reserve_space(struct btrfs_inode *inode,
|
||||
@@ -27,5 +26,6 @@ int btrfs_delalloc_reserve_space(struct btrfs_inode *inode,
|
||||
int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes,
|
||||
u64 disk_num_bytes, bool noflush);
|
||||
void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes);
|
||||
void btrfs_delalloc_shrink_extents(struct btrfs_inode *inode, u64 reserved_len, u64 new_len);
|
||||
|
||||
#endif /* BTRFS_DELALLOC_SPACE_H */
|
||||
|
||||
+28
-45
@@ -119,7 +119,12 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Will return either the node or PTR_ERR(-ENOMEM) */
|
||||
/*
|
||||
* Look up an existing delayed node associated with @btrfs_inode or create a new
|
||||
* one and insert it to the delayed nodes of the root.
|
||||
*
|
||||
* Return the delayed node, or error pointer on failure.
|
||||
*/
|
||||
static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
|
||||
struct btrfs_inode *btrfs_inode)
|
||||
{
|
||||
@@ -211,17 +216,13 @@ static void btrfs_dequeue_delayed_node(struct btrfs_delayed_root *root,
|
||||
static struct btrfs_delayed_node *btrfs_first_delayed_node(
|
||||
struct btrfs_delayed_root *delayed_root)
|
||||
{
|
||||
struct list_head *p;
|
||||
struct btrfs_delayed_node *node = NULL;
|
||||
struct btrfs_delayed_node *node;
|
||||
|
||||
spin_lock(&delayed_root->lock);
|
||||
if (list_empty(&delayed_root->node_list))
|
||||
goto out;
|
||||
|
||||
p = delayed_root->node_list.next;
|
||||
node = list_entry(p, struct btrfs_delayed_node, n_list);
|
||||
refcount_inc(&node->refs);
|
||||
out:
|
||||
node = list_first_entry_or_null(&delayed_root->node_list,
|
||||
struct btrfs_delayed_node, n_list);
|
||||
if (node)
|
||||
refcount_inc(&node->refs);
|
||||
spin_unlock(&delayed_root->lock);
|
||||
|
||||
return node;
|
||||
@@ -293,18 +294,15 @@ static inline void btrfs_release_delayed_node(struct btrfs_delayed_node *node)
|
||||
static struct btrfs_delayed_node *btrfs_first_prepared_delayed_node(
|
||||
struct btrfs_delayed_root *delayed_root)
|
||||
{
|
||||
struct list_head *p;
|
||||
struct btrfs_delayed_node *node = NULL;
|
||||
struct btrfs_delayed_node *node;
|
||||
|
||||
spin_lock(&delayed_root->lock);
|
||||
if (list_empty(&delayed_root->prepare_list))
|
||||
goto out;
|
||||
|
||||
p = delayed_root->prepare_list.next;
|
||||
list_del_init(p);
|
||||
node = list_entry(p, struct btrfs_delayed_node, p_list);
|
||||
refcount_inc(&node->refs);
|
||||
out:
|
||||
node = list_first_entry_or_null(&delayed_root->prepare_list,
|
||||
struct btrfs_delayed_node, p_list);
|
||||
if (node) {
|
||||
list_del_init(&node->p_list);
|
||||
refcount_inc(&node->refs);
|
||||
}
|
||||
spin_unlock(&delayed_root->lock);
|
||||
|
||||
return node;
|
||||
@@ -454,40 +452,25 @@ static void btrfs_release_delayed_item(struct btrfs_delayed_item *item)
|
||||
static struct btrfs_delayed_item *__btrfs_first_delayed_insertion_item(
|
||||
struct btrfs_delayed_node *delayed_node)
|
||||
{
|
||||
struct rb_node *p;
|
||||
struct btrfs_delayed_item *item = NULL;
|
||||
struct rb_node *p = rb_first_cached(&delayed_node->ins_root);
|
||||
|
||||
p = rb_first_cached(&delayed_node->ins_root);
|
||||
if (p)
|
||||
item = rb_entry(p, struct btrfs_delayed_item, rb_node);
|
||||
|
||||
return item;
|
||||
return rb_entry_safe(p, struct btrfs_delayed_item, rb_node);
|
||||
}
|
||||
|
||||
static struct btrfs_delayed_item *__btrfs_first_delayed_deletion_item(
|
||||
struct btrfs_delayed_node *delayed_node)
|
||||
{
|
||||
struct rb_node *p;
|
||||
struct btrfs_delayed_item *item = NULL;
|
||||
struct rb_node *p = rb_first_cached(&delayed_node->del_root);
|
||||
|
||||
p = rb_first_cached(&delayed_node->del_root);
|
||||
if (p)
|
||||
item = rb_entry(p, struct btrfs_delayed_item, rb_node);
|
||||
|
||||
return item;
|
||||
return rb_entry_safe(p, struct btrfs_delayed_item, rb_node);
|
||||
}
|
||||
|
||||
static struct btrfs_delayed_item *__btrfs_next_delayed_item(
|
||||
struct btrfs_delayed_item *item)
|
||||
{
|
||||
struct rb_node *p;
|
||||
struct btrfs_delayed_item *next = NULL;
|
||||
struct rb_node *p = rb_next(&item->rb_node);
|
||||
|
||||
p = rb_next(&item->rb_node);
|
||||
if (p)
|
||||
next = rb_entry(p, struct btrfs_delayed_item, rb_node);
|
||||
|
||||
return next;
|
||||
return rb_entry_safe(p, struct btrfs_delayed_item, rb_node);
|
||||
}
|
||||
|
||||
static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,
|
||||
@@ -1397,17 +1380,17 @@ void btrfs_assert_delayed_root_empty(struct btrfs_fs_info *fs_info)
|
||||
WARN_ON(btrfs_first_delayed_node(fs_info->delayed_root));
|
||||
}
|
||||
|
||||
static int could_end_wait(struct btrfs_delayed_root *delayed_root, int seq)
|
||||
static bool could_end_wait(struct btrfs_delayed_root *delayed_root, int seq)
|
||||
{
|
||||
int val = atomic_read(&delayed_root->items_seq);
|
||||
|
||||
if (val < seq || val >= seq + BTRFS_DELAYED_BATCH)
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND)
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
void btrfs_balance_delayed_items(struct btrfs_fs_info *fs_info)
|
||||
|
||||
@@ -331,12 +331,9 @@ static struct btrfs_delayed_ref_node* tree_insert(struct rb_root_cached *root,
|
||||
struct btrfs_delayed_ref_node *ins)
|
||||
{
|
||||
struct rb_node *node = &ins->ref_node;
|
||||
struct rb_node *exist;
|
||||
struct rb_node *exist = rb_find_add_cached(node, root, cmp_refs_node);
|
||||
|
||||
exist = rb_find_add_cached(node, root, cmp_refs_node);
|
||||
if (exist)
|
||||
return rb_entry(exist, struct btrfs_delayed_ref_node, ref_node);
|
||||
return NULL;
|
||||
return rb_entry_safe(exist, struct btrfs_delayed_ref_node, ref_node);
|
||||
}
|
||||
|
||||
static struct btrfs_delayed_ref_head *find_first_ref_head(
|
||||
@@ -1339,7 +1336,7 @@ int __init btrfs_delayed_ref_init(void)
|
||||
{
|
||||
btrfs_delayed_ref_head_cachep = KMEM_CACHE(btrfs_delayed_ref_head, 0);
|
||||
if (!btrfs_delayed_ref_head_cachep)
|
||||
goto fail;
|
||||
return -ENOMEM;
|
||||
|
||||
btrfs_delayed_ref_node_cachep = KMEM_CACHE(btrfs_delayed_ref_node, 0);
|
||||
if (!btrfs_delayed_ref_node_cachep)
|
||||
|
||||
@@ -262,7 +262,6 @@ enum btrfs_ref_type {
|
||||
BTRFS_REF_NOT_SET,
|
||||
BTRFS_REF_DATA,
|
||||
BTRFS_REF_METADATA,
|
||||
BTRFS_REF_LAST,
|
||||
} __packed;
|
||||
|
||||
struct btrfs_ref {
|
||||
|
||||
+11
-11
@@ -637,7 +637,7 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
|
||||
break;
|
||||
case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
|
||||
case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
|
||||
ASSERT(0);
|
||||
DEBUG_WARN("unexpected STARTED ot SUSPENDED dev-replace state");
|
||||
ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED;
|
||||
up_write(&dev_replace->rwsem);
|
||||
goto leave;
|
||||
@@ -794,17 +794,17 @@ static int btrfs_set_target_alloc_state(struct btrfs_device *srcdev,
|
||||
|
||||
lockdep_assert_held(&srcdev->fs_info->chunk_mutex);
|
||||
|
||||
while (find_first_extent_bit(&srcdev->alloc_state, start,
|
||||
&found_start, &found_end,
|
||||
CHUNK_ALLOCATED, &cached_state)) {
|
||||
ret = set_extent_bit(&tgtdev->alloc_state, found_start,
|
||||
found_end, CHUNK_ALLOCATED, NULL);
|
||||
while (btrfs_find_first_extent_bit(&srcdev->alloc_state, start,
|
||||
&found_start, &found_end,
|
||||
CHUNK_ALLOCATED, &cached_state)) {
|
||||
ret = btrfs_set_extent_bit(&tgtdev->alloc_state, found_start,
|
||||
found_end, CHUNK_ALLOCATED, NULL);
|
||||
if (ret)
|
||||
break;
|
||||
start = found_end + 1;
|
||||
}
|
||||
|
||||
free_extent_state(cached_state);
|
||||
btrfs_free_extent_state(cached_state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1265,16 +1265,16 @@ static int btrfs_dev_replace_kthread(void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __pure btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace)
|
||||
bool __pure btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace)
|
||||
{
|
||||
if (!dev_replace->is_valid)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
switch (dev_replace->replace_state) {
|
||||
case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
|
||||
case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
|
||||
case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
|
||||
return 0;
|
||||
return false;
|
||||
case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
|
||||
case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
|
||||
/*
|
||||
@@ -1289,7 +1289,7 @@ int __pure btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace)
|
||||
*/
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
void btrfs_bio_counter_sub(struct btrfs_fs_info *fs_info, s64 amount)
|
||||
|
||||
@@ -25,7 +25,7 @@ void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
|
||||
int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info);
|
||||
void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info);
|
||||
int __pure btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace);
|
||||
bool __pure btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace);
|
||||
bool btrfs_finish_block_group_to_copy(struct btrfs_device *srcdev,
|
||||
struct btrfs_block_group *cache,
|
||||
u64 physical);
|
||||
|
||||
+37
-38
@@ -42,21 +42,21 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
|
||||
|
||||
/* Direct lock must be taken before the extent lock. */
|
||||
if (nowait) {
|
||||
if (!try_lock_dio_extent(io_tree, lockstart, lockend, cached_state))
|
||||
if (!btrfs_try_lock_dio_extent(io_tree, lockstart, lockend, cached_state))
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
lock_dio_extent(io_tree, lockstart, lockend, cached_state);
|
||||
btrfs_lock_dio_extent(io_tree, lockstart, lockend, cached_state);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (nowait) {
|
||||
if (!try_lock_extent(io_tree, lockstart, lockend,
|
||||
cached_state)) {
|
||||
if (!btrfs_try_lock_extent(io_tree, lockstart, lockend,
|
||||
cached_state)) {
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
lock_extent(io_tree, lockstart, lockend, cached_state);
|
||||
btrfs_lock_extent(io_tree, lockstart, lockend, cached_state);
|
||||
}
|
||||
/*
|
||||
* We're concerned with the entire range that we're going to be
|
||||
@@ -78,7 +78,7 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
|
||||
lockstart, lockend)))
|
||||
break;
|
||||
|
||||
unlock_extent(io_tree, lockstart, lockend, cached_state);
|
||||
btrfs_unlock_extent(io_tree, lockstart, lockend, cached_state);
|
||||
|
||||
if (ordered) {
|
||||
if (nowait) {
|
||||
@@ -131,7 +131,7 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
|
||||
}
|
||||
|
||||
if (ret)
|
||||
unlock_dio_extent(io_tree, lockstart, lockend, cached_state);
|
||||
btrfs_unlock_dio_extent(io_tree, lockstart, lockend, cached_state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -151,11 +151,11 @@ static struct extent_map *btrfs_create_dio_extent(struct btrfs_inode *inode,
|
||||
}
|
||||
|
||||
ordered = btrfs_alloc_ordered_extent(inode, start, file_extent,
|
||||
(1 << type) |
|
||||
(1 << BTRFS_ORDERED_DIRECT));
|
||||
(1U << type) |
|
||||
(1U << BTRFS_ORDERED_DIRECT));
|
||||
if (IS_ERR(ordered)) {
|
||||
if (em) {
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
btrfs_drop_extent_map_range(inode, start,
|
||||
start + file_extent->num_bytes - 1, false);
|
||||
}
|
||||
@@ -204,8 +204,7 @@ again:
|
||||
BTRFS_ORDERED_REGULAR);
|
||||
btrfs_dec_block_group_reservations(fs_info, ins.objectid);
|
||||
if (IS_ERR(em))
|
||||
btrfs_free_reserved_extent(fs_info, ins.objectid, ins.offset,
|
||||
1);
|
||||
btrfs_free_reserved_extent(fs_info, ins.objectid, ins.offset, true);
|
||||
|
||||
return em;
|
||||
}
|
||||
@@ -246,7 +245,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
|
||||
else
|
||||
type = BTRFS_ORDERED_NOCOW;
|
||||
len = min(len, em->len - (start - em->start));
|
||||
block_start = extent_map_block_start(em) + (start - em->start);
|
||||
block_start = btrfs_extent_map_block_start(em) + (start - em->start);
|
||||
|
||||
if (can_nocow_extent(BTRFS_I(inode), start, &len, &file_extent,
|
||||
false) == 1) {
|
||||
@@ -265,7 +264,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
|
||||
nowait);
|
||||
if (ret < 0) {
|
||||
/* Our caller expects us to free the input extent map. */
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
*map = NULL;
|
||||
btrfs_dec_nocow_writers(bg);
|
||||
if (nowait && (ret == -ENOSPC || ret == -EDQUOT))
|
||||
@@ -278,7 +277,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
|
||||
&file_extent, type);
|
||||
btrfs_dec_nocow_writers(bg);
|
||||
if (type == BTRFS_ORDERED_PREALLOC) {
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
*map = em2;
|
||||
em = em2;
|
||||
}
|
||||
@@ -291,7 +290,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
|
||||
dio_data->nocow_done = true;
|
||||
} else {
|
||||
/* Our caller expects us to free the input extent map. */
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
*map = NULL;
|
||||
|
||||
if (nowait) {
|
||||
@@ -440,8 +439,8 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
|
||||
start, data_alloc_len, false);
|
||||
if (!ret)
|
||||
dio_data->data_space_reserved = true;
|
||||
else if (ret && !(BTRFS_I(inode)->flags &
|
||||
(BTRFS_INODE_NODATACOW | BTRFS_INODE_PREALLOC)))
|
||||
else if (!(BTRFS_I(inode)->flags &
|
||||
(BTRFS_INODE_NODATACOW | BTRFS_INODE_PREALLOC)))
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -474,8 +473,8 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
|
||||
* to buffered IO. Don't blame me, this is the price we pay for using
|
||||
* the generic code.
|
||||
*/
|
||||
if (extent_map_is_compressed(em) || em->disk_bytenr == EXTENT_MAP_INLINE) {
|
||||
free_extent_map(em);
|
||||
if (btrfs_extent_map_is_compressed(em) || em->disk_bytenr == EXTENT_MAP_INLINE) {
|
||||
btrfs_free_extent_map(em);
|
||||
/*
|
||||
* If we are in a NOWAIT context, return -EAGAIN in order to
|
||||
* fallback to buffered IO. This is not only because we can
|
||||
@@ -516,7 +515,7 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
|
||||
* after we have submitted bios for all the extents in the range.
|
||||
*/
|
||||
if ((flags & IOMAP_NOWAIT) && len < length) {
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
ret = -EAGAIN;
|
||||
goto unlock_err;
|
||||
}
|
||||
@@ -558,13 +557,13 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
|
||||
iomap->addr = IOMAP_NULL_ADDR;
|
||||
iomap->type = IOMAP_HOLE;
|
||||
} else {
|
||||
iomap->addr = extent_map_block_start(em) + (start - em->start);
|
||||
iomap->addr = btrfs_extent_map_block_start(em) + (start - em->start);
|
||||
iomap->type = IOMAP_MAPPED;
|
||||
}
|
||||
iomap->offset = start;
|
||||
iomap->bdev = fs_info->fs_devices->latest_dev->bdev;
|
||||
iomap->length = len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
/*
|
||||
* Reads will hold the EXTENT_DIO_LOCKED bit until the io is completed,
|
||||
@@ -575,13 +574,13 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
|
||||
if (write)
|
||||
unlock_bits |= EXTENT_DIO_LOCKED;
|
||||
|
||||
clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
|
||||
unlock_bits, &cached_state);
|
||||
btrfs_clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
|
||||
unlock_bits, &cached_state);
|
||||
|
||||
/* We didn't use everything, unlock the dio extent for the remainder. */
|
||||
if (!write && (start + len) < lockend)
|
||||
unlock_dio_extent(&BTRFS_I(inode)->io_tree, start + len,
|
||||
lockend, NULL);
|
||||
btrfs_unlock_dio_extent(&BTRFS_I(inode)->io_tree, start + len,
|
||||
lockend, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -591,8 +590,8 @@ unlock_err:
|
||||
* to update this, be explicit that we expect EXTENT_LOCKED and
|
||||
* EXTENT_DIO_LOCKED to be set here, and so that's what we're clearing.
|
||||
*/
|
||||
clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
|
||||
EXTENT_LOCKED | EXTENT_DIO_LOCKED, &cached_state);
|
||||
btrfs_clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
|
||||
EXTENT_LOCKED | EXTENT_DIO_LOCKED, &cached_state);
|
||||
err:
|
||||
if (dio_data->data_space_reserved) {
|
||||
btrfs_free_reserved_data_space(BTRFS_I(inode),
|
||||
@@ -615,8 +614,8 @@ static int btrfs_dio_iomap_end(struct inode *inode, loff_t pos, loff_t length,
|
||||
|
||||
if (!write && (iomap->type == IOMAP_HOLE)) {
|
||||
/* If reading from a hole, unlock and return */
|
||||
unlock_dio_extent(&BTRFS_I(inode)->io_tree, pos,
|
||||
pos + length - 1, NULL);
|
||||
btrfs_unlock_dio_extent(&BTRFS_I(inode)->io_tree, pos,
|
||||
pos + length - 1, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -627,8 +626,8 @@ static int btrfs_dio_iomap_end(struct inode *inode, loff_t pos, loff_t length,
|
||||
btrfs_finish_ordered_extent(dio_data->ordered, NULL,
|
||||
pos, length, false);
|
||||
else
|
||||
unlock_dio_extent(&BTRFS_I(inode)->io_tree, pos,
|
||||
pos + length - 1, NULL);
|
||||
btrfs_unlock_dio_extent(&BTRFS_I(inode)->io_tree, pos,
|
||||
pos + length - 1, NULL);
|
||||
ret = -ENOTBLK;
|
||||
}
|
||||
if (write) {
|
||||
@@ -660,8 +659,8 @@ static void btrfs_dio_end_io(struct btrfs_bio *bbio)
|
||||
dip->file_offset, dip->bytes,
|
||||
!bio->bi_status);
|
||||
} else {
|
||||
unlock_dio_extent(&inode->io_tree, dip->file_offset,
|
||||
dip->file_offset + dip->bytes - 1, NULL);
|
||||
btrfs_unlock_dio_extent(&inode->io_tree, dip->file_offset,
|
||||
dip->file_offset + dip->bytes - 1, NULL);
|
||||
}
|
||||
|
||||
bbio->bio.bi_private = bbio->private;
|
||||
@@ -692,9 +691,9 @@ static int btrfs_extract_ordered_extent(struct btrfs_bio *bbio,
|
||||
* a pre-existing one.
|
||||
*/
|
||||
if (!test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) {
|
||||
ret = split_extent_map(bbio->inode, bbio->file_offset,
|
||||
ordered->num_bytes, len,
|
||||
ordered->disk_bytenr);
|
||||
ret = btrfs_split_extent_map(bbio->inode, bbio->file_offset,
|
||||
ordered->num_bytes, len,
|
||||
ordered->disk_bytenr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
+3
-1
@@ -256,7 +256,9 @@ again:
|
||||
* the discard lists.
|
||||
*/
|
||||
ASSERT(block_group->discard_index !=
|
||||
BTRFS_DISCARD_INDEX_UNUSED);
|
||||
BTRFS_DISCARD_INDEX_UNUSED,
|
||||
"discard_index=%d",
|
||||
block_group->discard_index);
|
||||
} else {
|
||||
list_del_init(&block_group->discard_list);
|
||||
btrfs_put_block_group(block_group);
|
||||
|
||||
+62
-137
@@ -193,10 +193,11 @@ static int btrfs_repair_eb_io_failure(const struct extent_buffer *eb,
|
||||
u64 end = min_t(u64, eb->start + eb->len,
|
||||
folio_pos(folio) + eb->folio_size);
|
||||
u32 len = end - start;
|
||||
phys_addr_t paddr = PFN_PHYS(folio_pfn(folio)) +
|
||||
offset_in_folio(folio, start);
|
||||
|
||||
ret = btrfs_repair_io_failure(fs_info, 0, start, len,
|
||||
start, folio, offset_in_folio(folio, start),
|
||||
mirror_num);
|
||||
ret = btrfs_repair_io_failure(fs_info, 0, start, len, start,
|
||||
paddr, mirror_num);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
@@ -224,7 +225,6 @@ int btrfs_read_extent_buffer(struct extent_buffer *eb,
|
||||
ASSERT(check);
|
||||
|
||||
while (1) {
|
||||
clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
|
||||
ret = read_extent_buffer_pages(eb, mirror_num, check);
|
||||
if (!ret)
|
||||
break;
|
||||
@@ -256,7 +256,7 @@ int btrfs_read_extent_buffer(struct extent_buffer *eb,
|
||||
/*
|
||||
* Checksum a dirty tree block before IO.
|
||||
*/
|
||||
blk_status_t btree_csum_one_bio(struct btrfs_bio *bbio)
|
||||
int btree_csum_one_bio(struct btrfs_bio *bbio)
|
||||
{
|
||||
struct extent_buffer *eb = bbio->private;
|
||||
struct btrfs_fs_info *fs_info = eb->fs_info;
|
||||
@@ -267,9 +267,9 @@ blk_status_t btree_csum_one_bio(struct btrfs_bio *bbio)
|
||||
|
||||
/* Btree blocks are always contiguous on disk. */
|
||||
if (WARN_ON_ONCE(bbio->file_offset != eb->start))
|
||||
return BLK_STS_IOERR;
|
||||
return -EIO;
|
||||
if (WARN_ON_ONCE(bbio->bio.bi_iter.bi_size != eb->len))
|
||||
return BLK_STS_IOERR;
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* If an extent_buffer is marked as EXTENT_BUFFER_ZONED_ZEROOUT, don't
|
||||
@@ -278,13 +278,13 @@ blk_status_t btree_csum_one_bio(struct btrfs_bio *bbio)
|
||||
*/
|
||||
if (test_bit(EXTENT_BUFFER_ZONED_ZEROOUT, &eb->bflags)) {
|
||||
memzero_extent_buffer(eb, 0, eb->len);
|
||||
return BLK_STS_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(found_start != eb->start))
|
||||
return BLK_STS_IOERR;
|
||||
return -EIO;
|
||||
if (WARN_ON(!btrfs_meta_folio_test_uptodate(eb->folios[0], eb)))
|
||||
return BLK_STS_IOERR;
|
||||
return -EIO;
|
||||
|
||||
ASSERT(memcmp_extent_buffer(eb, fs_info->fs_devices->metadata_uuid,
|
||||
offsetof(struct btrfs_header, fsid),
|
||||
@@ -312,7 +312,7 @@ blk_status_t btree_csum_one_bio(struct btrfs_bio *bbio)
|
||||
goto error;
|
||||
}
|
||||
write_extent_buffer(eb, result, 0, fs_info->csum_size);
|
||||
return BLK_STS_OK;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
btrfs_print_tree(eb, 0);
|
||||
@@ -326,7 +326,7 @@ error:
|
||||
*/
|
||||
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG) ||
|
||||
btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID);
|
||||
return errno_to_blk_status(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool check_tree_block_fsid(struct extent_buffer *eb)
|
||||
@@ -452,15 +452,9 @@ int btrfs_validate_extent_buffer(struct extent_buffer *eb,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a leaf block and it is corrupt, set the corrupt bit so
|
||||
* that we don't try and read the other copies of this block, just
|
||||
* return -EIO.
|
||||
*/
|
||||
if (found_level == 0 && btrfs_check_leaf(eb)) {
|
||||
set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
|
||||
/* If this is a leaf block and it is corrupt, just return -EIO. */
|
||||
if (found_level == 0 && btrfs_check_leaf(eb))
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
if (found_level > 0 && btrfs_check_node(eb))
|
||||
ret = -EIO;
|
||||
@@ -641,11 +635,16 @@ struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
|
||||
|
||||
}
|
||||
|
||||
static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
|
||||
u64 objectid)
|
||||
static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info,
|
||||
u64 objectid, gfp_t flags)
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
bool dummy = btrfs_is_testing(fs_info);
|
||||
|
||||
root = kzalloc(sizeof(*root), flags);
|
||||
if (!root)
|
||||
return NULL;
|
||||
|
||||
memset(&root->root_key, 0, sizeof(root->root_key));
|
||||
memset(&root->root_item, 0, sizeof(root->root_item));
|
||||
memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
|
||||
@@ -698,10 +697,10 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
|
||||
btrfs_set_root_last_log_commit(root, 0);
|
||||
root->anon_dev = 0;
|
||||
if (!dummy) {
|
||||
extent_io_tree_init(fs_info, &root->dirty_log_pages,
|
||||
IO_TREE_ROOT_DIRTY_LOG_PAGES);
|
||||
extent_io_tree_init(fs_info, &root->log_csum_range,
|
||||
IO_TREE_LOG_CSUM_RANGE);
|
||||
btrfs_extent_io_tree_init(fs_info, &root->dirty_log_pages,
|
||||
IO_TREE_ROOT_DIRTY_LOG_PAGES);
|
||||
btrfs_extent_io_tree_init(fs_info, &root->log_csum_range,
|
||||
IO_TREE_LOG_CSUM_RANGE);
|
||||
}
|
||||
|
||||
spin_lock_init(&root->root_item_lock);
|
||||
@@ -712,14 +711,7 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
|
||||
list_add_tail(&root->leak_list, &fs_info->allocated_roots);
|
||||
spin_unlock(&fs_info->fs_roots_radix_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info,
|
||||
u64 objectid, gfp_t flags)
|
||||
{
|
||||
struct btrfs_root *root = kzalloc(sizeof(*root), flags);
|
||||
if (root)
|
||||
__setup_root(root, fs_info, objectid);
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -1863,8 +1855,8 @@ void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info)
|
||||
int i;
|
||||
|
||||
while (!list_empty(&fs_info->dead_roots)) {
|
||||
gang[0] = list_entry(fs_info->dead_roots.next,
|
||||
struct btrfs_root, root_list);
|
||||
gang[0] = list_first_entry(&fs_info->dead_roots,
|
||||
struct btrfs_root, root_list);
|
||||
list_del(&gang[0]->root_list);
|
||||
|
||||
if (test_bit(BTRFS_ROOT_IN_RADIX, &gang[0]->state))
|
||||
@@ -1927,9 +1919,9 @@ static int btrfs_init_btree_inode(struct super_block *sb)
|
||||
inode->i_mapping->a_ops = &btree_aops;
|
||||
mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
|
||||
|
||||
extent_io_tree_init(fs_info, &BTRFS_I(inode)->io_tree,
|
||||
IO_TREE_BTREE_INODE_IO);
|
||||
extent_map_tree_init(&BTRFS_I(inode)->extent_tree);
|
||||
btrfs_extent_io_tree_init(fs_info, &BTRFS_I(inode)->io_tree,
|
||||
IO_TREE_BTREE_INODE_IO);
|
||||
btrfs_extent_map_tree_init(&BTRFS_I(inode)->extent_tree);
|
||||
|
||||
BTRFS_I(inode)->root = btrfs_grab_root(fs_info->tree_root);
|
||||
set_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags);
|
||||
@@ -2002,7 +1994,7 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info)
|
||||
btrfs_alloc_ordered_workqueue(fs_info, "qgroup-rescan",
|
||||
ordered_flags);
|
||||
fs_info->discard_ctl.discard_workers =
|
||||
alloc_ordered_workqueue("btrfs_discard", WQ_FREEZABLE);
|
||||
alloc_ordered_workqueue("btrfs-discard", WQ_FREEZABLE);
|
||||
|
||||
if (!(fs_info->workers &&
|
||||
fs_info->delalloc_workers && fs_info->flush_workers &&
|
||||
@@ -2769,10 +2761,21 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lockdep gets confused between our buffer_tree which requires IRQ locking because
|
||||
* we modify marks in the IRQ context, and our delayed inode xarray which doesn't
|
||||
* have these requirements. Use a class key so lockdep doesn't get them mixed up.
|
||||
*/
|
||||
static struct lock_class_key buffer_xa_class;
|
||||
|
||||
void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
|
||||
INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC);
|
||||
|
||||
/* Use the same flags as mapping->i_pages. */
|
||||
xa_init_flags(&fs_info->buffer_tree, XA_FLAGS_LOCK_IRQ | XA_FLAGS_ACCOUNT);
|
||||
lockdep_set_class(&fs_info->buffer_tree.xa_lock, &buffer_xa_class);
|
||||
|
||||
INIT_LIST_HEAD(&fs_info->trans_list);
|
||||
INIT_LIST_HEAD(&fs_info->dead_roots);
|
||||
INIT_LIST_HEAD(&fs_info->delayed_iputs);
|
||||
@@ -2784,7 +2787,6 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
|
||||
spin_lock_init(&fs_info->delayed_iput_lock);
|
||||
spin_lock_init(&fs_info->defrag_inodes_lock);
|
||||
spin_lock_init(&fs_info->super_lock);
|
||||
spin_lock_init(&fs_info->buffer_lock);
|
||||
spin_lock_init(&fs_info->unused_bgs_lock);
|
||||
spin_lock_init(&fs_info->treelog_bg_lock);
|
||||
spin_lock_init(&fs_info->zone_active_bgs_lock);
|
||||
@@ -2829,6 +2831,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
|
||||
BTRFS_BLOCK_RSV_GLOBAL);
|
||||
btrfs_init_block_rsv(&fs_info->trans_block_rsv, BTRFS_BLOCK_RSV_TRANS);
|
||||
btrfs_init_block_rsv(&fs_info->chunk_block_rsv, BTRFS_BLOCK_RSV_CHUNK);
|
||||
btrfs_init_block_rsv(&fs_info->treelog_rsv, BTRFS_BLOCK_RSV_TREELOG);
|
||||
btrfs_init_block_rsv(&fs_info->empty_block_rsv, BTRFS_BLOCK_RSV_EMPTY);
|
||||
btrfs_init_block_rsv(&fs_info->delayed_block_rsv,
|
||||
BTRFS_BLOCK_RSV_DELOPS);
|
||||
@@ -2862,8 +2865,8 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
|
||||
rwlock_init(&fs_info->block_group_cache_lock);
|
||||
fs_info->block_group_cache_tree = RB_ROOT_CACHED;
|
||||
|
||||
extent_io_tree_init(fs_info, &fs_info->excluded_extents,
|
||||
IO_TREE_FS_EXCLUDED_EXTENTS);
|
||||
btrfs_extent_io_tree_init(fs_info, &fs_info->excluded_extents,
|
||||
IO_TREE_FS_EXCLUDED_EXTENTS);
|
||||
|
||||
mutex_init(&fs_info->ordered_operations_mutex);
|
||||
mutex_init(&fs_info->tree_log_mutex);
|
||||
@@ -3315,7 +3318,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
|
||||
/*
|
||||
* Read super block and check the signature bytes only
|
||||
*/
|
||||
disk_super = btrfs_read_dev_super(fs_devices->latest_dev->bdev);
|
||||
disk_super = btrfs_read_disk_super(fs_devices->latest_dev->bdev, 0, false);
|
||||
if (IS_ERR(disk_super)) {
|
||||
ret = PTR_ERR(disk_super);
|
||||
goto fail_alloc;
|
||||
@@ -3710,85 +3713,6 @@ static void btrfs_end_super_write(struct bio *bio)
|
||||
bio_put(bio);
|
||||
}
|
||||
|
||||
struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev,
|
||||
int copy_num, bool drop_cache)
|
||||
{
|
||||
struct btrfs_super_block *super;
|
||||
struct page *page;
|
||||
u64 bytenr, bytenr_orig;
|
||||
struct address_space *mapping = bdev->bd_mapping;
|
||||
int ret;
|
||||
|
||||
bytenr_orig = btrfs_sb_offset(copy_num);
|
||||
ret = btrfs_sb_log_location_bdev(bdev, copy_num, READ, &bytenr);
|
||||
if (ret == -ENOENT)
|
||||
return ERR_PTR(-EINVAL);
|
||||
else if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (bytenr + BTRFS_SUPER_INFO_SIZE >= bdev_nr_bytes(bdev))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (drop_cache) {
|
||||
/* This should only be called with the primary sb. */
|
||||
ASSERT(copy_num == 0);
|
||||
|
||||
/*
|
||||
* Drop the page of the primary superblock, so later read will
|
||||
* always read from the device.
|
||||
*/
|
||||
invalidate_inode_pages2_range(mapping,
|
||||
bytenr >> PAGE_SHIFT,
|
||||
(bytenr + BTRFS_SUPER_INFO_SIZE) >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
page = read_cache_page_gfp(mapping, bytenr >> PAGE_SHIFT, GFP_NOFS);
|
||||
if (IS_ERR(page))
|
||||
return ERR_CAST(page);
|
||||
|
||||
super = page_address(page);
|
||||
if (btrfs_super_magic(super) != BTRFS_MAGIC) {
|
||||
btrfs_release_disk_super(super);
|
||||
return ERR_PTR(-ENODATA);
|
||||
}
|
||||
|
||||
if (btrfs_super_bytenr(super) != bytenr_orig) {
|
||||
btrfs_release_disk_super(super);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return super;
|
||||
}
|
||||
|
||||
|
||||
struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev)
|
||||
{
|
||||
struct btrfs_super_block *super, *latest = NULL;
|
||||
int i;
|
||||
u64 transid = 0;
|
||||
|
||||
/* we would like to check all the supers, but that would make
|
||||
* a btrfs mount succeed after a mkfs from a different FS.
|
||||
* So, we need to add a special mount option to scan for
|
||||
* later supers, using BTRFS_SUPER_MIRROR_MAX instead
|
||||
*/
|
||||
for (i = 0; i < 1; i++) {
|
||||
super = btrfs_read_dev_one_super(bdev, i, false);
|
||||
if (IS_ERR(super))
|
||||
continue;
|
||||
|
||||
if (!latest || btrfs_super_generation(super) > transid) {
|
||||
if (latest)
|
||||
btrfs_release_disk_super(super);
|
||||
|
||||
latest = super;
|
||||
transid = btrfs_super_generation(super);
|
||||
}
|
||||
}
|
||||
|
||||
return super;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write superblock @sb to the @device. Do not wait for completion, all the
|
||||
* folios we use for writing are locked.
|
||||
@@ -3828,8 +3752,8 @@ static int write_dev_supers(struct btrfs_device *device,
|
||||
continue;
|
||||
} else if (ret < 0) {
|
||||
btrfs_err(device->fs_info,
|
||||
"couldn't get super block location for mirror %d",
|
||||
i);
|
||||
"couldn't get super block location for mirror %d error %d",
|
||||
i, ret);
|
||||
atomic_inc(&device->sb_write_errors);
|
||||
continue;
|
||||
}
|
||||
@@ -3848,8 +3772,8 @@ static int write_dev_supers(struct btrfs_device *device,
|
||||
GFP_NOFS);
|
||||
if (IS_ERR(folio)) {
|
||||
btrfs_err(device->fs_info,
|
||||
"couldn't get super block page for bytenr %llu",
|
||||
bytenr);
|
||||
"couldn't get super block page for bytenr %llu error %ld",
|
||||
bytenr, PTR_ERR(folio));
|
||||
atomic_inc(&device->sb_write_errors);
|
||||
continue;
|
||||
}
|
||||
@@ -4244,8 +4168,9 @@ static void warn_about_uncommitted_trans(struct btrfs_fs_info *fs_info)
|
||||
u64 found_end;
|
||||
|
||||
found = true;
|
||||
while (find_first_extent_bit(&trans->dirty_pages, cur,
|
||||
&found_start, &found_end, EXTENT_DIRTY, &cached)) {
|
||||
while (btrfs_find_first_extent_bit(&trans->dirty_pages, cur,
|
||||
&found_start, &found_end,
|
||||
EXTENT_DIRTY, &cached)) {
|
||||
dirty_bytes += found_end + 1 - found_start;
|
||||
cur = found_end + 1;
|
||||
}
|
||||
@@ -4441,7 +4366,7 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
|
||||
set_bit(BTRFS_FS_CLOSING_DONE, &fs_info->flags);
|
||||
|
||||
if (btrfs_check_quota_leak(fs_info)) {
|
||||
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
|
||||
DEBUG_WARN("qgroup reserved space leaked");
|
||||
btrfs_err(fs_info, "qgroup reserved space leaked");
|
||||
}
|
||||
|
||||
@@ -4698,9 +4623,9 @@ static void btrfs_destroy_marked_extents(struct btrfs_fs_info *fs_info,
|
||||
u64 start = 0;
|
||||
u64 end;
|
||||
|
||||
while (find_first_extent_bit(dirty_pages, start, &start, &end,
|
||||
mark, NULL)) {
|
||||
clear_extent_bits(dirty_pages, start, end, mark);
|
||||
while (btrfs_find_first_extent_bit(dirty_pages, start, &start, &end,
|
||||
mark, NULL)) {
|
||||
btrfs_clear_extent_bits(dirty_pages, start, end, mark);
|
||||
while (start <= end) {
|
||||
eb = find_extent_buffer(fs_info, start);
|
||||
start += fs_info->nodesize;
|
||||
@@ -4733,14 +4658,14 @@ static void btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info,
|
||||
* the same extent range.
|
||||
*/
|
||||
mutex_lock(&fs_info->unused_bg_unpin_mutex);
|
||||
if (!find_first_extent_bit(unpin, 0, &start, &end,
|
||||
EXTENT_DIRTY, &cached_state)) {
|
||||
if (!btrfs_find_first_extent_bit(unpin, 0, &start, &end,
|
||||
EXTENT_DIRTY, &cached_state)) {
|
||||
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
clear_extent_dirty(unpin, start, end, &cached_state);
|
||||
free_extent_state(cached_state);
|
||||
btrfs_clear_extent_dirty(unpin, start, end, &cached_state);
|
||||
btrfs_free_extent_state(cached_state);
|
||||
btrfs_error_unpin_extent_range(fs_info, start, end);
|
||||
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
|
||||
cond_resched();
|
||||
|
||||
+1
-4
@@ -58,9 +58,6 @@ int btrfs_validate_super(const struct btrfs_fs_info *fs_info,
|
||||
const struct btrfs_super_block *sb, int mirror_num);
|
||||
int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount);
|
||||
int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors);
|
||||
struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev);
|
||||
struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev,
|
||||
int copy_num, bool drop_cache);
|
||||
int btrfs_commit_super(struct btrfs_fs_info *fs_info);
|
||||
struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
|
||||
const struct btrfs_key *key);
|
||||
@@ -114,7 +111,7 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
|
||||
int btrfs_read_extent_buffer(struct extent_buffer *buf,
|
||||
const struct btrfs_tree_parent_check *check);
|
||||
|
||||
blk_status_t btree_csum_one_bio(struct btrfs_bio *bbio);
|
||||
int btree_csum_one_bio(struct btrfs_bio *bbio);
|
||||
int btrfs_alloc_log_tree_node(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
|
||||
|
||||
+290
-220
File diff suppressed because it is too large
Load Diff
+95
-92
@@ -17,7 +17,6 @@ struct btrfs_inode;
|
||||
/* Bits for the extent state */
|
||||
enum {
|
||||
ENUM_BIT(EXTENT_DIRTY),
|
||||
ENUM_BIT(EXTENT_UPTODATE),
|
||||
ENUM_BIT(EXTENT_LOCKED),
|
||||
ENUM_BIT(EXTENT_DIO_LOCKED),
|
||||
ENUM_BIT(EXTENT_NEW),
|
||||
@@ -38,6 +37,11 @@ enum {
|
||||
* that is left for the ordered extent completion.
|
||||
*/
|
||||
ENUM_BIT(EXTENT_DELALLOC_NEW),
|
||||
/*
|
||||
* Mark that a range is being locked for finishing an ordered extent.
|
||||
* Used together with EXTENT_LOCKED.
|
||||
*/
|
||||
ENUM_BIT(EXTENT_FINISHING_ORDERED),
|
||||
/*
|
||||
* When an ordered extent successfully completes for a region marked as
|
||||
* a new delalloc range, use this flag when clearing a new delalloc
|
||||
@@ -130,117 +134,116 @@ struct extent_state {
|
||||
#endif
|
||||
};
|
||||
|
||||
struct btrfs_inode *extent_io_tree_to_inode(struct extent_io_tree *tree);
|
||||
const struct btrfs_inode *extent_io_tree_to_inode_const(const struct extent_io_tree *tree);
|
||||
const struct btrfs_fs_info *extent_io_tree_to_fs_info(const struct extent_io_tree *tree);
|
||||
const struct btrfs_inode *btrfs_extent_io_tree_to_inode(const struct extent_io_tree *tree);
|
||||
const struct btrfs_fs_info *btrfs_extent_io_tree_to_fs_info(const struct extent_io_tree *tree);
|
||||
|
||||
void extent_io_tree_init(struct btrfs_fs_info *fs_info,
|
||||
struct extent_io_tree *tree, unsigned int owner);
|
||||
void extent_io_tree_release(struct extent_io_tree *tree);
|
||||
int __lock_extent(struct extent_io_tree *tree, u64 start, u64 end, u32 bits,
|
||||
struct extent_state **cached);
|
||||
bool __try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end, u32 bits,
|
||||
struct extent_state **cached);
|
||||
void btrfs_extent_io_tree_init(struct btrfs_fs_info *fs_info,
|
||||
struct extent_io_tree *tree, unsigned int owner);
|
||||
void btrfs_extent_io_tree_release(struct extent_io_tree *tree);
|
||||
int btrfs_lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, u32 bits,
|
||||
struct extent_state **cached);
|
||||
bool btrfs_try_lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
u32 bits, struct extent_state **cached);
|
||||
|
||||
static inline int lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
struct extent_state **cached)
|
||||
static inline int btrfs_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
struct extent_state **cached)
|
||||
{
|
||||
return __lock_extent(tree, start, end, EXTENT_LOCKED, cached);
|
||||
return btrfs_lock_extent_bits(tree, start, end, EXTENT_LOCKED, cached);
|
||||
}
|
||||
|
||||
static inline bool try_lock_extent(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, struct extent_state **cached)
|
||||
static inline bool btrfs_try_lock_extent(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, struct extent_state **cached)
|
||||
{
|
||||
return __try_lock_extent(tree, start, end, EXTENT_LOCKED, cached);
|
||||
return btrfs_try_lock_extent_bits(tree, start, end, EXTENT_LOCKED, cached);
|
||||
}
|
||||
|
||||
int __init extent_state_init_cachep(void);
|
||||
void __cold extent_state_free_cachep(void);
|
||||
int __init btrfs_extent_state_init_cachep(void);
|
||||
void __cold btrfs_extent_state_free_cachep(void);
|
||||
|
||||
u64 count_range_bits(struct extent_io_tree *tree,
|
||||
u64 *start, u64 search_end,
|
||||
u64 max_bytes, u32 bits, int contig,
|
||||
struct extent_state **cached_state);
|
||||
|
||||
void free_extent_state(struct extent_state *state);
|
||||
bool test_range_bit(struct extent_io_tree *tree, u64 start, u64 end, u32 bit,
|
||||
struct extent_state *cached_state);
|
||||
bool test_range_bit_exists(struct extent_io_tree *tree, u64 start, u64 end, u32 bit);
|
||||
int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
u32 bits, struct extent_changeset *changeset);
|
||||
int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
u32 bits, struct extent_state **cached,
|
||||
struct extent_changeset *changeset);
|
||||
|
||||
static inline int clear_extent_bit(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, u32 bits,
|
||||
struct extent_state **cached)
|
||||
{
|
||||
return __clear_extent_bit(tree, start, end, bits, cached, NULL);
|
||||
}
|
||||
|
||||
static inline int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
struct extent_state **cached)
|
||||
{
|
||||
return __clear_extent_bit(tree, start, end, EXTENT_LOCKED, cached, NULL);
|
||||
}
|
||||
|
||||
static inline int clear_extent_bits(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, u32 bits)
|
||||
{
|
||||
return clear_extent_bit(tree, start, end, bits, NULL);
|
||||
}
|
||||
|
||||
int set_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
u32 bits, struct extent_changeset *changeset);
|
||||
int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
u32 bits, struct extent_state **cached_state);
|
||||
|
||||
static inline int clear_extent_uptodate(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, struct extent_state **cached_state)
|
||||
{
|
||||
return __clear_extent_bit(tree, start, end, EXTENT_UPTODATE,
|
||||
cached_state, NULL);
|
||||
}
|
||||
|
||||
static inline int clear_extent_dirty(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, struct extent_state **cached)
|
||||
{
|
||||
return clear_extent_bit(tree, start, end,
|
||||
EXTENT_DIRTY | EXTENT_DELALLOC |
|
||||
EXTENT_DO_ACCOUNTING, cached);
|
||||
}
|
||||
|
||||
int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
u32 bits, u32 clear_bits,
|
||||
struct extent_state **cached_state);
|
||||
|
||||
bool find_first_extent_bit(struct extent_io_tree *tree, u64 start,
|
||||
u64 *start_ret, u64 *end_ret, u32 bits,
|
||||
u64 btrfs_count_range_bits(struct extent_io_tree *tree,
|
||||
u64 *start, u64 search_end,
|
||||
u64 max_bytes, u32 bits, int contig,
|
||||
struct extent_state **cached_state);
|
||||
void find_first_clear_extent_bit(struct extent_io_tree *tree, u64 start,
|
||||
u64 *start_ret, u64 *end_ret, u32 bits);
|
||||
int find_contiguous_extent_bit(struct extent_io_tree *tree, u64 start,
|
||||
u64 *start_ret, u64 *end_ret, u32 bits);
|
||||
|
||||
void btrfs_free_extent_state(struct extent_state *state);
|
||||
bool btrfs_test_range_bit(struct extent_io_tree *tree, u64 start, u64 end, u32 bit,
|
||||
struct extent_state *cached_state);
|
||||
bool btrfs_test_range_bit_exists(struct extent_io_tree *tree, u64 start, u64 end, u32 bit);
|
||||
void btrfs_get_range_bits(struct extent_io_tree *tree, u64 start, u64 end, u32 *bits,
|
||||
struct extent_state **cached_state);
|
||||
int btrfs_clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
u32 bits, struct extent_changeset *changeset);
|
||||
int btrfs_clear_extent_bit_changeset(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
u32 bits, struct extent_state **cached,
|
||||
struct extent_changeset *changeset);
|
||||
|
||||
static inline int btrfs_clear_extent_bit(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, u32 bits,
|
||||
struct extent_state **cached)
|
||||
{
|
||||
return btrfs_clear_extent_bit_changeset(tree, start, end, bits, cached, NULL);
|
||||
}
|
||||
|
||||
static inline int btrfs_unlock_extent(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
struct extent_state **cached)
|
||||
{
|
||||
return btrfs_clear_extent_bit_changeset(tree, start, end, EXTENT_LOCKED,
|
||||
cached, NULL);
|
||||
}
|
||||
|
||||
static inline int btrfs_clear_extent_bits(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, u32 bits)
|
||||
{
|
||||
return btrfs_clear_extent_bit(tree, start, end, bits, NULL);
|
||||
}
|
||||
|
||||
int btrfs_set_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
u32 bits, struct extent_changeset *changeset);
|
||||
int btrfs_set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
u32 bits, struct extent_state **cached_state);
|
||||
|
||||
static inline int btrfs_clear_extent_dirty(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, struct extent_state **cached)
|
||||
{
|
||||
return btrfs_clear_extent_bit(tree, start, end,
|
||||
EXTENT_DIRTY | EXTENT_DELALLOC |
|
||||
EXTENT_DO_ACCOUNTING, cached);
|
||||
}
|
||||
|
||||
int btrfs_convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
u32 bits, u32 clear_bits,
|
||||
struct extent_state **cached_state);
|
||||
|
||||
bool btrfs_find_first_extent_bit(struct extent_io_tree *tree, u64 start,
|
||||
u64 *start_ret, u64 *end_ret, u32 bits,
|
||||
struct extent_state **cached_state);
|
||||
void btrfs_find_first_clear_extent_bit(struct extent_io_tree *tree, u64 start,
|
||||
u64 *start_ret, u64 *end_ret, u32 bits);
|
||||
bool btrfs_find_contiguous_extent_bit(struct extent_io_tree *tree, u64 start,
|
||||
u64 *start_ret, u64 *end_ret, u32 bits);
|
||||
bool btrfs_find_delalloc_range(struct extent_io_tree *tree, u64 *start,
|
||||
u64 *end, u64 max_bytes,
|
||||
struct extent_state **cached_state);
|
||||
static inline int lock_dio_extent(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, struct extent_state **cached)
|
||||
static inline int btrfs_lock_dio_extent(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, struct extent_state **cached)
|
||||
{
|
||||
return __lock_extent(tree, start, end, EXTENT_DIO_LOCKED, cached);
|
||||
return btrfs_lock_extent_bits(tree, start, end, EXTENT_DIO_LOCKED, cached);
|
||||
}
|
||||
|
||||
static inline bool try_lock_dio_extent(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, struct extent_state **cached)
|
||||
static inline bool btrfs_try_lock_dio_extent(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, struct extent_state **cached)
|
||||
{
|
||||
return __try_lock_extent(tree, start, end, EXTENT_DIO_LOCKED, cached);
|
||||
return btrfs_try_lock_extent_bits(tree, start, end, EXTENT_DIO_LOCKED, cached);
|
||||
}
|
||||
|
||||
static inline int unlock_dio_extent(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, struct extent_state **cached)
|
||||
static inline int btrfs_unlock_dio_extent(struct extent_io_tree *tree, u64 start,
|
||||
u64 end, struct extent_state **cached)
|
||||
{
|
||||
return __clear_extent_bit(tree, start, end, EXTENT_DIO_LOCKED, cached, NULL);
|
||||
return btrfs_clear_extent_bit_changeset(tree, start, end, EXTENT_DIO_LOCKED,
|
||||
cached, NULL);
|
||||
}
|
||||
|
||||
struct extent_state *btrfs_next_extent_state(struct extent_io_tree *tree,
|
||||
struct extent_state *state);
|
||||
|
||||
#endif /* BTRFS_EXTENT_IO_TREE_H */
|
||||
|
||||
+100
-62
@@ -409,15 +409,15 @@ static u64 hash_extent_data_ref_item(struct extent_buffer *leaf,
|
||||
btrfs_extent_data_ref_offset(leaf, ref));
|
||||
}
|
||||
|
||||
static int match_extent_data_ref(struct extent_buffer *leaf,
|
||||
struct btrfs_extent_data_ref *ref,
|
||||
u64 root_objectid, u64 owner, u64 offset)
|
||||
static bool match_extent_data_ref(struct extent_buffer *leaf,
|
||||
struct btrfs_extent_data_ref *ref,
|
||||
u64 root_objectid, u64 owner, u64 offset)
|
||||
{
|
||||
if (btrfs_extent_data_ref_root(leaf, ref) != root_objectid ||
|
||||
btrfs_extent_data_ref_objectid(leaf, ref) != owner ||
|
||||
btrfs_extent_data_ref_offset(leaf, ref) != offset)
|
||||
return 0;
|
||||
return 1;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static noinline int lookup_extent_data_ref(struct btrfs_trans_handle *trans,
|
||||
@@ -2006,7 +2006,12 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
|
||||
|
||||
delayed_refs = &trans->transaction->delayed_refs;
|
||||
if (min_bytes == 0) {
|
||||
max_count = delayed_refs->num_heads_ready;
|
||||
/*
|
||||
* We may be subject to a harmless race if some task is
|
||||
* concurrently adding or removing a delayed ref, so silence
|
||||
* KCSAN and similar tools.
|
||||
*/
|
||||
max_count = data_race(delayed_refs->num_heads_ready);
|
||||
min_bytes = U64_MAX;
|
||||
}
|
||||
|
||||
@@ -2598,8 +2603,8 @@ static int pin_down_extent(struct btrfs_trans_handle *trans,
|
||||
spin_unlock(&cache->lock);
|
||||
spin_unlock(&cache->space_info->lock);
|
||||
|
||||
set_extent_bit(&trans->transaction->pinned_extents, bytenr,
|
||||
bytenr + num_bytes - 1, EXTENT_DIRTY, NULL);
|
||||
btrfs_set_extent_bit(&trans->transaction->pinned_extents, bytenr,
|
||||
bytenr + num_bytes - 1, EXTENT_DIRTY, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2818,34 +2823,63 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
struct btrfs_block_group *block_group, *tmp;
|
||||
struct list_head *deleted_bgs;
|
||||
struct extent_io_tree *unpin;
|
||||
struct extent_io_tree *unpin = &trans->transaction->pinned_extents;
|
||||
struct extent_state *cached_state = NULL;
|
||||
u64 start;
|
||||
u64 end;
|
||||
int unpin_error = 0;
|
||||
int ret;
|
||||
|
||||
unpin = &trans->transaction->pinned_extents;
|
||||
mutex_lock(&fs_info->unused_bg_unpin_mutex);
|
||||
btrfs_find_first_extent_bit(unpin, 0, &start, &end, EXTENT_DIRTY, &cached_state);
|
||||
|
||||
while (!TRANS_ABORTED(trans)) {
|
||||
struct extent_state *cached_state = NULL;
|
||||
|
||||
mutex_lock(&fs_info->unused_bg_unpin_mutex);
|
||||
if (!find_first_extent_bit(unpin, 0, &start, &end,
|
||||
EXTENT_DIRTY, &cached_state)) {
|
||||
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
|
||||
break;
|
||||
}
|
||||
while (!TRANS_ABORTED(trans) && cached_state) {
|
||||
struct extent_state *next_state;
|
||||
|
||||
if (btrfs_test_opt(fs_info, DISCARD_SYNC))
|
||||
ret = btrfs_discard_extent(fs_info, start,
|
||||
end + 1 - start, NULL);
|
||||
|
||||
clear_extent_dirty(unpin, start, end, &cached_state);
|
||||
next_state = btrfs_next_extent_state(unpin, cached_state);
|
||||
btrfs_clear_extent_dirty(unpin, start, end, &cached_state);
|
||||
ret = unpin_extent_range(fs_info, start, end, true);
|
||||
BUG_ON(ret);
|
||||
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
|
||||
free_extent_state(cached_state);
|
||||
cond_resched();
|
||||
/*
|
||||
* If we get an error unpinning an extent range, store the first
|
||||
* error to return later after trying to unpin all ranges and do
|
||||
* the sync discards. Our caller will abort the transaction
|
||||
* (which already wrote new superblocks) and on the next mount
|
||||
* the space will be available as it was pinned by in-memory
|
||||
* only structures in this phase.
|
||||
*/
|
||||
if (ret) {
|
||||
btrfs_err_rl(fs_info,
|
||||
"failed to unpin extent range [%llu, %llu] when committing transaction %llu: %s (%d)",
|
||||
start, end, trans->transid,
|
||||
btrfs_decode_error(ret), ret);
|
||||
if (!unpin_error)
|
||||
unpin_error = ret;
|
||||
}
|
||||
|
||||
btrfs_free_extent_state(cached_state);
|
||||
|
||||
if (need_resched()) {
|
||||
btrfs_free_extent_state(next_state);
|
||||
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
|
||||
cond_resched();
|
||||
cached_state = NULL;
|
||||
mutex_lock(&fs_info->unused_bg_unpin_mutex);
|
||||
btrfs_find_first_extent_bit(unpin, 0, &start, &end,
|
||||
EXTENT_DIRTY, &cached_state);
|
||||
} else {
|
||||
cached_state = next_state;
|
||||
if (cached_state) {
|
||||
start = cached_state->start;
|
||||
end = cached_state->end;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
|
||||
btrfs_free_extent_state(cached_state);
|
||||
|
||||
if (btrfs_test_opt(fs_info, DISCARD_ASYNC)) {
|
||||
btrfs_discard_calc_delay(&fs_info->discard_ctl);
|
||||
@@ -2859,14 +2893,10 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
|
||||
*/
|
||||
deleted_bgs = &trans->transaction->deleted_bgs;
|
||||
list_for_each_entry_safe(block_group, tmp, deleted_bgs, bg_list) {
|
||||
u64 trimmed = 0;
|
||||
|
||||
ret = -EROFS;
|
||||
if (!TRANS_ABORTED(trans))
|
||||
ret = btrfs_discard_extent(fs_info,
|
||||
block_group->start,
|
||||
block_group->length,
|
||||
&trimmed);
|
||||
ret = btrfs_discard_extent(fs_info, block_group->start,
|
||||
block_group->length, NULL);
|
||||
|
||||
/*
|
||||
* Not strictly necessary to lock, as the block_group should be
|
||||
@@ -2888,7 +2918,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return unpin_error;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3483,17 +3513,11 @@ int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
||||
WARN_ON(test_bit(EXTENT_BUFFER_DIRTY, &buf->bflags));
|
||||
|
||||
btrfs_add_free_space(bg, buf->start, buf->len);
|
||||
btrfs_free_reserved_bytes(bg, buf->len, 0);
|
||||
btrfs_free_reserved_bytes(bg, buf->len, false);
|
||||
btrfs_put_block_group(bg);
|
||||
trace_btrfs_reserved_extent_free(fs_info, buf->start, buf->len);
|
||||
|
||||
out:
|
||||
|
||||
/*
|
||||
* Deleting the buffer, clear the corrupt flag since it doesn't
|
||||
* matter anymore.
|
||||
*/
|
||||
clear_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4111,6 +4135,7 @@ static int can_allocate_chunk(struct btrfs_fs_info *fs_info,
|
||||
static int find_free_extent_update_loop(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_key *ins,
|
||||
struct find_free_extent_ctl *ffe_ctl,
|
||||
struct btrfs_space_info *space_info,
|
||||
bool full_search)
|
||||
{
|
||||
struct btrfs_root *root = fs_info->chunk_root;
|
||||
@@ -4165,7 +4190,7 @@ static int find_free_extent_update_loop(struct btrfs_fs_info *fs_info,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = btrfs_chunk_alloc(trans, ffe_ctl->flags,
|
||||
ret = btrfs_chunk_alloc(trans, space_info, ffe_ctl->flags,
|
||||
CHUNK_ALLOC_FORCE_FOR_EXTENT);
|
||||
|
||||
/* Do not bail out on ENOSPC since we can do more. */
|
||||
@@ -4382,11 +4407,22 @@ static noinline int find_free_extent(struct btrfs_root *root,
|
||||
ins->objectid = 0;
|
||||
ins->offset = 0;
|
||||
|
||||
trace_find_free_extent(root, ffe_ctl);
|
||||
trace_btrfs_find_free_extent(root, ffe_ctl);
|
||||
|
||||
space_info = btrfs_find_space_info(fs_info, ffe_ctl->flags);
|
||||
if (btrfs_is_zoned(fs_info) && space_info) {
|
||||
/* Use dedicated sub-space_info for dedicated block group users. */
|
||||
if (ffe_ctl->for_data_reloc) {
|
||||
space_info = space_info->sub_group[0];
|
||||
ASSERT(space_info->subgroup_id == BTRFS_SUB_GROUP_DATA_RELOC);
|
||||
} else if (ffe_ctl->for_treelog) {
|
||||
space_info = space_info->sub_group[0];
|
||||
ASSERT(space_info->subgroup_id == BTRFS_SUB_GROUP_TREELOG);
|
||||
}
|
||||
}
|
||||
if (!space_info) {
|
||||
btrfs_err(fs_info, "No space info for %llu", ffe_ctl->flags);
|
||||
btrfs_err(fs_info, "no space info for %llu, tree-log %d, relocation %d",
|
||||
ffe_ctl->flags, ffe_ctl->for_treelog, ffe_ctl->for_data_reloc);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
@@ -4408,6 +4444,7 @@ static noinline int find_free_extent(struct btrfs_root *root,
|
||||
* picked out then we don't care that the block group is cached.
|
||||
*/
|
||||
if (block_group && block_group_bits(block_group, ffe_ctl->flags) &&
|
||||
block_group->space_info == space_info &&
|
||||
block_group->cached != BTRFS_CACHE_NO) {
|
||||
down_read(&space_info->groups_sem);
|
||||
if (list_empty(&block_group->list) ||
|
||||
@@ -4433,7 +4470,7 @@ static noinline int find_free_extent(struct btrfs_root *root,
|
||||
}
|
||||
}
|
||||
search:
|
||||
trace_find_free_extent_search_loop(root, ffe_ctl);
|
||||
trace_btrfs_find_free_extent_search_loop(root, ffe_ctl);
|
||||
ffe_ctl->have_caching_bg = false;
|
||||
if (ffe_ctl->index == btrfs_bg_flags_to_raid_index(ffe_ctl->flags) ||
|
||||
ffe_ctl->index == 0)
|
||||
@@ -4485,7 +4522,7 @@ search:
|
||||
}
|
||||
|
||||
have_block_group:
|
||||
trace_find_free_extent_have_block_group(root, ffe_ctl, block_group);
|
||||
trace_btrfs_find_free_extent_have_block_group(root, ffe_ctl, block_group);
|
||||
ffe_ctl->cached = btrfs_block_group_done(block_group);
|
||||
if (unlikely(!ffe_ctl->cached)) {
|
||||
ffe_ctl->have_caching_bg = true;
|
||||
@@ -4578,7 +4615,8 @@ loop:
|
||||
}
|
||||
up_read(&space_info->groups_sem);
|
||||
|
||||
ret = find_free_extent_update_loop(fs_info, ins, ffe_ctl, full_search);
|
||||
ret = find_free_extent_update_loop(fs_info, ins, ffe_ctl, space_info,
|
||||
full_search);
|
||||
if (ret > 0)
|
||||
goto search;
|
||||
|
||||
@@ -4700,8 +4738,8 @@ again:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_free_reserved_extent(struct btrfs_fs_info *fs_info,
|
||||
u64 start, u64 len, int delalloc)
|
||||
int btrfs_free_reserved_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len,
|
||||
bool is_delalloc)
|
||||
{
|
||||
struct btrfs_block_group *cache;
|
||||
|
||||
@@ -4713,7 +4751,7 @@ int btrfs_free_reserved_extent(struct btrfs_fs_info *fs_info,
|
||||
}
|
||||
|
||||
btrfs_add_free_space(cache, start, len);
|
||||
btrfs_free_reserved_bytes(cache, len, delalloc);
|
||||
btrfs_free_reserved_bytes(cache, len, is_delalloc);
|
||||
trace_btrfs_reserved_extent_free(fs_info, start, len);
|
||||
|
||||
btrfs_put_block_group(cache);
|
||||
@@ -5071,17 +5109,17 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
* EXTENT bit to differentiate dirty pages.
|
||||
*/
|
||||
if (buf->log_index == 0)
|
||||
set_extent_bit(&root->dirty_log_pages, buf->start,
|
||||
buf->start + buf->len - 1,
|
||||
EXTENT_DIRTY, NULL);
|
||||
btrfs_set_extent_bit(&root->dirty_log_pages, buf->start,
|
||||
buf->start + buf->len - 1,
|
||||
EXTENT_DIRTY, NULL);
|
||||
else
|
||||
set_extent_bit(&root->dirty_log_pages, buf->start,
|
||||
buf->start + buf->len - 1,
|
||||
EXTENT_NEW, NULL);
|
||||
btrfs_set_extent_bit(&root->dirty_log_pages, buf->start,
|
||||
buf->start + buf->len - 1,
|
||||
EXTENT_NEW, NULL);
|
||||
} else {
|
||||
buf->log_index = -1;
|
||||
set_extent_bit(&trans->transaction->dirty_pages, buf->start,
|
||||
buf->start + buf->len - 1, EXTENT_DIRTY, NULL);
|
||||
btrfs_set_extent_bit(&trans->transaction->dirty_pages, buf->start,
|
||||
buf->start + buf->len - 1, EXTENT_DIRTY, NULL);
|
||||
}
|
||||
/* this returns a buffer locked for blocking */
|
||||
return buf;
|
||||
@@ -5187,7 +5225,7 @@ out_free_buf:
|
||||
btrfs_tree_unlock(buf);
|
||||
free_extent_buffer(buf);
|
||||
out_free_reserved:
|
||||
btrfs_free_reserved_extent(fs_info, ins.objectid, ins.offset, 0);
|
||||
btrfs_free_reserved_extent(fs_info, ins.objectid, ins.offset, false);
|
||||
out_unuse:
|
||||
btrfs_unuse_block_rsv(fs_info, block_rsv, blocksize);
|
||||
return ERR_PTR(ret);
|
||||
@@ -6397,13 +6435,13 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed)
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
find_first_clear_extent_bit(&device->alloc_state, start,
|
||||
&start, &end,
|
||||
CHUNK_TRIMMED | CHUNK_ALLOCATED);
|
||||
btrfs_find_first_clear_extent_bit(&device->alloc_state, start,
|
||||
&start, &end,
|
||||
CHUNK_TRIMMED | CHUNK_ALLOCATED);
|
||||
|
||||
/* Check if there are any CHUNK_* bits left */
|
||||
if (start > device->total_bytes) {
|
||||
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
|
||||
DEBUG_WARN();
|
||||
btrfs_warn_in_rcu(fs_info,
|
||||
"ignoring attempt to trim beyond device size: offset %llu length %llu device %s device size %llu",
|
||||
start, end - start + 1,
|
||||
@@ -6436,8 +6474,8 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed)
|
||||
ret = btrfs_issue_discard(device->bdev, start, len,
|
||||
&bytes);
|
||||
if (!ret)
|
||||
set_extent_bit(&device->alloc_state, start,
|
||||
start + bytes - 1, CHUNK_TRIMMED, NULL);
|
||||
btrfs_set_extent_bit(&device->alloc_state, start,
|
||||
start + bytes - 1, CHUNK_TRIMMED, NULL);
|
||||
mutex_unlock(&fs_info->chunk_mutex);
|
||||
|
||||
if (ret)
|
||||
|
||||
@@ -149,8 +149,8 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_ref *ref);
|
||||
|
||||
u64 btrfs_get_extent_owner_root(struct btrfs_fs_info *fs_info,
|
||||
struct extent_buffer *leaf, int slot);
|
||||
int btrfs_free_reserved_extent(struct btrfs_fs_info *fs_info,
|
||||
u64 start, u64 len, int delalloc);
|
||||
int btrfs_free_reserved_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len,
|
||||
bool is_delalloc);
|
||||
int btrfs_pin_reserved_extent(struct btrfs_trans_handle *trans,
|
||||
const struct extent_buffer *eb);
|
||||
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans);
|
||||
|
||||
+464
-496
File diff suppressed because it is too large
Load Diff
@@ -38,16 +38,10 @@ struct btrfs_tree_parent_check;
|
||||
enum {
|
||||
EXTENT_BUFFER_UPTODATE,
|
||||
EXTENT_BUFFER_DIRTY,
|
||||
EXTENT_BUFFER_CORRUPT,
|
||||
/* this got triggered by readahead */
|
||||
EXTENT_BUFFER_READAHEAD,
|
||||
EXTENT_BUFFER_TREE_REF,
|
||||
EXTENT_BUFFER_STALE,
|
||||
EXTENT_BUFFER_WRITEBACK,
|
||||
/* read IO error */
|
||||
EXTENT_BUFFER_READ_ERR,
|
||||
EXTENT_BUFFER_UNMAPPED,
|
||||
EXTENT_BUFFER_IN_TREE,
|
||||
/* write IO error */
|
||||
EXTENT_BUFFER_WRITE_ERR,
|
||||
/* Indicate the extent buffer is written zeroed out (for zoned) */
|
||||
@@ -79,7 +73,7 @@ enum {
|
||||
* single word in a bitmap may straddle two pages in the extent buffer.
|
||||
*/
|
||||
#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE)
|
||||
#define BYTE_MASK ((1 << BITS_PER_BYTE) - 1)
|
||||
#define BYTE_MASK ((1U << BITS_PER_BYTE) - 1)
|
||||
#define BITMAP_FIRST_BYTE_MASK(start) \
|
||||
((BYTE_MASK << ((start) & (BITS_PER_BYTE - 1))) & BYTE_MASK)
|
||||
#define BITMAP_LAST_BYTE_MASK(nbits) \
|
||||
@@ -246,6 +240,7 @@ void extent_write_locked_range(struct inode *inode, const struct folio *locked_f
|
||||
int btrfs_writepages(struct address_space *mapping, struct writeback_control *wbc);
|
||||
int btree_write_cache_pages(struct address_space *mapping,
|
||||
struct writeback_control *wbc);
|
||||
void btrfs_btree_wait_writeback_range(struct btrfs_fs_info *fs_info, u64 start, u64 end);
|
||||
void btrfs_readahead(struct readahead_control *rac);
|
||||
int set_folio_extent_mapped(struct folio *folio);
|
||||
void clear_folio_extent_mapped(struct folio *folio);
|
||||
|
||||
+87
-88
@@ -13,7 +13,7 @@
|
||||
|
||||
static struct kmem_cache *extent_map_cache;
|
||||
|
||||
int __init extent_map_init(void)
|
||||
int __init btrfs_extent_map_init(void)
|
||||
{
|
||||
extent_map_cache = kmem_cache_create("btrfs_extent_map",
|
||||
sizeof(struct extent_map), 0, 0, NULL);
|
||||
@@ -22,7 +22,7 @@ int __init extent_map_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __cold extent_map_exit(void)
|
||||
void __cold btrfs_extent_map_exit(void)
|
||||
{
|
||||
kmem_cache_destroy(extent_map_cache);
|
||||
}
|
||||
@@ -31,7 +31,7 @@ void __cold extent_map_exit(void)
|
||||
* Initialize the extent tree @tree. Should be called for each new inode or
|
||||
* other user of the extent_map interface.
|
||||
*/
|
||||
void extent_map_tree_init(struct extent_map_tree *tree)
|
||||
void btrfs_extent_map_tree_init(struct extent_map_tree *tree)
|
||||
{
|
||||
tree->root = RB_ROOT;
|
||||
INIT_LIST_HEAD(&tree->modified_extents);
|
||||
@@ -42,7 +42,7 @@ void extent_map_tree_init(struct extent_map_tree *tree)
|
||||
* Allocate a new extent_map structure. The new structure is returned with a
|
||||
* reference count of one and needs to be freed using free_extent_map()
|
||||
*/
|
||||
struct extent_map *alloc_extent_map(void)
|
||||
struct extent_map *btrfs_alloc_extent_map(void)
|
||||
{
|
||||
struct extent_map *em;
|
||||
em = kmem_cache_zalloc(extent_map_cache, GFP_NOFS);
|
||||
@@ -58,12 +58,12 @@ struct extent_map *alloc_extent_map(void)
|
||||
* Drop the reference out on @em by one and free the structure if the reference
|
||||
* count hits zero.
|
||||
*/
|
||||
void free_extent_map(struct extent_map *em)
|
||||
void btrfs_free_extent_map(struct extent_map *em)
|
||||
{
|
||||
if (!em)
|
||||
return;
|
||||
if (refcount_dec_and_test(&em->refs)) {
|
||||
WARN_ON(extent_map_in_tree(em));
|
||||
WARN_ON(btrfs_extent_map_in_tree(em));
|
||||
WARN_ON(!list_empty(&em->list));
|
||||
kmem_cache_free(extent_map_cache, em);
|
||||
}
|
||||
@@ -102,19 +102,19 @@ static int tree_insert(struct rb_root *root, struct extent_map *em)
|
||||
|
||||
if (em->start < entry->start)
|
||||
p = &(*p)->rb_left;
|
||||
else if (em->start >= extent_map_end(entry))
|
||||
else if (em->start >= btrfs_extent_map_end(entry))
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
orig_parent = parent;
|
||||
while (parent && em->start >= extent_map_end(entry)) {
|
||||
while (parent && em->start >= btrfs_extent_map_end(entry)) {
|
||||
parent = rb_next(parent);
|
||||
entry = rb_entry(parent, struct extent_map, rb_node);
|
||||
}
|
||||
if (parent)
|
||||
if (end > entry->start && em->start < extent_map_end(entry))
|
||||
if (end > entry->start && em->start < btrfs_extent_map_end(entry))
|
||||
return -EEXIST;
|
||||
|
||||
parent = orig_parent;
|
||||
@@ -124,7 +124,7 @@ static int tree_insert(struct rb_root *root, struct extent_map *em)
|
||||
entry = rb_entry(parent, struct extent_map, rb_node);
|
||||
}
|
||||
if (parent)
|
||||
if (end > entry->start && em->start < extent_map_end(entry))
|
||||
if (end > entry->start && em->start < btrfs_extent_map_end(entry))
|
||||
return -EEXIST;
|
||||
|
||||
rb_link_node(&em->rb_node, orig_parent, p);
|
||||
@@ -136,8 +136,8 @@ static int tree_insert(struct rb_root *root, struct extent_map *em)
|
||||
* Search through the tree for an extent_map with a given offset. If it can't
|
||||
* be found, try to find some neighboring extents
|
||||
*/
|
||||
static struct rb_node *__tree_search(struct rb_root *root, u64 offset,
|
||||
struct rb_node **prev_or_next_ret)
|
||||
static struct rb_node *tree_search(struct rb_root *root, u64 offset,
|
||||
struct rb_node **prev_or_next_ret)
|
||||
{
|
||||
struct rb_node *n = root->rb_node;
|
||||
struct rb_node *prev = NULL;
|
||||
@@ -154,14 +154,14 @@ static struct rb_node *__tree_search(struct rb_root *root, u64 offset,
|
||||
|
||||
if (offset < entry->start)
|
||||
n = n->rb_left;
|
||||
else if (offset >= extent_map_end(entry))
|
||||
else if (offset >= btrfs_extent_map_end(entry))
|
||||
n = n->rb_right;
|
||||
else
|
||||
return n;
|
||||
}
|
||||
|
||||
orig_prev = prev;
|
||||
while (prev && offset >= extent_map_end(prev_entry)) {
|
||||
while (prev && offset >= btrfs_extent_map_end(prev_entry)) {
|
||||
prev = rb_next(prev);
|
||||
prev_entry = rb_entry(prev, struct extent_map, rb_node);
|
||||
}
|
||||
@@ -188,14 +188,14 @@ static struct rb_node *__tree_search(struct rb_root *root, u64 offset,
|
||||
|
||||
static inline u64 extent_map_block_len(const struct extent_map *em)
|
||||
{
|
||||
if (extent_map_is_compressed(em))
|
||||
if (btrfs_extent_map_is_compressed(em))
|
||||
return em->disk_num_bytes;
|
||||
return em->len;
|
||||
}
|
||||
|
||||
static inline u64 extent_map_block_end(const struct extent_map *em)
|
||||
{
|
||||
const u64 block_start = extent_map_block_start(em);
|
||||
const u64 block_start = btrfs_extent_map_block_start(em);
|
||||
const u64 block_end = block_start + extent_map_block_len(em);
|
||||
|
||||
if (block_end < block_start)
|
||||
@@ -210,7 +210,7 @@ static bool can_merge_extent_map(const struct extent_map *em)
|
||||
return false;
|
||||
|
||||
/* Don't merge compressed extents, we need to know their actual size. */
|
||||
if (extent_map_is_compressed(em))
|
||||
if (btrfs_extent_map_is_compressed(em))
|
||||
return false;
|
||||
|
||||
if (em->flags & EXTENT_FLAG_LOGGING)
|
||||
@@ -230,7 +230,7 @@ static bool can_merge_extent_map(const struct extent_map *em)
|
||||
/* Check to see if two extent_map structs are adjacent and safe to merge. */
|
||||
static bool mergeable_maps(const struct extent_map *prev, const struct extent_map *next)
|
||||
{
|
||||
if (extent_map_end(prev) != next->start)
|
||||
if (btrfs_extent_map_end(prev) != next->start)
|
||||
return false;
|
||||
|
||||
/*
|
||||
@@ -242,7 +242,7 @@ static bool mergeable_maps(const struct extent_map *prev, const struct extent_ma
|
||||
return false;
|
||||
|
||||
if (next->disk_bytenr < EXTENT_MAP_LAST_BYTE - 1)
|
||||
return extent_map_block_start(next) == extent_map_block_end(prev);
|
||||
return btrfs_extent_map_block_start(next) == extent_map_block_end(prev);
|
||||
|
||||
/* HOLES and INLINE extents. */
|
||||
return next->disk_bytenr == prev->disk_bytenr;
|
||||
@@ -270,8 +270,8 @@ static void merge_ondisk_extents(const struct extent_map *prev, const struct ext
|
||||
u64 new_offset;
|
||||
|
||||
/* @prev and @next should not be compressed. */
|
||||
ASSERT(!extent_map_is_compressed(prev));
|
||||
ASSERT(!extent_map_is_compressed(next));
|
||||
ASSERT(!btrfs_extent_map_is_compressed(prev));
|
||||
ASSERT(!btrfs_extent_map_is_compressed(next));
|
||||
|
||||
/*
|
||||
* There are two different cases where @prev and @next can be merged.
|
||||
@@ -327,9 +327,9 @@ static void validate_extent_map(struct btrfs_fs_info *fs_info, struct extent_map
|
||||
if (em->offset + em->len > em->ram_bytes)
|
||||
dump_extent_map(fs_info, "ram_bytes too small", em);
|
||||
if (em->offset + em->len > em->disk_num_bytes &&
|
||||
!extent_map_is_compressed(em))
|
||||
!btrfs_extent_map_is_compressed(em))
|
||||
dump_extent_map(fs_info, "disk_num_bytes too small", em);
|
||||
if (!extent_map_is_compressed(em) &&
|
||||
if (!btrfs_extent_map_is_compressed(em) &&
|
||||
em->ram_bytes != em->disk_num_bytes)
|
||||
dump_extent_map(fs_info,
|
||||
"ram_bytes mismatch with disk_num_bytes for non-compressed em",
|
||||
@@ -361,8 +361,8 @@ static void try_merge_map(struct btrfs_inode *inode, struct extent_map *em)
|
||||
|
||||
if (em->start != 0) {
|
||||
rb = rb_prev(&em->rb_node);
|
||||
if (rb)
|
||||
merge = rb_entry(rb, struct extent_map, rb_node);
|
||||
merge = rb_entry_safe(rb, struct extent_map, rb_node);
|
||||
|
||||
if (rb && can_merge_extent_map(merge) && mergeable_maps(merge, em)) {
|
||||
em->start = merge->start;
|
||||
em->len += merge->len;
|
||||
@@ -374,13 +374,13 @@ static void try_merge_map(struct btrfs_inode *inode, struct extent_map *em)
|
||||
|
||||
validate_extent_map(fs_info, em);
|
||||
remove_em(inode, merge);
|
||||
free_extent_map(merge);
|
||||
btrfs_free_extent_map(merge);
|
||||
}
|
||||
}
|
||||
|
||||
rb = rb_next(&em->rb_node);
|
||||
if (rb)
|
||||
merge = rb_entry(rb, struct extent_map, rb_node);
|
||||
merge = rb_entry_safe(rb, struct extent_map, rb_node);
|
||||
|
||||
if (rb && can_merge_extent_map(merge) && mergeable_maps(em, merge)) {
|
||||
em->len += merge->len;
|
||||
if (em->disk_bytenr < EXTENT_MAP_LAST_BYTE)
|
||||
@@ -389,7 +389,7 @@ static void try_merge_map(struct btrfs_inode *inode, struct extent_map *em)
|
||||
em->generation = max(em->generation, merge->generation);
|
||||
em->flags |= EXTENT_FLAG_MERGED;
|
||||
remove_em(inode, merge);
|
||||
free_extent_map(merge);
|
||||
btrfs_free_extent_map(merge);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,7 +409,7 @@ static void try_merge_map(struct btrfs_inode *inode, struct extent_map *em)
|
||||
* -ENOENT when the extent is not found in the tree
|
||||
* -EUCLEAN if the found extent does not match the expected start
|
||||
*/
|
||||
int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen)
|
||||
int btrfs_unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||
struct extent_map_tree *tree = &inode->extent_tree;
|
||||
@@ -417,7 +417,7 @@ int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen)
|
||||
struct extent_map *em;
|
||||
|
||||
write_lock(&tree->lock);
|
||||
em = lookup_extent_mapping(tree, start, len);
|
||||
em = btrfs_lookup_extent_mapping(tree, start, len);
|
||||
|
||||
if (WARN_ON(!em)) {
|
||||
btrfs_warn(fs_info,
|
||||
@@ -444,17 +444,17 @@ int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen)
|
||||
|
||||
out:
|
||||
write_unlock(&tree->lock);
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void clear_em_logging(struct btrfs_inode *inode, struct extent_map *em)
|
||||
void btrfs_clear_em_logging(struct btrfs_inode *inode, struct extent_map *em)
|
||||
{
|
||||
lockdep_assert_held_write(&inode->extent_tree.lock);
|
||||
|
||||
em->flags &= ~EXTENT_FLAG_LOGGING;
|
||||
if (extent_map_in_tree(em))
|
||||
if (btrfs_extent_map_in_tree(em))
|
||||
try_merge_map(inode, em);
|
||||
}
|
||||
|
||||
@@ -508,16 +508,15 @@ static int add_extent_mapping(struct btrfs_inode *inode,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct extent_map *
|
||||
__lookup_extent_mapping(struct extent_map_tree *tree,
|
||||
u64 start, u64 len, int strict)
|
||||
static struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
|
||||
u64 start, u64 len, int strict)
|
||||
{
|
||||
struct extent_map *em;
|
||||
struct rb_node *rb_node;
|
||||
struct rb_node *prev_or_next = NULL;
|
||||
u64 end = range_end(start, len);
|
||||
|
||||
rb_node = __tree_search(&tree->root, start, &prev_or_next);
|
||||
rb_node = tree_search(&tree->root, start, &prev_or_next);
|
||||
if (!rb_node) {
|
||||
if (prev_or_next)
|
||||
rb_node = prev_or_next;
|
||||
@@ -527,7 +526,7 @@ __lookup_extent_mapping(struct extent_map_tree *tree,
|
||||
|
||||
em = rb_entry(rb_node, struct extent_map, rb_node);
|
||||
|
||||
if (strict && !(end > em->start && start < extent_map_end(em)))
|
||||
if (strict && !(end > em->start && start < btrfs_extent_map_end(em)))
|
||||
return NULL;
|
||||
|
||||
refcount_inc(&em->refs);
|
||||
@@ -546,10 +545,10 @@ __lookup_extent_mapping(struct extent_map_tree *tree,
|
||||
* intersect, so check the object returned carefully to make sure that no
|
||||
* additional lookups are needed.
|
||||
*/
|
||||
struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
|
||||
u64 start, u64 len)
|
||||
struct extent_map *btrfs_lookup_extent_mapping(struct extent_map_tree *tree,
|
||||
u64 start, u64 len)
|
||||
{
|
||||
return __lookup_extent_mapping(tree, start, len, 1);
|
||||
return lookup_extent_mapping(tree, start, len, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -564,10 +563,10 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
|
||||
*
|
||||
* If one can't be found, any nearby extent may be returned
|
||||
*/
|
||||
struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
|
||||
u64 start, u64 len)
|
||||
struct extent_map *btrfs_search_extent_mapping(struct extent_map_tree *tree,
|
||||
u64 start, u64 len)
|
||||
{
|
||||
return __lookup_extent_mapping(tree, start, len, 0);
|
||||
return lookup_extent_mapping(tree, start, len, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -579,7 +578,7 @@ struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
|
||||
* Remove @em from the extent tree of @inode. No reference counts are dropped,
|
||||
* and no checks are done to see if the range is in use.
|
||||
*/
|
||||
void remove_extent_mapping(struct btrfs_inode *inode, struct extent_map *em)
|
||||
void btrfs_remove_extent_mapping(struct btrfs_inode *inode, struct extent_map *em)
|
||||
{
|
||||
struct extent_map_tree *tree = &inode->extent_tree;
|
||||
|
||||
@@ -605,7 +604,7 @@ static void replace_extent_mapping(struct btrfs_inode *inode,
|
||||
validate_extent_map(fs_info, new);
|
||||
|
||||
WARN_ON(cur->flags & EXTENT_FLAG_PINNED);
|
||||
ASSERT(extent_map_in_tree(cur));
|
||||
ASSERT(btrfs_extent_map_in_tree(cur));
|
||||
if (!(cur->flags & EXTENT_FLAG_LOGGING))
|
||||
list_del_init(&cur->list);
|
||||
rb_replace_node(&cur->rb_node, &new->rb_node, &tree->root);
|
||||
@@ -651,7 +650,7 @@ static noinline int merge_extent_mapping(struct btrfs_inode *inode,
|
||||
u64 end;
|
||||
u64 start_diff;
|
||||
|
||||
if (map_start < em->start || map_start >= extent_map_end(em))
|
||||
if (map_start < em->start || map_start >= btrfs_extent_map_end(em))
|
||||
return -EINVAL;
|
||||
|
||||
if (existing->start > map_start) {
|
||||
@@ -662,10 +661,10 @@ static noinline int merge_extent_mapping(struct btrfs_inode *inode,
|
||||
next = next_extent_map(prev);
|
||||
}
|
||||
|
||||
start = prev ? extent_map_end(prev) : em->start;
|
||||
start = prev ? btrfs_extent_map_end(prev) : em->start;
|
||||
start = max_t(u64, start, em->start);
|
||||
end = next ? next->start : extent_map_end(em);
|
||||
end = min_t(u64, end, extent_map_end(em));
|
||||
end = next ? next->start : btrfs_extent_map_end(em);
|
||||
end = min_t(u64, end, btrfs_extent_map_end(em));
|
||||
start_diff = start - em->start;
|
||||
em->start = start;
|
||||
em->len = end - start;
|
||||
@@ -716,7 +715,7 @@ int btrfs_add_extent_mapping(struct btrfs_inode *inode,
|
||||
if (ret == -EEXIST) {
|
||||
struct extent_map *existing;
|
||||
|
||||
existing = search_extent_mapping(&inode->extent_tree, start, len);
|
||||
existing = btrfs_search_extent_mapping(&inode->extent_tree, start, len);
|
||||
|
||||
trace_btrfs_handle_em_exist(fs_info, existing, em, start, len);
|
||||
|
||||
@@ -725,8 +724,8 @@ int btrfs_add_extent_mapping(struct btrfs_inode *inode,
|
||||
* extent causing the -EEXIST.
|
||||
*/
|
||||
if (start >= existing->start &&
|
||||
start < extent_map_end(existing)) {
|
||||
free_extent_map(em);
|
||||
start < btrfs_extent_map_end(existing)) {
|
||||
btrfs_free_extent_map(em);
|
||||
*em_in = existing;
|
||||
ret = 0;
|
||||
} else {
|
||||
@@ -739,14 +738,14 @@ int btrfs_add_extent_mapping(struct btrfs_inode *inode,
|
||||
*/
|
||||
ret = merge_extent_mapping(inode, existing, em, start);
|
||||
if (WARN_ON(ret)) {
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
*em_in = NULL;
|
||||
btrfs_warn(fs_info,
|
||||
"extent map merge error existing [%llu, %llu) with em [%llu, %llu) start %llu",
|
||||
existing->start, extent_map_end(existing),
|
||||
existing->start, btrfs_extent_map_end(existing),
|
||||
orig_start, orig_start + orig_len, start);
|
||||
}
|
||||
free_extent_map(existing);
|
||||
btrfs_free_extent_map(existing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,8 +771,8 @@ static void drop_all_extent_maps_fast(struct btrfs_inode *inode)
|
||||
|
||||
em = rb_entry(node, struct extent_map, rb_node);
|
||||
em->flags &= ~(EXTENT_FLAG_PINNED | EXTENT_FLAG_LOGGING);
|
||||
remove_extent_mapping(inode, em);
|
||||
free_extent_map(em);
|
||||
btrfs_remove_extent_mapping(inode, em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
if (cond_resched_rwlock_write(&tree->lock))
|
||||
node = rb_first(&tree->root);
|
||||
@@ -826,15 +825,15 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
|
||||
* range ends after our range (and they might be the same extent map),
|
||||
* because we need to split those two extent maps at the boundaries.
|
||||
*/
|
||||
split = alloc_extent_map();
|
||||
split2 = alloc_extent_map();
|
||||
split = btrfs_alloc_extent_map();
|
||||
split2 = btrfs_alloc_extent_map();
|
||||
|
||||
write_lock(&em_tree->lock);
|
||||
em = lookup_extent_mapping(em_tree, start, len);
|
||||
em = btrfs_lookup_extent_mapping(em_tree, start, len);
|
||||
|
||||
while (em) {
|
||||
/* extent_map_end() returns exclusive value (last byte + 1). */
|
||||
const u64 em_end = extent_map_end(em);
|
||||
const u64 em_end = btrfs_extent_map_end(em);
|
||||
struct extent_map *next_em = NULL;
|
||||
u64 gen;
|
||||
unsigned long flags;
|
||||
@@ -898,7 +897,7 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
|
||||
split->generation = gen;
|
||||
split->flags = flags;
|
||||
replace_extent_mapping(inode, em, split, modified);
|
||||
free_extent_map(split);
|
||||
btrfs_free_extent_map(split);
|
||||
split = split2;
|
||||
split2 = NULL;
|
||||
}
|
||||
@@ -925,7 +924,7 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
|
||||
split->ram_bytes = split->len;
|
||||
}
|
||||
|
||||
if (extent_map_in_tree(em)) {
|
||||
if (btrfs_extent_map_in_tree(em)) {
|
||||
replace_extent_mapping(inode, em, split, modified);
|
||||
} else {
|
||||
int ret;
|
||||
@@ -936,11 +935,11 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
|
||||
if (WARN_ON(ret != 0) && modified)
|
||||
btrfs_set_inode_full_sync(inode);
|
||||
}
|
||||
free_extent_map(split);
|
||||
btrfs_free_extent_map(split);
|
||||
split = NULL;
|
||||
}
|
||||
remove_em:
|
||||
if (extent_map_in_tree(em)) {
|
||||
if (btrfs_extent_map_in_tree(em)) {
|
||||
/*
|
||||
* If the extent map is still in the tree it means that
|
||||
* either of the following is true:
|
||||
@@ -965,25 +964,25 @@ remove_em:
|
||||
ASSERT(!split);
|
||||
btrfs_set_inode_full_sync(inode);
|
||||
}
|
||||
remove_extent_mapping(inode, em);
|
||||
btrfs_remove_extent_mapping(inode, em);
|
||||
}
|
||||
|
||||
/*
|
||||
* Once for the tree reference (we replaced or removed the
|
||||
* extent map from the tree).
|
||||
*/
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
next:
|
||||
/* Once for us (for our lookup reference). */
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = next_em;
|
||||
}
|
||||
|
||||
write_unlock(&em_tree->lock);
|
||||
|
||||
free_extent_map(split);
|
||||
free_extent_map(split2);
|
||||
btrfs_free_extent_map(split);
|
||||
btrfs_free_extent_map(split2);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1007,7 +1006,7 @@ int btrfs_replace_extent_map_range(struct btrfs_inode *inode,
|
||||
struct extent_map_tree *tree = &inode->extent_tree;
|
||||
int ret;
|
||||
|
||||
ASSERT(!extent_map_in_tree(new_em));
|
||||
ASSERT(!btrfs_extent_map_in_tree(new_em));
|
||||
|
||||
/*
|
||||
* The caller has locked an appropriate file range in the inode's io
|
||||
@@ -1033,8 +1032,8 @@ int btrfs_replace_extent_map_range(struct btrfs_inode *inode,
|
||||
*
|
||||
* This function is used when an ordered_extent needs to be split.
|
||||
*/
|
||||
int split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre,
|
||||
u64 new_logical)
|
||||
int btrfs_split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre,
|
||||
u64 new_logical)
|
||||
{
|
||||
struct extent_map_tree *em_tree = &inode->extent_tree;
|
||||
struct extent_map *em;
|
||||
@@ -1046,25 +1045,25 @@ int split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre,
|
||||
ASSERT(pre != 0);
|
||||
ASSERT(pre < len);
|
||||
|
||||
split_pre = alloc_extent_map();
|
||||
split_pre = btrfs_alloc_extent_map();
|
||||
if (!split_pre)
|
||||
return -ENOMEM;
|
||||
split_mid = alloc_extent_map();
|
||||
split_mid = btrfs_alloc_extent_map();
|
||||
if (!split_mid) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free_pre;
|
||||
}
|
||||
|
||||
lock_extent(&inode->io_tree, start, start + len - 1, NULL);
|
||||
btrfs_lock_extent(&inode->io_tree, start, start + len - 1, NULL);
|
||||
write_lock(&em_tree->lock);
|
||||
em = lookup_extent_mapping(em_tree, start, len);
|
||||
em = btrfs_lookup_extent_mapping(em_tree, start, len);
|
||||
if (!em) {
|
||||
ret = -EIO;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ASSERT(em->len == len);
|
||||
ASSERT(!extent_map_is_compressed(em));
|
||||
ASSERT(!btrfs_extent_map_is_compressed(em));
|
||||
ASSERT(em->disk_bytenr < EXTENT_MAP_LAST_BYTE);
|
||||
ASSERT(em->flags & EXTENT_FLAG_PINNED);
|
||||
ASSERT(!(em->flags & EXTENT_FLAG_LOGGING));
|
||||
@@ -1093,7 +1092,7 @@ int split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre,
|
||||
/* Insert the middle extent_map. */
|
||||
split_mid->start = em->start + pre;
|
||||
split_mid->len = em->len - pre;
|
||||
split_mid->disk_bytenr = extent_map_block_start(em) + pre;
|
||||
split_mid->disk_bytenr = btrfs_extent_map_block_start(em) + pre;
|
||||
split_mid->disk_num_bytes = split_mid->len;
|
||||
split_mid->offset = 0;
|
||||
split_mid->ram_bytes = split_mid->len;
|
||||
@@ -1102,16 +1101,16 @@ int split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre,
|
||||
add_extent_mapping(inode, split_mid, 1);
|
||||
|
||||
/* Once for us */
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
/* Once for the tree */
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
out_unlock:
|
||||
write_unlock(&em_tree->lock);
|
||||
unlock_extent(&inode->io_tree, start, start + len - 1, NULL);
|
||||
free_extent_map(split_mid);
|
||||
btrfs_unlock_extent(&inode->io_tree, start, start + len - 1, NULL);
|
||||
btrfs_free_extent_map(split_mid);
|
||||
out_free_pre:
|
||||
free_extent_map(split_pre);
|
||||
btrfs_free_extent_map(split_pre);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1168,10 +1167,10 @@ static long btrfs_scan_inode(struct btrfs_inode *inode, struct btrfs_em_shrink_c
|
||||
if (!list_empty(&em->list) && em->generation >= cur_fs_gen)
|
||||
btrfs_set_inode_full_sync(inode);
|
||||
|
||||
remove_extent_mapping(inode, em);
|
||||
btrfs_remove_extent_mapping(inode, em);
|
||||
trace_btrfs_extent_map_shrinker_remove_em(inode, em);
|
||||
/* Drop the reference for the tree. */
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
nr_dropped++;
|
||||
next:
|
||||
if (ctx->scanned >= ctx->nr_to_scan)
|
||||
|
||||
+23
-22
@@ -108,8 +108,8 @@ struct extent_map_tree {
|
||||
|
||||
struct btrfs_inode;
|
||||
|
||||
static inline void extent_map_set_compression(struct extent_map *em,
|
||||
enum btrfs_compression_type type)
|
||||
static inline void btrfs_extent_map_set_compression(struct extent_map *em,
|
||||
enum btrfs_compression_type type)
|
||||
{
|
||||
if (type == BTRFS_COMPRESS_ZLIB)
|
||||
em->flags |= EXTENT_FLAG_COMPRESS_ZLIB;
|
||||
@@ -119,7 +119,8 @@ static inline void extent_map_set_compression(struct extent_map *em,
|
||||
em->flags |= EXTENT_FLAG_COMPRESS_ZSTD;
|
||||
}
|
||||
|
||||
static inline enum btrfs_compression_type extent_map_compression(const struct extent_map *em)
|
||||
static inline enum btrfs_compression_type btrfs_extent_map_compression(
|
||||
const struct extent_map *em)
|
||||
{
|
||||
if (em->flags & EXTENT_FLAG_COMPRESS_ZLIB)
|
||||
return BTRFS_COMPRESS_ZLIB;
|
||||
@@ -137,50 +138,50 @@ static inline enum btrfs_compression_type extent_map_compression(const struct ex
|
||||
* More efficient way to determine if extent is compressed, instead of using
|
||||
* 'extent_map_compression() != BTRFS_COMPRESS_NONE'.
|
||||
*/
|
||||
static inline bool extent_map_is_compressed(const struct extent_map *em)
|
||||
static inline bool btrfs_extent_map_is_compressed(const struct extent_map *em)
|
||||
{
|
||||
return (em->flags & (EXTENT_FLAG_COMPRESS_ZLIB |
|
||||
EXTENT_FLAG_COMPRESS_LZO |
|
||||
EXTENT_FLAG_COMPRESS_ZSTD)) != 0;
|
||||
}
|
||||
|
||||
static inline int extent_map_in_tree(const struct extent_map *em)
|
||||
static inline int btrfs_extent_map_in_tree(const struct extent_map *em)
|
||||
{
|
||||
return !RB_EMPTY_NODE(&em->rb_node);
|
||||
}
|
||||
|
||||
static inline u64 extent_map_block_start(const struct extent_map *em)
|
||||
static inline u64 btrfs_extent_map_block_start(const struct extent_map *em)
|
||||
{
|
||||
if (em->disk_bytenr < EXTENT_MAP_LAST_BYTE) {
|
||||
if (extent_map_is_compressed(em))
|
||||
if (btrfs_extent_map_is_compressed(em))
|
||||
return em->disk_bytenr;
|
||||
return em->disk_bytenr + em->offset;
|
||||
}
|
||||
return em->disk_bytenr;
|
||||
}
|
||||
|
||||
static inline u64 extent_map_end(const struct extent_map *em)
|
||||
static inline u64 btrfs_extent_map_end(const struct extent_map *em)
|
||||
{
|
||||
if (em->start + em->len < em->start)
|
||||
return (u64)-1;
|
||||
return em->start + em->len;
|
||||
}
|
||||
|
||||
void extent_map_tree_init(struct extent_map_tree *tree);
|
||||
struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
|
||||
u64 start, u64 len);
|
||||
void remove_extent_mapping(struct btrfs_inode *inode, struct extent_map *em);
|
||||
int split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre,
|
||||
u64 new_logical);
|
||||
void btrfs_extent_map_tree_init(struct extent_map_tree *tree);
|
||||
struct extent_map *btrfs_lookup_extent_mapping(struct extent_map_tree *tree,
|
||||
u64 start, u64 len);
|
||||
void btrfs_remove_extent_mapping(struct btrfs_inode *inode, struct extent_map *em);
|
||||
int btrfs_split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre,
|
||||
u64 new_logical);
|
||||
|
||||
struct extent_map *alloc_extent_map(void);
|
||||
void free_extent_map(struct extent_map *em);
|
||||
int __init extent_map_init(void);
|
||||
void __cold extent_map_exit(void);
|
||||
int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen);
|
||||
void clear_em_logging(struct btrfs_inode *inode, struct extent_map *em);
|
||||
struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
|
||||
u64 start, u64 len);
|
||||
struct extent_map *btrfs_alloc_extent_map(void);
|
||||
void btrfs_free_extent_map(struct extent_map *em);
|
||||
int __init btrfs_extent_map_init(void);
|
||||
void __cold btrfs_extent_map_exit(void);
|
||||
int btrfs_unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen);
|
||||
void btrfs_clear_em_logging(struct btrfs_inode *inode, struct extent_map *em);
|
||||
struct extent_map *btrfs_search_extent_mapping(struct extent_map_tree *tree,
|
||||
u64 start, u64 len);
|
||||
int btrfs_add_extent_mapping(struct btrfs_inode *inode,
|
||||
struct extent_map **em_in, u64 start, u64 len);
|
||||
void btrfs_drop_extent_map_range(struct btrfs_inode *inode,
|
||||
|
||||
+4
-5
@@ -634,7 +634,7 @@ static int extent_fiemap(struct btrfs_inode *inode,
|
||||
const u64 ino = btrfs_ino(inode);
|
||||
struct extent_state *cached_state = NULL;
|
||||
struct extent_state *delalloc_cached_state = NULL;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct fiemap_cache cache = { 0 };
|
||||
struct btrfs_backref_share_check_ctx *backref_ctx;
|
||||
u64 last_extent_end = 0;
|
||||
@@ -661,7 +661,7 @@ restart:
|
||||
range_end = round_up(start + len, sectorsize);
|
||||
prev_extent_end = range_start;
|
||||
|
||||
lock_extent(&inode->io_tree, range_start, range_end, &cached_state);
|
||||
btrfs_lock_extent(&inode->io_tree, range_start, range_end, &cached_state);
|
||||
|
||||
ret = fiemap_find_last_extent_offset(inode, path, &last_extent_end);
|
||||
if (ret < 0)
|
||||
@@ -841,7 +841,7 @@ check_eof_delalloc:
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
unlock_extent(&inode->io_tree, range_start, range_end, &cached_state);
|
||||
btrfs_unlock_extent(&inode->io_tree, range_start, range_end, &cached_state);
|
||||
|
||||
if (ret == BTRFS_FIEMAP_FLUSH_CACHE) {
|
||||
btrfs_release_path(path);
|
||||
@@ -871,10 +871,9 @@ out_unlock:
|
||||
|
||||
ret = emit_last_fiemap_cache(fieinfo, &cache);
|
||||
out:
|
||||
free_extent_state(delalloc_cached_state);
|
||||
btrfs_free_extent_state(delalloc_cached_state);
|
||||
kfree(cache.entries);
|
||||
btrfs_free_backref_share_ctx(backref_ctx);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+24
-25
@@ -46,7 +46,7 @@
|
||||
void btrfs_inode_safe_disk_i_size_write(struct btrfs_inode *inode, u64 new_i_size)
|
||||
{
|
||||
u64 start, end, i_size;
|
||||
int ret;
|
||||
bool found;
|
||||
|
||||
spin_lock(&inode->lock);
|
||||
i_size = new_i_size ?: i_size_read(&inode->vfs_inode);
|
||||
@@ -55,9 +55,9 @@ void btrfs_inode_safe_disk_i_size_write(struct btrfs_inode *inode, u64 new_i_siz
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = find_contiguous_extent_bit(inode->file_extent_tree, 0, &start,
|
||||
&end, EXTENT_DIRTY);
|
||||
if (!ret && start == 0)
|
||||
found = btrfs_find_contiguous_extent_bit(inode->file_extent_tree, 0, &start,
|
||||
&end, EXTENT_DIRTY);
|
||||
if (found && start == 0)
|
||||
i_size = min(i_size, end + 1);
|
||||
else
|
||||
i_size = 0;
|
||||
@@ -91,8 +91,8 @@ int btrfs_inode_set_file_extent_range(struct btrfs_inode *inode, u64 start,
|
||||
|
||||
ASSERT(IS_ALIGNED(start + len, inode->root->fs_info->sectorsize));
|
||||
|
||||
return set_extent_bit(inode->file_extent_tree, start, start + len - 1,
|
||||
EXTENT_DIRTY, NULL);
|
||||
return btrfs_set_extent_bit(inode->file_extent_tree, start, start + len - 1,
|
||||
EXTENT_DIRTY, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -121,8 +121,8 @@ int btrfs_inode_clear_file_extent_range(struct btrfs_inode *inode, u64 start,
|
||||
ASSERT(IS_ALIGNED(start + len, inode->root->fs_info->sectorsize) ||
|
||||
len == (u64)-1);
|
||||
|
||||
return clear_extent_bit(inode->file_extent_tree, start,
|
||||
start + len - 1, EXTENT_DIRTY, NULL);
|
||||
return btrfs_clear_extent_bit(inode->file_extent_tree, start,
|
||||
start + len - 1, EXTENT_DIRTY, NULL);
|
||||
}
|
||||
|
||||
static size_t bytes_to_csum_size(const struct btrfs_fs_info *fs_info, u32 bytes)
|
||||
@@ -336,7 +336,7 @@ out:
|
||||
*
|
||||
* Return: BLK_STS_RESOURCE if allocating memory fails, BLK_STS_OK otherwise.
|
||||
*/
|
||||
blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
|
||||
int btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
|
||||
{
|
||||
struct btrfs_inode *inode = bbio->inode;
|
||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||
@@ -347,12 +347,12 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
|
||||
u32 orig_len = bio->bi_iter.bi_size;
|
||||
u64 orig_disk_bytenr = bio->bi_iter.bi_sector << SECTOR_SHIFT;
|
||||
const unsigned int nblocks = orig_len >> fs_info->sectorsize_bits;
|
||||
blk_status_t ret = BLK_STS_OK;
|
||||
int ret = 0;
|
||||
u32 bio_offset = 0;
|
||||
|
||||
if ((inode->flags & BTRFS_INODE_NODATASUM) ||
|
||||
test_bit(BTRFS_FS_STATE_NO_DATA_CSUMS, &fs_info->fs_state))
|
||||
return BLK_STS_OK;
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* This function is only called for read bio.
|
||||
@@ -369,12 +369,12 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
|
||||
ASSERT(bio_op(bio) == REQ_OP_READ);
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return BLK_STS_RESOURCE;
|
||||
return -ENOMEM;
|
||||
|
||||
if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) {
|
||||
bbio->csum = kmalloc_array(nblocks, csum_size, GFP_NOFS);
|
||||
if (!bbio->csum)
|
||||
return BLK_STS_RESOURCE;
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
bbio->csum = bbio->csum_inline;
|
||||
}
|
||||
@@ -406,7 +406,7 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
|
||||
count = search_csum_tree(fs_info, path, cur_disk_bytenr,
|
||||
orig_len - bio_offset, csum_dst);
|
||||
if (count < 0) {
|
||||
ret = errno_to_blk_status(count);
|
||||
ret = count;
|
||||
if (bbio->csum != bbio->csum_inline)
|
||||
kfree(bbio->csum);
|
||||
bbio->csum = NULL;
|
||||
@@ -430,9 +430,9 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
|
||||
if (btrfs_root_id(inode->root) == BTRFS_DATA_RELOC_TREE_OBJECTID) {
|
||||
u64 file_offset = bbio->file_offset + bio_offset;
|
||||
|
||||
set_extent_bit(&inode->io_tree, file_offset,
|
||||
file_offset + sectorsize - 1,
|
||||
EXTENT_NODATASUM, NULL);
|
||||
btrfs_set_extent_bit(&inode->io_tree, file_offset,
|
||||
file_offset + sectorsize - 1,
|
||||
EXTENT_NODATASUM, NULL);
|
||||
} else {
|
||||
btrfs_warn_rl(fs_info,
|
||||
"csum hole found for disk bytenr range [%llu, %llu)",
|
||||
@@ -735,7 +735,7 @@ fail:
|
||||
/*
|
||||
* Calculate checksums of the data contained inside a bio.
|
||||
*/
|
||||
blk_status_t btrfs_csum_one_bio(struct btrfs_bio *bbio)
|
||||
int btrfs_csum_one_bio(struct btrfs_bio *bbio)
|
||||
{
|
||||
struct btrfs_ordered_extent *ordered = bbio->ordered;
|
||||
struct btrfs_inode *inode = bbio->inode;
|
||||
@@ -757,7 +757,7 @@ blk_status_t btrfs_csum_one_bio(struct btrfs_bio *bbio)
|
||||
memalloc_nofs_restore(nofs_flag);
|
||||
|
||||
if (!sums)
|
||||
return BLK_STS_RESOURCE;
|
||||
return -ENOMEM;
|
||||
|
||||
sums->len = bio->bi_iter.bi_size;
|
||||
INIT_LIST_HEAD(&sums->list);
|
||||
@@ -794,11 +794,11 @@ blk_status_t btrfs_csum_one_bio(struct btrfs_bio *bbio)
|
||||
* record the updated logical address on Zone Append completion.
|
||||
* Allocate just the structure with an empty sums array here for that case.
|
||||
*/
|
||||
blk_status_t btrfs_alloc_dummy_sum(struct btrfs_bio *bbio)
|
||||
int btrfs_alloc_dummy_sum(struct btrfs_bio *bbio)
|
||||
{
|
||||
bbio->sums = kmalloc(sizeof(*bbio->sums), GFP_NOFS);
|
||||
if (!bbio->sums)
|
||||
return BLK_STS_RESOURCE;
|
||||
return -ENOMEM;
|
||||
bbio->sums->len = bbio->bio.bi_iter.bi_size;
|
||||
bbio->sums->logical = bbio->bio.bi_iter.bi_sector << SECTOR_SHIFT;
|
||||
btrfs_add_ordered_sum(bbio->ordered, bbio->sums);
|
||||
@@ -1048,7 +1048,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
struct btrfs_key file_key;
|
||||
struct btrfs_key found_key;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_csum_item *item;
|
||||
struct btrfs_csum_item *item_end;
|
||||
struct extent_buffer *leaf = NULL;
|
||||
@@ -1259,7 +1259,6 @@ found:
|
||||
goto again;
|
||||
}
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1297,7 +1296,7 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
|
||||
em->disk_num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
|
||||
em->offset = btrfs_file_extent_offset(leaf, fi);
|
||||
if (compress_type != BTRFS_COMPRESS_NONE) {
|
||||
extent_map_set_compression(em, compress_type);
|
||||
btrfs_extent_map_set_compression(em, compress_type);
|
||||
} else {
|
||||
/*
|
||||
* Older kernels can create regular non-hole data
|
||||
@@ -1317,7 +1316,7 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
|
||||
em->start = 0;
|
||||
em->len = fs_info->sectorsize;
|
||||
em->offset = 0;
|
||||
extent_map_set_compression(em, compress_type);
|
||||
btrfs_extent_map_set_compression(em, compress_type);
|
||||
} else {
|
||||
btrfs_err(fs_info,
|
||||
"unknown file extent item type %d, inode %llu, offset %llu, "
|
||||
|
||||
@@ -53,7 +53,7 @@ static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize)
|
||||
|
||||
int btrfs_del_csums(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 bytenr, u64 len);
|
||||
blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio);
|
||||
int btrfs_lookup_bio_sums(struct btrfs_bio *bbio);
|
||||
int btrfs_insert_hole_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 objectid, u64 pos,
|
||||
u64 num_bytes);
|
||||
@@ -64,8 +64,8 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
||||
int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_ordered_sum *sums);
|
||||
blk_status_t btrfs_csum_one_bio(struct btrfs_bio *bbio);
|
||||
blk_status_t btrfs_alloc_dummy_sum(struct btrfs_bio *bbio);
|
||||
int btrfs_csum_one_bio(struct btrfs_bio *bbio);
|
||||
int btrfs_alloc_dummy_sum(struct btrfs_bio *bbio);
|
||||
int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
|
||||
struct list_head *list, int search_commit,
|
||||
bool nowait);
|
||||
|
||||
+439
-343
File diff suppressed because it is too large
Load Diff
+25
-27
@@ -308,8 +308,9 @@ int btrfs_truncate_free_space_cache(struct btrfs_trans_handle *trans,
|
||||
bool locked = false;
|
||||
|
||||
if (block_group) {
|
||||
struct btrfs_path *path = btrfs_alloc_path();
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
@@ -330,13 +331,12 @@ int btrfs_truncate_free_space_cache(struct btrfs_trans_handle *trans,
|
||||
spin_lock(&block_group->lock);
|
||||
block_group->disk_cache_state = BTRFS_DC_CLEAR;
|
||||
spin_unlock(&block_group->lock);
|
||||
btrfs_free_path(path);
|
||||
}
|
||||
|
||||
btrfs_i_size_write(inode, 0);
|
||||
truncate_pagecache(vfs_inode, 0);
|
||||
|
||||
lock_extent(&inode->io_tree, 0, (u64)-1, &cached_state);
|
||||
btrfs_lock_extent(&inode->io_tree, 0, (u64)-1, &cached_state);
|
||||
btrfs_drop_extent_map_range(inode, 0, (u64)-1, false);
|
||||
|
||||
/*
|
||||
@@ -348,7 +348,7 @@ int btrfs_truncate_free_space_cache(struct btrfs_trans_handle *trans,
|
||||
inode_sub_bytes(&inode->vfs_inode, control.sub_bytes);
|
||||
btrfs_inode_safe_disk_i_size_write(inode, control.last_size);
|
||||
|
||||
unlock_extent(&inode->io_tree, 0, (u64)-1, &cached_state);
|
||||
btrfs_unlock_extent(&inode->io_tree, 0, (u64)-1, &cached_state);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
@@ -457,7 +457,7 @@ static int io_ctl_prepare_pages(struct btrfs_io_ctl *io_ctl, bool uptodate)
|
||||
mask);
|
||||
if (IS_ERR(folio)) {
|
||||
io_ctl_drop_pages(io_ctl);
|
||||
return -ENOMEM;
|
||||
return PTR_ERR(folio);
|
||||
}
|
||||
|
||||
ret = set_folio_extent_mapped(folio);
|
||||
@@ -1080,9 +1080,8 @@ int write_cache_extent_entries(struct btrfs_io_ctl *io_ctl,
|
||||
|
||||
/* Get the cluster for this block_group if it exists */
|
||||
if (block_group && !list_empty(&block_group->cluster_list)) {
|
||||
cluster = list_entry(block_group->cluster_list.next,
|
||||
struct btrfs_free_cluster,
|
||||
block_group_list);
|
||||
cluster = list_first_entry(&block_group->cluster_list,
|
||||
struct btrfs_free_cluster, block_group_list);
|
||||
}
|
||||
|
||||
if (!node && cluster) {
|
||||
@@ -1160,8 +1159,8 @@ update_cache_item(struct btrfs_trans_handle *trans,
|
||||
|
||||
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
|
||||
if (ret < 0) {
|
||||
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
|
||||
EXTENT_DELALLOC, NULL);
|
||||
btrfs_clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
|
||||
EXTENT_DELALLOC, NULL);
|
||||
goto fail;
|
||||
}
|
||||
leaf = path->nodes[0];
|
||||
@@ -1172,9 +1171,9 @@ update_cache_item(struct btrfs_trans_handle *trans,
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
||||
if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID ||
|
||||
found_key.offset != offset) {
|
||||
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0,
|
||||
inode->i_size - 1, EXTENT_DELALLOC,
|
||||
NULL);
|
||||
btrfs_clear_extent_bit(&BTRFS_I(inode)->io_tree, 0,
|
||||
inode->i_size - 1, EXTENT_DELALLOC,
|
||||
NULL);
|
||||
btrfs_release_path(path);
|
||||
goto fail;
|
||||
}
|
||||
@@ -1219,9 +1218,9 @@ static noinline_for_stack int write_pinned_extent_entries(
|
||||
start = block_group->start;
|
||||
|
||||
while (start < block_group->start + block_group->length) {
|
||||
if (!find_first_extent_bit(unpin, start,
|
||||
&extent_start, &extent_end,
|
||||
EXTENT_DIRTY, NULL))
|
||||
if (!btrfs_find_first_extent_bit(unpin, start,
|
||||
&extent_start, &extent_end,
|
||||
EXTENT_DIRTY, NULL))
|
||||
return 0;
|
||||
|
||||
/* This pinned extent is out of our range */
|
||||
@@ -1267,8 +1266,8 @@ static int flush_dirty_cache(struct inode *inode)
|
||||
|
||||
ret = btrfs_wait_ordered_range(BTRFS_I(inode), 0, (u64)-1);
|
||||
if (ret)
|
||||
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
|
||||
EXTENT_DELALLOC, NULL);
|
||||
btrfs_clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
|
||||
EXTENT_DELALLOC, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1288,8 +1287,8 @@ cleanup_write_cache_enospc(struct inode *inode,
|
||||
struct extent_state **cached_state)
|
||||
{
|
||||
io_ctl_drop_pages(io_ctl);
|
||||
unlock_extent(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
||||
cached_state);
|
||||
btrfs_unlock_extent(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
||||
cached_state);
|
||||
}
|
||||
|
||||
static int __btrfs_wait_cache_io(struct btrfs_root *root,
|
||||
@@ -1414,8 +1413,8 @@ static int __btrfs_write_out_cache(struct inode *inode,
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
lock_extent(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
||||
&cached_state);
|
||||
btrfs_lock_extent(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
||||
&cached_state);
|
||||
|
||||
io_ctl_set_generation(io_ctl, trans->transid);
|
||||
|
||||
@@ -1475,8 +1474,8 @@ static int __btrfs_write_out_cache(struct inode *inode,
|
||||
io_ctl_drop_pages(io_ctl);
|
||||
io_ctl_free(io_ctl);
|
||||
|
||||
unlock_extent(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
||||
&cached_state);
|
||||
btrfs_unlock_extent(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
||||
&cached_state);
|
||||
|
||||
/*
|
||||
* at this point the pages are under IO and we're happy,
|
||||
@@ -2342,9 +2341,8 @@ again:
|
||||
struct rb_node *node;
|
||||
struct btrfs_free_space *entry;
|
||||
|
||||
cluster = list_entry(block_group->cluster_list.next,
|
||||
struct btrfs_free_cluster,
|
||||
block_group_list);
|
||||
cluster = list_first_entry(&block_group->cluster_list,
|
||||
struct btrfs_free_cluster, block_group_list);
|
||||
spin_lock(&cluster->lock);
|
||||
node = rb_first(&cluster->root);
|
||||
if (!node) {
|
||||
|
||||
+39
-23
@@ -117,7 +117,7 @@ struct btrfs_free_space_info *search_free_space_info(
|
||||
if (ret != 0) {
|
||||
btrfs_warn(fs_info, "missing free space info for %llu",
|
||||
block_group->start);
|
||||
ASSERT(0);
|
||||
DEBUG_WARN();
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
@@ -141,12 +141,12 @@ static int btrfs_search_prev_slot(struct btrfs_trans_handle *trans,
|
||||
return ret;
|
||||
|
||||
if (ret == 0) {
|
||||
ASSERT(0);
|
||||
DEBUG_WARN();
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (p->slots[0] == 0) {
|
||||
ASSERT(0);
|
||||
DEBUG_WARN("no previous slot found");
|
||||
return -EIO;
|
||||
}
|
||||
p->slots[0]--;
|
||||
@@ -223,6 +223,7 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
|
||||
bitmap = alloc_bitmap(bitmap_size);
|
||||
if (!bitmap) {
|
||||
ret = -ENOMEM;
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -235,8 +236,10 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
|
||||
|
||||
while (!done) {
|
||||
ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
leaf = path->nodes[0];
|
||||
nr = 0;
|
||||
@@ -271,14 +274,17 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
ret = btrfs_del_items(trans, root, path, path->slots[0], nr);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
btrfs_release_path(path);
|
||||
}
|
||||
|
||||
info = search_free_space_info(trans, block_group, path, 1);
|
||||
if (IS_ERR(info)) {
|
||||
ret = PTR_ERR(info);
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
leaf = path->nodes[0];
|
||||
@@ -293,8 +299,8 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
|
||||
"incorrect extent count for %llu; counted %u, expected %u",
|
||||
block_group->start, extent_count,
|
||||
expected_extent_count);
|
||||
ASSERT(0);
|
||||
ret = -EIO;
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -315,8 +321,10 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
|
||||
|
||||
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
||||
data_size);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
leaf = path->nodes[0];
|
||||
ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
|
||||
@@ -331,8 +339,6 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
|
||||
ret = 0;
|
||||
out:
|
||||
kvfree(bitmap);
|
||||
if (ret)
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -358,6 +364,7 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans,
|
||||
bitmap = alloc_bitmap(bitmap_size);
|
||||
if (!bitmap) {
|
||||
ret = -ENOMEM;
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -370,8 +377,10 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans,
|
||||
|
||||
while (!done) {
|
||||
ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
leaf = path->nodes[0];
|
||||
nr = 0;
|
||||
@@ -412,14 +421,17 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
ret = btrfs_del_items(trans, root, path, path->slots[0], nr);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
btrfs_release_path(path);
|
||||
}
|
||||
|
||||
info = search_free_space_info(trans, block_group, path, 1);
|
||||
if (IS_ERR(info)) {
|
||||
ret = PTR_ERR(info);
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
leaf = path->nodes[0];
|
||||
@@ -441,8 +453,10 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans,
|
||||
key.offset = (end_bit - start_bit) * block_group->fs_info->sectorsize;
|
||||
|
||||
ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
btrfs_release_path(path);
|
||||
|
||||
extent_count++;
|
||||
@@ -455,16 +469,14 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans,
|
||||
"incorrect extent count for %llu; counted %u, expected %u",
|
||||
block_group->start, extent_count,
|
||||
expected_extent_count);
|
||||
ASSERT(0);
|
||||
ret = -EIO;
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
kvfree(bitmap);
|
||||
if (ret)
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -838,13 +850,15 @@ int remove_from_free_space_tree(struct btrfs_trans_handle *trans,
|
||||
path = btrfs_alloc_path();
|
||||
if (!path) {
|
||||
ret = -ENOMEM;
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
block_group = btrfs_lookup_block_group(trans->fs_info, start);
|
||||
if (!block_group) {
|
||||
ASSERT(0);
|
||||
DEBUG_WARN("no block group found for start=%llu", start);
|
||||
ret = -ENOENT;
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -852,12 +866,12 @@ int remove_from_free_space_tree(struct btrfs_trans_handle *trans,
|
||||
ret = __remove_from_free_space_tree(trans, block_group, path, start,
|
||||
size);
|
||||
mutex_unlock(&block_group->free_space_lock);
|
||||
if (ret)
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
|
||||
btrfs_put_block_group(block_group);
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
if (ret)
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1031,25 +1045,27 @@ int add_to_free_space_tree(struct btrfs_trans_handle *trans,
|
||||
path = btrfs_alloc_path();
|
||||
if (!path) {
|
||||
ret = -ENOMEM;
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
block_group = btrfs_lookup_block_group(trans->fs_info, start);
|
||||
if (!block_group) {
|
||||
ASSERT(0);
|
||||
DEBUG_WARN("no block group found for start=%llu", start);
|
||||
ret = -ENOENT;
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&block_group->free_space_lock);
|
||||
ret = __add_to_free_space_tree(trans, block_group, path, start, size);
|
||||
mutex_unlock(&block_group->free_space_lock);
|
||||
if (ret)
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
|
||||
btrfs_put_block_group(block_group);
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
if (ret)
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1555,7 +1571,7 @@ static int load_free_space_bitmaps(struct btrfs_caching_control *caching_ctl,
|
||||
"incorrect extent count for %llu; counted %u, expected %u",
|
||||
block_group->start, extent_count,
|
||||
expected_extent_count);
|
||||
ASSERT(0);
|
||||
DEBUG_WARN();
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
@@ -1619,7 +1635,7 @@ static int load_free_space_extents(struct btrfs_caching_control *caching_ctl,
|
||||
"incorrect extent count for %llu; counted %u, expected %u",
|
||||
block_group->start, extent_count,
|
||||
expected_extent_count);
|
||||
ASSERT(0);
|
||||
DEBUG_WARN();
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
+3
-3
@@ -472,6 +472,8 @@ struct btrfs_fs_info {
|
||||
struct btrfs_block_rsv delayed_block_rsv;
|
||||
/* Block reservation for delayed refs */
|
||||
struct btrfs_block_rsv delayed_refs_rsv;
|
||||
/* Block reservation for treelog tree */
|
||||
struct btrfs_block_rsv treelog_rsv;
|
||||
|
||||
struct btrfs_block_rsv empty_block_rsv;
|
||||
|
||||
@@ -777,10 +779,8 @@ struct btrfs_fs_info {
|
||||
|
||||
struct btrfs_delayed_root *delayed_root;
|
||||
|
||||
/* Extent buffer radix tree */
|
||||
spinlock_t buffer_lock;
|
||||
/* Entries are eb->start / sectorsize */
|
||||
struct radix_tree_root buffer_radix;
|
||||
struct xarray buffer_tree;
|
||||
|
||||
/* Next backup root to be overwritten */
|
||||
int backup_root_index;
|
||||
|
||||
+11
-20
@@ -109,7 +109,7 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
|
||||
u64 inode_objectid, u64 ref_objectid,
|
||||
u64 *index)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_key key;
|
||||
struct btrfs_inode_extref *extref;
|
||||
struct extent_buffer *leaf;
|
||||
@@ -129,9 +129,9 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
|
||||
|
||||
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
||||
if (ret > 0)
|
||||
ret = -ENOENT;
|
||||
return -ENOENT;
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Sanity check - did we find the right item for this name?
|
||||
@@ -142,8 +142,7 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
|
||||
ref_objectid, name);
|
||||
if (!extref) {
|
||||
btrfs_abort_transaction(trans, -ENOENT);
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
leaf = path->nodes[0];
|
||||
@@ -152,12 +151,8 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
|
||||
*index = btrfs_inode_extref_index(leaf, extref);
|
||||
|
||||
if (del_len == item_size) {
|
||||
/*
|
||||
* Common case only one ref in the item, remove the
|
||||
* whole item.
|
||||
*/
|
||||
ret = btrfs_del_item(trans, root, path);
|
||||
goto out;
|
||||
/* Common case only one ref in the item, remove the whole item. */
|
||||
return btrfs_del_item(trans, root, path);
|
||||
}
|
||||
|
||||
ptr = (unsigned long)extref;
|
||||
@@ -168,9 +163,6 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
|
||||
|
||||
btrfs_truncate_item(trans, path, item_size - del_len, 1);
|
||||
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -260,7 +252,7 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
|
||||
int ret;
|
||||
int ins_len = name->len + sizeof(*extref);
|
||||
unsigned long ptr;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_key key;
|
||||
struct extent_buffer *leaf;
|
||||
|
||||
@@ -279,13 +271,13 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
|
||||
path->slots[0],
|
||||
ref_objectid,
|
||||
name))
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
btrfs_extend_item(trans, path, ins_len);
|
||||
ret = 0;
|
||||
}
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
leaf = path->nodes[0];
|
||||
ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char);
|
||||
@@ -298,9 +290,8 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
|
||||
|
||||
ptr = (unsigned long)&extref->name;
|
||||
write_extent_buffer(path->nodes[0], name->name, ptr, name->len);
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
|
||||
|
||||
+379
-301
File diff suppressed because it is too large
Load Diff
+9
-9
@@ -1446,8 +1446,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static noinline int key_in_sk(const struct btrfs_key *key,
|
||||
const struct btrfs_ioctl_search_key *sk)
|
||||
static noinline bool key_in_sk(const struct btrfs_key *key,
|
||||
const struct btrfs_ioctl_search_key *sk)
|
||||
{
|
||||
struct btrfs_key test;
|
||||
int ret;
|
||||
@@ -1458,7 +1458,7 @@ static noinline int key_in_sk(const struct btrfs_key *key,
|
||||
|
||||
ret = btrfs_comp_cpu_keys(key, &test);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
test.objectid = sk->max_objectid;
|
||||
test.type = sk->max_type;
|
||||
@@ -1466,8 +1466,8 @@ static noinline int key_in_sk(const struct btrfs_key *key,
|
||||
|
||||
ret = btrfs_comp_cpu_keys(key, &test);
|
||||
if (ret > 0)
|
||||
return 0;
|
||||
return 1;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static noinline int copy_to_sk(struct btrfs_path *path,
|
||||
@@ -4507,7 +4507,7 @@ static int btrfs_ioctl_encoded_read(struct file *file, void __user *argp,
|
||||
args.compression, &unlocked);
|
||||
|
||||
if (!unlocked) {
|
||||
unlock_extent(io_tree, start, lockend, &cached_state);
|
||||
btrfs_unlock_extent(io_tree, start, lockend, &cached_state);
|
||||
btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
|
||||
}
|
||||
}
|
||||
@@ -4696,7 +4696,7 @@ static void btrfs_uring_read_finished(struct io_uring_cmd *cmd, unsigned int iss
|
||||
ret = priv->count;
|
||||
|
||||
out:
|
||||
unlock_extent(io_tree, priv->start, priv->lockend, &priv->cached_state);
|
||||
btrfs_unlock_extent(io_tree, priv->start, priv->lockend, &priv->cached_state);
|
||||
btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
|
||||
|
||||
io_uring_cmd_done(cmd, ret, 0, issue_flags);
|
||||
@@ -4785,7 +4785,7 @@ static int btrfs_uring_read_extent(struct kiocb *iocb, struct iov_iter *iter,
|
||||
return -EIOCBQUEUED;
|
||||
|
||||
out_fail:
|
||||
unlock_extent(io_tree, start, lockend, &cached_state);
|
||||
btrfs_unlock_extent(io_tree, start, lockend, &cached_state);
|
||||
btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
|
||||
kfree(priv);
|
||||
return ret;
|
||||
@@ -4910,7 +4910,7 @@ static int btrfs_uring_encoded_read(struct io_uring_cmd *cmd, unsigned int issue
|
||||
(const char *)&data->args + copy_end_kernel,
|
||||
sizeof(data->args) - copy_end_kernel)) {
|
||||
if (ret == -EIOCBQUEUED) {
|
||||
unlock_extent(io_tree, start, lockend, &cached_state);
|
||||
btrfs_unlock_extent(io_tree, start, lockend, &cached_state);
|
||||
btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
|
||||
}
|
||||
ret = -EFAULT;
|
||||
|
||||
+4
-4
@@ -149,15 +149,15 @@ void btrfs_tree_read_lock_nested(struct extent_buffer *eb, enum btrfs_lock_nesti
|
||||
/*
|
||||
* Try-lock for read.
|
||||
*
|
||||
* Return 1 if the rwlock has been taken, 0 otherwise
|
||||
* Return true if the rwlock has been taken, false otherwise
|
||||
*/
|
||||
int btrfs_try_tree_read_lock(struct extent_buffer *eb)
|
||||
bool btrfs_try_tree_read_lock(struct extent_buffer *eb)
|
||||
{
|
||||
if (down_read_trylock(&eb->lock)) {
|
||||
trace_btrfs_try_tree_read_lock(eb);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -189,7 +189,7 @@ static inline void btrfs_tree_read_lock(struct extent_buffer *eb)
|
||||
}
|
||||
|
||||
void btrfs_tree_read_unlock(struct extent_buffer *eb);
|
||||
int btrfs_try_tree_read_lock(struct extent_buffer *eb);
|
||||
bool btrfs_try_tree_read_lock(struct extent_buffer *eb);
|
||||
struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root);
|
||||
struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root);
|
||||
struct extent_buffer *btrfs_try_read_lock_root_node(struct btrfs_root *root);
|
||||
|
||||
+2
-3
@@ -252,9 +252,8 @@ int lzo_compress_folios(struct list_head *ws, struct address_space *mapping,
|
||||
/* Compress at most one sector of data each time */
|
||||
in_len = min_t(u32, start + len - cur_in, sectorsize - sector_off);
|
||||
ASSERT(in_len);
|
||||
data_in = kmap_local_folio(folio_in, 0);
|
||||
ret = lzo1x_1_compress(data_in +
|
||||
offset_in_page(cur_in), in_len,
|
||||
data_in = kmap_local_folio(folio_in, offset_in_folio(folio_in, cur_in));
|
||||
ret = lzo1x_1_compress(data_in, in_len,
|
||||
workspace->cbuf, &out_len,
|
||||
workspace->mem);
|
||||
kunmap_local(data_in);
|
||||
|
||||
+76
-7
@@ -3,6 +3,7 @@
|
||||
#ifndef BTRFS_MESSAGES_H
|
||||
#define BTRFS_MESSAGES_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/bug.h>
|
||||
@@ -170,15 +171,83 @@ do { \
|
||||
|
||||
#ifdef CONFIG_BTRFS_ASSERT
|
||||
|
||||
#define btrfs_assertfail(expr, file, line) ({ \
|
||||
pr_err("assertion failed: %s, in %s:%d\n", (expr), (file), (line)); \
|
||||
BUG(); \
|
||||
})
|
||||
__printf(1, 2)
|
||||
static inline void verify_assert_printk_format(const char *fmt, ...) {
|
||||
/* Stub to verify the assertion format string. */
|
||||
}
|
||||
|
||||
/* Take the first token if any. */
|
||||
#define __FIRST_ARG(_, ...) _
|
||||
/*
|
||||
* Skip the first token and return the rest, if it's empty the comma is dropped.
|
||||
* As ##__VA_ARGS__ cannot be at the beginning of the macro the __VA_OPT__ is needed
|
||||
* and supported since GCC 8 and Clang 12.
|
||||
*/
|
||||
#define __REST_ARGS(_, ... ) __VA_OPT__(,) __VA_ARGS__
|
||||
|
||||
#if defined(CONFIG_CC_IS_CLANG) || GCC_VERSION >= 80000
|
||||
/*
|
||||
* Assertion with optional printk() format.
|
||||
*
|
||||
* Accepted syntax:
|
||||
* ASSERT(condition);
|
||||
* ASSERT(condition, "string");
|
||||
* ASSERT(condition, "variable=%d", variable);
|
||||
*
|
||||
* How it works:
|
||||
* - if there's no format string, ""[0] evaluates at compile time to 0 and the
|
||||
* true branch is executed
|
||||
* - any non-empty format string with the "" prefix evaluates to != 0 at
|
||||
* compile time and the false branch is executed
|
||||
* - stringified condition is printed as %s so we don't accidentally mix format
|
||||
* strings (the % operator)
|
||||
* - there can be only one printk() call, so the format strings and arguments are
|
||||
* spliced together:
|
||||
* DEFAULT_FMT [USER_FMT], DEFAULT_ARGS [, USER_ARGS]
|
||||
* - comma between DEFAULT_ARGS and USER_ARGS is handled by preprocessor
|
||||
* (requires __VA_OPT__ support)
|
||||
* - otherwise we could use __VA_OPT(,) __VA_ARGS__ for the 2nd+ argument of args,
|
||||
*/
|
||||
#define ASSERT(cond, args...) \
|
||||
do { \
|
||||
verify_assert_printk_format("check the format string" args); \
|
||||
if (!likely(cond)) { \
|
||||
if (("" __FIRST_ARG(args) [0]) == 0) { \
|
||||
pr_err("assertion failed: %s :: %ld, in %s:%d\n", \
|
||||
#cond, (long)(cond), __FILE__, __LINE__); \
|
||||
} else { \
|
||||
pr_err("assertion failed: %s :: %ld, in %s:%d (" __FIRST_ARG(args) ")\n", \
|
||||
#cond, (long)(cond), __FILE__, __LINE__ __REST_ARGS(args)); \
|
||||
} \
|
||||
BUG(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define ASSERT(expr) \
|
||||
(likely(expr) ? (void)0 : btrfs_assertfail(#expr, __FILE__, __LINE__))
|
||||
#else
|
||||
#define ASSERT(expr) (void)(expr)
|
||||
|
||||
/* For GCC < 8.x only the simple output. */
|
||||
|
||||
#define ASSERT(cond, args...) \
|
||||
do { \
|
||||
verify_assert_printk_format("check the format string" args); \
|
||||
if (!likely(cond)) { \
|
||||
pr_err("assertion failed: %s :: %ld, in %s:%d\n", \
|
||||
#cond, (long)(cond), __FILE__, __LINE__); \
|
||||
BUG(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define ASSERT(cond, args...) (void)(cond)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BTRFS_DEBUG
|
||||
/* Verbose warning only under debug build. */
|
||||
#define DEBUG_WARN(args...) WARN(1, KERN_ERR args)
|
||||
#else
|
||||
#define DEBUG_WARN(...) do {} while(0)
|
||||
#endif
|
||||
|
||||
__printf(5, 6)
|
||||
|
||||
+42
-31
@@ -153,25 +153,30 @@ static struct btrfs_ordered_extent *alloc_ordered_extent(
|
||||
struct btrfs_ordered_extent *entry;
|
||||
int ret;
|
||||
u64 qgroup_rsv = 0;
|
||||
const bool is_nocow = (flags &
|
||||
((1U << BTRFS_ORDERED_NOCOW) | (1U << BTRFS_ORDERED_PREALLOC)));
|
||||
|
||||
if (flags &
|
||||
((1 << BTRFS_ORDERED_NOCOW) | (1 << BTRFS_ORDERED_PREALLOC))) {
|
||||
/* For nocow write, we can release the qgroup rsv right now */
|
||||
/*
|
||||
* For a NOCOW write we can free the qgroup reserve right now. For a COW
|
||||
* one we transfer the reserved space from the inode's iotree into the
|
||||
* ordered extent by calling btrfs_qgroup_release_data() and tracking
|
||||
* the qgroup reserved amount in the ordered extent, so that later after
|
||||
* completing the ordered extent, when running the data delayed ref it
|
||||
* creates, we free the reserved data with btrfs_qgroup_free_refroot().
|
||||
*/
|
||||
if (is_nocow)
|
||||
ret = btrfs_qgroup_free_data(inode, NULL, file_offset, num_bytes, &qgroup_rsv);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
} else {
|
||||
/*
|
||||
* The ordered extent has reserved qgroup space, release now
|
||||
* and pass the reserved number for qgroup_record to free.
|
||||
*/
|
||||
else
|
||||
ret = btrfs_qgroup_release_data(inode, file_offset, num_bytes, &qgroup_rsv);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
entry = kmem_cache_zalloc(btrfs_ordered_extent_cache, GFP_NOFS);
|
||||
if (!entry)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (!entry) {
|
||||
entry = ERR_PTR(-ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
entry->file_offset = file_offset;
|
||||
entry->num_bytes = num_bytes;
|
||||
@@ -180,7 +185,12 @@ static struct btrfs_ordered_extent *alloc_ordered_extent(
|
||||
entry->disk_num_bytes = disk_num_bytes;
|
||||
entry->offset = offset;
|
||||
entry->bytes_left = num_bytes;
|
||||
entry->inode = BTRFS_I(igrab(&inode->vfs_inode));
|
||||
if (WARN_ON_ONCE(!igrab(&inode->vfs_inode))) {
|
||||
kmem_cache_free(btrfs_ordered_extent_cache, entry);
|
||||
entry = ERR_PTR(-ESTALE);
|
||||
goto out;
|
||||
}
|
||||
entry->inode = inode;
|
||||
entry->compress_type = compress_type;
|
||||
entry->truncated_len = (u64)-1;
|
||||
entry->qgroup_rsv = qgroup_rsv;
|
||||
@@ -203,6 +213,12 @@ static struct btrfs_ordered_extent *alloc_ordered_extent(
|
||||
btrfs_mod_outstanding_extents(inode, 1);
|
||||
spin_unlock(&inode->lock);
|
||||
|
||||
out:
|
||||
if (IS_ERR(entry) && !is_nocow)
|
||||
btrfs_qgroup_free_refroot(inode->root->fs_info,
|
||||
btrfs_root_id(inode->root),
|
||||
qgroup_rsv, BTRFS_QGROUP_RSV_DATA);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -253,7 +269,7 @@ static void insert_ordered_extent(struct btrfs_ordered_extent *entry)
|
||||
* @disk_bytenr: Offset of extent on disk.
|
||||
* @disk_num_bytes: Size of extent on disk.
|
||||
* @offset: Offset into unencoded data where file data starts.
|
||||
* @flags: Flags specifying type of extent (1 << BTRFS_ORDERED_*).
|
||||
* @flags: Flags specifying type of extent (1U << BTRFS_ORDERED_*).
|
||||
* @compress_type: Compression algorithm used for data.
|
||||
*
|
||||
* Most of these parameters correspond to &struct btrfs_file_extent_item. The
|
||||
@@ -607,23 +623,18 @@ out:
|
||||
*/
|
||||
void btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
|
||||
{
|
||||
struct list_head *cur;
|
||||
struct btrfs_ordered_sum *sum;
|
||||
|
||||
trace_btrfs_ordered_extent_put(entry->inode, entry);
|
||||
|
||||
if (refcount_dec_and_test(&entry->refs)) {
|
||||
struct btrfs_ordered_sum *sum;
|
||||
struct btrfs_ordered_sum *tmp;
|
||||
|
||||
ASSERT(list_empty(&entry->root_extent_list));
|
||||
ASSERT(list_empty(&entry->log_list));
|
||||
ASSERT(RB_EMPTY_NODE(&entry->rb_node));
|
||||
if (entry->inode)
|
||||
btrfs_add_delayed_iput(entry->inode);
|
||||
while (!list_empty(&entry->list)) {
|
||||
cur = entry->list.next;
|
||||
sum = list_entry(cur, struct btrfs_ordered_sum, list);
|
||||
list_del(&sum->list);
|
||||
btrfs_add_delayed_iput(entry->inode);
|
||||
list_for_each_entry_safe(sum, tmp, &entry->list, list)
|
||||
kvfree(sum);
|
||||
}
|
||||
kmem_cache_free(btrfs_ordered_extent_cache, entry);
|
||||
}
|
||||
}
|
||||
@@ -1173,7 +1184,7 @@ void btrfs_lock_and_flush_ordered_range(struct btrfs_inode *inode, u64 start,
|
||||
cachedp = cached_state;
|
||||
|
||||
while (1) {
|
||||
lock_extent(&inode->io_tree, start, end, cachedp);
|
||||
btrfs_lock_extent(&inode->io_tree, start, end, cachedp);
|
||||
ordered = btrfs_lookup_ordered_range(inode, start,
|
||||
end - start + 1);
|
||||
if (!ordered) {
|
||||
@@ -1186,7 +1197,7 @@ void btrfs_lock_and_flush_ordered_range(struct btrfs_inode *inode, u64 start,
|
||||
refcount_dec(&cache->refs);
|
||||
break;
|
||||
}
|
||||
unlock_extent(&inode->io_tree, start, end, cachedp);
|
||||
btrfs_unlock_extent(&inode->io_tree, start, end, cachedp);
|
||||
btrfs_start_ordered_extent(ordered);
|
||||
btrfs_put_ordered_extent(ordered);
|
||||
}
|
||||
@@ -1204,7 +1215,7 @@ bool btrfs_try_lock_ordered_range(struct btrfs_inode *inode, u64 start, u64 end,
|
||||
{
|
||||
struct btrfs_ordered_extent *ordered;
|
||||
|
||||
if (!try_lock_extent(&inode->io_tree, start, end, cached_state))
|
||||
if (!btrfs_try_lock_extent(&inode->io_tree, start, end, cached_state))
|
||||
return false;
|
||||
|
||||
ordered = btrfs_lookup_ordered_range(inode, start, end - start + 1);
|
||||
@@ -1212,7 +1223,7 @@ bool btrfs_try_lock_ordered_range(struct btrfs_inode *inode, u64 start, u64 end,
|
||||
return true;
|
||||
|
||||
btrfs_put_ordered_extent(ordered);
|
||||
unlock_extent(&inode->io_tree, start, end, cached_state);
|
||||
btrfs_unlock_extent(&inode->io_tree, start, end, cached_state);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
+28
-27
@@ -83,7 +83,7 @@ static void qgroup_rsv_add(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_qgroup *qgroup, u64 num_bytes,
|
||||
enum btrfs_qgroup_rsv_type type)
|
||||
{
|
||||
trace_qgroup_update_reserve(fs_info, qgroup, num_bytes, type);
|
||||
trace_btrfs_qgroup_update_reserve(fs_info, qgroup, num_bytes, type);
|
||||
qgroup->rsv.values[type] += num_bytes;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ static void qgroup_rsv_release(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_qgroup *qgroup, u64 num_bytes,
|
||||
enum btrfs_qgroup_rsv_type type)
|
||||
{
|
||||
trace_qgroup_update_reserve(fs_info, qgroup, -(s64)num_bytes, type);
|
||||
trace_btrfs_qgroup_update_reserve(fs_info, qgroup, -(s64)num_bytes, type);
|
||||
if (qgroup->rsv.values[type] >= num_bytes) {
|
||||
qgroup->rsv.values[type] -= num_bytes;
|
||||
return;
|
||||
@@ -1823,7 +1823,7 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid)
|
||||
if (qgroup->rsv.values[BTRFS_QGROUP_RSV_DATA] ||
|
||||
qgroup->rsv.values[BTRFS_QGROUP_RSV_META_PREALLOC] ||
|
||||
qgroup->rsv.values[BTRFS_QGROUP_RSV_META_PERTRANS]) {
|
||||
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
|
||||
DEBUG_WARN();
|
||||
btrfs_warn_rl(fs_info,
|
||||
"to be deleted qgroup %u/%llu has non-zero numbers, data %llu meta prealloc %llu meta pertrans %llu",
|
||||
btrfs_qgroup_level(qgroup->qgroupid),
|
||||
@@ -1843,7 +1843,7 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid)
|
||||
!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT)) {
|
||||
if (qgroup->rfer || qgroup->excl ||
|
||||
qgroup->rfer_cmpr || qgroup->excl_cmpr) {
|
||||
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
|
||||
DEBUG_WARN();
|
||||
btrfs_warn_rl(fs_info,
|
||||
"to be deleted qgroup %u/%llu has non-zero numbers, rfer %llu rfer_cmpr %llu excl %llu excl_cmpr %llu",
|
||||
btrfs_qgroup_level(qgroup->qgroupid),
|
||||
@@ -2837,8 +2837,8 @@ static void qgroup_update_counters(struct btrfs_fs_info *fs_info,
|
||||
cur_old_count = btrfs_qgroup_get_old_refcnt(qg, seq);
|
||||
cur_new_count = btrfs_qgroup_get_new_refcnt(qg, seq);
|
||||
|
||||
trace_qgroup_update_counters(fs_info, qg, cur_old_count,
|
||||
cur_new_count);
|
||||
trace_btrfs_qgroup_update_counters(fs_info, qg, cur_old_count,
|
||||
cur_new_count);
|
||||
|
||||
/* Rfer update part */
|
||||
if (cur_old_count == 0 && cur_new_count > 0) {
|
||||
@@ -3100,8 +3100,7 @@ cleanup:
|
||||
kfree(record);
|
||||
|
||||
}
|
||||
trace_qgroup_num_dirty_extents(fs_info, trans->transid,
|
||||
num_dirty_extents);
|
||||
trace_btrfs_qgroup_num_dirty_extents(fs_info, trans->transid, num_dirty_extents);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -4129,8 +4128,8 @@ static int qgroup_unreserve_range(struct btrfs_inode *inode,
|
||||
* Now the entry is in [start, start + len), revert the
|
||||
* EXTENT_QGROUP_RESERVED bit.
|
||||
*/
|
||||
clear_ret = clear_extent_bits(&inode->io_tree, entry_start,
|
||||
entry_end, EXTENT_QGROUP_RESERVED);
|
||||
clear_ret = btrfs_clear_extent_bits(&inode->io_tree, entry_start,
|
||||
entry_end, EXTENT_QGROUP_RESERVED);
|
||||
if (!ret && clear_ret < 0)
|
||||
ret = clear_ret;
|
||||
|
||||
@@ -4232,8 +4231,9 @@ static int qgroup_reserve_data(struct btrfs_inode *inode,
|
||||
reserved = *reserved_ret;
|
||||
/* Record already reserved space */
|
||||
orig_reserved = reserved->bytes_changed;
|
||||
ret = set_record_extent_bits(&inode->io_tree, start,
|
||||
start + len -1, EXTENT_QGROUP_RESERVED, reserved);
|
||||
ret = btrfs_set_record_extent_bits(&inode->io_tree, start,
|
||||
start + len - 1, EXTENT_QGROUP_RESERVED,
|
||||
reserved);
|
||||
|
||||
/* Newly reserved space */
|
||||
to_reserve = reserved->bytes_changed - orig_reserved;
|
||||
@@ -4326,9 +4326,10 @@ static int qgroup_free_reserved_data(struct btrfs_inode *inode,
|
||||
* EXTENT_QGROUP_RESERVED, we won't double free.
|
||||
* So not need to rush.
|
||||
*/
|
||||
ret = clear_record_extent_bits(&inode->io_tree, free_start,
|
||||
free_start + free_len - 1,
|
||||
EXTENT_QGROUP_RESERVED, &changeset);
|
||||
ret = btrfs_clear_record_extent_bits(&inode->io_tree, free_start,
|
||||
free_start + free_len - 1,
|
||||
EXTENT_QGROUP_RESERVED,
|
||||
&changeset);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
freed += changeset.bytes_changed;
|
||||
@@ -4352,9 +4353,9 @@ static int __btrfs_qgroup_release_data(struct btrfs_inode *inode,
|
||||
int ret;
|
||||
|
||||
if (btrfs_qgroup_mode(inode->root->fs_info) == BTRFS_QGROUP_MODE_DISABLED) {
|
||||
return clear_record_extent_bits(&inode->io_tree, start,
|
||||
start + len - 1,
|
||||
EXTENT_QGROUP_RESERVED, NULL);
|
||||
return btrfs_clear_record_extent_bits(&inode->io_tree, start,
|
||||
start + len - 1,
|
||||
EXTENT_QGROUP_RESERVED, NULL);
|
||||
}
|
||||
|
||||
/* In release case, we shouldn't have @reserved */
|
||||
@@ -4362,8 +4363,8 @@ static int __btrfs_qgroup_release_data(struct btrfs_inode *inode,
|
||||
if (free && reserved)
|
||||
return qgroup_free_reserved_data(inode, reserved, start, len, released);
|
||||
extent_changeset_init(&changeset);
|
||||
ret = clear_record_extent_bits(&inode->io_tree, start, start + len -1,
|
||||
EXTENT_QGROUP_RESERVED, &changeset);
|
||||
ret = btrfs_clear_record_extent_bits(&inode->io_tree, start, start + len - 1,
|
||||
EXTENT_QGROUP_RESERVED, &changeset);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -4472,7 +4473,7 @@ int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
|
||||
return 0;
|
||||
|
||||
BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize));
|
||||
trace_qgroup_meta_reserve(root, (s64)num_bytes, type);
|
||||
trace_btrfs_qgroup_meta_reserve(root, (s64)num_bytes, type);
|
||||
ret = qgroup_reserve(root, num_bytes, enforce, type);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -4517,7 +4518,7 @@ void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root)
|
||||
return;
|
||||
|
||||
/* TODO: Update trace point to handle such free */
|
||||
trace_qgroup_meta_free_all_pertrans(root);
|
||||
trace_btrfs_qgroup_meta_free_all_pertrans(root);
|
||||
/* Special value -1 means to free all reserved space */
|
||||
btrfs_qgroup_free_refroot(fs_info, btrfs_root_id(root), (u64)-1,
|
||||
BTRFS_QGROUP_RSV_META_PERTRANS);
|
||||
@@ -4539,7 +4540,7 @@ void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
|
||||
*/
|
||||
num_bytes = sub_root_meta_rsv(root, num_bytes, type);
|
||||
BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize));
|
||||
trace_qgroup_meta_reserve(root, -(s64)num_bytes, type);
|
||||
trace_btrfs_qgroup_meta_reserve(root, -(s64)num_bytes, type);
|
||||
btrfs_qgroup_free_refroot(fs_info, btrfs_root_id(root), num_bytes, type);
|
||||
}
|
||||
|
||||
@@ -4593,7 +4594,7 @@ void btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes)
|
||||
/* Same as btrfs_qgroup_free_meta_prealloc() */
|
||||
num_bytes = sub_root_meta_rsv(root, num_bytes,
|
||||
BTRFS_QGROUP_RSV_META_PREALLOC);
|
||||
trace_qgroup_meta_convert(root, num_bytes);
|
||||
trace_btrfs_qgroup_meta_convert(root, num_bytes);
|
||||
qgroup_convert_meta(fs_info, btrfs_root_id(root), num_bytes);
|
||||
if (!sb_rdonly(fs_info->sb))
|
||||
add_root_meta_rsv(root, num_bytes, BTRFS_QGROUP_RSV_META_PERTRANS);
|
||||
@@ -4611,8 +4612,8 @@ void btrfs_qgroup_check_reserved_leak(struct btrfs_inode *inode)
|
||||
int ret;
|
||||
|
||||
extent_changeset_init(&changeset);
|
||||
ret = clear_record_extent_bits(&inode->io_tree, 0, (u64)-1,
|
||||
EXTENT_QGROUP_RESERVED, &changeset);
|
||||
ret = btrfs_clear_record_extent_bits(&inode->io_tree, 0, (u64)-1,
|
||||
EXTENT_QGROUP_RESERVED, &changeset);
|
||||
|
||||
WARN_ON(ret < 0);
|
||||
if (WARN_ON(changeset.bytes_changed)) {
|
||||
@@ -4766,7 +4767,7 @@ int btrfs_qgroup_add_swapped_blocks(struct btrfs_root *subvol_root,
|
||||
* Marking qgroup inconsistent should be enough
|
||||
* for end users.
|
||||
*/
|
||||
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
|
||||
DEBUG_WARN("duplicated but mismatched entry found");
|
||||
ret = -EEXIST;
|
||||
}
|
||||
kfree(block);
|
||||
|
||||
+115
-104
@@ -134,14 +134,17 @@ struct btrfs_stripe_hash_table {
|
||||
};
|
||||
|
||||
/*
|
||||
* A bvec like structure to present a sector inside a page.
|
||||
*
|
||||
* Unlike bvec we don't need bvlen, as it's fixed to sectorsize.
|
||||
* A structure to present a sector inside a page, the length is fixed to
|
||||
* sectorsize;
|
||||
*/
|
||||
struct sector_ptr {
|
||||
struct page *page;
|
||||
unsigned int pgoff:24;
|
||||
unsigned int uptodate:8;
|
||||
/*
|
||||
* Blocks from the bio list can still be highmem.
|
||||
* So here we use physical address to present a page and the offset inside it.
|
||||
*/
|
||||
phys_addr_t paddr;
|
||||
bool has_paddr;
|
||||
bool uptodate;
|
||||
};
|
||||
|
||||
static void rmw_rbio_work(struct work_struct *work);
|
||||
@@ -200,8 +203,7 @@ int btrfs_alloc_stripe_hash_table(struct btrfs_fs_info *info)
|
||||
struct btrfs_stripe_hash_table *x;
|
||||
struct btrfs_stripe_hash *cur;
|
||||
struct btrfs_stripe_hash *h;
|
||||
int num_entries = 1 << BTRFS_STRIPE_HASH_TABLE_BITS;
|
||||
int i;
|
||||
unsigned int num_entries = 1U << BTRFS_STRIPE_HASH_TABLE_BITS;
|
||||
|
||||
if (info->stripe_hash_table)
|
||||
return 0;
|
||||
@@ -222,7 +224,7 @@ int btrfs_alloc_stripe_hash_table(struct btrfs_fs_info *info)
|
||||
|
||||
h = table->table;
|
||||
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
for (unsigned int i = 0; i < num_entries; i++) {
|
||||
cur = h + i;
|
||||
INIT_LIST_HEAD(&cur->hash_list);
|
||||
spin_lock_init(&cur->lock);
|
||||
@@ -233,6 +235,14 @@ int btrfs_alloc_stripe_hash_table(struct btrfs_fs_info *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void memcpy_sectors(const struct sector_ptr *dst,
|
||||
const struct sector_ptr *src, u32 blocksize)
|
||||
{
|
||||
memcpy_page(phys_to_page(dst->paddr), offset_in_page(dst->paddr),
|
||||
phys_to_page(src->paddr), offset_in_page(src->paddr),
|
||||
blocksize);
|
||||
}
|
||||
|
||||
/*
|
||||
* caching an rbio means to copy anything from the
|
||||
* bio_sectors array into the stripe_pages array. We
|
||||
@@ -253,7 +263,7 @@ static void cache_rbio_pages(struct btrfs_raid_bio *rbio)
|
||||
|
||||
for (i = 0; i < rbio->nr_sectors; i++) {
|
||||
/* Some range not covered by bio (partial write), skip it */
|
||||
if (!rbio->bio_sectors[i].page) {
|
||||
if (!rbio->bio_sectors[i].has_paddr) {
|
||||
/*
|
||||
* Even if the sector is not covered by bio, if it is
|
||||
* a data sector it should still be uptodate as it is
|
||||
@@ -264,12 +274,8 @@ static void cache_rbio_pages(struct btrfs_raid_bio *rbio)
|
||||
continue;
|
||||
}
|
||||
|
||||
ASSERT(rbio->stripe_sectors[i].page);
|
||||
memcpy_page(rbio->stripe_sectors[i].page,
|
||||
rbio->stripe_sectors[i].pgoff,
|
||||
rbio->bio_sectors[i].page,
|
||||
rbio->bio_sectors[i].pgoff,
|
||||
rbio->bioc->fs_info->sectorsize);
|
||||
memcpy_sectors(&rbio->stripe_sectors[i], &rbio->bio_sectors[i],
|
||||
rbio->bioc->fs_info->sectorsize);
|
||||
rbio->stripe_sectors[i].uptodate = 1;
|
||||
}
|
||||
set_bit(RBIO_CACHE_READY_BIT, &rbio->flags);
|
||||
@@ -326,8 +332,13 @@ static void index_stripe_sectors(struct btrfs_raid_bio *rbio)
|
||||
int page_index = offset >> PAGE_SHIFT;
|
||||
|
||||
ASSERT(page_index < rbio->nr_pages);
|
||||
rbio->stripe_sectors[i].page = rbio->stripe_pages[page_index];
|
||||
rbio->stripe_sectors[i].pgoff = offset_in_page(offset);
|
||||
if (!rbio->stripe_pages[page_index])
|
||||
continue;
|
||||
|
||||
rbio->stripe_sectors[i].has_paddr = true;
|
||||
rbio->stripe_sectors[i].paddr =
|
||||
page_to_phys(rbio->stripe_pages[page_index]) +
|
||||
offset_in_page(offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,9 +518,8 @@ static void btrfs_clear_rbio_cache(struct btrfs_fs_info *info)
|
||||
|
||||
spin_lock(&table->cache_lock);
|
||||
while (!list_empty(&table->stripe_cache)) {
|
||||
rbio = list_entry(table->stripe_cache.next,
|
||||
struct btrfs_raid_bio,
|
||||
stripe_cache);
|
||||
rbio = list_first_entry(&table->stripe_cache,
|
||||
struct btrfs_raid_bio, stripe_cache);
|
||||
__remove_rbio_from_cache(rbio);
|
||||
}
|
||||
spin_unlock(&table->cache_lock);
|
||||
@@ -567,9 +577,9 @@ static void cache_rbio(struct btrfs_raid_bio *rbio)
|
||||
if (table->cache_size > RBIO_CACHE_SIZE) {
|
||||
struct btrfs_raid_bio *found;
|
||||
|
||||
found = list_entry(table->stripe_cache.prev,
|
||||
struct btrfs_raid_bio,
|
||||
stripe_cache);
|
||||
found = list_last_entry(&table->stripe_cache,
|
||||
struct btrfs_raid_bio,
|
||||
stripe_cache);
|
||||
|
||||
if (found != rbio)
|
||||
__remove_rbio_from_cache(found);
|
||||
@@ -882,14 +892,14 @@ done_nolock:
|
||||
remove_rbio_from_cache(rbio);
|
||||
}
|
||||
|
||||
static void rbio_endio_bio_list(struct bio *cur, blk_status_t err)
|
||||
static void rbio_endio_bio_list(struct bio *cur, blk_status_t status)
|
||||
{
|
||||
struct bio *next;
|
||||
|
||||
while (cur) {
|
||||
next = cur->bi_next;
|
||||
cur->bi_next = NULL;
|
||||
cur->bi_status = err;
|
||||
cur->bi_status = status;
|
||||
bio_endio(cur);
|
||||
cur = next;
|
||||
}
|
||||
@@ -899,7 +909,7 @@ static void rbio_endio_bio_list(struct bio *cur, blk_status_t err)
|
||||
* this frees the rbio and runs through all the bios in the
|
||||
* bio_list and calls end_io on them
|
||||
*/
|
||||
static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, blk_status_t err)
|
||||
static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, blk_status_t status)
|
||||
{
|
||||
struct bio *cur = bio_list_get(&rbio->bio_list);
|
||||
struct bio *extra;
|
||||
@@ -928,9 +938,9 @@ static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, blk_status_t err)
|
||||
extra = bio_list_get(&rbio->bio_list);
|
||||
free_raid_bio(rbio);
|
||||
|
||||
rbio_endio_bio_list(cur, err);
|
||||
rbio_endio_bio_list(cur, status);
|
||||
if (extra)
|
||||
rbio_endio_bio_list(extra, err);
|
||||
rbio_endio_bio_list(extra, status);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -962,9 +972,9 @@ static struct sector_ptr *sector_in_rbio(struct btrfs_raid_bio *rbio,
|
||||
|
||||
spin_lock(&rbio->bio_list_lock);
|
||||
sector = &rbio->bio_sectors[index];
|
||||
if (sector->page || bio_list_only) {
|
||||
if (sector->has_paddr || bio_list_only) {
|
||||
/* Don't return sector without a valid page pointer */
|
||||
if (!sector->page)
|
||||
if (!sector->has_paddr)
|
||||
sector = NULL;
|
||||
spin_unlock(&rbio->bio_list_lock);
|
||||
return sector;
|
||||
@@ -1142,7 +1152,7 @@ static int rbio_add_io_sector(struct btrfs_raid_bio *rbio,
|
||||
rbio, stripe_nr);
|
||||
ASSERT_RBIO_SECTOR(sector_nr >= 0 && sector_nr < rbio->stripe_nsectors,
|
||||
rbio, sector_nr);
|
||||
ASSERT(sector->page);
|
||||
ASSERT(sector->has_paddr);
|
||||
|
||||
stripe = &rbio->bioc->stripes[stripe_nr];
|
||||
disk_start = stripe->physical + sector_nr * sectorsize;
|
||||
@@ -1173,8 +1183,8 @@ static int rbio_add_io_sector(struct btrfs_raid_bio *rbio,
|
||||
*/
|
||||
if (last_end == disk_start && !last->bi_status &&
|
||||
last->bi_bdev == stripe->dev->bdev) {
|
||||
ret = bio_add_page(last, sector->page, sectorsize,
|
||||
sector->pgoff);
|
||||
ret = bio_add_page(last, phys_to_page(sector->paddr),
|
||||
sectorsize, offset_in_page(sector->paddr));
|
||||
if (ret == sectorsize)
|
||||
return 0;
|
||||
}
|
||||
@@ -1187,7 +1197,8 @@ static int rbio_add_io_sector(struct btrfs_raid_bio *rbio,
|
||||
bio->bi_iter.bi_sector = disk_start >> SECTOR_SHIFT;
|
||||
bio->bi_private = rbio;
|
||||
|
||||
__bio_add_page(bio, sector->page, sectorsize, sector->pgoff);
|
||||
__bio_add_page(bio, phys_to_page(sector->paddr), sectorsize,
|
||||
offset_in_page(sector->paddr));
|
||||
bio_list_add(bio_list, bio);
|
||||
return 0;
|
||||
}
|
||||
@@ -1195,23 +1206,20 @@ static int rbio_add_io_sector(struct btrfs_raid_bio *rbio,
|
||||
static void index_one_bio(struct btrfs_raid_bio *rbio, struct bio *bio)
|
||||
{
|
||||
const u32 sectorsize = rbio->bioc->fs_info->sectorsize;
|
||||
struct bio_vec bvec;
|
||||
struct bvec_iter iter;
|
||||
const u32 sectorsize_bits = rbio->bioc->fs_info->sectorsize_bits;
|
||||
struct bvec_iter iter = bio->bi_iter;
|
||||
u32 offset = (bio->bi_iter.bi_sector << SECTOR_SHIFT) -
|
||||
rbio->bioc->full_stripe_logical;
|
||||
|
||||
bio_for_each_segment(bvec, bio, iter) {
|
||||
u32 bvec_offset;
|
||||
while (iter.bi_size) {
|
||||
unsigned int index = (offset >> sectorsize_bits);
|
||||
struct sector_ptr *sector = &rbio->bio_sectors[index];
|
||||
struct bio_vec bv = bio_iter_iovec(bio, iter);
|
||||
|
||||
for (bvec_offset = 0; bvec_offset < bvec.bv_len;
|
||||
bvec_offset += sectorsize, offset += sectorsize) {
|
||||
int index = offset / sectorsize;
|
||||
struct sector_ptr *sector = &rbio->bio_sectors[index];
|
||||
|
||||
sector->page = bvec.bv_page;
|
||||
sector->pgoff = bvec.bv_offset + bvec_offset;
|
||||
ASSERT(sector->pgoff < PAGE_SIZE);
|
||||
}
|
||||
sector->has_paddr = true;
|
||||
sector->paddr = bvec_phys(&bv);
|
||||
bio_advance_iter_single(bio, &iter, sectorsize);
|
||||
offset += sectorsize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1289,6 +1297,15 @@ static void assert_rbio(struct btrfs_raid_bio *rbio)
|
||||
ASSERT_RBIO(rbio->nr_data < rbio->real_stripes, rbio);
|
||||
}
|
||||
|
||||
static inline void *kmap_local_sector(const struct sector_ptr *sector)
|
||||
{
|
||||
/* The sector pointer must have a page mapped to it. */
|
||||
ASSERT(sector->has_paddr);
|
||||
|
||||
return kmap_local_page(phys_to_page(sector->paddr)) +
|
||||
offset_in_page(sector->paddr);
|
||||
}
|
||||
|
||||
/* Generate PQ for one vertical stripe. */
|
||||
static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr)
|
||||
{
|
||||
@@ -1301,14 +1318,13 @@ static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr)
|
||||
/* First collect one sector from each data stripe */
|
||||
for (stripe = 0; stripe < rbio->nr_data; stripe++) {
|
||||
sector = sector_in_rbio(rbio, stripe, sectornr, 0);
|
||||
pointers[stripe] = kmap_local_page(sector->page) +
|
||||
sector->pgoff;
|
||||
pointers[stripe] = kmap_local_sector(sector);
|
||||
}
|
||||
|
||||
/* Then add the parity stripe */
|
||||
sector = rbio_pstripe_sector(rbio, sectornr);
|
||||
sector->uptodate = 1;
|
||||
pointers[stripe++] = kmap_local_page(sector->page) + sector->pgoff;
|
||||
pointers[stripe++] = kmap_local_sector(sector);
|
||||
|
||||
if (has_qstripe) {
|
||||
/*
|
||||
@@ -1317,8 +1333,7 @@ static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr)
|
||||
*/
|
||||
sector = rbio_qstripe_sector(rbio, sectornr);
|
||||
sector->uptodate = 1;
|
||||
pointers[stripe++] = kmap_local_page(sector->page) +
|
||||
sector->pgoff;
|
||||
pointers[stripe++] = kmap_local_sector(sector);
|
||||
|
||||
assert_rbio(rbio);
|
||||
raid6_call.gen_syndrome(rbio->real_stripes, sectorsize,
|
||||
@@ -1477,15 +1492,14 @@ static void set_rbio_range_error(struct btrfs_raid_bio *rbio, struct bio *bio)
|
||||
* stripe_pages[], thus we need to locate the sector.
|
||||
*/
|
||||
static struct sector_ptr *find_stripe_sector(struct btrfs_raid_bio *rbio,
|
||||
struct page *page,
|
||||
unsigned int pgoff)
|
||||
phys_addr_t paddr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rbio->nr_sectors; i++) {
|
||||
struct sector_ptr *sector = &rbio->stripe_sectors[i];
|
||||
|
||||
if (sector->page == page && sector->pgoff == pgoff)
|
||||
if (sector->has_paddr && sector->paddr == paddr)
|
||||
return sector;
|
||||
}
|
||||
return NULL;
|
||||
@@ -1505,11 +1519,10 @@ static void set_bio_pages_uptodate(struct btrfs_raid_bio *rbio, struct bio *bio)
|
||||
|
||||
bio_for_each_segment_all(bvec, bio, iter_all) {
|
||||
struct sector_ptr *sector;
|
||||
int pgoff;
|
||||
phys_addr_t paddr = bvec_phys(bvec);
|
||||
|
||||
for (pgoff = bvec->bv_offset; pgoff - bvec->bv_offset < bvec->bv_len;
|
||||
pgoff += sectorsize) {
|
||||
sector = find_stripe_sector(rbio, bvec->bv_page, pgoff);
|
||||
for (u32 off = 0; off < bvec->bv_len; off += sectorsize) {
|
||||
sector = find_stripe_sector(rbio, paddr + off);
|
||||
ASSERT(sector);
|
||||
if (sector)
|
||||
sector->uptodate = 1;
|
||||
@@ -1519,17 +1532,14 @@ static void set_bio_pages_uptodate(struct btrfs_raid_bio *rbio, struct bio *bio)
|
||||
|
||||
static int get_bio_sector_nr(struct btrfs_raid_bio *rbio, struct bio *bio)
|
||||
{
|
||||
struct bio_vec *bv = bio_first_bvec_all(bio);
|
||||
phys_addr_t bvec_paddr = bvec_phys(bio_first_bvec_all(bio));
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rbio->nr_sectors; i++) {
|
||||
struct sector_ptr *sector;
|
||||
|
||||
sector = &rbio->stripe_sectors[i];
|
||||
if (sector->page == bv->bv_page && sector->pgoff == bv->bv_offset)
|
||||
if (rbio->stripe_sectors[i].paddr == bvec_paddr)
|
||||
break;
|
||||
sector = &rbio->bio_sectors[i];
|
||||
if (sector->page == bv->bv_page && sector->pgoff == bv->bv_offset)
|
||||
if (rbio->bio_sectors[i].has_paddr &&
|
||||
rbio->bio_sectors[i].paddr == bvec_paddr)
|
||||
break;
|
||||
}
|
||||
ASSERT(i < rbio->nr_sectors);
|
||||
@@ -1575,11 +1585,11 @@ static void verify_bio_data_sectors(struct btrfs_raid_bio *rbio,
|
||||
return;
|
||||
|
||||
bio_for_each_segment_all(bvec, bio, iter_all) {
|
||||
int bv_offset;
|
||||
void *kaddr;
|
||||
|
||||
for (bv_offset = bvec->bv_offset;
|
||||
bv_offset < bvec->bv_offset + bvec->bv_len;
|
||||
bv_offset += fs_info->sectorsize, total_sector_nr++) {
|
||||
kaddr = bvec_kmap_local(bvec);
|
||||
for (u32 off = 0; off < bvec->bv_len;
|
||||
off += fs_info->sectorsize, total_sector_nr++) {
|
||||
u8 csum_buf[BTRFS_CSUM_SIZE];
|
||||
u8 *expected_csum = rbio->csum_buf +
|
||||
total_sector_nr * fs_info->csum_size;
|
||||
@@ -1589,11 +1599,12 @@ static void verify_bio_data_sectors(struct btrfs_raid_bio *rbio,
|
||||
if (!test_bit(total_sector_nr, rbio->csum_bitmap))
|
||||
continue;
|
||||
|
||||
ret = btrfs_check_sector_csum(fs_info, bvec->bv_page,
|
||||
bv_offset, csum_buf, expected_csum);
|
||||
ret = btrfs_check_sector_csum(fs_info, kaddr + off,
|
||||
csum_buf, expected_csum);
|
||||
if (ret < 0)
|
||||
set_bit(total_sector_nr, rbio->error_bitmap);
|
||||
}
|
||||
kunmap_local(kaddr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1689,8 +1700,8 @@ static void raid_unplug(struct blk_plug_cb *cb, bool from_schedule)
|
||||
list_sort(NULL, &plug->rbio_list, plug_cmp);
|
||||
|
||||
while (!list_empty(&plug->rbio_list)) {
|
||||
cur = list_entry(plug->rbio_list.next,
|
||||
struct btrfs_raid_bio, plug_list);
|
||||
cur = list_first_entry(&plug->rbio_list,
|
||||
struct btrfs_raid_bio, plug_list);
|
||||
list_del_init(&cur->plug_list);
|
||||
|
||||
if (rbio_is_full(cur)) {
|
||||
@@ -1791,6 +1802,7 @@ static int verify_one_sector(struct btrfs_raid_bio *rbio,
|
||||
struct sector_ptr *sector;
|
||||
u8 csum_buf[BTRFS_CSUM_SIZE];
|
||||
u8 *csum_expected;
|
||||
void *kaddr;
|
||||
int ret;
|
||||
|
||||
if (!rbio->csum_bitmap || !rbio->csum_buf)
|
||||
@@ -1809,13 +1821,12 @@ static int verify_one_sector(struct btrfs_raid_bio *rbio,
|
||||
sector = rbio_stripe_sector(rbio, stripe_nr, sector_nr);
|
||||
}
|
||||
|
||||
ASSERT(sector->page);
|
||||
|
||||
csum_expected = rbio->csum_buf +
|
||||
(stripe_nr * rbio->stripe_nsectors + sector_nr) *
|
||||
fs_info->csum_size;
|
||||
ret = btrfs_check_sector_csum(fs_info, sector->page, sector->pgoff,
|
||||
csum_buf, csum_expected);
|
||||
kaddr = kmap_local_sector(sector);
|
||||
ret = btrfs_check_sector_csum(fs_info, kaddr, csum_buf, csum_expected);
|
||||
kunmap_local(kaddr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1872,9 +1883,7 @@ static int recover_vertical(struct btrfs_raid_bio *rbio, int sector_nr,
|
||||
} else {
|
||||
sector = rbio_stripe_sector(rbio, stripe_nr, sector_nr);
|
||||
}
|
||||
ASSERT(sector->page);
|
||||
pointers[stripe_nr] = kmap_local_page(sector->page) +
|
||||
sector->pgoff;
|
||||
pointers[stripe_nr] = kmap_local_sector(sector);
|
||||
unmap_array[stripe_nr] = pointers[stripe_nr];
|
||||
}
|
||||
|
||||
@@ -2282,9 +2291,8 @@ static int rmw_read_wait_recover(struct btrfs_raid_bio *rbio)
|
||||
static void raid_wait_write_end_io(struct bio *bio)
|
||||
{
|
||||
struct btrfs_raid_bio *rbio = bio->bi_private;
|
||||
blk_status_t err = bio->bi_status;
|
||||
|
||||
if (err)
|
||||
if (bio->bi_status)
|
||||
rbio_update_error_bitmap(rbio, bio);
|
||||
bio_put(bio);
|
||||
if (atomic_dec_and_test(&rbio->stripes_pending))
|
||||
@@ -2326,7 +2334,7 @@ static bool need_read_stripe_sectors(struct btrfs_raid_bio *rbio)
|
||||
* thus this rbio can not be cached one, as cached one must
|
||||
* have all its data sectors present and uptodate.
|
||||
*/
|
||||
if (!sector->page || !sector->uptodate)
|
||||
if (!sector->has_paddr || !sector->uptodate)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -2516,6 +2524,7 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
|
||||
int stripe;
|
||||
int sectornr;
|
||||
bool has_qstripe;
|
||||
struct page *page;
|
||||
struct sector_ptr p_sector = { 0 };
|
||||
struct sector_ptr q_sector = { 0 };
|
||||
struct bio_list bio_list;
|
||||
@@ -2547,29 +2556,33 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
|
||||
*/
|
||||
clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags);
|
||||
|
||||
p_sector.page = alloc_page(GFP_NOFS);
|
||||
if (!p_sector.page)
|
||||
page = alloc_page(GFP_NOFS);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
p_sector.pgoff = 0;
|
||||
p_sector.has_paddr = true;
|
||||
p_sector.paddr = page_to_phys(page);
|
||||
p_sector.uptodate = 1;
|
||||
page = NULL;
|
||||
|
||||
if (has_qstripe) {
|
||||
/* RAID6, allocate and map temp space for the Q stripe */
|
||||
q_sector.page = alloc_page(GFP_NOFS);
|
||||
if (!q_sector.page) {
|
||||
__free_page(p_sector.page);
|
||||
p_sector.page = NULL;
|
||||
page = alloc_page(GFP_NOFS);
|
||||
if (!page) {
|
||||
__free_page(phys_to_page(p_sector.paddr));
|
||||
p_sector.has_paddr = false;
|
||||
return -ENOMEM;
|
||||
}
|
||||
q_sector.pgoff = 0;
|
||||
q_sector.has_paddr = true;
|
||||
q_sector.paddr = page_to_phys(page);
|
||||
q_sector.uptodate = 1;
|
||||
pointers[rbio->real_stripes - 1] = kmap_local_page(q_sector.page);
|
||||
page = NULL;
|
||||
pointers[rbio->real_stripes - 1] = kmap_local_sector(&q_sector);
|
||||
}
|
||||
|
||||
bitmap_clear(rbio->error_bitmap, 0, rbio->nr_sectors);
|
||||
|
||||
/* Map the parity stripe just once */
|
||||
pointers[nr_data] = kmap_local_page(p_sector.page);
|
||||
pointers[nr_data] = kmap_local_sector(&p_sector);
|
||||
|
||||
for_each_set_bit(sectornr, &rbio->dbitmap, rbio->stripe_nsectors) {
|
||||
struct sector_ptr *sector;
|
||||
@@ -2578,8 +2591,7 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
|
||||
/* first collect one page from each data stripe */
|
||||
for (stripe = 0; stripe < nr_data; stripe++) {
|
||||
sector = sector_in_rbio(rbio, stripe, sectornr, 0);
|
||||
pointers[stripe] = kmap_local_page(sector->page) +
|
||||
sector->pgoff;
|
||||
pointers[stripe] = kmap_local_sector(sector);
|
||||
}
|
||||
|
||||
if (has_qstripe) {
|
||||
@@ -2595,7 +2607,7 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
|
||||
|
||||
/* Check scrubbing parity and repair it */
|
||||
sector = rbio_stripe_sector(rbio, rbio->scrubp, sectornr);
|
||||
parity = kmap_local_page(sector->page) + sector->pgoff;
|
||||
parity = kmap_local_sector(sector);
|
||||
if (memcmp(parity, pointers[rbio->scrubp], sectorsize) != 0)
|
||||
memcpy(parity, pointers[rbio->scrubp], sectorsize);
|
||||
else
|
||||
@@ -2608,12 +2620,11 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
|
||||
}
|
||||
|
||||
kunmap_local(pointers[nr_data]);
|
||||
__free_page(p_sector.page);
|
||||
p_sector.page = NULL;
|
||||
if (q_sector.page) {
|
||||
kunmap_local(pointers[rbio->real_stripes - 1]);
|
||||
__free_page(q_sector.page);
|
||||
q_sector.page = NULL;
|
||||
__free_page(phys_to_page(p_sector.paddr));
|
||||
p_sector.has_paddr = false;
|
||||
if (q_sector.has_paddr) {
|
||||
__free_page(phys_to_page(q_sector.paddr));
|
||||
q_sector.has_paddr = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+7
-8
@@ -87,7 +87,7 @@ static int copy_inline_to_page(struct btrfs_inode *inode,
|
||||
FGP_LOCK | FGP_ACCESSED | FGP_CREAT,
|
||||
btrfs_alloc_write_mask(mapping));
|
||||
if (IS_ERR(folio)) {
|
||||
ret = -ENOMEM;
|
||||
ret = PTR_ERR(folio);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
@@ -95,9 +95,8 @@ static int copy_inline_to_page(struct btrfs_inode *inode,
|
||||
if (ret < 0)
|
||||
goto out_unlock;
|
||||
|
||||
clear_extent_bit(&inode->io_tree, file_offset, range_end,
|
||||
EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
|
||||
NULL);
|
||||
btrfs_clear_extent_bits(&inode->io_tree, file_offset, range_end,
|
||||
EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG);
|
||||
ret = btrfs_set_extent_delalloc(inode, file_offset, range_end, 0, NULL);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
@@ -646,10 +645,10 @@ static int btrfs_extent_same_range(struct btrfs_inode *src, u64 loff, u64 len,
|
||||
* because we have already locked the inode's i_mmap_lock in exclusive
|
||||
* mode.
|
||||
*/
|
||||
lock_extent(&dst->io_tree, dst_loff, end, &cached_state);
|
||||
btrfs_lock_extent(&dst->io_tree, dst_loff, end, &cached_state);
|
||||
ret = btrfs_clone(&src->vfs_inode, &dst->vfs_inode, loff, len,
|
||||
ALIGN(len, bs), dst_loff, 1);
|
||||
unlock_extent(&dst->io_tree, dst_loff, end, &cached_state);
|
||||
btrfs_unlock_extent(&dst->io_tree, dst_loff, end, &cached_state);
|
||||
|
||||
btrfs_btree_balance_dirty(fs_info);
|
||||
|
||||
@@ -749,9 +748,9 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
|
||||
* mode.
|
||||
*/
|
||||
end = destoff + len - 1;
|
||||
lock_extent(&BTRFS_I(inode)->io_tree, destoff, end, &cached_state);
|
||||
btrfs_lock_extent(&BTRFS_I(inode)->io_tree, destoff, end, &cached_state);
|
||||
ret = btrfs_clone(src, inode, off, olen, len, destoff, 0);
|
||||
unlock_extent(&BTRFS_I(inode)->io_tree, destoff, end, &cached_state);
|
||||
btrfs_unlock_extent(&BTRFS_I(inode)->io_tree, destoff, end, &cached_state);
|
||||
|
||||
/*
|
||||
* We may have copied an inline extent into a page of the destination
|
||||
|
||||
+54
-58
@@ -178,8 +178,9 @@ static void mark_block_processed(struct reloc_control *rc,
|
||||
in_range(node->bytenr, rc->block_group->start,
|
||||
rc->block_group->length)) {
|
||||
blocksize = rc->extent_root->fs_info->nodesize;
|
||||
set_extent_bit(&rc->processed_blocks, node->bytenr,
|
||||
node->bytenr + blocksize - 1, EXTENT_DIRTY, NULL);
|
||||
btrfs_set_extent_bit(&rc->processed_blocks, node->bytenr,
|
||||
node->bytenr + blocksize - 1, EXTENT_DIRTY,
|
||||
NULL);
|
||||
}
|
||||
node->processed = 1;
|
||||
}
|
||||
@@ -195,8 +196,8 @@ static struct btrfs_backref_node *walk_up_backref(
|
||||
int idx = *index;
|
||||
|
||||
while (!list_empty(&node->upper)) {
|
||||
edge = list_entry(node->upper.next,
|
||||
struct btrfs_backref_edge, list[LOWER]);
|
||||
edge = list_first_entry(&node->upper, struct btrfs_backref_edge,
|
||||
list[LOWER]);
|
||||
edges[idx++] = edge;
|
||||
node = edge->node[UPPER];
|
||||
}
|
||||
@@ -222,8 +223,8 @@ static struct btrfs_backref_node *walk_down_backref(
|
||||
idx--;
|
||||
continue;
|
||||
}
|
||||
edge = list_entry(edge->list[LOWER].next,
|
||||
struct btrfs_backref_edge, list[LOWER]);
|
||||
edge = list_first_entry(&edge->list[LOWER], struct btrfs_backref_edge,
|
||||
list[LOWER]);
|
||||
edges[idx - 1] = edge;
|
||||
*index = idx;
|
||||
return edge->node[UPPER];
|
||||
@@ -347,8 +348,8 @@ static bool handle_useless_nodes(struct reloc_control *rc,
|
||||
struct btrfs_backref_edge *edge;
|
||||
struct btrfs_backref_node *lower;
|
||||
|
||||
edge = list_entry(cur->lower.next,
|
||||
struct btrfs_backref_edge, list[UPPER]);
|
||||
edge = list_first_entry(&cur->lower, struct btrfs_backref_edge,
|
||||
list[UPPER]);
|
||||
list_del(&edge->list[UPPER]);
|
||||
list_del(&edge->list[LOWER]);
|
||||
lower = edge->node[LOWER];
|
||||
@@ -910,16 +911,16 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
|
||||
/* Take mmap lock to serialize with reflinks. */
|
||||
if (!down_read_trylock(&inode->i_mmap_lock))
|
||||
continue;
|
||||
ret = try_lock_extent(&inode->io_tree, key.offset,
|
||||
end, &cached_state);
|
||||
ret = btrfs_try_lock_extent(&inode->io_tree, key.offset,
|
||||
end, &cached_state);
|
||||
if (!ret) {
|
||||
up_read(&inode->i_mmap_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
btrfs_drop_extent_map_range(inode, key.offset, end, true);
|
||||
unlock_extent(&inode->io_tree, key.offset, end,
|
||||
&cached_state);
|
||||
btrfs_unlock_extent(&inode->io_tree, key.offset, end,
|
||||
&cached_state);
|
||||
up_read(&inode->i_mmap_lock);
|
||||
}
|
||||
}
|
||||
@@ -1378,9 +1379,9 @@ static int invalidate_extent_cache(struct btrfs_root *root,
|
||||
}
|
||||
|
||||
/* the lock_extent waits for read_folio to complete */
|
||||
lock_extent(&inode->io_tree, start, end, &cached_state);
|
||||
btrfs_lock_extent(&inode->io_tree, start, end, &cached_state);
|
||||
btrfs_drop_extent_map_range(inode, start, end, true);
|
||||
unlock_extent(&inode->io_tree, start, end, &cached_state);
|
||||
btrfs_unlock_extent(&inode->io_tree, start, end, &cached_state);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1697,8 +1698,8 @@ again:
|
||||
rc->merge_reloc_tree = true;
|
||||
|
||||
while (!list_empty(&rc->reloc_roots)) {
|
||||
reloc_root = list_entry(rc->reloc_roots.next,
|
||||
struct btrfs_root, root_list);
|
||||
reloc_root = list_first_entry(&rc->reloc_roots,
|
||||
struct btrfs_root, root_list);
|
||||
list_del_init(&reloc_root->root_list);
|
||||
|
||||
root = btrfs_get_fs_root(fs_info, reloc_root->root_key.offset,
|
||||
@@ -1813,8 +1814,7 @@ again:
|
||||
|
||||
while (!list_empty(&reloc_roots)) {
|
||||
found = 1;
|
||||
reloc_root = list_entry(reloc_roots.next,
|
||||
struct btrfs_root, root_list);
|
||||
reloc_root = list_first_entry(&reloc_roots, struct btrfs_root, root_list);
|
||||
|
||||
root = btrfs_get_fs_root(fs_info, reloc_root->root_key.offset,
|
||||
false);
|
||||
@@ -1930,11 +1930,11 @@ static int record_reloc_root_in_trans(struct btrfs_trans_handle *trans,
|
||||
* reloc root without a corresponding root this could return ENOENT.
|
||||
*/
|
||||
if (IS_ERR(root)) {
|
||||
ASSERT(0);
|
||||
DEBUG_WARN("error %ld reading root for reloc root", PTR_ERR(root));
|
||||
return PTR_ERR(root);
|
||||
}
|
||||
if (root->reloc_root != reloc_root) {
|
||||
ASSERT(0);
|
||||
DEBUG_WARN("unexpected reloc root found");
|
||||
btrfs_err(fs_info,
|
||||
"root %llu has two reloc roots associated with it",
|
||||
reloc_root->root_key.offset);
|
||||
@@ -2109,8 +2109,8 @@ static noinline_for_stack u64 calcu_metadata_size(struct reloc_control *rc,
|
||||
if (list_empty(&next->upper))
|
||||
break;
|
||||
|
||||
edge = list_entry(next->upper.next,
|
||||
struct btrfs_backref_edge, list[LOWER]);
|
||||
edge = list_first_entry(&next->upper, struct btrfs_backref_edge,
|
||||
list[LOWER]);
|
||||
edges[index++] = edge;
|
||||
next = edge->node[UPPER];
|
||||
}
|
||||
@@ -2356,8 +2356,8 @@ static int finish_pending_nodes(struct btrfs_trans_handle *trans,
|
||||
|
||||
for (level = 0; level < BTRFS_MAX_LEVEL; level++) {
|
||||
while (!list_empty(&cache->pending[level])) {
|
||||
node = list_entry(cache->pending[level].next,
|
||||
struct btrfs_backref_node, list);
|
||||
node = list_first_entry(&cache->pending[level],
|
||||
struct btrfs_backref_node, list);
|
||||
list_move_tail(&node->list, &list);
|
||||
BUG_ON(!node->pending);
|
||||
|
||||
@@ -2395,8 +2395,8 @@ static void update_processed_blocks(struct reloc_control *rc,
|
||||
if (list_empty(&next->upper))
|
||||
break;
|
||||
|
||||
edge = list_entry(next->upper.next,
|
||||
struct btrfs_backref_edge, list[LOWER]);
|
||||
edge = list_first_entry(&next->upper, struct btrfs_backref_edge,
|
||||
list[LOWER]);
|
||||
edges[index++] = edge;
|
||||
next = edge->node[UPPER];
|
||||
}
|
||||
@@ -2408,8 +2408,8 @@ static int tree_block_processed(u64 bytenr, struct reloc_control *rc)
|
||||
{
|
||||
u32 blocksize = rc->extent_root->fs_info->nodesize;
|
||||
|
||||
if (test_range_bit(&rc->processed_blocks, bytenr,
|
||||
bytenr + blocksize - 1, EXTENT_DIRTY, NULL))
|
||||
if (btrfs_test_range_bit(&rc->processed_blocks, bytenr,
|
||||
bytenr + blocksize - 1, EXTENT_DIRTY, NULL))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -2706,9 +2706,6 @@ static noinline_for_stack int prealloc_file_extent_cluster(struct reloc_control
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
clear_extent_bits(&inode->io_tree, i_size,
|
||||
round_up(i_size, PAGE_SIZE) - 1,
|
||||
EXTENT_UPTODATE);
|
||||
folio = filemap_lock_folio(mapping, i_size >> PAGE_SHIFT);
|
||||
/*
|
||||
* If page is freed we don't need to do anything then, as we
|
||||
@@ -2738,21 +2735,21 @@ static noinline_for_stack int prealloc_file_extent_cluster(struct reloc_control
|
||||
else
|
||||
end = cluster->end - offset;
|
||||
|
||||
lock_extent(&inode->io_tree, start, end, &cached_state);
|
||||
btrfs_lock_extent(&inode->io_tree, start, end, &cached_state);
|
||||
num_bytes = end + 1 - start;
|
||||
ret = btrfs_prealloc_file_range(&inode->vfs_inode, 0, start,
|
||||
num_bytes, num_bytes,
|
||||
end + 1, &alloc_hint);
|
||||
cur_offset = end + 1;
|
||||
unlock_extent(&inode->io_tree, start, end, &cached_state);
|
||||
btrfs_unlock_extent(&inode->io_tree, start, end, &cached_state);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
btrfs_inode_unlock(inode, 0);
|
||||
|
||||
if (cur_offset < prealloc_end)
|
||||
btrfs_free_reserved_data_space_noquota(inode->root->fs_info,
|
||||
prealloc_end + 1 - cur_offset);
|
||||
btrfs_free_reserved_data_space_noquota(inode,
|
||||
prealloc_end + 1 - cur_offset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2766,7 +2763,7 @@ static noinline_for_stack int setup_relocation_extent_mapping(struct reloc_contr
|
||||
u64 end = rc->cluster.end - offset;
|
||||
int ret = 0;
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -2777,10 +2774,10 @@ static noinline_for_stack int setup_relocation_extent_mapping(struct reloc_contr
|
||||
em->ram_bytes = em->len;
|
||||
em->flags |= EXTENT_FLAG_PINNED;
|
||||
|
||||
lock_extent(&inode->io_tree, start, end, &cached_state);
|
||||
btrfs_lock_extent(&inode->io_tree, start, end, &cached_state);
|
||||
ret = btrfs_replace_extent_map_range(inode, em, false);
|
||||
unlock_extent(&inode->io_tree, start, end, &cached_state);
|
||||
free_extent_map(em);
|
||||
btrfs_unlock_extent(&inode->io_tree, start, end, &cached_state);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -2902,15 +2899,15 @@ again:
|
||||
goto release_folio;
|
||||
|
||||
/* Mark the range delalloc and dirty for later writeback */
|
||||
lock_extent(&BTRFS_I(inode)->io_tree, clamped_start, clamped_end,
|
||||
&cached_state);
|
||||
btrfs_lock_extent(&BTRFS_I(inode)->io_tree, clamped_start,
|
||||
clamped_end, &cached_state);
|
||||
ret = btrfs_set_extent_delalloc(BTRFS_I(inode), clamped_start,
|
||||
clamped_end, 0, &cached_state);
|
||||
if (ret) {
|
||||
clear_extent_bit(&BTRFS_I(inode)->io_tree,
|
||||
clamped_start, clamped_end,
|
||||
EXTENT_LOCKED | EXTENT_BOUNDARY,
|
||||
&cached_state);
|
||||
btrfs_clear_extent_bit(&BTRFS_I(inode)->io_tree,
|
||||
clamped_start, clamped_end,
|
||||
EXTENT_LOCKED | EXTENT_BOUNDARY,
|
||||
&cached_state);
|
||||
btrfs_delalloc_release_metadata(BTRFS_I(inode),
|
||||
clamped_len, true);
|
||||
btrfs_delalloc_release_extents(BTRFS_I(inode),
|
||||
@@ -2932,12 +2929,12 @@ again:
|
||||
u64 boundary_end = boundary_start +
|
||||
fs_info->sectorsize - 1;
|
||||
|
||||
set_extent_bit(&BTRFS_I(inode)->io_tree,
|
||||
boundary_start, boundary_end,
|
||||
EXTENT_BOUNDARY, NULL);
|
||||
btrfs_set_extent_bit(&BTRFS_I(inode)->io_tree,
|
||||
boundary_start, boundary_end,
|
||||
EXTENT_BOUNDARY, NULL);
|
||||
}
|
||||
unlock_extent(&BTRFS_I(inode)->io_tree, clamped_start, clamped_end,
|
||||
&cached_state);
|
||||
btrfs_unlock_extent(&BTRFS_I(inode)->io_tree, clamped_start, clamped_end,
|
||||
&cached_state);
|
||||
btrfs_delalloc_release_extents(BTRFS_I(inode), clamped_len);
|
||||
cur += clamped_len;
|
||||
|
||||
@@ -3435,9 +3432,9 @@ next:
|
||||
goto next;
|
||||
}
|
||||
|
||||
block_found = find_first_extent_bit(&rc->processed_blocks,
|
||||
key.objectid, &start, &end,
|
||||
EXTENT_DIRTY, NULL);
|
||||
block_found = btrfs_find_first_extent_bit(&rc->processed_blocks,
|
||||
key.objectid, &start, &end,
|
||||
EXTENT_DIRTY, NULL);
|
||||
|
||||
if (block_found && start <= key.objectid) {
|
||||
btrfs_release_path(path);
|
||||
@@ -3646,7 +3643,7 @@ restart:
|
||||
}
|
||||
|
||||
btrfs_release_path(path);
|
||||
clear_extent_bits(&rc->processed_blocks, 0, (u64)-1, EXTENT_DIRTY);
|
||||
btrfs_clear_extent_bits(&rc->processed_blocks, 0, (u64)-1, EXTENT_DIRTY);
|
||||
|
||||
if (trans) {
|
||||
btrfs_end_transaction_throttle(trans);
|
||||
@@ -3862,7 +3859,7 @@ static struct reloc_control *alloc_reloc_control(struct btrfs_fs_info *fs_info)
|
||||
btrfs_backref_init_cache(fs_info, &rc->backref_cache, true);
|
||||
rc->reloc_root_tree.rb_root = RB_ROOT;
|
||||
spin_lock_init(&rc->reloc_root_tree.lock);
|
||||
extent_io_tree_init(fs_info, &rc->processed_blocks, IO_TREE_RELOC_BLOCKS);
|
||||
btrfs_extent_io_tree_init(fs_info, &rc->processed_blocks, IO_TREE_RELOC_BLOCKS);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -4185,8 +4182,7 @@ int btrfs_recover_relocation(struct btrfs_fs_info *fs_info)
|
||||
rc->merge_reloc_tree = true;
|
||||
|
||||
while (!list_empty(&reloc_roots)) {
|
||||
reloc_root = list_entry(reloc_roots.next,
|
||||
struct btrfs_root, root_list);
|
||||
reloc_root = list_first_entry(&reloc_roots, struct btrfs_root, root_list);
|
||||
list_del(&reloc_root->root_list);
|
||||
|
||||
if (btrfs_root_refs(&reloc_root->root_item) == 0) {
|
||||
@@ -4279,7 +4275,7 @@ int btrfs_reloc_clone_csums(struct btrfs_ordered_extent *ordered)
|
||||
|
||||
while (!list_empty(&list)) {
|
||||
struct btrfs_ordered_sum *sums =
|
||||
list_entry(list.next, struct btrfs_ordered_sum, list);
|
||||
list_first_entry(&list, struct btrfs_ordered_sum, list);
|
||||
|
||||
list_del_init(&sums->list);
|
||||
|
||||
|
||||
+285
-173
@@ -66,8 +66,6 @@ struct scrub_ctx;
|
||||
|
||||
/* Represent one sector and its needed info to verify the content. */
|
||||
struct scrub_sector_verification {
|
||||
bool is_metadata;
|
||||
|
||||
union {
|
||||
/*
|
||||
* Csum pointer for data csum verification. Should point to a
|
||||
@@ -100,6 +98,38 @@ enum scrub_stripe_flags {
|
||||
SCRUB_STRIPE_FLAG_NO_REPORT,
|
||||
};
|
||||
|
||||
/*
|
||||
* We have multiple bitmaps for one scrub_stripe.
|
||||
* However each bitmap has at most (BTRFS_STRIPE_LEN / blocksize) bits,
|
||||
* which is normally 16, and much smaller than BITS_PER_LONG (32 or 64).
|
||||
*
|
||||
* So to reduce memory usage for each scrub_stripe, we pack those bitmaps
|
||||
* into a larger one.
|
||||
*
|
||||
* These enum records where the sub-bitmap are inside the larger one.
|
||||
* Each subbitmap starts at scrub_bitmap_nr_##name * nr_sectors bit.
|
||||
*/
|
||||
enum {
|
||||
/* Which blocks are covered by extent items. */
|
||||
scrub_bitmap_nr_has_extent = 0,
|
||||
|
||||
/* Which blocks are meteadata. */
|
||||
scrub_bitmap_nr_is_metadata,
|
||||
|
||||
/*
|
||||
* Which blocks have errors, including IO, csum, and metadata
|
||||
* errors.
|
||||
* This sub-bitmap is the OR results of the next few error related
|
||||
* sub-bitmaps.
|
||||
*/
|
||||
scrub_bitmap_nr_error,
|
||||
scrub_bitmap_nr_io_error,
|
||||
scrub_bitmap_nr_csum_error,
|
||||
scrub_bitmap_nr_meta_error,
|
||||
scrub_bitmap_nr_meta_gen_error,
|
||||
scrub_bitmap_nr_last,
|
||||
};
|
||||
|
||||
#define SCRUB_STRIPE_PAGES (BTRFS_STRIPE_LEN / PAGE_SIZE)
|
||||
|
||||
/*
|
||||
@@ -138,36 +168,15 @@ struct scrub_stripe {
|
||||
*/
|
||||
unsigned long state;
|
||||
|
||||
/* Indicate which sectors are covered by extent items. */
|
||||
unsigned long extent_sector_bitmap;
|
||||
/* The large bitmap contains all the sub-bitmaps. */
|
||||
unsigned long bitmaps[BITS_TO_LONGS(scrub_bitmap_nr_last *
|
||||
(BTRFS_STRIPE_LEN / BTRFS_MIN_BLOCKSIZE))];
|
||||
|
||||
/*
|
||||
* The errors hit during the initial read of the stripe.
|
||||
*
|
||||
* Would be utilized for error reporting and repair.
|
||||
*
|
||||
* The remaining init_nr_* records the number of errors hit, only used
|
||||
* by error reporting.
|
||||
* For writeback (repair or replace) error reporting.
|
||||
* This one is protected by a spinlock, thus can not be packed into
|
||||
* the larger bitmap.
|
||||
*/
|
||||
unsigned long init_error_bitmap;
|
||||
unsigned int init_nr_io_errors;
|
||||
unsigned int init_nr_csum_errors;
|
||||
unsigned int init_nr_meta_errors;
|
||||
|
||||
/*
|
||||
* The following error bitmaps are all for the current status.
|
||||
* Every time we submit a new read, these bitmaps may be updated.
|
||||
*
|
||||
* error_bitmap = io_error_bitmap | csum_error_bitmap | meta_error_bitmap;
|
||||
*
|
||||
* IO and csum errors can happen for both metadata and data.
|
||||
*/
|
||||
unsigned long error_bitmap;
|
||||
unsigned long io_error_bitmap;
|
||||
unsigned long csum_error_bitmap;
|
||||
unsigned long meta_error_bitmap;
|
||||
|
||||
/* For writeback (repair or replace) error reporting. */
|
||||
unsigned long write_error_bitmap;
|
||||
|
||||
/* Writeback can be concurrent, thus we need to protect the bitmap. */
|
||||
@@ -219,6 +228,90 @@ struct scrub_ctx {
|
||||
refcount_t refs;
|
||||
};
|
||||
|
||||
#define scrub_calc_start_bit(stripe, name, block_nr) \
|
||||
({ \
|
||||
unsigned int __start_bit; \
|
||||
\
|
||||
ASSERT(block_nr < stripe->nr_sectors, \
|
||||
"nr_sectors=%u block_nr=%u", stripe->nr_sectors, block_nr); \
|
||||
__start_bit = scrub_bitmap_nr_##name * stripe->nr_sectors + block_nr; \
|
||||
__start_bit; \
|
||||
})
|
||||
|
||||
#define IMPLEMENT_SCRUB_BITMAP_OPS(name) \
|
||||
static inline void scrub_bitmap_set_##name(struct scrub_stripe *stripe, \
|
||||
unsigned int block_nr, \
|
||||
unsigned int nr_blocks) \
|
||||
{ \
|
||||
const unsigned int start_bit = scrub_calc_start_bit(stripe, \
|
||||
name, block_nr); \
|
||||
\
|
||||
bitmap_set(stripe->bitmaps, start_bit, nr_blocks); \
|
||||
} \
|
||||
static inline void scrub_bitmap_clear_##name(struct scrub_stripe *stripe, \
|
||||
unsigned int block_nr, \
|
||||
unsigned int nr_blocks) \
|
||||
{ \
|
||||
const unsigned int start_bit = scrub_calc_start_bit(stripe, name, \
|
||||
block_nr); \
|
||||
\
|
||||
bitmap_clear(stripe->bitmaps, start_bit, nr_blocks); \
|
||||
} \
|
||||
static inline bool scrub_bitmap_test_bit_##name(struct scrub_stripe *stripe, \
|
||||
unsigned int block_nr) \
|
||||
{ \
|
||||
const unsigned int start_bit = scrub_calc_start_bit(stripe, name, \
|
||||
block_nr); \
|
||||
\
|
||||
return test_bit(start_bit, stripe->bitmaps); \
|
||||
} \
|
||||
static inline void scrub_bitmap_set_bit_##name(struct scrub_stripe *stripe, \
|
||||
unsigned int block_nr) \
|
||||
{ \
|
||||
const unsigned int start_bit = scrub_calc_start_bit(stripe, name, \
|
||||
block_nr); \
|
||||
\
|
||||
set_bit(start_bit, stripe->bitmaps); \
|
||||
} \
|
||||
static inline void scrub_bitmap_clear_bit_##name(struct scrub_stripe *stripe, \
|
||||
unsigned int block_nr) \
|
||||
{ \
|
||||
const unsigned int start_bit = scrub_calc_start_bit(stripe, name, \
|
||||
block_nr); \
|
||||
\
|
||||
clear_bit(start_bit, stripe->bitmaps); \
|
||||
} \
|
||||
static inline unsigned long scrub_bitmap_read_##name(struct scrub_stripe *stripe) \
|
||||
{ \
|
||||
const unsigned int nr_blocks = stripe->nr_sectors; \
|
||||
\
|
||||
ASSERT(nr_blocks > 0 && nr_blocks <= BITS_PER_LONG, \
|
||||
"nr_blocks=%u BITS_PER_LONG=%u", \
|
||||
nr_blocks, BITS_PER_LONG); \
|
||||
\
|
||||
return bitmap_read(stripe->bitmaps, nr_blocks * scrub_bitmap_nr_##name, \
|
||||
stripe->nr_sectors); \
|
||||
} \
|
||||
static inline bool scrub_bitmap_empty_##name(struct scrub_stripe *stripe) \
|
||||
{ \
|
||||
unsigned long bitmap = scrub_bitmap_read_##name(stripe); \
|
||||
\
|
||||
return bitmap_empty(&bitmap, stripe->nr_sectors); \
|
||||
} \
|
||||
static inline unsigned int scrub_bitmap_weight_##name(struct scrub_stripe *stripe) \
|
||||
{ \
|
||||
unsigned long bitmap = scrub_bitmap_read_##name(stripe); \
|
||||
\
|
||||
return bitmap_weight(&bitmap, stripe->nr_sectors); \
|
||||
}
|
||||
IMPLEMENT_SCRUB_BITMAP_OPS(has_extent);
|
||||
IMPLEMENT_SCRUB_BITMAP_OPS(is_metadata);
|
||||
IMPLEMENT_SCRUB_BITMAP_OPS(error);
|
||||
IMPLEMENT_SCRUB_BITMAP_OPS(io_error);
|
||||
IMPLEMENT_SCRUB_BITMAP_OPS(csum_error);
|
||||
IMPLEMENT_SCRUB_BITMAP_OPS(meta_error);
|
||||
IMPLEMENT_SCRUB_BITMAP_OPS(meta_gen_error);
|
||||
|
||||
struct scrub_warning {
|
||||
struct btrfs_path *path;
|
||||
u64 extent_item_size;
|
||||
@@ -228,6 +321,19 @@ struct scrub_warning {
|
||||
struct btrfs_device *dev;
|
||||
};
|
||||
|
||||
struct scrub_error_records {
|
||||
/*
|
||||
* Bitmap recording which blocks hit errors (IO/csum/...) during the
|
||||
* initial read.
|
||||
*/
|
||||
unsigned long init_error_bitmap;
|
||||
|
||||
unsigned int nr_io_errors;
|
||||
unsigned int nr_csum_errors;
|
||||
unsigned int nr_meta_errors;
|
||||
unsigned int nr_meta_gen_errors;
|
||||
};
|
||||
|
||||
static void release_scrub_stripe(struct scrub_stripe *stripe)
|
||||
{
|
||||
if (!stripe)
|
||||
@@ -579,20 +685,15 @@ static int fill_writer_pointer_gap(struct scrub_ctx *sctx, u64 physical)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct page *scrub_stripe_get_page(struct scrub_stripe *stripe, int sector_nr)
|
||||
static void *scrub_stripe_get_kaddr(struct scrub_stripe *stripe, int sector_nr)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
|
||||
int page_index = (sector_nr << fs_info->sectorsize_bits) >> PAGE_SHIFT;
|
||||
u32 offset = (sector_nr << stripe->bg->fs_info->sectorsize_bits);
|
||||
const struct page *page = stripe->pages[offset >> PAGE_SHIFT];
|
||||
|
||||
return stripe->pages[page_index];
|
||||
}
|
||||
|
||||
static unsigned int scrub_stripe_get_page_offset(struct scrub_stripe *stripe,
|
||||
int sector_nr)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
|
||||
|
||||
return offset_in_page(sector_nr << fs_info->sectorsize_bits);
|
||||
/* stripe->pages[] is allocated by us and no highmem is allowed. */
|
||||
ASSERT(page);
|
||||
ASSERT(!PageHighMem(page));
|
||||
return page_address(page) + offset_in_page(offset);
|
||||
}
|
||||
|
||||
static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr)
|
||||
@@ -600,24 +701,22 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr
|
||||
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
|
||||
const u32 sectors_per_tree = fs_info->nodesize >> fs_info->sectorsize_bits;
|
||||
const u64 logical = stripe->logical + (sector_nr << fs_info->sectorsize_bits);
|
||||
const struct page *first_page = scrub_stripe_get_page(stripe, sector_nr);
|
||||
const unsigned int first_off = scrub_stripe_get_page_offset(stripe, sector_nr);
|
||||
void *first_kaddr = scrub_stripe_get_kaddr(stripe, sector_nr);
|
||||
struct btrfs_header *header = first_kaddr;
|
||||
SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
|
||||
u8 on_disk_csum[BTRFS_CSUM_SIZE];
|
||||
u8 calculated_csum[BTRFS_CSUM_SIZE];
|
||||
struct btrfs_header *header;
|
||||
|
||||
/*
|
||||
* Here we don't have a good way to attach the pages (and subpages)
|
||||
* to a dummy extent buffer, thus we have to directly grab the members
|
||||
* from pages.
|
||||
*/
|
||||
header = (struct btrfs_header *)(page_address(first_page) + first_off);
|
||||
memcpy(on_disk_csum, header->csum, fs_info->csum_size);
|
||||
|
||||
if (logical != btrfs_stack_header_bytenr(header)) {
|
||||
bitmap_set(&stripe->csum_error_bitmap, sector_nr, sectors_per_tree);
|
||||
bitmap_set(&stripe->error_bitmap, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_set_meta_error(stripe, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_set_error(stripe, sector_nr, sectors_per_tree);
|
||||
btrfs_warn_rl(fs_info,
|
||||
"tree block %llu mirror %u has bad bytenr, has %llu want %llu",
|
||||
logical, stripe->mirror_num,
|
||||
@@ -626,8 +725,8 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr
|
||||
}
|
||||
if (memcmp(header->fsid, fs_info->fs_devices->metadata_uuid,
|
||||
BTRFS_FSID_SIZE) != 0) {
|
||||
bitmap_set(&stripe->meta_error_bitmap, sector_nr, sectors_per_tree);
|
||||
bitmap_set(&stripe->error_bitmap, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_set_meta_error(stripe, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_set_error(stripe, sector_nr, sectors_per_tree);
|
||||
btrfs_warn_rl(fs_info,
|
||||
"tree block %llu mirror %u has bad fsid, has %pU want %pU",
|
||||
logical, stripe->mirror_num,
|
||||
@@ -636,8 +735,8 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr
|
||||
}
|
||||
if (memcmp(header->chunk_tree_uuid, fs_info->chunk_tree_uuid,
|
||||
BTRFS_UUID_SIZE) != 0) {
|
||||
bitmap_set(&stripe->meta_error_bitmap, sector_nr, sectors_per_tree);
|
||||
bitmap_set(&stripe->error_bitmap, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_set_meta_error(stripe, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_set_error(stripe, sector_nr, sectors_per_tree);
|
||||
btrfs_warn_rl(fs_info,
|
||||
"tree block %llu mirror %u has bad chunk tree uuid, has %pU want %pU",
|
||||
logical, stripe->mirror_num,
|
||||
@@ -648,21 +747,18 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr
|
||||
/* Now check tree block csum. */
|
||||
shash->tfm = fs_info->csum_shash;
|
||||
crypto_shash_init(shash);
|
||||
crypto_shash_update(shash, page_address(first_page) + first_off +
|
||||
BTRFS_CSUM_SIZE, fs_info->sectorsize - BTRFS_CSUM_SIZE);
|
||||
crypto_shash_update(shash, first_kaddr + BTRFS_CSUM_SIZE,
|
||||
fs_info->sectorsize - BTRFS_CSUM_SIZE);
|
||||
|
||||
for (int i = sector_nr + 1; i < sector_nr + sectors_per_tree; i++) {
|
||||
struct page *page = scrub_stripe_get_page(stripe, i);
|
||||
unsigned int page_off = scrub_stripe_get_page_offset(stripe, i);
|
||||
|
||||
crypto_shash_update(shash, page_address(page) + page_off,
|
||||
crypto_shash_update(shash, scrub_stripe_get_kaddr(stripe, i),
|
||||
fs_info->sectorsize);
|
||||
}
|
||||
|
||||
crypto_shash_final(shash, calculated_csum);
|
||||
if (memcmp(calculated_csum, on_disk_csum, fs_info->csum_size) != 0) {
|
||||
bitmap_set(&stripe->meta_error_bitmap, sector_nr, sectors_per_tree);
|
||||
bitmap_set(&stripe->error_bitmap, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_set_meta_error(stripe, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_set_error(stripe, sector_nr, sectors_per_tree);
|
||||
btrfs_warn_rl(fs_info,
|
||||
"tree block %llu mirror %u has bad csum, has " CSUM_FMT " want " CSUM_FMT,
|
||||
logical, stripe->mirror_num,
|
||||
@@ -672,8 +768,8 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr
|
||||
}
|
||||
if (stripe->sectors[sector_nr].generation !=
|
||||
btrfs_stack_header_generation(header)) {
|
||||
bitmap_set(&stripe->meta_error_bitmap, sector_nr, sectors_per_tree);
|
||||
bitmap_set(&stripe->error_bitmap, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_set_meta_gen_error(stripe, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_set_error(stripe, sector_nr, sectors_per_tree);
|
||||
btrfs_warn_rl(fs_info,
|
||||
"tree block %llu mirror %u has bad generation, has %llu want %llu",
|
||||
logical, stripe->mirror_num,
|
||||
@@ -681,9 +777,10 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr
|
||||
stripe->sectors[sector_nr].generation);
|
||||
return;
|
||||
}
|
||||
bitmap_clear(&stripe->error_bitmap, sector_nr, sectors_per_tree);
|
||||
bitmap_clear(&stripe->csum_error_bitmap, sector_nr, sectors_per_tree);
|
||||
bitmap_clear(&stripe->meta_error_bitmap, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_clear_error(stripe, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_clear_csum_error(stripe, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_clear_meta_error(stripe, sector_nr, sectors_per_tree);
|
||||
scrub_bitmap_clear_meta_gen_error(stripe, sector_nr, sectors_per_tree);
|
||||
}
|
||||
|
||||
static void scrub_verify_one_sector(struct scrub_stripe *stripe, int sector_nr)
|
||||
@@ -691,23 +788,22 @@ static void scrub_verify_one_sector(struct scrub_stripe *stripe, int sector_nr)
|
||||
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
|
||||
struct scrub_sector_verification *sector = &stripe->sectors[sector_nr];
|
||||
const u32 sectors_per_tree = fs_info->nodesize >> fs_info->sectorsize_bits;
|
||||
struct page *page = scrub_stripe_get_page(stripe, sector_nr);
|
||||
unsigned int pgoff = scrub_stripe_get_page_offset(stripe, sector_nr);
|
||||
void *kaddr = scrub_stripe_get_kaddr(stripe, sector_nr);
|
||||
u8 csum_buf[BTRFS_CSUM_SIZE];
|
||||
int ret;
|
||||
|
||||
ASSERT(sector_nr >= 0 && sector_nr < stripe->nr_sectors);
|
||||
|
||||
/* Sector not utilized, skip it. */
|
||||
if (!test_bit(sector_nr, &stripe->extent_sector_bitmap))
|
||||
if (!scrub_bitmap_test_bit_has_extent(stripe, sector_nr))
|
||||
return;
|
||||
|
||||
/* IO error, no need to check. */
|
||||
if (test_bit(sector_nr, &stripe->io_error_bitmap))
|
||||
if (scrub_bitmap_test_bit_io_error(stripe, sector_nr))
|
||||
return;
|
||||
|
||||
/* Metadata, verify the full tree block. */
|
||||
if (sector->is_metadata) {
|
||||
if (scrub_bitmap_test_bit_is_metadata(stripe, sector_nr)) {
|
||||
/*
|
||||
* Check if the tree block crosses the stripe boundary. If
|
||||
* crossed the boundary, we cannot verify it but only give a
|
||||
@@ -733,17 +829,17 @@ static void scrub_verify_one_sector(struct scrub_stripe *stripe, int sector_nr)
|
||||
* cases without csum, we have no other choice but to trust it.
|
||||
*/
|
||||
if (!sector->csum) {
|
||||
clear_bit(sector_nr, &stripe->error_bitmap);
|
||||
scrub_bitmap_clear_bit_error(stripe, sector_nr);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = btrfs_check_sector_csum(fs_info, page, pgoff, csum_buf, sector->csum);
|
||||
ret = btrfs_check_sector_csum(fs_info, kaddr, csum_buf, sector->csum);
|
||||
if (ret < 0) {
|
||||
set_bit(sector_nr, &stripe->csum_error_bitmap);
|
||||
set_bit(sector_nr, &stripe->error_bitmap);
|
||||
scrub_bitmap_set_bit_csum_error(stripe, sector_nr);
|
||||
scrub_bitmap_set_bit_error(stripe, sector_nr);
|
||||
} else {
|
||||
clear_bit(sector_nr, &stripe->csum_error_bitmap);
|
||||
clear_bit(sector_nr, &stripe->error_bitmap);
|
||||
scrub_bitmap_clear_bit_csum_error(stripe, sector_nr);
|
||||
scrub_bitmap_clear_bit_error(stripe, sector_nr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,7 +852,7 @@ static void scrub_verify_one_stripe(struct scrub_stripe *stripe, unsigned long b
|
||||
|
||||
for_each_set_bit(sector_nr, &bitmap, stripe->nr_sectors) {
|
||||
scrub_verify_one_sector(stripe, sector_nr);
|
||||
if (stripe->sectors[sector_nr].is_metadata)
|
||||
if (scrub_bitmap_test_bit_is_metadata(stripe, sector_nr))
|
||||
sector_nr += sectors_per_tree - 1;
|
||||
}
|
||||
}
|
||||
@@ -766,8 +862,7 @@ static int calc_sector_number(struct scrub_stripe *stripe, struct bio_vec *first
|
||||
int i;
|
||||
|
||||
for (i = 0; i < stripe->nr_sectors; i++) {
|
||||
if (scrub_stripe_get_page(stripe, i) == first_bvec->bv_page &&
|
||||
scrub_stripe_get_page_offset(stripe, i) == first_bvec->bv_offset)
|
||||
if (scrub_stripe_get_kaddr(stripe, i) == bvec_virt(first_bvec))
|
||||
break;
|
||||
}
|
||||
ASSERT(i < stripe->nr_sectors);
|
||||
@@ -795,13 +890,13 @@ static void scrub_repair_read_endio(struct btrfs_bio *bbio)
|
||||
bio_size += bvec->bv_len;
|
||||
|
||||
if (bbio->bio.bi_status) {
|
||||
bitmap_set(&stripe->io_error_bitmap, sector_nr,
|
||||
bio_size >> fs_info->sectorsize_bits);
|
||||
bitmap_set(&stripe->error_bitmap, sector_nr,
|
||||
bio_size >> fs_info->sectorsize_bits);
|
||||
scrub_bitmap_set_io_error(stripe, sector_nr,
|
||||
bio_size >> fs_info->sectorsize_bits);
|
||||
scrub_bitmap_set_error(stripe, sector_nr,
|
||||
bio_size >> fs_info->sectorsize_bits);
|
||||
} else {
|
||||
bitmap_clear(&stripe->io_error_bitmap, sector_nr,
|
||||
bio_size >> fs_info->sectorsize_bits);
|
||||
scrub_bitmap_clear_io_error(stripe, sector_nr,
|
||||
bio_size >> fs_info->sectorsize_bits);
|
||||
}
|
||||
bio_put(&bbio->bio);
|
||||
if (atomic_dec_and_test(&stripe->pending_io))
|
||||
@@ -814,27 +909,39 @@ static int calc_next_mirror(int mirror, int num_copies)
|
||||
return (mirror + 1 > num_copies) ? 1 : mirror + 1;
|
||||
}
|
||||
|
||||
static void scrub_bio_add_sector(struct btrfs_bio *bbio, struct scrub_stripe *stripe,
|
||||
int sector_nr)
|
||||
{
|
||||
void *kaddr = scrub_stripe_get_kaddr(stripe, sector_nr);
|
||||
int ret;
|
||||
|
||||
ret = bio_add_page(&bbio->bio, virt_to_page(kaddr), bbio->fs_info->sectorsize,
|
||||
offset_in_page(kaddr));
|
||||
/*
|
||||
* Caller should ensure the bbio has enough size.
|
||||
* And we cannot use __bio_add_page(), which doesn't do any merge.
|
||||
*
|
||||
* Meanwhile for scrub_submit_initial_read() we fully rely on the merge
|
||||
* to create the minimal amount of bio vectors, for fs block size < page
|
||||
* size cases.
|
||||
*/
|
||||
ASSERT(ret == bbio->fs_info->sectorsize);
|
||||
}
|
||||
|
||||
static void scrub_stripe_submit_repair_read(struct scrub_stripe *stripe,
|
||||
int mirror, int blocksize, bool wait)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
|
||||
struct btrfs_bio *bbio = NULL;
|
||||
const unsigned long old_error_bitmap = stripe->error_bitmap;
|
||||
const unsigned long old_error_bitmap = scrub_bitmap_read_error(stripe);
|
||||
int i;
|
||||
|
||||
ASSERT(stripe->mirror_num >= 1);
|
||||
ASSERT(atomic_read(&stripe->pending_io) == 0);
|
||||
|
||||
for_each_set_bit(i, &old_error_bitmap, stripe->nr_sectors) {
|
||||
struct page *page;
|
||||
int pgoff;
|
||||
int ret;
|
||||
|
||||
page = scrub_stripe_get_page(stripe, i);
|
||||
pgoff = scrub_stripe_get_page_offset(stripe, i);
|
||||
|
||||
/* The current sector cannot be merged, submit the bio. */
|
||||
if (bbio && ((i > 0 && !test_bit(i - 1, &stripe->error_bitmap)) ||
|
||||
if (bbio && ((i > 0 && !test_bit(i - 1, &old_error_bitmap)) ||
|
||||
bbio->bio.bi_iter.bi_size >= blocksize)) {
|
||||
ASSERT(bbio->bio.bi_iter.bi_size);
|
||||
atomic_inc(&stripe->pending_io);
|
||||
@@ -851,8 +958,7 @@ static void scrub_stripe_submit_repair_read(struct scrub_stripe *stripe,
|
||||
(i << fs_info->sectorsize_bits)) >> SECTOR_SHIFT;
|
||||
}
|
||||
|
||||
ret = bio_add_page(&bbio->bio, page, fs_info->sectorsize, pgoff);
|
||||
ASSERT(ret == fs_info->sectorsize);
|
||||
scrub_bio_add_sector(bbio, stripe, i);
|
||||
}
|
||||
if (bbio) {
|
||||
ASSERT(bbio->bio.bi_iter.bi_size);
|
||||
@@ -864,12 +970,15 @@ static void scrub_stripe_submit_repair_read(struct scrub_stripe *stripe,
|
||||
}
|
||||
|
||||
static void scrub_stripe_report_errors(struct scrub_ctx *sctx,
|
||||
struct scrub_stripe *stripe)
|
||||
struct scrub_stripe *stripe,
|
||||
const struct scrub_error_records *errors)
|
||||
{
|
||||
static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
|
||||
DEFAULT_RATELIMIT_BURST);
|
||||
struct btrfs_fs_info *fs_info = sctx->fs_info;
|
||||
struct btrfs_device *dev = NULL;
|
||||
const unsigned long extent_bitmap = scrub_bitmap_read_has_extent(stripe);
|
||||
const unsigned long error_bitmap = scrub_bitmap_read_error(stripe);
|
||||
u64 physical = 0;
|
||||
int nr_data_sectors = 0;
|
||||
int nr_meta_sectors = 0;
|
||||
@@ -886,7 +995,7 @@ static void scrub_stripe_report_errors(struct scrub_ctx *sctx,
|
||||
* Although our scrub_stripe infrastructure is mostly based on btrfs_submit_bio()
|
||||
* thus no need for dev/physical, error reporting still needs dev and physical.
|
||||
*/
|
||||
if (!bitmap_empty(&stripe->init_error_bitmap, stripe->nr_sectors)) {
|
||||
if (!bitmap_empty(&errors->init_error_bitmap, stripe->nr_sectors)) {
|
||||
u64 mapped_len = fs_info->sectorsize;
|
||||
struct btrfs_io_context *bioc = NULL;
|
||||
int stripe_index = stripe->mirror_num - 1;
|
||||
@@ -909,10 +1018,10 @@ static void scrub_stripe_report_errors(struct scrub_ctx *sctx,
|
||||
}
|
||||
|
||||
skip:
|
||||
for_each_set_bit(sector_nr, &stripe->extent_sector_bitmap, stripe->nr_sectors) {
|
||||
for_each_set_bit(sector_nr, &extent_bitmap, stripe->nr_sectors) {
|
||||
bool repaired = false;
|
||||
|
||||
if (stripe->sectors[sector_nr].is_metadata) {
|
||||
if (scrub_bitmap_test_bit_is_metadata(stripe, sector_nr)) {
|
||||
nr_meta_sectors++;
|
||||
} else {
|
||||
nr_data_sectors++;
|
||||
@@ -920,14 +1029,14 @@ skip:
|
||||
nr_nodatacsum_sectors++;
|
||||
}
|
||||
|
||||
if (test_bit(sector_nr, &stripe->init_error_bitmap) &&
|
||||
!test_bit(sector_nr, &stripe->error_bitmap)) {
|
||||
if (test_bit(sector_nr, &errors->init_error_bitmap) &&
|
||||
!test_bit(sector_nr, &error_bitmap)) {
|
||||
nr_repaired_sectors++;
|
||||
repaired = true;
|
||||
}
|
||||
|
||||
/* Good sector from the beginning, nothing need to be done. */
|
||||
if (!test_bit(sector_nr, &stripe->init_error_bitmap))
|
||||
if (!test_bit(sector_nr, &errors->init_error_bitmap))
|
||||
continue;
|
||||
|
||||
/*
|
||||
@@ -960,31 +1069,46 @@ skip:
|
||||
stripe->logical, stripe->mirror_num);
|
||||
}
|
||||
|
||||
if (test_bit(sector_nr, &stripe->io_error_bitmap))
|
||||
if (scrub_bitmap_test_bit_io_error(stripe, sector_nr))
|
||||
if (__ratelimit(&rs) && dev)
|
||||
scrub_print_common_warning("i/o error", dev, false,
|
||||
stripe->logical, physical);
|
||||
if (test_bit(sector_nr, &stripe->csum_error_bitmap))
|
||||
if (scrub_bitmap_test_bit_csum_error(stripe, sector_nr))
|
||||
if (__ratelimit(&rs) && dev)
|
||||
scrub_print_common_warning("checksum error", dev, false,
|
||||
stripe->logical, physical);
|
||||
if (test_bit(sector_nr, &stripe->meta_error_bitmap))
|
||||
if (scrub_bitmap_test_bit_meta_error(stripe, sector_nr))
|
||||
if (__ratelimit(&rs) && dev)
|
||||
scrub_print_common_warning("header error", dev, false,
|
||||
stripe->logical, physical);
|
||||
if (scrub_bitmap_test_bit_meta_gen_error(stripe, sector_nr))
|
||||
if (__ratelimit(&rs) && dev)
|
||||
scrub_print_common_warning("generation error", dev, false,
|
||||
stripe->logical, physical);
|
||||
}
|
||||
|
||||
/* Update the device stats. */
|
||||
for (int i = 0; i < errors->nr_io_errors; i++)
|
||||
btrfs_dev_stat_inc_and_print(stripe->dev, BTRFS_DEV_STAT_READ_ERRS);
|
||||
for (int i = 0; i < errors->nr_csum_errors; i++)
|
||||
btrfs_dev_stat_inc_and_print(stripe->dev, BTRFS_DEV_STAT_CORRUPTION_ERRS);
|
||||
/* Generation mismatch error is based on each metadata, not each block. */
|
||||
for (int i = 0; i < errors->nr_meta_gen_errors;
|
||||
i += (fs_info->nodesize >> fs_info->sectorsize_bits))
|
||||
btrfs_dev_stat_inc_and_print(stripe->dev, BTRFS_DEV_STAT_GENERATION_ERRS);
|
||||
|
||||
spin_lock(&sctx->stat_lock);
|
||||
sctx->stat.data_extents_scrubbed += stripe->nr_data_extents;
|
||||
sctx->stat.tree_extents_scrubbed += stripe->nr_meta_extents;
|
||||
sctx->stat.data_bytes_scrubbed += nr_data_sectors << fs_info->sectorsize_bits;
|
||||
sctx->stat.tree_bytes_scrubbed += nr_meta_sectors << fs_info->sectorsize_bits;
|
||||
sctx->stat.no_csum += nr_nodatacsum_sectors;
|
||||
sctx->stat.read_errors += stripe->init_nr_io_errors;
|
||||
sctx->stat.csum_errors += stripe->init_nr_csum_errors;
|
||||
sctx->stat.verify_errors += stripe->init_nr_meta_errors;
|
||||
sctx->stat.read_errors += errors->nr_io_errors;
|
||||
sctx->stat.csum_errors += errors->nr_csum_errors;
|
||||
sctx->stat.verify_errors += errors->nr_meta_errors +
|
||||
errors->nr_meta_gen_errors;
|
||||
sctx->stat.uncorrectable_errors +=
|
||||
bitmap_weight(&stripe->error_bitmap, stripe->nr_sectors);
|
||||
bitmap_weight(&error_bitmap, stripe->nr_sectors);
|
||||
sctx->stat.corrected_errors += nr_repaired_sectors;
|
||||
spin_unlock(&sctx->stat_lock);
|
||||
}
|
||||
@@ -1010,26 +1134,26 @@ static void scrub_stripe_read_repair_worker(struct work_struct *work)
|
||||
struct scrub_stripe *stripe = container_of(work, struct scrub_stripe, work);
|
||||
struct scrub_ctx *sctx = stripe->sctx;
|
||||
struct btrfs_fs_info *fs_info = sctx->fs_info;
|
||||
struct scrub_error_records errors = { 0 };
|
||||
int num_copies = btrfs_num_copies(fs_info, stripe->bg->start,
|
||||
stripe->bg->length);
|
||||
unsigned long repaired;
|
||||
unsigned long error;
|
||||
int mirror;
|
||||
int i;
|
||||
|
||||
ASSERT(stripe->mirror_num > 0);
|
||||
|
||||
wait_scrub_stripe_io(stripe);
|
||||
scrub_verify_one_stripe(stripe, stripe->extent_sector_bitmap);
|
||||
scrub_verify_one_stripe(stripe, scrub_bitmap_read_has_extent(stripe));
|
||||
/* Save the initial failed bitmap for later repair and report usage. */
|
||||
stripe->init_error_bitmap = stripe->error_bitmap;
|
||||
stripe->init_nr_io_errors = bitmap_weight(&stripe->io_error_bitmap,
|
||||
stripe->nr_sectors);
|
||||
stripe->init_nr_csum_errors = bitmap_weight(&stripe->csum_error_bitmap,
|
||||
stripe->nr_sectors);
|
||||
stripe->init_nr_meta_errors = bitmap_weight(&stripe->meta_error_bitmap,
|
||||
stripe->nr_sectors);
|
||||
errors.init_error_bitmap = scrub_bitmap_read_error(stripe);
|
||||
errors.nr_io_errors = scrub_bitmap_weight_io_error(stripe);
|
||||
errors.nr_csum_errors = scrub_bitmap_weight_csum_error(stripe);
|
||||
errors.nr_meta_errors = scrub_bitmap_weight_meta_error(stripe);
|
||||
errors.nr_meta_gen_errors = scrub_bitmap_weight_meta_gen_error(stripe);
|
||||
|
||||
if (bitmap_empty(&stripe->init_error_bitmap, stripe->nr_sectors))
|
||||
if (bitmap_empty(&errors.init_error_bitmap, stripe->nr_sectors))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
@@ -1041,13 +1165,13 @@ static void scrub_stripe_read_repair_worker(struct work_struct *work)
|
||||
for (mirror = calc_next_mirror(stripe->mirror_num, num_copies);
|
||||
mirror != stripe->mirror_num;
|
||||
mirror = calc_next_mirror(mirror, num_copies)) {
|
||||
const unsigned long old_error_bitmap = stripe->error_bitmap;
|
||||
const unsigned long old_error_bitmap = scrub_bitmap_read_error(stripe);
|
||||
|
||||
scrub_stripe_submit_repair_read(stripe, mirror,
|
||||
BTRFS_STRIPE_LEN, false);
|
||||
wait_scrub_stripe_io(stripe);
|
||||
scrub_verify_one_stripe(stripe, old_error_bitmap);
|
||||
if (bitmap_empty(&stripe->error_bitmap, stripe->nr_sectors))
|
||||
if (scrub_bitmap_empty_error(stripe))
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1065,21 +1189,22 @@ static void scrub_stripe_read_repair_worker(struct work_struct *work)
|
||||
for (i = 0, mirror = stripe->mirror_num;
|
||||
i < num_copies;
|
||||
i++, mirror = calc_next_mirror(mirror, num_copies)) {
|
||||
const unsigned long old_error_bitmap = stripe->error_bitmap;
|
||||
const unsigned long old_error_bitmap = scrub_bitmap_read_error(stripe);
|
||||
|
||||
scrub_stripe_submit_repair_read(stripe, mirror,
|
||||
fs_info->sectorsize, true);
|
||||
wait_scrub_stripe_io(stripe);
|
||||
scrub_verify_one_stripe(stripe, old_error_bitmap);
|
||||
if (bitmap_empty(&stripe->error_bitmap, stripe->nr_sectors))
|
||||
if (scrub_bitmap_empty_error(stripe))
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
error = scrub_bitmap_read_error(stripe);
|
||||
/*
|
||||
* Submit the repaired sectors. For zoned case, we cannot do repair
|
||||
* in-place, but queue the bg to be relocated.
|
||||
*/
|
||||
bitmap_andnot(&repaired, &stripe->init_error_bitmap, &stripe->error_bitmap,
|
||||
bitmap_andnot(&repaired, &errors.init_error_bitmap, &error,
|
||||
stripe->nr_sectors);
|
||||
if (!sctx->readonly && !bitmap_empty(&repaired, stripe->nr_sectors)) {
|
||||
if (btrfs_is_zoned(fs_info)) {
|
||||
@@ -1090,7 +1215,7 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
scrub_stripe_report_errors(sctx, stripe);
|
||||
scrub_stripe_report_errors(sctx, stripe, &errors);
|
||||
set_bit(SCRUB_STRIPE_FLAG_REPAIR_DONE, &stripe->state);
|
||||
wake_up(&stripe->repair_wait);
|
||||
}
|
||||
@@ -1110,10 +1235,10 @@ static void scrub_read_endio(struct btrfs_bio *bbio)
|
||||
num_sectors = bio_size >> stripe->bg->fs_info->sectorsize_bits;
|
||||
|
||||
if (bbio->bio.bi_status) {
|
||||
bitmap_set(&stripe->io_error_bitmap, sector_nr, num_sectors);
|
||||
bitmap_set(&stripe->error_bitmap, sector_nr, num_sectors);
|
||||
scrub_bitmap_set_io_error(stripe, sector_nr, num_sectors);
|
||||
scrub_bitmap_set_error(stripe, sector_nr, num_sectors);
|
||||
} else {
|
||||
bitmap_clear(&stripe->io_error_bitmap, sector_nr, num_sectors);
|
||||
scrub_bitmap_clear_io_error(stripe, sector_nr, num_sectors);
|
||||
}
|
||||
bio_put(&bbio->bio);
|
||||
if (atomic_dec_and_test(&stripe->pending_io)) {
|
||||
@@ -1142,6 +1267,9 @@ static void scrub_write_endio(struct btrfs_bio *bbio)
|
||||
bitmap_set(&stripe->write_error_bitmap, sector_nr,
|
||||
bio_size >> fs_info->sectorsize_bits);
|
||||
spin_unlock_irqrestore(&stripe->write_error_lock, flags);
|
||||
for (int i = 0; i < (bio_size >> fs_info->sectorsize_bits); i++)
|
||||
btrfs_dev_stat_inc_and_print(stripe->dev,
|
||||
BTRFS_DEV_STAT_WRITE_ERRS);
|
||||
}
|
||||
bio_put(&bbio->bio);
|
||||
|
||||
@@ -1199,12 +1327,8 @@ static void scrub_write_sectors(struct scrub_ctx *sctx, struct scrub_stripe *str
|
||||
int sector_nr;
|
||||
|
||||
for_each_set_bit(sector_nr, &write_bitmap, stripe->nr_sectors) {
|
||||
struct page *page = scrub_stripe_get_page(stripe, sector_nr);
|
||||
unsigned int pgoff = scrub_stripe_get_page_offset(stripe, sector_nr);
|
||||
int ret;
|
||||
|
||||
/* We should only writeback sectors covered by an extent. */
|
||||
ASSERT(test_bit(sector_nr, &stripe->extent_sector_bitmap));
|
||||
ASSERT(scrub_bitmap_test_bit_has_extent(stripe, sector_nr));
|
||||
|
||||
/* Cannot merge with previous sector, submit the current one. */
|
||||
if (bbio && sector_nr && !test_bit(sector_nr - 1, &write_bitmap)) {
|
||||
@@ -1218,8 +1342,7 @@ static void scrub_write_sectors(struct scrub_ctx *sctx, struct scrub_stripe *str
|
||||
(sector_nr << fs_info->sectorsize_bits)) >>
|
||||
SECTOR_SHIFT;
|
||||
}
|
||||
ret = bio_add_page(&bbio->bio, page, fs_info->sectorsize, pgoff);
|
||||
ASSERT(ret == fs_info->sectorsize);
|
||||
scrub_bio_add_sector(bbio, stripe, sector_nr);
|
||||
}
|
||||
if (bbio)
|
||||
scrub_submit_write_bio(sctx, stripe, bbio, dev_replace);
|
||||
@@ -1493,9 +1616,9 @@ static void fill_one_extent_info(struct btrfs_fs_info *fs_info,
|
||||
struct scrub_sector_verification *sector =
|
||||
&stripe->sectors[nr_sector];
|
||||
|
||||
set_bit(nr_sector, &stripe->extent_sector_bitmap);
|
||||
scrub_bitmap_set_bit_has_extent(stripe, nr_sector);
|
||||
if (extent_flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
|
||||
sector->is_metadata = true;
|
||||
scrub_bitmap_set_bit_is_metadata(stripe, nr_sector);
|
||||
sector->generation = extent_gen;
|
||||
}
|
||||
}
|
||||
@@ -1503,15 +1626,8 @@ static void fill_one_extent_info(struct btrfs_fs_info *fs_info,
|
||||
|
||||
static void scrub_stripe_reset_bitmaps(struct scrub_stripe *stripe)
|
||||
{
|
||||
stripe->extent_sector_bitmap = 0;
|
||||
stripe->init_error_bitmap = 0;
|
||||
stripe->init_nr_io_errors = 0;
|
||||
stripe->init_nr_csum_errors = 0;
|
||||
stripe->init_nr_meta_errors = 0;
|
||||
stripe->error_bitmap = 0;
|
||||
stripe->io_error_bitmap = 0;
|
||||
stripe->csum_error_bitmap = 0;
|
||||
stripe->meta_error_bitmap = 0;
|
||||
ASSERT(stripe->nr_sectors);
|
||||
bitmap_zero(stripe->bitmaps, scrub_bitmap_nr_last * stripe->nr_sectors);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1646,7 +1762,6 @@ static void scrub_reset_stripe(struct scrub_stripe *stripe)
|
||||
stripe->state = 0;
|
||||
|
||||
for (int i = 0; i < stripe->nr_sectors; i++) {
|
||||
stripe->sectors[i].is_metadata = false;
|
||||
stripe->sectors[i].csum = NULL;
|
||||
stripe->sectors[i].generation = 0;
|
||||
}
|
||||
@@ -1665,24 +1780,21 @@ static void scrub_submit_extent_sector_read(struct scrub_stripe *stripe)
|
||||
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
|
||||
struct btrfs_bio *bbio = NULL;
|
||||
unsigned int nr_sectors = stripe_length(stripe) >> fs_info->sectorsize_bits;
|
||||
const unsigned long has_extent = scrub_bitmap_read_has_extent(stripe);
|
||||
u64 stripe_len = BTRFS_STRIPE_LEN;
|
||||
int mirror = stripe->mirror_num;
|
||||
int i;
|
||||
|
||||
atomic_inc(&stripe->pending_io);
|
||||
|
||||
for_each_set_bit(i, &stripe->extent_sector_bitmap, stripe->nr_sectors) {
|
||||
struct page *page = scrub_stripe_get_page(stripe, i);
|
||||
unsigned int pgoff = scrub_stripe_get_page_offset(stripe, i);
|
||||
|
||||
for_each_set_bit(i, &has_extent, stripe->nr_sectors) {
|
||||
/* We're beyond the chunk boundary, no need to read anymore. */
|
||||
if (i >= nr_sectors)
|
||||
break;
|
||||
|
||||
/* The current sector cannot be merged, submit the bio. */
|
||||
if (bbio &&
|
||||
((i > 0 &&
|
||||
!test_bit(i - 1, &stripe->extent_sector_bitmap)) ||
|
||||
((i > 0 && !test_bit(i - 1, &has_extent)) ||
|
||||
bbio->bio.bi_iter.bi_size >= stripe_len)) {
|
||||
ASSERT(bbio->bio.bi_iter.bi_size);
|
||||
atomic_inc(&stripe->pending_io);
|
||||
@@ -1716,8 +1828,8 @@ static void scrub_submit_extent_sector_read(struct scrub_stripe *stripe)
|
||||
* the extent tree, then it's a preallocated
|
||||
* extent and not an error.
|
||||
*/
|
||||
set_bit(i, &stripe->io_error_bitmap);
|
||||
set_bit(i, &stripe->error_bitmap);
|
||||
scrub_bitmap_set_bit_io_error(stripe, i);
|
||||
scrub_bitmap_set_bit_error(stripe, i);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -1727,7 +1839,7 @@ static void scrub_submit_extent_sector_read(struct scrub_stripe *stripe)
|
||||
bbio->bio.bi_iter.bi_sector = logical >> SECTOR_SHIFT;
|
||||
}
|
||||
|
||||
__bio_add_page(&bbio->bio, page, fs_info->sectorsize, pgoff);
|
||||
scrub_bio_add_sector(bbio, stripe, i);
|
||||
}
|
||||
|
||||
if (bbio) {
|
||||
@@ -1765,15 +1877,8 @@ static void scrub_submit_initial_read(struct scrub_ctx *sctx,
|
||||
|
||||
bbio->bio.bi_iter.bi_sector = stripe->logical >> SECTOR_SHIFT;
|
||||
/* Read the whole range inside the chunk boundary. */
|
||||
for (unsigned int cur = 0; cur < nr_sectors; cur++) {
|
||||
struct page *page = scrub_stripe_get_page(stripe, cur);
|
||||
unsigned int pgoff = scrub_stripe_get_page_offset(stripe, cur);
|
||||
int ret;
|
||||
|
||||
ret = bio_add_page(&bbio->bio, page, fs_info->sectorsize, pgoff);
|
||||
/* We should have allocated enough bio vectors. */
|
||||
ASSERT(ret == fs_info->sectorsize);
|
||||
}
|
||||
for (unsigned int cur = 0; cur < nr_sectors; cur++)
|
||||
scrub_bio_add_sector(bbio, stripe, cur);
|
||||
atomic_inc(&stripe->pending_io);
|
||||
|
||||
/*
|
||||
@@ -1794,10 +1899,11 @@ static void scrub_submit_initial_read(struct scrub_ctx *sctx,
|
||||
|
||||
static bool stripe_has_metadata_error(struct scrub_stripe *stripe)
|
||||
{
|
||||
const unsigned long error = scrub_bitmap_read_error(stripe);
|
||||
int i;
|
||||
|
||||
for_each_set_bit(i, &stripe->error_bitmap, stripe->nr_sectors) {
|
||||
if (stripe->sectors[i].is_metadata) {
|
||||
for_each_set_bit(i, &error, stripe->nr_sectors) {
|
||||
if (scrub_bitmap_test_bit_is_metadata(stripe, i)) {
|
||||
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
|
||||
|
||||
btrfs_err(fs_info,
|
||||
@@ -1872,13 +1978,16 @@ static int flush_scrub_stripes(struct scrub_ctx *sctx)
|
||||
}
|
||||
for (int i = 0; i < nr_stripes; i++) {
|
||||
unsigned long good;
|
||||
unsigned long has_extent;
|
||||
unsigned long error;
|
||||
|
||||
stripe = &sctx->stripes[i];
|
||||
|
||||
ASSERT(stripe->dev == fs_info->dev_replace.srcdev);
|
||||
|
||||
bitmap_andnot(&good, &stripe->extent_sector_bitmap,
|
||||
&stripe->error_bitmap, stripe->nr_sectors);
|
||||
has_extent = scrub_bitmap_read_has_extent(stripe);
|
||||
error = scrub_bitmap_read_error(stripe);
|
||||
bitmap_andnot(&good, &has_extent, &error, stripe->nr_sectors);
|
||||
scrub_write_sectors(sctx, stripe, good, true);
|
||||
}
|
||||
}
|
||||
@@ -2012,7 +2121,7 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
|
||||
/* Check if all data stripes are empty. */
|
||||
for (int i = 0; i < data_stripes; i++) {
|
||||
stripe = &sctx->raid56_data_stripes[i];
|
||||
if (!bitmap_empty(&stripe->extent_sector_bitmap, stripe->nr_sectors)) {
|
||||
if (!scrub_bitmap_empty_has_extent(stripe)) {
|
||||
all_empty = false;
|
||||
break;
|
||||
}
|
||||
@@ -2044,15 +2153,18 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
|
||||
*/
|
||||
for (int i = 0; i < data_stripes; i++) {
|
||||
unsigned long error;
|
||||
unsigned long has_extent;
|
||||
|
||||
stripe = &sctx->raid56_data_stripes[i];
|
||||
|
||||
error = scrub_bitmap_read_error(stripe);
|
||||
has_extent = scrub_bitmap_read_has_extent(stripe);
|
||||
|
||||
/*
|
||||
* We should only check the errors where there is an extent.
|
||||
* As we may hit an empty data stripe while it's missing.
|
||||
*/
|
||||
bitmap_and(&error, &stripe->error_bitmap,
|
||||
&stripe->extent_sector_bitmap, stripe->nr_sectors);
|
||||
bitmap_and(&error, &error, &has_extent, stripe->nr_sectors);
|
||||
if (!bitmap_empty(&error, stripe->nr_sectors)) {
|
||||
btrfs_err(fs_info,
|
||||
"unrepaired sectors detected, full stripe %llu data stripe %u errors %*pbl",
|
||||
@@ -2061,8 +2173,8 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
bitmap_or(&extent_bitmap, &extent_bitmap,
|
||||
&stripe->extent_sector_bitmap, stripe->nr_sectors);
|
||||
bitmap_or(&extent_bitmap, &extent_bitmap, &has_extent,
|
||||
stripe->nr_sectors);
|
||||
}
|
||||
|
||||
/* Now we can check and regenerate the P/Q stripe. */
|
||||
|
||||
+17
-71
@@ -383,11 +383,11 @@ static void inconsistent_snapshot_error(struct send_ctx *sctx,
|
||||
result_string = "updated";
|
||||
break;
|
||||
case BTRFS_COMPARE_TREE_SAME:
|
||||
ASSERT(0);
|
||||
DEBUG_WARN("no change between trees");
|
||||
result_string = "unchanged";
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
DEBUG_WARN("unexpected comparison result %d", result);
|
||||
result_string = "unexpected";
|
||||
}
|
||||
|
||||
@@ -816,11 +816,8 @@ static int send_cmd(struct send_ctx *sctx)
|
||||
static int send_rename(struct send_ctx *sctx,
|
||||
struct fs_path *from, struct fs_path *to)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
|
||||
int ret;
|
||||
|
||||
btrfs_debug(fs_info, "send_rename %s -> %s", from->start, to->start);
|
||||
|
||||
ret = begin_cmd(sctx, BTRFS_SEND_C_RENAME);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -840,11 +837,8 @@ tlv_put_failure:
|
||||
static int send_link(struct send_ctx *sctx,
|
||||
struct fs_path *path, struct fs_path *lnk)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
|
||||
int ret;
|
||||
|
||||
btrfs_debug(fs_info, "send_link %s -> %s", path->start, lnk->start);
|
||||
|
||||
ret = begin_cmd(sctx, BTRFS_SEND_C_LINK);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -863,11 +857,8 @@ tlv_put_failure:
|
||||
*/
|
||||
static int send_unlink(struct send_ctx *sctx, struct fs_path *path)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
|
||||
int ret;
|
||||
|
||||
btrfs_debug(fs_info, "send_unlink %s", path->start);
|
||||
|
||||
ret = begin_cmd(sctx, BTRFS_SEND_C_UNLINK);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -885,11 +876,8 @@ tlv_put_failure:
|
||||
*/
|
||||
static int send_rmdir(struct send_ctx *sctx, struct fs_path *path)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
|
||||
int ret;
|
||||
|
||||
btrfs_debug(fs_info, "send_rmdir %s", path->start);
|
||||
|
||||
ret = begin_cmd(sctx, BTRFS_SEND_C_RMDIR);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -1573,7 +1561,6 @@ static int find_extent_clone(struct send_ctx *sctx,
|
||||
struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
|
||||
int ret;
|
||||
int extent_type;
|
||||
u64 logical;
|
||||
u64 disk_byte;
|
||||
u64 num_bytes;
|
||||
struct btrfs_file_extent_item *fi;
|
||||
@@ -1604,7 +1591,6 @@ static int find_extent_clone(struct send_ctx *sctx,
|
||||
|
||||
compressed = btrfs_file_extent_compression(eb, fi);
|
||||
num_bytes = btrfs_file_extent_num_bytes(eb, fi);
|
||||
logical = disk_byte + btrfs_file_extent_offset(eb, fi);
|
||||
|
||||
/*
|
||||
* Setup the clone roots.
|
||||
@@ -1686,14 +1672,8 @@ static int find_extent_clone(struct send_ctx *sctx,
|
||||
}
|
||||
up_read(&fs_info->commit_root_sem);
|
||||
|
||||
btrfs_debug(fs_info,
|
||||
"find_extent_clone: data_offset=%llu, ino=%llu, num_bytes=%llu, logical=%llu",
|
||||
data_offset, ino, num_bytes, logical);
|
||||
|
||||
if (!backref_ctx.found) {
|
||||
btrfs_debug(fs_info, "no clones found");
|
||||
if (!backref_ctx.found)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
cur_clone_root = NULL;
|
||||
for (i = 0; i < sctx->clone_roots_cnt; i++) {
|
||||
@@ -2631,12 +2611,9 @@ static void free_path_for_command(const struct send_ctx *sctx, struct fs_path *p
|
||||
|
||||
static int send_truncate(struct send_ctx *sctx, u64 ino, u64 gen, u64 size)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
|
||||
int ret = 0;
|
||||
struct fs_path *p;
|
||||
|
||||
btrfs_debug(fs_info, "send_truncate %llu size=%llu", ino, size);
|
||||
|
||||
p = get_path_for_command(sctx, ino, gen);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
@@ -2658,12 +2635,9 @@ out:
|
||||
|
||||
static int send_chmod(struct send_ctx *sctx, u64 ino, u64 gen, u64 mode)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
|
||||
int ret = 0;
|
||||
struct fs_path *p;
|
||||
|
||||
btrfs_debug(fs_info, "send_chmod %llu mode=%llu", ino, mode);
|
||||
|
||||
p = get_path_for_command(sctx, ino, gen);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
@@ -2685,15 +2659,12 @@ out:
|
||||
|
||||
static int send_fileattr(struct send_ctx *sctx, u64 ino, u64 gen, u64 fileattr)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
|
||||
int ret = 0;
|
||||
struct fs_path *p;
|
||||
|
||||
if (sctx->proto < 2)
|
||||
return 0;
|
||||
|
||||
btrfs_debug(fs_info, "send_fileattr %llu fileattr=%llu", ino, fileattr);
|
||||
|
||||
p = get_path_for_command(sctx, ino, gen);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
@@ -2715,13 +2686,9 @@ out:
|
||||
|
||||
static int send_chown(struct send_ctx *sctx, u64 ino, u64 gen, u64 uid, u64 gid)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
|
||||
int ret = 0;
|
||||
struct fs_path *p;
|
||||
|
||||
btrfs_debug(fs_info, "send_chown %llu uid=%llu, gid=%llu",
|
||||
ino, uid, gid);
|
||||
|
||||
p = get_path_for_command(sctx, ino, gen);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
@@ -2744,7 +2711,6 @@ out:
|
||||
|
||||
static int send_utimes(struct send_ctx *sctx, u64 ino, u64 gen)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
|
||||
int ret = 0;
|
||||
struct fs_path *p = NULL;
|
||||
struct btrfs_inode_item *ii;
|
||||
@@ -2753,8 +2719,6 @@ static int send_utimes(struct send_ctx *sctx, u64 ino, u64 gen)
|
||||
struct btrfs_key key;
|
||||
int slot;
|
||||
|
||||
btrfs_debug(fs_info, "send_utimes %llu", ino);
|
||||
|
||||
p = get_path_for_command(sctx, ino, gen);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
@@ -2861,7 +2825,6 @@ static int trim_dir_utimes_cache(struct send_ctx *sctx)
|
||||
*/
|
||||
static int send_create_inode(struct send_ctx *sctx, u64 ino)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
|
||||
int ret = 0;
|
||||
struct fs_path *p;
|
||||
int cmd;
|
||||
@@ -2870,8 +2833,6 @@ static int send_create_inode(struct send_ctx *sctx, u64 ino)
|
||||
u64 mode;
|
||||
u64 rdev;
|
||||
|
||||
btrfs_debug(fs_info, "send_create_inode %llu", ino);
|
||||
|
||||
p = fs_path_alloc();
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
@@ -3098,7 +3059,7 @@ static void __free_recorded_refs(struct list_head *head)
|
||||
struct recorded_ref *cur;
|
||||
|
||||
while (!list_empty(head)) {
|
||||
cur = list_entry(head->next, struct recorded_ref, list);
|
||||
cur = list_first_entry(head, struct recorded_ref, list);
|
||||
recorded_ref_free(cur);
|
||||
}
|
||||
}
|
||||
@@ -4224,8 +4185,6 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
|
||||
bool orphanized_dir = false;
|
||||
bool orphanized_ancestor = false;
|
||||
|
||||
btrfs_debug(fs_info, "process_recorded_refs %llu", sctx->cur_ino);
|
||||
|
||||
/*
|
||||
* This should never happen as the root dir always has the same ref
|
||||
* which is always '..'
|
||||
@@ -4560,8 +4519,7 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
|
||||
/*
|
||||
* We have a moved dir. Add the old parent to check_dirs
|
||||
*/
|
||||
cur = list_entry(sctx->deleted_refs.next, struct recorded_ref,
|
||||
list);
|
||||
cur = list_first_entry(&sctx->deleted_refs, struct recorded_ref, list);
|
||||
ret = dup_ref(cur, &check_dirs);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
@@ -5263,10 +5221,9 @@ static int put_file_data(struct send_ctx *sctx, u64 offset, u32 len)
|
||||
{
|
||||
struct btrfs_root *root = sctx->send_root;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
struct folio *folio;
|
||||
pgoff_t index = offset >> PAGE_SHIFT;
|
||||
pgoff_t last_index;
|
||||
unsigned pg_offset = offset_in_page(offset);
|
||||
u64 cur = offset;
|
||||
const u64 end = offset + len;
|
||||
const pgoff_t last_index = ((end - 1) >> PAGE_SHIFT);
|
||||
struct address_space *mapping = sctx->cur_inode->i_mapping;
|
||||
int ret;
|
||||
|
||||
@@ -5274,13 +5231,12 @@ static int put_file_data(struct send_ctx *sctx, u64 offset, u32 len)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
last_index = (offset + len - 1) >> PAGE_SHIFT;
|
||||
while (cur < end) {
|
||||
pgoff_t index = (cur >> PAGE_SHIFT);
|
||||
unsigned int cur_len;
|
||||
unsigned int pg_offset;
|
||||
struct folio *folio;
|
||||
|
||||
while (index <= last_index) {
|
||||
unsigned cur_len = min_t(unsigned, len,
|
||||
PAGE_SIZE - pg_offset);
|
||||
|
||||
again:
|
||||
folio = filemap_lock_folio(mapping, index);
|
||||
if (IS_ERR(folio)) {
|
||||
page_cache_sync_readahead(mapping,
|
||||
@@ -5293,8 +5249,8 @@ again:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WARN_ON(folio_order(folio));
|
||||
pg_offset = offset_in_folio(folio, cur);
|
||||
cur_len = min_t(unsigned int, end - cur, folio_size(folio) - pg_offset);
|
||||
|
||||
if (folio_test_readahead(folio))
|
||||
page_cache_async_readahead(mapping, &sctx->ra, NULL, folio,
|
||||
@@ -5316,7 +5272,7 @@ again:
|
||||
if (folio->mapping != mapping) {
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
goto again;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5324,9 +5280,7 @@ again:
|
||||
pg_offset, cur_len);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
index++;
|
||||
pg_offset = 0;
|
||||
len -= cur_len;
|
||||
cur += cur_len;
|
||||
sctx->send_size += cur_len;
|
||||
}
|
||||
|
||||
@@ -5339,12 +5293,9 @@ again:
|
||||
*/
|
||||
static int send_write(struct send_ctx *sctx, u64 offset, u32 len)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = sctx->send_root->fs_info;
|
||||
int ret = 0;
|
||||
struct fs_path *p;
|
||||
|
||||
btrfs_debug(fs_info, "send_write offset=%llu, len=%d", offset, len);
|
||||
|
||||
p = get_cur_inode_path(sctx);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
@@ -5377,11 +5328,6 @@ static int send_clone(struct send_ctx *sctx,
|
||||
struct fs_path *cur_inode_path;
|
||||
u64 gen;
|
||||
|
||||
btrfs_debug(sctx->send_root->fs_info,
|
||||
"send_clone offset=%llu, len=%d, clone_root=%llu, clone_inode=%llu, clone_offset=%llu",
|
||||
offset, len, btrfs_root_id(clone_root->root),
|
||||
clone_root->ino, clone_root->offset);
|
||||
|
||||
cur_inode_path = get_cur_inode_path(sctx);
|
||||
if (IS_ERR(cur_inode_path))
|
||||
return PTR_ERR(cur_inode_path);
|
||||
|
||||
+120
-54
@@ -50,11 +50,11 @@
|
||||
* num_bytes we want to reserve.
|
||||
*
|
||||
* ->reserve
|
||||
* space_info->bytes_may_reserve += num_bytes
|
||||
* space_info->bytes_may_use += num_bytes
|
||||
*
|
||||
* ->extent allocation
|
||||
* Call btrfs_add_reserved_bytes() which does
|
||||
* space_info->bytes_may_reserve -= num_bytes
|
||||
* space_info->bytes_may_use -= num_bytes
|
||||
* space_info->bytes_reserved += extent_bytes
|
||||
*
|
||||
* ->insert reference
|
||||
@@ -234,19 +234,11 @@ void btrfs_update_space_info_chunk_size(struct btrfs_space_info *space_info,
|
||||
WRITE_ONCE(space_info->chunk_size, chunk_size);
|
||||
}
|
||||
|
||||
static int create_space_info(struct btrfs_fs_info *info, u64 flags)
|
||||
static void init_space_info(struct btrfs_fs_info *info,
|
||||
struct btrfs_space_info *space_info, u64 flags)
|
||||
{
|
||||
|
||||
struct btrfs_space_info *space_info;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
space_info = kzalloc(sizeof(*space_info), GFP_NOFS);
|
||||
if (!space_info)
|
||||
return -ENOMEM;
|
||||
|
||||
space_info->fs_info = info;
|
||||
for (i = 0; i < BTRFS_NR_RAID_TYPES; i++)
|
||||
for (int i = 0; i < BTRFS_NR_RAID_TYPES; i++)
|
||||
INIT_LIST_HEAD(&space_info->block_groups[i]);
|
||||
init_rwsem(&space_info->groups_sem);
|
||||
spin_lock_init(&space_info->lock);
|
||||
@@ -257,9 +249,64 @@ static int create_space_info(struct btrfs_fs_info *info, u64 flags)
|
||||
INIT_LIST_HEAD(&space_info->priority_tickets);
|
||||
space_info->clamp = 1;
|
||||
btrfs_update_space_info_chunk_size(space_info, calc_chunk_size(info, flags));
|
||||
space_info->subgroup_id = BTRFS_SUB_GROUP_PRIMARY;
|
||||
|
||||
if (btrfs_is_zoned(info))
|
||||
space_info->bg_reclaim_threshold = BTRFS_DEFAULT_ZONED_RECLAIM_THRESH;
|
||||
}
|
||||
|
||||
static int create_space_info_sub_group(struct btrfs_space_info *parent, u64 flags,
|
||||
enum btrfs_space_info_sub_group id, int index)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = parent->fs_info;
|
||||
struct btrfs_space_info *sub_group;
|
||||
int ret;
|
||||
|
||||
ASSERT(parent->subgroup_id == BTRFS_SUB_GROUP_PRIMARY);
|
||||
ASSERT(id != BTRFS_SUB_GROUP_PRIMARY);
|
||||
|
||||
sub_group = kzalloc(sizeof(*sub_group), GFP_NOFS);
|
||||
if (!sub_group)
|
||||
return -ENOMEM;
|
||||
|
||||
init_space_info(fs_info, sub_group, flags);
|
||||
parent->sub_group[index] = sub_group;
|
||||
sub_group->parent = parent;
|
||||
sub_group->subgroup_id = id;
|
||||
|
||||
ret = btrfs_sysfs_add_space_info_type(fs_info, sub_group);
|
||||
if (ret) {
|
||||
kfree(sub_group);
|
||||
parent->sub_group[index] = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int create_space_info(struct btrfs_fs_info *info, u64 flags)
|
||||
{
|
||||
|
||||
struct btrfs_space_info *space_info;
|
||||
int ret = 0;
|
||||
|
||||
space_info = kzalloc(sizeof(*space_info), GFP_NOFS);
|
||||
if (!space_info)
|
||||
return -ENOMEM;
|
||||
|
||||
init_space_info(info, space_info, flags);
|
||||
|
||||
if (btrfs_is_zoned(info)) {
|
||||
if (flags & BTRFS_BLOCK_GROUP_DATA)
|
||||
ret = create_space_info_sub_group(space_info, flags,
|
||||
BTRFS_SUB_GROUP_DATA_RELOC,
|
||||
0);
|
||||
else if (flags & BTRFS_BLOCK_GROUP_METADATA)
|
||||
ret = create_space_info_sub_group(space_info, flags,
|
||||
BTRFS_SUB_GROUP_TREELOG,
|
||||
0);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = btrfs_sysfs_add_space_info_type(info, space_info);
|
||||
if (ret)
|
||||
@@ -312,31 +359,29 @@ out:
|
||||
void btrfs_add_bg_to_space_info(struct btrfs_fs_info *info,
|
||||
struct btrfs_block_group *block_group)
|
||||
{
|
||||
struct btrfs_space_info *found;
|
||||
struct btrfs_space_info *space_info = block_group->space_info;
|
||||
int factor, index;
|
||||
|
||||
factor = btrfs_bg_type_to_factor(block_group->flags);
|
||||
|
||||
found = btrfs_find_space_info(info, block_group->flags);
|
||||
ASSERT(found);
|
||||
spin_lock(&found->lock);
|
||||
found->total_bytes += block_group->length;
|
||||
found->disk_total += block_group->length * factor;
|
||||
found->bytes_used += block_group->used;
|
||||
found->disk_used += block_group->used * factor;
|
||||
found->bytes_readonly += block_group->bytes_super;
|
||||
btrfs_space_info_update_bytes_zone_unusable(found, block_group->zone_unusable);
|
||||
spin_lock(&space_info->lock);
|
||||
space_info->total_bytes += block_group->length;
|
||||
space_info->disk_total += block_group->length * factor;
|
||||
space_info->bytes_used += block_group->used;
|
||||
space_info->disk_used += block_group->used * factor;
|
||||
space_info->bytes_readonly += block_group->bytes_super;
|
||||
btrfs_space_info_update_bytes_zone_unusable(space_info, block_group->zone_unusable);
|
||||
if (block_group->length > 0)
|
||||
found->full = 0;
|
||||
btrfs_try_granting_tickets(info, found);
|
||||
spin_unlock(&found->lock);
|
||||
space_info->full = 0;
|
||||
btrfs_try_granting_tickets(info, space_info);
|
||||
spin_unlock(&space_info->lock);
|
||||
|
||||
block_group->space_info = found;
|
||||
block_group->space_info = space_info;
|
||||
|
||||
index = btrfs_bg_flags_to_raid_index(block_group->flags);
|
||||
down_write(&found->groups_sem);
|
||||
list_add_tail(&block_group->list, &found->block_groups[index]);
|
||||
up_write(&found->groups_sem);
|
||||
down_write(&space_info->groups_sem);
|
||||
list_add_tail(&block_group->list, &space_info->block_groups[index]);
|
||||
up_write(&space_info->groups_sem);
|
||||
}
|
||||
|
||||
struct btrfs_space_info *btrfs_find_space_info(struct btrfs_fs_info *info,
|
||||
@@ -556,8 +601,9 @@ static void __btrfs_dump_space_info(const struct btrfs_fs_info *fs_info,
|
||||
lockdep_assert_held(&info->lock);
|
||||
|
||||
/* The free space could be negative in case of overcommit */
|
||||
btrfs_info(fs_info, "space_info %s has %lld free, is %sfull",
|
||||
flag_str,
|
||||
btrfs_info(fs_info,
|
||||
"space_info %s (sub-group id %d) has %lld free, is %sfull",
|
||||
flag_str, info->subgroup_id,
|
||||
(s64)(info->total_bytes - btrfs_space_info_used(info, true)),
|
||||
info->full ? "" : "not ");
|
||||
btrfs_info(fs_info,
|
||||
@@ -812,7 +858,7 @@ static void flush_space(struct btrfs_fs_info *fs_info,
|
||||
ret = PTR_ERR(trans);
|
||||
break;
|
||||
}
|
||||
ret = btrfs_chunk_alloc(trans,
|
||||
ret = btrfs_chunk_alloc(trans, space_info,
|
||||
btrfs_get_alloc_profile(fs_info, space_info->flags),
|
||||
(state == ALLOC_CHUNK) ? CHUNK_ALLOC_NO_FORCE :
|
||||
CHUNK_ALLOC_FORCE);
|
||||
@@ -1083,23 +1129,15 @@ static bool maybe_fail_all_tickets(struct btrfs_fs_info *fs_info,
|
||||
return (tickets_id != space_info->tickets_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is for normal flushers, we can wait all goddamned day if we want to. We
|
||||
* will loop and continuously try to flush as long as we are making progress.
|
||||
* We count progress as clearing off tickets each time we have to loop.
|
||||
*/
|
||||
static void btrfs_async_reclaim_metadata_space(struct work_struct *work)
|
||||
static void do_async_reclaim_metadata_space(struct btrfs_space_info *space_info)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info;
|
||||
struct btrfs_space_info *space_info;
|
||||
struct btrfs_fs_info *fs_info = space_info->fs_info;
|
||||
u64 to_reclaim;
|
||||
enum btrfs_flush_state flush_state;
|
||||
int commit_cycles = 0;
|
||||
u64 last_tickets_id;
|
||||
enum btrfs_flush_state final_state;
|
||||
|
||||
fs_info = container_of(work, struct btrfs_fs_info, async_reclaim_work);
|
||||
space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
|
||||
if (btrfs_is_zoned(fs_info))
|
||||
final_state = RESET_ZONES;
|
||||
else
|
||||
@@ -1173,6 +1211,25 @@ static void btrfs_async_reclaim_metadata_space(struct work_struct *work)
|
||||
} while (flush_state <= final_state);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is for normal flushers, it can wait as much time as needed. We will
|
||||
* loop and continuously try to flush as long as we are making progress. We
|
||||
* count progress as clearing off tickets each time we have to loop.
|
||||
*/
|
||||
static void btrfs_async_reclaim_metadata_space(struct work_struct *work)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info;
|
||||
struct btrfs_space_info *space_info;
|
||||
|
||||
fs_info = container_of(work, struct btrfs_fs_info, async_reclaim_work);
|
||||
space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
|
||||
do_async_reclaim_metadata_space(space_info);
|
||||
for (int i = 0; i < BTRFS_SPACE_INFO_SUB_GROUP_MAX; i++) {
|
||||
if (space_info->sub_group[i])
|
||||
do_async_reclaim_metadata_space(space_info->sub_group[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This handles pre-flushing of metadata space before we get to the point that
|
||||
* we need to start blocking threads on tickets. The logic here is different
|
||||
@@ -1318,16 +1375,12 @@ static const enum btrfs_flush_state data_flush_states[] = {
|
||||
ALLOC_CHUNK_FORCE,
|
||||
};
|
||||
|
||||
static void btrfs_async_reclaim_data_space(struct work_struct *work)
|
||||
static void do_async_reclaim_data_space(struct btrfs_space_info *space_info)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info;
|
||||
struct btrfs_space_info *space_info;
|
||||
struct btrfs_fs_info *fs_info = space_info->fs_info;
|
||||
u64 last_tickets_id;
|
||||
enum btrfs_flush_state flush_state = 0;
|
||||
|
||||
fs_info = container_of(work, struct btrfs_fs_info, async_data_reclaim_work);
|
||||
space_info = fs_info->data_sinfo;
|
||||
|
||||
spin_lock(&space_info->lock);
|
||||
if (list_empty(&space_info->tickets)) {
|
||||
space_info->flush = 0;
|
||||
@@ -1395,6 +1448,19 @@ aborted_fs:
|
||||
spin_unlock(&space_info->lock);
|
||||
}
|
||||
|
||||
static void btrfs_async_reclaim_data_space(struct work_struct *work)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info;
|
||||
struct btrfs_space_info *space_info;
|
||||
|
||||
fs_info = container_of(work, struct btrfs_fs_info, async_data_reclaim_work);
|
||||
space_info = fs_info->data_sinfo;
|
||||
do_async_reclaim_data_space(space_info);
|
||||
for (int i = 0; i < BTRFS_SPACE_INFO_SUB_GROUP_MAX; i++)
|
||||
if (space_info->sub_group[i])
|
||||
do_async_reclaim_data_space(space_info->sub_group[i]);
|
||||
}
|
||||
|
||||
void btrfs_init_async_reclaim_work(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
INIT_WORK(&fs_info->async_reclaim_work, btrfs_async_reclaim_metadata_space);
|
||||
@@ -1836,10 +1902,10 @@ int btrfs_reserve_metadata_bytes(struct btrfs_fs_info *fs_info,
|
||||
* This will reserve bytes from the data space info. If there is not enough
|
||||
* space then we will attempt to flush space as specified by flush.
|
||||
*/
|
||||
int btrfs_reserve_data_bytes(struct btrfs_fs_info *fs_info, u64 bytes,
|
||||
int btrfs_reserve_data_bytes(struct btrfs_space_info *space_info, u64 bytes,
|
||||
enum btrfs_reserve_flush_enum flush)
|
||||
{
|
||||
struct btrfs_space_info *data_sinfo = fs_info->data_sinfo;
|
||||
struct btrfs_fs_info *fs_info = space_info->fs_info;
|
||||
int ret;
|
||||
|
||||
ASSERT(flush == BTRFS_RESERVE_FLUSH_DATA ||
|
||||
@@ -1847,12 +1913,12 @@ int btrfs_reserve_data_bytes(struct btrfs_fs_info *fs_info, u64 bytes,
|
||||
flush == BTRFS_RESERVE_NO_FLUSH);
|
||||
ASSERT(!current->journal_info || flush != BTRFS_RESERVE_FLUSH_DATA);
|
||||
|
||||
ret = __reserve_bytes(fs_info, data_sinfo, bytes, flush);
|
||||
ret = __reserve_bytes(fs_info, space_info, bytes, flush);
|
||||
if (ret == -ENOSPC) {
|
||||
trace_btrfs_space_reservation(fs_info, "space_info:enospc",
|
||||
data_sinfo->flags, bytes, 1);
|
||||
space_info->flags, bytes, 1);
|
||||
if (btrfs_test_opt(fs_info, ENOSPC_DEBUG))
|
||||
btrfs_dump_space_info(fs_info, data_sinfo, bytes, 0);
|
||||
btrfs_dump_space_info(fs_info, space_info, bytes, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
+11
-1
@@ -98,8 +98,18 @@ enum btrfs_flush_state {
|
||||
RESET_ZONES = 12,
|
||||
};
|
||||
|
||||
enum btrfs_space_info_sub_group {
|
||||
BTRFS_SUB_GROUP_PRIMARY,
|
||||
BTRFS_SUB_GROUP_DATA_RELOC,
|
||||
BTRFS_SUB_GROUP_TREELOG,
|
||||
};
|
||||
|
||||
#define BTRFS_SPACE_INFO_SUB_GROUP_MAX 1
|
||||
struct btrfs_space_info {
|
||||
struct btrfs_fs_info *fs_info;
|
||||
struct btrfs_space_info *parent;
|
||||
struct btrfs_space_info *sub_group[BTRFS_SPACE_INFO_SUB_GROUP_MAX];
|
||||
int subgroup_id;
|
||||
spinlock_t lock;
|
||||
|
||||
u64 total_bytes; /* total bytes in the space,
|
||||
@@ -288,7 +298,7 @@ static inline void btrfs_space_info_free_bytes_may_use(
|
||||
btrfs_try_granting_tickets(space_info->fs_info, space_info);
|
||||
spin_unlock(&space_info->lock);
|
||||
}
|
||||
int btrfs_reserve_data_bytes(struct btrfs_fs_info *fs_info, u64 bytes,
|
||||
int btrfs_reserve_data_bytes(struct btrfs_space_info *space_info, u64 bytes,
|
||||
enum btrfs_reserve_flush_enum flush);
|
||||
void btrfs_dump_space_info_for_trans_abort(struct btrfs_fs_info *fs_info);
|
||||
void btrfs_init_async_reclaim_work(struct btrfs_fs_info *fs_info);
|
||||
|
||||
+2
-4
@@ -69,7 +69,8 @@ int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_subpage *subpage;
|
||||
|
||||
/* For metadata we don't support large folio yet. */
|
||||
ASSERT(!folio_test_large(folio));
|
||||
if (type == BTRFS_SUBPAGE_METADATA)
|
||||
ASSERT(!folio_test_large(folio));
|
||||
|
||||
/*
|
||||
* We have cases like a dummy extent buffer page, which is not mapped
|
||||
@@ -181,9 +182,6 @@ void btrfs_folio_dec_eb_refs(const struct btrfs_fs_info *fs_info, struct folio *
|
||||
static void btrfs_subpage_assert(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio, u64 start, u32 len)
|
||||
{
|
||||
/* For subpage support, the folio must be single page. */
|
||||
ASSERT(folio_order(folio) == 0);
|
||||
|
||||
/* Basic checks */
|
||||
ASSERT(folio_test_private(folio) && folio_get_private(folio));
|
||||
ASSERT(IS_ALIGNED(start, fs_info->sectorsize) &&
|
||||
|
||||
+8
-16
@@ -125,7 +125,6 @@ enum {
|
||||
/* Rescue options */
|
||||
Opt_rescue,
|
||||
Opt_usebackuproot,
|
||||
Opt_nologreplay,
|
||||
|
||||
/* Debugging options */
|
||||
Opt_enospc_debug,
|
||||
@@ -246,8 +245,6 @@ static const struct fs_parameter_spec btrfs_fs_parameters[] = {
|
||||
|
||||
/* Rescue options. */
|
||||
fsparam_enum("rescue", Opt_rescue, btrfs_parameter_rescue),
|
||||
/* Deprecated, with alias rescue=nologreplay */
|
||||
__fsparam(NULL, "nologreplay", Opt_nologreplay, fs_param_deprecated, NULL),
|
||||
/* Deprecated, with alias rescue=usebackuproot */
|
||||
__fsparam(NULL, "usebackuproot", Opt_usebackuproot, fs_param_deprecated, NULL),
|
||||
/* For compatibility only, alias for "rescue=nologreplay". */
|
||||
@@ -449,11 +446,6 @@ static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
||||
else
|
||||
btrfs_clear_opt(ctx->mount_opt, NOTREELOG);
|
||||
break;
|
||||
case Opt_nologreplay:
|
||||
btrfs_warn(NULL,
|
||||
"'nologreplay' is deprecated, use 'rescue=nologreplay' instead");
|
||||
btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY);
|
||||
break;
|
||||
case Opt_norecovery:
|
||||
btrfs_info(NULL,
|
||||
"'norecovery' is for compatibility only, recommended to use 'rescue=nologreplay'");
|
||||
@@ -1152,11 +1144,11 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
|
||||
/*
|
||||
* subvolumes are identified by ino 256
|
||||
*/
|
||||
static inline int is_subvolume_inode(struct inode *inode)
|
||||
static inline bool is_subvolume_inode(struct inode *inode)
|
||||
{
|
||||
if (inode && inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
|
||||
return 1;
|
||||
return 0;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
|
||||
@@ -2296,7 +2288,7 @@ static int check_dev_super(struct btrfs_device *dev)
|
||||
return 0;
|
||||
|
||||
/* Only need to check the primary super block. */
|
||||
sb = btrfs_read_dev_one_super(dev->bdev, 0, true);
|
||||
sb = btrfs_read_disk_super(dev->bdev, 0, true);
|
||||
if (IS_ERR(sb))
|
||||
return PTR_ERR(sb);
|
||||
|
||||
@@ -2529,8 +2521,8 @@ static const struct init_sequence mod_init_seq[] = {
|
||||
.init_func = btrfs_free_space_init,
|
||||
.exit_func = btrfs_free_space_exit,
|
||||
}, {
|
||||
.init_func = extent_state_init_cachep,
|
||||
.exit_func = extent_state_free_cachep,
|
||||
.init_func = btrfs_extent_state_init_cachep,
|
||||
.exit_func = btrfs_extent_state_free_cachep,
|
||||
}, {
|
||||
.init_func = extent_buffer_init_cachep,
|
||||
.exit_func = extent_buffer_free_cachep,
|
||||
@@ -2538,8 +2530,8 @@ static const struct init_sequence mod_init_seq[] = {
|
||||
.init_func = btrfs_bioset_init,
|
||||
.exit_func = btrfs_bioset_exit,
|
||||
}, {
|
||||
.init_func = extent_map_init,
|
||||
.exit_func = extent_map_exit,
|
||||
.init_func = btrfs_extent_map_init,
|
||||
.exit_func = btrfs_extent_map_exit,
|
||||
#ifdef CONFIG_BTRFS_EXPERIMENTAL
|
||||
}, {
|
||||
.init_func = btrfs_read_policy_init,
|
||||
|
||||
+23
-4
@@ -1930,16 +1930,35 @@ void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info)
|
||||
kobject_put(&space_info->kobj);
|
||||
}
|
||||
|
||||
static const char *alloc_name(u64 flags)
|
||||
static const char *alloc_name(struct btrfs_space_info *space_info)
|
||||
{
|
||||
u64 flags = space_info->flags;
|
||||
|
||||
switch (flags) {
|
||||
case BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA:
|
||||
return "mixed";
|
||||
case BTRFS_BLOCK_GROUP_METADATA:
|
||||
return "metadata";
|
||||
switch (space_info->subgroup_id) {
|
||||
case BTRFS_SUB_GROUP_PRIMARY:
|
||||
return "metadata";
|
||||
case BTRFS_SUB_GROUP_TREELOG:
|
||||
return "metadata-treelog";
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return "metadata (unknown sub-group)";
|
||||
}
|
||||
case BTRFS_BLOCK_GROUP_DATA:
|
||||
return "data";
|
||||
switch (space_info->subgroup_id) {
|
||||
case BTRFS_SUB_GROUP_PRIMARY:
|
||||
return "data";
|
||||
case BTRFS_SUB_GROUP_DATA_RELOC:
|
||||
return "data-reloc";
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return "data (unknown sub-group)";
|
||||
}
|
||||
case BTRFS_BLOCK_GROUP_SYSTEM:
|
||||
ASSERT(space_info->subgroup_id == BTRFS_SUB_GROUP_PRIMARY);
|
||||
return "system";
|
||||
default:
|
||||
WARN_ON(1);
|
||||
@@ -1958,7 +1977,7 @@ int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info,
|
||||
|
||||
ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype,
|
||||
fs_info->space_info_kobj, "%s",
|
||||
alloc_name(space_info->flags));
|
||||
alloc_name(space_info));
|
||||
if (ret) {
|
||||
kobject_put(&space_info->kobj);
|
||||
return ret;
|
||||
|
||||
@@ -102,7 +102,7 @@ struct btrfs_device *btrfs_alloc_dummy_device(struct btrfs_fs_info *fs_info)
|
||||
if (!dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
extent_io_tree_init(fs_info, &dev->alloc_state, 0);
|
||||
btrfs_extent_io_tree_init(fs_info, &dev->alloc_state, 0);
|
||||
INIT_LIST_HEAD(&dev->dev_list);
|
||||
list_add(&dev->dev_list, &fs_info->fs_devices->devices);
|
||||
|
||||
@@ -111,7 +111,7 @@ struct btrfs_device *btrfs_alloc_dummy_device(struct btrfs_fs_info *fs_info)
|
||||
|
||||
static void btrfs_free_dummy_device(struct btrfs_device *dev)
|
||||
{
|
||||
extent_io_tree_release(&dev->alloc_state);
|
||||
btrfs_extent_io_tree_release(&dev->alloc_state);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
@@ -157,9 +157,9 @@ struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(u32 nodesize, u32 sectorsize)
|
||||
|
||||
void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
struct radix_tree_iter iter;
|
||||
void **slot;
|
||||
struct btrfs_device *dev, *tmp;
|
||||
struct extent_buffer *eb;
|
||||
unsigned long index;
|
||||
|
||||
if (!fs_info)
|
||||
return;
|
||||
@@ -169,25 +169,13 @@ void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
|
||||
|
||||
test_mnt->mnt_sb->s_fs_info = NULL;
|
||||
|
||||
spin_lock(&fs_info->buffer_lock);
|
||||
radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) {
|
||||
struct extent_buffer *eb;
|
||||
|
||||
eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock);
|
||||
if (!eb)
|
||||
continue;
|
||||
/* Shouldn't happen but that kind of thinking creates CVE's */
|
||||
if (radix_tree_exception(eb)) {
|
||||
if (radix_tree_deref_retry(eb))
|
||||
slot = radix_tree_iter_retry(&iter);
|
||||
continue;
|
||||
}
|
||||
slot = radix_tree_iter_resume(slot, &iter);
|
||||
spin_unlock(&fs_info->buffer_lock);
|
||||
free_extent_buffer_stale(eb);
|
||||
spin_lock(&fs_info->buffer_lock);
|
||||
xa_lock_irq(&fs_info->buffer_tree);
|
||||
xa_for_each(&fs_info->buffer_tree, index, eb) {
|
||||
xa_unlock_irq(&fs_info->buffer_tree);
|
||||
free_extent_buffer(eb);
|
||||
xa_lock_irq(&fs_info->buffer_tree);
|
||||
}
|
||||
spin_unlock(&fs_info->buffer_lock);
|
||||
xa_unlock_irq(&fs_info->buffer_tree);
|
||||
|
||||
btrfs_mapping_tree_free(fs_info);
|
||||
list_for_each_entry_safe(dev, tmp, &fs_info->fs_devices->devices,
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
#include "../disk-io.h"
|
||||
#include "../btrfs_inode.h"
|
||||
|
||||
#define PROCESS_UNLOCK (1 << 0)
|
||||
#define PROCESS_RELEASE (1 << 1)
|
||||
#define PROCESS_TEST_LOCKED (1 << 2)
|
||||
#define PROCESS_UNLOCK (1U << 0)
|
||||
#define PROCESS_RELEASE (1U << 1)
|
||||
#define PROCESS_TEST_LOCKED (1U << 2)
|
||||
|
||||
static noinline int process_page_range(struct inode *inode, u64 start, u64 end,
|
||||
unsigned long flags)
|
||||
@@ -74,7 +74,6 @@ static void extent_flag_to_str(const struct extent_state *state, char *dest)
|
||||
|
||||
dest[0] = 0;
|
||||
PRINT_ONE_FLAG(state, dest, cur, DIRTY);
|
||||
PRINT_ONE_FLAG(state, dest, cur, UPTODATE);
|
||||
PRINT_ONE_FLAG(state, dest, cur, LOCKED);
|
||||
PRINT_ONE_FLAG(state, dest, cur, NEW);
|
||||
PRINT_ONE_FLAG(state, dest, cur, DELALLOC);
|
||||
@@ -150,7 +149,7 @@ static int test_find_delalloc(u32 sectorsize, u32 nodesize)
|
||||
* Passing NULL as we don't have fs_info but tracepoints are not used
|
||||
* at this point
|
||||
*/
|
||||
extent_io_tree_init(NULL, tmp, IO_TREE_SELFTEST);
|
||||
btrfs_extent_io_tree_init(NULL, tmp, IO_TREE_SELFTEST);
|
||||
|
||||
/*
|
||||
* First go through and create and mark all of our pages dirty, we pin
|
||||
@@ -177,7 +176,7 @@ static int test_find_delalloc(u32 sectorsize, u32 nodesize)
|
||||
* |--- delalloc ---|
|
||||
* |--- search ---|
|
||||
*/
|
||||
set_extent_bit(tmp, 0, sectorsize - 1, EXTENT_DELALLOC, NULL);
|
||||
btrfs_set_extent_bit(tmp, 0, sectorsize - 1, EXTENT_DELALLOC, NULL);
|
||||
start = 0;
|
||||
end = start + PAGE_SIZE - 1;
|
||||
found = find_lock_delalloc_range(inode, page_folio(locked_page), &start,
|
||||
@@ -191,7 +190,7 @@ static int test_find_delalloc(u32 sectorsize, u32 nodesize)
|
||||
sectorsize - 1, start, end);
|
||||
goto out_bits;
|
||||
}
|
||||
unlock_extent(tmp, start, end, NULL);
|
||||
btrfs_unlock_extent(tmp, start, end, NULL);
|
||||
unlock_page(locked_page);
|
||||
put_page(locked_page);
|
||||
|
||||
@@ -208,7 +207,7 @@ static int test_find_delalloc(u32 sectorsize, u32 nodesize)
|
||||
test_err("couldn't find the locked page");
|
||||
goto out_bits;
|
||||
}
|
||||
set_extent_bit(tmp, sectorsize, max_bytes - 1, EXTENT_DELALLOC, NULL);
|
||||
btrfs_set_extent_bit(tmp, sectorsize, max_bytes - 1, EXTENT_DELALLOC, NULL);
|
||||
start = test_start;
|
||||
end = start + PAGE_SIZE - 1;
|
||||
found = find_lock_delalloc_range(inode, page_folio(locked_page), &start,
|
||||
@@ -227,7 +226,7 @@ static int test_find_delalloc(u32 sectorsize, u32 nodesize)
|
||||
test_err("there were unlocked pages in the range");
|
||||
goto out_bits;
|
||||
}
|
||||
unlock_extent(tmp, start, end, NULL);
|
||||
btrfs_unlock_extent(tmp, start, end, NULL);
|
||||
/* locked_page was unlocked above */
|
||||
put_page(locked_page);
|
||||
|
||||
@@ -263,7 +262,7 @@ static int test_find_delalloc(u32 sectorsize, u32 nodesize)
|
||||
*
|
||||
* We are re-using our test_start from above since it works out well.
|
||||
*/
|
||||
set_extent_bit(tmp, max_bytes, total_dirty - 1, EXTENT_DELALLOC, NULL);
|
||||
btrfs_set_extent_bit(tmp, max_bytes, total_dirty - 1, EXTENT_DELALLOC, NULL);
|
||||
start = test_start;
|
||||
end = start + PAGE_SIZE - 1;
|
||||
found = find_lock_delalloc_range(inode, page_folio(locked_page), &start,
|
||||
@@ -282,7 +281,7 @@ static int test_find_delalloc(u32 sectorsize, u32 nodesize)
|
||||
test_err("pages in range were not all locked");
|
||||
goto out_bits;
|
||||
}
|
||||
unlock_extent(tmp, start, end, NULL);
|
||||
btrfs_unlock_extent(tmp, start, end, NULL);
|
||||
|
||||
/*
|
||||
* Now to test where we run into a page that is no longer dirty in the
|
||||
@@ -327,7 +326,7 @@ static int test_find_delalloc(u32 sectorsize, u32 nodesize)
|
||||
out_bits:
|
||||
if (ret)
|
||||
dump_extent_io_tree(tmp);
|
||||
clear_extent_bits(tmp, 0, total_dirty - 1, (unsigned)-1);
|
||||
btrfs_clear_extent_bits(tmp, 0, total_dirty - 1, (unsigned)-1);
|
||||
out:
|
||||
if (locked_page)
|
||||
put_page(locked_page);
|
||||
@@ -565,10 +564,10 @@ static int test_find_first_clear_extent_bit(void)
|
||||
|
||||
test_msg("running find_first_clear_extent_bit test");
|
||||
|
||||
extent_io_tree_init(NULL, &tree, IO_TREE_SELFTEST);
|
||||
btrfs_extent_io_tree_init(NULL, &tree, IO_TREE_SELFTEST);
|
||||
|
||||
/* Test correct handling of empty tree */
|
||||
find_first_clear_extent_bit(&tree, 0, &start, &end, CHUNK_TRIMMED);
|
||||
btrfs_find_first_clear_extent_bit(&tree, 0, &start, &end, CHUNK_TRIMMED);
|
||||
if (start != 0 || end != -1) {
|
||||
test_err(
|
||||
"error getting a range from completely empty tree: start %llu end %llu",
|
||||
@@ -579,11 +578,11 @@ static int test_find_first_clear_extent_bit(void)
|
||||
* Set 1M-4M alloc/discard and 32M-64M thus leaving a hole between
|
||||
* 4M-32M
|
||||
*/
|
||||
set_extent_bit(&tree, SZ_1M, SZ_4M - 1,
|
||||
CHUNK_TRIMMED | CHUNK_ALLOCATED, NULL);
|
||||
btrfs_set_extent_bit(&tree, SZ_1M, SZ_4M - 1,
|
||||
CHUNK_TRIMMED | CHUNK_ALLOCATED, NULL);
|
||||
|
||||
find_first_clear_extent_bit(&tree, SZ_512K, &start, &end,
|
||||
CHUNK_TRIMMED | CHUNK_ALLOCATED);
|
||||
btrfs_find_first_clear_extent_bit(&tree, SZ_512K, &start, &end,
|
||||
CHUNK_TRIMMED | CHUNK_ALLOCATED);
|
||||
|
||||
if (start != 0 || end != SZ_1M - 1) {
|
||||
test_err("error finding beginning range: start %llu end %llu",
|
||||
@@ -592,14 +591,14 @@ static int test_find_first_clear_extent_bit(void)
|
||||
}
|
||||
|
||||
/* Now add 32M-64M so that we have a hole between 4M-32M */
|
||||
set_extent_bit(&tree, SZ_32M, SZ_64M - 1,
|
||||
CHUNK_TRIMMED | CHUNK_ALLOCATED, NULL);
|
||||
btrfs_set_extent_bit(&tree, SZ_32M, SZ_64M - 1,
|
||||
CHUNK_TRIMMED | CHUNK_ALLOCATED, NULL);
|
||||
|
||||
/*
|
||||
* Request first hole starting at 12M, we should get 4M-32M
|
||||
*/
|
||||
find_first_clear_extent_bit(&tree, 12 * SZ_1M, &start, &end,
|
||||
CHUNK_TRIMMED | CHUNK_ALLOCATED);
|
||||
btrfs_find_first_clear_extent_bit(&tree, 12 * SZ_1M, &start, &end,
|
||||
CHUNK_TRIMMED | CHUNK_ALLOCATED);
|
||||
|
||||
if (start != SZ_4M || end != SZ_32M - 1) {
|
||||
test_err("error finding trimmed range: start %llu end %llu",
|
||||
@@ -611,8 +610,8 @@ static int test_find_first_clear_extent_bit(void)
|
||||
* Search in the middle of allocated range, should get the next one
|
||||
* available, which happens to be unallocated -> 4M-32M
|
||||
*/
|
||||
find_first_clear_extent_bit(&tree, SZ_2M, &start, &end,
|
||||
CHUNK_TRIMMED | CHUNK_ALLOCATED);
|
||||
btrfs_find_first_clear_extent_bit(&tree, SZ_2M, &start, &end,
|
||||
CHUNK_TRIMMED | CHUNK_ALLOCATED);
|
||||
|
||||
if (start != SZ_4M || end != SZ_32M - 1) {
|
||||
test_err("error finding next unalloc range: start %llu end %llu",
|
||||
@@ -624,9 +623,9 @@ static int test_find_first_clear_extent_bit(void)
|
||||
* Set 64M-72M with CHUNK_ALLOC flag, then search for CHUNK_TRIMMED flag
|
||||
* being unset in this range, we should get the entry in range 64M-72M
|
||||
*/
|
||||
set_extent_bit(&tree, SZ_64M, SZ_64M + SZ_8M - 1, CHUNK_ALLOCATED, NULL);
|
||||
find_first_clear_extent_bit(&tree, SZ_64M + SZ_1M, &start, &end,
|
||||
CHUNK_TRIMMED);
|
||||
btrfs_set_extent_bit(&tree, SZ_64M, SZ_64M + SZ_8M - 1, CHUNK_ALLOCATED, NULL);
|
||||
btrfs_find_first_clear_extent_bit(&tree, SZ_64M + SZ_1M, &start, &end,
|
||||
CHUNK_TRIMMED);
|
||||
|
||||
if (start != SZ_64M || end != SZ_64M + SZ_8M - 1) {
|
||||
test_err("error finding exact range: start %llu end %llu",
|
||||
@@ -634,8 +633,8 @@ static int test_find_first_clear_extent_bit(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
find_first_clear_extent_bit(&tree, SZ_64M - SZ_8M, &start, &end,
|
||||
CHUNK_TRIMMED);
|
||||
btrfs_find_first_clear_extent_bit(&tree, SZ_64M - SZ_8M, &start, &end,
|
||||
CHUNK_TRIMMED);
|
||||
|
||||
/*
|
||||
* Search in the middle of set range whose immediate neighbour doesn't
|
||||
@@ -651,7 +650,7 @@ static int test_find_first_clear_extent_bit(void)
|
||||
* Search beyond any known range, shall return after last known range
|
||||
* and end should be -1
|
||||
*/
|
||||
find_first_clear_extent_bit(&tree, -1, &start, &end, CHUNK_TRIMMED);
|
||||
btrfs_find_first_clear_extent_bit(&tree, -1, &start, &end, CHUNK_TRIMMED);
|
||||
if (start != SZ_64M + SZ_8M || end != -1) {
|
||||
test_err(
|
||||
"error handling beyond end of range search: start %llu end %llu",
|
||||
@@ -663,7 +662,7 @@ static int test_find_first_clear_extent_bit(void)
|
||||
out:
|
||||
if (ret)
|
||||
dump_extent_io_tree(&tree);
|
||||
clear_extent_bits(&tree, 0, (u64)-1, CHUNK_TRIMMED | CHUNK_ALLOCATED);
|
||||
btrfs_clear_extent_bits(&tree, 0, (u64)-1, CHUNK_TRIMMED | CHUNK_ALLOCATED);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ static int free_extent_map_tree(struct btrfs_inode *inode)
|
||||
while (!RB_EMPTY_ROOT(&em_tree->root)) {
|
||||
node = rb_first(&em_tree->root);
|
||||
em = rb_entry(node, struct extent_map, rb_node);
|
||||
remove_extent_mapping(inode, em);
|
||||
btrfs_remove_extent_mapping(inode, em);
|
||||
|
||||
#ifdef CONFIG_BTRFS_DEBUG
|
||||
if (refcount_read(&em->refs) != 1) {
|
||||
@@ -36,7 +36,7 @@ static int free_extent_map_tree(struct btrfs_inode *inode)
|
||||
refcount_set(&em->refs, 1);
|
||||
}
|
||||
#endif
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
}
|
||||
write_unlock(&em_tree->lock);
|
||||
|
||||
@@ -68,7 +68,7 @@ static int test_case_1(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
int ret;
|
||||
int ret2;
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
return -ENOMEM;
|
||||
@@ -87,10 +87,10 @@ static int test_case_1(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
test_err("cannot add extent range [0, 16K)");
|
||||
goto out;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
/* Add [16K, 20K) following [0, 16K) */
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
ret = -ENOMEM;
|
||||
@@ -109,9 +109,9 @@ static int test_case_1(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
test_err("cannot add extent range [16K, 20K)");
|
||||
goto out;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
ret = -ENOMEM;
|
||||
@@ -137,7 +137,7 @@ static int test_case_1(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
if (em->start != 0 || extent_map_end(em) != SZ_16K ||
|
||||
if (em->start != 0 || btrfs_extent_map_end(em) != SZ_16K ||
|
||||
em->disk_bytenr != 0 || em->disk_num_bytes != SZ_16K) {
|
||||
test_err(
|
||||
"case1 [%llu %llu]: ret %d return a wrong em (start %llu len %llu disk_bytenr %llu disk_num_bytes %llu",
|
||||
@@ -145,7 +145,7 @@ static int test_case_1(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
em->disk_bytenr, em->disk_num_bytes);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
out:
|
||||
ret2 = free_extent_map_tree(inode);
|
||||
if (ret == 0)
|
||||
@@ -167,7 +167,7 @@ static int test_case_2(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
int ret;
|
||||
int ret2;
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
return -ENOMEM;
|
||||
@@ -186,10 +186,10 @@ static int test_case_2(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
test_err("cannot add extent range [0, 1K)");
|
||||
goto out;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
/* Add [4K, 8K) following [0, 1K) */
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
ret = -ENOMEM;
|
||||
@@ -208,9 +208,9 @@ static int test_case_2(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
test_err("cannot add extent range [4K, 8K)");
|
||||
goto out;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
ret = -ENOMEM;
|
||||
@@ -235,14 +235,14 @@ static int test_case_2(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
if (em->start != 0 || extent_map_end(em) != SZ_1K ||
|
||||
if (em->start != 0 || btrfs_extent_map_end(em) != SZ_1K ||
|
||||
em->disk_bytenr != EXTENT_MAP_INLINE) {
|
||||
test_err(
|
||||
"case2 [0 1K]: ret %d return a wrong em (start %llu len %llu disk_bytenr %llu",
|
||||
ret, em->start, em->len, em->disk_bytenr);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
out:
|
||||
ret2 = free_extent_map_tree(inode);
|
||||
if (ret == 0)
|
||||
@@ -260,7 +260,7 @@ static int __test_case_3(struct btrfs_fs_info *fs_info,
|
||||
int ret;
|
||||
int ret2;
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
return -ENOMEM;
|
||||
@@ -279,9 +279,9 @@ static int __test_case_3(struct btrfs_fs_info *fs_info,
|
||||
test_err("cannot add extent range [4K, 8K)");
|
||||
goto out;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
ret = -ENOMEM;
|
||||
@@ -312,15 +312,15 @@ static int __test_case_3(struct btrfs_fs_info *fs_info,
|
||||
* Since bytes within em are contiguous, em->block_start is identical to
|
||||
* em->start.
|
||||
*/
|
||||
if (start < em->start || start + len > extent_map_end(em) ||
|
||||
em->start != extent_map_block_start(em)) {
|
||||
if (start < em->start || start + len > btrfs_extent_map_end(em) ||
|
||||
em->start != btrfs_extent_map_block_start(em)) {
|
||||
test_err(
|
||||
"case3 [%llu %llu): ret %d em (start %llu len %llu disk_bytenr %llu block_len %llu)",
|
||||
start, start + len, ret, em->start, em->len,
|
||||
em->disk_bytenr, em->disk_num_bytes);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
out:
|
||||
ret2 = free_extent_map_tree(inode);
|
||||
if (ret == 0)
|
||||
@@ -369,7 +369,7 @@ static int __test_case_4(struct btrfs_fs_info *fs_info,
|
||||
int ret;
|
||||
int ret2;
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
return -ENOMEM;
|
||||
@@ -388,9 +388,9 @@ static int __test_case_4(struct btrfs_fs_info *fs_info,
|
||||
test_err("cannot add extent range [0, 8K)");
|
||||
goto out;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
ret = -ENOMEM;
|
||||
@@ -410,9 +410,9 @@ static int __test_case_4(struct btrfs_fs_info *fs_info,
|
||||
test_err("cannot add extent range [8K, 32K)");
|
||||
goto out;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
ret = -ENOMEM;
|
||||
@@ -438,14 +438,14 @@ static int __test_case_4(struct btrfs_fs_info *fs_info,
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
if (start < em->start || start + len > extent_map_end(em)) {
|
||||
if (start < em->start || start + len > btrfs_extent_map_end(em)) {
|
||||
test_err(
|
||||
"case4 [%llu %llu): ret %d, added wrong em (start %llu len %llu disk_bytenr %llu disk_num_bytes %llu)",
|
||||
start, start + len, ret, em->start, em->len,
|
||||
em->disk_bytenr, em->disk_num_bytes);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
out:
|
||||
ret2 = free_extent_map_tree(inode);
|
||||
if (ret == 0)
|
||||
@@ -498,7 +498,7 @@ static int add_compressed_extent(struct btrfs_inode *inode,
|
||||
struct extent_map *em;
|
||||
int ret;
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
return -ENOMEM;
|
||||
@@ -513,7 +513,7 @@ static int add_compressed_extent(struct btrfs_inode *inode,
|
||||
write_lock(&em_tree->lock);
|
||||
ret = btrfs_add_extent_mapping(inode, &em, em->start, em->len);
|
||||
write_unlock(&em_tree->lock);
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
if (ret < 0) {
|
||||
test_err("cannot add extent map [%llu, %llu)", start, start + len);
|
||||
return ret;
|
||||
@@ -719,7 +719,7 @@ static int test_case_6(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
ret = -ENOMEM;
|
||||
@@ -751,7 +751,7 @@ static int test_case_6(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
ret2 = free_extent_map_tree(inode);
|
||||
if (ret == 0)
|
||||
ret = ret2;
|
||||
@@ -773,7 +773,7 @@ static int test_case_7(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
|
||||
test_msg("Running btrfs_drop_extent_cache with pinned");
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
return -ENOMEM;
|
||||
@@ -793,9 +793,9 @@ static int test_case_7(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
test_err("couldn't add extent map");
|
||||
goto out;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
ret = -ENOMEM;
|
||||
@@ -815,7 +815,7 @@ static int test_case_7(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
test_err("couldn't add extent map");
|
||||
goto out;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
/*
|
||||
* Drop [0, 36K) This should skip the [0, 4K) extent and then split the
|
||||
@@ -826,7 +826,7 @@ static int test_case_7(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
/* Make sure our extent maps look sane. */
|
||||
ret = -EINVAL;
|
||||
|
||||
em = lookup_extent_mapping(em_tree, 0, SZ_16K);
|
||||
em = btrfs_lookup_extent_mapping(em_tree, 0, SZ_16K);
|
||||
if (!em) {
|
||||
test_err("didn't find an em at 0 as expected");
|
||||
goto out;
|
||||
@@ -842,10 +842,10 @@ static int test_case_7(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
goto out;
|
||||
}
|
||||
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
read_lock(&em_tree->lock);
|
||||
em = lookup_extent_mapping(em_tree, SZ_16K, SZ_16K);
|
||||
em = btrfs_lookup_extent_mapping(em_tree, SZ_16K, SZ_16K);
|
||||
read_unlock(&em_tree->lock);
|
||||
if (em) {
|
||||
test_err("found an em when we weren't expecting one");
|
||||
@@ -853,7 +853,7 @@ static int test_case_7(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
}
|
||||
|
||||
read_lock(&em_tree->lock);
|
||||
em = lookup_extent_mapping(em_tree, SZ_32K, SZ_16K);
|
||||
em = btrfs_lookup_extent_mapping(em_tree, SZ_32K, SZ_16K);
|
||||
read_unlock(&em_tree->lock);
|
||||
if (!em) {
|
||||
test_err("didn't find an em at 32K as expected");
|
||||
@@ -870,16 +870,16 @@ static int test_case_7(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (extent_map_block_start(em) != SZ_32K + SZ_4K) {
|
||||
if (btrfs_extent_map_block_start(em) != SZ_32K + SZ_4K) {
|
||||
test_err("em->block_start is %llu, expected 36K",
|
||||
extent_map_block_start(em));
|
||||
btrfs_extent_map_block_start(em));
|
||||
goto out;
|
||||
}
|
||||
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
read_lock(&em_tree->lock);
|
||||
em = lookup_extent_mapping(em_tree, 48 * SZ_1K, (u64)-1);
|
||||
em = btrfs_lookup_extent_mapping(em_tree, 48 * SZ_1K, (u64)-1);
|
||||
read_unlock(&em_tree->lock);
|
||||
if (em) {
|
||||
test_err("found an unexpected em above 48K");
|
||||
@@ -888,9 +888,9 @@ static int test_case_7(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
/* Unpin our extent to prevent warning when removing it below. */
|
||||
ret2 = unpin_extent_cache(inode, 0, SZ_16K, 0);
|
||||
ret2 = btrfs_unpin_extent_cache(inode, 0, SZ_16K, 0);
|
||||
if (ret == 0)
|
||||
ret = ret2;
|
||||
ret2 = free_extent_map_tree(inode);
|
||||
@@ -913,7 +913,7 @@ static int test_case_8(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
int ret;
|
||||
int ret2;
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
return -ENOMEM;
|
||||
@@ -928,13 +928,13 @@ static int test_case_8(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
write_lock(&em_tree->lock);
|
||||
ret = btrfs_add_extent_mapping(inode, &em, em->start, em->len);
|
||||
write_unlock(&em_tree->lock);
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
if (ret < 0) {
|
||||
test_err("couldn't add extent map for range [120K, 128K)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
em = alloc_extent_map();
|
||||
em = btrfs_alloc_extent_map();
|
||||
if (!em) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
||||
ret = -ENOMEM;
|
||||
@@ -967,7 +967,7 @@ static int test_case_8(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode)
|
||||
write_lock(&em_tree->lock);
|
||||
ret = btrfs_add_extent_mapping(inode, &em, SZ_1K * 140, SZ_4K);
|
||||
write_unlock(&em_tree->lock);
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
if (ret < 0) {
|
||||
test_err("couldn't add extent map for range [108K, 144K)");
|
||||
goto out;
|
||||
|
||||
@@ -268,7 +268,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
test_err("expected a hole, got %llu", em->disk_bytenr);
|
||||
goto out;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
btrfs_drop_extent_map_range(BTRFS_I(inode), 0, (u64)-1, false);
|
||||
|
||||
/*
|
||||
@@ -314,7 +314,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
* this?
|
||||
*/
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
if (IS_ERR(em)) {
|
||||
@@ -336,7 +336,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
goto out;
|
||||
}
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
/* Regular extent */
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
@@ -363,7 +363,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
goto out;
|
||||
}
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
/* The next 3 are split extents */
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
@@ -389,10 +389,10 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
test_err("wrong offset, want 0, have %llu", em->offset);
|
||||
goto out;
|
||||
}
|
||||
disk_bytenr = extent_map_block_start(em);
|
||||
disk_bytenr = btrfs_extent_map_block_start(em);
|
||||
orig_start = em->start;
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
if (IS_ERR(em)) {
|
||||
@@ -414,7 +414,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
goto out;
|
||||
}
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
if (IS_ERR(em)) {
|
||||
@@ -441,13 +441,13 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
goto out;
|
||||
}
|
||||
disk_bytenr += (em->start - orig_start);
|
||||
if (extent_map_block_start(em) != disk_bytenr) {
|
||||
if (btrfs_extent_map_block_start(em) != disk_bytenr) {
|
||||
test_err("wrong block start, want %llu, have %llu",
|
||||
disk_bytenr, extent_map_block_start(em));
|
||||
disk_bytenr, btrfs_extent_map_block_start(em));
|
||||
goto out;
|
||||
}
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
/* Prealloc extent */
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
@@ -475,7 +475,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
goto out;
|
||||
}
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
/* The next 3 are a half written prealloc extent */
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
@@ -502,10 +502,10 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
test_err("wrong offset, want 0, have %llu", em->offset);
|
||||
goto out;
|
||||
}
|
||||
disk_bytenr = extent_map_block_start(em);
|
||||
disk_bytenr = btrfs_extent_map_block_start(em);
|
||||
orig_start = em->start;
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
if (IS_ERR(em)) {
|
||||
@@ -531,13 +531,13 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
em->start - orig_start, em->offset);
|
||||
goto out;
|
||||
}
|
||||
if (extent_map_block_start(em) != disk_bytenr + em->offset) {
|
||||
if (btrfs_extent_map_block_start(em) != disk_bytenr + em->offset) {
|
||||
test_err("unexpected block start, wanted %llu, have %llu",
|
||||
disk_bytenr + em->offset, extent_map_block_start(em));
|
||||
disk_bytenr + em->offset, btrfs_extent_map_block_start(em));
|
||||
goto out;
|
||||
}
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
if (IS_ERR(em)) {
|
||||
@@ -564,13 +564,13 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
em->start, em->offset, orig_start);
|
||||
goto out;
|
||||
}
|
||||
if (extent_map_block_start(em) != disk_bytenr + em->offset) {
|
||||
if (btrfs_extent_map_block_start(em) != disk_bytenr + em->offset) {
|
||||
test_err("unexpected block start, wanted %llu, have %llu",
|
||||
disk_bytenr + em->offset, extent_map_block_start(em));
|
||||
disk_bytenr + em->offset, btrfs_extent_map_block_start(em));
|
||||
goto out;
|
||||
}
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
/* Now for the compressed extent */
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
@@ -597,13 +597,13 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
test_err("wrong offset, want 0, have %llu", em->offset);
|
||||
goto out;
|
||||
}
|
||||
if (extent_map_compression(em) != BTRFS_COMPRESS_ZLIB) {
|
||||
if (btrfs_extent_map_compression(em) != BTRFS_COMPRESS_ZLIB) {
|
||||
test_err("unexpected compress type, wanted %d, got %d",
|
||||
BTRFS_COMPRESS_ZLIB, extent_map_compression(em));
|
||||
BTRFS_COMPRESS_ZLIB, btrfs_extent_map_compression(em));
|
||||
goto out;
|
||||
}
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
/* Split compressed extent */
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
@@ -630,15 +630,15 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
test_err("wrong offset, want 0, have %llu", em->offset);
|
||||
goto out;
|
||||
}
|
||||
if (extent_map_compression(em) != BTRFS_COMPRESS_ZLIB) {
|
||||
if (btrfs_extent_map_compression(em) != BTRFS_COMPRESS_ZLIB) {
|
||||
test_err("unexpected compress type, wanted %d, got %d",
|
||||
BTRFS_COMPRESS_ZLIB, extent_map_compression(em));
|
||||
BTRFS_COMPRESS_ZLIB, btrfs_extent_map_compression(em));
|
||||
goto out;
|
||||
}
|
||||
disk_bytenr = extent_map_block_start(em);
|
||||
disk_bytenr = btrfs_extent_map_block_start(em);
|
||||
orig_start = em->start;
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
if (IS_ERR(em)) {
|
||||
@@ -664,16 +664,16 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
goto out;
|
||||
}
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
if (IS_ERR(em)) {
|
||||
test_err("got an error when we shouldn't have");
|
||||
goto out;
|
||||
}
|
||||
if (extent_map_block_start(em) != disk_bytenr) {
|
||||
if (btrfs_extent_map_block_start(em) != disk_bytenr) {
|
||||
test_err("block start does not match, want %llu got %llu",
|
||||
disk_bytenr, extent_map_block_start(em));
|
||||
disk_bytenr, btrfs_extent_map_block_start(em));
|
||||
goto out;
|
||||
}
|
||||
if (em->start != offset || em->len != 2 * sectorsize) {
|
||||
@@ -692,13 +692,13 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
em->start, em->offset, orig_start);
|
||||
goto out;
|
||||
}
|
||||
if (extent_map_compression(em) != BTRFS_COMPRESS_ZLIB) {
|
||||
if (btrfs_extent_map_compression(em) != BTRFS_COMPRESS_ZLIB) {
|
||||
test_err("unexpected compress type, wanted %d, got %d",
|
||||
BTRFS_COMPRESS_ZLIB, extent_map_compression(em));
|
||||
BTRFS_COMPRESS_ZLIB, btrfs_extent_map_compression(em));
|
||||
goto out;
|
||||
}
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
/* A hole between regular extents but no hole extent */
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset + 6, sectorsize);
|
||||
@@ -725,7 +725,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
goto out;
|
||||
}
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, SZ_4M);
|
||||
if (IS_ERR(em)) {
|
||||
@@ -757,7 +757,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
goto out;
|
||||
}
|
||||
offset = em->start + em->len;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||
if (IS_ERR(em)) {
|
||||
@@ -785,7 +785,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
||||
ret = 0;
|
||||
out:
|
||||
if (!IS_ERR(em))
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
iput(inode);
|
||||
btrfs_free_dummy_root(root);
|
||||
btrfs_free_dummy_fs_info(fs_info);
|
||||
@@ -858,15 +858,16 @@ static int test_hole_first(u32 sectorsize, u32 nodesize)
|
||||
em->flags);
|
||||
goto out;
|
||||
}
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
|
||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, sectorsize, 2 * sectorsize);
|
||||
if (IS_ERR(em)) {
|
||||
test_err("got an error when we shouldn't have");
|
||||
goto out;
|
||||
}
|
||||
if (extent_map_block_start(em) != sectorsize) {
|
||||
test_err("expected a real extent, got %llu", extent_map_block_start(em));
|
||||
if (btrfs_extent_map_block_start(em) != sectorsize) {
|
||||
test_err("expected a real extent, got %llu",
|
||||
btrfs_extent_map_block_start(em));
|
||||
goto out;
|
||||
}
|
||||
if (em->start != sectorsize || em->len != sectorsize) {
|
||||
@@ -883,7 +884,7 @@ static int test_hole_first(u32 sectorsize, u32 nodesize)
|
||||
ret = 0;
|
||||
out:
|
||||
if (!IS_ERR(em))
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
iput(inode);
|
||||
btrfs_free_dummy_root(root);
|
||||
btrfs_free_dummy_fs_info(fs_info);
|
||||
@@ -949,11 +950,10 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
|
||||
}
|
||||
|
||||
/* [BTRFS_MAX_EXTENT_SIZE/2][sectorsize HOLE][the rest] */
|
||||
ret = clear_extent_bit(&BTRFS_I(inode)->io_tree,
|
||||
BTRFS_MAX_EXTENT_SIZE >> 1,
|
||||
(BTRFS_MAX_EXTENT_SIZE >> 1) + sectorsize - 1,
|
||||
EXTENT_DELALLOC | EXTENT_DELALLOC_NEW |
|
||||
EXTENT_UPTODATE, NULL);
|
||||
ret = btrfs_clear_extent_bits(&BTRFS_I(inode)->io_tree,
|
||||
BTRFS_MAX_EXTENT_SIZE >> 1,
|
||||
(BTRFS_MAX_EXTENT_SIZE >> 1) + sectorsize - 1,
|
||||
EXTENT_DELALLOC | EXTENT_DELALLOC_NEW);
|
||||
if (ret) {
|
||||
test_err("clear_extent_bit returned %d", ret);
|
||||
goto out;
|
||||
@@ -1017,11 +1017,10 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
|
||||
}
|
||||
|
||||
/* [BTRFS_MAX_EXTENT_SIZE+4k][4K HOLE][BTRFS_MAX_EXTENT_SIZE+4k] */
|
||||
ret = clear_extent_bit(&BTRFS_I(inode)->io_tree,
|
||||
BTRFS_MAX_EXTENT_SIZE + sectorsize,
|
||||
BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1,
|
||||
EXTENT_DELALLOC | EXTENT_DELALLOC_NEW |
|
||||
EXTENT_UPTODATE, NULL);
|
||||
ret = btrfs_clear_extent_bits(&BTRFS_I(inode)->io_tree,
|
||||
BTRFS_MAX_EXTENT_SIZE + sectorsize,
|
||||
BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1,
|
||||
EXTENT_DELALLOC | EXTENT_DELALLOC_NEW);
|
||||
if (ret) {
|
||||
test_err("clear_extent_bit returned %d", ret);
|
||||
goto out;
|
||||
@@ -1052,9 +1051,8 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
|
||||
}
|
||||
|
||||
/* Empty */
|
||||
ret = clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
|
||||
EXTENT_DELALLOC | EXTENT_DELALLOC_NEW |
|
||||
EXTENT_UPTODATE, NULL);
|
||||
ret = btrfs_clear_extent_bits(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
|
||||
EXTENT_DELALLOC | EXTENT_DELALLOC_NEW);
|
||||
if (ret) {
|
||||
test_err("clear_extent_bit returned %d", ret);
|
||||
goto out;
|
||||
@@ -1068,9 +1066,8 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
|
||||
ret = 0;
|
||||
out:
|
||||
if (ret)
|
||||
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
|
||||
EXTENT_DELALLOC | EXTENT_DELALLOC_NEW |
|
||||
EXTENT_UPTODATE, NULL);
|
||||
btrfs_clear_extent_bits(&BTRFS_I(inode)->io_tree, 0, (u64)-1,
|
||||
EXTENT_DELALLOC | EXTENT_DELALLOC_NEW);
|
||||
iput(inode);
|
||||
btrfs_free_dummy_root(root);
|
||||
btrfs_free_dummy_fs_info(fs_info);
|
||||
|
||||
+37
-37
@@ -197,7 +197,7 @@ static noinline void switch_commit_roots(struct btrfs_trans_handle *trans)
|
||||
list_del_init(&root->dirty_list);
|
||||
free_extent_buffer(root->commit_root);
|
||||
root->commit_root = btrfs_root_node(root);
|
||||
extent_io_tree_release(&root->dirty_log_pages);
|
||||
btrfs_extent_io_tree_release(&root->dirty_log_pages);
|
||||
btrfs_qgroup_clean_swapped_blocks(root);
|
||||
}
|
||||
|
||||
@@ -383,10 +383,10 @@ loop:
|
||||
INIT_LIST_HEAD(&cur_trans->deleted_bgs);
|
||||
spin_lock_init(&cur_trans->dropped_roots_lock);
|
||||
list_add_tail(&cur_trans->list, &fs_info->trans_list);
|
||||
extent_io_tree_init(fs_info, &cur_trans->dirty_pages,
|
||||
IO_TREE_TRANS_DIRTY_PAGES);
|
||||
extent_io_tree_init(fs_info, &cur_trans->pinned_extents,
|
||||
IO_TREE_FS_PINNED_EXTENTS);
|
||||
btrfs_extent_io_tree_init(fs_info, &cur_trans->dirty_pages,
|
||||
IO_TREE_TRANS_DIRTY_PAGES);
|
||||
btrfs_extent_io_tree_init(fs_info, &cur_trans->pinned_extents,
|
||||
IO_TREE_FS_PINNED_EXTENTS);
|
||||
btrfs_set_fs_generation(fs_info, fs_info->generation + 1);
|
||||
cur_trans->transid = fs_info->generation;
|
||||
fs_info->running_transaction = cur_trans;
|
||||
@@ -538,15 +538,15 @@ static void wait_current_trans(struct btrfs_fs_info *fs_info)
|
||||
}
|
||||
}
|
||||
|
||||
static int may_wait_transaction(struct btrfs_fs_info *fs_info, int type)
|
||||
static bool may_wait_transaction(struct btrfs_fs_info *fs_info, int type)
|
||||
{
|
||||
if (test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
if (type == TRANS_START)
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool need_reserve_reloc_root(struct btrfs_root *root)
|
||||
@@ -761,9 +761,10 @@ got_it:
|
||||
* value here.
|
||||
*/
|
||||
if (do_chunk_alloc && num_bytes) {
|
||||
u64 flags = h->block_rsv->space_info->flags;
|
||||
struct btrfs_space_info *space_info = h->block_rsv->space_info;
|
||||
u64 flags = space_info->flags;
|
||||
|
||||
btrfs_chunk_alloc(h, btrfs_get_alloc_profile(fs_info, flags),
|
||||
btrfs_chunk_alloc(h, space_info, btrfs_get_alloc_profile(fs_info, flags),
|
||||
CHUNK_ALLOC_NO_FORCE);
|
||||
}
|
||||
|
||||
@@ -1128,13 +1129,13 @@ int btrfs_write_marked_extents(struct btrfs_fs_info *fs_info,
|
||||
u64 start = 0;
|
||||
u64 end;
|
||||
|
||||
while (find_first_extent_bit(dirty_pages, start, &start, &end,
|
||||
mark, &cached_state)) {
|
||||
while (btrfs_find_first_extent_bit(dirty_pages, start, &start, &end,
|
||||
mark, &cached_state)) {
|
||||
bool wait_writeback = false;
|
||||
|
||||
ret = convert_extent_bit(dirty_pages, start, end,
|
||||
EXTENT_NEED_WAIT,
|
||||
mark, &cached_state);
|
||||
ret = btrfs_convert_extent_bit(dirty_pages, start, end,
|
||||
EXTENT_NEED_WAIT,
|
||||
mark, &cached_state);
|
||||
/*
|
||||
* convert_extent_bit can return -ENOMEM, which is most of the
|
||||
* time a temporary error. So when it happens, ignore the error
|
||||
@@ -1155,8 +1156,8 @@ int btrfs_write_marked_extents(struct btrfs_fs_info *fs_info,
|
||||
if (!ret)
|
||||
ret = filemap_fdatawrite_range(mapping, start, end);
|
||||
if (!ret && wait_writeback)
|
||||
ret = filemap_fdatawait_range(mapping, start, end);
|
||||
free_extent_state(cached_state);
|
||||
btrfs_btree_wait_writeback_range(fs_info, start, end);
|
||||
btrfs_free_extent_state(cached_state);
|
||||
if (ret)
|
||||
break;
|
||||
cached_state = NULL;
|
||||
@@ -1175,14 +1176,13 @@ int btrfs_write_marked_extents(struct btrfs_fs_info *fs_info,
|
||||
static int __btrfs_wait_marked_extents(struct btrfs_fs_info *fs_info,
|
||||
struct extent_io_tree *dirty_pages)
|
||||
{
|
||||
struct address_space *mapping = fs_info->btree_inode->i_mapping;
|
||||
struct extent_state *cached_state = NULL;
|
||||
u64 start = 0;
|
||||
u64 end;
|
||||
int ret = 0;
|
||||
|
||||
while (find_first_extent_bit(dirty_pages, start, &start, &end,
|
||||
EXTENT_NEED_WAIT, &cached_state)) {
|
||||
while (btrfs_find_first_extent_bit(dirty_pages, start, &start, &end,
|
||||
EXTENT_NEED_WAIT, &cached_state)) {
|
||||
/*
|
||||
* Ignore -ENOMEM errors returned by clear_extent_bit().
|
||||
* When committing the transaction, we'll remove any entries
|
||||
@@ -1191,13 +1191,13 @@ static int __btrfs_wait_marked_extents(struct btrfs_fs_info *fs_info,
|
||||
* concurrently - we do it only at transaction commit time when
|
||||
* it's safe to do it (through extent_io_tree_release()).
|
||||
*/
|
||||
ret = clear_extent_bit(dirty_pages, start, end,
|
||||
EXTENT_NEED_WAIT, &cached_state);
|
||||
ret = btrfs_clear_extent_bit(dirty_pages, start, end,
|
||||
EXTENT_NEED_WAIT, &cached_state);
|
||||
if (ret == -ENOMEM)
|
||||
ret = 0;
|
||||
if (!ret)
|
||||
ret = filemap_fdatawait_range(mapping, start, end);
|
||||
free_extent_state(cached_state);
|
||||
btrfs_btree_wait_writeback_range(fs_info, start, end);
|
||||
btrfs_free_extent_state(cached_state);
|
||||
if (ret)
|
||||
break;
|
||||
cached_state = NULL;
|
||||
@@ -1265,7 +1265,7 @@ static int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans)
|
||||
blk_finish_plug(&plug);
|
||||
ret2 = btrfs_wait_extents(fs_info, dirty_pages);
|
||||
|
||||
extent_io_tree_release(&trans->transaction->dirty_pages);
|
||||
btrfs_extent_io_tree_release(&trans->transaction->dirty_pages);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1327,7 +1327,6 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans)
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
struct list_head *dirty_bgs = &trans->transaction->dirty_bgs;
|
||||
struct list_head *io_bgs = &trans->transaction->io_bgs;
|
||||
struct list_head *next;
|
||||
struct extent_buffer *eb;
|
||||
int ret;
|
||||
|
||||
@@ -1363,13 +1362,13 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans)
|
||||
again:
|
||||
while (!list_empty(&fs_info->dirty_cowonly_roots)) {
|
||||
struct btrfs_root *root;
|
||||
next = fs_info->dirty_cowonly_roots.next;
|
||||
list_del_init(next);
|
||||
root = list_entry(next, struct btrfs_root, dirty_list);
|
||||
clear_bit(BTRFS_ROOT_DIRTY, &root->state);
|
||||
|
||||
list_add_tail(&root->dirty_list,
|
||||
&trans->transaction->switch_commits);
|
||||
root = list_first_entry(&fs_info->dirty_cowonly_roots,
|
||||
struct btrfs_root, dirty_list);
|
||||
clear_bit(BTRFS_ROOT_DIRTY, &root->state);
|
||||
list_move_tail(&root->dirty_list,
|
||||
&trans->transaction->switch_commits);
|
||||
|
||||
ret = update_cowonly_root(trans, root);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -2271,14 +2270,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
|
||||
wake_up(&fs_info->transaction_blocked_wait);
|
||||
btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_COMMIT_PREP);
|
||||
|
||||
if (cur_trans->list.prev != &fs_info->trans_list) {
|
||||
if (!list_is_first(&cur_trans->list, &fs_info->trans_list)) {
|
||||
enum btrfs_trans_state want_state = TRANS_STATE_COMPLETED;
|
||||
|
||||
if (trans->in_fsync)
|
||||
want_state = TRANS_STATE_SUPER_COMMITTED;
|
||||
|
||||
prev_trans = list_entry(cur_trans->list.prev,
|
||||
struct btrfs_transaction, list);
|
||||
prev_trans = list_prev_entry(cur_trans, list);
|
||||
if (prev_trans->state < want_state) {
|
||||
refcount_inc(&prev_trans->use_count);
|
||||
spin_unlock(&fs_info->trans_lock);
|
||||
@@ -2555,7 +2553,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
|
||||
wake_up(&cur_trans->commit_wait);
|
||||
btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED);
|
||||
|
||||
btrfs_finish_extent_commit(trans);
|
||||
ret = btrfs_finish_extent_commit(trans);
|
||||
if (ret)
|
||||
goto scrub_continue;
|
||||
|
||||
if (test_bit(BTRFS_TRANS_HAVE_FREE_BGS, &cur_trans->flags))
|
||||
btrfs_clear_space_info_full(fs_info);
|
||||
|
||||
+10
-12
@@ -1571,7 +1571,7 @@ static int check_extent_item(struct extent_buffer *leaf,
|
||||
inline_type);
|
||||
return -EUCLEAN;
|
||||
}
|
||||
if (inline_type < last_type) {
|
||||
if (unlikely(inline_type < last_type)) {
|
||||
extent_err(leaf, slot,
|
||||
"inline ref out-of-order: has type %u, prev type %u",
|
||||
inline_type, last_type);
|
||||
@@ -1580,7 +1580,7 @@ static int check_extent_item(struct extent_buffer *leaf,
|
||||
/* Type changed, allow the sequence starts from U64_MAX again. */
|
||||
if (inline_type > last_type)
|
||||
last_seq = U64_MAX;
|
||||
if (seq > last_seq) {
|
||||
if (unlikely(seq > last_seq)) {
|
||||
extent_err(leaf, slot,
|
||||
"inline ref out-of-order: has type %u offset %llu seq 0x%llx, prev type %u seq 0x%llx",
|
||||
inline_type, inline_offset, seq,
|
||||
@@ -1929,7 +1929,7 @@ static enum btrfs_tree_block_status check_leaf_item(struct extent_buffer *leaf,
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
if (unlikely(ret))
|
||||
return BTRFS_TREE_BLOCK_INVALID_ITEM;
|
||||
return BTRFS_TREE_BLOCK_CLEAN;
|
||||
}
|
||||
@@ -2229,9 +2229,8 @@ int btrfs_verify_level_key(struct extent_buffer *eb,
|
||||
int ret;
|
||||
|
||||
found_level = btrfs_header_level(eb);
|
||||
if (found_level != check->level) {
|
||||
WARN(IS_ENABLED(CONFIG_BTRFS_DEBUG),
|
||||
KERN_ERR "BTRFS: tree level check failed\n");
|
||||
if (unlikely(found_level != check->level)) {
|
||||
DEBUG_WARN();
|
||||
btrfs_err(fs_info,
|
||||
"tree level mismatch detected, bytenr=%llu level expected=%u has=%u",
|
||||
eb->start, check->level, found_level);
|
||||
@@ -2251,11 +2250,11 @@ int btrfs_verify_level_key(struct extent_buffer *eb,
|
||||
return 0;
|
||||
|
||||
/* We have @first_key, so this @eb must have at least one item */
|
||||
if (btrfs_header_nritems(eb) == 0) {
|
||||
if (unlikely(btrfs_header_nritems(eb) == 0)) {
|
||||
btrfs_err(fs_info,
|
||||
"invalid tree nritems, bytenr=%llu nritems=0 expect >0",
|
||||
eb->start);
|
||||
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
|
||||
DEBUG_WARN();
|
||||
return -EUCLEAN;
|
||||
}
|
||||
|
||||
@@ -2263,11 +2262,10 @@ int btrfs_verify_level_key(struct extent_buffer *eb,
|
||||
btrfs_node_key_to_cpu(eb, &found_key, 0);
|
||||
else
|
||||
btrfs_item_key_to_cpu(eb, &found_key, 0);
|
||||
ret = btrfs_comp_cpu_keys(&check->first_key, &found_key);
|
||||
|
||||
if (ret) {
|
||||
WARN(IS_ENABLED(CONFIG_BTRFS_DEBUG),
|
||||
KERN_ERR "BTRFS: tree first key check failed\n");
|
||||
ret = btrfs_comp_cpu_keys(&check->first_key, &found_key);
|
||||
if (unlikely(ret)) {
|
||||
DEBUG_WARN();
|
||||
btrfs_err(fs_info,
|
||||
"tree first key mismatch detected, bytenr=%llu parent_transid=%llu key expected=(%llu,%u,%llu) has=(%llu,%u,%llu)",
|
||||
eb->start, check->transid, check->first_key.objectid,
|
||||
|
||||
+37
-29
@@ -860,9 +860,9 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_ordered_sum *sums;
|
||||
struct btrfs_root *csum_root;
|
||||
|
||||
sums = list_entry(ordered_sums.next,
|
||||
struct btrfs_ordered_sum,
|
||||
list);
|
||||
sums = list_first_entry(&ordered_sums,
|
||||
struct btrfs_ordered_sum,
|
||||
list);
|
||||
csum_root = btrfs_csum_root(fs_info,
|
||||
sums->logical);
|
||||
if (!ret)
|
||||
@@ -3251,8 +3251,8 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
}
|
||||
|
||||
extent_io_tree_release(&log->dirty_log_pages);
|
||||
extent_io_tree_release(&log->log_csum_range);
|
||||
btrfs_extent_io_tree_release(&log->dirty_log_pages);
|
||||
btrfs_extent_io_tree_release(&log->log_csum_range);
|
||||
|
||||
btrfs_put_root(log);
|
||||
}
|
||||
@@ -4300,8 +4300,8 @@ static int log_csums(struct btrfs_trans_handle *trans,
|
||||
* file which happens to refer to the same extent as well. Such races
|
||||
* can leave checksum items in the log with overlapping ranges.
|
||||
*/
|
||||
ret = lock_extent(&log_root->log_csum_range, sums->logical, lock_end,
|
||||
&cached_state);
|
||||
ret = btrfs_lock_extent(&log_root->log_csum_range, sums->logical, lock_end,
|
||||
&cached_state);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
@@ -4317,8 +4317,8 @@ static int log_csums(struct btrfs_trans_handle *trans,
|
||||
if (!ret)
|
||||
ret = btrfs_csum_file_blocks(trans, log_root, sums);
|
||||
|
||||
unlock_extent(&log_root->log_csum_range, sums->logical, lock_end,
|
||||
&cached_state);
|
||||
btrfs_unlock_extent(&log_root->log_csum_range, sums->logical, lock_end,
|
||||
&cached_state);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -4648,7 +4648,7 @@ static int log_extent_csums(struct btrfs_trans_handle *trans,
|
||||
return 0;
|
||||
|
||||
/* If we're compressed we have to save the entire range of csums. */
|
||||
if (extent_map_is_compressed(em)) {
|
||||
if (btrfs_extent_map_is_compressed(em)) {
|
||||
csum_offset = 0;
|
||||
csum_len = em->disk_num_bytes;
|
||||
} else {
|
||||
@@ -4657,7 +4657,7 @@ static int log_extent_csums(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
/* block start is already adjusted for the file extent offset. */
|
||||
block_start = extent_map_block_start(em);
|
||||
block_start = btrfs_extent_map_block_start(em);
|
||||
csum_root = btrfs_csum_root(trans->fs_info, block_start);
|
||||
ret = btrfs_lookup_csums_list(csum_root, block_start + csum_offset,
|
||||
block_start + csum_offset + csum_len - 1,
|
||||
@@ -4667,9 +4667,9 @@ static int log_extent_csums(struct btrfs_trans_handle *trans,
|
||||
ret = 0;
|
||||
|
||||
while (!list_empty(&ordered_sums)) {
|
||||
struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next,
|
||||
struct btrfs_ordered_sum,
|
||||
list);
|
||||
struct btrfs_ordered_sum *sums = list_first_entry(&ordered_sums,
|
||||
struct btrfs_ordered_sum,
|
||||
list);
|
||||
if (!ret)
|
||||
ret = log_csums(trans, inode, log_root, sums);
|
||||
list_del(&sums->list);
|
||||
@@ -4692,7 +4692,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_key key;
|
||||
enum btrfs_compression_type compress_type;
|
||||
u64 extent_offset = em->offset;
|
||||
u64 block_start = extent_map_block_start(em);
|
||||
u64 block_start = btrfs_extent_map_block_start(em);
|
||||
u64 block_len;
|
||||
int ret;
|
||||
|
||||
@@ -4703,7 +4703,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
|
||||
btrfs_set_stack_file_extent_type(&fi, BTRFS_FILE_EXTENT_REG);
|
||||
|
||||
block_len = em->disk_num_bytes;
|
||||
compress_type = extent_map_compression(em);
|
||||
compress_type = btrfs_extent_map_compression(em);
|
||||
if (compress_type != BTRFS_COMPRESS_NONE) {
|
||||
btrfs_set_stack_file_extent_disk_bytenr(&fi, block_start);
|
||||
btrfs_set_stack_file_extent_disk_num_bytes(&fi, block_len);
|
||||
@@ -4947,7 +4947,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
|
||||
list_sort(NULL, &extents, extent_cmp);
|
||||
process:
|
||||
while (!list_empty(&extents)) {
|
||||
em = list_entry(extents.next, struct extent_map, list);
|
||||
em = list_first_entry(&extents, struct extent_map, list);
|
||||
|
||||
list_del_init(&em->list);
|
||||
|
||||
@@ -4956,8 +4956,8 @@ process:
|
||||
* private list.
|
||||
*/
|
||||
if (ret) {
|
||||
clear_em_logging(inode, em);
|
||||
free_extent_map(em);
|
||||
btrfs_clear_em_logging(inode, em);
|
||||
btrfs_free_extent_map(em);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -4965,8 +4965,8 @@ process:
|
||||
|
||||
ret = log_one_extent(trans, inode, em, path, ctx);
|
||||
write_lock(&tree->lock);
|
||||
clear_em_logging(inode, em);
|
||||
free_extent_map(em);
|
||||
btrfs_clear_em_logging(inode, em);
|
||||
btrfs_free_extent_map(em);
|
||||
}
|
||||
WARN_ON(!list_empty(&extents));
|
||||
write_unlock(&tree->lock);
|
||||
@@ -6583,6 +6583,19 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
|
||||
btrfs_log_get_delayed_items(inode, &delayed_ins_list,
|
||||
&delayed_del_list);
|
||||
|
||||
/*
|
||||
* If we are fsyncing a file with 0 hard links, then commit the delayed
|
||||
* inode because the last inode ref (or extref) item may still be in the
|
||||
* subvolume tree and if we log it the file will still exist after a log
|
||||
* replay. So commit the delayed inode to delete that last ref and we
|
||||
* skip logging it.
|
||||
*/
|
||||
if (inode->vfs_inode.i_nlink == 0) {
|
||||
ret = btrfs_commit_inode_delayed_inode(inode);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = copy_inode_items_to_log(trans, inode, &min_key, &max_key,
|
||||
path, dst_path, logged_isize,
|
||||
inode_only, ctx,
|
||||
@@ -7051,14 +7064,9 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
|
||||
if (btrfs_root_generation(&root->root_item) == trans->transid)
|
||||
return BTRFS_LOG_FORCE_COMMIT;
|
||||
|
||||
/*
|
||||
* Skip already logged inodes or inodes corresponding to tmpfiles
|
||||
* (since logging them is pointless, a link count of 0 means they
|
||||
* will never be accessible).
|
||||
*/
|
||||
if ((btrfs_inode_in_log(inode, trans->transid) &&
|
||||
list_empty(&ctx->ordered_extents)) ||
|
||||
inode->vfs_inode.i_nlink == 0)
|
||||
/* Skip already logged inodes and without new extents. */
|
||||
if (btrfs_inode_in_log(inode, trans->transid) &&
|
||||
list_empty(&ctx->ordered_extents))
|
||||
return BTRFS_NO_LOG_SYNC;
|
||||
|
||||
ret = start_log_trans(trans, root, ctx);
|
||||
|
||||
+189
-156
@@ -404,7 +404,7 @@ static void btrfs_free_device(struct btrfs_device *device)
|
||||
{
|
||||
WARN_ON(!list_empty(&device->post_commit_list));
|
||||
rcu_string_free(device->name);
|
||||
extent_io_tree_release(&device->alloc_state);
|
||||
btrfs_extent_io_tree_release(&device->alloc_state);
|
||||
btrfs_destroy_dev_zone_info(device);
|
||||
kfree(device);
|
||||
}
|
||||
@@ -415,8 +415,8 @@ static void free_fs_devices(struct btrfs_fs_devices *fs_devices)
|
||||
|
||||
WARN_ON(fs_devices->opened);
|
||||
while (!list_empty(&fs_devices->devices)) {
|
||||
device = list_entry(fs_devices->devices.next,
|
||||
struct btrfs_device, dev_list);
|
||||
device = list_first_entry(&fs_devices->devices,
|
||||
struct btrfs_device, dev_list);
|
||||
list_del(&device->dev_list);
|
||||
btrfs_free_device(device);
|
||||
}
|
||||
@@ -428,8 +428,8 @@ void __exit btrfs_cleanup_fs_uuids(void)
|
||||
struct btrfs_fs_devices *fs_devices;
|
||||
|
||||
while (!list_empty(&fs_uuids)) {
|
||||
fs_devices = list_entry(fs_uuids.next,
|
||||
struct btrfs_fs_devices, fs_list);
|
||||
fs_devices = list_first_entry(&fs_uuids, struct btrfs_fs_devices,
|
||||
fs_list);
|
||||
list_del(&fs_devices->fs_list);
|
||||
free_fs_devices(fs_devices);
|
||||
}
|
||||
@@ -493,7 +493,7 @@ btrfs_get_bdev_and_sb(const char *device_path, blk_mode_t flags, void *holder,
|
||||
}
|
||||
}
|
||||
invalidate_bdev(bdev);
|
||||
*disk_super = btrfs_read_dev_super(bdev);
|
||||
*disk_super = btrfs_read_disk_super(bdev, 0, false);
|
||||
if (IS_ERR(*disk_super)) {
|
||||
ret = PTR_ERR(*disk_super);
|
||||
fput(*bdev_file);
|
||||
@@ -1149,7 +1149,7 @@ static void btrfs_close_one_device(struct btrfs_device *device)
|
||||
|
||||
device->fs_info = NULL;
|
||||
atomic_set(&device->dev_stats_ccnt, 0);
|
||||
extent_io_tree_release(&device->alloc_state);
|
||||
btrfs_extent_io_tree_release(&device->alloc_state);
|
||||
|
||||
/*
|
||||
* Reset the flush error record. We might have a transient flush error
|
||||
@@ -1325,48 +1325,58 @@ void btrfs_release_disk_super(struct btrfs_super_block *super)
|
||||
put_page(page);
|
||||
}
|
||||
|
||||
static struct btrfs_super_block *btrfs_read_disk_super(struct block_device *bdev,
|
||||
u64 bytenr, u64 bytenr_orig)
|
||||
struct btrfs_super_block *btrfs_read_disk_super(struct block_device *bdev,
|
||||
int copy_num, bool drop_cache)
|
||||
{
|
||||
struct btrfs_super_block *disk_super;
|
||||
struct btrfs_super_block *super;
|
||||
struct page *page;
|
||||
void *p;
|
||||
pgoff_t index;
|
||||
u64 bytenr, bytenr_orig;
|
||||
struct address_space *mapping = bdev->bd_mapping;
|
||||
int ret;
|
||||
|
||||
/* make sure our super fits in the device */
|
||||
if (bytenr + PAGE_SIZE >= bdev_nr_bytes(bdev))
|
||||
bytenr_orig = btrfs_sb_offset(copy_num);
|
||||
ret = btrfs_sb_log_location_bdev(bdev, copy_num, READ, &bytenr);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT)
|
||||
ret = -EINVAL;
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
if (bytenr + BTRFS_SUPER_INFO_SIZE >= bdev_nr_bytes(bdev))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* make sure our super fits in the page */
|
||||
if (sizeof(*disk_super) > PAGE_SIZE)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (drop_cache) {
|
||||
/* This should only be called with the primary sb. */
|
||||
ASSERT(copy_num == 0);
|
||||
|
||||
/* make sure our super doesn't straddle pages on disk */
|
||||
index = bytenr >> PAGE_SHIFT;
|
||||
if ((bytenr + sizeof(*disk_super) - 1) >> PAGE_SHIFT != index)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* pull in the page with our super */
|
||||
page = read_cache_page_gfp(bdev->bd_mapping, index, GFP_KERNEL);
|
||||
/*
|
||||
* Drop the page of the primary superblock, so later read will
|
||||
* always read from the device.
|
||||
*/
|
||||
invalidate_inode_pages2_range(mapping, bytenr >> PAGE_SHIFT,
|
||||
(bytenr + BTRFS_SUPER_INFO_SIZE) >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
page = read_cache_page_gfp(mapping, bytenr >> PAGE_SHIFT, GFP_NOFS);
|
||||
if (IS_ERR(page))
|
||||
return ERR_CAST(page);
|
||||
|
||||
p = page_address(page);
|
||||
|
||||
/* align our pointer to the offset of the super block */
|
||||
disk_super = p + offset_in_page(bytenr);
|
||||
|
||||
if (btrfs_super_bytenr(disk_super) != bytenr_orig ||
|
||||
btrfs_super_magic(disk_super) != BTRFS_MAGIC) {
|
||||
btrfs_release_disk_super(p);
|
||||
super = page_address(page);
|
||||
if (btrfs_super_magic(super) != BTRFS_MAGIC ||
|
||||
btrfs_super_bytenr(super) != bytenr_orig) {
|
||||
btrfs_release_disk_super(super);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (disk_super->label[0] && disk_super->label[BTRFS_LABEL_SIZE - 1])
|
||||
disk_super->label[BTRFS_LABEL_SIZE - 1] = 0;
|
||||
/*
|
||||
* Make sure the last byte of label is properly NUL termiated. We use
|
||||
* '%s' to print the label, if not properly NUL termiated we can access
|
||||
* beyond the label.
|
||||
*/
|
||||
if (super->label[0] && super->label[BTRFS_LABEL_SIZE - 1])
|
||||
super->label[BTRFS_LABEL_SIZE - 1] = 0;
|
||||
|
||||
return disk_super;
|
||||
return super;
|
||||
}
|
||||
|
||||
int btrfs_forget_devices(dev_t devt)
|
||||
@@ -1437,9 +1447,7 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
|
||||
bool new_device_added = false;
|
||||
struct btrfs_device *device = NULL;
|
||||
struct file *bdev_file;
|
||||
u64 bytenr;
|
||||
dev_t devt;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&uuid_mutex);
|
||||
|
||||
@@ -1457,20 +1465,7 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
|
||||
if (IS_ERR(bdev_file))
|
||||
return ERR_CAST(bdev_file);
|
||||
|
||||
/*
|
||||
* We would like to check all the super blocks, but doing so would
|
||||
* allow a mount to succeed after a mkfs from a different filesystem.
|
||||
* Currently, recovery from a bad primary btrfs superblock is done
|
||||
* using the userspace command 'btrfs check --super'.
|
||||
*/
|
||||
ret = btrfs_sb_log_location_bdev(file_bdev(bdev_file), 0, READ, &bytenr);
|
||||
if (ret) {
|
||||
device = ERR_PTR(ret);
|
||||
goto error_bdev_put;
|
||||
}
|
||||
|
||||
disk_super = btrfs_read_disk_super(file_bdev(bdev_file), bytenr,
|
||||
btrfs_sb_offset(0));
|
||||
disk_super = btrfs_read_disk_super(file_bdev(bdev_file), 0, false);
|
||||
if (IS_ERR(disk_super)) {
|
||||
device = ERR_CAST(disk_super);
|
||||
goto error_bdev_put;
|
||||
@@ -1511,9 +1506,9 @@ static bool contains_pending_extent(struct btrfs_device *device, u64 *start,
|
||||
|
||||
lockdep_assert_held(&device->fs_info->chunk_mutex);
|
||||
|
||||
if (find_first_extent_bit(&device->alloc_state, *start,
|
||||
&physical_start, &physical_end,
|
||||
CHUNK_ALLOCATED, NULL)) {
|
||||
if (btrfs_find_first_extent_bit(&device->alloc_state, *start,
|
||||
&physical_start, &physical_end,
|
||||
CHUNK_ALLOCATED, NULL)) {
|
||||
|
||||
if (in_range(physical_start, *start, len) ||
|
||||
in_range(*start, physical_start,
|
||||
@@ -1528,6 +1523,9 @@ static bool contains_pending_extent(struct btrfs_device *device, u64 *start,
|
||||
static u64 dev_extent_search_start(struct btrfs_device *device)
|
||||
{
|
||||
switch (device->fs_devices->chunk_alloc_policy) {
|
||||
default:
|
||||
btrfs_warn_unknown_chunk_allocation(device->fs_devices->chunk_alloc_policy);
|
||||
fallthrough;
|
||||
case BTRFS_CHUNK_ALLOC_REGULAR:
|
||||
return BTRFS_DEVICE_RANGE_RESERVED;
|
||||
case BTRFS_CHUNK_ALLOC_ZONED:
|
||||
@@ -1537,8 +1535,6 @@ static u64 dev_extent_search_start(struct btrfs_device *device)
|
||||
* for superblock logging.
|
||||
*/
|
||||
return 0;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1551,7 +1547,8 @@ static bool dev_extent_hole_check_zoned(struct btrfs_device *device,
|
||||
int ret;
|
||||
bool changed = false;
|
||||
|
||||
ASSERT(IS_ALIGNED(*hole_start, zone_size));
|
||||
ASSERT(IS_ALIGNED(*hole_start, zone_size),
|
||||
"hole_start=%llu zone_size=%llu", *hole_start, zone_size);
|
||||
|
||||
while (*hole_size > 0) {
|
||||
pos = btrfs_find_allocatable_zones(device, *hole_start,
|
||||
@@ -1617,6 +1614,9 @@ static bool dev_extent_hole_check(struct btrfs_device *device, u64 *hole_start,
|
||||
}
|
||||
|
||||
switch (device->fs_devices->chunk_alloc_policy) {
|
||||
default:
|
||||
btrfs_warn_unknown_chunk_allocation(device->fs_devices->chunk_alloc_policy);
|
||||
fallthrough;
|
||||
case BTRFS_CHUNK_ALLOC_REGULAR:
|
||||
/* No extra check */
|
||||
break;
|
||||
@@ -1631,8 +1631,6 @@ static bool dev_extent_hole_check(struct btrfs_device *device, u64 *hole_start,
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1802,7 +1800,9 @@ next:
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
ASSERT(max_hole_start + max_hole_size <= search_end);
|
||||
ASSERT(max_hole_start + max_hole_size <= search_end,
|
||||
"max_hole_start=%llu max_hole_size=%llu search_end=%llu",
|
||||
max_hole_start, max_hole_size, search_end);
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
*start = max_hole_start;
|
||||
@@ -2115,7 +2115,7 @@ static u64 btrfs_num_devices(struct btrfs_fs_info *fs_info)
|
||||
|
||||
down_read(&fs_info->dev_replace.rwsem);
|
||||
if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) {
|
||||
ASSERT(num_devices > 1);
|
||||
ASSERT(num_devices > 1, "num_devices=%llu", num_devices);
|
||||
num_devices--;
|
||||
}
|
||||
up_read(&fs_info->dev_replace.rwsem);
|
||||
@@ -2131,7 +2131,7 @@ static void btrfs_scratch_superblock(struct btrfs_fs_info *fs_info,
|
||||
const u64 bytenr = btrfs_sb_offset(copy_num);
|
||||
int ret;
|
||||
|
||||
disk_super = btrfs_read_disk_super(bdev, bytenr, bytenr);
|
||||
disk_super = btrfs_read_disk_super(bdev, copy_num, false);
|
||||
if (IS_ERR(disk_super))
|
||||
return;
|
||||
|
||||
@@ -2319,7 +2319,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
|
||||
*/
|
||||
if (cur_devices->num_devices == 0) {
|
||||
list_del_init(&cur_devices->seed_list);
|
||||
ASSERT(cur_devices->opened == 1);
|
||||
ASSERT(cur_devices->opened == 1, "opened=%d", cur_devices->opened);
|
||||
cur_devices->opened--;
|
||||
free_fs_devices(cur_devices);
|
||||
}
|
||||
@@ -3249,7 +3249,8 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset)
|
||||
* user having built with ASSERT enabled, so if ASSERT doesn't
|
||||
* do anything we still error out.
|
||||
*/
|
||||
ASSERT(0);
|
||||
DEBUG_WARN("errr %ld reading chunk map at offset %llu",
|
||||
PTR_ERR(map), chunk_offset);
|
||||
return PTR_ERR(map);
|
||||
}
|
||||
|
||||
@@ -3330,8 +3331,16 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset)
|
||||
if (ret == -ENOSPC) {
|
||||
const u64 sys_flags = btrfs_system_alloc_profile(fs_info);
|
||||
struct btrfs_block_group *sys_bg;
|
||||
struct btrfs_space_info *space_info;
|
||||
|
||||
sys_bg = btrfs_create_chunk(trans, sys_flags);
|
||||
space_info = btrfs_find_space_info(fs_info, sys_flags);
|
||||
if (!space_info) {
|
||||
ret = -EINVAL;
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sys_bg = btrfs_create_chunk(trans, space_info, sys_flags);
|
||||
if (IS_ERR(sys_bg)) {
|
||||
ret = PTR_ERR(sys_bg);
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
@@ -3791,26 +3800,25 @@ static void reset_balance_state(struct btrfs_fs_info *fs_info)
|
||||
* Balance filters. Return 1 if chunk should be filtered out
|
||||
* (should not be balanced).
|
||||
*/
|
||||
static int chunk_profiles_filter(u64 chunk_type,
|
||||
struct btrfs_balance_args *bargs)
|
||||
static bool chunk_profiles_filter(u64 chunk_type, struct btrfs_balance_args *bargs)
|
||||
{
|
||||
chunk_type = chunk_to_extended(chunk_type) &
|
||||
BTRFS_EXTENDED_PROFILE_MASK;
|
||||
|
||||
if (bargs->profiles & chunk_type)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
|
||||
struct btrfs_balance_args *bargs)
|
||||
static bool chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
|
||||
struct btrfs_balance_args *bargs)
|
||||
{
|
||||
struct btrfs_block_group *cache;
|
||||
u64 chunk_used;
|
||||
u64 user_thresh_min;
|
||||
u64 user_thresh_max;
|
||||
int ret = 1;
|
||||
bool ret = true;
|
||||
|
||||
cache = btrfs_lookup_block_group(fs_info, chunk_offset);
|
||||
chunk_used = cache->used;
|
||||
@@ -3828,18 +3836,18 @@ static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chunk_off
|
||||
user_thresh_max = mult_perc(cache->length, bargs->usage_max);
|
||||
|
||||
if (user_thresh_min <= chunk_used && chunk_used < user_thresh_max)
|
||||
ret = 0;
|
||||
ret = false;
|
||||
|
||||
btrfs_put_block_group(cache);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int chunk_usage_filter(struct btrfs_fs_info *fs_info,
|
||||
u64 chunk_offset, struct btrfs_balance_args *bargs)
|
||||
static bool chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
|
||||
struct btrfs_balance_args *bargs)
|
||||
{
|
||||
struct btrfs_block_group *cache;
|
||||
u64 chunk_used, user_thresh;
|
||||
int ret = 1;
|
||||
bool ret = true;
|
||||
|
||||
cache = btrfs_lookup_block_group(fs_info, chunk_offset);
|
||||
chunk_used = cache->used;
|
||||
@@ -3852,15 +3860,14 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info,
|
||||
user_thresh = mult_perc(cache->length, bargs->usage);
|
||||
|
||||
if (chunk_used < user_thresh)
|
||||
ret = 0;
|
||||
ret = false;
|
||||
|
||||
btrfs_put_block_group(cache);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int chunk_devid_filter(struct extent_buffer *leaf,
|
||||
struct btrfs_chunk *chunk,
|
||||
struct btrfs_balance_args *bargs)
|
||||
static bool chunk_devid_filter(struct extent_buffer *leaf, struct btrfs_chunk *chunk,
|
||||
struct btrfs_balance_args *bargs)
|
||||
{
|
||||
struct btrfs_stripe *stripe;
|
||||
int num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
|
||||
@@ -3869,10 +3876,10 @@ static int chunk_devid_filter(struct extent_buffer *leaf,
|
||||
for (i = 0; i < num_stripes; i++) {
|
||||
stripe = btrfs_stripe_nr(chunk, i);
|
||||
if (btrfs_stripe_devid(leaf, stripe) == bargs->devid)
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static u64 calc_data_stripes(u64 type, int num_stripes)
|
||||
@@ -3885,9 +3892,8 @@ static u64 calc_data_stripes(u64 type, int num_stripes)
|
||||
}
|
||||
|
||||
/* [pstart, pend) */
|
||||
static int chunk_drange_filter(struct extent_buffer *leaf,
|
||||
struct btrfs_chunk *chunk,
|
||||
struct btrfs_balance_args *bargs)
|
||||
static bool chunk_drange_filter(struct extent_buffer *leaf, struct btrfs_chunk *chunk,
|
||||
struct btrfs_balance_args *bargs)
|
||||
{
|
||||
struct btrfs_stripe *stripe;
|
||||
int num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
|
||||
@@ -3898,7 +3904,7 @@ static int chunk_drange_filter(struct extent_buffer *leaf,
|
||||
int i;
|
||||
|
||||
if (!(bargs->flags & BTRFS_BALANCE_ARGS_DEVID))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
type = btrfs_chunk_type(leaf, chunk);
|
||||
factor = calc_data_stripes(type, num_stripes);
|
||||
@@ -3914,56 +3920,53 @@ static int chunk_drange_filter(struct extent_buffer *leaf,
|
||||
|
||||
if (stripe_offset < bargs->pend &&
|
||||
stripe_offset + stripe_length > bargs->pstart)
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* [vstart, vend) */
|
||||
static int chunk_vrange_filter(struct extent_buffer *leaf,
|
||||
struct btrfs_chunk *chunk,
|
||||
u64 chunk_offset,
|
||||
struct btrfs_balance_args *bargs)
|
||||
static bool chunk_vrange_filter(struct extent_buffer *leaf, struct btrfs_chunk *chunk,
|
||||
u64 chunk_offset, struct btrfs_balance_args *bargs)
|
||||
{
|
||||
if (chunk_offset < bargs->vend &&
|
||||
chunk_offset + btrfs_chunk_length(leaf, chunk) > bargs->vstart)
|
||||
/* at least part of the chunk is inside this vrange */
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int chunk_stripes_range_filter(struct extent_buffer *leaf,
|
||||
struct btrfs_chunk *chunk,
|
||||
struct btrfs_balance_args *bargs)
|
||||
static bool chunk_stripes_range_filter(struct extent_buffer *leaf,
|
||||
struct btrfs_chunk *chunk,
|
||||
struct btrfs_balance_args *bargs)
|
||||
{
|
||||
int num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
|
||||
|
||||
if (bargs->stripes_min <= num_stripes
|
||||
&& num_stripes <= bargs->stripes_max)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int chunk_soft_convert_filter(u64 chunk_type,
|
||||
struct btrfs_balance_args *bargs)
|
||||
static bool chunk_soft_convert_filter(u64 chunk_type, struct btrfs_balance_args *bargs)
|
||||
{
|
||||
if (!(bargs->flags & BTRFS_BALANCE_ARGS_CONVERT))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
chunk_type = chunk_to_extended(chunk_type) &
|
||||
BTRFS_EXTENDED_PROFILE_MASK;
|
||||
|
||||
if (bargs->target == chunk_type)
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int should_balance_chunk(struct extent_buffer *leaf,
|
||||
struct btrfs_chunk *chunk, u64 chunk_offset)
|
||||
static bool should_balance_chunk(struct extent_buffer *leaf, struct btrfs_chunk *chunk,
|
||||
u64 chunk_offset)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = leaf->fs_info;
|
||||
struct btrfs_balance_control *bctl = fs_info->balance_ctl;
|
||||
@@ -3973,7 +3976,7 @@ static int should_balance_chunk(struct extent_buffer *leaf,
|
||||
/* type filter */
|
||||
if (!((chunk_type & BTRFS_BLOCK_GROUP_TYPE_MASK) &
|
||||
(bctl->flags & BTRFS_BALANCE_TYPE_MASK))) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chunk_type & BTRFS_BLOCK_GROUP_DATA)
|
||||
@@ -3986,46 +3989,46 @@ static int should_balance_chunk(struct extent_buffer *leaf,
|
||||
/* profiles filter */
|
||||
if ((bargs->flags & BTRFS_BALANCE_ARGS_PROFILES) &&
|
||||
chunk_profiles_filter(chunk_type, bargs)) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* usage filter */
|
||||
if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE) &&
|
||||
chunk_usage_filter(fs_info, chunk_offset, bargs)) {
|
||||
return 0;
|
||||
return false;
|
||||
} else if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) &&
|
||||
chunk_usage_range_filter(fs_info, chunk_offset, bargs)) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* devid filter */
|
||||
if ((bargs->flags & BTRFS_BALANCE_ARGS_DEVID) &&
|
||||
chunk_devid_filter(leaf, chunk, bargs)) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* drange filter, makes sense only with devid filter */
|
||||
if ((bargs->flags & BTRFS_BALANCE_ARGS_DRANGE) &&
|
||||
chunk_drange_filter(leaf, chunk, bargs)) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* vrange filter */
|
||||
if ((bargs->flags & BTRFS_BALANCE_ARGS_VRANGE) &&
|
||||
chunk_vrange_filter(leaf, chunk, chunk_offset, bargs)) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* stripes filter */
|
||||
if ((bargs->flags & BTRFS_BALANCE_ARGS_STRIPES_RANGE) &&
|
||||
chunk_stripes_range_filter(leaf, chunk, bargs)) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* soft profile changing mode */
|
||||
if ((bargs->flags & BTRFS_BALANCE_ARGS_SOFT) &&
|
||||
chunk_soft_convert_filter(chunk_type, bargs)) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4033,7 +4036,7 @@ static int should_balance_chunk(struct extent_buffer *leaf,
|
||||
*/
|
||||
if ((bargs->flags & BTRFS_BALANCE_ARGS_LIMIT)) {
|
||||
if (bargs->limit == 0)
|
||||
return 0;
|
||||
return false;
|
||||
else
|
||||
bargs->limit--;
|
||||
} else if ((bargs->flags & BTRFS_BALANCE_ARGS_LIMIT_RANGE)) {
|
||||
@@ -4043,12 +4046,12 @@ static int should_balance_chunk(struct extent_buffer *leaf,
|
||||
* about the count of all chunks that satisfy the filters.
|
||||
*/
|
||||
if (bargs->limit_max == 0)
|
||||
return 0;
|
||||
return false;
|
||||
else
|
||||
bargs->limit_max--;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int __btrfs_balance(struct btrfs_fs_info *fs_info)
|
||||
@@ -4663,7 +4666,8 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info)
|
||||
}
|
||||
|
||||
spin_lock(&fs_info->super_lock);
|
||||
ASSERT(fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE_PAUSED);
|
||||
ASSERT(fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE_PAUSED,
|
||||
"exclusive_operation=%d", fs_info->exclusive_operation);
|
||||
fs_info->exclusive_operation = BTRFS_EXCLOP_BALANCE;
|
||||
spin_unlock(&fs_info->super_lock);
|
||||
/*
|
||||
@@ -4999,8 +5003,8 @@ again:
|
||||
|
||||
mutex_lock(&fs_info->chunk_mutex);
|
||||
/* Clear all state bits beyond the shrunk device size */
|
||||
clear_extent_bits(&device->alloc_state, new_size, (u64)-1,
|
||||
CHUNK_STATE_MASK);
|
||||
btrfs_clear_extent_bits(&device->alloc_state, new_size, (u64)-1,
|
||||
CHUNK_STATE_MASK);
|
||||
|
||||
btrfs_device_set_disk_total_bytes(device, new_size);
|
||||
if (list_empty(&device->post_commit_list))
|
||||
@@ -5127,6 +5131,8 @@ struct alloc_chunk_ctl {
|
||||
u64 stripe_size;
|
||||
u64 chunk_size;
|
||||
int ndevs;
|
||||
/* Space_info the block group is going to belong. */
|
||||
struct btrfs_space_info *space_info;
|
||||
};
|
||||
|
||||
static void init_alloc_chunk_ctl_policy_regular(
|
||||
@@ -5200,14 +5206,15 @@ static void init_alloc_chunk_ctl(struct btrfs_fs_devices *fs_devices,
|
||||
ctl->ndevs = 0;
|
||||
|
||||
switch (fs_devices->chunk_alloc_policy) {
|
||||
default:
|
||||
btrfs_warn_unknown_chunk_allocation(fs_devices->chunk_alloc_policy);
|
||||
fallthrough;
|
||||
case BTRFS_CHUNK_ALLOC_REGULAR:
|
||||
init_alloc_chunk_ctl_policy_regular(fs_devices, ctl);
|
||||
break;
|
||||
case BTRFS_CHUNK_ALLOC_ZONED:
|
||||
init_alloc_chunk_ctl_policy_zoned(fs_devices, ctl);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5346,7 +5353,9 @@ static int decide_stripe_size_zoned(struct alloc_chunk_ctl *ctl,
|
||||
* It should hold because:
|
||||
* dev_extent_min == dev_extent_want == zone_size * dev_stripes
|
||||
*/
|
||||
ASSERT(devices_info[ctl->ndevs - 1].max_avail == ctl->dev_extent_min);
|
||||
ASSERT(devices_info[ctl->ndevs - 1].max_avail == ctl->dev_extent_min,
|
||||
"ndevs=%d max_avail=%llu dev_extent_min=%llu", ctl->ndevs,
|
||||
devices_info[ctl->ndevs - 1].max_avail, ctl->dev_extent_min);
|
||||
|
||||
ctl->stripe_size = zone_size;
|
||||
ctl->num_stripes = ctl->ndevs * ctl->dev_stripes;
|
||||
@@ -5359,7 +5368,9 @@ static int decide_stripe_size_zoned(struct alloc_chunk_ctl *ctl,
|
||||
ctl->dev_stripes);
|
||||
ctl->num_stripes = ctl->ndevs * ctl->dev_stripes;
|
||||
data_stripes = (ctl->num_stripes - ctl->nparity) / ctl->ncopies;
|
||||
ASSERT(ctl->stripe_size * data_stripes <= ctl->max_chunk_size);
|
||||
ASSERT(ctl->stripe_size * data_stripes <= ctl->max_chunk_size,
|
||||
"stripe_size=%llu data_stripes=%d max_chunk_size=%llu",
|
||||
ctl->stripe_size, data_stripes, ctl->max_chunk_size);
|
||||
}
|
||||
|
||||
ctl->chunk_size = ctl->stripe_size * data_stripes;
|
||||
@@ -5392,12 +5403,13 @@ static int decide_stripe_size(struct btrfs_fs_devices *fs_devices,
|
||||
ctl->ndevs = min(ctl->ndevs, ctl->devs_max);
|
||||
|
||||
switch (fs_devices->chunk_alloc_policy) {
|
||||
default:
|
||||
btrfs_warn_unknown_chunk_allocation(fs_devices->chunk_alloc_policy);
|
||||
fallthrough;
|
||||
case BTRFS_CHUNK_ALLOC_REGULAR:
|
||||
return decide_stripe_size_regular(ctl, devices_info);
|
||||
case BTRFS_CHUNK_ALLOC_ZONED:
|
||||
return decide_stripe_size_zoned(ctl, devices_info);
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5407,9 +5419,9 @@ static void chunk_map_device_set_bits(struct btrfs_chunk_map *map, unsigned int
|
||||
struct btrfs_io_stripe *stripe = &map->stripes[i];
|
||||
struct btrfs_device *device = stripe->dev;
|
||||
|
||||
set_extent_bit(&device->alloc_state, stripe->physical,
|
||||
stripe->physical + map->stripe_size - 1,
|
||||
bits | EXTENT_NOWAIT, NULL);
|
||||
btrfs_set_extent_bit(&device->alloc_state, stripe->physical,
|
||||
stripe->physical + map->stripe_size - 1,
|
||||
bits | EXTENT_NOWAIT, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5419,10 +5431,9 @@ static void chunk_map_device_clear_bits(struct btrfs_chunk_map *map, unsigned in
|
||||
struct btrfs_io_stripe *stripe = &map->stripes[i];
|
||||
struct btrfs_device *device = stripe->dev;
|
||||
|
||||
__clear_extent_bit(&device->alloc_state, stripe->physical,
|
||||
stripe->physical + map->stripe_size - 1,
|
||||
bits | EXTENT_NOWAIT,
|
||||
NULL, NULL);
|
||||
btrfs_clear_extent_bits(&device->alloc_state, stripe->physical,
|
||||
stripe->physical + map->stripe_size - 1,
|
||||
bits | EXTENT_NOWAIT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5529,7 +5540,8 @@ static struct btrfs_block_group *create_chunk(struct btrfs_trans_handle *trans,
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
block_group = btrfs_make_block_group(trans, type, start, ctl->chunk_size);
|
||||
block_group = btrfs_make_block_group(trans, ctl->space_info, type, start,
|
||||
ctl->chunk_size);
|
||||
if (IS_ERR(block_group)) {
|
||||
btrfs_remove_chunk_map(info, map);
|
||||
return block_group;
|
||||
@@ -5555,7 +5567,8 @@ static struct btrfs_block_group *create_chunk(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,
|
||||
u64 type)
|
||||
struct btrfs_space_info *space_info,
|
||||
u64 type)
|
||||
{
|
||||
struct btrfs_fs_info *info = trans->fs_info;
|
||||
struct btrfs_fs_devices *fs_devices = info->fs_devices;
|
||||
@@ -5567,7 +5580,7 @@ struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,
|
||||
lockdep_assert_held(&info->chunk_mutex);
|
||||
|
||||
if (!alloc_profile_is_valid(type, 0)) {
|
||||
ASSERT(0);
|
||||
DEBUG_WARN("invalid alloc profile for type %llu", type);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
@@ -5579,12 +5592,13 @@ struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,
|
||||
|
||||
if (!(type & BTRFS_BLOCK_GROUP_TYPE_MASK)) {
|
||||
btrfs_err(info, "invalid chunk type 0x%llx requested", type);
|
||||
ASSERT(0);
|
||||
DEBUG_WARN();
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
ctl.start = find_next_chunk(info);
|
||||
ctl.type = type;
|
||||
ctl.space_info = space_info;
|
||||
init_alloc_chunk_ctl(fs_devices, &ctl);
|
||||
|
||||
devices_info = kcalloc(fs_devices->rw_devices, sizeof(*devices_info),
|
||||
@@ -5728,7 +5742,9 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans)
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
u64 alloc_profile;
|
||||
struct btrfs_block_group *meta_bg;
|
||||
struct btrfs_space_info *meta_space_info;
|
||||
struct btrfs_block_group *sys_bg;
|
||||
struct btrfs_space_info *sys_space_info;
|
||||
|
||||
/*
|
||||
* When adding a new device for sprouting, the seed device is read-only
|
||||
@@ -5752,12 +5768,22 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans)
|
||||
*/
|
||||
|
||||
alloc_profile = btrfs_metadata_alloc_profile(fs_info);
|
||||
meta_bg = btrfs_create_chunk(trans, alloc_profile);
|
||||
meta_space_info = btrfs_find_space_info(fs_info, alloc_profile);
|
||||
if (!meta_space_info) {
|
||||
DEBUG_WARN();
|
||||
return -EINVAL;
|
||||
}
|
||||
meta_bg = btrfs_create_chunk(trans, meta_space_info, alloc_profile);
|
||||
if (IS_ERR(meta_bg))
|
||||
return PTR_ERR(meta_bg);
|
||||
|
||||
alloc_profile = btrfs_system_alloc_profile(fs_info);
|
||||
sys_bg = btrfs_create_chunk(trans, alloc_profile);
|
||||
sys_space_info = btrfs_find_space_info(fs_info, alloc_profile);
|
||||
if (!sys_space_info) {
|
||||
DEBUG_WARN();
|
||||
return -EINVAL;
|
||||
}
|
||||
sys_bg = btrfs_create_chunk(trans, sys_space_info, alloc_profile);
|
||||
if (IS_ERR(sys_bg))
|
||||
return PTR_ERR(sys_bg);
|
||||
|
||||
@@ -5957,7 +5983,7 @@ static int btrfs_read_rr(const struct btrfs_chunk_map *map, int first, int num_s
|
||||
|
||||
static int find_live_mirror(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_chunk_map *map, int first,
|
||||
int dev_replace_is_ongoing)
|
||||
bool dev_replace_is_ongoing)
|
||||
{
|
||||
const enum btrfs_read_policy policy = READ_ONCE(fs_info->fs_devices->read_policy);
|
||||
int i;
|
||||
@@ -5966,8 +5992,8 @@ static int find_live_mirror(struct btrfs_fs_info *fs_info,
|
||||
int tolerance;
|
||||
struct btrfs_device *srcdev;
|
||||
|
||||
ASSERT((map->type &
|
||||
(BTRFS_BLOCK_GROUP_RAID1_MASK | BTRFS_BLOCK_GROUP_RAID10)));
|
||||
ASSERT((map->type & (BTRFS_BLOCK_GROUP_RAID1_MASK | BTRFS_BLOCK_GROUP_RAID10)),
|
||||
"type=%llu", map->type);
|
||||
|
||||
if (map->type & BTRFS_BLOCK_GROUP_RAID10)
|
||||
num_stripes = map->sub_stripes;
|
||||
@@ -6268,7 +6294,7 @@ static void handle_ops_on_dev_replace(struct btrfs_io_context *bioc,
|
||||
}
|
||||
|
||||
/* We can only have at most 2 extra nr_stripes (for DUP). */
|
||||
ASSERT(nr_extra_stripes <= 2);
|
||||
ASSERT(nr_extra_stripes <= 2, "nr_extra_stripes=%d", nr_extra_stripes);
|
||||
/*
|
||||
* For GET_READ_MIRRORS, we can only return at most 1 extra stripe for
|
||||
* replace.
|
||||
@@ -6279,7 +6305,8 @@ static void handle_ops_on_dev_replace(struct btrfs_io_context *bioc,
|
||||
struct btrfs_io_stripe *second = &bioc->stripes[num_stripes + 1];
|
||||
|
||||
/* Only DUP can have two extra stripes. */
|
||||
ASSERT(bioc->map_type & BTRFS_BLOCK_GROUP_DUP);
|
||||
ASSERT(bioc->map_type & BTRFS_BLOCK_GROUP_DUP,
|
||||
"map_type=%llu", bioc->map_type);
|
||||
|
||||
/*
|
||||
* Swap the last stripe stripes and reduce @nr_extra_stripes.
|
||||
@@ -6306,7 +6333,8 @@ static u64 btrfs_max_io_len(struct btrfs_chunk_map *map, u64 offset,
|
||||
*/
|
||||
io_geom->stripe_offset = offset & BTRFS_STRIPE_LEN_MASK;
|
||||
io_geom->stripe_nr = offset >> BTRFS_STRIPE_LEN_SHIFT;
|
||||
ASSERT(io_geom->stripe_offset < U32_MAX);
|
||||
ASSERT(io_geom->stripe_offset < U32_MAX,
|
||||
"stripe_offset=%llu", io_geom->stripe_offset);
|
||||
|
||||
if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
|
||||
unsigned long full_stripe_len =
|
||||
@@ -6324,8 +6352,12 @@ static u64 btrfs_max_io_len(struct btrfs_chunk_map *map, u64 offset,
|
||||
io_geom->raid56_full_stripe_start = btrfs_stripe_nr_to_offset(
|
||||
rounddown(io_geom->stripe_nr, nr_data_stripes(map)));
|
||||
|
||||
ASSERT(io_geom->raid56_full_stripe_start + full_stripe_len > offset);
|
||||
ASSERT(io_geom->raid56_full_stripe_start <= offset);
|
||||
ASSERT(io_geom->raid56_full_stripe_start + full_stripe_len > offset,
|
||||
"raid56_full_stripe_start=%llu full_stripe_len=%lu offset=%llu",
|
||||
io_geom->raid56_full_stripe_start, full_stripe_len, offset);
|
||||
ASSERT(io_geom->raid56_full_stripe_start <= offset,
|
||||
"raid56_full_stripe_start=%llu offset=%llu",
|
||||
io_geom->raid56_full_stripe_start, offset);
|
||||
/*
|
||||
* For writes to RAID56, allow to write a full stripe set, but
|
||||
* no straddling of stripe sets.
|
||||
@@ -6491,7 +6523,7 @@ static void map_blocks_raid56_read(struct btrfs_chunk_map *map,
|
||||
{
|
||||
int data_stripes = nr_data_stripes(map);
|
||||
|
||||
ASSERT(io_geom->mirror_num <= 1);
|
||||
ASSERT(io_geom->mirror_num <= 1, "mirror_num=%d", io_geom->mirror_num);
|
||||
/* Just grab the data stripe directly. */
|
||||
io_geom->stripe_index = io_geom->stripe_nr % data_stripes;
|
||||
io_geom->stripe_nr /= data_stripes;
|
||||
@@ -6559,7 +6591,7 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
|
||||
int num_copies;
|
||||
struct btrfs_io_context *bioc = NULL;
|
||||
struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
|
||||
int dev_replace_is_ongoing = 0;
|
||||
bool dev_replace_is_ongoing = false;
|
||||
u16 num_alloc_stripes;
|
||||
u64 max_len;
|
||||
|
||||
@@ -6864,7 +6896,7 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
|
||||
|
||||
atomic_set(&dev->dev_stats_ccnt, 0);
|
||||
btrfs_device_data_ordered_init(dev);
|
||||
extent_io_tree_init(fs_info, &dev->alloc_state, IO_TREE_DEVICE_ALLOC_STATE);
|
||||
btrfs_extent_io_tree_init(fs_info, &dev->alloc_state, IO_TREE_DEVICE_ALLOC_STATE);
|
||||
|
||||
if (devid)
|
||||
tmp = *devid;
|
||||
@@ -7836,7 +7868,7 @@ void btrfs_commit_device_sizes(struct btrfs_transaction *trans)
|
||||
{
|
||||
struct btrfs_device *curr, *next;
|
||||
|
||||
ASSERT(trans->state == TRANS_STATE_COMMIT_DOING);
|
||||
ASSERT(trans->state == TRANS_STATE_COMMIT_DOING, "state=%d" , trans->state);
|
||||
|
||||
if (list_empty(&trans->dev_update_list))
|
||||
return;
|
||||
@@ -8205,7 +8237,7 @@ static void map_raid56_repair_block(struct btrfs_io_context *bioc,
|
||||
logical < stripe_start + BTRFS_STRIPE_LEN)
|
||||
break;
|
||||
}
|
||||
ASSERT(i < data_stripes);
|
||||
ASSERT(i < data_stripes, "i=%d data_stripes=%d", i, data_stripes);
|
||||
smap->dev = bioc->stripes[i].dev;
|
||||
smap->physical = bioc->stripes[i].physical +
|
||||
((logical - bioc->full_stripe_logical) &
|
||||
@@ -8234,7 +8266,7 @@ int btrfs_map_repair_block(struct btrfs_fs_info *fs_info,
|
||||
int mirror_ret = mirror_num;
|
||||
int ret;
|
||||
|
||||
ASSERT(mirror_num > 0);
|
||||
ASSERT(mirror_num > 0, "mirror_num=%d", mirror_num);
|
||||
|
||||
ret = btrfs_map_block(fs_info, BTRFS_MAP_WRITE, logical, &map_length,
|
||||
&bioc, smap, &mirror_ret);
|
||||
@@ -8242,7 +8274,7 @@ int btrfs_map_repair_block(struct btrfs_fs_info *fs_info,
|
||||
return ret;
|
||||
|
||||
/* The map range should not cross stripe boundary. */
|
||||
ASSERT(map_length >= length);
|
||||
ASSERT(map_length >= length, "map_length=%llu length=%u", map_length, length);
|
||||
|
||||
/* Already mapped to single stripe. */
|
||||
if (!bioc)
|
||||
@@ -8254,7 +8286,8 @@ int btrfs_map_repair_block(struct btrfs_fs_info *fs_info,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ASSERT(mirror_num <= bioc->num_stripes);
|
||||
ASSERT(mirror_num <= bioc->num_stripes,
|
||||
"mirror_num=%d num_stripes=%d", mirror_num, bioc->num_stripes);
|
||||
smap->dev = bioc->stripes[mirror_num - 1].dev;
|
||||
smap->physical = bioc->stripes[mirror_num - 1].physical;
|
||||
out:
|
||||
|
||||
+9
-2
@@ -473,7 +473,6 @@ struct btrfs_io_stripe {
|
||||
struct btrfs_device *dev;
|
||||
/* Block mapping. */
|
||||
u64 physical;
|
||||
u64 length;
|
||||
bool rst_search_commit_root;
|
||||
/* For the endio handler. */
|
||||
struct btrfs_io_context *bioc;
|
||||
@@ -715,7 +714,8 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
|
||||
int btrfs_read_sys_array(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info);
|
||||
struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,
|
||||
u64 type);
|
||||
struct btrfs_space_info *space_info,
|
||||
u64 type);
|
||||
void btrfs_mapping_tree_free(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
|
||||
blk_mode_t flags, void *holder);
|
||||
@@ -786,6 +786,8 @@ struct btrfs_chunk_map *btrfs_find_chunk_map_nolock(struct btrfs_fs_info *fs_inf
|
||||
struct btrfs_chunk_map *btrfs_get_chunk_map(struct btrfs_fs_info *fs_info,
|
||||
u64 logical, u64 length);
|
||||
void btrfs_remove_chunk_map(struct btrfs_fs_info *fs_info, struct btrfs_chunk_map *map);
|
||||
struct btrfs_super_block *btrfs_read_disk_super(struct block_device *bdev,
|
||||
int copy_num, bool drop_cache);
|
||||
void btrfs_release_disk_super(struct btrfs_super_block *super);
|
||||
|
||||
static inline void btrfs_dev_stat_inc(struct btrfs_device *dev,
|
||||
@@ -847,6 +849,11 @@ static inline const char *btrfs_dev_name(const struct btrfs_device *device)
|
||||
return rcu_str_deref(device->name);
|
||||
}
|
||||
|
||||
static inline void btrfs_warn_unknown_chunk_allocation(enum btrfs_chunk_allocation_policy pol)
|
||||
{
|
||||
WARN_ONCE(1, "unknown allocation policy %d, fallback to regular", pol);
|
||||
}
|
||||
|
||||
void btrfs_commit_device_sizes(struct btrfs_transaction *trans);
|
||||
|
||||
struct list_head * __attribute_const__ btrfs_get_fs_uuids(void);
|
||||
|
||||
+3
-6
@@ -120,8 +120,6 @@ static int copy_data_into_buffer(struct address_space *mapping,
|
||||
ret = btrfs_compress_filemap_get_folio(mapping, cur, &folio);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* No large folio support yet. */
|
||||
ASSERT(!folio_test_large(folio));
|
||||
|
||||
offset = offset_in_folio(folio, cur);
|
||||
copy_length = min(folio_size(folio) - offset,
|
||||
@@ -205,7 +203,6 @@ int zlib_compress_folios(struct list_head *ws, struct address_space *mapping,
|
||||
workspace->strm.next_in = workspace->buf;
|
||||
workspace->strm.avail_in = copy_length;
|
||||
} else {
|
||||
unsigned int pg_off;
|
||||
unsigned int cur_len;
|
||||
|
||||
if (data_in) {
|
||||
@@ -217,9 +214,9 @@ int zlib_compress_folios(struct list_head *ws, struct address_space *mapping,
|
||||
start, &in_folio);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
pg_off = offset_in_page(start);
|
||||
cur_len = btrfs_calc_input_length(orig_end, start);
|
||||
data_in = kmap_local_folio(in_folio, pg_off);
|
||||
cur_len = btrfs_calc_input_length(in_folio, orig_end, start);
|
||||
data_in = kmap_local_folio(in_folio,
|
||||
offset_in_folio(in_folio, start));
|
||||
start += cur_len;
|
||||
workspace->strm.next_in = data_in;
|
||||
workspace->strm.avail_in = cur_len;
|
||||
|
||||
+8
-20
@@ -989,7 +989,7 @@ int btrfs_advance_sb_log(struct btrfs_device *device, int mirror)
|
||||
}
|
||||
|
||||
/* All the zones are FULL. Should not reach here. */
|
||||
ASSERT(0);
|
||||
DEBUG_WARN("unexpected state, all zones full");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -1797,12 +1797,12 @@ static void btrfs_rewrite_logical_zoned(struct btrfs_ordered_extent *ordered,
|
||||
ordered->disk_bytenr = logical;
|
||||
|
||||
write_lock(&em_tree->lock);
|
||||
em = search_extent_mapping(em_tree, ordered->file_offset,
|
||||
ordered->num_bytes);
|
||||
em = btrfs_search_extent_mapping(em_tree, ordered->file_offset,
|
||||
ordered->num_bytes);
|
||||
/* The em should be a new COW extent, thus it should not have an offset. */
|
||||
ASSERT(em->offset == 0);
|
||||
em->disk_bytenr = logical;
|
||||
free_extent_map(em);
|
||||
btrfs_free_extent_map(em);
|
||||
write_unlock(&em_tree->lock);
|
||||
}
|
||||
|
||||
@@ -1812,8 +1812,8 @@ static bool btrfs_zoned_split_ordered(struct btrfs_ordered_extent *ordered,
|
||||
struct btrfs_ordered_extent *new;
|
||||
|
||||
if (!test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags) &&
|
||||
split_extent_map(ordered->inode, ordered->file_offset,
|
||||
ordered->num_bytes, len, logical))
|
||||
btrfs_split_extent_map(ordered->inode, ordered->file_offset,
|
||||
ordered->num_bytes, len, logical))
|
||||
return false;
|
||||
|
||||
new = btrfs_split_ordered_extent(ordered, len);
|
||||
@@ -2171,27 +2171,15 @@ static void wait_eb_writebacks(struct btrfs_block_group *block_group)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = block_group->fs_info;
|
||||
const u64 end = block_group->start + block_group->length;
|
||||
struct radix_tree_iter iter;
|
||||
struct extent_buffer *eb;
|
||||
void __rcu **slot;
|
||||
unsigned long index, start = (block_group->start >> fs_info->sectorsize_bits);
|
||||
|
||||
rcu_read_lock();
|
||||
radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter,
|
||||
block_group->start >> fs_info->sectorsize_bits) {
|
||||
eb = radix_tree_deref_slot(slot);
|
||||
if (!eb)
|
||||
continue;
|
||||
if (radix_tree_deref_retry(eb)) {
|
||||
slot = radix_tree_iter_retry(&iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
xa_for_each_start(&fs_info->buffer_tree, index, eb, start) {
|
||||
if (eb->start < block_group->start)
|
||||
continue;
|
||||
if (eb->start >= end)
|
||||
break;
|
||||
|
||||
slot = radix_tree_iter_resume(slot, &iter);
|
||||
rcu_read_unlock();
|
||||
wait_on_extent_buffer_writeback(eb);
|
||||
rcu_read_lock();
|
||||
|
||||
+5
-5
@@ -24,7 +24,7 @@
|
||||
#include "super.h"
|
||||
|
||||
#define ZSTD_BTRFS_MAX_WINDOWLOG 17
|
||||
#define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
|
||||
#define ZSTD_BTRFS_MAX_INPUT (1U << ZSTD_BTRFS_MAX_WINDOWLOG)
|
||||
#define ZSTD_BTRFS_DEFAULT_LEVEL 3
|
||||
#define ZSTD_BTRFS_MIN_LEVEL -15
|
||||
#define ZSTD_BTRFS_MAX_LEVEL 15
|
||||
@@ -426,8 +426,8 @@ int zstd_compress_folios(struct list_head *ws, struct address_space *mapping,
|
||||
ret = btrfs_compress_filemap_get_folio(mapping, start, &in_folio);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
cur_len = btrfs_calc_input_length(orig_end, start);
|
||||
workspace->in_buf.src = kmap_local_folio(in_folio, offset_in_page(start));
|
||||
cur_len = btrfs_calc_input_length(in_folio, orig_end, start);
|
||||
workspace->in_buf.src = kmap_local_folio(in_folio, offset_in_folio(in_folio, start));
|
||||
workspace->in_buf.pos = 0;
|
||||
workspace->in_buf.size = cur_len;
|
||||
|
||||
@@ -511,9 +511,9 @@ int zstd_compress_folios(struct list_head *ws, struct address_space *mapping,
|
||||
ret = btrfs_compress_filemap_get_folio(mapping, start, &in_folio);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
cur_len = btrfs_calc_input_length(orig_end, start);
|
||||
cur_len = btrfs_calc_input_length(in_folio, orig_end, start);
|
||||
workspace->in_buf.src = kmap_local_folio(in_folio,
|
||||
offset_in_page(start));
|
||||
offset_in_folio(in_folio, start));
|
||||
workspace->in_buf.pos = 0;
|
||||
workspace->in_buf.size = cur_len;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,6 @@ FLUSH_STATES
|
||||
|
||||
#define EXTENT_FLAGS \
|
||||
{ EXTENT_DIRTY, "DIRTY"}, \
|
||||
{ EXTENT_UPTODATE, "UPTODATE"}, \
|
||||
{ EXTENT_LOCKED, "LOCKED"}, \
|
||||
{ EXTENT_NEW, "NEW"}, \
|
||||
{ EXTENT_DELALLOC, "DELALLOC"}, \
|
||||
@@ -224,8 +223,7 @@ DECLARE_EVENT_CLASS(btrfs__inode,
|
||||
__entry->generation = BTRFS_I(inode)->generation;
|
||||
__entry->last_trans = BTRFS_I(inode)->last_trans;
|
||||
__entry->logged_trans = BTRFS_I(inode)->logged_trans;
|
||||
__entry->root_objectid =
|
||||
BTRFS_I(inode)->root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(BTRFS_I(inode)->root);
|
||||
),
|
||||
|
||||
TP_printk_btrfs("root=%llu(%s) gen=%llu ino=%llu blocks=%llu "
|
||||
@@ -297,7 +295,7 @@ TRACE_EVENT_CONDITION(btrfs_get_extent,
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(root->fs_info,
|
||||
__entry->root_objectid = root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(root);
|
||||
__entry->ino = btrfs_ino(inode);
|
||||
__entry->start = map->start;
|
||||
__entry->len = map->len;
|
||||
@@ -376,7 +374,7 @@ DECLARE_EVENT_CLASS(btrfs__file_extent_item_regular,
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(bi->root->fs_info,
|
||||
__entry->root_obj = bi->root->root_key.objectid;
|
||||
__entry->root_obj = btrfs_root_id(bi->root);
|
||||
__entry->ino = btrfs_ino(bi);
|
||||
__entry->isize = bi->vfs_inode.i_size;
|
||||
__entry->disk_isize = bi->disk_i_size;
|
||||
@@ -427,7 +425,7 @@ DECLARE_EVENT_CLASS(
|
||||
|
||||
TP_fast_assign_btrfs(
|
||||
bi->root->fs_info,
|
||||
__entry->root_obj = bi->root->root_key.objectid;
|
||||
__entry->root_obj = btrfs_root_id(bi->root);
|
||||
__entry->ino = btrfs_ino(bi);
|
||||
__entry->isize = bi->vfs_inode.i_size;
|
||||
__entry->disk_isize = bi->disk_i_size;
|
||||
@@ -527,7 +525,7 @@ DECLARE_EVENT_CLASS(btrfs__ordered_extent,
|
||||
__entry->flags = ordered->flags;
|
||||
__entry->compress_type = ordered->compress_type;
|
||||
__entry->refs = refcount_read(&ordered->refs);
|
||||
__entry->root_objectid = inode->root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(inode->root);
|
||||
__entry->truncated_len = ordered->truncated_len;
|
||||
),
|
||||
|
||||
@@ -664,7 +662,7 @@ TRACE_EVENT(btrfs_finish_ordered_extent,
|
||||
__entry->start = start;
|
||||
__entry->len = len;
|
||||
__entry->uptodate = uptodate;
|
||||
__entry->root_objectid = inode->root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(inode->root);
|
||||
),
|
||||
|
||||
TP_printk_btrfs("root=%llu(%s) ino=%llu start=%llu len=%llu uptodate=%d",
|
||||
@@ -705,8 +703,7 @@ DECLARE_EVENT_CLASS(btrfs__writepage,
|
||||
__entry->for_reclaim = wbc->for_reclaim;
|
||||
__entry->range_cyclic = wbc->range_cyclic;
|
||||
__entry->writeback_index = inode->i_mapping->writeback_index;
|
||||
__entry->root_objectid =
|
||||
BTRFS_I(inode)->root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(BTRFS_I(inode)->root);
|
||||
),
|
||||
|
||||
TP_printk_btrfs("root=%llu(%s) ino=%llu page_index=%lu "
|
||||
@@ -750,7 +747,7 @@ TRACE_EVENT(btrfs_writepage_end_io_hook,
|
||||
__entry->start = start;
|
||||
__entry->end = end;
|
||||
__entry->uptodate = uptodate;
|
||||
__entry->root_objectid = inode->root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(inode->root);
|
||||
),
|
||||
|
||||
TP_printk_btrfs("root=%llu(%s) ino=%llu start=%llu end=%llu uptodate=%d",
|
||||
@@ -780,8 +777,7 @@ TRACE_EVENT(btrfs_sync_file,
|
||||
__entry->ino = btrfs_ino(BTRFS_I(inode));
|
||||
__entry->parent = btrfs_ino(BTRFS_I(d_inode(dentry->d_parent)));
|
||||
__entry->datasync = datasync;
|
||||
__entry->root_objectid =
|
||||
BTRFS_I(inode)->root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(BTRFS_I(inode)->root);
|
||||
),
|
||||
|
||||
TP_printk_btrfs("root=%llu(%s) ino=%llu parent=%llu datasync=%d",
|
||||
@@ -1052,7 +1048,7 @@ DECLARE_EVENT_CLASS(btrfs__chunk,
|
||||
__entry->sub_stripes = map->sub_stripes;
|
||||
__entry->offset = offset;
|
||||
__entry->size = size;
|
||||
__entry->root_objectid = fs_info->chunk_root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(fs_info->chunk_root);
|
||||
),
|
||||
|
||||
TP_printk_btrfs("root=%llu(%s) offset=%llu size=%llu "
|
||||
@@ -1097,7 +1093,7 @@ TRACE_EVENT(btrfs_cow_block,
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(root->fs_info,
|
||||
__entry->root_objectid = root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(root);
|
||||
__entry->buf_start = buf->start;
|
||||
__entry->refs = atomic_read(&buf->refs);
|
||||
__entry->cow_start = cow->start;
|
||||
@@ -1240,7 +1236,7 @@ DEFINE_EVENT(btrfs__reserved_extent, btrfs_reserved_extent_free,
|
||||
TP_ARGS(fs_info, start, len)
|
||||
);
|
||||
|
||||
TRACE_EVENT(find_free_extent,
|
||||
TRACE_EVENT(btrfs_find_free_extent,
|
||||
|
||||
TP_PROTO(const struct btrfs_root *root,
|
||||
const struct find_free_extent_ctl *ffe_ctl),
|
||||
@@ -1255,7 +1251,7 @@ TRACE_EVENT(find_free_extent,
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(root->fs_info,
|
||||
__entry->root_objectid = root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(root);
|
||||
__entry->num_bytes = ffe_ctl->num_bytes;
|
||||
__entry->empty_size = ffe_ctl->empty_size;
|
||||
__entry->flags = ffe_ctl->flags;
|
||||
@@ -1268,7 +1264,7 @@ TRACE_EVENT(find_free_extent,
|
||||
BTRFS_GROUP_FLAGS))
|
||||
);
|
||||
|
||||
TRACE_EVENT(find_free_extent_search_loop,
|
||||
TRACE_EVENT(btrfs_find_free_extent_search_loop,
|
||||
|
||||
TP_PROTO(const struct btrfs_root *root,
|
||||
const struct find_free_extent_ctl *ffe_ctl),
|
||||
@@ -1284,7 +1280,7 @@ TRACE_EVENT(find_free_extent_search_loop,
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(root->fs_info,
|
||||
__entry->root_objectid = root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(root);
|
||||
__entry->num_bytes = ffe_ctl->num_bytes;
|
||||
__entry->empty_size = ffe_ctl->empty_size;
|
||||
__entry->flags = ffe_ctl->flags;
|
||||
@@ -1298,7 +1294,7 @@ TRACE_EVENT(find_free_extent_search_loop,
|
||||
__entry->loop)
|
||||
);
|
||||
|
||||
TRACE_EVENT(find_free_extent_have_block_group,
|
||||
TRACE_EVENT(btrfs_find_free_extent_have_block_group,
|
||||
|
||||
TP_PROTO(const struct btrfs_root *root,
|
||||
const struct find_free_extent_ctl *ffe_ctl,
|
||||
@@ -1318,7 +1314,7 @@ TRACE_EVENT(find_free_extent_have_block_group,
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(root->fs_info,
|
||||
__entry->root_objectid = root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(root);
|
||||
__entry->num_bytes = ffe_ctl->num_bytes;
|
||||
__entry->empty_size = ffe_ctl->empty_size;
|
||||
__entry->flags = ffe_ctl->flags;
|
||||
@@ -1480,7 +1476,7 @@ TRACE_EVENT(btrfs_setup_cluster,
|
||||
);
|
||||
|
||||
struct extent_state;
|
||||
TRACE_EVENT(alloc_extent_state,
|
||||
TRACE_EVENT(btrfs_alloc_extent_state,
|
||||
|
||||
TP_PROTO(const struct extent_state *state,
|
||||
gfp_t mask, unsigned long IP),
|
||||
@@ -1503,7 +1499,7 @@ TRACE_EVENT(alloc_extent_state,
|
||||
show_gfp_flags(__entry->mask), __entry->ip)
|
||||
);
|
||||
|
||||
TRACE_EVENT(free_extent_state,
|
||||
TRACE_EVENT(btrfs_free_extent_state,
|
||||
|
||||
TP_PROTO(const struct extent_state *state, unsigned long IP),
|
||||
|
||||
@@ -1672,8 +1668,7 @@ DECLARE_EVENT_CLASS(btrfs__qgroup_rsv_data,
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(btrfs_sb(inode->i_sb),
|
||||
__entry->rootid =
|
||||
BTRFS_I(inode)->root->root_key.objectid;
|
||||
__entry->rootid = btrfs_root_id(BTRFS_I(inode)->root);
|
||||
__entry->ino = btrfs_ino(BTRFS_I(inode));
|
||||
__entry->start = start;
|
||||
__entry->len = len;
|
||||
@@ -1744,7 +1739,7 @@ DEFINE_EVENT(btrfs_qgroup_extent, btrfs_qgroup_trace_extent,
|
||||
TP_ARGS(fs_info, rec, bytenr)
|
||||
);
|
||||
|
||||
TRACE_EVENT(qgroup_num_dirty_extents,
|
||||
TRACE_EVENT(btrfs_qgroup_num_dirty_extents,
|
||||
|
||||
TP_PROTO(const struct btrfs_fs_info *fs_info, u64 transid,
|
||||
u64 num_dirty_extents),
|
||||
@@ -1798,7 +1793,7 @@ TRACE_EVENT(btrfs_qgroup_account_extent,
|
||||
__entry->nr_new_roots)
|
||||
);
|
||||
|
||||
TRACE_EVENT(qgroup_update_counters,
|
||||
TRACE_EVENT(btrfs_qgroup_update_counters,
|
||||
|
||||
TP_PROTO(const struct btrfs_fs_info *fs_info,
|
||||
const struct btrfs_qgroup *qgroup,
|
||||
@@ -1827,7 +1822,7 @@ TRACE_EVENT(qgroup_update_counters,
|
||||
__entry->cur_old_count, __entry->cur_new_count)
|
||||
);
|
||||
|
||||
TRACE_EVENT(qgroup_update_reserve,
|
||||
TRACE_EVENT(btrfs_qgroup_update_reserve,
|
||||
|
||||
TP_PROTO(const struct btrfs_fs_info *fs_info, const struct btrfs_qgroup *qgroup,
|
||||
s64 diff, int type),
|
||||
@@ -1853,7 +1848,7 @@ TRACE_EVENT(qgroup_update_reserve,
|
||||
__entry->cur_reserved, __entry->diff)
|
||||
);
|
||||
|
||||
TRACE_EVENT(qgroup_meta_reserve,
|
||||
TRACE_EVENT(btrfs_qgroup_meta_reserve,
|
||||
|
||||
TP_PROTO(const struct btrfs_root *root, s64 diff, int type),
|
||||
|
||||
@@ -1866,7 +1861,7 @@ TRACE_EVENT(qgroup_meta_reserve,
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(root->fs_info,
|
||||
__entry->refroot = root->root_key.objectid;
|
||||
__entry->refroot = btrfs_root_id(root);
|
||||
__entry->diff = diff;
|
||||
__entry->type = type;
|
||||
),
|
||||
@@ -1876,7 +1871,7 @@ TRACE_EVENT(qgroup_meta_reserve,
|
||||
__print_symbolic(__entry->type, QGROUP_RSV_TYPES), __entry->diff)
|
||||
);
|
||||
|
||||
TRACE_EVENT(qgroup_meta_convert,
|
||||
TRACE_EVENT(btrfs_qgroup_meta_convert,
|
||||
|
||||
TP_PROTO(const struct btrfs_root *root, s64 diff),
|
||||
|
||||
@@ -1888,7 +1883,7 @@ TRACE_EVENT(qgroup_meta_convert,
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(root->fs_info,
|
||||
__entry->refroot = root->root_key.objectid;
|
||||
__entry->refroot = btrfs_root_id(root);
|
||||
__entry->diff = diff;
|
||||
),
|
||||
|
||||
@@ -1899,7 +1894,7 @@ TRACE_EVENT(qgroup_meta_convert,
|
||||
__entry->diff)
|
||||
);
|
||||
|
||||
TRACE_EVENT(qgroup_meta_free_all_pertrans,
|
||||
TRACE_EVENT(btrfs_qgroup_meta_free_all_pertrans,
|
||||
|
||||
TP_PROTO(struct btrfs_root *root),
|
||||
|
||||
@@ -1912,7 +1907,7 @@ TRACE_EVENT(qgroup_meta_free_all_pertrans,
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(root->fs_info,
|
||||
__entry->refroot = root->root_key.objectid;
|
||||
__entry->refroot = btrfs_root_id(root);
|
||||
spin_lock(&root->qgroup_meta_rsv_lock);
|
||||
__entry->diff = -(s64)root->qgroup_meta_rsv_pertrans;
|
||||
spin_unlock(&root->qgroup_meta_rsv_lock);
|
||||
@@ -1994,7 +1989,7 @@ TRACE_EVENT(btrfs_inode_mod_outstanding_extents,
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(root->fs_info,
|
||||
__entry->root_objectid = root->root_key.objectid;
|
||||
__entry->root_objectid = btrfs_root_id(root);
|
||||
__entry->ino = ino;
|
||||
__entry->mod = mod;
|
||||
__entry->outstanding = outstanding;
|
||||
@@ -2074,12 +2069,12 @@ TRACE_EVENT(btrfs_set_extent_bit,
|
||||
__field( unsigned, set_bits)
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(extent_io_tree_to_fs_info(tree),
|
||||
const struct btrfs_inode *inode = extent_io_tree_to_inode_const(tree);
|
||||
TP_fast_assign_btrfs(btrfs_extent_io_tree_to_fs_info(tree),
|
||||
const struct btrfs_inode *inode = btrfs_extent_io_tree_to_inode(tree);
|
||||
|
||||
__entry->owner = tree->owner;
|
||||
__entry->ino = inode ? btrfs_ino(inode) : 0;
|
||||
__entry->rootid = inode ? inode->root->root_key.objectid : 0;
|
||||
__entry->rootid = inode ? btrfs_root_id(inode->root) : 0;
|
||||
__entry->start = start;
|
||||
__entry->len = len;
|
||||
__entry->set_bits = set_bits;
|
||||
@@ -2107,12 +2102,12 @@ TRACE_EVENT(btrfs_clear_extent_bit,
|
||||
__field( unsigned, clear_bits)
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(extent_io_tree_to_fs_info(tree),
|
||||
const struct btrfs_inode *inode = extent_io_tree_to_inode_const(tree);
|
||||
TP_fast_assign_btrfs(btrfs_extent_io_tree_to_fs_info(tree),
|
||||
const struct btrfs_inode *inode = btrfs_extent_io_tree_to_inode(tree);
|
||||
|
||||
__entry->owner = tree->owner;
|
||||
__entry->ino = inode ? btrfs_ino(inode) : 0;
|
||||
__entry->rootid = inode ? inode->root->root_key.objectid : 0;
|
||||
__entry->rootid = inode ? btrfs_root_id(inode->root) : 0;
|
||||
__entry->start = start;
|
||||
__entry->len = len;
|
||||
__entry->clear_bits = clear_bits;
|
||||
@@ -2141,12 +2136,12 @@ TRACE_EVENT(btrfs_convert_extent_bit,
|
||||
__field( unsigned, clear_bits)
|
||||
),
|
||||
|
||||
TP_fast_assign_btrfs(extent_io_tree_to_fs_info(tree),
|
||||
const struct btrfs_inode *inode = extent_io_tree_to_inode_const(tree);
|
||||
TP_fast_assign_btrfs(btrfs_extent_io_tree_to_fs_info(tree),
|
||||
const struct btrfs_inode *inode = btrfs_extent_io_tree_to_inode(tree);
|
||||
|
||||
__entry->owner = tree->owner;
|
||||
__entry->ino = inode ? btrfs_ino(inode) : 0;
|
||||
__entry->rootid = inode ? inode->root->root_key.objectid : 0;
|
||||
__entry->rootid = inode ? btrfs_root_id(inode->root) : 0;
|
||||
__entry->start = start;
|
||||
__entry->len = len;
|
||||
__entry->set_bits = set_bits;
|
||||
@@ -2341,11 +2336,7 @@ DEFINE_EVENT(btrfs_locking_events, name, \
|
||||
|
||||
DEFINE_BTRFS_LOCK_EVENT(btrfs_tree_unlock);
|
||||
DEFINE_BTRFS_LOCK_EVENT(btrfs_tree_read_unlock);
|
||||
DEFINE_BTRFS_LOCK_EVENT(btrfs_tree_read_unlock_blocking);
|
||||
DEFINE_BTRFS_LOCK_EVENT(btrfs_set_lock_blocking_read);
|
||||
DEFINE_BTRFS_LOCK_EVENT(btrfs_set_lock_blocking_write);
|
||||
DEFINE_BTRFS_LOCK_EVENT(btrfs_try_tree_read_lock);
|
||||
DEFINE_BTRFS_LOCK_EVENT(btrfs_tree_read_lock_atomic);
|
||||
|
||||
DECLARE_EVENT_CLASS(btrfs__space_info_update,
|
||||
|
||||
@@ -2621,7 +2612,7 @@ TRACE_EVENT(btrfs_extent_map_shrinker_remove_em,
|
||||
|
||||
TP_fast_assign_btrfs(inode->root->fs_info,
|
||||
__entry->ino = btrfs_ino(inode);
|
||||
__entry->root_id = inode->root->root_key.objectid;
|
||||
__entry->root_id = btrfs_root_id(inode->root);
|
||||
__entry->start = em->start;
|
||||
__entry->len = em->len;
|
||||
__entry->flags = em->flags;
|
||||
|
||||
Reference in New Issue
Block a user