Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144315069
D46295.id156285.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
18 KB
Referenced Files
None
Subscribers
None
D46295.id156285.diff
View Options
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -352,6 +352,7 @@
device virtio_blk # VirtIO Block device
device virtio_scsi # VirtIO SCSI device
device virtio_balloon # VirtIO Memory Balloon device
+device virtio_fs # VirtIO File System device
# Linux KVM paravirtualization support
device kvm_clock # KVM paravirtual clock driver
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3443,6 +3443,7 @@
dev/virtio/random/virtio_random.c optional virtio_random
dev/virtio/scmi/virtio_scmi.c optional virtio_scmi
dev/virtio/scsi/virtio_scsi.c optional virtio_scsi
+dev/virtio/fs/virtio_fs.c optional virtio_fs
dev/vkbd/vkbd.c optional vkbd
dev/vmgenc/vmgenc_acpi.c optional acpi
dev/vmware/vmxnet3/if_vmx.c optional vmx
diff --git a/sys/dev/virtio/fs/virtio_fs.h b/sys/dev/virtio/fs/virtio_fs.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/virtio/fs/virtio_fs.h
@@ -0,0 +1,44 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2024, Emil Tsalapatis <emil@etsalapatis.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _VIRTIO_FS_H
+#define _VIRTIO_FS_H
+
+struct vtfs_softc;
+typedef struct vtfs_softc *vtfs_instance;
+typedef void (*vtfs_fuse_cb)(void *, uint32_t);
+typedef void (*vtfs_teardown_cb)(void *);
+
+void vtfs_register_cb(vtfs_instance, vtfs_fuse_cb, vtfs_fuse_cb,
+ vtfs_teardown_cb, void *);
+int vtfs_enqueue(vtfs_instance, void *, struct sglist *, int, int, bool);
+int vtfs_find(char *, vtfs_instance *);
+void vtfs_release(vtfs_instance);
+void vtfs_drain(vtfs_instance);
+void vtfs_unregister_cb(vtfs_instance);
+
+#endif /* _VIRTIO_FS_H */
diff --git a/sys/dev/virtio/fs/virtio_fs.c b/sys/dev/virtio/fs/virtio_fs.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/virtio/fs/virtio_fs.c
@@ -0,0 +1,617 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2024, Emil Tsalapatis <emil@etsalapatis.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Device for the VirtIO file system. */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/selinfo.h>
+#include <sys/sglist.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
+
+#include <machine/bus.h>
+#include <sys/bus.h>
+
+#include <dev/virtio/virtio.h>
+#include <dev/virtio/virtqueue.h>
+#include <dev/virtio/fs/virtio_fs.h>
+
+#include "virtio_if.h"
+#include "virtio_fs_internal.h"
+
+SYSCTL_NODE(_dev, OID_AUTO, vtfs, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "Virtio FS paravirt device");
+
+bool vtfs_debug = false;
+SYSCTL_BOOL(_dev_vtfs, OID_AUTO, debug, CTLFLAG_RW, &vtfs_debug, false,
+ "vtfs debug logging");
+
+#define VTFS_DEBUG(fmt, ...) \
+ do { \
+ if (vtfs_debug) \
+ printf("(%s:%d) " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ } while (0)
+
+#define VTFS_ERR(fmt, ...) \
+ do { \
+ printf("[VTFS] (%s:%d) " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ } while (0)
+
+/* Module-wide device list. */
+
+LIST_HEAD(, vtfs_softc) vtfs_contexts = LIST_HEAD_INITIALIZER(vtfs_contexts);
+struct mtx vtfs_mod_mtx;
+MTX_SYSINIT(vtfs_mod_mtx, &vtfs_mod_mtx, "Virtio FS Global Lock", MTX_DEF);
+
+#define VTFS_LOCK() mtx_lock(&vtfs_mod_mtx)
+#define VTFS_UNLOCK() mtx_unlock(&vtfs_mod_mtx)
+
+#define FSQ_LOCK(_fsq) mtx_lock(&(_fsq)->vtfsq_mtx)
+#define FSQ_UNLOCK(_fsq) mtx_unlock(&(_fsq)->vtfsq_mtx)
+#define FSQ_WAIT(_fsq) cv_wait(&(_fsq)->vtfsq_cv, &(_fsq)->vtfsq_mtx)
+#define FSQ_KICK(_fsq) cv_broadcast(&(_fsq)->vtfsq_cv)
+
+static int vtfs_modevent(module_t, int, void *);
+
+static int vtfs_probe(device_t);
+static int vtfs_attach(device_t);
+static int vtfs_detach(device_t);
+
+static device_method_t vtfs_methods[] = {
+ DEVMETHOD(device_probe, vtfs_probe),
+ DEVMETHOD(device_attach, vtfs_attach),
+ DEVMETHOD(device_detach, vtfs_detach),
+ DEVMETHOD_END
+};
+
+static driver_t vtfs_driver = {
+ "vtfs",
+ vtfs_methods,
+ sizeof(struct vtfs_softc),
+};
+
+VIRTIO_DRIVER_MODULE(vtfs, vtfs_driver, vtfs_modevent, NULL);
+MODULE_VERSION(vtfs, 1);
+MODULE_DEPEND(vtfs, virtio, 1, 1, 1);
+
+VIRTIO_SIMPLE_PNPINFO(vtfs, VIRTIO_ID_FS, "VirtIO FS Adapter");
+
+static int
+vtfs_modevent(module_t mod, int type, void *unused)
+{
+ int error = 0;
+
+ switch (type) {
+ case MOD_LOAD:
+ case MOD_UNLOAD:
+ case MOD_QUIESCE:
+ case MOD_SHUTDOWN:
+ break;
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
+
+static int
+vtfs_probe(device_t dev)
+{
+ return (VIRTIO_SIMPLE_PROBE(dev, vtfs));
+}
+
+static int
+vtfs_read_config(struct vtfs_softc *sc)
+{
+ device_t dev;
+ size_t taglen;
+#ifdef INVARIANTS
+ struct vtfs_config fscfg;
+#endif
+
+ dev = sc->vtfs_dev;
+
+ _Static_assert(sizeof(sc->vtfs_nqs) == sizeof(fscfg.num_request_queues),
+ "reading num_request_queues into wrongly typed struct");
+
+ virtio_read_device_config(dev,
+ offsetof(struct vtfs_config, num_request_queues),
+ &sc->vtfs_nqs,
+ sizeof(&sc->vtfs_nqs));
+
+ if (sc->vtfs_nqs <= 0) {
+ VTFS_ERR("read non-positive queue number from host");
+ return (EINVAL);
+ }
+
+ /* Account for the priority queue. */
+ sc->vtfs_nqs += 1;
+
+ virtio_read_device_config_array(dev,
+ offsetof(struct vtfs_config, tag),
+ sc->vtfs_tag, 1, TAG_SIZE);
+
+ /* The read tag may not be NUL-terminated. */
+ taglen = strnlen(sc->vtfs_tag, TAG_SIZE);
+ if (taglen == 0) {
+ VTFS_ERR("read empty tag");
+ return (EINVAL);
+ }
+
+ KASSERT(taglen < sizeof(sc->vtfs_tag), ("overran tag buffer"));
+ sc->vtfs_tag[taglen] = '\0';
+
+ VTFS_DEBUG("fs tag: %s, # vqs: %d", sc->vtfs_tag, sc->vtfs_nqs);
+
+ return (0);
+}
+
+static void
+vtfs_vq_intr(void *xfsq)
+{
+ struct vtfs_fsq *fsq = xfsq;
+ struct virtqueue *vq = fsq->vtfsq_vq;
+ uint32_t len;
+ void *ftick;
+
+ /* We turn off vtfs interrupts before removing the callback. */
+ KASSERT(fsq->vtfsq_cb != NULL, ("missing fuse callback"));
+
+ FSQ_LOCK(fsq);
+
+again:
+ /* Go through the tickets one by one, invoke the fuse callback. */
+ while ((ftick = virtqueue_dequeue(vq, &len)) != NULL)
+ fsq->vtfsq_cb(ftick, len);
+
+ /* If the host pushed another descriptor in the meantime, go again. */
+ if (virtqueue_enable_intr(vq) != 0) {
+ virtqueue_disable_intr(vq);
+ goto again;
+ }
+
+ FSQ_KICK(fsq);
+ FSQ_UNLOCK(fsq);
+}
+
+static int
+vtfs_init_fsq(struct vtfs_softc *sc, int id)
+{
+ struct vtfs_fsq *fsq = &sc->vtfs_fsqs[id];
+ int error;
+
+ if (id == 0) {
+ snprintf(fsq->vtfsq_name, sizeof(fsq->vtfsq_name),
+ "%s-priority", device_get_nameunit(sc->vtfs_dev));
+ } else {
+ snprintf(fsq->vtfsq_name, sizeof(fsq->vtfsq_name),
+ "%s-queue%d", device_get_nameunit(sc->vtfs_dev), id);
+ }
+
+ mtx_init(&fsq->vtfsq_mtx, fsq->vtfsq_name, NULL, MTX_DEF);
+ cv_init(&fsq->vtfsq_cv, "fsqvqcv");
+
+ fsq->vtfsq_tq = taskqueue_create("vtfsqtq", M_WAITOK,
+ taskqueue_thread_enqueue, &fsq->vtfsq_tq);
+ if (fsq->vtfsq_tq == NULL)
+ return (ENOMEM);
+
+ error = taskqueue_start_threads(&fsq->vtfsq_tq, VTFS_TQTHREAD,
+ PVM, "VirtioFS device");
+ if (error != 0)
+ return (error);
+
+ fsq->vtfsq_sc = sc;
+ VTFS_DEBUG("vq %s online", fsq->vtfsq_name);
+
+ return (0);
+}
+
+static void
+vtfs_fini_fsq(struct vtfs_fsq *fsq)
+{
+
+ if (fsq->vtfsq_sg != NULL) {
+ sglist_free(fsq->vtfsq_sg);
+ fsq->vtfsq_sg = NULL;
+ }
+
+ if (fsq->vtfsq_tq != NULL) {
+ taskqueue_drain_all(fsq->vtfsq_tq);
+ taskqueue_free(fsq->vtfsq_tq);
+ fsq->vtfsq_tq = NULL;
+ }
+
+ if (mtx_initialized(&fsq->vtfsq_mtx) != 0) {
+ cv_destroy(&fsq->vtfsq_cv);
+ mtx_destroy(&fsq->vtfsq_mtx);
+ }
+
+ VTFS_DEBUG("vq %s destroyed", fsq->vtfsq_name);
+}
+
+static int
+vtfs_alloc_fsqueues(struct vtfs_softc *sc)
+{
+ int error;
+ int nvqs;
+ int i, j;
+
+ nvqs = sc->vtfs_nqs;
+ sc->vtfs_fsqs = malloc((sizeof(*sc->vtfs_fsqs)) * nvqs, M_DEVBUF,
+ M_NOWAIT | M_ZERO);
+ if (sc->vtfs_fsqs == NULL)
+ return (ENOMEM);
+
+ for (i = 0; i < nvqs; i++) {
+ error = vtfs_init_fsq(sc, i);
+ if (error != 0)
+ goto fail;
+ }
+
+ return (0);
+
+fail:
+ VTFS_DEBUG("failed while initializing vq %d", i);
+
+ /* Clean up any initialized fsqs. */
+ for (j = 0; j < i; j++)
+ vtfs_fini_fsq(&sc->vtfs_fsqs[j]);
+
+ free(sc->vtfs_fsqs, M_DEVBUF);
+ sc->vtfs_fsqs = NULL;
+
+ return (error);
+}
+
+static void
+vtfs_free_fsqueues(struct vtfs_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < sc->vtfs_nqs; i++)
+ vtfs_fini_fsq(&sc->vtfs_fsqs[i]);
+
+ free(sc->vtfs_fsqs, M_DEVBUF);
+ sc->vtfs_fsqs = NULL;
+}
+
+static int
+vtfs_alloc_virtqueues(struct vtfs_softc *sc)
+{
+ struct vq_alloc_info *vq_info;
+ struct vtfs_fsq *fsq;
+ device_t dev;
+ int error;
+ int nqs;
+ int i;
+
+ dev = sc->vtfs_dev;
+ nqs = sc->vtfs_nqs;
+
+ /*
+ * We have num_request_queues regular queues and one high-priority
+ * queue for FORGET/general priority operations.
+ */
+ KASSERT(nqs > 1, ("missing regular queues"));
+
+ vq_info = malloc(sizeof(*vq_info) * nqs, M_TEMP, M_NOWAIT);
+ if (vq_info == NULL)
+ return (ENOMEM);
+
+ for (i = 0; i < nqs; i++) {
+ fsq = &sc->vtfs_fsqs[i];
+ VQ_ALLOC_INFO_INIT(&vq_info[i], VTFS_MAXSEGS, vtfs_vq_intr,
+ fsq, &fsq->vtfsq_vq, "%s", fsq->vtfsq_name);
+ }
+
+ error = virtio_alloc_virtqueues(dev, nqs, vq_info);
+ free(vq_info, M_TEMP);
+
+ VTFS_DEBUG("virtqueues online");
+
+ return (error);
+}
+
+static int
+vtfs_enable_intr(device_t dev)
+{
+ struct vtfs_softc *sc;
+ int error;
+ int i;
+
+ sc = device_get_softc(dev);
+
+ error = virtio_setup_intr(dev, INTR_TYPE_BIO);
+ if (error != 0)
+ return (error);
+
+ for (i = 0; i < sc->vtfs_nqs; i++)
+ virtqueue_enable_intr(sc->vtfs_fsqs[i].vtfsq_vq);
+
+
+ return (0);
+}
+
+static void
+vtfs_stop(struct vtfs_softc *sc)
+{
+ struct virtqueue *vq;
+ int i;
+
+ /* The file system should have cleared the virtqueues when umounting .*/
+ for (i = 0; i < sc->vtfs_nqs; i++) {
+ vq = sc->vtfs_fsqs[i].vtfsq_vq;
+ virtqueue_disable_intr(vq);
+ KASSERT(virtqueue_empty(vq), ("virtqueue not empty"));
+ }
+
+ virtio_stop(sc->vtfs_dev);
+
+}
+
+static void
+vtfs_add(struct vtfs_softc *sc)
+{
+ VTFS_LOCK();
+ LIST_INSERT_HEAD(&vtfs_contexts, sc, vtfs_link);
+ VTFS_UNLOCK();
+}
+static void
+vtfs_remove(struct vtfs_softc *sc)
+{
+ VTFS_LOCK();
+ LIST_REMOVE(sc, vtfs_link);
+ VTFS_UNLOCK();
+}
+
+int
+vtfs_find(char *tag, struct vtfs_softc **scp)
+{
+ struct vtfs_softc *sc;
+
+ VTFS_LOCK();
+
+ LIST_FOREACH(sc, &vtfs_contexts, vtfs_link) {
+ if (strncmp(sc->vtfs_tag, tag, sizeof(sc->vtfs_tag)) != 0)
+ continue;
+
+ if (sc->vtfs_inuse) {
+ VTFS_UNLOCK();
+ return (EALREADY);
+ }
+
+ sc->vtfs_inuse = true;
+ VTFS_UNLOCK();
+
+ *scp = sc;
+
+ return (0);
+ }
+
+ VTFS_UNLOCK();
+
+ return (EINVAL);
+}
+
+void
+vtfs_release(struct vtfs_softc *sc)
+{
+ VTFS_LOCK();
+ sc->vtfs_inuse = false;
+ VTFS_UNLOCK();
+}
+
+static int
+vtfs_attach(device_t dev)
+{
+ struct vtfs_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+ sc->vtfs_dev = dev;
+ sc->vtfs_inuse = false;
+
+ error = vtfs_read_config(sc);
+ if (error != 0)
+ goto fail;
+
+ error = vtfs_alloc_fsqueues(sc);
+ if (error != 0)
+ goto fail;
+
+ error = vtfs_alloc_virtqueues(sc);
+ if (error != 0)
+ goto fail;
+
+ error = vtfs_enable_intr(dev);
+ if (error != 0)
+ goto fail;
+
+ vtfs_add(sc);
+
+ return (0);
+
+fail:
+ vtfs_detach(dev);
+
+ return (error);
+}
+
+
+static int
+vtfs_detach(device_t dev)
+{
+ struct vtfs_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ vtfs_remove(sc);
+
+ /* Kill any active FUSE session. */
+ if (sc->vtfs_detach_cb)
+ sc->vtfs_detach_cb(sc->vtfs_detach_cb_arg);
+
+ vtfs_drain(sc);
+
+ vtfs_stop(sc);
+ vtfs_free_fsqueues(sc);
+
+ VTFS_DEBUG("device detached");
+
+ return (0);
+}
+
+void
+vtfs_register_cb(struct vtfs_softc *sc, vtfs_fuse_cb forget_cb,
+ vtfs_fuse_cb regular_cb, vtfs_teardown_cb detach_cb,
+ void *detach_cb_arg)
+{
+ struct vtfs_fsq *fsq;
+ int i;
+
+ sc->vtfs_detach_cb = detach_cb;
+ sc->vtfs_detach_cb_arg = detach_cb_arg;
+
+ for (i = 0; i < sc->vtfs_nqs; i++) {
+ fsq = &sc->vtfs_fsqs[i];
+ FSQ_LOCK(fsq);
+ if (i == VTFS_FORGET_FSQ)
+ fsq->vtfsq_cb = forget_cb;
+ else
+ fsq->vtfsq_cb = regular_cb;
+ FSQ_UNLOCK(fsq);
+ }
+
+}
+
+void
+vtfs_unregister_cb(struct vtfs_softc *sc)
+{
+ struct vtfs_fsq *fsq;
+ int i;
+
+ for (i = 0; i < sc->vtfs_nqs; i++) {
+ fsq = &sc->vtfs_fsqs[i];
+
+ FSQ_LOCK(fsq);
+ fsq->vtfsq_cb = NULL;
+ FSQ_UNLOCK(fsq);
+ }
+
+ sc->vtfs_detach_cb_arg = NULL;
+ sc->vtfs_detach_cb = NULL;
+}
+
+int
+vtfs_enqueue(struct vtfs_softc *sc, void *ftick, struct sglist *sg,
+ int readable, int writable, bool urgent)
+{
+ struct virtqueue *vq;
+ struct vtfs_fsq *fsq;
+ int error;
+
+ if (urgent)
+ fsq = &sc->vtfs_fsqs[VTFS_FORGET_FSQ];
+ else
+ fsq = &sc->vtfs_fsqs[VTFS_REGULAR_FSQ];
+
+ FSQ_LOCK(fsq);
+ vq = fsq->vtfsq_vq;
+
+ KASSERT(sg->sg_nseg == readable + writable, ("inconsistent segmentation"));
+
+ error = virtqueue_enqueue(vq, ftick, sg, readable, writable);
+ while (error == ENOSPC) {
+ FSQ_WAIT(fsq);
+ error = virtqueue_enqueue(vq, ftick, sg, readable, writable);
+ }
+
+ if (error != 0) {
+ FSQ_UNLOCK(fsq);
+ return (error);
+ }
+
+ virtqueue_notify(vq);
+
+ FSQ_UNLOCK(fsq);
+ sglist_free(sg);
+
+ return (0);
+}
+
+static void
+vtfs_drain_vq(struct vtfs_fsq *fsq)
+{
+ struct virtqueue *vq = fsq->vtfsq_vq;
+ uint32_t len;
+ void *ftick;
+
+ /*
+ * If there is no callback, we don't have an
+ * upper-level FUSE session.
+ */
+ if (fsq->vtfsq_cb == NULL) {
+ KASSERT(virtqueue_empty(vq), ("virtqueue not empty"));
+ return;
+ }
+
+ vq = fsq->vtfsq_vq;
+
+ while ((ftick = virtqueue_dequeue(vq, &len)) != NULL) {
+ fsq->vtfsq_cb(ftick, len);
+ }
+
+ KASSERT(virtqueue_empty(vq), ("virtqueue not empty"));
+}
+
+void
+vtfs_drain(struct vtfs_softc *sc)
+{
+ struct vtfs_fsq *fsq;
+ int i;
+
+ for (i = 0; i < sc->vtfs_nqs; i++) {
+ fsq = &sc->vtfs_fsqs[i];
+ FSQ_LOCK(fsq);
+ virtqueue_disable_intr(fsq->vtfsq_vq);
+ vtfs_drain_vq(fsq);
+ FSQ_UNLOCK(fsq);
+ }
+}
diff --git a/sys/dev/virtio/fs/virtio_fs_internal.h b/sys/dev/virtio/fs/virtio_fs_internal.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/virtio/fs/virtio_fs_internal.h
@@ -0,0 +1,50 @@
+#ifndef _VIRTIO_FS_INTERNAL_
+#define _VIRTIO_FS_INTERNAL_
+
+/* Protocol-specified file system tag size. */
+#define TAG_SIZE (36)
+#define FSQ_NAME_SIZE (16)
+
+/* Struct for the file system instance. Provided by the host. */
+struct vtfs_config {
+ /* UTF-8 File system tag. */
+ uint8_t tag[TAG_SIZE];
+ /* Number of request queues. */
+ uint32_t num_request_queues;
+ /* Minimum # bytes for each buffer in the notification queue. */
+ uint32_t notify_buf_size;
+} __packed;
+
+/* A queue structure belonging to a virtio fs device. */
+struct vtfs_fsq {
+ struct mtx vtfsq_mtx;
+ struct cv vtfsq_cv;
+ struct virtqueue *vtfsq_vq;
+ struct taskqueue *vtfsq_tq;
+ struct sglist *vtfsq_sg;
+ char vtfsq_name[FSQ_NAME_SIZE];
+ struct vtfs_softc *vtfsq_sc;
+ vtfs_fuse_cb vtfsq_cb;
+};
+
+/* A single virtio fs device instance. */
+struct vtfs_softc {
+ device_t vtfs_dev;
+ struct mtx vtfs_mtx;
+ struct vtfs_fsq *vtfs_fsqs;
+ bool vtfs_inuse; /* protected by the vtfs modulelock */
+ vtfs_teardown_cb vtfs_detach_cb;
+ void *vtfs_detach_cb_arg;
+ /* Host-provided config state. */
+ uint8_t vtfs_tag[TAG_SIZE + 1];
+ uint32_t vtfs_nqs;
+ LIST_ENTRY(vtfs_softc) vtfs_link;
+};
+
+#define VTFS_FORGET_FSQ (0)
+#define VTFS_REGULAR_FSQ (1)
+
+#define VTFS_MAXSEGS (16)
+#define VTFS_TQTHREAD (4)
+
+#endif /* _VIRTIO_FS_INTERNAL_ */
diff --git a/sys/modules/virtio/Makefile b/sys/modules/virtio/Makefile
--- a/sys/modules/virtio/Makefile
+++ b/sys/modules/virtio/Makefile
@@ -22,6 +22,6 @@
# SUCH DAMAGE.
#
-SUBDIR= virtio pci network block balloon scsi random console p9fs
+SUBDIR= virtio pci network block balloon scsi random console p9fs fs
.include <bsd.subdir.mk>
diff --git a/sys/modules/virtio/Makefile b/sys/modules/virtio/fs/Makefile
copy from sys/modules/virtio/Makefile
copy to sys/modules/virtio/fs/Makefile
--- a/sys/modules/virtio/Makefile
+++ b/sys/modules/virtio/fs/Makefile
@@ -1,5 +1,3 @@
-#
-#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
@@ -22,6 +20,11 @@
# SUCH DAMAGE.
#
-SUBDIR= virtio pci network block balloon scsi random console p9fs
+.PATH: ${SRCTOP}/sys/dev/virtio/fs
+
+KMOD= vtfs
+SRCS= virtio_fs.c
+SRCS+= virtio_bus_if.h virtio_if.h
+SRCS+= bus_if.h device_if.h
-.include <bsd.subdir.mk>
+.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 8, 7:32 PM (12 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28489477
Default Alt Text
D46295.id156285.diff (18 KB)
Attached To
Mode
D46295: add virtio file system device support
Attached
Detach File
Event Timeline
Log In to Comment