[Concept,19/34] vfs: Add boot integration and block-device mount

Message ID 20260403140523.1998228-20-sjg@u-boot.org
State New
Headers
Series Add a virtual filesystem (VFS) layer to U-Boot |

Commit Message

Simon Glass April 3, 2026, 2:04 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

Add bootflow support for block-backed VFS filesystems. When a filesystem
with a block device is mounted, its bootdev can discover boot scripts
and extlinux configs through the standard bootmeth interface. Non-block
filesystems (e.g. hostfs) return -ENOENT so the bootflow scanner skips
them gracefully.

Add fs_mount_blkdev() and fs_mount_blkdev_auto() for mounting
filesystems from block devices. Auto-detection iterates all UCLASS_FS
drivers whose name ends in '_fs' until one succeeds. Reject mounts on
already-occupied mount points with -EBUSY.

Extend the mount command to support 'mount <iface> <dev:part> <path>'
and 'mount -t <type> <iface> <dev:part> <path>' syntax.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 cmd/fs.c       | 45 ++++++++++++++++++++++++++++++++++++++++++---
 fs/fs-uclass.c | 30 +++++++++++++++++++++++++++---
 include/fs.h   |  2 ++
 3 files changed, 71 insertions(+), 6 deletions(-)
  

Patch

diff --git a/cmd/fs.c b/cmd/fs.c
index 694222e5d10..7231e4efcd1 100644
--- a/cmd/fs.c
+++ b/cmd/fs.c
@@ -8,12 +8,15 @@ 
  * Copyright 2026 Simon Glass <sjg@chromium.org>
  */
 
+#include <blk.h>
 #include <command.h>
 #include <dm.h>
 #include <env.h>
 #include <file.h>
+#include <fs.h>
 #include <fs_legacy.h>
 #include <mapmem.h>
+#include <part.h>
 #include <vfs.h>
 #include <dm/uclass.h>
 
@@ -26,7 +29,7 @@  static int mount_handler(int argc, char *const argv[])
 {
 	struct udevice *vfs, *fsdev, *dir, *mnt;
 	const char *subpath;
-	int ret;
+	int part_num, ret;
 
 	vfs = vfs_root();
 	if (!vfs)
@@ -37,6 +40,39 @@  static int mount_handler(int argc, char *const argv[])
 		return 0;
 	}
 
+	/* mount -t <type> <interface> <dev:part> <mountpoint> */
+	if (!strcmp(argv[1], "-t")) {
+		struct disk_partition info;
+		struct blk_desc *desc;
+
+		if (argc < 6)
+			return -EINVAL;
+
+		ret = blk_get_device_part_str(argv[3], argv[4], &desc,
+					      &info, 1);
+		if (ret < 0)
+			return ret;
+		part_num = ret;
+
+		return fs_mount_blkdev(argv[2], desc, part_num, &info,
+				       argv[5]);
+	}
+
+	/* mount <iface> <dev:part> <mountpoint> - auto-detect type */
+	if (argc == 4) {
+		struct disk_partition info;
+		struct blk_desc *desc;
+
+		ret = blk_get_device_part_str(argv[1], argv[2], &desc,
+					      &info, 1);
+		if (ret < 0)
+			return ret;
+		part_num = ret;
+
+		return fs_mount_blkdev_auto(desc, part_num, &info, argv[3]);
+	}
+
+	/* mount <dev> <mountpoint> - mount an existing UCLASS_FS device */
 	if (argc < 3)
 		return -EINVAL;
 
@@ -71,11 +107,14 @@  static int do_mount(struct cmd_tbl *cmdtp, int flag, int argc,
 }
 
 U_BOOT_CMD(
-	mount,	3,	1,	do_mount,
+	mount,	6,	1,	do_mount,
 	"mount a filesystem",
 	"[<dev> <mountpoint>]\n"
 	"    - With no args, list all mounts\n"
-	"    - Mount device 'dev' at 'mountpoint'"
+	"mount <iface> <dev:part> <mountpoint>\n"
+	"    - Auto-detect and mount a filesystem\n"
+	"mount -t <type> <iface> <dev:part> <mountpoint>\n"
+	"    - Mount a specific filesystem type"
 );
 
 static int umount_handler(const char *path)
diff --git a/fs/fs-uclass.c b/fs/fs-uclass.c
index 4492ff60522..435fd32bc75 100644
--- a/fs/fs-uclass.c
+++ b/fs/fs-uclass.c
@@ -7,7 +7,9 @@ 
 
 #define LOG_CATEGORY	UCLASS_FS
 
+#include <blk.h>
 #include <bootdev.h>
+#include <bootflow.h>
 #include <bootmeth.h>
 #include <dir.h>
 #include <dm.h>
@@ -124,16 +126,38 @@  static int fs_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
 			   struct bootflow *bflow)
 {
 	struct udevice *fsdev = dev_get_parent(dev);
+	struct fs_plat *plat = dev_get_uclass_plat(fsdev);
+	char name[60];
 	int ret;
 
 	log_debug("get_bootflow fs '%s'\n", fsdev->name);
 
-	/* for now, always fail here as we don't have FS support in bootmeths */
-	return -ENOENT;
+	/*
+	 * Block-backed filesystems expose their blk device and partition so
+	 * that existing bootmeths (script, extlinux) can read files using the
+	 * legacy FS layer.
+	 */
+	if (!plat->desc || !plat->desc->bdev)
+		return log_msg_ret("blk", -ENOENT);
+
+	bflow->blk = plat->desc->bdev;
+	bflow->part = plat->part_num;
+
+	snprintf(name, sizeof(name), "%s.bootflow", fsdev->name);
+	bflow->name = strdup(name);
+	if (!bflow->name)
+		return log_msg_ret("nam", -ENOMEM);
+
+	bflow->state = BOOTFLOWST_MEDIA;
 
 	ret = bootmeth_check(bflow->method, iter);
 	if (ret)
-		return log_msg_ret("check", ret);
+		return log_msg_ret("chk", ret);
+
+	/* Let the bootmeth discover files (extlinux.conf, boot.scr, etc.) */
+	ret = bootmeth_read_bootflow(bflow->method, bflow);
+	if (ret)
+		return log_msg_ret("rd", ret);
 
 	return 0;
 }
diff --git a/include/fs.h b/include/fs.h
index efca9b80611..925f810902b 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -30,11 +30,13 @@  enum {
  *
  * @name: Name of the filesystem, or empty if not available
  * @desc: Block device descriptor, or NULL if not block-backed
+ * @part_num: Partition number (valid only when @desc is non-NULL)
  * @part: Partition information (valid only when @desc is non-NULL)
  */
 struct fs_plat {
 	char name[FS_MAX_NAME_LEN];
 	struct blk_desc *desc;
+	int part_num;
 	struct disk_partition part;
 };