[PATCH v2] md: Allow setting persistent superblock version for md= command line

Subsystems: documentation, software raid (multiple disks) support, the rest

STALE407d

3 messages, 2 authors, 2025-08-25 · open the first message on its own page

[PATCH v2] md: Allow setting persistent superblock version for md= command line

From: Jeremias Stotter <hidden>
Date: 2025-08-25 11:36:03

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

Signed-off-by: Jeremias Stotter <redacted>
---
 Documentation/admin-guide/md.rst |  8 +++++
 drivers/md/md-autodetect.c       | 61 ++++++++++++++++++++++++++++++--
 2 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/Documentation/admin-guide/md.rst b/Documentation/admin-guide/md.rst
index 4ff2cc291d18..7b904d73ace0 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=v<superblock version no.>,<md device no.>,dev0,dev1,...,devn
+
+for example, for a raid array with superblock version 1.2 it could look like this::
+
+  md=v1.2,0,/dev/sda1,/dev/sdb1
+
 ``md device no.``
 +++++++++++++++++
 
diff --git a/drivers/md/md-autodetect.c b/drivers/md/md-autodetect.c
index 4b80165afd23..4c4775c33963 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;
 
@@ -56,6 +58,9 @@ static int md_setup_ents __initdata;
  * 2001-06-03: Dave Cinege <dcinege@psychosis.com>
  *		Shifted name_to_kdev_t() and related operations to md_set_drive()
  *		for later execution. Rewrote section to make devfs compatible.
+ * 2025-08-24: Jeremias Stotter <jeremias@jears.at>
+ *              Allow setting of the superblock version:
+ *              md=vX.X,...
  */
 static int __init md_setup(char *str)
 {
@@ -63,6 +68,49 @@ static int __init md_setup(char *str)
 	char *pername = "";
 	char *str1;
 	int ent;
+	int major_i = 0, minor_i = 0;
+
+	if (*str == 'v') {
+		char *version = ++str;
+		char *version_end = strchr(str, ',');
+
+		if (!version_end) {
+			pr_warn("md: Version (%s) has been specified wrong, no ',' found, use like this: md=vX.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 wrong, no '.' to separate major and minor version found, use like this: md=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 wrong, couldn't convert major '%s' to number, use like this: md=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 wrong, couldn't convert minor '%s' to number, use like this: md=vX.X,...\n",
+				minor_s);
+			return 0;
+		}
+	}
 
 	if (*str == 'd') {
 		partitioned = 1;
@@ -116,6 +164,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 +250,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 +326,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]);
 }
-- 
2.49.1

Re: [PATCH v2] md: Allow setting persistent superblock version for md= command line

From: Paul Menzel <hidden>
Date: 2025-08-25 11:58:32

Dear Jeremias,


Thank you very much for your patch, and welcome to the Linux kernel community!

Am 25.08.25 um 13:34 schrieb Jeremias Stotter:
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:
Could you start by describing the problem. I am using several systems, where arrays with version ≥ can be assembled. What am I missing?
quoted hunk
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

Signed-off-by: Jeremias Stotter <redacted>
---
  Documentation/admin-guide/md.rst |  8 +++++
  drivers/md/md-autodetect.c       | 61 ++++++++++++++++++++++++++++++--
  2 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/Documentation/admin-guide/md.rst b/Documentation/admin-guide/md.rst
index 4ff2cc291d18..7b904d73ace0 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=v<superblock version no.>,<md device no.>,dev0,dev1,...,devn
+
+for example, for a raid array with superblock version 1.2 it could look like this::
+
+  md=v1.2,0,/dev/sda1,/dev/sdb1
+
Why not keep the pattern of the other options to specify <md device no.> first?
quoted hunk
  ``md device no.``
  +++++++++++++++++
  
diff --git a/drivers/md/md-autodetect.c b/drivers/md/md-autodetect.c
index 4b80165afd23..4c4775c33963 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;
  
@@ -56,6 +58,9 @@ static int md_setup_ents __initdata;
   * 2001-06-03: Dave Cinege <dcinege@psychosis.com>
   *		Shifted name_to_kdev_t() and related operations to md_set_drive()
   *		for later execution. Rewrote section to make devfs compatible.
+ * 2025-08-24: Jeremias Stotter <jeremias@jears.at>
+ *              Allow setting of the superblock version:
+ *              md=vX.X,...
I believe since git (and BitKeeper before) being used, these headers are not updated any more.
quoted hunk
   */
  static int __init md_setup(char *str)
  {
@@ -63,6 +68,49 @@ static int __init md_setup(char *str)
  	char *pername = "";
  	char *str1;
  	int ent;
+	int major_i = 0, minor_i = 0;
+
+	if (*str == 'v') {
+		char *version = ++str;
+		char *version_end = strchr(str, ',');
+
+		if (!version_end) {
+			pr_warn("md: Version (%s) has been specified wrong, no ',' found, use like this: md=vX.X,...\n",
s/wrong/incorrectly/?

Or wrong*ly*. Same below.
quoted hunk
+				version);
+			return 0;
+		}
+		*version_end = '\0';
+		str = version_end + 1;
+
+		char *separator = strchr(version, '.');
+
+		if (!separator) {
+			pr_warn("md: Version (%s) has been specified wrong, no '.' to separate major and minor version found, use like this: md=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 wrong, couldn't convert major '%s' to number, use like this: md=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 wrong, couldn't convert minor '%s' to number, use like this: md=vX.X,...\n",
+				minor_s);
+			return 0;
+		}
+	}
  
  	if (*str == 'd') {
  		partitioned = 1;
@@ -116,6 +164,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 +250,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 +326,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]);
  }

Kind regards,

Paul

Re: [PATCH v2] md: Allow setting persistent superblock version for md= command line

From: <hidden>
Date: 2025-08-25 13:35:02

On 2025-08-25 13:58, Paul Menzel wrote:
Dear Jeremias,


Thank you very much for your patch, and welcome to the Linux kernel community!

Am 25.08.25 um 13:34 schrieb Jeremias Stotter:
quoted
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:
Could you start by describing the problem. I am using several systems, where arrays with version ≥ can be assembled. What am I missing?
quoted
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

Signed-off-by: Jeremias Stotter <redacted>
---
  Documentation/admin-guide/md.rst |  8 +++++
  drivers/md/md-autodetect.c       | 61 ++++++++++++++++++++++++++++++--
  2 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/Documentation/admin-guide/md.rst b/Documentation/admin-guide/md.rst
index 4ff2cc291d18..7b904d73ace0 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=v<superblock version no.>,<md device no.>,dev0,dev1,...,devn
+
+for example, for a raid array with superblock version 1.2 it could look like this::
+
+  md=v1.2,0,/dev/sda1,/dev/sdb1
+
Why not keep the pattern of the other options to specify <md device no.> first?
quoted
  ``md device no.``
  +++++++++++++++++
  diff --git a/drivers/md/md-autodetect.c b/drivers/md/md-autodetect.c
index 4b80165afd23..4c4775c33963 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;
  @@ -56,6 +58,9 @@ static int md_setup_ents __initdata;
   * 2001-06-03: Dave Cinege <dcinege@psychosis.com>
   *		Shifted name_to_kdev_t() and related operations to md_set_drive()
   *		for later execution. Rewrote section to make devfs compatible.
+ * 2025-08-24: Jeremias Stotter <jeremias@jears.at>
+ *              Allow setting of the superblock version:
+ *              md=vX.X,...
I believe since git (and BitKeeper before) being used, these headers are not updated any more.
quoted
   */
  static int __init md_setup(char *str)
  {
@@ -63,6 +68,49 @@ static int __init md_setup(char *str)
  	char *pername = "";
  	char *str1;
  	int ent;
+	int major_i = 0, minor_i = 0;
+
+	if (*str == 'v') {
+		char *version = ++str;
+		char *version_end = strchr(str, ',');
+
+		if (!version_end) {
+			pr_warn("md: Version (%s) has been specified wrong, no ',' found, use like this: md=vX.X,...\n",
s/wrong/incorrectly/?

Or wrong*ly*. Same below.
quoted
+				version);
+			return 0;
+		}
+		*version_end = '\0';
+		str = version_end + 1;
+
+		char *separator = strchr(version, '.');
+
+		if (!separator) {
+			pr_warn("md: Version (%s) has been specified wrong, no '.' to separate major and minor version found, use like this: md=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 wrong, couldn't convert major '%s' to number, use like this: md=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 wrong, couldn't convert minor '%s' to number, use like this: md=vX.X,...\n",
+				minor_s);
+			return 0;
+		}
+	}
    	if (*str == 'd') {
  		partitioned = 1;
@@ -116,6 +164,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 +250,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 +326,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]);
  }

Kind regards,

Paul
Hello Paul,

thanks for the feedback! This is my first patch, please excuse me for not being familiar with the kernel development process yet.
This is relevant, for example, when using an array with version 1.2 as root.
When assembling an array without an initrd that is version 1.2 for example, you get an invalid version 0.0 superblock error as the kernel tries to assemble the array with that version. There is no way right now to specify the superblock version from the kernel command line alone, so the array is just never assembled. Or am I missing something?

I will be sending you a patch taking into account your other concerns.

Kind regards,

Jeremias
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help