for-7.3-rc1-tag

-----BEGIN PGP SIGNATURE-----
 
 iQJPBAABCgA5FiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmqcOFUbFIAAAAAABAAO
 bWFudTIsMi41KzEuMTIsMiwyAAoJEMVl1fnXbVg7DwAP/i5lmUS85n22uWD7wkmU
 5ocMbdl9cKprtcpi8axR9kbtBIC5bq0j3sUwmiFgR6KI774v7FnxJ3AIrey3GwtF
 okiaWLffKOYROCDvmLg36ciSbFGEqjS8lwOPl1geBX7tZhhnGgcV+XRXcMv4ehj8
 HiOtjN8a+8kXrYTMB73JhBkzku7Hojb/vA9ZHXeCLjP4nfzlXneqltSQw/+3uVvf
 jrLfOX3a1lgLkz0Q7AlfAO7ppXv5msrZYu7E1aILYtLA5K6J6Gh1jyK+Y8OZlvdg
 hukhU3mAw2pCV5dg6rAurYWzVhE/tNmKmlg2s1LiW3K1Q2NNSPGvR0ArmAnd9bPY
 6ZwoK47m98xuZgIAO7v+ej9LYI3XANGwdupTmrKhQ7shLYtzvSsob7kWRYfjCMWu
 UaTGshMsrfMXZNznXm2Ydy1Gmr3TBI2J1HpUFiibRL4XgsQ7u9hLUFwiFUiMEi9V
 g9oqTN/1VUMsImADlnrdAf30pLtOe8PHV1naFLdmdl+iCPc9o0cX9X5m2fHWtkpt
 Cjz/au8Z0zMVJMIDUZuBgCX4mWNSx7pWYKQYvlGOLQEehXNLRVcY5SnIqRman8WF
 gnUPaaTb6KDS+SJjRDPkRH9ihGlNEd2c/tzrxek4/42CF842PGeMvGK06PtPyzxW
 LWtmCtBWRArSHUq09NZbboim
 =z6qW
 -----END PGP SIGNATURE-----

Merge tag 'for-7.3-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux

Pull btrfs fixes from David Sterba:

 - preserve inode compression level when changing attributes

 - fix lost wakeup when waiting for a zstd workspace

 - fix bio context leaks after ordered extent processing errors

 - in send, handle unexpected extents for non-regular inodes

 - handle edge case in creation of reloc tree with enabled quotas

 - in scrub report the exact failing offset, not the stripe base

 - error handling fixes
     - error code propagation in send, zoned mode and raid-stripe-tree
     - restore active device pointer after seeding device addition error
     - transaction abort fixups

 - update Chris' email address

* tag 'for-7.3-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  MAINTAINERS: update Chris Mason's email address
  btrfs: tests: do not touch page cache if root/inode allocation failed
  btrfs: zstd: fix lost wakeup when waiting for a workspace
  btrfs: do not force reloc root creation during qgroup_account_snapshot()
  btrfs: send: fix lost error return value in will_overwrite_ref()
  btrfs: abort transaction before releasing tree_log_mutex on commit failure
  btrfs: zoned: propagate do_zone_finish() error in btrfs_zone_finish_endio()
  btrfs: zoned: finish active block group cleanup if call_zone_finish() fails
  btrfs: send: reject extents for non-regular inodes
  btrfs: return proper negative error code for update_raid_extent_item()
  btrfs: fix the possible bioc_list memory leak during error
  btrfs: fix transaction use-after-free in raid stripe insertion
  btrfs: scrub: report the failing sector's address, not the stripe base
  btrfs: preserve the compression property when other inode flags change
  btrfs: restore active device pointers after failed sprout
  btrfs: detach failed sprout device from transaction update list
  btrfs: clean up target device if block group marking fails
This commit is contained in:
Linus Torvalds 2026-09-05 10:18:21 -07:00
commit d9d80a859b
13 changed files with 104 additions and 38 deletions

View File

@ -5671,8 +5671,8 @@ W: http://bu3sch.de/btgpio.php
F: drivers/gpio/gpio-bt8xx.c
BTRFS FILE SYSTEM
M: Chris Mason <clm@fb.com>
M: David Sterba <dsterba@suse.com>
R: Chris Mason <mason@kernel.org>
L: linux-btrfs@vger.kernel.org
S: Maintained
W: https://btrfs.readthedocs.io

View File

@ -636,7 +636,7 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
ret = mark_block_group_to_copy(fs_info, src_device);
if (ret)
return ret;
goto leave;
down_write(&dev_replace->rwsem);
dev_replace->replace_task = current;

View File

@ -3436,6 +3436,9 @@ int btrfs_finish_one_ordered(struct btrfs_ordered_extent *ordered_extent)
*/
btrfs_remove_ordered_extent(ordered_extent);
/* Cleanup any remaining biocs attached to the OE. */
btrfs_cleanup_ordered_bioc_list(ordered_extent);
/* once for us */
btrfs_put_ordered_extent(ordered_extent);
/* once for the tree */

View File

@ -384,6 +384,7 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
inode_flags &= ~BTRFS_INODE_COMPRESS;
inode_flags |= BTRFS_INODE_NOCOMPRESS;
} else if (fsflags & FS_COMPR_FL) {
enum btrfs_compression_type comp_type;
if (IS_SWAPFILE(&inode->vfs_inode))
return -ETXTBSY;
@ -391,9 +392,23 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
inode_flags |= BTRFS_INODE_COMPRESS;
inode_flags &= ~BTRFS_INODE_NOCOMPRESS;
comp = btrfs_compress_type2str(fs_info->compress_type);
if (!comp || comp[0] == 0)
comp = btrfs_compress_type2str(BTRFS_COMPRESS_ZLIB);
/*
* Keep the algorithm recorded in the compression property,
* otherwise changing an unrelated attribute would reset it to
* the mount default, since FS_IOC_SETFLAGS callers write back
* the whole flag set they got from FS_IOC_GETFLAGS and that
* includes FS_COMPR_FL for any inode carrying the property.
*
* Inodes with the compress flag set but no property keep using
* the mount default, so they behave as before.
*/
if (inode->prop_compress)
comp_type = inode->prop_compress;
else if (fs_info->compress_type)
comp_type = fs_info->compress_type;
else
comp_type = BTRFS_COMPRESS_ZLIB;
comp = btrfs_compress_type2str(comp_type);
} else {
inode_flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
}

View File

@ -310,8 +310,10 @@ static int update_raid_extent_item(struct btrfs_trans_handle *trans,
ret = btrfs_search_slot(trans, trans->fs_info->stripe_root, key, path,
0, 1);
if (ret)
return (ret == 1 ? ret : -EINVAL);
if (ret > 0)
ret = -ENOENT;
if (ret < 0)
return ret;
leaf = path->nodes[0];
slot = path->slots[0];
@ -337,7 +339,6 @@ int btrfs_insert_one_raid_extent(struct btrfs_trans_handle *trans,
stripe_extent = kzalloc(item_size, GFP_NOFS);
if (unlikely(!stripe_extent)) {
btrfs_abort_transaction(trans, -ENOMEM);
btrfs_end_transaction(trans);
return -ENOMEM;
}
@ -374,7 +375,7 @@ int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
struct btrfs_ordered_extent *ordered_extent)
{
struct btrfs_io_context *bioc;
int ret;
int ret = 0;
if (!btrfs_fs_incompat(trans->fs_info, RAID_STRIPE_TREE))
return 0;
@ -382,17 +383,23 @@ int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
list_for_each_entry(bioc, &ordered_extent->bioc_list, rst_ordered_entry) {
ret = btrfs_insert_one_raid_extent(trans, bioc);
if (ret)
return ret;
break;
}
while (!list_empty(&ordered_extent->bioc_list)) {
bioc = list_first_entry(&ordered_extent->bioc_list,
btrfs_cleanup_ordered_bioc_list(ordered_extent);
return ret;
}
void btrfs_cleanup_ordered_bioc_list(struct btrfs_ordered_extent *ordered)
{
while (!list_empty(&ordered->bioc_list)) {
struct btrfs_io_context *bioc;
bioc = list_first_entry(&ordered->bioc_list,
typeof(*bioc), rst_ordered_entry);
list_del(&bioc->rst_ordered_entry);
btrfs_put_bioc(bioc);
}
return 0;
}
int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,

View File

@ -28,6 +28,7 @@ int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
u32 stripe_index, struct btrfs_io_stripe *stripe);
int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
struct btrfs_ordered_extent *ordered_extent);
void btrfs_cleanup_ordered_bioc_list(struct btrfs_ordered_extent *ordered);
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
int btrfs_insert_one_raid_extent(struct btrfs_trans_handle *trans,

View File

@ -1023,6 +1023,10 @@ static void scrub_stripe_report_errors(struct scrub_ctx *sctx,
skip:
for_each_set_bit(sector_nr, &extent_bitmap, stripe->nr_sectors) {
const u64 sector_logical = stripe->logical +
((u64)sector_nr << fs_info->sectorsize_bits);
const u64 sector_physical = physical +
((u64)sector_nr << fs_info->sectorsize_bits);
bool repaired = false;
if (scrub_bitmap_test_bit_is_metadata(stripe, sector_nr)) {
@ -1051,12 +1055,12 @@ static void scrub_stripe_report_errors(struct scrub_ctx *sctx,
if (dev) {
btrfs_err_rl(fs_info,
"scrub: fixed up error at logical %llu on dev %s physical %llu",
stripe->logical, btrfs_dev_name(dev),
physical);
sector_logical, btrfs_dev_name(dev),
sector_physical);
} else {
btrfs_err_rl(fs_info,
"scrub: fixed up error at logical %llu on mirror %u",
stripe->logical, stripe->mirror_num);
sector_logical, stripe->mirror_num);
}
continue;
}
@ -1065,30 +1069,30 @@ static void scrub_stripe_report_errors(struct scrub_ctx *sctx,
if (dev) {
btrfs_err_rl(fs_info,
"scrub: unable to fixup (regular) error at logical %llu on dev %s physical %llu",
stripe->logical, btrfs_dev_name(dev),
physical);
sector_logical, btrfs_dev_name(dev),
sector_physical);
} else {
btrfs_err_rl(fs_info,
"scrub: unable to fixup (regular) error at logical %llu on mirror %u",
stripe->logical, stripe->mirror_num);
sector_logical, stripe->mirror_num);
}
if (scrub_bitmap_test_bit_io_error(stripe, sector_nr))
if (__ratelimit(&rs) && dev)
scrub_print_common_warning("i/o error", dev, false,
stripe->logical, physical);
sector_logical, sector_physical);
if (scrub_bitmap_test_bit_csum_error(stripe, sector_nr))
if (__ratelimit(&rs) && dev)
scrub_print_common_warning("checksum error", dev, false,
stripe->logical, physical);
sector_logical, sector_physical);
if (scrub_bitmap_test_bit_meta_error(stripe, sector_nr))
if (__ratelimit(&rs) && dev)
scrub_print_common_warning("header error", dev, false,
stripe->logical, physical);
sector_logical, sector_physical);
if (scrub_bitmap_test_bit_meta_gen_error(stripe, sector_nr))
if (__ratelimit(&rs) && dev)
scrub_print_common_warning("generation error", dev, false,
stripe->logical, physical);
sector_logical, sector_physical);
}
/* Update the device stats. */

View File

@ -2065,7 +2065,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
ret = is_inode_existent(sctx, dir, dir_gen, NULL, &parent_root_dir_gen);
if (ret <= 0)
return 0;
return ret;
/*
* If we have a parent root we need to verify that the parent dir was
@ -6417,6 +6417,13 @@ static int process_extent(struct send_ctx *sctx,
if (S_ISLNK(sctx->cur_inode_mode))
return 0;
if (unlikely(!S_ISREG(sctx->cur_inode_mode))) {
btrfs_crit(sctx->send_root->fs_info,
"send: extent for non-regular inode %llu root %llu mode 0%llo",
key->objectid, btrfs_root_id(sctx->send_root),
sctx->cur_inode_mode & S_IFMT);
return -EUCLEAN;
}
if (sctx->parent_root && !sctx->cur_inode_new) {
ret = is_extent_unchanged(sctx, path, key);

View File

@ -133,14 +133,14 @@ static int test_find_delalloc(u32 sectorsize, u32 nodesize)
if (IS_ERR(root)) {
test_std_err(TEST_ALLOC_ROOT);
ret = PTR_ERR(root);
goto out;
goto out_root_info;
}
inode = btrfs_new_test_inode();
if (!inode) {
test_std_err(TEST_ALLOC_INODE);
ret = -ENOMEM;
goto out;
goto out_root_info;
}
tmp = &BTRFS_I(inode)->io_tree;
BTRFS_I(inode)->root = root;
@ -333,6 +333,7 @@ static int test_find_delalloc(u32 sectorsize, u32 nodesize)
process_page_range(inode, 0, total_dirty - 1,
PROCESS_UNLOCK | PROCESS_RELEASE);
iput(inode);
out_root_info:
btrfs_free_dummy_root(root);
btrfs_free_dummy_fs_info(fs_info);
return ret;

View File

@ -458,8 +458,19 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans,
* through btrfs_record_root_in_trans without having to take the
* lock. smp_wmb() makes sure that all the writes above are
* done before we pop in the zero below
*
* If @force is true, it means the call is from
* qgroup_account_snapshot(), which only requires radix tree
* tracking.
* We should not force reloc root creation here, as the root
* may have already been modified, and in that case
* root->commit_root has already been dropped.
*
* Using that commit root will cause the reloc root to refer
* to a deleted extent, causing extent tree corruption.
*/
ret = btrfs_init_reloc_root(trans, root);
if (!force)
ret = btrfs_init_reloc_root(trans, root);
smp_mb__before_atomic();
clear_bit(BTRFS_ROOT_IN_TRANS_SETUP, &root->state);
}
@ -2583,6 +2594,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
ret = btrfs_write_and_wait_transaction(trans);
if (unlikely(ret)) {
btrfs_err(fs_info, "error while writing out transaction: %pe", ERR_PTR(ret));
/*
* Abort before releasing tree_log_mutex, so a log sync waiting
* on it sees the fs error and skips writing super_for_commit
* for this failed transaction. See btrfs_sync_log().
*/
btrfs_abort_transaction(trans, ret);
mutex_unlock(&fs_info->tree_log_mutex);
goto scrub_continue;
}

View File

@ -3117,7 +3117,11 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
error_sysfs:
btrfs_sysfs_remove_device(device);
mutex_lock(&fs_info->fs_devices->device_list_mutex);
if (seeding_dev)
btrfs_assign_next_active_device(device, seed_devices->latest_dev);
mutex_lock(&fs_info->chunk_mutex);
if (!list_empty(&device->post_commit_list))
list_del_init(&device->post_commit_list);
list_del_rcu(&device->dev_list);
list_del(&device->dev_alloc_list);
fs_info->fs_devices->num_devices--;

View File

@ -2626,16 +2626,13 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
down_read(&dev_replace->rwsem);
map = block_group->physical_map;
for (i = 0; i < map->num_stripes; i++) {
ret = call_zone_finish(block_group, &map->stripes[i]);
if (ret) {
up_read(&dev_replace->rwsem);
return ret;
}
if (ret)
break;
}
up_read(&dev_replace->rwsem);
if (!fully_written)
if (!ret && !fully_written)
btrfs_dec_block_group_ro(block_group);
spin_lock(&fs_info->zone_active_bgs_lock);
@ -2648,7 +2645,7 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
clear_and_wake_up_bit(BTRFS_FS_NEED_ZONE_FINISH, &fs_info->flags);
return 0;
return ret;
}
int btrfs_zone_finish(struct btrfs_block_group *block_group)
@ -2713,6 +2710,7 @@ int btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 leng
{
struct btrfs_block_group *block_group;
u64 min_alloc_bytes;
int ret = 0;
if (!btrfs_is_zoned(fs_info))
return 0;
@ -2732,11 +2730,11 @@ int btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 leng
block_group->start + block_group->zone_capacity)
goto out;
do_zone_finish(block_group, true);
ret = do_zone_finish(block_group, true);
out:
btrfs_put_block_group(block_group);
return 0;
return ret;
}
static void btrfs_zone_finish_endio_workfn(struct work_struct *work)

View File

@ -307,8 +307,17 @@ struct list_head *zstd_get_workspace(struct btrfs_fs_info *fs_info, int level)
DEFINE_WAIT(wait);
prepare_to_wait(&zwsm->wait, &wait, TASK_UNINTERRUPTIBLE);
schedule();
/*
* Re-check after being queued: zstd_put_workspace() only wakes
* a queue that already has a sleeper, so a workspace returned
* since the failed allocation woke nobody.
*/
ws = zstd_find_workspace(fs_info, level);
if (!ws)
schedule();
finish_wait(&zwsm->wait, &wait);
if (ws)
return ws;
goto again;
}