virtio: Add support for files

Add an implementation of virtio-fs files, including looking them up and
reading them.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass
2025-06-26 07:43:44 -06:00
parent 310b668cd7
commit ce5ca9b204
4 changed files with 170 additions and 1 deletions

View File

@@ -12,4 +12,4 @@ obj-$(CONFIG_VIRTIO_SANDBOX_EMUL) += sandbox_emul.o emul_blk.o
obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
obj-$(CONFIG_VIRTIO_RNG) += virtio_rng.o
obj-$(CONFIG_VIRTIO_FS) += fs.o fs_dir.o
obj-$(CONFIG_VIRTIO_FS) += fs.o fs_dir.o fs_file.o

View File

@@ -105,6 +105,22 @@ static int virtio_fs_dir_close(struct udevice *dev, struct fs_dir_stream *strm)
return 0;
}
static int open_file(struct udevice *dev, const char *leaf,
enum dir_open_flags_t oflags, struct udevice **filp)
{
struct udevice *fil;
int ret;
log_debug("start '%s'\n", leaf);
ret = virtio_fs_setup_file(dev, leaf, oflags, &fil);
log_debug("ret %d\n", ret);
if (ret)
return log_msg_ret("dof", ret);
*filp = fil;
return 0;
}
static int virtio_fs_dir_remove(struct udevice *dev)
{
struct virtio_fs_dir_priv *dir_priv = dev_get_priv(dev);
@@ -124,6 +140,7 @@ static struct dir_ops virtio_fs_dir_ops = {
.open = virtio_fs_dir_open,
.read = virtio_fs_dir_read,
.close = virtio_fs_dir_close,
.open_file = open_file,
};
static const struct udevice_id dir_ids[] = {

136
drivers/virtio/fs_file.c Normal file
View File

@@ -0,0 +1,136 @@
// SPDX-License-Identifier: GPL-2.0
/*
* U-Boot Virtio-FS files
*
* Copyright 2025 Simon Glass <sjg@chromium.org>
*
* Supports access to files in virtio-fs
*/
#define LOG_CATEGORY UCLASS_VIRTIO
#include <dm.h>
#include <file.h>
#include <fs.h>
#include <malloc.h>
#include <virtio_fs.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <linux/fuse.h>
#include "fs_internal.h"
/**
* struct file_priv - Information about a virtio file
*
* @flags: Open-mode flags
* @backing_id: Backing ID for the file
* @fh: Unique filehandle for the file
* @size: Size of the file
*/
struct file_priv {
u64 nodeid;
enum dir_open_flags_t flags;
u64 fh;
};
static ssize_t virtio_fs_read_iter(struct udevice *dev, struct iov_iter *iter,
loff_t pos)
{
struct file_priv *priv = dev_get_priv(dev);
struct udevice *dir = dev_get_parent(dev);
struct udevice *fsdev = dev_get_parent(dir);
ssize_t ret;
log_debug("start dev '%s' len %zx\n", dev->name, iter->count);
ret = virtio_fs_read(fsdev, priv->nodeid, priv->fh, pos,
iter_iov_ptr(iter), iter_iov_avail(iter));
if (ret < 0)
return log_msg_ret("vfr", ret);
iter_advance(iter, ret);
log_debug("read %zx bytes\n", ret);
return ret;
}
static int virtio_fs_file_remove(struct udevice *dev)
{
struct virtio_fs_dir_priv *dir_priv = dev_get_priv(dev);
if (*dir_priv->path) {
int ret;
ret = virtio_fs_forget(dev, dir_priv->inode);
if (ret)
return log_msg_ret("vfr", ret);
}
return 0;
}
static struct file_ops virtio_fs_file_ops = {
.read_iter = virtio_fs_read_iter,
};
static const struct udevice_id file_ids[] = {
{ .compatible = "virtio-fs,file" },
{ }
};
U_BOOT_DRIVER(virtio_fs_file) = {
.name = "virtio_fs_file",
.id = UCLASS_FILE,
.of_match = file_ids,
.remove = virtio_fs_file_remove,
.ops = &virtio_fs_file_ops,
.priv_auto = sizeof(struct file_priv),
.flags = DM_FLAG_ACTIVE_DMA,
};
int virtio_fs_setup_file(struct udevice *dir, const char *leaf,
enum dir_open_flags_t oflags, struct udevice **devp)
{
struct udevice *fil, *fsdev = dev_get_parent(dir);
struct virtio_fs_dir_priv *dir_priv = dev_get_priv(dir);
struct file_uc_priv *file_uc_priv;
struct file_priv *file_priv;
struct fuse_entry_out out;
uint flags;
u64 fh;
int ret;
log_debug("dir '%s' inode %llx leaf '%s' oflags %d\n", dir->name,
dir_priv->inode, leaf, oflags);
ret = virtio_fs_lookup_(fsdev, dir_priv->inode, leaf, &out);
if (ret) {
log_debug("lookup fail ret=%d\n", ret);
return log_msg_ret("vfl", ret);
}
log_debug("open nodeid %lld\n", out.nodeid);
ret = virtio_fs_open_file(fsdev, out.nodeid, oflags, &fh, &flags);
if (ret) {
log_debug("fail ret=%d\n", ret);
return log_msg_ret("vfo", ret);
}
log_debug("result fh %llx flags %x\n", fh, flags);
ret = file_add_probe(dir, DM_DRIVER_REF(virtio_fs_file), leaf,
out.attr.size, flags, &fil);
if (ret) {
/* TODO: close file? */
return log_msg_ret("vfp", ret);
}
file_priv = dev_get_priv(fil);
file_priv->nodeid = out.nodeid;
file_priv->fh = fh;
file_priv->flags = flags;
file_uc_priv = dev_get_uclass_priv(fil);
log_debug("opened file dev '%s' inode %lld size %zx\n", fil->name,
file_priv->nodeid, file_uc_priv->size);
*devp = fil;
return 0;
}

View File

@@ -162,4 +162,20 @@ long virtio_fs_read(struct udevice *dev, u64 nodeid, u64 fh, u64 offset,
int virtio_fs_setup_dir(struct udevice *fsdev, const char *path,
struct udevice **devp);
/**
* virtio_fs_setup_file() - Look up and open a file, creating a new device
*
* Sets up a new open file: performs a lookup for the file within a given
* directory, opens it via FUSE, then probes and adds a new 'file' device to
* represent the opened file
*
* @dir: The directory device in which to look for the file
* @leaf: The name of the file to open (the leaf name)
* @oflags: Open flags to use when opening the file
* @devp: On success, returns a pointer to the newly created file device
* Return: 0 on success, -ve on error
*/
int virtio_fs_setup_file(struct udevice *dir, const char *leaf,
enum dir_open_flags_t flags, struct udevice **devp);
#endif