diff mbox series

[v5,04/10] btrfs: handle value associated with raid1 balancing parameter

Message ID 6a303a3da8116c3743fa9be605dde540d8a60f1a.1735748715.git.anand.jain@oracle.com (mailing list archive)
State New
Headers show
Series raid1 balancing methods | expand

Commit Message

Anand Jain Jan. 1, 2025, 6:06 p.m. UTC
This change enables specifying additional configuration values alongside
the raid1 balancing / read policy in a single input string.

Updated btrfs_read_policy_to_enum() to parse and handle a value associated
with the policy in the format `policy:value`, the value part if present is
converted 64-bit integer. Update btrfs_read_policy_store() to accommodate
the new parameter.

Signed-off-by: Anand Jain <anand.jain@oracle.com>
---
 fs/btrfs/sysfs.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

Comments

David Sterba Jan. 2, 2025, 6:29 p.m. UTC | #1
On Thu, Jan 02, 2025 at 02:06:33AM +0800, Anand Jain wrote:
> This change enables specifying additional configuration values alongside
> the raid1 balancing / read policy in a single input string.
> 
> Updated btrfs_read_policy_to_enum() to parse and handle a value associated
> with the policy in the format `policy:value`, the value part if present is
> converted 64-bit integer. Update btrfs_read_policy_store() to accommodate
> the new parameter.
> 
> Signed-off-by: Anand Jain <anand.jain@oracle.com>
> ---
>  fs/btrfs/sysfs.c | 16 ++++++++++++++--
>  1 file changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
> index 3b0325259c02..cf6e5322621f 100644
> --- a/fs/btrfs/sysfs.c
> +++ b/fs/btrfs/sysfs.c
> @@ -1307,15 +1307,26 @@ BTRFS_ATTR(, temp_fsid, btrfs_temp_fsid_show);
>  
>  static const char * const btrfs_read_policy_name[] = { "pid" };
>  
> -static int btrfs_read_policy_to_enum(const char *str)
> +static int btrfs_read_policy_to_enum(const char *str, s64 *value)
>  {
>  	char param[32] = {'\0'};
> +	char *__maybe_unused value_str;
>  
>  	if (!str || strlen(str) == 0)
>  		return 0;
>  
>  	strncpy(param, str, sizeof(param) - 1);
>  
> +#ifdef CONFIG_BTRFS_EXPERIMENTAL
> +	/* Separate value from input in policy:value format. */
> +	if ((value_str = strchr(param, ':'))) {
> +		*value_str = '\0';
> +		value_str++;
> +		if (value && kstrtou64(value_str, 10, value) != 0)
> +			return -EINVAL;

I think I've mentioned that before, this lacks validation of the
'value', there should be some lower and upper bound check. Minimum can
be the sectorsize and maximum maybe 1G or 2G, so the u32 type is
sufficient. The silent conversion from u64 to s64 should be avoided.
Anand Jain Jan. 3, 2025, 3:04 p.m. UTC | #2
On 2/1/25 23:59, David Sterba wrote:
> On Thu, Jan 02, 2025 at 02:06:33AM +0800, Anand Jain wrote:
>> This change enables specifying additional configuration values alongside
>> the raid1 balancing / read policy in a single input string.
>>
>> Updated btrfs_read_policy_to_enum() to parse and handle a value associated
>> with the policy in the format `policy:value`, the value part if present is
>> converted 64-bit integer. Update btrfs_read_policy_store() to accommodate
>> the new parameter.
>>
>> Signed-off-by: Anand Jain <anand.jain@oracle.com>
>> ---
>>   fs/btrfs/sysfs.c | 16 ++++++++++++++--
>>   1 file changed, 14 insertions(+), 2 deletions(-)
>>
>> diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
>> index 3b0325259c02..cf6e5322621f 100644
>> --- a/fs/btrfs/sysfs.c
>> +++ b/fs/btrfs/sysfs.c
>> @@ -1307,15 +1307,26 @@ BTRFS_ATTR(, temp_fsid, btrfs_temp_fsid_show);
>>   
>>   static const char * const btrfs_read_policy_name[] = { "pid" };
>>   
>> -static int btrfs_read_policy_to_enum(const char *str)
>> +static int btrfs_read_policy_to_enum(const char *str, s64 *value)
>>   {
>>   	char param[32] = {'\0'};
>> +	char *__maybe_unused value_str;
>>   
>>   	if (!str || strlen(str) == 0)
>>   		return 0;
>>   
>>   	strncpy(param, str, sizeof(param) - 1);
>>   
>> +#ifdef CONFIG_BTRFS_EXPERIMENTAL
>> +	/* Separate value from input in policy:value format. */
>> +	if ((value_str = strchr(param, ':'))) {
>> +		*value_str = '\0';
>> +		value_str++;
>> +		if (value && kstrtou64(value_str, 10, value) != 0)
>> +			return -EINVAL;
> 
> I think I've mentioned that before, this lacks validation of the
> 'value', there should be some lower and upper bound check. Minimum can
> be the sectorsize and maximum maybe 1G or 2G, so the u32 type is
> sufficient.

Regarding the lack of validation, as I replied earlier, only the
minimum needs validation, not the upper limit. A 1TB disk or SAN
storage can be connected to a 32-bit host, and we can still read
the full 1TB from a single mirror. IMO, it depends on the use case,
or we can revisit it based on feedback.?

The patch already handles the lower limit.

$ echo round-robin:1024 > 
/sys/fs/btrfs/b03580af-900e-4940-a7f8-3f04f9981a12/read_policy

$ cat /sys/fs/btrfs/b03580af-900e-4940-a7f8-3f04f9981a12/read_policy
pid [round-robin:4096] devid:1

$ dmesg -k | tail -1
BTRFS warning (device sda): read_policy: min contiguous read 1024 should 
be multiples of the sectorsize 4096, rounded to 4096

> The silent conversion from u64 to s64 should be avoided.

Do you mean from s64 to u64?

Thanks, Anand
David Sterba Jan. 3, 2025, 4:05 p.m. UTC | #3
On Fri, Jan 03, 2025 at 08:34:12PM +0530, Anand Jain wrote:
> >> +#ifdef CONFIG_BTRFS_EXPERIMENTAL
> >> +	/* Separate value from input in policy:value format. */
> >> +	if ((value_str = strchr(param, ':'))) {
> >> +		*value_str = '\0';
> >> +		value_str++;
> >> +		if (value && kstrtou64(value_str, 10, value) != 0)
> >> +			return -EINVAL;
> > 
> > I think I've mentioned that before, this lacks validation of the
> > 'value', there should be some lower and upper bound check. Minimum can
> > be the sectorsize and maximum maybe 1G or 2G, so the u32 type is
> > sufficient.
> 
> Regarding the lack of validation, as I replied earlier, only the
> minimum needs validation, not the upper limit. A 1TB disk or SAN
> storage can be connected to a 32-bit host, and we can still read
> the full 1TB from a single mirror. IMO, it depends on the use case,
> or we can revisit it based on feedback.?

SAN is not a typical storage, what the load balancing should assume is a
set of individual rotational or ssd/nvme disks. Also 32bit host is not
something we're expecting by default.

> The patch already handles the lower limit.
> 
> $ echo round-robin:1024 > 
> /sys/fs/btrfs/b03580af-900e-4940-a7f8-3f04f9981a12/read_policy
> 
> $ cat /sys/fs/btrfs/b03580af-900e-4940-a7f8-3f04f9981a12/read_policy
> pid [round-robin:4096] devid:1
> 
> $ dmesg -k | tail -1
> BTRFS warning (device sda): read_policy: min contiguous read 1024 should 
> be multiples of the sectorsize 4096, rounded to 4096

Right.

> > The silent conversion from u64 to s64 should be avoided.
> 
> Do you mean from s64 to u64?

Yes, I've used kstrtos64 and reject negative values, then the types
match. I'm not sure about the upper bound, the idea was like 1G or 2G
but a fast NVME can do a few gigabytes per second so we may need more
than a 32bit type can hold. But it's counted in blocks it's 4G * 4K so
it's safe.
diff mbox series

Patch

diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index 3b0325259c02..cf6e5322621f 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -1307,15 +1307,26 @@  BTRFS_ATTR(, temp_fsid, btrfs_temp_fsid_show);
 
 static const char * const btrfs_read_policy_name[] = { "pid" };
 
-static int btrfs_read_policy_to_enum(const char *str)
+static int btrfs_read_policy_to_enum(const char *str, s64 *value)
 {
 	char param[32] = {'\0'};
+	char *__maybe_unused value_str;
 
 	if (!str || strlen(str) == 0)
 		return 0;
 
 	strncpy(param, str, sizeof(param) - 1);
 
+#ifdef CONFIG_BTRFS_EXPERIMENTAL
+	/* Separate value from input in policy:value format. */
+	if ((value_str = strchr(param, ':'))) {
+		*value_str = '\0';
+		value_str++;
+		if (value && kstrtou64(value_str, 10, value) != 0)
+			return -EINVAL;
+	}
+#endif
+
 	return sysfs_match_string(btrfs_read_policy_name, param);
 }
 
@@ -1351,8 +1362,9 @@  static ssize_t btrfs_read_policy_store(struct kobject *kobj,
 {
 	struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
 	int index;
+	s64 value = -1;
 
-	index = btrfs_read_policy_to_enum(buf);
+	index = btrfs_read_policy_to_enum(buf, &value);
 	if (index < 0)
 		return -EINVAL;