Commit 19fc516a authored by Stefan Roesch's avatar Stefan Roesch Committed by David Sterba
Browse files

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: default avatarStefan Roesch <shr@fb.com>
Reviewed-by: default avatarDavid 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: default avatarDavid Sterba <dsterba@suse.com>
parent f6fca391
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
@@ -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];