linux-raid.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3] md: Allow setting persistent superblock version for md= command line
       [not found] <20250825144029.2924-1-jeremias@jears.at>
@ 2025-08-25 14:53 ` jeremias
  2025-08-27  7:26   ` Yu Kuai
  0 siblings, 1 reply; 3+ messages in thread
From: jeremias @ 2025-08-25 14:53 UTC (permalink / raw)
  To: Linux Raid

This allows for setting a superblock version on the kernel command line 
to be
able to assemble version >=1.0 arrays. It can optionally be set like 
this:

md=vX.X,...

This will set the version of the array before assembly so it can be 
assembled
correctly.

Also updated docs accordingly.

v2: Use pr_warn instead of printk

v3: Change order of options so it stays with past pattern

Signed-off-by: Jeremias Stotter <jeremias@jears.at>
---
  Documentation/admin-guide/md.rst |  8 +++++
  drivers/md/md-autodetect.c       | 59 ++++++++++++++++++++++++++++++--
  2 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/Documentation/admin-guide/md.rst 
b/Documentation/admin-guide/md.rst
index 4ff2cc291d18..f57ae871c997 100644
--- a/Documentation/admin-guide/md.rst
+++ b/Documentation/admin-guide/md.rst
@@ -23,6 +23,14 @@ or, to assemble a partitionable array::

    md=d<md device no.>,dev0,dev1,...,devn

+if you are using superblock versions greater than 0, use the 
following::
+
+  md=<md device no.>,v<superblock version no.>,dev0,dev1,...,devn
+
+for example, for a raid array with superblock version 1.2 it could look 
like this::
+
+  md=0,v1.2,/dev/sda1,/dev/sdb1
+
  ``md device no.``
  +++++++++++++++++

diff --git a/drivers/md/md-autodetect.c b/drivers/md/md-autodetect.c
index 4b80165afd23..67d38559ad50 100644
--- a/drivers/md/md-autodetect.c
+++ b/drivers/md/md-autodetect.c
@@ -32,6 +32,8 @@ static struct md_setup_args {
  	int partitioned;
  	int level;
  	int chunk;
+	int major_version;
+	int minor_version;
  	char *device_names;
  } md_setup_args[256] __initdata;

@@ -63,6 +65,7 @@ static int __init md_setup(char *str)
  	char *pername = "";
  	char *str1;
  	int ent;
+	int major_i = 0, minor_i = 0;

  	if (*str == 'd') {
  		partitioned = 1;
@@ -109,6 +112,49 @@ static int __init md_setup(char *str)
  	case 0:
  		md_setup_args[ent].level = LEVEL_NONE;
  		pername="super-block";
+
+		if (*str == 'v') { /* Superblock version */
+			char *version = ++str;
+			char *version_end = strchr(str, ',');
+
+			if (!version_end) {
+				pr_warn("md: Version (%s) has been specified wrongly, no ',' found, 
use like this: md=<md dev. no.>,X.X,...\n",
+					version);
+				return 0;
+			}
+			*version_end = '\0';
+			str = version_end + 1;
+
+			char *separator = strchr(version, '.');
+
+			if (!separator) {
+				pr_warn("md: Version (%s) has been specified wrongly, no '.' to 
separate major and minor version found, use like this: md=<md dev. 
no.>,vX.X,...\n",
+					version);
+				return 0;
+			}
+			*separator = '\0';
+			char *minor_s = separator + 1;
+
+			int ret = kstrtoint(version, 10, &major_i);
+
+			if (ret != 0) {
+				pr_warn("md: Version has been specified wrongly, couldn't convert 
major '%s' to number, use like this: md=<md dev. no.>,vX.X,...\n",
+					version);
+				return 0;
+			}
+			if (major_i != 0 && major_i != 1) {
+				pr_warn("md: Major version %d is not valid, use 0 or 1\n",
+					major_i);
+				return 0;
+			}
+			ret = kstrtoint(minor_s, 10, &minor_i);
+			if (ret != 0) {
+				pr_warn("md: Version has been specified wrongly, couldn't convert 
minor '%s' to number, use like this: md=<md dev. no.>,vX.X,...\n",
+					minor_s);
+				return 0;
+			}
+		}
+
  	}

  	printk(KERN_INFO "md: Will configure md%d (%s) from %s, below.\n",
@@ -116,6 +162,8 @@ static int __init md_setup(char *str)
  	md_setup_args[ent].device_names = str;
  	md_setup_args[ent].partitioned = partitioned;
  	md_setup_args[ent].minor = minor;
+	md_setup_args[ent].minor_version = minor_i;
+	md_setup_args[ent].major_version = major_i;

  	return 1;
  }
@@ -200,6 +248,9 @@ static void __init md_setup_drive(struct 
md_setup_args *args)

  	err = md_set_array_info(mddev, &ainfo);

+	mddev->major_version = args->major_version;
+	mddev->minor_version = args->minor_version;
+
  	for (i = 0; i <= MD_SB_DISKS && devices[i]; i++) {
  		struct mdu_disk_info_s dinfo = {
  			.major	= MAJOR(devices[i]),
@@ -273,11 +324,15 @@ void __init md_run_setup(void)
  {
  	int ent;

+	/*
+	 * Assemble manually defined raids first
+	 */
+	for (ent = 0; ent < md_setup_ents; ent++)
+		md_setup_drive(&md_setup_args[ent]);
+
  	if (raid_noautodetect)
  		printk(KERN_INFO "md: Skipping autodetection of RAID arrays. 
(raid=autodetect will force)\n");
  	else
  		autodetect_raid();

-	for (ent = 0; ent < md_setup_ents; ent++)
-		md_setup_drive(&md_setup_args[ent]);
  }

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v3] md: Allow setting persistent superblock version for md= command line
  2025-08-25 14:53 ` [PATCH v3] md: Allow setting persistent superblock version for md= command line jeremias
@ 2025-08-27  7:26   ` Yu Kuai
  2025-08-27  9:47     ` Yu Kuai
  0 siblings, 1 reply; 3+ messages in thread
From: Yu Kuai @ 2025-08-27  7:26 UTC (permalink / raw)
  To: jeremias, Linux Raid, yukuai (C)

Hi,

在 2025/08/25 22:53, jeremias@jears.at 写道:
> This allows for setting a superblock version on the kernel command line 
> to be
> able to assemble version >=1.0 arrays. It can optionally be set like this:
> 
> md=vX.X,...
> 
> This will set the version of the array before assembly so it can be 
> assembled
> correctly.
> 

You should explain that current autodetect is only supported for 0.90
array.

> Also updated docs accordingly.
> 
> v2: Use pr_warn instead of printk
> 
> v3: Change order of options so it stays with past pattern
> 
> Signed-off-by: Jeremias Stotter <jeremias@jears.at>
> ---
>   Documentation/admin-guide/md.rst |  8 +++++
>   drivers/md/md-autodetect.c       | 59 ++++++++++++++++++++++++++++++--
>   2 files changed, 65 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/admin-guide/md.rst 
> b/Documentation/admin-guide/md.rst
> index 4ff2cc291d18..f57ae871c997 100644
> --- a/Documentation/admin-guide/md.rst
> +++ b/Documentation/admin-guide/md.rst
> @@ -23,6 +23,14 @@ or, to assemble a partitionable array::
> 
>     md=d<md device no.>,dev0,dev1,...,devn
> 
> +if you are using superblock versions greater than 0, use the following::
> +
> +  md=<md device no.>,v<superblock version no.>,dev0,dev1,...,devn
> +
> +for example, for a raid array with superblock version 1.2 it could look 
> like this::
> +
> +  md=0,v1.2,/dev/sda1,/dev/sdb1
> +
>   ``md device no.``
>   +++++++++++++++++
> 

What about md_autostart_arrays()? where 0.90 is still the only default
choice.
> diff --git a/drivers/md/md-autodetect.c b/drivers/md/md-autodetect.c
> index 4b80165afd23..67d38559ad50 100644
> --- a/drivers/md/md-autodetect.c
> +++ b/drivers/md/md-autodetect.c
> @@ -32,6 +32,8 @@ static struct md_setup_args {
>       int partitioned;
>       int level;
>       int chunk;
> +    int major_version;
> +    int minor_version;
>       char *device_names;
>   } md_setup_args[256] __initdata;
> 
> @@ -63,6 +65,7 @@ static int __init md_setup(char *str)
>       char *pername = "";
>       char *str1;
>       int ent;
> +    int major_i = 0, minor_i = 0;
> 
>       if (*str == 'd') {
>           partitioned = 1;
> @@ -109,6 +112,49 @@ static int __init md_setup(char *str)
>       case 0:
>           md_setup_args[ent].level = LEVEL_NONE;
>           pername="super-block";
> +
> +        if (*str == 'v') { /* Superblock version */
> +            char *version = ++str;
> +            char *version_end = strchr(str, ',');
> +
> +            if (!version_end) {
> +                pr_warn("md: Version (%s) has been specified wrongly, 
> no ',' found, use like this: md=<md dev. no.>,X.X,...\n",
> +                    version);
> +                return 0;
> +            }
> +            *version_end = '\0';
> +            str = version_end + 1;
> +
> +            char *separator = strchr(version, '.');
> +
> +            if (!separator) {
> +                pr_warn("md: Version (%s) has been specified wrongly, 
> no '.' to separate major and minor version found, use like this: md=<md 
> dev. no.>,vX.X,...\n",
> +                    version);
> +                return 0;
> +            }
> +            *separator = '\0';
> +            char *minor_s = separator + 1;
> +
> +            int ret = kstrtoint(version, 10, &major_i);
> +
> +            if (ret != 0) {
> +                pr_warn("md: Version has been specified wrongly, 
> couldn't convert major '%s' to number, use like this: md=<md dev. 
> no.>,vX.X,...\n",
> +                    version);
> +                return 0;
> +            }
> +            if (major_i != 0 && major_i != 1) {
> +                pr_warn("md: Major version %d is not valid, use 0 or 1\n",
> +                    major_i);
> +                return 0;
> +            }
> +            ret = kstrtoint(minor_s, 10, &minor_i);
> +            if (ret != 0) {
> +                pr_warn("md: Version has been specified wrongly, 
> couldn't convert minor '%s' to number, use like this: md=<md dev. 
> no.>,vX.X,...\n",
> +                    minor_s);
> +                return 0;
> +            }
> +        }
> +
>       }
> 
>       printk(KERN_INFO "md: Will configure md%d (%s) from %s, below.\n",
> @@ -116,6 +162,8 @@ static int __init md_setup(char *str)
>       md_setup_args[ent].device_names = str;
>       md_setup_args[ent].partitioned = partitioned;
>       md_setup_args[ent].minor = minor;
> +    md_setup_args[ent].minor_version = minor_i;
> +    md_setup_args[ent].major_version = major_i;
> 
>       return 1;
>   }
> @@ -200,6 +248,9 @@ static void __init md_setup_drive(struct 
> md_setup_args *args)
> 
>       err = md_set_array_info(mddev, &ainfo);
> 
> +    mddev->major_version = args->major_version;
> +    mddev->minor_version = args->minor_version;

I would expect to fix md_set_array_info() to hanlde this new case, to
make code more readable.

> +
>       for (i = 0; i <= MD_SB_DISKS && devices[i]; i++) {
>           struct mdu_disk_info_s dinfo = {
>               .major    = MAJOR(devices[i]),
> @@ -273,11 +324,15 @@ void __init md_run_setup(void)
>   {
>       int ent;
> 
> +    /*
> +     * Assemble manually defined raids first
> +     */
> +    for (ent = 0; ent < md_setup_ents; ent++)
> +        md_setup_drive(&md_setup_args[ent]);
> +

You just explain what you did in comment, Why do you change the order?

Thanks,
Kuai

>       if (raid_noautodetect)
>           printk(KERN_INFO "md: Skipping autodetection of RAID arrays. 
> (raid=autodetect will force)\n");
>       else
>           autodetect_raid();
> 
> -    for (ent = 0; ent < md_setup_ents; ent++)
> -        md_setup_drive(&md_setup_args[ent]);
>   }
> 
> .
> 


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v3] md: Allow setting persistent superblock version for md= command line
  2025-08-27  7:26   ` Yu Kuai
@ 2025-08-27  9:47     ` Yu Kuai
  0 siblings, 0 replies; 3+ messages in thread
From: Yu Kuai @ 2025-08-27  9:47 UTC (permalink / raw)
  To: Yu Kuai, jeremias, Linux Raid, yukuai (C)

Hi,

在 2025/08/27 15:26, Yu Kuai 写道:
> Hi,
> 
> 在 2025/08/25 22:53, jeremias@jears.at 写道:
>> This allows for setting a superblock version on the kernel command 
>> line to be
>> able to assemble version >=1.0 arrays. It can optionally be set like 
>> this:
>>
>> md=vX.X,...
>>
>> This will set the version of the array before assembly so it can be 
>> assembled
>> correctly.
>>
> 
> You should explain that current autodetect is only supported for 0.90
> array.
> 
>> Also updated docs accordingly.
>>
>> v2: Use pr_warn instead of printk
>>
>> v3: Change order of options so it stays with past pattern
>>
>> Signed-off-by: Jeremias Stotter <jeremias@jears.at>
>> ---
>>   Documentation/admin-guide/md.rst |  8 +++++
>>   drivers/md/md-autodetect.c       | 59 ++++++++++++++++++++++++++++++--
>>   2 files changed, 65 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/admin-guide/md.rst 
>> b/Documentation/admin-guide/md.rst
>> index 4ff2cc291d18..f57ae871c997 100644
>> --- a/Documentation/admin-guide/md.rst
>> +++ b/Documentation/admin-guide/md.rst
>> @@ -23,6 +23,14 @@ or, to assemble a partitionable array::
>>
>>     md=d<md device no.>,dev0,dev1,...,devn
>>
>> +if you are using superblock versions greater than 0, use the following::
>> +
>> +  md=<md device no.>,v<superblock version no.>,dev0,dev1,...,devn
>> +
>> +for example, for a raid array with superblock version 1.2 it could 
>> look like this::
>> +
>> +  md=0,v1.2,/dev/sda1,/dev/sdb1
>> +
>>   ``md device no.``
>>   +++++++++++++++++
>>
> 
> What about md_autostart_arrays()? where 0.90 is still the only default
> choice.
>> diff --git a/drivers/md/md-autodetect.c b/drivers/md/md-autodetect.c
>> index 4b80165afd23..67d38559ad50 100644
>> --- a/drivers/md/md-autodetect.c
>> +++ b/drivers/md/md-autodetect.c
>> @@ -32,6 +32,8 @@ static struct md_setup_args {
>>       int partitioned;
>>       int level;
>>       int chunk;
>> +    int major_version;
>> +    int minor_version;
>>       char *device_names;
>>   } md_setup_args[256] __initdata;
>>
>> @@ -63,6 +65,7 @@ static int __init md_setup(char *str)
>>       char *pername = "";
>>       char *str1;
>>       int ent;
>> +    int major_i = 0, minor_i = 0;
>>
>>       if (*str == 'd') {
>>           partitioned = 1;
>> @@ -109,6 +112,49 @@ static int __init md_setup(char *str)
>>       case 0:
>>           md_setup_args[ent].level = LEVEL_NONE;
>>           pername="super-block";
>> +
>> +        if (*str == 'v') { /* Superblock version */
>> +            char *version = ++str;
>> +            char *version_end = strchr(str, ',');
>> +
>> +            if (!version_end) {
>> +                pr_warn("md: Version (%s) has been specified wrongly, 
>> no ',' found, use like this: md=<md dev. no.>,X.X,...\n",
>> +                    version);
>> +                return 0;
>> +            }
>> +            *version_end = '\0';
>> +            str = version_end + 1;
>> +
>> +            char *separator = strchr(version, '.');
>> +
>> +            if (!separator) {
>> +                pr_warn("md: Version (%s) has been specified wrongly, 
>> no '.' to separate major and minor version found, use like this: 
>> md=<md dev. no.>,vX.X,...\n",
>> +                    version);
>> +                return 0;
>> +            }
>> +            *separator = '\0';
>> +            char *minor_s = separator + 1;
>> +
>> +            int ret = kstrtoint(version, 10, &major_i);
>> +
>> +            if (ret != 0) {
>> +                pr_warn("md: Version has been specified wrongly, 
>> couldn't convert major '%s' to number, use like this: md=<md dev. 
>> no.>,vX.X,...\n",
>> +                    version);
>> +                return 0;
>> +            }
>> +            if (major_i != 0 && major_i != 1) {
>> +                pr_warn("md: Major version %d is not valid, use 0 or 
>> 1\n",
>> +                    major_i);
>> +                return 0;
>> +            }
>> +            ret = kstrtoint(minor_s, 10, &minor_i);
>> +            if (ret != 0) {
>> +                pr_warn("md: Version has been specified wrongly, 
>> couldn't convert minor '%s' to number, use like this: md=<md dev. 
>> no.>,vX.X,...\n",
>> +                    minor_s);
>> +                return 0;
>> +            }
>> +        }
>> +
>>       }
>>
>>       printk(KERN_INFO "md: Will configure md%d (%s) from %s, below.\n",
>> @@ -116,6 +162,8 @@ static int __init md_setup(char *str)
>>       md_setup_args[ent].device_names = str;
>>       md_setup_args[ent].partitioned = partitioned;
>>       md_setup_args[ent].minor = minor;
>> +    md_setup_args[ent].minor_version = minor_i;
>> +    md_setup_args[ent].major_version = major_i;
>>
>>       return 1;
>>   }
>> @@ -200,6 +248,9 @@ static void __init md_setup_drive(struct 
>> md_setup_args *args)
>>
>>       err = md_set_array_info(mddev, &ainfo);
>>
>> +    mddev->major_version = args->major_version;
>> +    mddev->minor_version = args->minor_version;
> 
> I would expect to fix md_set_array_info() to hanlde this new case, to
> make code more readable.
> 
>> +
>>       for (i = 0; i <= MD_SB_DISKS && devices[i]; i++) {
>>           struct mdu_disk_info_s dinfo = {
>>               .major    = MAJOR(devices[i]),
>> @@ -273,11 +324,15 @@ void __init md_run_setup(void)
>>   {
>>       int ent;
>>
>> +    /*
>> +     * Assemble manually defined raids first
>> +     */
>> +    for (ent = 0; ent < md_setup_ents; ent++)
>> +        md_setup_drive(&md_setup_args[ent]);
>> +

And BTW, take a closer look at autodetect code, although you set
mddev->major_version to 1, however, md_set_array_info() will set
mddev->raid_disks while mddev->pers is still NULL, hence from
md_add_new_disk(), -EINVAL will be returned directly:

md_add_new_disk
	if (!mddev->raid_disks)
		......
		return;
	if (mddev->pers)
		......
		return;

         /* otherwise, md_add_new_disk is only allowed
         ┊* for major_version==0 superblocks
         ┊*/
         if (mddev->major_version != 0) {
                 pr_warn("%s: ADD_NEW_DISK not supported\n", mdname(mddev));
                 return -EINVAL;
         }

What am I missing?

Thanks,
Kuai

> 
> You just explain what you did in comment, Why do you change the order?
> 
> Thanks,
> Kuai
> 
>>       if (raid_noautodetect)
>>           printk(KERN_INFO "md: Skipping autodetection of RAID arrays. 
>> (raid=autodetect will force)\n");
>>       else
>>           autodetect_raid();
>>
>> -    for (ent = 0; ent < md_setup_ents; ent++)
>> -        md_setup_drive(&md_setup_args[ent]);
>>   }
>>
>> .
>>
> 
> .
> 

And BTW, take a closer look at autodetect code, alouth


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-08-27  9:47 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20250825144029.2924-1-jeremias@jears.at>
2025-08-25 14:53 ` [PATCH v3] md: Allow setting persistent superblock version for md= command line jeremias
2025-08-27  7:26   ` Yu Kuai
2025-08-27  9:47     ` Yu Kuai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).