git: 752bde7da6ad - main - loader: Allow dynmaic creation of MD disks

From: Warner Losh <imp_at_FreeBSD.org>
Date: Fri, 11 Sep 2026 05:04:19 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=752bde7da6ad11b53af82f81d44e0ae2729c56d7

commit 752bde7da6ad11b53af82f81d44e0ae2729c56d7
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2026-09-11 04:13:14 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2026-09-11 04:15:27 +0000

    loader: Allow dynmaic creation of MD disks
    
    Augment the md device to allow creation of md devices. This is useful
    when UEFI doesn't support RamDisk and in other cases where we have a
    handy initrd-like image we want to use.
    
    Sponsored by:           Netflix
    Differential Revision:  https://reviews.freebsd.org/D59418
---
 stand/common/bootstrap.h |   4 ++
 stand/common/md.c        | 131 +++++++++++++++++++++++++++++++++++------------
 2 files changed, 102 insertions(+), 33 deletions(-)

diff --git a/stand/common/bootstrap.h b/stand/common/bootstrap.h
index ba56f2e3c149..7dab530a368a 100644
--- a/stand/common/bootstrap.h
+++ b/stand/common/bootstrap.h
@@ -382,6 +382,10 @@ int mount_currdev(struct env_var *, int, const void *);
 void set_currdev(const char *devname);
 
 /* md.c */
+#define MD_FLAG_KERNEL	0x01
+
+extern struct devsw md_dev;
+int md_register(void *image, size_t size, unsigned int flags);
 void md_export_to_kernel(uint64_t start, uint64_t len);
 
 #endif /* !_BOOTSTRAP_H_ */
diff --git a/stand/common/md.c b/stand/common/md.c
index 604bf2ae64a8..04bafa8e4dec 100644
--- a/stand/common/md.c
+++ b/stand/common/md.c
@@ -33,6 +33,36 @@
 #include "bootstrap.h"
 
 #define	MD_BLOCK_SIZE	512
+#define	MD_FLAG_MASK	MD_FLAG_KERNEL
+
+struct md_info {
+	STAILQ_ENTRY(md_info) md_link;
+	void		*md_image;
+	size_t		 md_size;
+	unsigned int	 md_flags;
+	int		 md_unit;
+};
+
+static STAILQ_HEAD(, md_info) md_list = STAILQ_HEAD_INITIALIZER(md_list);
+static int md_next_unit;
+
+static int md_init(void);
+static int md_strategy(void *, int, daddr_t, size_t, char *, size_t *);
+static int md_open(struct open_file *, ...);
+static int md_close(struct open_file *);
+static int md_print(int);
+
+struct devsw md_dev = {
+	.dv_name = "md",
+	.dv_type = DEVT_DISK,
+	.dv_init = md_init,
+	.dv_strategy = md_strategy,
+	.dv_open = md_open,
+	.dv_close = md_close,
+	.dv_ioctl = noioctl,
+	.dv_print = md_print,
+	.dv_cleanup = nullsys,
+};
 
 /*
  * The kernel can accept a MD inline in the metadata, or out-of-line via
@@ -53,6 +83,44 @@ md_export_to_kernel(uint64_t start, uint64_t len)
 	unit++;
 }
 
+static struct md_info *
+md_get_info(int unit)
+{
+	struct md_info *md;
+
+	STAILQ_FOREACH(md, &md_list, md_link) {
+		if (md->md_unit == unit)
+			return (md);
+	}
+	return (NULL);
+}
+
+int
+md_register(void *image, size_t size, unsigned int flags)
+{
+	struct md_info *md;
+
+	if (image == NULL || size == 0 || size % MD_BLOCK_SIZE != 0 ||
+	    (flags & ~MD_FLAG_MASK) != 0) {
+		errno = EINVAL;
+		return (-1);
+	}
+	md = malloc(sizeof(*md));
+	if (md == NULL) {
+		errno = ENOMEM;
+		return (-1);
+	}
+	md->md_image = image;
+	md->md_size = size;
+	md->md_flags = flags;
+	md->md_unit = md_next_unit++;
+	STAILQ_INSERT_TAIL(&md_list, md, md_link);
+
+	if ((flags & MD_FLAG_KERNEL) != 0)
+		md_export_to_kernel((uintptr_t)image, size);
+	return (md->md_unit);
+}
+
 #ifdef MD_IMAGE_SIZE
 
 #if (MD_IMAGE_SIZE == 0 || MD_IMAGE_SIZE % MD_BLOCK_SIZE)
@@ -72,30 +140,16 @@ static struct {
 	.start = "MFS Filesystem goes here",
 	.end = "MFS Filesystem had better STOP here",
 };
-
-/* devsw I/F */
-static int md_init(void);
-static int md_strategy(void *, int, daddr_t, size_t, char *, size_t *);
-static int md_open(struct open_file *, ...);
-static int md_close(struct open_file *);
-static int md_print(int);
-
-struct devsw md_dev = {
-	.dv_name = "md",
-	.dv_type = DEVT_DISK,
-	.dv_init = md_init,
-	.dv_strategy = md_strategy,
-	.dv_open = md_open,
-	.dv_close = md_close,
-	.dv_ioctl = noioctl,
-	.dv_print = md_print,
-	.dv_cleanup = nullsys,
-};
+#endif
 
 static int
 md_init(void)
 {
 
+#ifdef MD_IMAGE_SIZE
+	if (md_register(md_image.start, MD_IMAGE_SIZE, 0) < 0)
+		return (errno);
+#endif
 	return (0);
 }
 
@@ -104,30 +158,32 @@ md_strategy(void *devdata, int rw, daddr_t blk, size_t size,
     char *buf, size_t *rsize)
 {
 	struct devdesc *dev = (struct devdesc *)devdata;
+	struct md_info *md;
 	size_t ofs;
 
-	if (dev->d_unit != 0)
+	md = md_get_info(dev->d_unit);
+	if (md == NULL)
 		return (ENXIO);
 
-	if (blk < 0 || blk >= (MD_IMAGE_SIZE / MD_BLOCK_SIZE))
+	if (blk < 0 || (uintmax_t)blk >= md->md_size / MD_BLOCK_SIZE)
 		return (EIO);
 
 	if (size % MD_BLOCK_SIZE)
 		return (EIO);
 
 	ofs = blk * MD_BLOCK_SIZE;
-	if ((ofs + size) > MD_IMAGE_SIZE)
-		size = MD_IMAGE_SIZE - ofs;
+	if (size > md->md_size - ofs)
+		size = md->md_size - ofs;
 
 	if (rsize != NULL)
 		*rsize = size;
 
 	switch (rw & F_MASK) {
 	case F_READ:
-		bcopy(md_image.start + ofs, buf, size);
+		bcopy((char *)md->md_image + ofs, buf, size);
 		return (0);
 	case F_WRITE:
-		bcopy(buf, md_image.start + ofs, size);
+		bcopy(buf, (char *)md->md_image + ofs, size);
 		return (0);
 	}
 
@@ -144,7 +200,7 @@ md_open(struct open_file *f, ...)
 	dev = va_arg(ap, struct devdesc *);
 	va_end(ap);
 
-	if (dev->d_unit != 0)
+	if (md_get_info(dev->d_unit) == NULL)
 		return (ENXIO);
 
 	return (0);
@@ -156,18 +212,27 @@ md_close(struct open_file *f)
 	struct devdesc *dev;
 
 	dev = (struct devdesc *)(f->f_devdata);
-	return ((dev->d_unit != 0) ? ENXIO : 0);
+	return (md_get_info(dev->d_unit) == NULL ? ENXIO : 0);
 }
 
 static int
 md_print(int verbose)
 {
+	struct md_info *md;
+	int ret;
 
+	if (STAILQ_EMPTY(&md_list))
+		return (0);
 	printf("%s devices:", md_dev.dv_name);
-	if (pager_output("\n") != 0)
-		return (1);
-
-	printf("MD (%u bytes)", MD_IMAGE_SIZE);
-	return (pager_output("\n"));
+	if ((ret = pager_output("\n")) != 0)
+		return (ret);
+
+	STAILQ_FOREACH(md, &md_list, md_link) {
+		printf("    %s%d:    %ju X %u blocks", md_dev.dv_name,
+		    md->md_unit, (uintmax_t)(md->md_size / MD_BLOCK_SIZE),
+		    MD_BLOCK_SIZE);
+		if ((ret = pager_output("\n")) != 0)
+			return (ret);
+	}
+	return (0);
 }
-#endif