@@ -2987,6 +2987,14 @@ config CMD_FS_LEGACY
include load, save, ls, size, mkdir, rm, ln, mv, fstype and
fstypes.
+config CMD_VFS
+ bool "fs - virtual filesystem commands"
+ depends on VFS
+ default y if SANDBOX
+ help
+ Provides the 'fs' command with mount, umount and ls subcommands
+ for the virtual filesystem layer.
+
config CMD_FS_UUID
bool "fsuuid command"
default y if SANDBOX
@@ -94,6 +94,7 @@ obj-$(CONFIG_CMD_FPGA) += fpga.o
obj-$(CONFIG_CMD_LUKS) += luks.o
obj-$(CONFIG_CMD_FPGAD) += fpgad.o
obj-$(CONFIG_CMD_FS_LEGACY) += fs_legacy.o
+obj-$(CONFIG_CMD_VFS) += vfs.o
obj-$(CONFIG_CMD_FUSE) += fuse.o
obj-$(CONFIG_CMD_FWU_METADATA) += fwu_mdata.o
obj-$(CONFIG_CMD_GETTIME) += gettime.o
new file mode 100644
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * VFS commands - 'fs mount', 'fs umount'
+ *
+ * Provides a new 'fs' command with subcommands for the virtual filesystem
+ * layer, co-existing with the legacy filesystem commands in cmd/fs.c.
+ *
+ * Copyright 2026 Simon Glass <sjg@chromium.org>
+ */
+
+#include <command.h>
+#include <dm.h>
+#include <fs.h>
+#include <vfs.h>
+#include <dm/uclass.h>
+
+static int fs_mount_handler(int argc, char *const argv[])
+{
+ struct udevice *vfs, *fsdev, *dir;
+ int ret;
+
+ vfs = vfs_root();
+ if (!vfs)
+ return -ENXIO;
+
+ if (argc < 2) {
+ vfs_print_mounts();
+ return 0;
+ }
+
+ if (argc < 3)
+ return -EINVAL;
+
+ ret = uclass_get_device_by_name(UCLASS_FS, argv[1], &fsdev);
+ if (ret)
+ return ret;
+
+ ret = vfs_resolve(vfs, argv[2], &dir);
+ if (ret)
+ return ret;
+
+ return vfs_mount(vfs, dir, fsdev);
+}
+
+static int do_fs_mount(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int ret;
+
+ if (argc == 2)
+ return CMD_RET_USAGE;
+
+ ret = fs_mount_handler(argc, argv);
+ if (ret) {
+ printf("fs mount failed: %dE\n", ret);
+ return CMD_RET_FAILURE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int fs_umount_handler(const char *path)
+{
+ struct udevice *vfs;
+
+ vfs = vfs_root();
+ if (!vfs)
+ return -ENXIO;
+
+ return vfs_umount_path(vfs, path);
+}
+
+static int do_fs_umount(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int ret;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ ret = fs_umount_handler(argv[1]);
+ if (ret) {
+ printf("fs umount failed: %dE\n", ret);
+ return CMD_RET_FAILURE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+U_BOOT_LONGHELP(fs,
+ "mount [<dev> <mountpoint>] - list or create mounts\n"
+ "fs umount <mountpoint> - unmount a filesystem");
+
+U_BOOT_CMD_WITH_SUBCMDS(fs, "Filesystem operations", fs_help_text,
+ U_BOOT_SUBCMD_MKENT(mount, 3, 1, do_fs_mount),
+ U_BOOT_SUBCMD_MKENT(umount, 2, 1, do_fs_umount));
@@ -247,4 +247,31 @@ static int dm_test_vfs_mount(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_vfs_mount, UTF_SCAN_FDT);
+
+/* Test the VFS layer using the 'fs' command */
+static int dm_test_vfs_cmd(struct unit_test_state *uts)
+{
+ ut_assertok(vfs_init());
+
+ /* Mount the sandbox FS at /host */
+ ut_assertok(run_command("fs mount hostfs /host", 0));
+ ut_assert_console_end();
+
+ /* Verify it appears in the mount list */
+ ut_assertok(run_command("fs mount", 0));
+ ut_assert_nextlinen("/host");
+ ut_assert_console_end();
+
+ /* Unmount */
+ ut_assertok(run_command("fs umount /host", 0));
+ ut_assert_console_end();
+
+ /* Mount list should now be empty */
+ ut_assertok(run_command("fs mount", 0));
+ ut_assert_console_end();
+
+ return 0;
+}
+DM_TEST(dm_test_vfs_cmd, UTF_SCAN_FDT);
+
#endif