
From: Simon Glass <sjg@chromium.org> Add an implementation of virtio-fs files, including looking them up and reading them. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/virtio/Makefile | 2 +- drivers/virtio/fs_dir.c | 17 +++++ drivers/virtio/fs_file.c | 136 +++++++++++++++++++++++++++++++++++ drivers/virtio/fs_internal.h | 16 +++++ 4 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 drivers/virtio/fs_file.c diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 3e985f7a5e7..37b805a9c24 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -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 diff --git a/drivers/virtio/fs_dir.c b/drivers/virtio/fs_dir.c index 1bc536f56bf..b346ded8a09 100644 --- a/drivers/virtio/fs_dir.c +++ b/drivers/virtio/fs_dir.c @@ -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[] = { diff --git a/drivers/virtio/fs_file.c b/drivers/virtio/fs_file.c new file mode 100644 index 00000000000..adb428fcd3e --- /dev/null +++ b/drivers/virtio/fs_file.c @@ -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; +} diff --git a/drivers/virtio/fs_internal.h b/drivers/virtio/fs_internal.h index c71c7ca48a7..460a79d9854 100644 --- a/drivers/virtio/fs_internal.h +++ b/drivers/virtio/fs_internal.h @@ -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 -- 2.43.0