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:
Linus Torvalds
2026-06-16 12:08:02 +05:30
58 changed files with 3480 additions and 1909 deletions
+3 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
-18
View File
@@ -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);
+4 -2
View File
@@ -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,
+4 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+2 -2
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+19 -6
View File
@@ -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,
+3 -3
View File
@@ -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
View File
@@ -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