for-7.0-rc3-tag
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmmytygACgkQxWXV+ddt
WDuiKw/+IyoS2IE95Jd4G2hezcsaqJNAvv5q90vVyLepT/7jzRbYrHytk7z/0v56
+Pjc1JHgp+TidYKZa52E/R09eEvYCyuZvEq4bnClOnO3CAJDCixqTKWV70CcYiHX
HoSCuPML2CJMLZY3u6MxATgk46y1ey3UkbmQ4oufoUHrjAE+D3pDQsYQ9BWR/P6J
4LbyZ214uIUPvbp0wPJ14cVUMpNxs116JmWvK9dxWQNZSzFcq2IVuLwQUcZBPAdb
dursd0kt6HXXmNCITmUD8O+ipG4U1akn8FuCjaLqo4LF1AH2f6OzNjucsisfa1tE
4MD+ATzmNsew5q6dtyfcvv8Btl+olbTP4KGibLl9PCCM9vlkzl3EN5GPUllGi6S9
T8jqe2pILXZHEx1DIQjHaXJsnuHG9aEkUbkSHUxIa15QDj66omrZZkZG3EF5Buy9
TogJJgESYU19dt/y110Q/vD/LPOgJhB3NBXwIx1FDYA1OwaAjt6hUcVRVRI5PtpL
moAIG4nNrPz5Pa875NvguFmrXFIudpTqyANHCPVio4eqDR7LeSg9vVHj9zeOfeRD
gmn3WGuGNb6L+86TNet/nFQhjxhkKqsnSbzO2zoPQKhG6FS+HSLnUwvJYL4/YnkW
QEeveeI/6Duiei4DHuw7FXmZVNQxeBEWW6MTFDHA1UNV3HMKewA=
=TgSD
-----END PGP SIGNATURE-----
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
This commit is contained in:
commit
e0b38d286e
|
|
@ -3594,7 +3594,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
|
|||
}
|
||||
}
|
||||
|
||||
btrfs_zoned_reserve_data_reloc_bg(fs_info);
|
||||
btrfs_free_zone_cache(fs_info);
|
||||
|
||||
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
|
|||
goto fail_cleaner;
|
||||
}
|
||||
|
||||
/*
|
||||
* Starts a transaction, must be called after the transaction kthread
|
||||
* is initialized.
|
||||
*/
|
||||
btrfs_zoned_reserve_data_reloc_bg(fs_info);
|
||||
|
||||
ret = btrfs_read_qgroup_config(fs_info);
|
||||
if (ret)
|
||||
goto fail_trans_kthread;
|
||||
|
|
|
|||
|
|
@ -4507,6 +4507,7 @@ static int try_release_subpage_extent_buffer(struct folio *folio)
|
|||
*/
|
||||
if (!test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) {
|
||||
spin_unlock(&eb->refs_lock);
|
||||
rcu_read_lock();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6612,6 +6612,25 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
|
|||
int ret;
|
||||
bool xa_reserved = false;
|
||||
|
||||
if (!args->orphan && !args->subvol) {
|
||||
/*
|
||||
* Before anything else, check if we can add the name to the
|
||||
* parent directory. We want to avoid a dir item overflow in
|
||||
* case we have an existing dir item due to existing name
|
||||
* hash collisions. We do this check here before we call
|
||||
* btrfs_add_link() down below so that we can avoid a
|
||||
* transaction abort (which could be exploited by malicious
|
||||
* users).
|
||||
*
|
||||
* For subvolumes we already do this in btrfs_mksubvol().
|
||||
*/
|
||||
ret = btrfs_check_dir_item_collision(BTRFS_I(dir)->root,
|
||||
btrfs_ino(BTRFS_I(dir)),
|
||||
name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -672,6 +672,13 @@ static noinline int create_subvol(struct mnt_idmap *idmap,
|
|||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Subvolumes have orphans cleaned on first dentry lookup. A new
|
||||
* subvolume cannot have any orphans, so we should set the bit before we
|
||||
* add the subvolume dentry to the dentry cache, so that it is in the
|
||||
* same state as a subvolume after first lookup.
|
||||
*/
|
||||
set_bit(BTRFS_ROOT_ORPHAN_CLEANUP, &new_root->state);
|
||||
d_instantiate_new(dentry, new_inode_args.inode);
|
||||
new_inode_args.inode = NULL;
|
||||
|
||||
|
|
@ -3852,6 +3859,25 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
|
|||
goto out;
|
||||
}
|
||||
|
||||
received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid,
|
||||
BTRFS_UUID_SIZE);
|
||||
|
||||
/*
|
||||
* Before we attempt to add the new received uuid, check if we have room
|
||||
* for it in case there's already an item. If the size of the existing
|
||||
* item plus this root's ID (u64) exceeds the maximum item size, we can
|
||||
* return here without the need to abort a transaction. If we don't do
|
||||
* this check, the btrfs_uuid_tree_add() call below would fail with
|
||||
* -EOVERFLOW and result in a transaction abort. Malicious users could
|
||||
* exploit this to turn the fs into RO mode.
|
||||
*/
|
||||
if (received_uuid_changed && !btrfs_is_empty_uuid(sa->uuid)) {
|
||||
ret = btrfs_uuid_tree_check_overflow(fs_info, sa->uuid,
|
||||
BTRFS_UUID_KEY_RECEIVED_SUBVOL);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1 - root item
|
||||
* 2 - uuid items (received uuid + subvol uuid)
|
||||
|
|
@ -3867,15 +3893,12 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
|
|||
sa->rtime.sec = ct.tv_sec;
|
||||
sa->rtime.nsec = ct.tv_nsec;
|
||||
|
||||
received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid,
|
||||
BTRFS_UUID_SIZE);
|
||||
if (received_uuid_changed &&
|
||||
!btrfs_is_empty_uuid(root_item->received_uuid)) {
|
||||
ret = btrfs_uuid_tree_remove(trans, root_item->received_uuid,
|
||||
BTRFS_UUID_KEY_RECEIVED_SUBVOL,
|
||||
btrfs_root_id(root));
|
||||
if (unlikely(ret && ret != -ENOENT)) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
btrfs_end_transaction(trans);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -3890,7 +3913,8 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
|
|||
|
||||
ret = btrfs_update_root(trans, fs_info->tree_root,
|
||||
&root->root_key, &root->root_item);
|
||||
if (ret < 0) {
|
||||
if (unlikely(ret < 0)) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
btrfs_end_transaction(trans);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ void _btrfs_printk(const struct btrfs_fs_info *fs_info, unsigned int level, cons
|
|||
|
||||
#else
|
||||
|
||||
#define btrfs_printk_in_rcu(fs_info, level, fmt, args...) \
|
||||
btrfs_no_printk(fs_info, fmt, ##args)
|
||||
|
||||
#define btrfs_printk_in_rcu(fs_info, level, fmt, args...) \
|
||||
btrfs_no_printk(fs_info, fmt, ##args)
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ static const struct root_name_map root_map[] = {
|
|||
{ BTRFS_BLOCK_GROUP_TREE_OBJECTID, "BLOCK_GROUP_TREE" },
|
||||
{ BTRFS_DATA_RELOC_TREE_OBJECTID, "DATA_RELOC_TREE" },
|
||||
{ BTRFS_RAID_STRIPE_TREE_OBJECTID, "RAID_STRIPE_TREE" },
|
||||
{ BTRFS_REMAP_TREE_OBJECTID, "REMAP_TREE" },
|
||||
};
|
||||
|
||||
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
|
|||
[BTRFS_UUID_KEY_SUBVOL] = "UUID_KEY_SUBVOL",
|
||||
[BTRFS_UUID_KEY_RECEIVED_SUBVOL] = "UUID_KEY_RECEIVED_SUBVOL",
|
||||
[BTRFS_RAID_STRIPE_KEY] = "RAID_STRIPE",
|
||||
[BTRFS_IDENTITY_REMAP_KEY] = "IDENTITY_REMAP",
|
||||
[BTRFS_REMAP_KEY] = "REMAP",
|
||||
[BTRFS_REMAP_BACKREF_KEY] = "REMAP_BACKREF",
|
||||
};
|
||||
|
||||
if (key->type == 0 && key->objectid == BTRFS_FREE_SPACE_OBJECTID)
|
||||
|
|
@ -435,6 +439,7 @@ void btrfs_print_leaf(const struct extent_buffer *l)
|
|||
struct btrfs_extent_data_ref *dref;
|
||||
struct btrfs_shared_data_ref *sref;
|
||||
struct btrfs_dev_extent *dev_extent;
|
||||
struct btrfs_remap_item *remap;
|
||||
struct btrfs_key key;
|
||||
|
||||
if (!l)
|
||||
|
|
@ -569,6 +574,11 @@ void btrfs_print_leaf(const struct extent_buffer *l)
|
|||
print_raid_stripe_key(l, btrfs_item_size(l, i),
|
||||
btrfs_item_ptr(l, i, struct btrfs_stripe_extent));
|
||||
break;
|
||||
case BTRFS_REMAP_KEY:
|
||||
case BTRFS_REMAP_BACKREF_KEY:
|
||||
remap = btrfs_item_ptr(l, i, struct btrfs_remap_item);
|
||||
pr_info("\t\taddress %llu\n", btrfs_remap_address(l, remap));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4399,6 +4399,8 @@ static int move_existing_remaps(struct btrfs_fs_info *fs_info,
|
|||
|
||||
leaf = path->nodes[0];
|
||||
}
|
||||
|
||||
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
|
||||
}
|
||||
|
||||
remap = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_remap_item);
|
||||
|
|
|
|||
|
|
@ -2194,8 +2194,11 @@ void btrfs_reclaim_sweep(const struct btrfs_fs_info *fs_info)
|
|||
if (!btrfs_should_periodic_reclaim(space_info))
|
||||
continue;
|
||||
for (raid = 0; raid < BTRFS_NR_RAID_TYPES; raid++) {
|
||||
if (do_reclaim_sweep(space_info, raid))
|
||||
if (do_reclaim_sweep(space_info, raid)) {
|
||||
spin_lock(&space_info->lock);
|
||||
btrfs_set_periodic_reclaim_ready(space_info, false);
|
||||
spin_unlock(&space_info->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1905,6 +1905,22 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
|||
ret = btrfs_uuid_tree_add(trans, new_root_item->received_uuid,
|
||||
BTRFS_UUID_KEY_RECEIVED_SUBVOL,
|
||||
objectid);
|
||||
/*
|
||||
* We are creating of lot of snapshots of the same root that was
|
||||
* received (has a received UUID) and reached a leaf's limit for
|
||||
* an item. We can safely ignore this and avoid a transaction
|
||||
* abort. A deletion of this snapshot will still work since we
|
||||
* ignore if an item with a BTRFS_UUID_KEY_RECEIVED_SUBVOL key
|
||||
* is missing (see btrfs_delete_subvolume()). Send/receive will
|
||||
* work too since it peeks the first root id from the existing
|
||||
* item (it could peek any), and in case it's missing it
|
||||
* falls back to search by BTRFS_UUID_KEY_SUBVOL keys.
|
||||
* Creation of a snapshot does not require CAP_SYS_ADMIN, so
|
||||
* we don't want users triggering transaction aborts, either
|
||||
* intentionally or not.
|
||||
*/
|
||||
if (ret == -EOVERFLOW)
|
||||
ret = 0;
|
||||
if (unlikely(ret && ret != -EEXIST)) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto fail;
|
||||
|
|
|
|||
|
|
@ -199,6 +199,44 @@ int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, const u8 *uuid, u8
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we can add one root ID to a UUID key.
|
||||
* If the key does not yet exists, we can, otherwise only if extended item does
|
||||
* not exceeds the maximum item size permitted by the leaf size.
|
||||
*
|
||||
* Returns 0 on success, negative value on error.
|
||||
*/
|
||||
int btrfs_uuid_tree_check_overflow(struct btrfs_fs_info *fs_info,
|
||||
const u8 *uuid, u8 type)
|
||||
{
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
int ret;
|
||||
u32 item_size;
|
||||
struct btrfs_key key;
|
||||
|
||||
if (WARN_ON_ONCE(!fs_info->uuid_root))
|
||||
return -EINVAL;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
btrfs_uuid_to_key(uuid, type, &key);
|
||||
ret = btrfs_search_slot(NULL, fs_info->uuid_root, &key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
return 0;
|
||||
|
||||
item_size = btrfs_item_size(path->nodes[0], path->slots[0]);
|
||||
|
||||
if (sizeof(struct btrfs_item) + item_size + sizeof(u64) >
|
||||
BTRFS_LEAF_DATA_SIZE(fs_info))
|
||||
return -EOVERFLOW;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btrfs_uuid_iter_rem(struct btrfs_root *uuid_root, u8 *uuid, u8 type,
|
||||
u64 subid)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, const u8 *uuid, u8 typ
|
|||
u64 subid);
|
||||
int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, const u8 *uuid, u8 type,
|
||||
u64 subid);
|
||||
int btrfs_uuid_tree_check_overflow(struct btrfs_fs_info *fs_info,
|
||||
const u8 *uuid, u8 type);
|
||||
int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_uuid_scan_kthread(void *data);
|
||||
|
|
|
|||
Loading…
Reference in New Issue