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>
164 lines
3.4 KiB
C
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;
|
|
}
|