btrfs: sysfs: add force_chunk_alloc trigger to force allocation

Adds write-only trigger to force new chunk allocation for a given block
group type. It is at

  /sys/fs/btrfs/<uuid>/allocation/<type>/force_chunk_alloc

Note: this is now only for debugging and testing and is enabled with the
      CONFIG_BTRFS_DEBUG configuration option. The transaction is
      started from sysfs context and can be problematic in some cases.

Signed-off-by: Stefan Roesch <shr@fb.com>
Reviewed-by: David Sterba <dsterba@suse.com>
[ Changes from the original submission:
  - update changelog
  - drop unnecessary error messages
  - switch value to bool and use kstrtobool
  - move BTRFS_ATTR_W definition
  - add comment for using transaction
]
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Stefan Roesch 2022-02-08 11:31:22 -08:00 committed by David Sterba
parent 19fc516a51
commit 22c55e3bbb

View File

@ -62,6 +62,10 @@ struct raid_kobject {
.store = _store, \
}
#define BTRFS_ATTR_W(_prefix, _name, _store) \
static struct kobj_attribute btrfs_attr_##_prefix##_##_name = \
__INIT_KOBJ_ATTR(_name, 0200, NULL, _store)
#define BTRFS_ATTR_RW(_prefix, _name, _show, _store) \
static struct kobj_attribute btrfs_attr_##_prefix##_##_name = \
__INIT_KOBJ_ATTR(_name, 0644, _show, _store)
@ -771,6 +775,52 @@ static ssize_t btrfs_chunk_size_store(struct kobject *kobj,
return len;
}
#ifdef CONFIG_BTRFS_DEBUG
/*
* Request chunk allocation with current chunk size.
*/
static ssize_t btrfs_force_chunk_alloc_store(struct kobject *kobj,
struct kobj_attribute *a,
const char *buf, size_t len)
{
struct btrfs_space_info *space_info = to_space_info(kobj);
struct btrfs_fs_info *fs_info = to_fs_info(get_btrfs_kobj(kobj));
struct btrfs_trans_handle *trans;
bool val;
int ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (sb_rdonly(fs_info->sb))
return -EROFS;
ret = kstrtobool(buf, &val);
if (ret)
return ret;
if (!val)
return -EINVAL;
/*
* This is unsafe to be called from sysfs context and may cause
* unexpected problems.
*/
trans = btrfs_start_transaction(fs_info->tree_root, 0);
if (IS_ERR(trans))
return PTR_ERR(trans);
ret = btrfs_force_chunk_alloc(trans, space_info->flags);
btrfs_end_transaction(trans);
if (ret == 1)
return len;
return -ENOSPC;
}
BTRFS_ATTR_W(space_info, force_chunk_alloc, btrfs_force_chunk_alloc_store);
#endif
SPACE_INFO_ATTR(flags);
SPACE_INFO_ATTR(total_bytes);
SPACE_INFO_ATTR(bytes_used);
@ -837,6 +887,9 @@ static struct attribute *space_info_attrs[] = {
BTRFS_ATTR_PTR(space_info, disk_total),
BTRFS_ATTR_PTR(space_info, bg_reclaim_threshold),
BTRFS_ATTR_PTR(space_info, chunk_size),
#ifdef CONFIG_BTRFS_DEBUG
BTRFS_ATTR_PTR(space_info, force_chunk_alloc),
#endif
NULL,
};
ATTRIBUTE_GROUPS(space_info);