Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

btrfs: error handling fixes #1507

Open
wants to merge 43 commits into
base: for-next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
3ff8678
btrfs: simplify waiting for encoded read endios
morbidrsa Nov 13, 2024
a47f958
btrfs: fix improper generation check in snapshot delete
josefbacik Nov 13, 2024
a498a0b
btrfs: move select_delayed_ref() and export it
josefbacik Nov 13, 2024
1c5210d
btrfs: selftests: add delayed ref self test cases
josefbacik Nov 14, 2024
804349c
btrfs: use kmemdup() in btrfs_uring_encoded_read()
maharmstone Nov 11, 2024
04ea13a
btrfs: use PTR_ERR() instead of PTR_ERR_OR_ZERO() for btrfs_get_extent()
adam900710 Nov 24, 2024
5b7b718
btrfs: send: remove redundant assignments to variable ret
ColinIanKing Nov 13, 2024
1c9b5a0
btrfs: fix mount failure due to remount races
adam900710 Oct 30, 2024
9a83e05
btrfs: handle FS_IOC_READ_VERITY_METADATA ioctl
allisonkarlitskaya Nov 26, 2024
0384091
btrfs: factor out btrfs_return_free_space()
naota Nov 14, 2024
1b7f3b5
btrfs: drop fs_info argument from btrfs_update_space_info_*()
naota Nov 14, 2024
c74c6d6
btrfs: zoned: reclaim unused zone by zone resetting
naota Nov 14, 2024
e9cac55
btrfs: fix missing snapshot drew unlock when root is dead during swap…
fdmanana Nov 29, 2024
dd26254
btrfs: don't BUG_ON() in btrfs_drop_extents()
morbidrsa Dec 2, 2024
c74b836
btrfs: fix data race when accessing the inode's disk_i_size at btrfs_…
Dec 3, 2024
bb232b2
btrfs: use bio_is_zone_append() in the completion handler
Nov 4, 2024
a52be67
btrfs: split bios to the fs sector size boundary
Nov 4, 2024
0eaa478
btrfs: properly wait for writeback before buffered write
adam900710 Dec 2, 2024
cd7f8d6
btrfs: handle bio_split() errors
morbidrsa Dec 3, 2024
4ad7c16
btrfs: flush delalloc workers queue before stopping cleaner kthread d…
fdmanana Dec 3, 2024
bc35155
btrfs: tree-checker: reject inline extent items with 0 ref count
adam900710 Dec 4, 2024
9118b50
btrfs: convert BUG_ON in btrfs_reloc_cow_block() to proper error hand…
josefbacik Oct 3, 2024
e6f07f4
btrfs: remove the changed list for backref cache
josefbacik Oct 3, 2024
1f46c1f
btrfs: add a comment for new_bytenr in backref_cache_node
josefbacik Oct 3, 2024
e0663eb
btrfs: simplify loop in select_reloc_root()
josefbacik Oct 3, 2024
5f01f14
btrfs: remove clone_backref_node() from relocation
josefbacik Oct 3, 2024
ad26f06
btrfs: don't build backref tree for COW-only blocks
josefbacik Oct 3, 2024
71e8a93
btrfs: do not handle non-shareable roots in backref cache
josefbacik Oct 3, 2024
d6617ca
btrfs: simplify btrfs_backref_release_cache()
josefbacik Oct 3, 2024
70e2821
btrfs: remove the ->lowest and ->leaves members from struct btrfs_bac…
josefbacik Oct 3, 2024
53b66d0
btrfs: remove detached list from struct btrfs_backref_cache
josefbacik Oct 3, 2024
c7e32cf
btrfs: improve the warning and error message for btrfs_remove_qgroup()
adam900710 Nov 10, 2024
c5b39d5
btrfs: open-code btrfs_copy_from_user()
adam900710 Nov 7, 2024
94ca57a
btrfs: output the reason for open_ctree() failure
adam900710 Dec 10, 2024
cc3ceda
btrfs: fix double accounting race when btrfs_run_delalloc_range() failed
adam900710 Nov 26, 2024
51e0c5f
btrfs: fix double accounting race when extent_writepage_io() failed
adam900710 Nov 26, 2024
d1a4d05
btrfs: fix the error handling of submit_uncompressed_range()
adam900710 Dec 6, 2024
9f8aec2
btrfs: do proper folio cleanup when cow_file_range() failed
adam900710 Nov 29, 2024
d3a8799
btrfs: do proper folio cleanup when run_delalloc_nocow() failed
adam900710 Dec 2, 2024
7533f83
btrfs: subpage: fix the bitmap dump for the locked flags
adam900710 Nov 27, 2024
498c745
btrfs: subpage: dump the involved bitmap when ASSERT() failed
adam900710 Nov 27, 2024
68c6ef2
btrfs: add extra error messages for delalloc range related errors
adam900710 Nov 27, 2024
ccbea21
btrfs: remove the unused @locked_folio parameter from
adam900710 Dec 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fs/btrfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \
tests/extent-buffer-tests.o tests/btrfs-tests.o \
tests/extent-io-tests.o tests/inode-tests.o tests/qgroup-tests.o \
tests/free-space-tree-tests.o tests/extent-map-tests.o \
tests/raid-stripe-tree-tests.o
tests/raid-stripe-tree-tests.o tests/delayed-refs-tests.o
93 changes: 24 additions & 69 deletions fs/btrfs/backref.c
Original file line number Diff line number Diff line change
Expand Up @@ -3022,9 +3022,6 @@ void btrfs_backref_init_cache(struct btrfs_fs_info *fs_info,
cache->rb_root = RB_ROOT;
for (i = 0; i < BTRFS_MAX_LEVEL; i++)
INIT_LIST_HEAD(&cache->pending[i]);
INIT_LIST_HEAD(&cache->changed);
INIT_LIST_HEAD(&cache->detached);
INIT_LIST_HEAD(&cache->leaves);
INIT_LIST_HEAD(&cache->pending_edge);
INIT_LIST_HEAD(&cache->useless_node);
cache->fs_info = fs_info;
Expand Down Expand Up @@ -3132,29 +3129,17 @@ void btrfs_backref_drop_node(struct btrfs_backref_cache *tree,
void btrfs_backref_cleanup_node(struct btrfs_backref_cache *cache,
struct btrfs_backref_node *node)
{
struct btrfs_backref_node *upper;
struct btrfs_backref_edge *edge;

if (!node)
return;

BUG_ON(!node->lowest && !node->detached);
while (!list_empty(&node->upper)) {
edge = list_entry(node->upper.next, struct btrfs_backref_edge,
list[LOWER]);
upper = edge->node[UPPER];
list_del(&edge->list[LOWER]);
list_del(&edge->list[UPPER]);
btrfs_backref_free_edge(cache, edge);

/*
* Add the node to leaf node list if no other child block
* cached.
*/
if (list_empty(&upper->lower)) {
list_add_tail(&upper->lower, &cache->leaves);
upper->lowest = 1;
}
}

btrfs_backref_drop_node(cache, node);
Expand All @@ -3166,33 +3151,13 @@ void btrfs_backref_cleanup_node(struct btrfs_backref_cache *cache,
void btrfs_backref_release_cache(struct btrfs_backref_cache *cache)
{
struct btrfs_backref_node *node;
int i;

while (!list_empty(&cache->detached)) {
node = list_entry(cache->detached.next,
struct btrfs_backref_node, list);
while ((node = rb_entry_safe(rb_first(&cache->rb_root),
struct btrfs_backref_node, rb_node)))
btrfs_backref_cleanup_node(cache, node);
}

while (!list_empty(&cache->leaves)) {
node = list_entry(cache->leaves.next,
struct btrfs_backref_node, lower);
btrfs_backref_cleanup_node(cache, node);
}

for (i = 0; i < BTRFS_MAX_LEVEL; i++) {
while (!list_empty(&cache->pending[i])) {
node = list_first_entry(&cache->pending[i],
struct btrfs_backref_node,
list);
btrfs_backref_cleanup_node(cache, node);
}
}
ASSERT(list_empty(&cache->pending_edge));
ASSERT(list_empty(&cache->useless_node));
ASSERT(list_empty(&cache->changed));
ASSERT(list_empty(&cache->detached));
ASSERT(RB_EMPTY_ROOT(&cache->rb_root));
ASSERT(!cache->nr_nodes);
ASSERT(!cache->nr_edges);
}
Expand Down Expand Up @@ -3316,8 +3281,12 @@ static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans,
root = btrfs_get_fs_root(fs_info, ref_key->offset, false);
if (IS_ERR(root))
return PTR_ERR(root);
if (!test_bit(BTRFS_ROOT_SHAREABLE, &root->state))
cur->cowonly = 1;

/* We shouldn't be using backref cache for non-shareable roots. */
if (unlikely(!test_bit(BTRFS_ROOT_SHAREABLE, &root->state))) {
btrfs_put_root(root);
return -EUCLEAN;
}

if (btrfs_root_level(&root->root_item) == cur->level) {
/* Tree root */
Expand Down Expand Up @@ -3403,8 +3372,15 @@ static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans,
goto out;
}
upper->owner = btrfs_header_owner(eb);
if (!test_bit(BTRFS_ROOT_SHAREABLE, &root->state))
upper->cowonly = 1;

/* We shouldn't be using backref cache for non shareable roots. */
if (unlikely(!test_bit(BTRFS_ROOT_SHAREABLE, &root->state))) {
btrfs_put_root(root);
btrfs_backref_free_edge(cache, edge);
btrfs_backref_free_node(cache, upper);
ret = -EUCLEAN;
goto out;
}

/*
* If we know the block isn't shared we can avoid
Expand Down Expand Up @@ -3595,15 +3571,9 @@ int btrfs_backref_finish_upper_links(struct btrfs_backref_cache *cache,

ASSERT(start->checked);

/* Insert this node to cache if it's not COW-only */
if (!start->cowonly) {
rb_node = rb_simple_insert(&cache->rb_root, start->bytenr,
&start->rb_node);
if (rb_node)
btrfs_backref_panic(cache->fs_info, start->bytenr,
-EEXIST);
list_add_tail(&start->lower, &cache->leaves);
}
rb_node = rb_simple_insert(&cache->rb_root, start->bytenr, &start->rb_node);
if (rb_node)
btrfs_backref_panic(cache->fs_info, start->bytenr, -EEXIST);

/*
* Use breadth first search to iterate all related edges.
Expand Down Expand Up @@ -3642,11 +3612,6 @@ int btrfs_backref_finish_upper_links(struct btrfs_backref_cache *cache,
* parents have already been linked.
*/
if (!RB_EMPTY_NODE(&upper->rb_node)) {
if (upper->lowest) {
list_del_init(&upper->lower);
upper->lowest = 0;
}

list_add_tail(&edge->list[UPPER], &upper->lower);
continue;
}
Expand All @@ -3657,23 +3622,13 @@ int btrfs_backref_finish_upper_links(struct btrfs_backref_cache *cache,
return -EUCLEAN;
}

/* Sanity check, COW-only node has non-COW-only parent */
if (start->cowonly != upper->cowonly) {
ASSERT(0);
rb_node = rb_simple_insert(&cache->rb_root, upper->bytenr,
&upper->rb_node);
if (unlikely(rb_node)) {
btrfs_backref_panic(cache->fs_info, upper->bytenr, -EEXIST);
return -EUCLEAN;
}

/* Only cache non-COW-only (subvolume trees) tree blocks */
if (!upper->cowonly) {
rb_node = rb_simple_insert(&cache->rb_root, upper->bytenr,
&upper->rb_node);
if (rb_node) {
btrfs_backref_panic(cache->fs_info,
upper->bytenr, -EEXIST);
return -EUCLEAN;
}
}

list_add_tail(&edge->list[UPPER], &upper->lower);

/*
Expand Down
16 changes: 6 additions & 10 deletions fs/btrfs/backref.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,12 @@ struct btrfs_backref_node {
u64 bytenr;
}; /* Use rb_simple_node for search/insert */

/*
* This is a sanity check, whenever we COW a block we will update
* new_bytenr with it's current location, and we will check this in
* various places to validate that the cache makes sense, it shouldn't
* be used for anything else.
*/
u64 new_bytenr;
/* Objectid of tree block owner, can be not uptodate */
u64 owner;
Expand All @@ -335,10 +341,6 @@ struct btrfs_backref_node {
struct extent_buffer *eb;
/* Level of the tree block */
unsigned int level:8;
/* Is the block in a non-shareable tree */
unsigned int cowonly:1;
/* 1 if no child node is in the cache */
unsigned int lowest:1;
/* Is the extent buffer locked */
unsigned int locked:1;
/* Has the block been processed */
Expand Down Expand Up @@ -391,12 +393,6 @@ struct btrfs_backref_cache {
* level blocks may not reflect the new location
*/
struct list_head pending[BTRFS_MAX_LEVEL];
/* List of backref nodes with no child node */
struct list_head leaves;
/* List of blocks that have been COWed in current transaction */
struct list_head changed;
/* List of detached backref node. */
struct list_head detached;

u64 last_trans;

Expand Down
33 changes: 26 additions & 7 deletions fs/btrfs/bio.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ static struct btrfs_bio *btrfs_split_bio(struct btrfs_fs_info *fs_info,

bio = bio_split(&orig_bbio->bio, map_length >> SECTOR_SHIFT, GFP_NOFS,
&btrfs_clone_bioset);
if (IS_ERR(bio))
return ERR_CAST(bio);

bbio = btrfs_bio(bio);
btrfs_bio_init(bbio, fs_info, NULL, orig_bbio);
bbio->inode = orig_bbio->inode;
Expand Down Expand Up @@ -355,7 +358,7 @@ static void btrfs_simple_end_io(struct bio *bio)
INIT_WORK(&bbio->end_io_work, btrfs_end_bio_work);
queue_work(btrfs_end_io_wq(fs_info, bio), &bbio->end_io_work);
} else {
if (bio_op(bio) == REQ_OP_ZONE_APPEND && !bio->bi_status)
if (bio_is_zone_append(bio) && !bio->bi_status)
btrfs_record_physical_zoned(bbio);
btrfs_bio_end_io(bbio, bbio->bio.bi_status);
}
Expand Down Expand Up @@ -398,7 +401,7 @@ static void btrfs_orig_write_end_io(struct bio *bio)
else
bio->bi_status = BLK_STS_OK;

if (bio_op(bio) == REQ_OP_ZONE_APPEND && !bio->bi_status)
if (bio_is_zone_append(bio) && !bio->bi_status)
stripe->physical = bio->bi_iter.bi_sector << SECTOR_SHIFT;

btrfs_bio_end_io(bbio, bbio->bio.bi_status);
Expand All @@ -412,7 +415,7 @@ static void btrfs_clone_write_end_io(struct bio *bio)
if (bio->bi_status) {
atomic_inc(&stripe->bioc->error);
btrfs_log_dev_io_error(bio, stripe->dev);
} else if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
} else if (bio_is_zone_append(bio)) {
stripe->physical = bio->bi_iter.bi_sector << SECTOR_SHIFT;
}

Expand Down Expand Up @@ -649,8 +652,14 @@ static u64 btrfs_append_map_length(struct btrfs_bio *bbio, u64 map_length)
map_length = min(map_length, bbio->fs_info->max_zone_append_size);
sector_offset = bio_split_rw_at(&bbio->bio, &bbio->fs_info->limits,
&nr_segs, map_length);
if (sector_offset)
return sector_offset << SECTOR_SHIFT;
if (sector_offset) {
/*
* bio_split_rw_at() could split at a size smaller than our
* sectorsize and thus cause unaligned I/Os. Fix that by
* always rounding down to the nearest boundary.
*/
return ALIGN_DOWN(sector_offset << SECTOR_SHIFT, bbio->fs_info->sectorsize);
}
return map_length;
}

Expand Down Expand Up @@ -678,15 +687,24 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num)
&bioc, &smap, &mirror_num);
if (error) {
ret = errno_to_blk_status(error);
goto fail;
btrfs_bio_counter_dec(fs_info);
goto end_bbio;
}

map_length = min(map_length, length);
if (use_append)
map_length = btrfs_append_map_length(bbio, map_length);

if (map_length < length) {
bbio = btrfs_split_bio(fs_info, bbio, map_length);
struct btrfs_bio *split;

split = btrfs_split_bio(fs_info, bbio, map_length);
if (IS_ERR(split)) {
ret = errno_to_blk_status(PTR_ERR(split));
btrfs_bio_counter_dec(fs_info);
goto end_bbio;
}
bbio = split;
bio = &bbio->bio;
}

Expand Down Expand Up @@ -760,6 +778,7 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num)

btrfs_bio_end_io(remaining, ret);
}
end_bbio:
btrfs_bio_end_io(bbio, ret);
/* Do not submit another chunk */
return true;
Expand Down
16 changes: 6 additions & 10 deletions fs/btrfs/block-group.c
Original file line number Diff line number Diff line change
Expand Up @@ -1223,7 +1223,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
block_group->space_info->total_bytes -= block_group->length;
block_group->space_info->bytes_readonly -=
(block_group->length - block_group->zone_unusable);
btrfs_space_info_update_bytes_zone_unusable(fs_info, block_group->space_info,
btrfs_space_info_update_bytes_zone_unusable(block_group->space_info,
-block_group->zone_unusable);
block_group->space_info->disk_total -= block_group->length * factor;

Expand Down Expand Up @@ -1396,8 +1396,7 @@ static int inc_block_group_ro(struct btrfs_block_group *cache, int force)
if (btrfs_is_zoned(cache->fs_info)) {
/* Migrate zone_unusable bytes to readonly */
sinfo->bytes_readonly += cache->zone_unusable;
btrfs_space_info_update_bytes_zone_unusable(cache->fs_info, sinfo,
-cache->zone_unusable);
btrfs_space_info_update_bytes_zone_unusable(sinfo, -cache->zone_unusable);
cache->zone_unusable = 0;
}
cache->ro++;
Expand Down Expand Up @@ -1645,8 +1644,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
spin_lock(&space_info->lock);
spin_lock(&block_group->lock);

btrfs_space_info_update_bytes_pinned(fs_info, space_info,
-block_group->pinned);
btrfs_space_info_update_bytes_pinned(space_info, -block_group->pinned);
space_info->bytes_readonly += block_group->pinned;
block_group->pinned = 0;

Expand Down Expand Up @@ -3060,8 +3058,7 @@ void btrfs_dec_block_group_ro(struct btrfs_block_group *cache)
(cache->alloc_offset - cache->used - cache->pinned -
cache->reserved) +
(cache->length - cache->zone_capacity);
btrfs_space_info_update_bytes_zone_unusable(cache->fs_info, sinfo,
cache->zone_unusable);
btrfs_space_info_update_bytes_zone_unusable(sinfo, cache->zone_unusable);
sinfo->bytes_readonly -= cache->zone_unusable;
}
num_bytes = cache->length - cache->reserved -
Expand Down Expand Up @@ -3699,7 +3696,7 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
old_val -= num_bytes;
cache->used = old_val;
cache->pinned += num_bytes;
btrfs_space_info_update_bytes_pinned(info, space_info, num_bytes);
btrfs_space_info_update_bytes_pinned(space_info, num_bytes);
space_info->bytes_used -= num_bytes;
space_info->disk_used -= num_bytes * factor;
if (READ_ONCE(space_info->periodic_reclaim))
Expand Down Expand Up @@ -3781,8 +3778,7 @@ int btrfs_add_reserved_bytes(struct btrfs_block_group *cache,
space_info->bytes_reserved += num_bytes;
trace_btrfs_space_reservation(cache->fs_info, "space_info",
space_info->flags, num_bytes, 1);
btrfs_space_info_update_bytes_may_use(cache->fs_info,
space_info, -ram_bytes);
btrfs_space_info_update_bytes_may_use(space_info, -ram_bytes);
if (delalloc)
cache->delalloc_bytes += num_bytes;

Expand Down
10 changes: 3 additions & 7 deletions fs/btrfs/block-rsv.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,7 @@ static u64 block_rsv_release_bytes(struct btrfs_fs_info *fs_info,
spin_unlock(&dest->lock);
}
if (num_bytes)
btrfs_space_info_free_bytes_may_use(fs_info,
space_info,
num_bytes);
btrfs_space_info_free_bytes_may_use(space_info, num_bytes);
}
if (qgroup_to_release_ret)
*qgroup_to_release_ret = qgroup_to_release;
Expand Down Expand Up @@ -383,13 +381,11 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)

if (block_rsv->reserved < block_rsv->size) {
num_bytes = block_rsv->size - block_rsv->reserved;
btrfs_space_info_update_bytes_may_use(fs_info, sinfo,
num_bytes);
btrfs_space_info_update_bytes_may_use(sinfo, num_bytes);
block_rsv->reserved = block_rsv->size;
} else if (block_rsv->reserved > block_rsv->size) {
num_bytes = block_rsv->reserved - block_rsv->size;
btrfs_space_info_update_bytes_may_use(fs_info, sinfo,
-num_bytes);
btrfs_space_info_update_bytes_may_use(sinfo, -num_bytes);
block_rsv->reserved = block_rsv->size;
btrfs_try_granting_tickets(fs_info, sinfo);
}
Expand Down
Loading