Files
u-boot/fs/fs-uclass.c
Simon Glass 5ab90a9307 virtio: Plumb virtio-fs into the legacy filesystem code
Add compatibility function to support a single virtio-fs via the normal
'ls' and 'load' commands. Other commands are not supported for now.

Add a workaround for the fact that virtiofs does not use a block device.
The existing filesystem layer does not support non-block filesystems -
sandbox's hostfs mostly bypasses this code.

Make sure that sandbox does not try to mount a virtio-fs as this does
not work at present. It will require either a fake driver for virtio-fs
which connects to host files, or possibly something involving FUSE.

Series-to: concept
Cover-letter:
virtio: Support virtio-fs
This series introduces support for virtio-fs, a filesystem which
provides access to host files from within a QEMU guest OS.

A new filesystem driver is created with support for the three uclasses
(FS, DIR, FILE). A compatibility layer is added as well, so that the
existing cmdline work as expected.

Only listing directories and reading files are supported so far.

Since sandbox works by using a NULL blk_desc, a workaround is added for
now. Once we switch commands (and bootstd!) over to the new filesystem
approach, this will go away.

It is possible to test this using something like:

   ./scripts/build-qemu -a x86  -rs -D .

then within U-Boot:

   ls virtio 0
END

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-30 11:57:41 -06:00

148 lines
2.9 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Implementation of a filesystem, e.g. on a partition
*
* Copyright 2025 Simon Glass <sjg@chromium.org>
*/
#define LOG_CATEGORY UCLASS_FS
#include <bootdev.h>
#include <bootmeth.h>
#include <dm.h>
#include <fs.h>
#include <dm/device-internal.h>
int fs_split_path(const char *fname, char **subdirp, const char **leafp)
{
char *subdir, *p;
if (!*fname)
return log_msg_ret("fsp", -EINVAL);
/* allocate space for the whole filename, for simplicity */
subdir = strdup(fname);
if (!subdir)
return log_msg_ret("fsp", -ENOMEM);
p = strrchr(subdir, '/');
if (p) {
*leafp = p + 1;
*p = '\0';
} else {
*leafp = fname;
strcpy(subdir, "/");
}
*subdirp = subdir;
return 0;
}
int fs_lookup_dir(struct udevice *dev, const char *path, struct udevice **dirp)
{
struct fs_ops *ops = fs_get_ops(dev);
return ops->lookup_dir(dev, path, dirp);
}
int fs_mount(struct udevice *dev)
{
struct fs_ops *ops = fs_get_ops(dev);
int ret;
ret = ops->mount(dev);
if (ret)
return log_msg_ret("fsm", ret);
ret = bootdev_setup_for_dev(dev, "fs_bootdev");
if (ret)
return log_msg_ret("fss", ret);
return 0;
}
int fs_unmount(struct udevice *dev)
{
struct fs_ops *ops = fs_get_ops(dev);
return ops->unmount(dev);
}
static int fs_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
struct bootflow *bflow)
{
struct udevice *fsdev = dev_get_parent(dev);
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;
ret = bootmeth_check(bflow->method, iter);
if (ret)
return log_msg_ret("check", ret);
return 0;
}
static int fs_bootdev_bind(struct udevice *dev)
{
struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
/*
* we don't know what priority to give this, so pick something a little
* slow for now
*/
ucp->prio = BOOTDEVP_3_INTERNAL_SLOW;
return 0;
}
static int fs_bootdev_hunt(struct bootdev_hunter *info, bool show)
{
struct udevice *dev;
int ret;
/* mount all filesystems, which will create bootdevs for each */
uclass_foreach_dev_probe(UCLASS_FS, dev) {
ret = fs_mount(dev);
if (ret)
log_warning("Failed to mount filesystem '%s'\n",
dev->name);
}
return 0;
}
struct bootdev_ops fs_bootdev_ops = {
.get_bootflow = fs_get_bootflow,
};
static const struct udevice_id fs_bootdev_ids[] = {
{ .compatible = "u-boot,bootdev-fs" },
{ }
};
U_BOOT_DRIVER(fs_bootdev) = {
.name = "fs_bootdev",
.id = UCLASS_BOOTDEV,
.ops = &fs_bootdev_ops,
.bind = fs_bootdev_bind,
.of_match = fs_bootdev_ids,
};
BOOTDEV_HUNTER(fs_bootdev_hunter) = {
.prio = BOOTDEVP_3_INTERNAL_SLOW,
.uclass = UCLASS_FS,
.hunt = fs_bootdev_hunt,
.drv = DM_DRIVER_REF(fs_bootdev),
};
UCLASS_DRIVER(fs) = {
.name = "fs",
.id = UCLASS_FS,
.per_device_auto = sizeof(struct fs_priv),
.per_device_plat_auto = sizeof(struct fs_plat),
};