Files
u-boot/drivers/virtio/fs_file.c
Simon Glass ce5ca9b204 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>
2025-06-30 08:35:18 -06:00

137 lines
3.2 KiB
C

// 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;
}