virtio: Add top-level functions for virtio-fs
Provide access to the virtual queue and some functions for sending various FUSE messages. Add myself as a maintainer of virtio. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
@@ -85,4 +85,17 @@ config VIRTIO_RNG
|
||||
help
|
||||
This is the virtual random number generator driver. It can be used
|
||||
with QEMU based targets.
|
||||
|
||||
config VIRTIO_FS
|
||||
bool "virtio filesystem driver"
|
||||
depends on VIRTIO && FS
|
||||
default y
|
||||
help
|
||||
Provides support for virtio-fs which provides access to host files
|
||||
within the guest OS. This needs a user-space helper (virtiofsd) when
|
||||
running QEMU - see https://virtio-fs.gitlab.io/ for details.
|
||||
|
||||
A specification for the protocol is available at
|
||||
https://docs.oasis-open.org/virtio/virtio/v1.3/virtio-v1.3.html
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -12,3 +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
|
||||
|
||||
427
drivers/virtio/fs.c
Normal file
427
drivers/virtio/fs.c
Normal file
@@ -0,0 +1,427 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* U-Boot Virtio-FS Driver
|
||||
*
|
||||
* Copyright 2025 Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* This driver provides U-Boot with the ability to access a virtio-fs
|
||||
* device, allowing the bootloader to read files from a shared directory
|
||||
* on the host. This is particularly useful for loading kernels, device
|
||||
* tree blobs, and other boot-time resources.
|
||||
*
|
||||
* The driver is implemented using the U-Boot driver model and the virtio
|
||||
* uclass. It communicates with the host using the FUSE protocol over
|
||||
* virtqueues.
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY UCLASS_VIRTIO
|
||||
|
||||
#include <dir.h>
|
||||
#include <dm.h>
|
||||
#include <fs.h>
|
||||
#include <log.h>
|
||||
#include <virtio.h>
|
||||
#include <virtio_fs.h>
|
||||
#include <virtio_ring.h>
|
||||
#include <linux/fuse.h>
|
||||
#include "fs_internal.h"
|
||||
|
||||
#define MAX_FNAME_LEN 256 /* including \0 terminator */
|
||||
#define VIRTIO_FS_TAG_SIZE 36
|
||||
|
||||
/**
|
||||
* struct virtio_fs_config - Configuration info for virtio-fs
|
||||
*
|
||||
* Modelled on Linux v6.15 include/uapi/linux/type.h
|
||||
*
|
||||
* @tag: filesystem name padded with NUL
|
||||
*/
|
||||
struct __packed virtio_fs_config {
|
||||
u8 tag[VIRTIO_FS_TAG_SIZE];
|
||||
__le32 unused1;
|
||||
__le32 unused2;
|
||||
};
|
||||
|
||||
/*
|
||||
* Driver-private data
|
||||
*
|
||||
* @tag: Tag for the filesystem
|
||||
* @root: inode of the root node, or 0 if not known
|
||||
* @vdev: virtio device to which this FS is attached
|
||||
* @vq: Virtual queue to use
|
||||
* @config: Configuration read from QEMU
|
||||
* @root_inode: Inode of the root directory exported into QEMU
|
||||
* @next_id: ID to use for the next FUSE request
|
||||
*/
|
||||
struct virtio_fs_priv {
|
||||
char tag[VIRTIO_FS_TAG_SIZE + 1];
|
||||
struct virtio_device *vdev;
|
||||
struct virtqueue *vq;
|
||||
struct virtio_fs_config config;
|
||||
u64 root_inode;
|
||||
int next_id;
|
||||
};
|
||||
|
||||
u64 virtio_fs_get_root(struct udevice *dev)
|
||||
{
|
||||
struct virtio_fs_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return priv->root_inode;
|
||||
}
|
||||
|
||||
/**
|
||||
* virtio_fs_xfer() - Perform a transfer of a FUSE request
|
||||
*
|
||||
* @dev: virtio-fs device to use (UCLASS_FS)
|
||||
* @inhdr: FUSE header to send
|
||||
* @in: Extra data to send (must be present)
|
||||
* @insize: Size of data to send
|
||||
* @outhdr: Returns the output header received via FUSE
|
||||
* @out: Place to put extra output data (NULL if none)
|
||||
* @outsize: Size of output buffer at @out (must be 0 if @out is NULL)
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
static int virtio_fs_xfer(struct udevice *dev, struct fuse_in_header *inhdr,
|
||||
const void *in, int insize,
|
||||
struct fuse_out_header *outhdr, void *out,
|
||||
int outsize)
|
||||
{
|
||||
struct virtio_fs_priv *priv = dev_get_priv(dev);
|
||||
struct virtqueue *vq = priv->vq;
|
||||
struct virtio_sg sg[4];
|
||||
struct virtio_sg *sgs[4];
|
||||
uint dummy_len;
|
||||
int i, ret;
|
||||
|
||||
inhdr->unique = priv->next_id++;
|
||||
|
||||
sg[0].addr = inhdr;
|
||||
sg[0].length = sizeof(*inhdr);
|
||||
sg[1].addr = (void *)in;
|
||||
sg[1].length = insize;
|
||||
sg[2].addr = outhdr;
|
||||
sg[2].length = sizeof(*outhdr);
|
||||
sg[3].addr = out;
|
||||
sg[3].length = outsize;
|
||||
for (i = 0; i < 4; i++)
|
||||
sgs[i] = &sg[i];
|
||||
inhdr->len = sizeof(*inhdr) + insize;
|
||||
outhdr->len = sizeof(*outhdr) + outsize;
|
||||
|
||||
log_debug("sg[1].addr %p sg[3].length %zx\n", sg[1].addr, sg[3].length);
|
||||
ret = virtqueue_add(vq, sgs, 2, out ? 2 : 1);
|
||||
if (ret) {
|
||||
log_err("Failed to add buffers to virtqueue\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtqueue_kick(vq);
|
||||
|
||||
log_debug("wait...");
|
||||
while (!virtqueue_get_buf(vq, &dummy_len))
|
||||
;
|
||||
log_debug("done\n");
|
||||
if (outhdr->error)
|
||||
return log_msg_ret("vix", outhdr->error);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int virtio_fs_lookup_(struct udevice *dev, u64 nodeid, const char *name,
|
||||
struct fuse_entry_out *out)
|
||||
{
|
||||
struct fuse_in_header inhdr = {};
|
||||
struct fuse_out_header outhdr;
|
||||
int name_len = strlen(name) + 1;
|
||||
int ret;
|
||||
|
||||
inhdr.opcode = FUSE_LOOKUP;
|
||||
inhdr.nodeid = nodeid;
|
||||
|
||||
ret = virtio_fs_xfer(dev, &inhdr, name, name_len, &outhdr, out,
|
||||
sizeof(struct fuse_entry_out));
|
||||
log_debug("len %x error %x unique %llx\n", outhdr.len, outhdr.error,
|
||||
outhdr.unique);
|
||||
if (ret)
|
||||
return log_msg_ret("vfl", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int virtio_fs_lookup(struct udevice *dev, const char *name, u64 *entryp)
|
||||
{
|
||||
struct virtio_fs_priv *priv = dev_get_priv(dev);
|
||||
struct fuse_entry_out out;
|
||||
int ret;
|
||||
|
||||
log_debug("dev '%s': lookup in inode %llx name '%s'\n", dev->name,
|
||||
priv->root_inode, name);
|
||||
ret = virtio_fs_lookup_(dev, priv->root_inode, name, &out);
|
||||
if (ret)
|
||||
return log_msg_ret("vfl", ret);
|
||||
*entryp = out.nodeid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int virtio_fs_forget(struct udevice *dev, u64 nodeid)
|
||||
{
|
||||
struct fuse_in_header inhdr = {};
|
||||
struct fuse_forget_in in;
|
||||
struct fuse_out_header outhdr;
|
||||
int ret;
|
||||
|
||||
inhdr.opcode = FUSE_FORGET;
|
||||
inhdr.nodeid = nodeid;
|
||||
in.nlookup = 1;
|
||||
|
||||
ret = virtio_fs_xfer(dev, &inhdr, &in, sizeof(in), &outhdr, NULL, 0);
|
||||
log_debug("len %x error %x unique %llx\n", outhdr.len, outhdr.error,
|
||||
outhdr.unique);
|
||||
if (ret)
|
||||
return log_msg_ret("vfl", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int virtio_fs_opendir(struct udevice *dev, u64 nodeid, u64 *fhp)
|
||||
{
|
||||
struct fuse_in_header inhdr = {};
|
||||
struct fuse_open_in in = {};
|
||||
struct fuse_out_header outhdr;
|
||||
struct fuse_open_out out;
|
||||
int ret;
|
||||
|
||||
inhdr.opcode = FUSE_OPENDIR;
|
||||
inhdr.nodeid = nodeid;
|
||||
|
||||
ret = virtio_fs_xfer(dev, &inhdr, &in, sizeof(in), &outhdr, &out,
|
||||
sizeof(struct fuse_open_out));
|
||||
log_debug("fh %llx open_flags %x backing_id %x\n", out.fh,
|
||||
out.open_flags, out.backing_id);
|
||||
log_debug("len %x error %x unique %llx\n", outhdr.len, outhdr.error,
|
||||
outhdr.unique);
|
||||
if (ret)
|
||||
return log_msg_ret("vfo", ret);
|
||||
*fhp = out.fh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int virtio_fs_readdir(struct udevice *dev, u64 nodeid, u64 fh, u64 offset,
|
||||
void *buf, int size, int *out_sizep)
|
||||
{
|
||||
struct fuse_in_header inhdr = {};
|
||||
struct fuse_read_in in = {};
|
||||
struct fuse_out_header outhdr;
|
||||
uint len;
|
||||
int ret;
|
||||
|
||||
inhdr.opcode = FUSE_READDIRPLUS;
|
||||
inhdr.nodeid = nodeid;
|
||||
|
||||
in.fh = fh;
|
||||
in.size = size;
|
||||
in.offset = offset;
|
||||
ret = virtio_fs_xfer(dev, &inhdr, &in, sizeof(in), &outhdr, buf, size);
|
||||
log_debug("len %x error %x unique %llx\n", outhdr.len, outhdr.error,
|
||||
outhdr.unique);
|
||||
if (ret)
|
||||
return log_msg_ret("vfr", ret);
|
||||
|
||||
len = outhdr.len - sizeof(outhdr);
|
||||
/* sanity check */
|
||||
if (len > size) {
|
||||
log_debug("virtio: internal size error outhdr.len %x size %x\n",
|
||||
outhdr.len, size);
|
||||
return log_msg_ret("vle", -EFAULT);
|
||||
}
|
||||
*out_sizep = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int virtio_fs_releasedir(struct udevice *dev, u64 nodeid, u64 fh)
|
||||
{
|
||||
struct fuse_in_header inhdr = {};
|
||||
struct fuse_release_in in = {};
|
||||
struct fuse_out_header outhdr;
|
||||
int ret;
|
||||
|
||||
inhdr.opcode = FUSE_RELEASEDIR;
|
||||
inhdr.nodeid = nodeid;
|
||||
in.fh = fh;
|
||||
|
||||
ret = virtio_fs_xfer(dev, &inhdr, &in, sizeof(in), &outhdr, NULL, 0);
|
||||
if (ret)
|
||||
return log_msg_ret("vfe", ret);
|
||||
log_debug("len %x error %x unique %llx\n", outhdr.len, outhdr.error,
|
||||
outhdr.unique);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int virtio_fs_open_file(struct udevice *dev, u64 nodeid,
|
||||
enum dir_open_flags_t flags, u64 *fhp, uint *flagsp)
|
||||
{
|
||||
struct fuse_in_header inhdr = {};
|
||||
char buf[MAX_FNAME_LEN + sizeof(struct fuse_open_in)];
|
||||
struct fuse_open_in *in = (struct fuse_open_in *)buf;
|
||||
struct fuse_out_header outhdr;
|
||||
struct fuse_open_out out;
|
||||
int ret;
|
||||
|
||||
inhdr.opcode = FUSE_OPEN;
|
||||
inhdr.nodeid = nodeid;
|
||||
|
||||
in->flags = 0;
|
||||
in->open_flags = flags;
|
||||
|
||||
ret = virtio_fs_xfer(dev, &inhdr, buf, sizeof(*in), &outhdr,
|
||||
&out, sizeof(struct fuse_open_out));
|
||||
if (ret)
|
||||
return log_msg_ret("vfr", ret);
|
||||
|
||||
*fhp = out.fh;
|
||||
*flagsp = out.open_flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long virtio_fs_read(struct udevice *dev, u64 nodeid, u64 fh, u64 offset,
|
||||
void *buf, uint size)
|
||||
{
|
||||
struct fuse_in_header inhdr = {};
|
||||
struct fuse_read_in in = {};
|
||||
struct fuse_out_header outhdr;
|
||||
int ret;
|
||||
|
||||
log_debug("dev '%s' nodeid %lld fh %lld offset %llx size %x buf %p\n",
|
||||
dev->name, nodeid, fh, offset, size, buf);
|
||||
inhdr.opcode = FUSE_READ;
|
||||
inhdr.nodeid = nodeid;
|
||||
|
||||
in.fh = fh;
|
||||
in.offset = offset;
|
||||
in.size = size;
|
||||
|
||||
ret = virtio_fs_xfer(dev, &inhdr, &in, sizeof(in), &outhdr, buf, size);
|
||||
if (ret)
|
||||
return log_msg_ret("vfr", ret);
|
||||
log_debug("read len %x\n", outhdr.len);
|
||||
|
||||
return outhdr.len;
|
||||
}
|
||||
|
||||
static int virtio_fs_init(struct udevice *dev)
|
||||
{
|
||||
struct fuse_in_header inhdr = {};
|
||||
struct fuse_init_in in = {};
|
||||
struct fuse_out_header outhdr;
|
||||
struct fuse_init_out out;
|
||||
int ret;
|
||||
|
||||
inhdr.opcode = FUSE_INIT;
|
||||
|
||||
in.major = FUSE_KERNEL_VERSION;
|
||||
in.minor = FUSE_KERNEL_MINOR_VERSION;
|
||||
|
||||
ret = virtio_fs_xfer(dev, &inhdr, &in, sizeof(in), &outhdr, &out,
|
||||
sizeof(out));
|
||||
if (ret)
|
||||
return log_msg_ret("vfx", ret);
|
||||
log_debug("major %x minor %x max_readahead %x flags %x ", out.major,
|
||||
out.minor, out.max_readahead, out.flags);
|
||||
log_debug("max_background %x congestion_threshold %x max_write %x\n",
|
||||
out.max_background, out.congestion_threshold, out.max_write);
|
||||
log_debug("time_gran %x max_pages %x, map_alignment %x flags2 %x ",
|
||||
out.time_gran, out.max_pages, out.map_alignment, out.flags2);
|
||||
log_debug("max_stack_depth %x request_timeout %x\n",
|
||||
out.max_stack_depth, out.request_timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _virtio_fs_probe(struct udevice *dev)
|
||||
{
|
||||
struct virtio_dev_priv *virtio_priv = dev_get_uclass_priv(dev->parent);
|
||||
struct virtio_fs_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
/* Indicate what driver features we support */
|
||||
virtio_driver_features_init(virtio_priv, NULL, 0, NULL, 0);
|
||||
|
||||
virtio_cread_bytes(dev, 0, &priv->tag, VIRTIO_FS_TAG_SIZE);
|
||||
priv->tag[VIRTIO_FS_TAG_SIZE] = '\0';
|
||||
|
||||
log_debug("tag %s\n", priv->tag);
|
||||
|
||||
ret = virtio_find_vqs(dev, 1, &priv->vq);
|
||||
if (ret)
|
||||
return log_msg_ret("vff", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_fs_mount(struct udevice *dev)
|
||||
{
|
||||
struct fs_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct virtio_fs_priv *priv = dev_get_priv(dev);
|
||||
struct fuse_entry_out out;
|
||||
int ret;
|
||||
|
||||
if (uc_priv->mounted)
|
||||
return log_msg_ret("vfi", -EISCONN);
|
||||
|
||||
ret = virtio_fs_init(dev);
|
||||
if (ret)
|
||||
return log_msg_ret("vfi", ret);
|
||||
|
||||
ret = virtio_fs_lookup_(dev, FUSE_ROOT_ID, ".", &out);
|
||||
if (ret) {
|
||||
log_err("Failed to lookup root directory: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
priv->root_inode = out.nodeid;
|
||||
log_debug("directory found, ino=%lld\n", priv->root_inode);
|
||||
|
||||
uc_priv->mounted = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_fs_unmount(struct udevice *dev)
|
||||
{
|
||||
struct fs_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct virtio_fs_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
if (!uc_priv->mounted)
|
||||
return log_msg_ret("vfu", -ENOTCONN);
|
||||
|
||||
ret = virtio_fs_forget(dev, priv->root_inode);
|
||||
if (ret)
|
||||
return log_msg_ret("vff", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct fs_ops virtio_fs_ops = {
|
||||
.mount = virtio_fs_mount,
|
||||
.unmount = virtio_fs_unmount,
|
||||
};
|
||||
|
||||
static const struct udevice_id virtio_fs_ids[] = {
|
||||
{ .compatible = "virtio,fs" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(virtio_fs) = {
|
||||
.name = VIRTIO_FS_DRV_NAME,
|
||||
.id = UCLASS_FS,
|
||||
.of_match = virtio_fs_ids,
|
||||
.ops = &virtio_fs_ops,
|
||||
.probe = _virtio_fs_probe,
|
||||
.priv_auto = sizeof(struct virtio_fs_priv),
|
||||
.flags = DM_FLAG_ACTIVE_DMA,
|
||||
};
|
||||
149
drivers/virtio/fs_internal.h
Normal file
149
drivers/virtio/fs_internal.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* U-Boot Virtio-FS directories
|
||||
*
|
||||
* Copyright 2025 Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* Supports access to directories in virtio-fs
|
||||
*/
|
||||
|
||||
#ifndef _FS_INTERNAL_H
|
||||
#define _FS_INTERNAL_H
|
||||
|
||||
#include <dir.h>
|
||||
|
||||
struct fuse_entry_out;
|
||||
struct udevice;
|
||||
|
||||
/**
|
||||
* struct virtio_fs_dir_priv - Information about a directory
|
||||
*
|
||||
* @inode: Associated inode for the directory
|
||||
* @path: Path of this directory, e.g. '/fred/mary', or NULL for the root
|
||||
* directory
|
||||
*/
|
||||
struct virtio_fs_dir_priv {
|
||||
u64 inode;
|
||||
char *path;
|
||||
};
|
||||
|
||||
/**
|
||||
* virtio_fs_lookup() - Look up an entry in a directory
|
||||
*
|
||||
* @dev: Filesystem device which holds the directory (UCLASS_FS)
|
||||
* @nodeid: Node ID of the directory containing the entry
|
||||
* @name: Name of the entry
|
||||
* @out: Returns lookup info
|
||||
* Return: 0 on success, -ENOENT if not found, other -ve on other error
|
||||
*/
|
||||
int virtio_fs_lookup_(struct udevice *dev, u64 nodeid, const char *name,
|
||||
struct fuse_entry_out *out);
|
||||
|
||||
/**
|
||||
* virtio_fs_lookup() - Look up an entry in a directory
|
||||
*
|
||||
* This is a simplified wrapper around virtio_fs_lookup_() that performs a
|
||||
* lookup within the filesystem's root directory.
|
||||
*
|
||||
* @dev: Filesystem device which holds the directory (UCLASS_FS)
|
||||
* @name: Name of the entry
|
||||
* @entryp: Returns the node ID of the entry, on success
|
||||
* Return: 0 on success, -ENOENT if not found, other -ve on other error
|
||||
*/
|
||||
int virtio_fs_lookup(struct udevice *dev, const char *name, u64 *entryp);
|
||||
|
||||
/**
|
||||
* virtio_fs_forget() - Forget a nodeid
|
||||
*
|
||||
* Tells FUSE that this nodeid is no-longer needed
|
||||
*
|
||||
* @dev: Filesystem device which holds the directory (UCLASS_FS)
|
||||
* @nodeid: Node ID to forget
|
||||
* Return: 0 on success, -ve on error
|
||||
*/
|
||||
int virtio_fs_forget(struct udevice *dev, u64 nodeid);
|
||||
|
||||
/**
|
||||
* virtio_fs_opendir() - Open a directory for reading
|
||||
*
|
||||
* @dev: Filesystem device which holds the directory (UCLASS_FS)
|
||||
* @nodeid: Node ID of the directory
|
||||
* @fhp: Returns unique filehandle for the directory
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
int virtio_fs_opendir(struct udevice *dev, u64 nodeid, u64 *fhp);
|
||||
|
||||
/**
|
||||
* virtio_fs_readdir() - Read a chunk of entries from a directory
|
||||
*
|
||||
* Fills in @buf with directory records, using an internal FUSE format. The
|
||||
* format is one struct fuse_direntplus (plus a name string) for each record.
|
||||
* See include/linux/fuse.h for the struct details (unfortunately not
|
||||
* commented). Use FUSE_DIRENTPLUS_SIZE() to calculate the size of each entry.
|
||||
*
|
||||
* It would be possible to convert the format into struct fs_dirent but the
|
||||
* API which uses it only allows returning a single record at a time, so it
|
||||
* seems best to tackle that later.
|
||||
*
|
||||
* @dev: Filesystem device which holds the directory (UCLASS_FS)
|
||||
* @nodeid: Node ID of the directory
|
||||
* @fh: Unique filehandle for the directory
|
||||
* @offset: Start offset for reading; use the value returned from the previous
|
||||
* call, or 0 to start at the beginning
|
||||
* @buf: Buffer to receive records, must be large enough to hold at least one
|
||||
* struct fuse_direntplus
|
||||
* @size: Size of buffer
|
||||
* @out_sizep: Returns amount of data used in the buffer
|
||||
*/
|
||||
int virtio_fs_readdir(struct udevice *dev, u64 nodeid, u64 fh, u64 offset,
|
||||
void *buf, int size, int *out_sizep);
|
||||
|
||||
/**
|
||||
* virtio_fs_releasedir() - Close a directory
|
||||
*
|
||||
* Use this on a directory opened with virtio_fs_opendir() when you have
|
||||
* finished reading entries with virtio_fs_readdir()
|
||||
*
|
||||
* @dev: Filesystem device which holds the directory (UCLASS_FS)
|
||||
* @nodeid: Node ID of the directory
|
||||
* @fh: Unique filehandle for the directory
|
||||
*/
|
||||
int virtio_fs_releasedir(struct udevice *dev, u64 nodeid, u64 fh);
|
||||
|
||||
/**
|
||||
* virtio_fs_open_file() - Open a file
|
||||
*
|
||||
* @dev: Filesystem device which holds the file (UCLASS_FS)
|
||||
* @nodeid: Node ID of the directory containing the file
|
||||
* @flags: Open-mode flags to use
|
||||
* @fhp: Return unique filehandle for the directory
|
||||
* @flagsp: Updated open-mode flags
|
||||
*/
|
||||
int virtio_fs_open_file(struct udevice *dev, u64 nodeid,
|
||||
enum dir_open_flags_t flags, u64 *fhp, uint *flagsp);
|
||||
|
||||
/**
|
||||
* virtio_fs_get_root() - Get the nodeid of the root directory of the virtio-fs
|
||||
*
|
||||
* Return: node ID of root node
|
||||
*/
|
||||
u64 virtio_fs_get_root(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* virtio_fs_read() - Read data from an open file
|
||||
*
|
||||
* Read a block of data from a file previously opened with
|
||||
* virtio_fs_open_file()
|
||||
*
|
||||
* @dev: Filesystem device (UCLASS_FS)
|
||||
* @nodeid: Node ID of the file being read (for context)
|
||||
* @fh: File handle of the open file
|
||||
* @offset: Offset within the file to start reading from
|
||||
* @buf: Buffer to store the read data
|
||||
* @size: Maximum number of bytes to read
|
||||
* Return: Number of bytes read on success, -ve on error
|
||||
*/
|
||||
long virtio_fs_read(struct udevice *dev, u64 nodeid, u64 fh, u64 offset,
|
||||
void *buf, uint size);
|
||||
|
||||
#endif
|
||||
@@ -30,6 +30,7 @@ static const char *const virtio_drv_name[VIRTIO_ID_MAX_NUM] = {
|
||||
[VIRTIO_ID_NET] = VIRTIO_NET_DRV_NAME,
|
||||
[VIRTIO_ID_BLOCK] = VIRTIO_BLK_DRV_NAME,
|
||||
[VIRTIO_ID_RNG] = VIRTIO_RNG_DRV_NAME,
|
||||
[VIRTIO_ID_FS] = VIRTIO_FS_DRV_NAME,
|
||||
};
|
||||
|
||||
int virtio_get_config(struct udevice *vdev, unsigned int offset,
|
||||
|
||||
Reference in New Issue
Block a user