Files
u-boot/drivers/virtio/fs_compat.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

164 lines
3.4 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* U-Boot Virtio-FS compatibility layer, to allow use with the legacy
* filesystem-layer
*
* Copyright 2025 Simon Glass <sjg@chromium.org>
*
*/
#define LOG_CATEGORY UCLASS_VIRTIO
#include <dir.h>
#include <dm.h>
#include <file.h>
#include <fs.h>
#include <malloc.h>
#include <virtio.h>
#include <virtio_fs.h>
#include <linux/fuse.h>
#include "fs_internal.h"
static struct udevice *fs_dev;
int virtio_fs_compat_opendir(const char *fname, struct fs_dir_stream **strmp)
{
struct udevice *dev;
int ret;
log_debug("starting fs_dev %p\n", fs_dev);
log_debug("lookup dev '%s' fname '%s'\n", fs_dev->name, fname);
ret = fs_lookup_dir(fs_dev, fname, &dev);
if (ret)
return log_msg_ret("vld", ret);
log_debug("open\n");
ret = dir_open(dev, strmp);
if (ret)
return log_msg_ret("vdo", ret);
return 0;
}
int virtio_fs_compat_readdir(struct fs_dir_stream *strm,
struct fs_dirent **dentp)
{
struct fs_dirent *dent;
int ret;
log_debug("read dev '%s'\n", fs_dev->name);
dent = malloc(sizeof(struct fs_dirent));
if (!dent)
return log_msg_ret("vrD", -ENOMEM);
ret = dir_read(strm->dev, strm, dent);
if (ret) {
free(dent);
return log_msg_ret("vrd", ret);
}
*dentp = dent;
log_debug("read done\n");
return 0;
}
void virtio_fs_compat_closedir(struct fs_dir_stream *strm)
{
int ret;
log_debug("close dev '%s'\n", fs_dev->name);
ret = dir_close(strm->dev, strm);
if (ret)
log_err("dir_close() failed: %dE\n", ret);
}
int virtio_fs_compat_probe(struct blk_desc *fs_dev_desc,
struct disk_partition *fs_partition)
{
struct udevice *dev;
int ret;
/*
* at present, sandbox cannot support virtiofs fully, so add a
* work-around here
*/
if (IS_ENABLED(CONFIG_SANDBOX))
return log_msg_ret("vfc", -ENOENT);
ret = uclass_first_device_err(UCLASS_FS, &dev);
if (ret) {
printf("No filesystem (err %dE)\n", ret);
return ret;
}
ret = fs_mount(dev);
if (ret && ret != -EISCONN) {
printf("Cannot mount filesystem (err %dE)\n", ret);
return ret;
}
fs_dev = dev;
log_debug("fs_dev %p\n", fs_dev);
return 0;
}
int virtio_fs_compat_size(const char *fname, loff_t *sizep)
{
struct fuse_entry_out out;
const char *leaf;
char *subdir;
int ret;
log_debug("filename '%s'\n", fname);
ret = fs_split_path(fname, &subdir, &leaf);
if (ret)
return log_msg_ret("vcp", ret);
log_debug("subdir '%s' leaf '%s'\n", subdir, leaf);
ret = virtio_fs_lookup_(fs_dev, virtio_fs_get_root(fs_dev), fname,
&out);
if (ret)
return log_msg_ret("vcl", ret);
log_debug("inode %llx size %llx\n", out.nodeid, out.attr.size);
*sizep = out.attr.size;
return 0;
}
int virtio_fs_compat_read(const char *fname, void *buf, loff_t offset,
loff_t len, loff_t *actread)
{
struct udevice *dir, *fil;
const char *leaf;
char *subdir;
long nread;
int ret;
log_debug("load '%s'\n", fname);
ret = fs_split_path(fname, &subdir, &leaf);
if (ret)
return log_msg_ret("fcr", ret);
log_debug("subdir '%s' leaf '%s'\n", subdir, leaf);
ret = fs_lookup_dir(fs_dev, subdir, &dir);
if (ret)
return log_msg_ret("fcl", ret);
log_debug("dir '%s'\n", dir->name);
ret = virtio_fs_setup_file(dir, leaf, DIR_O_RDONLY, &fil);
log_debug("virtio_fs_file_open returned %d\n", ret);
if (ret)
return log_msg_ret("fco", ret);
log_debug("reading file '%s'\n", fil->name);
nread = file_read_at(fil, buf, offset, len);
if (nread < 0)
return log_msg_ret("fco", nread);
*actread = nread;
return 0;
}