mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'for-7.2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs updates from David Sterba:
"The most noticeable change is to enable large folios by default, it's
been in testing for a few releases. Related to that is huge folio
support (still under experimental config). Otherwise a few ioctl
updates, performance improvements and usual fixes and core changes.
User visible changes:
- enable large folios by default, added in 6.17 (under experimental
build), no feature limitations, a big change internally
- new ioctl to return raw checksums to userspace (a bit tricky given
compression and tail extents), can be used for mkfs and
deduplication optimizations
- provide stable UUID for e.g. overlayfs and temp_fsid, also
reflected in statvfs() field f_fsid, internal dev_t is hashed in to
allow cloning
- add 32bit compat version of GET_SUBVOL_INFO ioctl
- in experimental build, support huge folios (up to 2M)
Performance related improvements/changes:
- limit bio size to the estimated optimum derived from the queue,
this prevents build up of too much data for writeback, which could
cause latency spikes (reported improvement 15% on sequential
writes)
- don't force direct IO to be serialized, forgotten change during
mount API port, brings back +60% of throughput
- lockless calculation of number of shrinkable extent maps, improve
performance with many memcg allocated objects
Notable fixes:
- in zoned mode, fix a deadlock due to zone reclaim and relocation
when space needs to be flushed
- don't trim device which is internally not tracked as writeable
(e.g. when missing device is being rescanned)
- fix deadlock when cloning inline extent and mounted with
flushoncommit
- fix false IO failures after direct IO falls back to buffered write
in some cases
Core:
- remove COW fixup mechanism completely; detect and fix changes to
pages outside of filesystem tracking, guaranteed since 5.8, grace
period is over
- remove 2K block size support, experimental to test subpage code on
x86_64 but now it would block folio changes
- tree-checker improvements of:
- free-space cache and tree items
- root reference and backref items
- extent state exceptions in reloc tree
- subpage mode updates:
- code optimizations, simplify tracking bitmaps
- re-enable readahead of compressed extent
- extend bitmap size to cover huge folios
- add tracepoints related to sync, tree-log and transactions
- device stats item tracking unification, remove item if there are no
stats recorded, also don't leave stale stats on replaced device
- allow extent buffer pages to be allocated as movable, to help page
migration
- added checks for proper extent buffer release
- btrfs.ko code size reduction due to transaction abort call
simplifications
- several struct size reductions
- more auto free conversions
- more verbose assertions"
* tag 'for-7.2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (130 commits)
btrfs: fix use-after-free after relocation failure with concurrent COW
btrfs: move WARN_ON on unexpected error in __add_tree_block()
btrfs: move locking into btrfs_get_reloc_bg_bytenr()
btrfs: lzo: reject compressed segment that overflows the compressed input
btrfs: retry faulting in the pages after a zero sized short direct write
btrfs: fix incorrect buffered IO fallback for append direct writes
btrfs: fix false IO failure after falling back to buffered write
btrfs: use verbose assertions in backref.c
btrfs: print a message when a missing device re-appears
btrfs: do not trim a device which is not writeable
btrfs: return real error after lookup failure in btrfs_ioctl_default_subvol()
btrfs: use mapping shared locking for reading super block
btrfs: use lockless read in nr_cached_objects shrinker callback
btrfs: switch local indicator variables to bools
btrfs: send: pass bool for pending_move and refs_processed parameters
btrfs: use shifts for sectorsize and nodesize
btrfs: fix deadlock cloning inline extent when using flushoncommit
btrfs: allocate eb-attached btree pages as movable
btrfs: add 32-bit compat ioctl for BTRFS_IOC_GET_SUBVOL_INFO
btrfs: derive f_fsid from on-disk fsid and dev_t
...
This commit is contained in:
+3
-5
@@ -93,10 +93,6 @@ config BTRFS_EXPERIMENTAL
|
||||
|
||||
Current list:
|
||||
|
||||
- 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,
|
||||
@@ -110,7 +106,9 @@ config BTRFS_EXPERIMENTAL
|
||||
|
||||
- extent tree v2 - complex rework of extent tracking
|
||||
|
||||
- large folio and block size (> page size) support
|
||||
- block size > page size support
|
||||
|
||||
- huge folios for data - folios can be as large as 2MiB now
|
||||
|
||||
- asynchronous checksum generation for data writes
|
||||
|
||||
|
||||
+35
-38
@@ -1256,7 +1256,7 @@ static bool lookup_backref_shared_cache(struct btrfs_backref_share_check_ctx *ct
|
||||
* realizing. We cache results only for extent buffers that lead from
|
||||
* the root node down to the leaf with the file extent item.
|
||||
*/
|
||||
ASSERT(level >= 0);
|
||||
ASSERT(level >= 0, "level=%d", level);
|
||||
|
||||
entry = &ctx->path_cache_entries[level];
|
||||
|
||||
@@ -1327,7 +1327,7 @@ static void store_backref_shared_cache(struct btrfs_backref_share_check_ctx *ctx
|
||||
* realizing. We cache results only for extent buffers that lead from
|
||||
* the root node down to the leaf with the file extent item.
|
||||
*/
|
||||
ASSERT(level >= 0);
|
||||
ASSERT(level >= 0, "level=%d", level);
|
||||
|
||||
if (is_shared)
|
||||
gen = btrfs_get_last_root_drop_gen(fs_info);
|
||||
@@ -2367,7 +2367,7 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
|
||||
info = (struct btrfs_tree_block_info *)(ei + 1);
|
||||
*out_level = btrfs_tree_block_level(eb, info);
|
||||
} else {
|
||||
ASSERT(key->type == BTRFS_METADATA_ITEM_KEY);
|
||||
ASSERT(key->type == BTRFS_METADATA_ITEM_KEY, "key->type=%hhu", key->type);
|
||||
*out_level = (u8)key->offset;
|
||||
}
|
||||
|
||||
@@ -2814,26 +2814,17 @@ struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
|
||||
return ifp;
|
||||
}
|
||||
|
||||
struct btrfs_backref_iter *btrfs_backref_iter_alloc(struct btrfs_fs_info *fs_info)
|
||||
int btrfs_backref_iter_init(struct btrfs_backref_iter *iter)
|
||||
{
|
||||
struct btrfs_backref_iter *ret;
|
||||
|
||||
ret = kzalloc_obj(*ret, GFP_NOFS);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
ret->path = btrfs_alloc_path();
|
||||
if (!ret->path) {
|
||||
kfree(ret);
|
||||
return NULL;
|
||||
}
|
||||
iter->path = btrfs_alloc_path();
|
||||
if (!iter->path)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Current backref iterator only supports iteration in commit root */
|
||||
ret->path->search_commit_root = true;
|
||||
ret->path->skip_locking = true;
|
||||
ret->fs_info = fs_info;
|
||||
iter->path->search_commit_root = true;
|
||||
iter->path->skip_locking = true;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btrfs_backref_iter_release(struct btrfs_backref_iter *iter)
|
||||
@@ -2846,9 +2837,8 @@ static void btrfs_backref_iter_release(struct btrfs_backref_iter *iter)
|
||||
memset(&iter->cur_key, 0, sizeof(iter->cur_key));
|
||||
}
|
||||
|
||||
int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
|
||||
int btrfs_backref_iter_start(struct btrfs_fs_info *fs_info, struct btrfs_backref_iter *iter, u64 bytenr)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = iter->fs_info;
|
||||
struct btrfs_root *extent_root = btrfs_extent_root(fs_info, bytenr);
|
||||
struct btrfs_path *path = iter->path;
|
||||
struct btrfs_extent_item *ei;
|
||||
@@ -2963,7 +2953,7 @@ static bool btrfs_backref_iter_is_inline_ref(struct btrfs_backref_iter *iter)
|
||||
* Return >0 if there is no extra backref for this bytenr.
|
||||
* Return <0 if there is something wrong happened.
|
||||
*/
|
||||
int btrfs_backref_iter_next(struct btrfs_backref_iter *iter)
|
||||
int btrfs_backref_iter_next(struct btrfs_fs_info *fs_info, struct btrfs_backref_iter *iter)
|
||||
{
|
||||
struct extent_buffer *eb = iter->path->nodes[0];
|
||||
struct btrfs_root *extent_root;
|
||||
@@ -2974,7 +2964,9 @@ int btrfs_backref_iter_next(struct btrfs_backref_iter *iter)
|
||||
|
||||
if (btrfs_backref_iter_is_inline_ref(iter)) {
|
||||
/* We're still inside the inline refs */
|
||||
ASSERT(iter->cur_ptr < iter->end_ptr);
|
||||
ASSERT(iter->cur_ptr < iter->end_ptr,
|
||||
"iter->cur_ptr=%u iter->end_ptr=%u",
|
||||
iter->cur_ptr, iter->end_ptr);
|
||||
|
||||
if (btrfs_backref_has_tree_block_info(iter)) {
|
||||
/* First tree block info */
|
||||
@@ -2997,10 +2989,9 @@ int btrfs_backref_iter_next(struct btrfs_backref_iter *iter)
|
||||
}
|
||||
|
||||
/* We're at keyed items, there is no inline item, go to the next one */
|
||||
extent_root = btrfs_extent_root(iter->fs_info, iter->bytenr);
|
||||
extent_root = btrfs_extent_root(fs_info, iter->bytenr);
|
||||
if (unlikely(!extent_root)) {
|
||||
btrfs_err(iter->fs_info,
|
||||
"missing extent root for extent at bytenr %llu",
|
||||
btrfs_err(fs_info, "missing extent root for extent at bytenr %llu",
|
||||
iter->bytenr);
|
||||
return -EUCLEAN;
|
||||
}
|
||||
@@ -3041,7 +3032,7 @@ struct btrfs_backref_node *btrfs_backref_alloc_node(
|
||||
{
|
||||
struct btrfs_backref_node *node;
|
||||
|
||||
ASSERT(level >= 0 && level < BTRFS_MAX_LEVEL);
|
||||
ASSERT(level >= 0 && level < BTRFS_MAX_LEVEL, "level=%d", level);
|
||||
node = kzalloc_obj(*node, GFP_NOFS);
|
||||
if (!node)
|
||||
return node;
|
||||
@@ -3063,7 +3054,7 @@ void btrfs_backref_free_node(struct btrfs_backref_cache *cache,
|
||||
if (node) {
|
||||
ASSERT(list_empty(&node->list));
|
||||
ASSERT(list_empty(&node->lower));
|
||||
ASSERT(node->eb == NULL);
|
||||
ASSERT(node->eb == NULL, "node->eb->start=%llu", node->eb->start);
|
||||
cache->nr_nodes--;
|
||||
btrfs_put_root(node->root);
|
||||
kfree(node);
|
||||
@@ -3166,15 +3157,18 @@ void btrfs_backref_release_cache(struct btrfs_backref_cache *cache)
|
||||
|
||||
ASSERT(list_empty(&cache->pending_edge));
|
||||
ASSERT(list_empty(&cache->useless_node));
|
||||
ASSERT(!cache->nr_nodes);
|
||||
ASSERT(!cache->nr_edges);
|
||||
ASSERT(!cache->nr_nodes, "cache->nr_nodes=%d", cache->nr_nodes);
|
||||
ASSERT(!cache->nr_edges, "cache->nr_edges=%d", cache->nr_edges);
|
||||
}
|
||||
|
||||
static void btrfs_backref_link_edge(struct btrfs_backref_edge *edge,
|
||||
struct btrfs_backref_node *lower,
|
||||
struct btrfs_backref_node *upper)
|
||||
{
|
||||
ASSERT(upper && lower && upper->level == lower->level + 1);
|
||||
ASSERT(upper != NULL);
|
||||
ASSERT(lower != NULL);
|
||||
ASSERT(upper->level == lower->level + 1, "upper->level=%d lower->level=%d",
|
||||
upper->level, lower->level);
|
||||
edge->node[LOWER] = lower;
|
||||
edge->node[UPPER] = upper;
|
||||
list_add_tail(&edge->list[LOWER], &lower->upper);
|
||||
@@ -3199,7 +3193,7 @@ static int handle_direct_tree_backref(struct btrfs_backref_cache *cache,
|
||||
struct btrfs_backref_node *upper;
|
||||
struct rb_node *rb_node;
|
||||
|
||||
ASSERT(ref_key->type == BTRFS_SHARED_BLOCK_REF_KEY);
|
||||
ASSERT(ref_key->type == BTRFS_SHARED_BLOCK_REF_KEY, "ref_key->type=%hhu", ref_key->type);
|
||||
|
||||
/* Only reloc root uses backref pointing to itself */
|
||||
if (ref_key->objectid == ref_key->offset) {
|
||||
@@ -3294,7 +3288,9 @@ static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans,
|
||||
|
||||
if (btrfs_root_level(&root->root_item) == cur->level) {
|
||||
/* Tree root */
|
||||
ASSERT(btrfs_root_bytenr(&root->root_item) == cur->bytenr);
|
||||
ASSERT(btrfs_root_bytenr(&root->root_item) == cur->bytenr,
|
||||
"root_bytenr=%llu cur->bytenr=%llu",
|
||||
btrfs_root_bytenr(&root->root_item), cur->bytenr);
|
||||
/*
|
||||
* For reloc backref cache, we may ignore reloc root. But for
|
||||
* general purpose backref cache, we can't rely on
|
||||
@@ -3344,8 +3340,9 @@ static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans,
|
||||
/* Add all nodes and edges in the path */
|
||||
for (; level < BTRFS_MAX_LEVEL; level++) {
|
||||
if (!path->nodes[level]) {
|
||||
ASSERT(btrfs_root_bytenr(&root->root_item) ==
|
||||
lower->bytenr);
|
||||
ASSERT(btrfs_root_bytenr(&root->root_item) == lower->bytenr,
|
||||
"root_bytenr=%llu lower->bytenr=%llu",
|
||||
btrfs_root_bytenr(&root->root_item), lower->bytenr);
|
||||
/* Same as previous should_ignore_reloc_root() call */
|
||||
if (btrfs_should_ignore_reloc_root(root) &&
|
||||
cache->is_reloc) {
|
||||
@@ -3454,7 +3451,7 @@ int btrfs_backref_add_tree_node(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_backref_node *exist;
|
||||
int ret;
|
||||
|
||||
ret = btrfs_backref_iter_start(iter, cur->bytenr);
|
||||
ret = btrfs_backref_iter_start(trans->fs_info, iter, cur->bytenr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/*
|
||||
@@ -3462,7 +3459,7 @@ int btrfs_backref_add_tree_node(struct btrfs_trans_handle *trans,
|
||||
* stored in it, but fetch it from the tree block
|
||||
*/
|
||||
if (btrfs_backref_has_tree_block_info(iter)) {
|
||||
ret = btrfs_backref_iter_next(iter);
|
||||
ret = btrfs_backref_iter_next(trans->fs_info, iter);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
/* No extra backref? This means the tree block is corrupted */
|
||||
@@ -3492,7 +3489,7 @@ int btrfs_backref_add_tree_node(struct btrfs_trans_handle *trans,
|
||||
exist = NULL;
|
||||
}
|
||||
|
||||
for (; ret == 0; ret = btrfs_backref_iter_next(iter)) {
|
||||
for (; ret == 0; ret = btrfs_backref_iter_next(trans->fs_info, iter)) {
|
||||
struct extent_buffer *eb;
|
||||
struct btrfs_key key;
|
||||
int type;
|
||||
|
||||
+4
-5
@@ -278,15 +278,12 @@ struct prelim_ref {
|
||||
struct btrfs_backref_iter {
|
||||
u64 bytenr;
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_fs_info *fs_info;
|
||||
struct btrfs_key cur_key;
|
||||
u32 item_ptr;
|
||||
u32 cur_ptr;
|
||||
u32 end_ptr;
|
||||
};
|
||||
|
||||
struct btrfs_backref_iter *btrfs_backref_iter_alloc(struct btrfs_fs_info *fs_info);
|
||||
|
||||
/*
|
||||
* For metadata with EXTENT_ITEM key (non-skinny) case, the first inline data
|
||||
* is btrfs_tree_block_info, without a btrfs_extent_inline_ref header.
|
||||
@@ -302,9 +299,11 @@ static inline bool btrfs_backref_has_tree_block_info(
|
||||
return false;
|
||||
}
|
||||
|
||||
int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr);
|
||||
int btrfs_backref_iter_init(struct btrfs_backref_iter *iter);
|
||||
|
||||
int btrfs_backref_iter_next(struct btrfs_backref_iter *iter);
|
||||
int btrfs_backref_iter_start(struct btrfs_fs_info *fs_info, struct btrfs_backref_iter *iter, u64 bytenr);
|
||||
|
||||
int btrfs_backref_iter_next(struct btrfs_fs_info *fs_info, struct btrfs_backref_iter *iter);
|
||||
|
||||
/*
|
||||
* Backref cache related structures
|
||||
|
||||
+38
-10
@@ -22,6 +22,34 @@
|
||||
#include "accessors.h"
|
||||
#include "extent-tree.h"
|
||||
|
||||
static struct kmem_cache *block_group_cache;
|
||||
static struct kmem_cache *free_space_ctl_cache;
|
||||
|
||||
int __init btrfs_init_block_group(void)
|
||||
{
|
||||
block_group_cache = kmem_cache_create("btrfs_block_group",
|
||||
sizeof(struct btrfs_block_group),
|
||||
0, 0, NULL);
|
||||
if (!block_group_cache)
|
||||
return -ENOMEM;
|
||||
|
||||
free_space_ctl_cache = kmem_cache_create("btrfs_free_space_ctl",
|
||||
sizeof(struct btrfs_free_space_ctl),
|
||||
0, 0, NULL);
|
||||
if (!free_space_ctl_cache) {
|
||||
kmem_cache_destroy(block_group_cache);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __cold btrfs_exit_block_group(void)
|
||||
{
|
||||
kmem_cache_destroy(block_group_cache);
|
||||
kmem_cache_destroy(free_space_ctl_cache);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BTRFS_DEBUG
|
||||
int btrfs_should_fragment_free_space(const struct btrfs_block_group *block_group)
|
||||
{
|
||||
@@ -180,9 +208,9 @@ void btrfs_put_block_group(struct btrfs_block_group *cache)
|
||||
btrfs_discard_cancel_work(&cache->fs_info->discard_ctl,
|
||||
cache);
|
||||
|
||||
kfree(cache->free_space_ctl);
|
||||
kmem_cache_free(free_space_ctl_cache, cache->free_space_ctl);
|
||||
btrfs_free_chunk_map(cache->physical_map);
|
||||
kfree(cache);
|
||||
kmem_cache_free(block_group_cache, cache);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2371,13 +2399,13 @@ static struct btrfs_block_group *btrfs_create_block_group(
|
||||
{
|
||||
struct btrfs_block_group *cache;
|
||||
|
||||
cache = kzalloc_obj(*cache, GFP_NOFS);
|
||||
cache = kmem_cache_zalloc(block_group_cache, GFP_NOFS);
|
||||
if (!cache)
|
||||
return NULL;
|
||||
|
||||
cache->free_space_ctl = kzalloc_obj(*cache->free_space_ctl, GFP_NOFS);
|
||||
cache->free_space_ctl = kmem_cache_zalloc(free_space_ctl_cache, GFP_NOFS);
|
||||
if (!cache->free_space_ctl) {
|
||||
kfree(cache);
|
||||
kmem_cache_free(block_group_cache, cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2454,7 +2482,7 @@ static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info)
|
||||
static int read_one_block_group(struct btrfs_fs_info *info,
|
||||
struct btrfs_block_group_item_v2 *bgi,
|
||||
const struct btrfs_key *key,
|
||||
int need_clear)
|
||||
bool need_clear)
|
||||
{
|
||||
struct btrfs_block_group *cache;
|
||||
const bool mixed = btrfs_fs_incompat(info, MIXED_GROUPS);
|
||||
@@ -2635,7 +2663,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
|
||||
struct btrfs_block_group *cache;
|
||||
struct btrfs_space_info *space_info;
|
||||
struct btrfs_key key;
|
||||
int need_clear = 0;
|
||||
bool need_clear = false;
|
||||
u64 cache_gen;
|
||||
|
||||
/*
|
||||
@@ -2660,9 +2688,9 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
|
||||
cache_gen = btrfs_super_cache_generation(info->super_copy);
|
||||
if (btrfs_test_opt(info, SPACE_CACHE) &&
|
||||
btrfs_super_generation(info->super_copy) != cache_gen)
|
||||
need_clear = 1;
|
||||
need_clear = true;
|
||||
if (btrfs_test_opt(info, CLEAR_CACHE))
|
||||
need_clear = 1;
|
||||
need_clear = true;
|
||||
|
||||
while (1) {
|
||||
struct btrfs_block_group_item_v2 bgi;
|
||||
@@ -4089,7 +4117,7 @@ int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type)
|
||||
struct btrfs_space_info *space_info;
|
||||
|
||||
space_info = btrfs_find_space_info(trans->fs_info, type);
|
||||
if (!space_info) {
|
||||
if (unlikely(!space_info)) {
|
||||
DEBUG_WARN();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+21
-19
@@ -122,6 +122,7 @@ struct btrfs_block_group {
|
||||
struct btrfs_fs_info *fs_info;
|
||||
struct btrfs_inode *inode;
|
||||
spinlock_t lock;
|
||||
unsigned int ro;
|
||||
u64 start;
|
||||
u64 length;
|
||||
u64 pinned;
|
||||
@@ -134,7 +135,8 @@ struct btrfs_block_group {
|
||||
u64 global_root_id;
|
||||
u64 remap_bytes;
|
||||
u32 identity_remap_count;
|
||||
|
||||
/* The last commited identity_remap_count value of this block group. */
|
||||
u32 last_identity_remap_count;
|
||||
/*
|
||||
* The last committed used bytes of this block group, if the above @used
|
||||
* is still the same as @last_used, we don't need to update block
|
||||
@@ -143,8 +145,6 @@ struct btrfs_block_group {
|
||||
u64 last_used;
|
||||
/* The last committed remap_bytes value of this block group. */
|
||||
u64 last_remap_bytes;
|
||||
/* The last commited identity_remap_count value of this block group. */
|
||||
u32 last_identity_remap_count;
|
||||
/* The last committed flags value for this block group. */
|
||||
u64 last_flags;
|
||||
|
||||
@@ -171,12 +171,10 @@ struct btrfs_block_group {
|
||||
unsigned long full_stripe_len;
|
||||
unsigned long runtime_flags;
|
||||
|
||||
unsigned int ro;
|
||||
|
||||
int disk_cache_state;
|
||||
enum btrfs_disk_cache_state disk_cache_state;
|
||||
|
||||
/* Cache tracking stuff */
|
||||
int cached;
|
||||
enum btrfs_caching_type cached;
|
||||
struct btrfs_caching_control *caching_ctl;
|
||||
|
||||
struct btrfs_space_info *space_info;
|
||||
@@ -192,6 +190,16 @@ struct btrfs_block_group {
|
||||
|
||||
refcount_t refs;
|
||||
|
||||
/*
|
||||
* When non-zero it means the block group's logical address and its
|
||||
* device extents can not be reused for future block group allocations
|
||||
* until the counter goes down to 0. This is to prevent them from being
|
||||
* reused while some task is still using the block group after it was
|
||||
* deleted - we want to make sure they can only be reused for new block
|
||||
* groups after that task is done with the deleted block group.
|
||||
*/
|
||||
atomic_t frozen;
|
||||
|
||||
/*
|
||||
* List of struct btrfs_free_clusters for this block group.
|
||||
* Today it will only have one thing on it, but that may change
|
||||
@@ -211,22 +219,12 @@ struct btrfs_block_group {
|
||||
/* For read-only block groups */
|
||||
struct list_head ro_list;
|
||||
|
||||
/*
|
||||
* When non-zero it means the block group's logical address and its
|
||||
* device extents can not be reused for future block group allocations
|
||||
* until the counter goes down to 0. This is to prevent them from being
|
||||
* reused while some task is still using the block group after it was
|
||||
* deleted - we want to make sure they can only be reused for new block
|
||||
* groups after that task is done with the deleted block group.
|
||||
*/
|
||||
atomic_t frozen;
|
||||
|
||||
/* For discard operations */
|
||||
struct list_head discard_list;
|
||||
int discard_index;
|
||||
enum btrfs_discard_state discard_state;
|
||||
u64 discard_eligible_time;
|
||||
u64 discard_cursor;
|
||||
enum btrfs_discard_state discard_state;
|
||||
|
||||
/* For dirty block groups */
|
||||
struct list_head dirty_list;
|
||||
@@ -263,6 +261,8 @@ struct btrfs_block_group {
|
||||
/* Protected by @free_space_lock. */
|
||||
bool using_free_space_bitmaps_cached;
|
||||
|
||||
enum btrfs_block_group_size_class size_class:8;
|
||||
|
||||
/*
|
||||
* Number of extents in this block group used for swap files.
|
||||
* All accesses protected by the spinlock 'lock'.
|
||||
@@ -281,7 +281,6 @@ struct btrfs_block_group {
|
||||
struct list_head active_bg_list;
|
||||
struct work_struct zone_finish_work;
|
||||
struct extent_buffer *last_eb;
|
||||
enum btrfs_block_group_size_class size_class;
|
||||
u64 reclaim_mark;
|
||||
};
|
||||
|
||||
@@ -320,6 +319,9 @@ static inline u64 btrfs_block_group_available_space(const struct btrfs_block_gro
|
||||
int btrfs_should_fragment_free_space(const struct btrfs_block_group *block_group);
|
||||
#endif
|
||||
|
||||
int __init btrfs_init_block_group(void);
|
||||
void __cold btrfs_exit_block_group(void);
|
||||
|
||||
struct btrfs_block_group *btrfs_lookup_first_block_group(
|
||||
struct btrfs_fs_info *info, u64 bytenr);
|
||||
struct btrfs_block_group *btrfs_lookup_block_group(
|
||||
|
||||
+2
-35
@@ -128,15 +128,6 @@ struct btrfs_inode {
|
||||
/* which subvolume this inode belongs to */
|
||||
struct btrfs_root *root;
|
||||
|
||||
#if BITS_PER_LONG == 32
|
||||
/*
|
||||
* The objectid of the corresponding BTRFS_INODE_ITEM_KEY.
|
||||
* On 64 bits platforms we can get it from vfs_inode.i_ino, which is an
|
||||
* unsigned long and therefore 64 bits on such platforms.
|
||||
*/
|
||||
u64 objectid;
|
||||
#endif
|
||||
|
||||
/* Cached value of inode property 'compression'. */
|
||||
u8 prop_compress;
|
||||
|
||||
@@ -372,30 +363,11 @@ static inline unsigned long btrfs_inode_hash(u64 objectid,
|
||||
return (unsigned long)h;
|
||||
}
|
||||
|
||||
#if BITS_PER_LONG == 32
|
||||
|
||||
/*
|
||||
* On 32 bit systems the i_ino of struct inode is 32 bits (unsigned long), so
|
||||
* we use the inode's location objectid which is a u64 to avoid truncation.
|
||||
*/
|
||||
static inline u64 btrfs_ino(const struct btrfs_inode *inode)
|
||||
{
|
||||
u64 ino = inode->objectid;
|
||||
|
||||
if (test_bit(BTRFS_INODE_ROOT_STUB, &inode->runtime_flags))
|
||||
ino = inode->vfs_inode.i_ino;
|
||||
return ino;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline u64 btrfs_ino(const struct btrfs_inode *inode)
|
||||
{
|
||||
return inode->vfs_inode.i_ino;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline void btrfs_get_inode_key(const struct btrfs_inode *inode,
|
||||
struct btrfs_key *key)
|
||||
{
|
||||
@@ -406,9 +378,6 @@ static inline void btrfs_get_inode_key(const struct btrfs_inode *inode,
|
||||
|
||||
static inline void btrfs_set_inode_number(struct btrfs_inode *inode, u64 ino)
|
||||
{
|
||||
#if BITS_PER_LONG == 32
|
||||
inode->objectid = ino;
|
||||
#endif
|
||||
inode->vfs_inode.i_ino = ino;
|
||||
}
|
||||
|
||||
@@ -531,12 +500,9 @@ static inline void btrfs_set_inode_mapping_order(struct btrfs_inode *inode)
|
||||
/* Metadata inode should not reach here. */
|
||||
ASSERT(is_data_inode(inode));
|
||||
|
||||
/* We only allow BITS_PER_LONGS blocks for each bitmap. */
|
||||
#ifdef CONFIG_BTRFS_EXPERIMENTAL
|
||||
mapping_set_folio_order_range(inode->vfs_inode.i_mapping,
|
||||
inode->root->fs_info->block_min_order,
|
||||
inode->root->fs_info->block_max_order);
|
||||
#endif
|
||||
}
|
||||
|
||||
void btrfs_calculate_block_csum_folio(struct btrfs_fs_info *fs_info,
|
||||
@@ -569,6 +535,8 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
|
||||
int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
|
||||
unsigned int extra_bits,
|
||||
struct extent_state **cached_state);
|
||||
int btrfs_reset_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
|
||||
unsigned int extra_bits, struct extent_state **cached_state);
|
||||
|
||||
struct btrfs_new_inode_args {
|
||||
/* Input */
|
||||
@@ -630,7 +598,6 @@ int btrfs_prealloc_file_range_trans(struct inode *inode,
|
||||
loff_t actual_len, u64 *alloc_hint);
|
||||
int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct folio *locked_folio,
|
||||
u64 start, u64 end, struct writeback_control *wbc);
|
||||
int btrfs_writepage_cow_fixup(struct folio *folio);
|
||||
int btrfs_encoded_io_compression_from_extent(struct btrfs_fs_info *fs_info,
|
||||
int compress_type);
|
||||
int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
|
||||
|
||||
+23
-60
@@ -355,21 +355,16 @@ struct compressed_bio *btrfs_alloc_compressed_write(struct btrfs_inode *inode,
|
||||
}
|
||||
|
||||
/*
|
||||
* Add extra pages in the same compressed file extent so that we don't need to
|
||||
* Add extra folios in the same compressed file extent so that we don't need to
|
||||
* re-read the same extent again and again.
|
||||
*
|
||||
* NOTE: this won't work well for subpage, as for subpage read, we lock the
|
||||
* full page then submit bio for each compressed/regular extents.
|
||||
*
|
||||
* This means, if we have several sectors in the same page points to the same
|
||||
* on-disk compressed data, we will re-read the same extent many times and
|
||||
* this function can only help for the next page.
|
||||
* If in the same folio, we have several non-contiguous blocks which are pointing
|
||||
* to the same on-disk compressed data, we will re-read the same extent many
|
||||
* times, as this function can only help cross folio situations.
|
||||
*/
|
||||
static noinline int add_ra_bio_pages(struct inode *inode,
|
||||
u64 compressed_end,
|
||||
struct compressed_bio *cb,
|
||||
int *memstall, unsigned long *pflags,
|
||||
bool direct_reclaim)
|
||||
static noinline int add_ra_bio_folios(struct inode *inode, u64 compressed_end,
|
||||
struct compressed_bio *cb, int *memstall,
|
||||
unsigned long *pflags, bool direct_reclaim)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||
pgoff_t end_index;
|
||||
@@ -391,16 +386,6 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
||||
if (isize == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* For current subpage support, we only support 64K page size,
|
||||
* which means maximum compressed extent size (128K) is just 2x page
|
||||
* size.
|
||||
* This makes readahead less effective, so here disable readahead for
|
||||
* subpage for now, until full compressed write is supported.
|
||||
*/
|
||||
if (fs_info->sectorsize < PAGE_SIZE)
|
||||
return 0;
|
||||
|
||||
/* For bs > ps cases, we don't support readahead for compressed folios for now. */
|
||||
if (fs_info->block_min_order)
|
||||
return 0;
|
||||
@@ -416,7 +401,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
||||
}
|
||||
|
||||
while (cur < compressed_end) {
|
||||
pgoff_t page_end;
|
||||
u64 folio_end;
|
||||
pgoff_t pg_index = cur >> PAGE_SHIFT;
|
||||
gfp_t masked_constraint_gfp;
|
||||
u32 add_size;
|
||||
@@ -438,8 +423,8 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
||||
break;
|
||||
|
||||
/*
|
||||
* Jump to next page start as we already have page for
|
||||
* current offset.
|
||||
* Jump to the next folio as we already have a folio for
|
||||
* the current offset.
|
||||
*/
|
||||
cur += (folio_sz - offset);
|
||||
continue;
|
||||
@@ -457,8 +442,8 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
||||
break;
|
||||
|
||||
if (filemap_add_folio(mapping, folio, pg_index, cache_gfp)) {
|
||||
/* There is already a page, skip to page end */
|
||||
cur += folio_size(folio);
|
||||
/* There is already a folio, skip to the folio end. */
|
||||
cur += folio_size(folio) - offset_in_folio(folio, cur);
|
||||
folio_put(folio);
|
||||
continue;
|
||||
}
|
||||
@@ -475,14 +460,14 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
||||
break;
|
||||
}
|
||||
|
||||
page_end = (pg_index << PAGE_SHIFT) + folio_size(folio) - 1;
|
||||
btrfs_lock_extent(tree, cur, page_end, NULL);
|
||||
folio_end = folio_next_pos(folio) - 1;
|
||||
btrfs_lock_extent(tree, cur, folio_end, NULL);
|
||||
read_lock(&em_tree->lock);
|
||||
em = btrfs_lookup_extent_mapping(em_tree, cur, page_end + 1 - cur);
|
||||
em = btrfs_lookup_extent_mapping(em_tree, cur, folio_end + 1 - cur);
|
||||
read_unlock(&em_tree->lock);
|
||||
|
||||
/*
|
||||
* At this point, we have a locked page in the page cache for
|
||||
* At this point, we have a locked folio in the page cache for
|
||||
* these bytes in the file. But, we have to make sure they map
|
||||
* to this compressed extent on disk.
|
||||
*/
|
||||
@@ -491,14 +476,14 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
||||
(btrfs_extent_map_block_start(em) >> SECTOR_SHIFT) !=
|
||||
orig_bio->bi_iter.bi_sector) {
|
||||
btrfs_free_extent_map(em);
|
||||
btrfs_unlock_extent(tree, cur, page_end, NULL);
|
||||
btrfs_unlock_extent(tree, cur, folio_end, NULL);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
break;
|
||||
}
|
||||
add_size = min(btrfs_extent_map_end(em), page_end + 1) - cur;
|
||||
add_size = min(btrfs_extent_map_end(em), folio_end + 1) - cur;
|
||||
btrfs_free_extent_map(em);
|
||||
btrfs_unlock_extent(tree, cur, page_end, NULL);
|
||||
btrfs_unlock_extent(tree, cur, folio_end, NULL);
|
||||
|
||||
if (folio_contains(folio, end_index)) {
|
||||
size_t zero_offset = offset_in_folio(folio, isize);
|
||||
@@ -516,13 +501,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
||||
folio_put(folio);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* If it's subpage, we also need to increase its
|
||||
* subpage::readers number, as at endio we will decrease
|
||||
* subpage::readers and to unlock the page.
|
||||
*/
|
||||
if (fs_info->sectorsize < PAGE_SIZE)
|
||||
btrfs_folio_set_lock(fs_info, folio, cur, add_size);
|
||||
btrfs_folio_set_lock(fs_info, folio, cur, add_size);
|
||||
folio_put(folio);
|
||||
cur += add_size;
|
||||
}
|
||||
@@ -613,8 +592,8 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
|
||||
}
|
||||
ASSERT(cb->bbio.bio.bi_iter.bi_size == compressed_len);
|
||||
|
||||
add_ra_bio_pages(&inode->vfs_inode, em_start + em_len, cb, &memstall,
|
||||
&pflags, !(bbio->bio.bi_opf & REQ_RAHEAD));
|
||||
add_ra_bio_folios(&inode->vfs_inode, em_start + em_len, cb, &memstall,
|
||||
&pflags, !(bbio->bio.bi_opf & REQ_RAHEAD));
|
||||
|
||||
cb->len = bbio->bio.bi_iter.bi_size;
|
||||
cb->bbio.bio.bi_iter.bi_sector = bbio->bio.bi_iter.bi_sector;
|
||||
@@ -1191,22 +1170,6 @@ 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.
|
||||
*
|
||||
@@ -1259,7 +1222,7 @@ int btrfs_decompress_buf2page(const char *buf, u32 buf_len,
|
||||
* cb->start may underflow, but subtracting that value can still
|
||||
* give us correct offset inside the full decompressed extent.
|
||||
*/
|
||||
bvec_offset = file_offset_from_bvec(&bvec) - cb->start;
|
||||
bvec_offset = page_offset(bvec.bv_page) + bvec.bv_offset - cb->start;
|
||||
|
||||
/* Haven't reached the bvec range, exit */
|
||||
if (decompressed + buf_len <= bvec_offset)
|
||||
|
||||
+12
-21
@@ -475,13 +475,10 @@ int btrfs_force_cow_block(struct btrfs_trans_handle *trans,
|
||||
struct extent_buffer *cow;
|
||||
int level, ret;
|
||||
int last_ref = 0;
|
||||
int unlock_orig = 0;
|
||||
const bool unlock_orig = (*cow_ret == buf);
|
||||
u64 parent_start = 0;
|
||||
u64 reloc_src_root = 0;
|
||||
|
||||
if (*cow_ret == buf)
|
||||
unlock_orig = 1;
|
||||
|
||||
btrfs_assert_tree_write_locked(buf);
|
||||
|
||||
WARN_ON(test_bit(BTRFS_ROOT_SHAREABLE, &root->state) &&
|
||||
@@ -1497,17 +1494,11 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
|
||||
if (p->reada == READA_FORWARD_ALWAYS)
|
||||
reada_for_search(fs_info, p, parent_level, slot, key->objectid);
|
||||
|
||||
/* first we do an atomic uptodate check */
|
||||
if (btrfs_buffer_uptodate(tmp, check.transid, NULL) > 0) {
|
||||
/*
|
||||
* Do extra check for first_key, eb can be stale due to
|
||||
* being cached, read from scrub, or have multiple
|
||||
* parents (shared tree blocks).
|
||||
*/
|
||||
if (unlikely(btrfs_verify_level_key(tmp, &check))) {
|
||||
ret = -EUCLEAN;
|
||||
goto out;
|
||||
}
|
||||
/* Check if the cached eb is uptodate. */
|
||||
ret = btrfs_buffer_uptodate(tmp, check.transid, &check);
|
||||
if (unlikely(ret < 0))
|
||||
goto out;
|
||||
if (ret > 0) {
|
||||
*eb_ret = tmp;
|
||||
tmp = NULL;
|
||||
ret = 0;
|
||||
@@ -2075,7 +2066,7 @@ again:
|
||||
}
|
||||
|
||||
while (b) {
|
||||
int dec = 0;
|
||||
bool dec = false;
|
||||
int ret2;
|
||||
|
||||
level = btrfs_header_level(b);
|
||||
@@ -2158,7 +2149,7 @@ cow_done:
|
||||
prev_cmp = ret;
|
||||
|
||||
if (ret && slot > 0) {
|
||||
dec = 1;
|
||||
dec = true;
|
||||
slot--;
|
||||
}
|
||||
p->slots[level] = slot;
|
||||
@@ -2288,7 +2279,7 @@ again:
|
||||
p->locks[level] = BTRFS_READ_LOCK;
|
||||
|
||||
while (b) {
|
||||
int dec = 0;
|
||||
bool dec = false;
|
||||
int ret2;
|
||||
|
||||
level = btrfs_header_level(b);
|
||||
@@ -2313,7 +2304,7 @@ again:
|
||||
}
|
||||
|
||||
if (ret && slot > 0) {
|
||||
dec = 1;
|
||||
dec = true;
|
||||
slot--;
|
||||
}
|
||||
p->slots[level] = slot;
|
||||
@@ -3674,7 +3665,7 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
|
||||
int wret;
|
||||
int split;
|
||||
int num_doubles = 0;
|
||||
int tried_avoid_double = 0;
|
||||
bool tried_avoid_double = false;
|
||||
|
||||
l = path->nodes[0];
|
||||
slot = path->slots[0];
|
||||
@@ -3836,7 +3827,7 @@ again:
|
||||
|
||||
push_for_double:
|
||||
push_for_double_split(trans, root, path, data_size);
|
||||
tried_avoid_double = 1;
|
||||
tried_avoid_double = true;
|
||||
if (btrfs_leaf_free_space(path->nodes[0]) >= data_size)
|
||||
return 0;
|
||||
goto again;
|
||||
|
||||
@@ -859,23 +859,6 @@ again:
|
||||
if (IS_ERR(folio))
|
||||
return folio;
|
||||
|
||||
/*
|
||||
* Since we can defragment files opened read-only, we can encounter
|
||||
* 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 (!IS_ENABLED(CONFIG_BTRFS_EXPERIMENTAL) && folio_test_large(folio)) {
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
return ERR_PTR(-ETXTBSY);
|
||||
}
|
||||
|
||||
ret = set_folio_extent_mapped(folio);
|
||||
if (ret < 0) {
|
||||
folio_unlock(folio);
|
||||
@@ -1179,7 +1162,6 @@ static int defrag_one_locked_target(struct btrfs_inode *inode,
|
||||
if (start >= folio_next_pos(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);
|
||||
|
||||
@@ -134,6 +134,8 @@ 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;
|
||||
else if (btrfs_is_zoned(fs_info) && btrfs_is_data_reloc_root(root))
|
||||
flush = BTRFS_RESERVE_FLUSH_ZONED_RELOCATION;
|
||||
|
||||
return btrfs_reserve_data_bytes(data_sinfo_for_inode(inode), bytes, flush);
|
||||
}
|
||||
@@ -279,7 +281,7 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
|
||||
*
|
||||
* This is overestimating in most cases.
|
||||
*/
|
||||
qgroup_rsv_size = (u64)outstanding_extents * fs_info->nodesize;
|
||||
qgroup_rsv_size = ((u64)outstanding_extents << fs_info->nodesize_bits);
|
||||
|
||||
spin_lock(&block_rsv->lock);
|
||||
block_rsv->size = reserve_size;
|
||||
@@ -309,7 +311,7 @@ static void calc_inode_reservations(struct btrfs_inode *inode,
|
||||
* for an inode update.
|
||||
*/
|
||||
*meta_reserve += inode_update;
|
||||
*qgroup_reserve = nr_extents * fs_info->nodesize;
|
||||
*qgroup_reserve = (nr_extents << fs_info->nodesize_bits);
|
||||
}
|
||||
|
||||
int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes,
|
||||
|
||||
@@ -615,6 +615,9 @@ static bool insert_delayed_ref(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_delayed_ref_node *exist;
|
||||
int mod;
|
||||
|
||||
ASSERT(ref->action == BTRFS_ADD_DELAYED_REF ||
|
||||
ref->action == BTRFS_DROP_DELAYED_REF);
|
||||
|
||||
spin_lock(&href->lock);
|
||||
exist = tree_insert(&href->ref_tree, ref);
|
||||
if (!exist) {
|
||||
@@ -641,7 +644,7 @@ static bool insert_delayed_ref(struct btrfs_trans_handle *trans,
|
||||
ASSERT(!list_empty(&exist->add_list));
|
||||
list_del_init(&exist->add_list);
|
||||
} else {
|
||||
ASSERT(0);
|
||||
DEBUG_WARN();
|
||||
}
|
||||
} else
|
||||
mod = -ref->ref_mod;
|
||||
|
||||
+10
-1
@@ -307,6 +307,8 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
||||
device->bdev_file = bdev_file;
|
||||
set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
|
||||
set_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state);
|
||||
/* Check the comment in btrfs_init_new_device() for the reason. */
|
||||
atomic_inc(&device->dev_stats_ccnt);
|
||||
device->dev_stats_valid = 1;
|
||||
set_blocksize(bdev_file, BTRFS_BDEV_BLOCKSIZE);
|
||||
device->fs_devices = fs_devices;
|
||||
@@ -1013,8 +1015,15 @@ error:
|
||||
|
||||
/* write back the superblocks */
|
||||
trans = btrfs_start_transaction(root, 0);
|
||||
if (!IS_ERR(trans))
|
||||
if (!IS_ERR(trans)) {
|
||||
/*
|
||||
* Ignore any error here, if we failed to remove the DEV_STATS
|
||||
* item for devid 0, it's not a big deal. We have other ways
|
||||
* to address it.
|
||||
*/
|
||||
btrfs_remove_dev_stat_item(trans, BTRFS_DEV_REPLACE_DEVID);
|
||||
btrfs_commit_transaction(trans);
|
||||
}
|
||||
|
||||
mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
|
||||
|
||||
|
||||
+57
-5
@@ -15,10 +15,12 @@
|
||||
|
||||
struct btrfs_dio_data {
|
||||
ssize_t submitted;
|
||||
loff_t old_isize;
|
||||
struct extent_changeset *data_reserved;
|
||||
struct btrfs_ordered_extent *ordered;
|
||||
bool data_space_reserved;
|
||||
bool nocow_done;
|
||||
bool updated_isize;
|
||||
};
|
||||
|
||||
struct btrfs_dio_private {
|
||||
@@ -228,6 +230,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
|
||||
bool space_reserved = false;
|
||||
u64 len = *lenp;
|
||||
u64 prev_len;
|
||||
loff_t old_isize;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
@@ -341,8 +344,14 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
|
||||
* Need to update the i_size under the extent lock so buffered
|
||||
* readers will get the updated i_size when we unlock.
|
||||
*/
|
||||
if (start + len > i_size_read(inode))
|
||||
old_isize = i_size_read(inode);
|
||||
if (start + len > old_isize) {
|
||||
if (!dio_data->updated_isize) {
|
||||
dio_data->old_isize = old_isize;
|
||||
dio_data->updated_isize = true;
|
||||
}
|
||||
i_size_write(inode, start + len);
|
||||
}
|
||||
out:
|
||||
if (ret && space_reserved) {
|
||||
btrfs_delalloc_release_extents(BTRFS_I(inode), len);
|
||||
@@ -624,12 +633,55 @@ static int btrfs_dio_iomap_end(struct inode *inode, loff_t pos, loff_t length,
|
||||
if (submitted < length) {
|
||||
pos += submitted;
|
||||
length -= submitted;
|
||||
if (write)
|
||||
if (write) {
|
||||
/*
|
||||
* Got a short write and have updated the isize, need to
|
||||
* revert the isize change.
|
||||
*
|
||||
* Normally we need to update isize with extent lock hold,
|
||||
* but we're safe due to the following factors:
|
||||
*
|
||||
* - Only a single writer can be enlarging isize
|
||||
* Enlarging isize will take the exclusive inode lock.
|
||||
*
|
||||
* - Buffered readers need to wait for the OE we're holding
|
||||
* Buffered readers will lock extent and wait for OE
|
||||
* of the folio range, and since page cache is invalidated
|
||||
* the OE wait can not be skipped.
|
||||
*
|
||||
* So here we are safe to revert the isize before
|
||||
* finishing the OE, and no reader of the remaining range
|
||||
* can see the enlarged size.
|
||||
*
|
||||
* TODO: Extend the DIO_LOCKED lifespan for direct writes,
|
||||
* and only enlarge isize after a successful write.
|
||||
*/
|
||||
if (dio_data->updated_isize) {
|
||||
u64 new_isize;
|
||||
|
||||
if (submitted == 0)
|
||||
new_isize = dio_data->old_isize;
|
||||
else
|
||||
new_isize = max(dio_data->old_isize, pos);
|
||||
i_size_write(inode, new_isize);
|
||||
dio_data->updated_isize = false;
|
||||
}
|
||||
/*
|
||||
* We have a short write, if there is any range
|
||||
* that is submitted properly, that part will have
|
||||
* its own OE split from the original one.
|
||||
*
|
||||
* So for the OE at dio_data->ordered, it's the part
|
||||
* that is not submitted, and should be marked
|
||||
* as fully truncated.
|
||||
*/
|
||||
btrfs_mark_ordered_extent_truncated(dio_data->ordered, 0);
|
||||
btrfs_finish_ordered_extent(dio_data->ordered,
|
||||
pos, length, false);
|
||||
else
|
||||
pos, length, true);
|
||||
} else {
|
||||
btrfs_unlock_dio_extent(&BTRFS_I(inode)->io_tree, pos,
|
||||
pos + length - 1, NULL);
|
||||
}
|
||||
ret = -ENOTBLK;
|
||||
}
|
||||
if (write) {
|
||||
@@ -926,7 +978,7 @@ again:
|
||||
if (ret > 0)
|
||||
written = ret;
|
||||
|
||||
if (iov_iter_count(from) > 0 && (ret == -EFAULT || ret > 0)) {
|
||||
if (iov_iter_count(from) > 0 && (ret == -EFAULT || ret >= 0)) {
|
||||
const size_t left = iov_iter_count(from);
|
||||
/*
|
||||
* We have more data left to write. Try to fault in as many as
|
||||
|
||||
+111
-28
@@ -215,7 +215,7 @@ int btrfs_read_extent_buffer(struct extent_buffer *eb,
|
||||
const struct btrfs_tree_parent_check *check)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = eb->fs_info;
|
||||
int failed = 0;
|
||||
bool failed = false;
|
||||
int ret;
|
||||
int num_copies = 0;
|
||||
int mirror_num = 0;
|
||||
@@ -234,7 +234,7 @@ int btrfs_read_extent_buffer(struct extent_buffer *eb,
|
||||
break;
|
||||
|
||||
if (!failed_mirror) {
|
||||
failed = 1;
|
||||
failed = true;
|
||||
failed_mirror = eb->read_mirror;
|
||||
}
|
||||
|
||||
@@ -491,10 +491,34 @@ static bool btree_release_folio(struct folio *folio, gfp_t gfp_flags)
|
||||
static void btree_invalidate_folio(struct folio *folio, size_t offset,
|
||||
size_t length)
|
||||
{
|
||||
struct extent_io_tree *tree;
|
||||
struct extent_io_tree *tree = &folio_to_inode(folio)->io_tree;
|
||||
struct extent_state *cached_state = NULL;
|
||||
const u64 start = folio_pos(folio);
|
||||
const u64 end = folio_next_pos(folio) - 1;
|
||||
|
||||
/*
|
||||
* The range must cover the full @folio.
|
||||
* Btree inode is never exposed to regular file operations, thus there
|
||||
* is no partial truncation.
|
||||
* The folio is only invalidated when the btree inode is evicted.
|
||||
*/
|
||||
ASSERT(offset == 0, "folio=%llu offset=%zu", folio_pos(folio), offset);
|
||||
ASSERT(length == folio_size(folio), "folio=%llu folio_size=%zu length=%zu",
|
||||
folio_pos(folio), folio_size(folio), length);
|
||||
|
||||
/* This function is only called for the btree inode */
|
||||
ASSERT(tree->owner == IO_TREE_BTREE_INODE_IO);
|
||||
|
||||
btrfs_lock_extent(tree, start, end, &cached_state);
|
||||
folio_wait_writeback(folio);
|
||||
|
||||
/*
|
||||
* Currently for btree io tree, only EXTENT_LOCKED is utilized,
|
||||
* so here we only need to unlock the extent range to free any
|
||||
* existing extent state.
|
||||
*/
|
||||
btrfs_unlock_extent(tree, start, end, &cached_state);
|
||||
|
||||
tree = &folio_to_inode(folio)->io_tree;
|
||||
extent_invalidate_folio(tree, folio, offset);
|
||||
btree_release_folio(folio, GFP_NOFS);
|
||||
if (folio_get_private(folio)) {
|
||||
btrfs_warn(folio_to_fs_info(folio),
|
||||
@@ -539,7 +563,7 @@ static bool btree_dirty_folio(struct address_space *mapping,
|
||||
continue;
|
||||
}
|
||||
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||
cur = page_start + cur_bit * fs_info->sectorsize;
|
||||
cur = page_start + (cur_bit << fs_info->sectorsize_bits);
|
||||
|
||||
eb = find_extent_buffer(fs_info, cur);
|
||||
ASSERT(eb);
|
||||
@@ -1736,7 +1760,6 @@ static int read_backup_root(struct btrfs_fs_info *fs_info, u8 priority)
|
||||
/* helper to cleanup workers */
|
||||
static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
btrfs_destroy_workqueue(fs_info->fixup_workers);
|
||||
btrfs_destroy_workqueue(fs_info->delalloc_workers);
|
||||
btrfs_destroy_workqueue(fs_info->workers);
|
||||
if (fs_info->endio_workers)
|
||||
@@ -1944,9 +1967,6 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info)
|
||||
fs_info->caching_workers =
|
||||
btrfs_alloc_workqueue(fs_info, "cache", flags, max_active, 0);
|
||||
|
||||
fs_info->fixup_workers =
|
||||
btrfs_alloc_ordered_workqueue(fs_info, "fixup", ordered_flags);
|
||||
|
||||
fs_info->endio_workers =
|
||||
alloc_workqueue("btrfs-endio", flags, max_active);
|
||||
fs_info->endio_meta_workers =
|
||||
@@ -1972,7 +1992,7 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info)
|
||||
fs_info->endio_workers && fs_info->endio_meta_workers &&
|
||||
fs_info->endio_write_workers &&
|
||||
fs_info->endio_freespace_worker && fs_info->rmw_workers &&
|
||||
fs_info->caching_workers && fs_info->fixup_workers &&
|
||||
fs_info->caching_workers &&
|
||||
fs_info->delayed_workers && fs_info->qgroup_rescan_workers &&
|
||||
fs_info->discard_ctl.discard_workers)) {
|
||||
return -ENOMEM;
|
||||
@@ -2776,6 +2796,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
|
||||
mutex_init(&fs_info->unused_bg_unpin_mutex);
|
||||
mutex_init(&fs_info->reclaim_bgs_lock);
|
||||
mutex_init(&fs_info->reloc_mutex);
|
||||
spin_lock_init(&fs_info->reloc_ctl_lock);
|
||||
mutex_init(&fs_info->delalloc_root_mutex);
|
||||
mutex_init(&fs_info->zoned_meta_io_lock);
|
||||
mutex_init(&fs_info->zoned_data_reloc_io_lock);
|
||||
@@ -3276,6 +3297,64 @@ static bool fs_is_full_ro(const struct btrfs_fs_info *fs_info)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to wait for any metadata readahead, and invalidate all btree folios.
|
||||
*
|
||||
* If the invalidation failed, report any dirty/held extent buffers.
|
||||
*/
|
||||
static void invalidate_and_check_btree_folios(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
unsigned long index = 0;
|
||||
struct extent_buffer *eb;
|
||||
int ret;
|
||||
|
||||
ret = invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
|
||||
if (likely(ret == 0))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Some btree pages can not be invalidated, this happens when some tree
|
||||
* blocks are still held (either by readahead or some task is holding a ref).
|
||||
*/
|
||||
rcu_read_lock();
|
||||
xa_for_each(&fs_info->buffer_tree, index, eb) {
|
||||
/* Increase the ref so that the eb won't disappear. */
|
||||
if (!refcount_inc_not_zero(&eb->refs))
|
||||
continue;
|
||||
rcu_read_unlock();
|
||||
|
||||
/* Wait for any readahead first. */
|
||||
if (test_bit(EXTENT_BUFFER_READING, &eb->bflags))
|
||||
wait_on_bit_io(&eb->bflags, EXTENT_BUFFER_READING,
|
||||
TASK_UNINTERRUPTIBLE);
|
||||
/*
|
||||
* The refs threshold is 2, one held by us at the beginning
|
||||
* of the loop, one for the ownership in the buffer tree.
|
||||
*/
|
||||
if (unlikely(refcount_read(&eb->refs) > 2 || extent_buffer_under_io(eb))) {
|
||||
WARN_ON_ONCE(IS_ENABLED(CONFIG_BTRFS_DEBUG));
|
||||
btrfs_warn(fs_info,
|
||||
"unable to release extent buffer %llu owner %llu gen %llu refs %u flags 0x%lx",
|
||||
eb->start, btrfs_header_owner(eb),
|
||||
btrfs_header_generation(eb),
|
||||
refcount_read(&eb->refs), eb->bflags);
|
||||
}
|
||||
free_extent_buffer(eb);
|
||||
rcu_read_lock();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
|
||||
}
|
||||
|
||||
static u32 calc_block_max_order(u32 sectorsize_bits)
|
||||
{
|
||||
u32 max_size;
|
||||
|
||||
max_size = min(BTRFS_MAX_BLOCKS_PER_FOLIO << sectorsize_bits,
|
||||
BTRFS_MAX_FOLIO_SIZE);
|
||||
return ilog2(round_up(max_size, PAGE_SIZE) >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_devices)
|
||||
{
|
||||
u32 sectorsize;
|
||||
@@ -3398,7 +3477,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
|
||||
fs_info->sectorsize = sectorsize;
|
||||
fs_info->sectorsize_bits = ilog2(sectorsize);
|
||||
fs_info->block_min_order = ilog2(round_up(sectorsize, PAGE_SIZE) >> PAGE_SHIFT);
|
||||
fs_info->block_max_order = ilog2((BITS_PER_LONG << fs_info->sectorsize_bits) >> PAGE_SHIFT);
|
||||
fs_info->block_max_order = calc_block_max_order(fs_info->sectorsize_bits);
|
||||
fs_info->csums_per_leaf = BTRFS_MAX_ITEM_SIZE(fs_info) / fs_info->csum_size;
|
||||
fs_info->stripesize = stripesize;
|
||||
fs_info->fs_devices->fs_info = fs_info;
|
||||
@@ -3451,7 +3530,16 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
|
||||
/* Update the values for the current filesystem. */
|
||||
sb->s_blocksize = sectorsize;
|
||||
sb->s_blocksize_bits = blksize_bits(sectorsize);
|
||||
memcpy(&sb->s_uuid, fs_info->fs_devices->fsid, BTRFS_FSID_SIZE);
|
||||
/*
|
||||
* When temp_fsid is active, fs_devices->fsid is assigned a random UUID
|
||||
* at mount. This inconsistent UUID causes issues for layered filesystems
|
||||
* like OverlayFS. Since metadata_uuid may or may not be set, provide the
|
||||
* on-disk UUID directly from the super_copy.
|
||||
*/
|
||||
if (fs_info->fs_devices->temp_fsid)
|
||||
memcpy(&sb->s_uuid, fs_info->super_copy->fsid, BTRFS_FSID_SIZE);
|
||||
else
|
||||
memcpy(&sb->s_uuid, fs_info->fs_devices->fsid, BTRFS_FSID_SIZE);
|
||||
|
||||
mutex_lock(&fs_info->chunk_mutex);
|
||||
ret = btrfs_read_sys_array(fs_info);
|
||||
@@ -3591,6 +3679,13 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
|
||||
}
|
||||
}
|
||||
|
||||
ret = btrfs_init_writeback_bio_size(fs_info);
|
||||
if (ret) {
|
||||
btrfs_err(fs_info, "failed to get optimum writeback size: %d",
|
||||
ret);
|
||||
goto fail_sysfs;
|
||||
}
|
||||
|
||||
btrfs_free_zone_cache(fs_info);
|
||||
|
||||
btrfs_check_active_zone_reservation(fs_info);
|
||||
@@ -3706,7 +3801,7 @@ fail_tree_roots:
|
||||
if (fs_info->data_reloc_root)
|
||||
btrfs_drop_and_free_fs_root(fs_info, fs_info->data_reloc_root);
|
||||
free_root_pointers(fs_info, true);
|
||||
invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
|
||||
invalidate_and_check_btree_folios(fs_info);
|
||||
|
||||
fail_sb_buffer:
|
||||
btrfs_stop_all_workers(fs_info);
|
||||
@@ -4209,7 +4304,6 @@ static void warn_about_uncommitted_trans(struct btrfs_fs_info *fs_info)
|
||||
list_del_init(&trans->list);
|
||||
|
||||
btrfs_put_transaction(trans);
|
||||
trace_btrfs_transaction_commit(fs_info);
|
||||
}
|
||||
ASSERT(!found);
|
||||
}
|
||||
@@ -4279,16 +4373,6 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
|
||||
if (unlikely(BTRFS_FS_ERROR(fs_info)))
|
||||
btrfs_error_commit_super(fs_info);
|
||||
|
||||
/*
|
||||
* Wait for any fixup workers to complete.
|
||||
* If we don't wait for them here and they are still running by the time
|
||||
* we call kthread_stop() against the cleaner kthread further below, we
|
||||
* get an use-after-free on the cleaner because the fixup worker adds an
|
||||
* inode to the list of delayed iputs and then attempts to wakeup the
|
||||
* cleaner kthread, which was already stopped and destroyed. We parked
|
||||
* already the cleaner, but below we run all pending delayed iputs.
|
||||
*/
|
||||
btrfs_flush_workqueue(fs_info->fixup_workers);
|
||||
/*
|
||||
* Similar case here, we have to wait for delalloc workers before we
|
||||
* proceed below and stop the cleaner kthread, otherwise we trigger a
|
||||
@@ -4412,7 +4496,7 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
|
||||
ASSERT(list_empty(&fs_info->delayed_iputs));
|
||||
set_bit(BTRFS_FS_CLOSING_DONE, &fs_info->flags);
|
||||
|
||||
if (btrfs_check_quota_leak(fs_info)) {
|
||||
if (unlikely(btrfs_check_quota_leak(fs_info))) {
|
||||
DEBUG_WARN("qgroup reserved space leaked");
|
||||
btrfs_err(fs_info, "qgroup reserved space leaked");
|
||||
}
|
||||
@@ -4445,7 +4529,7 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
|
||||
* We must make sure there is not any read request to
|
||||
* submit after we stop all workers.
|
||||
*/
|
||||
invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
|
||||
invalidate_and_check_btree_folios(fs_info);
|
||||
btrfs_stop_all_workers(fs_info);
|
||||
|
||||
/*
|
||||
@@ -4881,7 +4965,6 @@ static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info)
|
||||
spin_unlock(&fs_info->trans_lock);
|
||||
|
||||
btrfs_put_transaction(t);
|
||||
trace_btrfs_transaction_commit(fs_info);
|
||||
spin_lock(&fs_info->trans_lock);
|
||||
}
|
||||
spin_unlock(&fs_info->trans_lock);
|
||||
|
||||
@@ -1763,7 +1763,7 @@ u64 btrfs_count_range_bits(struct extent_io_tree *tree,
|
||||
u64 cur_start = *start;
|
||||
u64 total_bytes = 0;
|
||||
u64 last = 0;
|
||||
int found = 0;
|
||||
bool found = false;
|
||||
|
||||
if (WARN_ON(search_end < cur_start))
|
||||
return 0;
|
||||
@@ -1817,7 +1817,7 @@ search:
|
||||
break;
|
||||
if (!found) {
|
||||
*start = max(cur_start, state->start);
|
||||
found = 1;
|
||||
found = true;
|
||||
}
|
||||
last = state->end;
|
||||
} else if (contig && found) {
|
||||
|
||||
+36
-21
@@ -385,7 +385,7 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
|
||||
return type;
|
||||
}
|
||||
} else {
|
||||
ASSERT(is_data == BTRFS_REF_TYPE_ANY);
|
||||
ASSERT(is_data == BTRFS_REF_TYPE_ANY, "is_data=%d", is_data);
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -1699,13 +1699,13 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
|
||||
struct extent_buffer *leaf;
|
||||
u32 item_size;
|
||||
int ret;
|
||||
int metadata = 1;
|
||||
bool metadata = true;
|
||||
|
||||
if (TRANS_ABORTED(trans))
|
||||
return 0;
|
||||
|
||||
if (!btrfs_fs_incompat(fs_info, SKINNY_METADATA))
|
||||
metadata = 0;
|
||||
metadata = false;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
@@ -1745,7 +1745,7 @@ again:
|
||||
}
|
||||
if (ret > 0) {
|
||||
btrfs_release_path(path);
|
||||
metadata = 0;
|
||||
metadata = false;
|
||||
|
||||
key.objectid = head->bytenr;
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
@@ -2108,7 +2108,8 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
|
||||
locked_ref = btrfs_select_ref_head(fs_info, delayed_refs);
|
||||
if (IS_ERR_OR_NULL(locked_ref)) {
|
||||
if (PTR_ERR(locked_ref) == -EAGAIN) {
|
||||
continue;
|
||||
count++;
|
||||
goto again;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -2156,7 +2157,7 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
|
||||
* Either success case or btrfs_run_delayed_refs_for_head
|
||||
* returned -EAGAIN, meaning we need to select another head
|
||||
*/
|
||||
|
||||
again:
|
||||
locked_ref = NULL;
|
||||
cond_resched();
|
||||
} while ((min_bytes != U64_MAX && bytes_processed < min_bytes) ||
|
||||
@@ -2531,8 +2532,11 @@ int btrfs_cross_ref_exist(struct btrfs_inode *inode, u64 offset,
|
||||
struct btrfs_key key;
|
||||
|
||||
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
|
||||
ASSERT(key.objectid == bytenr);
|
||||
ASSERT(key.type == BTRFS_EXTENT_ITEM_KEY);
|
||||
ASSERT(key.objectid == bytenr,
|
||||
"key.objectid=%llu bytenr=%llu",
|
||||
key.objectid, bytenr);
|
||||
ASSERT(key.type == BTRFS_EXTENT_ITEM_KEY, "key.type=%u",
|
||||
key.type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3279,7 +3283,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||
int ret;
|
||||
int is_data;
|
||||
int extent_slot = 0;
|
||||
int found_extent = 0;
|
||||
bool found_extent = false;
|
||||
int num_to_del = 1;
|
||||
int refs_to_drop = node->ref_mod;
|
||||
u32 item_size;
|
||||
@@ -3335,12 +3339,12 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||
break;
|
||||
if (key.type == BTRFS_EXTENT_ITEM_KEY &&
|
||||
key.offset == num_bytes) {
|
||||
found_extent = 1;
|
||||
found_extent = true;
|
||||
break;
|
||||
}
|
||||
if (key.type == BTRFS_METADATA_ITEM_KEY &&
|
||||
key.offset == owner_objectid) {
|
||||
found_extent = 1;
|
||||
found_extent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4598,10 +4602,12 @@ static noinline int find_free_extent(struct btrfs_root *root,
|
||||
/* 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);
|
||||
ASSERT(space_info->subgroup_id == BTRFS_SUB_GROUP_DATA_RELOC,
|
||||
"space_info->subgroup_id=%d", space_info->subgroup_id);
|
||||
} else if (ffe_ctl->for_treelog) {
|
||||
space_info = space_info->sub_group[0];
|
||||
ASSERT(space_info->subgroup_id == BTRFS_SUB_GROUP_TREELOG);
|
||||
ASSERT(space_info->subgroup_id == BTRFS_SUB_GROUP_TREELOG,
|
||||
"space_info->subgroup_id=%d", space_info->subgroup_id);
|
||||
}
|
||||
}
|
||||
if (!space_info) {
|
||||
@@ -5781,16 +5787,21 @@ static int check_next_block_uptodate(struct btrfs_trans_handle *trans,
|
||||
|
||||
generation = btrfs_node_ptr_generation(path->nodes[level], path->slots[level]);
|
||||
|
||||
if (btrfs_buffer_uptodate(next, generation, NULL))
|
||||
return 0;
|
||||
|
||||
check.level = level - 1;
|
||||
check.transid = generation;
|
||||
check.owner_root = btrfs_root_id(root);
|
||||
check.has_first_key = true;
|
||||
btrfs_node_key_to_cpu(path->nodes[level], &check.first_key, path->slots[level]);
|
||||
|
||||
ret = btrfs_buffer_uptodate(next, generation, &check);
|
||||
if (ret > 0)
|
||||
return 0;
|
||||
btrfs_tree_unlock(next);
|
||||
if (ret < 0) {
|
||||
free_extent_buffer(next);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (level == 1)
|
||||
reada_walk_down(trans, root, wc, path);
|
||||
ret = btrfs_read_extent_buffer(next, &check);
|
||||
@@ -6613,12 +6624,16 @@ static int btrfs_trim_free_extents_throttle(struct btrfs_device *device,
|
||||
|
||||
*trimmed = 0;
|
||||
|
||||
/* Discard not supported = nothing to do. */
|
||||
if (!bdev_max_discard_sectors(device->bdev))
|
||||
/*
|
||||
* The caller only filters out MISSING devices, but a device that was
|
||||
* missing at mount and later rescanned has MISSING cleared while bdev
|
||||
* is still NULL and WRITEABLE is still unset. Skip those here.
|
||||
*/
|
||||
if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state) || !device->bdev)
|
||||
return 0;
|
||||
|
||||
/* Not writable = nothing to do. */
|
||||
if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state))
|
||||
/* Discard not supported = nothing to do. */
|
||||
if (!bdev_max_discard_sectors(device->bdev))
|
||||
return 0;
|
||||
|
||||
/* No free space = nothing to do. */
|
||||
@@ -6645,7 +6660,7 @@ static int btrfs_trim_free_extents_throttle(struct btrfs_device *device,
|
||||
start = max(start, cur_start);
|
||||
|
||||
/* Check if there are any CHUNK_* bits left */
|
||||
if (start > device->total_bytes) {
|
||||
if (unlikely(start > device->total_bytes)) {
|
||||
DEBUG_WARN();
|
||||
btrfs_warn(fs_info,
|
||||
"ignoring attempt to trim beyond device size: offset %llu length %llu device %s device size %llu",
|
||||
|
||||
+171
-174
File diff suppressed because it is too large
Load Diff
+19
-6
@@ -55,7 +55,6 @@ enum {
|
||||
/* Page starts writeback, clear dirty bit and set writeback bit */
|
||||
ENUM_BIT(PAGE_START_WRITEBACK),
|
||||
ENUM_BIT(PAGE_END_WRITEBACK),
|
||||
ENUM_BIT(PAGE_SET_ORDERED),
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -327,6 +326,12 @@ static inline bool extent_buffer_uptodate(const struct extent_buffer *eb)
|
||||
return test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
|
||||
}
|
||||
|
||||
static inline bool extent_buffer_under_io(const struct extent_buffer *eb)
|
||||
{
|
||||
return (test_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags) ||
|
||||
test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
|
||||
}
|
||||
|
||||
int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
|
||||
unsigned long start, unsigned long len);
|
||||
void read_extent_buffer(const struct extent_buffer *eb, void *dst,
|
||||
@@ -381,15 +386,23 @@ void extent_clear_unlock_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
|
||||
const struct folio *locked_folio,
|
||||
struct extent_state **cached,
|
||||
u32 bits_to_clear, unsigned long page_ops);
|
||||
int extent_invalidate_folio(struct extent_io_tree *tree,
|
||||
struct folio *folio, size_t offset);
|
||||
void btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans,
|
||||
struct extent_buffer *buf);
|
||||
|
||||
int btrfs_alloc_page_array(unsigned int nr_pages, struct page **page_array,
|
||||
bool nofail);
|
||||
static inline void btrfs_clear_folio_dirty_tag(struct folio *folio)
|
||||
{
|
||||
ASSERT(!folio_test_dirty(folio));
|
||||
ASSERT(folio_test_locked(folio));
|
||||
ASSERT(folio->mapping);
|
||||
xa_lock_irq(&folio->mapping->i_pages);
|
||||
__xa_clear_mark(&folio->mapping->i_pages, folio->index,
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
xa_unlock_irq(&folio->mapping->i_pages);
|
||||
}
|
||||
|
||||
int btrfs_alloc_page_array(unsigned int nr_pages, struct page **page_array, gfp_t gfp);
|
||||
int btrfs_alloc_folio_array(unsigned int nr_folios, unsigned int order,
|
||||
struct folio **folio_array);
|
||||
struct folio **folio_array, gfp_t gfp);
|
||||
|
||||
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
|
||||
bool find_lock_delalloc_range(struct inode *inode,
|
||||
|
||||
@@ -717,7 +717,7 @@ int btrfs_add_extent_mapping(struct btrfs_inode *inode,
|
||||
* file offset. Here just do a sanity check.
|
||||
*/
|
||||
if (em->disk_bytenr == EXTENT_MAP_INLINE)
|
||||
ASSERT(em->start == 0);
|
||||
ASSERT(em->start == 0, "em->start=%llu", em->start);
|
||||
|
||||
ret = add_extent_mapping(inode, em, false);
|
||||
/* it is possible that someone inserted the extent into the tree
|
||||
@@ -761,7 +761,7 @@ int btrfs_add_extent_mapping(struct btrfs_inode *inode,
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(ret == 0 || ret == -EEXIST);
|
||||
ASSERT(ret == 0 || ret == -EEXIST, "ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -943,7 +943,7 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
|
||||
|
||||
ret = add_extent_mapping(inode, split, modified);
|
||||
/* Logic error, shouldn't happen. */
|
||||
ASSERT(ret == 0);
|
||||
ASSERT(ret == 0, "ret=%d", ret);
|
||||
if (WARN_ON(ret != 0) && modified)
|
||||
btrfs_set_inode_full_sync(inode);
|
||||
}
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
|
||||
u64 cache_end;
|
||||
|
||||
/* Set at the end of extent_fiemap(). */
|
||||
ASSERT((flags & FIEMAP_EXTENT_LAST) == 0);
|
||||
ASSERT((flags & FIEMAP_EXTENT_LAST) == 0, "flags=0x%u", flags);
|
||||
|
||||
if (!cache->cached)
|
||||
goto assign;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user