Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 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; } |