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:
@@ -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
|
||||
|
||||
@@ -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
136
drivers/virtio/fs_file.c
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user