for-7.1-rc1-tag

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmnvdO8ACgkQxWXV+ddt
 WDuLqA//fcHDOnClWHRRUaIWhhkMYm7gNZkXf2d+qyYLMtAP2Cv2sZ+aV+OkHp5D
 /Gq1W1mUXZLabu0EV0xKICn01nwzWtbZwDO8Bo3+QEdLoAi2gITODsYyY8yeW9KO
 GfSBPsom+d7ktVrjaYE7Ppcm6YifBjWNDDcC+MX7Kpy+OUqhyOtsJIaEeTwii9+P
 eiyAAC1zqrHZtaQfLsY3WvM0baNaqlm1xURMjJPyRCAtjGpjZy1hK/iFsGcHRlfc
 SR//WT/MRnUAFn8zlIBG0wNrk1IEIgPPiA7hAXMRGXFKo0C6ICYLl5MJQh/o/MUs
 tFBdkBhtcX/Kynvwb059SyalXZzVhQvzaRN89ZGuDyalNiejRzb8F2oVCfKAVKIU
 MdkKOjnR5b7BUzCcZ1cJf1LgX4SngYKTnXrNGHpW0fuUzX6moJEd4wbrgmHjk9ke
 +TVdl2vcpAduvBU9idkpDAcUW998tcYmX/LyQhGYpR6k/4n2UdFZJPINqco3pOAO
 RIFbIgEAq9rUi+GMSJdEDMO6xLmUYoI6vaw7uZSU6E04zJPiVIcixfRDCBKGPV5Q
 Yl9PC3ViLSlgKWaG7UVl8PVaSkCQ7esbfPAnNI/+RBCUeehhSFygePcY+kH1k4LA
 0qMne1abDysUVwolb/1de/fqkznLlB3SlA447HwdvwMI0mCSb7w=
 =ajKs
 -----END PGP SIGNATURE-----

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

Pull btrfs fixes from David Sterba:

 - space reservation fixes:
     - correctly undo 'may_use' accounting for remap tree
     - avoid double decrement of 'may_use' when submitting async io

 - actually enable the shutdown ioctl callback (not just the superblock
   ops)

 - raid stripe tree fixes when deleting extents
     - add missing error handling
     - fix various incorrect values set

 - fix transaction state when removing a directory, possibly leading to
   EIO during log replay

 - additional b-tree node key checks during metadata readahead

 - error handling and transaction abort updates

* tag 'for-7.1-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: fix double-decrement of bytes_may_use in submit_one_async_extent()
  btrfs: check return value of btrfs_partially_delete_raid_extent()
  btrfs: handle -EAGAIN from btrfs_duplicate_item and refresh stale leaf pointer
  btrfs: replace ASSERT with proper error handling in stripe lookup fallback
  btrfs: fix wrong min_objectid in btrfs_previous_item() call
  btrfs: fix raid stripe search missing entries at leaf boundaries
  btrfs: copy devid in btrfs_partially_delete_raid_extent()
  btrfs: handle unexpected free-space-tree key types
  btrfs: fix missing last_unlink_trans update when removing a directory
  btrfs: don't clobber errors in add_remap_tree_entries()
  btrfs: enable shutdown ioctl for non-experimental builds
  btrfs: apply first key check for readahead when possible
  btrfs: abort transaction in do_remap_reloc_trans() on failure
  btrfs: fix bytes_may_use leak in do_remap_reloc_trans()
  btrfs: fix bytes_may_use leak in move_existing_remap()
This commit is contained in:
Linus Torvalds 2026-04-27 16:35:44 -07:00
commit 73082fbdb1
7 changed files with 104 additions and 29 deletions

View File

@ -4641,7 +4641,8 @@ int try_release_extent_buffer(struct folio *folio)
* to read the block we will not block on anything.
*/
void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
u64 bytenr, u64 owner_root, u64 gen, int level)
u64 bytenr, u64 owner_root, u64 gen, int level,
const struct btrfs_key *first_key)
{
struct btrfs_tree_parent_check check = {
.level = level,
@ -4650,6 +4651,11 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
struct extent_buffer *eb;
int ret;
if (first_key) {
memcpy(&check.first_key, first_key, sizeof(struct btrfs_key));
check.has_first_key = true;
}
eb = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level);
if (IS_ERR(eb))
return;
@ -4677,9 +4683,13 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
*/
void btrfs_readahead_node_child(struct extent_buffer *node, int slot)
{
struct btrfs_key node_key;
btrfs_node_key_to_cpu(node, &node_key, slot);
btrfs_readahead_tree_block(node->fs_info,
btrfs_node_blockptr(node, slot),
btrfs_header_owner(node),
btrfs_node_ptr_generation(node, slot),
btrfs_header_level(node) - 1);
btrfs_header_level(node) - 1,
&node_key);
}

View File

@ -287,7 +287,8 @@ static inline void wait_on_extent_buffer_writeback(struct extent_buffer *eb)
}
void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
u64 bytenr, u64 owner_root, u64 gen, int level);
u64 bytenr, u64 owner_root, u64 gen, int level,
const struct btrfs_key *first_key);
void btrfs_readahead_node_child(struct extent_buffer *node, int slot);
/* Note: this can be used in for loops without caching the value in a variable. */

View File

@ -259,7 +259,11 @@ int btrfs_convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
nr++;
path->slots[0]--;
} else {
ASSERT(0);
btrfs_err(fs_info, "unexpected free space tree key type %u",
found_key.type);
ret = -EUCLEAN;
btrfs_abort_transaction(trans, ret);
goto out;
}
}
@ -405,7 +409,11 @@ int btrfs_convert_free_space_to_extents(struct btrfs_trans_handle *trans,
nr++;
} else {
ASSERT(0);
btrfs_err(fs_info, "unexpected free space tree key type %u",
found_key.type);
ret = -EUCLEAN;
btrfs_abort_transaction(trans, ret);
goto out;
}
}
@ -1518,7 +1526,11 @@ int btrfs_remove_block_group_free_space(struct btrfs_trans_handle *trans,
nr++;
path->slots[0]--;
} else {
ASSERT(0);
btrfs_err(trans->fs_info, "unexpected free space tree key type %u",
found_key.type);
ret = -EUCLEAN;
btrfs_abort_transaction(trans, ret);
return ret;
}
}

View File

@ -1153,7 +1153,7 @@ static void submit_one_async_extent(struct async_chunk *async_chunk,
NULL, &cached,
EXTENT_LOCKED | EXTENT_DELALLOC |
EXTENT_DELALLOC_NEW |
EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING,
EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV,
PAGE_UNLOCK | PAGE_START_WRITEBACK |
PAGE_END_WRITEBACK);
if (async_extent->cb)
@ -4959,6 +4959,8 @@ static int btrfs_rmdir(struct inode *vfs_dir, struct dentry *dentry)
if (ret)
goto out;
btrfs_record_unlink_dir(trans, dir, inode, false);
/* now the directory is empty */
ret = btrfs_unlink_inode(trans, dir, inode, &fname.disk_name);
if (!ret)

View File

@ -5102,7 +5102,6 @@ static int btrfs_ioctl_subvol_sync(struct btrfs_fs_info *fs_info, void __user *a
return 0;
}
#ifdef CONFIG_BTRFS_EXPERIMENTAL
static int btrfs_ioctl_shutdown(struct btrfs_fs_info *fs_info, unsigned long arg)
{
int ret = 0;
@ -5134,10 +5133,12 @@ static int btrfs_ioctl_shutdown(struct btrfs_fs_info *fs_info, unsigned long arg
case BTRFS_SHUTDOWN_FLAGS_NOLOGFLUSH:
btrfs_force_shutdown(fs_info);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
#endif
long btrfs_ioctl(struct file *file, unsigned int
cmd, unsigned long arg)
@ -5294,10 +5295,8 @@ long btrfs_ioctl(struct file *file, unsigned int
#endif
case BTRFS_IOC_SUBVOL_SYNC_WAIT:
return btrfs_ioctl_subvol_sync(fs_info, argp);
#ifdef CONFIG_BTRFS_EXPERIMENTAL
case BTRFS_IOC_SHUTDOWN:
return btrfs_ioctl_shutdown(fs_info, arg);
#endif
}
return -ENOTTY;

View File

@ -45,8 +45,11 @@ static int btrfs_partially_delete_raid_extent(struct btrfs_trans_handle *trans,
for (int i = 0; i < btrfs_num_raid_stripes(item_size); i++) {
struct btrfs_raid_stride *stride = &extent->strides[i];
u64 devid;
u64 phys;
devid = btrfs_raid_stride_devid(leaf, stride);
btrfs_set_stack_raid_stride_devid(&newitem->strides[i], devid);
phys = btrfs_raid_stride_physical(leaf, stride) + frontpad;
btrfs_set_stack_raid_stride_physical(&newitem->strides[i], phys);
}
@ -95,14 +98,26 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
while (1) {
key.objectid = start;
key.type = BTRFS_RAID_STRIPE_KEY;
key.offset = 0;
key.offset = (u64)-1;
ret = btrfs_search_slot(trans, stripe_root, &key, path, -1, 1);
if (ret < 0)
break;
if (path->slots[0] == btrfs_header_nritems(path->nodes[0]))
path->slots[0]--;
/*
* Search with offset=(u64)-1 ensures we land on the correct
* leaf even when the target entry is the first item on a leaf.
* Since no real entry has offset=(u64)-1, ret is always 1 and
* slot points past the last entry with objectid==start (or
* past the end of the leaf if that entry is the last item).
* Back up one slot to find the actual entry.
*/
if (path->slots[0] == 0) {
/* No entry with objectid <= start exists. */
ret = 0;
break;
}
path->slots[0]--;
leaf = path->nodes[0];
slot = path->slots[0];
@ -123,7 +138,7 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
*/
if (found_start > start) {
if (slot == 0) {
ret = btrfs_previous_item(stripe_root, path, start,
ret = btrfs_previous_item(stripe_root, path, 0,
BTRFS_RAID_STRIPE_KEY);
if (ret) {
if (ret > 0)
@ -139,7 +154,10 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
btrfs_item_key_to_cpu(leaf, &key, slot);
found_start = key.objectid;
found_end = found_start + key.offset;
ASSERT(found_start <= start);
if (found_start > start || found_end <= start) {
ret = -ENOENT;
break;
}
}
if (key.type != BTRFS_RAID_STRIPE_KEY)
@ -176,9 +194,19 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
/* The "right" item. */
ret = btrfs_duplicate_item(trans, stripe_root, path, &newkey);
if (ret == -EAGAIN) {
btrfs_release_path(path);
continue;
}
if (ret)
break;
/*
* btrfs_duplicate_item() may have triggered a leaf
* split via setup_leaf_for_split(), so we must refresh
* our leaf pointer from the path.
*/
leaf = path->nodes[0];
item_size = btrfs_item_size(leaf, path->slots[0]);
extent = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_stripe_extent);
@ -195,8 +223,9 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
/* The "left" item. */
path->slots[0]--;
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
btrfs_partially_delete_raid_extent(trans, path, &key,
diff_start, 0);
ret = btrfs_partially_delete_raid_extent(trans, path,
&key,
diff_start, 0);
break;
}
@ -212,8 +241,11 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
if (found_start < start) {
u64 diff_start = start - found_start;
btrfs_partially_delete_raid_extent(trans, path, &key,
diff_start, 0);
ret = btrfs_partially_delete_raid_extent(trans, path,
&key,
diff_start, 0);
if (ret)
break;
start += (key.offset - diff_start);
length -= (key.offset - diff_start);
@ -236,9 +268,10 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
if (found_end > end) {
u64 diff_end = found_end - end;
btrfs_partially_delete_raid_extent(trans, path, &key,
key.offset - length,
length);
ret = btrfs_partially_delete_raid_extent(trans, path,
&key,
key.offset - length,
length);
ASSERT(key.offset - diff_end == length);
break;
}

View File

@ -2607,7 +2607,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,
if (!block->key_ready)
btrfs_readahead_tree_block(fs_info, block->bytenr,
block->owner, 0,
block->level);
block->level, NULL);
}
/* Get first keys */
@ -3876,7 +3876,7 @@ static int add_remap_tree_entries(struct btrfs_trans_handle *trans, struct btrfs
ret = btrfs_insert_empty_items(trans, fs_info->remap_root, path, &batch);
btrfs_release_path(path);
if (num_entries <= max_items)
if (ret || num_entries <= max_items)
break;
num_entries -= max_items;
@ -4174,6 +4174,12 @@ static int move_existing_remap(struct btrfs_fs_info *fs_info,
return ret;
}
if (ins.offset < length) {
spin_lock(&sinfo->lock);
btrfs_space_info_update_bytes_may_use(sinfo, ins.offset - length);
spin_unlock(&sinfo->lock);
}
dest_addr = ins.objectid;
dest_length = ins.offset;
@ -5000,6 +5006,12 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info,
return ret;
}
if (ins.offset < remap_length) {
spin_lock(&sinfo->lock);
btrfs_space_info_update_bytes_may_use(sinfo, ins.offset - remap_length);
spin_unlock(&sinfo->lock);
}
made_reservation = true;
new_addr = ins.objectid;
@ -5023,21 +5035,27 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info,
if (bg_needs_free_space) {
ret = btrfs_add_block_group_free_space(trans, dest_bg);
if (ret)
if (ret) {
btrfs_abort_transaction(trans, ret);
goto fail;
}
}
ret = copy_remapped_data(fs_info, start, new_addr, length);
if (ret)
if (ret) {
btrfs_abort_transaction(trans, ret);
goto fail;
}
ret = btrfs_remove_from_free_space_tree(trans, new_addr, length);
if (ret)
if (ret) {
btrfs_abort_transaction(trans, ret);
goto fail;
}
ret = add_remap_entry(trans, path, src_bg, start, new_addr, length);
if (ret) {
btrfs_add_to_free_space_tree(trans, new_addr, length);
btrfs_abort_transaction(trans, ret);
goto fail;
}