svn commit: r366413 - in head: etc/mtree lib lib/lib9p share/mk usr.sbin/bhyve

Jakub Wojciech Klama jceel at FreeBSD.org
Sat Oct 3 19:05:15 UTC 2020


Author: jceel
Date: Sat Oct  3 19:05:13 2020
New Revision: 366413
URL: https://svnweb.freebsd.org/changeset/base/366413

Log:
  Add virtio-9p (aka VirtFS) filesystem sharing to bhyve.
  
  VirtFS allows sharing an arbitrary directory tree between bhyve virtual
  machine and the host. Current implementation has a fairly complete support
  for 9P2000.L protocol, except for the extended attribute support. It has
  been verified to work with the qemu-kvm hypervisor.
  
  Reviewed by:	rgrimes, emaste, jhb, trasz
  Approved by:	trasz (mentor)
  MFC after:	1 month
  Relnotes:	yes
  Sponsored by:	Conclusive Engineering (development), vStack.com (funding)
  Differential Revision:	https://reviews.freebsd.org/D10335

Added:
  head/lib/lib9p/
  head/lib/lib9p/Makefile   (contents, props changed)
  head/usr.sbin/bhyve/pci_virtio_9p.c   (contents, props changed)
Modified:
  head/etc/mtree/BSD.include.dist
  head/lib/Makefile
  head/share/mk/bsd.libnames.mk
  head/share/mk/src.libnames.mk
  head/usr.sbin/bhyve/Makefile
  head/usr.sbin/bhyve/bhyve.8
  head/usr.sbin/bhyve/virtio.h

Modified: head/etc/mtree/BSD.include.dist
==============================================================================
--- head/etc/mtree/BSD.include.dist	Sat Oct  3 18:52:54 2020	(r366412)
+++ head/etc/mtree/BSD.include.dist	Sat Oct  3 19:05:13 2020	(r366413)
@@ -193,6 +193,8 @@
     ..
     lib80211
     ..
+    lib9p
+    ..
     libipt
     ..
     libmilter

Modified: head/lib/Makefile
==============================================================================
--- head/lib/Makefile	Sat Oct  3 18:52:54 2020	(r366412)
+++ head/lib/Makefile	Sat Oct  3 19:05:13 2020	(r366413)
@@ -30,6 +30,7 @@ SUBDIR=	${SUBDIR_BOOTSTRAP} \
 	.WAIT \
 	libsqlite3 \
 	geom \
+	lib9p \
 	libalias \
 	libarchive \
 	libauditd \

Added: head/lib/lib9p/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/lib9p/Makefile	Sat Oct  3 19:05:13 2020	(r366413)
@@ -0,0 +1,28 @@
+# $FreeBSD$
+
+.PATH:		${.CURDIR}/../../contrib/lib9p
+CFLAGS+=	-DWITH_CASPER
+CFLAGS+=	-I${.CURDIR}
+CFLAGS+=	-I${.CURDIR}/../../contrib/lib9p
+
+LIB=		9p
+PACKAGE=	lib${LIB}
+SHLIB_MAJOR=	1
+SRCS=		connection.c \
+		genacl.c \
+		hashtable.c \
+		log.c \
+		pack.c \
+		request.c \
+		rfuncs.c \
+		threadpool.c \
+		utils.c \
+		backend/fs.c \
+		transport/socket.c
+
+INCSDIR=	${INCLUDEDIR}/lib9p
+INCS=		fid.h lib9p.h backend/fs.h
+
+LIBADD=		sbuf
+
+.include <bsd.lib.mk>

Modified: head/share/mk/bsd.libnames.mk
==============================================================================
--- head/share/mk/bsd.libnames.mk	Sat Oct  3 18:52:54 2020	(r366412)
+++ head/share/mk/bsd.libnames.mk	Sat Oct  3 19:05:13 2020	(r366413)
@@ -17,6 +17,7 @@ LIBDESTDIR=	${SYSROOT:U${DESTDIR}}
 LIBCRT0?=	${LIBDESTDIR}${LIBDIR_BASE}/crt0.o
 
 LIB80211?=	${LIBDESTDIR}${LIBDIR_BASE}/lib80211.a
+LIB9P?=		${LIBDESTDIR}${LIBDIR_BASE}/lib9p.a
 LIBALIAS?=	${LIBDESTDIR}${LIBDIR_BASE}/libalias.a
 LIBARCHIVE?=	${LIBDESTDIR}${LIBDIR_BASE}/libarchive.a
 LIBASN1?=	${LIBDESTDIR}${LIBDIR_BASE}/libasn1.a

Modified: head/share/mk/src.libnames.mk
==============================================================================
--- head/share/mk/src.libnames.mk	Sat Oct  3 18:52:54 2020	(r366412)
+++ head/share/mk/src.libnames.mk	Sat Oct  3 19:05:13 2020	(r366413)
@@ -70,6 +70,7 @@ _LIBRARIES=	\
 		${_INTERNALLIBS} \
 		${LOCAL_LIBRARIES} \
 		80211 \
+		9p \
 		alias \
 		archive \
 		asn1 \
@@ -246,6 +247,7 @@ LIBVERIEXEC?=	${LIBVERIEXECDIR}/libveriexec.a
 # Each library's LIBADD needs to be duplicated here for static linkage of
 # 2nd+ order consumers.  Auto-generating this would be better.
 _DP_80211=	sbuf bsdxml
+_DP_9p=		sbuf
 _DP_archive=	z bz2 lzma bsdxml zstd
 _DP_zstd=	pthread
 .if ${MK_BLACKLIST} != "no"

Modified: head/usr.sbin/bhyve/Makefile
==============================================================================
--- head/usr.sbin/bhyve/Makefile	Sat Oct  3 18:52:54 2020	(r366412)
+++ head/usr.sbin/bhyve/Makefile	Sat Oct  3 19:05:13 2020	(r366413)
@@ -3,6 +3,7 @@
 #
 
 .include <src.opts.mk>
+CFLAGS+=-I${.CURDIR}/../../contrib/lib9p
 CFLAGS+=-I${SRCTOP}/sys
 .PATH:  ${SRCTOP}/sys/cam/ctl
 
@@ -47,6 +48,7 @@ SRCS=	\
 	pci_lpc.c		\
 	pci_nvme.c		\
 	pci_passthru.c		\
+	pci_virtio_9p.c		\
 	pci_virtio_block.c	\
 	pci_virtio_console.c	\
 	pci_virtio_net.c	\
@@ -82,7 +84,7 @@ CFLAGS.kernemu_dev.c+=	-I${SRCTOP}/sys/amd64
 .PATH:  ${BHYVE_SYSDIR}/sys/amd64/vmm
 SRCS+=	vmm_instruction_emul.c
 
-LIBADD=	vmmapi md pthread z util sbuf cam
+LIBADD=	vmmapi md pthread z util sbuf cam 9p casper cap_pwd cap_grp
 .if ${MK_BHYVE_SNAPSHOT} != "no"
 LIBADD+= ucl xo
 .endif

Modified: head/usr.sbin/bhyve/bhyve.8
==============================================================================
--- head/usr.sbin/bhyve/bhyve.8	Sat Oct  3 18:52:54 2020	(r366412)
+++ head/usr.sbin/bhyve/bhyve.8	Sat Oct  3 19:05:13 2020	(r366413)
@@ -258,6 +258,8 @@ Virtio network interface.
 Virtio block storage interface.
 .It Li virtio-scsi
 Virtio SCSI interface.
+.It Li virtio-9p
+Virtio 9p (VirtFS) interface.
 .It Li virtio-rnd
 Virtio RNG interface.
 .It Li virtio-console
@@ -372,6 +374,19 @@ are:
 .It Li iid= Ns Ar IID
 Initiator ID to use when sending requests to specified CTL port.
 The default value is 0.
+.El
+.Pp
+9P devices:
+.Bl -tag -width 10n
+.It Pa sharename=/path/to/share[,9p-device-options]
+.El
+.Pp
+The
+.Ar 9p-device-options
+are:
+.Bl -tag -width 10n
+.It Li ro
+Expose the share in read-only mode.
 .El
 .Pp
 TTY devices:

Added: head/usr.sbin/bhyve/pci_virtio_9p.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bhyve/pci_virtio_9p.c	Sat Oct  3 19:05:13 2020	(r366413)
@@ -0,0 +1,344 @@
+/*-
+ * Copyright (c) 2015 iXsystems Inc.
+ * Copyright (c) 2017-2018 Jakub Klama <jceel at FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+/*
+ * VirtIO filesystem passthrough using 9p protocol.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/linker_set.h>
+#include <sys/uio.h>
+#include <sys/capsicum.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <pthread.h>
+
+#include <lib9p.h>
+#include <backend/fs.h>
+
+#include "bhyverun.h"
+#include "pci_emul.h"
+#include "virtio.h"
+
+#define	VT9P_MAX_IOV	128
+#define VT9P_RINGSZ	256
+#define	VT9P_MAXTAGSZ	256
+#define	VT9P_CONFIGSPACESZ	(VT9P_MAXTAGSZ + sizeof(uint16_t))
+
+static int pci_vt9p_debug;
+#define DPRINTF(params) if (pci_vt9p_debug) printf params
+#define WPRINTF(params) printf params
+
+/*
+ * Per-device softc
+ */
+struct pci_vt9p_softc {
+	struct virtio_softc      vsc_vs;
+	struct vqueue_info       vsc_vq;
+	pthread_mutex_t          vsc_mtx;
+	uint64_t                 vsc_cfg;
+	uint64_t                 vsc_features;
+	char *                   vsc_rootpath;
+	struct pci_vt9p_config * vsc_config;
+	struct l9p_backend *     vsc_fs_backend;
+	struct l9p_server *      vsc_server;
+        struct l9p_connection *  vsc_conn;
+};
+
+struct pci_vt9p_request {
+	struct pci_vt9p_softc *	vsr_sc;
+	struct iovec *		vsr_iov;
+	size_t			vsr_niov;
+	size_t			vsr_respidx;
+	size_t			vsr_iolen;
+	uint16_t		vsr_idx;
+};
+
+struct pci_vt9p_config {
+	uint16_t tag_len;
+	char tag[0];
+} __attribute__((packed));
+
+static int pci_vt9p_send(struct l9p_request *, const struct iovec *,
+    const size_t, const size_t, void *);
+static void pci_vt9p_drop(struct l9p_request *, const struct iovec *, size_t,
+    void *);
+static void pci_vt9p_reset(void *);
+static void pci_vt9p_notify(void *, struct vqueue_info *);
+static int pci_vt9p_cfgread(void *, int, int, uint32_t *);
+static void pci_vt9p_neg_features(void *, uint64_t);
+
+static struct virtio_consts vt9p_vi_consts = {
+	"vt9p",			/* our name */
+	1,			/* we support 1 virtqueue */
+	VT9P_CONFIGSPACESZ,	/* config reg size */
+	pci_vt9p_reset,		/* reset */
+	pci_vt9p_notify,	/* device-wide qnotify */
+	pci_vt9p_cfgread,	/* read virtio config */
+	NULL,			/* write virtio config */
+	pci_vt9p_neg_features,	/* apply negotiated features */
+	(1 << 0),		/* our capabilities */
+};
+
+
+static void
+pci_vt9p_reset(void *vsc)
+{
+	struct pci_vt9p_softc *sc;
+
+	sc = vsc;
+
+	DPRINTF(("vt9p: device reset requested !\n"));
+	vi_reset_dev(&sc->vsc_vs);
+}
+
+static void
+pci_vt9p_neg_features(void *vsc, uint64_t negotiated_features)
+{
+	struct pci_vt9p_softc *sc = vsc;
+
+	sc->vsc_features = negotiated_features;
+}
+
+static int
+pci_vt9p_cfgread(void *vsc, int offset, int size, uint32_t *retval)
+{
+	struct pci_vt9p_softc *sc = vsc;
+	void *ptr;
+
+	ptr = (uint8_t *)sc->vsc_config + offset;
+	memcpy(retval, ptr, size);
+	return (0);
+}
+
+static int
+pci_vt9p_get_buffer(struct l9p_request *req, struct iovec *iov, size_t *niov,
+    void *arg)
+{
+	struct pci_vt9p_request *preq = req->lr_aux;
+	size_t n = preq->vsr_niov - preq->vsr_respidx;
+	
+	memcpy(iov, preq->vsr_iov + preq->vsr_respidx,
+	    n * sizeof(struct iovec));
+	*niov = n;
+	return (0);
+}
+
+static int
+pci_vt9p_send(struct l9p_request *req, const struct iovec *iov,
+    const size_t niov, const size_t iolen, void *arg)
+{
+	struct pci_vt9p_request *preq = req->lr_aux;
+	struct pci_vt9p_softc *sc = preq->vsr_sc;
+
+	preq->vsr_iolen = iolen;
+
+	pthread_mutex_lock(&sc->vsc_mtx);
+	vq_relchain(&sc->vsc_vq, preq->vsr_idx, preq->vsr_iolen);
+	vq_endchains(&sc->vsc_vq, 1);
+	pthread_mutex_unlock(&sc->vsc_mtx);
+	free(preq);
+	return (0);
+}
+
+static void
+pci_vt9p_drop(struct l9p_request *req, const struct iovec *iov, size_t niov,
+    void *arg)
+{
+	struct pci_vt9p_request *preq = req->lr_aux;
+	struct pci_vt9p_softc *sc = preq->vsr_sc;
+
+	pthread_mutex_lock(&sc->vsc_mtx);
+	vq_relchain(&sc->vsc_vq, preq->vsr_idx, 0);
+	vq_endchains(&sc->vsc_vq, 1);
+	pthread_mutex_unlock(&sc->vsc_mtx);
+	free(preq);
+}
+
+static void
+pci_vt9p_notify(void *vsc, struct vqueue_info *vq)
+{
+	struct iovec iov[VT9P_MAX_IOV];
+	struct pci_vt9p_softc *sc;
+	struct pci_vt9p_request *preq;
+	uint16_t idx, n, i;
+	uint16_t flags[VT9P_MAX_IOV];
+
+	sc = vsc;
+
+	while (vq_has_descs(vq)) {
+		n = vq_getchain(vq, &idx, iov, VT9P_MAX_IOV, flags);
+		preq = calloc(1, sizeof(struct pci_vt9p_request));
+		preq->vsr_sc = sc;
+		preq->vsr_idx = idx;
+		preq->vsr_iov = iov;
+		preq->vsr_niov = n;
+		preq->vsr_respidx = 0;
+
+		/* Count readable descriptors */
+		for (i = 0; i < n; i++) {
+			if (flags[i] & VRING_DESC_F_WRITE)
+				break;
+
+			preq->vsr_respidx++;
+		}
+
+		for (int i = 0; i < n; i++) {
+			DPRINTF(("vt9p: vt9p_notify(): desc%d base=%p, "
+			    "len=%zu, flags=0x%04x\r\n", i, iov[i].iov_base,
+			    iov[i].iov_len, flags[i]));
+		}
+
+		l9p_connection_recv(sc->vsc_conn, iov, preq->vsr_respidx, preq);
+	}
+}
+
+
+static int
+pci_vt9p_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
+{
+	struct pci_vt9p_softc *sc;
+	char *opt;
+	char *sharename = NULL;
+	char *rootpath = NULL;
+	int rootfd;
+	bool ro = false;
+	cap_rights_t rootcap;
+
+	if (opts == NULL) {
+		printf("virtio-9p: share name and path required\n");
+		return (1);
+	}
+
+	while ((opt = strsep(&opts, ",")) != NULL) {
+		if (strchr(opt, '=') != NULL) {
+			if (sharename != NULL) {
+				printf("virtio-9p: more than one share name given\n");
+				return (1);
+			}
+
+			sharename = strsep(&opt, "=");
+			rootpath = opt;
+			continue;
+		}
+
+		if (strcmp(opt, "ro") == 0) {
+			DPRINTF(("read-only mount requested\r\n"));
+			ro = true;
+			continue;
+		}
+
+		printf("virtio-9p: invalid option '%s'\n", opt);
+		return (1);
+	}
+
+	if (strlen(sharename) > VT9P_MAXTAGSZ) {
+		printf("virtio-9p: share name too long\n");
+		return (1);
+	}
+
+	rootfd = open(rootpath, O_DIRECTORY);
+	if (rootfd < 0)
+		return (-1);
+
+	sc = calloc(1, sizeof(struct pci_vt9p_softc));
+	sc->vsc_config = calloc(1, sizeof(struct pci_vt9p_config) +
+	    VT9P_MAXTAGSZ);
+
+	pthread_mutex_init(&sc->vsc_mtx, NULL);
+
+	cap_rights_init(&rootcap,
+	    CAP_LOOKUP, CAP_ACL_CHECK, CAP_ACL_DELETE, CAP_ACL_GET,
+	    CAP_ACL_SET, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_FSTAT,
+	    CAP_CREATE, CAP_FCHMODAT, CAP_FCHOWNAT, CAP_FTRUNCATE,
+	    CAP_LINKAT_SOURCE, CAP_LINKAT_TARGET, CAP_MKDIRAT, CAP_MKNODAT,
+	    CAP_PREAD, CAP_PWRITE, CAP_RENAMEAT_SOURCE, CAP_RENAMEAT_TARGET,
+	    CAP_SEEK, CAP_SYMLINKAT, CAP_UNLINKAT, CAP_EXTATTR_DELETE,
+	    CAP_EXTATTR_GET, CAP_EXTATTR_LIST, CAP_EXTATTR_SET,
+	    CAP_FUTIMES, CAP_FSTATFS, CAP_FSYNC, CAP_FPATHCONF);
+
+	if (cap_rights_limit(rootfd, &rootcap) != 0)
+		return (1);
+
+	sc->vsc_config->tag_len = (uint16_t)strlen(sharename);
+	memcpy(sc->vsc_config->tag, sharename, sc->vsc_config->tag_len);
+	
+	if (l9p_backend_fs_init(&sc->vsc_fs_backend, rootfd, ro) != 0) {
+		errno = ENXIO;
+		return (1);
+	}
+
+	if (l9p_server_init(&sc->vsc_server, sc->vsc_fs_backend) != 0) {
+		errno = ENXIO;
+		return (1);
+	}
+
+	if (l9p_connection_init(sc->vsc_server, &sc->vsc_conn) != 0) {
+		errno = EIO;
+		return (1);
+	}
+
+	sc->vsc_conn->lc_msize = L9P_MAX_IOV * PAGE_SIZE;
+	sc->vsc_conn->lc_lt.lt_get_response_buffer = pci_vt9p_get_buffer;
+	sc->vsc_conn->lc_lt.lt_send_response = pci_vt9p_send;
+	sc->vsc_conn->lc_lt.lt_drop_response = pci_vt9p_drop;
+
+	vi_softc_linkup(&sc->vsc_vs, &vt9p_vi_consts, sc, pi, &sc->vsc_vq);
+	sc->vsc_vs.vs_mtx = &sc->vsc_mtx;
+	sc->vsc_vq.vq_qsize = VT9P_RINGSZ;
+
+	/* initialize config space */
+	pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_9P);
+	pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
+	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE);
+	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_9P);
+	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);
+
+	if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix()))
+		return (1);
+	vi_set_io_bar(&sc->vsc_vs, 0);
+
+	return (0);
+}
+
+struct pci_devemu pci_de_v9p = {
+	.pe_emu =	"virtio-9p",
+	.pe_init =	pci_vt9p_init,
+	.pe_barwrite =	vi_pci_write,
+	.pe_barread =	vi_pci_read
+};
+PCI_EMUL_SET(pci_de_v9p);

Modified: head/usr.sbin/bhyve/virtio.h
==============================================================================
--- head/usr.sbin/bhyve/virtio.h	Sat Oct  3 18:52:54 2020	(r366412)
+++ head/usr.sbin/bhyve/virtio.h	Sat Oct  3 19:05:13 2020	(r366413)
@@ -216,6 +216,7 @@ struct vring_used {
 #define	VIRTIO_DEV_CONSOLE	0x1003
 #define	VIRTIO_DEV_RANDOM	0x1005
 #define	VIRTIO_DEV_SCSI		0x1008
+#define	VIRTIO_DEV_9P		0x1009
 
 /*
  * PCI config space constants.


More information about the svn-src-all mailing list