Skip to content

Commit e0b38d2

Browse files
committed
Merge tag 'for-7.0-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: - detect possible file name hash collision earlier so it does not lead to transaction abort - handle b-tree leaf overflows when snapshotting a subvolume with set received UUID, leading to transaction abort - in zoned mode, reorder relocation block group initialization after the transaction kthread start - fix orphan cleanup state tracking of subvolume, this could lead to invalid dentries under some conditions - add locking around updates of dynamic reclain state update - in subpage mode, add missing RCU unlock when trying to releae extent buffer - remap tree fixes: - add missing description strings for the newly added remap tree - properly update search key when iterating backrefs * tag 'for-7.0-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: remove duplicated definition of btrfs_printk_in_rcu() btrfs: remove unnecessary transaction abort in the received subvol ioctl btrfs: abort transaction on failure to update root in the received subvol ioctl btrfs: fix transaction abort on set received ioctl due to item overflow btrfs: fix transaction abort when snapshotting received subvolumes btrfs: fix transaction abort on file creation due to name hash collision btrfs: read key again after incrementing slot in move_existing_remaps() btrfs: add missing RCU unlock in error path in try_release_subpage_extent_buffer() btrfs: set BTRFS_ROOT_ORPHAN_CLEANUP during subvol create btrfs: zoned: move btrfs_zoned_reserve_data_reloc_bg() after kthread start btrfs: hold space_info->lock when clearing periodic reclaim ready btrfs: print-tree: add remap tree definitions
2 parents 2c7e63d + 0749cab commit e0b38d2

11 files changed

Lines changed: 126 additions & 9 deletions

File tree

fs/btrfs/disk-io.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3594,7 +3594,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
35943594
}
35953595
}
35963596

3597-
btrfs_zoned_reserve_data_reloc_bg(fs_info);
35983597
btrfs_free_zone_cache(fs_info);
35993598

36003599
btrfs_check_active_zone_reservation(fs_info);
@@ -3622,6 +3621,12 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
36223621
goto fail_cleaner;
36233622
}
36243623

3624+
/*
3625+
* Starts a transaction, must be called after the transaction kthread
3626+
* is initialized.
3627+
*/
3628+
btrfs_zoned_reserve_data_reloc_bg(fs_info);
3629+
36253630
ret = btrfs_read_qgroup_config(fs_info);
36263631
if (ret)
36273632
goto fail_trans_kthread;

fs/btrfs/extent_io.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4507,6 +4507,7 @@ static int try_release_subpage_extent_buffer(struct folio *folio)
45074507
*/
45084508
if (!test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) {
45094509
spin_unlock(&eb->refs_lock);
4510+
rcu_read_lock();
45104511
break;
45114512
}
45124513

fs/btrfs/inode.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6612,6 +6612,25 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
66126612
int ret;
66136613
bool xa_reserved = false;
66146614

6615+
if (!args->orphan && !args->subvol) {
6616+
/*
6617+
* Before anything else, check if we can add the name to the
6618+
* parent directory. We want to avoid a dir item overflow in
6619+
* case we have an existing dir item due to existing name
6620+
* hash collisions. We do this check here before we call
6621+
* btrfs_add_link() down below so that we can avoid a
6622+
* transaction abort (which could be exploited by malicious
6623+
* users).
6624+
*
6625+
* For subvolumes we already do this in btrfs_mksubvol().
6626+
*/
6627+
ret = btrfs_check_dir_item_collision(BTRFS_I(dir)->root,
6628+
btrfs_ino(BTRFS_I(dir)),
6629+
name);
6630+
if (ret < 0)
6631+
return ret;
6632+
}
6633+
66156634
path = btrfs_alloc_path();
66166635
if (!path)
66176636
return -ENOMEM;

fs/btrfs/ioctl.c

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,13 @@ static noinline int create_subvol(struct mnt_idmap *idmap,
672672
goto out;
673673
}
674674

675+
/*
676+
* Subvolumes have orphans cleaned on first dentry lookup. A new
677+
* subvolume cannot have any orphans, so we should set the bit before we
678+
* add the subvolume dentry to the dentry cache, so that it is in the
679+
* same state as a subvolume after first lookup.
680+
*/
681+
set_bit(BTRFS_ROOT_ORPHAN_CLEANUP, &new_root->state);
675682
d_instantiate_new(dentry, new_inode_args.inode);
676683
new_inode_args.inode = NULL;
677684

@@ -3852,6 +3859,25 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
38523859
goto out;
38533860
}
38543861

3862+
received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid,
3863+
BTRFS_UUID_SIZE);
3864+
3865+
/*
3866+
* Before we attempt to add the new received uuid, check if we have room
3867+
* for it in case there's already an item. If the size of the existing
3868+
* item plus this root's ID (u64) exceeds the maximum item size, we can
3869+
* return here without the need to abort a transaction. If we don't do
3870+
* this check, the btrfs_uuid_tree_add() call below would fail with
3871+
* -EOVERFLOW and result in a transaction abort. Malicious users could
3872+
* exploit this to turn the fs into RO mode.
3873+
*/
3874+
if (received_uuid_changed && !btrfs_is_empty_uuid(sa->uuid)) {
3875+
ret = btrfs_uuid_tree_check_overflow(fs_info, sa->uuid,
3876+
BTRFS_UUID_KEY_RECEIVED_SUBVOL);
3877+
if (ret < 0)
3878+
goto out;
3879+
}
3880+
38553881
/*
38563882
* 1 - root item
38573883
* 2 - uuid items (received uuid + subvol uuid)
@@ -3867,15 +3893,12 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
38673893
sa->rtime.sec = ct.tv_sec;
38683894
sa->rtime.nsec = ct.tv_nsec;
38693895

3870-
received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid,
3871-
BTRFS_UUID_SIZE);
38723896
if (received_uuid_changed &&
38733897
!btrfs_is_empty_uuid(root_item->received_uuid)) {
38743898
ret = btrfs_uuid_tree_remove(trans, root_item->received_uuid,
38753899
BTRFS_UUID_KEY_RECEIVED_SUBVOL,
38763900
btrfs_root_id(root));
38773901
if (unlikely(ret && ret != -ENOENT)) {
3878-
btrfs_abort_transaction(trans, ret);
38793902
btrfs_end_transaction(trans);
38803903
goto out;
38813904
}
@@ -3890,7 +3913,8 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
38903913

38913914
ret = btrfs_update_root(trans, fs_info->tree_root,
38923915
&root->root_key, &root->root_item);
3893-
if (ret < 0) {
3916+
if (unlikely(ret < 0)) {
3917+
btrfs_abort_transaction(trans, ret);
38943918
btrfs_end_transaction(trans);
38953919
goto out;
38963920
}

fs/btrfs/messages.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ void _btrfs_printk(const struct btrfs_fs_info *fs_info, unsigned int level, cons
2828

2929
#else
3030

31-
#define btrfs_printk_in_rcu(fs_info, level, fmt, args...) \
32-
btrfs_no_printk(fs_info, fmt, ##args)
33-
3431
#define btrfs_printk_in_rcu(fs_info, level, fmt, args...) \
3532
btrfs_no_printk(fs_info, fmt, ##args)
3633

fs/btrfs/print-tree.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static const struct root_name_map root_map[] = {
3838
{ BTRFS_BLOCK_GROUP_TREE_OBJECTID, "BLOCK_GROUP_TREE" },
3939
{ BTRFS_DATA_RELOC_TREE_OBJECTID, "DATA_RELOC_TREE" },
4040
{ BTRFS_RAID_STRIPE_TREE_OBJECTID, "RAID_STRIPE_TREE" },
41+
{ BTRFS_REMAP_TREE_OBJECTID, "REMAP_TREE" },
4142
};
4243

4344
const char *btrfs_root_name(const struct btrfs_key *key, char *buf)
@@ -415,6 +416,9 @@ static void key_type_string(const struct btrfs_key *key, char *buf, int buf_size
415416
[BTRFS_UUID_KEY_SUBVOL] = "UUID_KEY_SUBVOL",
416417
[BTRFS_UUID_KEY_RECEIVED_SUBVOL] = "UUID_KEY_RECEIVED_SUBVOL",
417418
[BTRFS_RAID_STRIPE_KEY] = "RAID_STRIPE",
419+
[BTRFS_IDENTITY_REMAP_KEY] = "IDENTITY_REMAP",
420+
[BTRFS_REMAP_KEY] = "REMAP",
421+
[BTRFS_REMAP_BACKREF_KEY] = "REMAP_BACKREF",
418422
};
419423

420424
if (key->type == 0 && key->objectid == BTRFS_FREE_SPACE_OBJECTID)
@@ -435,6 +439,7 @@ void btrfs_print_leaf(const struct extent_buffer *l)
435439
struct btrfs_extent_data_ref *dref;
436440
struct btrfs_shared_data_ref *sref;
437441
struct btrfs_dev_extent *dev_extent;
442+
struct btrfs_remap_item *remap;
438443
struct btrfs_key key;
439444

440445
if (!l)
@@ -569,6 +574,11 @@ void btrfs_print_leaf(const struct extent_buffer *l)
569574
print_raid_stripe_key(l, btrfs_item_size(l, i),
570575
btrfs_item_ptr(l, i, struct btrfs_stripe_extent));
571576
break;
577+
case BTRFS_REMAP_KEY:
578+
case BTRFS_REMAP_BACKREF_KEY:
579+
remap = btrfs_item_ptr(l, i, struct btrfs_remap_item);
580+
pr_info("\t\taddress %llu\n", btrfs_remap_address(l, remap));
581+
break;
572582
}
573583
}
574584
}

fs/btrfs/relocation.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4399,6 +4399,8 @@ static int move_existing_remaps(struct btrfs_fs_info *fs_info,
43994399

44004400
leaf = path->nodes[0];
44014401
}
4402+
4403+
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
44024404
}
44034405

44044406
remap = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_remap_item);

fs/btrfs/space-info.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2194,8 +2194,11 @@ void btrfs_reclaim_sweep(const struct btrfs_fs_info *fs_info)
21942194
if (!btrfs_should_periodic_reclaim(space_info))
21952195
continue;
21962196
for (raid = 0; raid < BTRFS_NR_RAID_TYPES; raid++) {
2197-
if (do_reclaim_sweep(space_info, raid))
2197+
if (do_reclaim_sweep(space_info, raid)) {
2198+
spin_lock(&space_info->lock);
21982199
btrfs_set_periodic_reclaim_ready(space_info, false);
2200+
spin_unlock(&space_info->lock);
2201+
}
21992202
}
22002203
}
22012204
}

fs/btrfs/transaction.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,6 +1905,22 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
19051905
ret = btrfs_uuid_tree_add(trans, new_root_item->received_uuid,
19061906
BTRFS_UUID_KEY_RECEIVED_SUBVOL,
19071907
objectid);
1908+
/*
1909+
* We are creating of lot of snapshots of the same root that was
1910+
* received (has a received UUID) and reached a leaf's limit for
1911+
* an item. We can safely ignore this and avoid a transaction
1912+
* abort. A deletion of this snapshot will still work since we
1913+
* ignore if an item with a BTRFS_UUID_KEY_RECEIVED_SUBVOL key
1914+
* is missing (see btrfs_delete_subvolume()). Send/receive will
1915+
* work too since it peeks the first root id from the existing
1916+
* item (it could peek any), and in case it's missing it
1917+
* falls back to search by BTRFS_UUID_KEY_SUBVOL keys.
1918+
* Creation of a snapshot does not require CAP_SYS_ADMIN, so
1919+
* we don't want users triggering transaction aborts, either
1920+
* intentionally or not.
1921+
*/
1922+
if (ret == -EOVERFLOW)
1923+
ret = 0;
19081924
if (unlikely(ret && ret != -EEXIST)) {
19091925
btrfs_abort_transaction(trans, ret);
19101926
goto fail;

fs/btrfs/uuid-tree.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,44 @@ int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, const u8 *uuid, u8
199199
return 0;
200200
}
201201

202+
/*
203+
* Check if we can add one root ID to a UUID key.
204+
* If the key does not yet exists, we can, otherwise only if extended item does
205+
* not exceeds the maximum item size permitted by the leaf size.
206+
*
207+
* Returns 0 on success, negative value on error.
208+
*/
209+
int btrfs_uuid_tree_check_overflow(struct btrfs_fs_info *fs_info,
210+
const u8 *uuid, u8 type)
211+
{
212+
BTRFS_PATH_AUTO_FREE(path);
213+
int ret;
214+
u32 item_size;
215+
struct btrfs_key key;
216+
217+
if (WARN_ON_ONCE(!fs_info->uuid_root))
218+
return -EINVAL;
219+
220+
path = btrfs_alloc_path();
221+
if (!path)
222+
return -ENOMEM;
223+
224+
btrfs_uuid_to_key(uuid, type, &key);
225+
ret = btrfs_search_slot(NULL, fs_info->uuid_root, &key, path, 0, 0);
226+
if (ret < 0)
227+
return ret;
228+
if (ret > 0)
229+
return 0;
230+
231+
item_size = btrfs_item_size(path->nodes[0], path->slots[0]);
232+
233+
if (sizeof(struct btrfs_item) + item_size + sizeof(u64) >
234+
BTRFS_LEAF_DATA_SIZE(fs_info))
235+
return -EOVERFLOW;
236+
237+
return 0;
238+
}
239+
202240
static int btrfs_uuid_iter_rem(struct btrfs_root *uuid_root, u8 *uuid, u8 type,
203241
u64 subid)
204242
{

0 commit comments

Comments
 (0)