btrfs: sysfs: export chunk size in space infos

Add new sysfs knob

  /sys/fs/btrfs/<uuid>/allocation/<type>/chunk_size.

This allows to query the chunk size and also set the chunk size.

Constraints:

- can be changed by root only
- system chunk size can't be set
- maximum chunk size is 10% of the filesystem size
- final value is rounded down to a multiple of 256M
- cannot be set on zoned filesystem

Note, that rounding and the 10% clamp will result to a different value
on filesystems smaller than 10G, typically 768M.

Signed-off-by: Stefan Roesch <shr@fb.com>
Reviewed-by: David Sterba <dsterba@suse.com>
[ Changes to original submission:
  - document setting constraints
  - drop read-only requirement
  - drop unnecessary error messages
  - fix return values of _store callback
  - use memparse for the value
  - fix rounding down to 256M
]
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Stefan Roesch 2022-02-08 11:31:21 -08:00 committed by David Sterba
parent f6fca3917b
commit 19fc516a51

View file

@ -21,6 +21,7 @@
#include "space-info.h"
#include "block-group.h"
#include "qgroup.h"
#include "misc.h"
/*
* Structure name Path
@ -92,6 +93,7 @@ static struct btrfs_feature_attr btrfs_attr_features_##_name = { \
static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj);
static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj);
static struct kobject *get_btrfs_kobj(struct kobject *kobj);
static struct btrfs_feature_attr *to_btrfs_feature_attr(struct kobj_attribute *a)
{
@ -709,6 +711,66 @@ static ssize_t btrfs_space_info_show_##field(struct kobject *kobj, \
} \
BTRFS_ATTR(space_info, field, btrfs_space_info_show_##field)
static ssize_t btrfs_chunk_size_show(struct kobject *kobj,
struct kobj_attribute *a, char *buf)
{
struct btrfs_space_info *sinfo = to_space_info(kobj);
return sysfs_emit(buf, "%llu\n", READ_ONCE(sinfo->chunk_size));
}
/*
* Store new chunk size in space info. Can be called on a read-only filesystem.
*
* If the new chunk size value is larger than 10% of free space it is reduced
* to match that limit. Alignment must be to 256M and the system chunk size
* cannot be set.
*/
static ssize_t btrfs_chunk_size_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));
char *retptr;
u64 val;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (!fs_info->fs_devices)
return -EINVAL;
if (btrfs_is_zoned(fs_info))
return -EINVAL;
/* System block type must not be changed. */
if (space_info->flags & BTRFS_BLOCK_GROUP_SYSTEM)
return -EPERM;
val = memparse(buf, &retptr);
/* There could be trailing '\n', also catch any typos after the value */
retptr = skip_spaces(retptr);
if (*retptr != 0 || val == 0)
return -EINVAL;
val = min(val, BTRFS_MAX_DATA_CHUNK_SIZE);
/* Limit stripe size to 10% of available space. */
val = min(div_factor(fs_info->fs_devices->total_rw_bytes, 1), val);
/* Must be multiple of 256M. */
val &= ~((u64)SZ_256M - 1);
/* Must be at least 256M. */
if (val < SZ_256M)
return -EINVAL;
btrfs_update_space_info_chunk_size(space_info, val);
return len;
}
SPACE_INFO_ATTR(flags);
SPACE_INFO_ATTR(total_bytes);
SPACE_INFO_ATTR(bytes_used);
@ -719,6 +781,7 @@ SPACE_INFO_ATTR(bytes_readonly);
SPACE_INFO_ATTR(bytes_zone_unusable);
SPACE_INFO_ATTR(disk_used);
SPACE_INFO_ATTR(disk_total);
BTRFS_ATTR_RW(space_info, chunk_size, btrfs_chunk_size_show, btrfs_chunk_size_store);
static ssize_t btrfs_sinfo_bg_reclaim_threshold_show(struct kobject *kobj,
struct kobj_attribute *a,
@ -773,6 +836,7 @@ static struct attribute *space_info_attrs[] = {
BTRFS_ATTR_PTR(space_info, disk_used),
BTRFS_ATTR_PTR(space_info, disk_total),
BTRFS_ATTR_PTR(space_info, bg_reclaim_threshold),
BTRFS_ATTR_PTR(space_info, chunk_size),
NULL,
};
ATTRIBUTE_GROUPS(space_info);
@ -1140,6 +1204,16 @@ static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj)
return to_fs_devs(kobj)->fs_info;
}
static struct kobject *get_btrfs_kobj(struct kobject *kobj)
{
while (kobj) {
if (kobj->ktype == &btrfs_ktype)
return kobj;
kobj = kobj->parent;
}
return NULL;
}
#define NUM_FEATURE_BITS 64
#define BTRFS_FEATURE_NAME_MAX 13
static char btrfs_unknown_feature_names[FEAT_MAX][NUM_FEATURE_BITS][BTRFS_FEATURE_NAME_MAX];