Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102626854
D31325.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D31325.diff
View Options
diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h
--- a/lib/libvmmapi/vmmapi.h
+++ b/lib/libvmmapi/vmmapi.h
@@ -33,6 +33,7 @@
#include <sys/param.h>
#include <sys/cpuset.h>
+#include <machine/vmm.h>
#include <machine/vmm_dev.h>
#include <stdbool.h>
@@ -113,6 +114,10 @@
int vm_munmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, size_t len);
+int vmmctl_open(void);
+int vm_fcreate(int fd, const char *name, bool persistent);
+int vm_fdestroy(int fd, const char *name);
+
int vm_create(const char *name);
int vm_get_device_fd(struct vmctx *ctx);
struct vmctx *vm_open(const char *name);
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
--- a/lib/libvmmapi/vmmapi.c
+++ b/lib/libvmmapi/vmmapi.c
@@ -105,6 +105,49 @@
return (fd);
}
+int
+vmmctl_open(void)
+{
+ /* Try to load vmm(4) */
+ if (modfind("vmm") < 0)
+ kldload("vmm");
+
+ return (open("/dev/vmmctl", O_RDWR));
+}
+
+int
+vm_fcreate(int fd, const char *name, bool persistent)
+{
+ struct vmmctl_create_op op;
+
+ if (strlen(name) > VM_MAX_NAMELEN) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+
+ strcpy(op.name, name);
+
+ op.flags = 0;
+ if (persistent)
+ op.flags |= VMMCTL_CREATE_PERSISTENT;
+
+ return (ioctl(fd, VMMCTL_CREATE, &op));
+}
+
+int
+vm_fdestroy(int fd, const char *name)
+{
+ struct vmmctl_destroy_op op;
+
+ if (strlen(name) > VM_MAX_NAMELEN) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+
+ strcpy(op.name, name);
+ return (ioctl(fd, VMMCTL_DESTROY, &op));
+}
+
int
vm_create(const char *name)
{
diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h
--- a/sys/amd64/include/vmm_dev.h
+++ b/sys/amd64/include/vmm_dev.h
@@ -347,6 +347,23 @@
IOCNUM_RESTORE_TIME = 115
};
+struct vmmctl_create_op {
+ char name[VM_MAX_NAMELEN + 1];
+ int flags;
+ uint64_t reserved[16];
+};
+#define VMMCTL_CREATE_PERSISTENT 0x01
+
+struct vmmctl_destroy_op {
+ char name[VM_MAX_NAMELEN + 1];
+ uint64_t reserved[16];
+};
+
+#define VMMCTL_CREATE \
+ _IOWR('v', 101, struct vmmctl_create_op)
+#define VMMCTL_DESTROY \
+ _IOWR('v', 102, struct vmmctl_destroy_op)
+
#define VM_RUN \
_IOWR('v', IOCNUM_RUN, struct vm_run)
#define VM_SUSPEND \
diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c
--- a/sys/amd64/vmm/vmm_dev.c
+++ b/sys/amd64/vmm/vmm_dev.c
@@ -79,12 +79,14 @@
};
struct vmmdev_softc {
- struct vm *vm; /* vm instance cookie */
+ struct vm *vm; /* vm instance cookie */
struct cdev *cdev;
struct ucred *ucred;
SLIST_ENTRY(vmmdev_softc) link;
SLIST_HEAD(, devmem_softc) devmem;
int flags;
+ TAILQ_ENTRY(vmmdev_softc) fvmm_next; /* next entry in fvmm list */
+ bool persistent;
};
#define VSC_LINKED 0x01
@@ -1063,6 +1065,11 @@
mtx_lock(&vmmdev_mtx);
sc = vmmdev_lookup(buf);
+ if (!sc->persistent) {
+ mtx_unlock(&vmmdev_mtx);
+ error = EPERM;
+ goto out;
+ }
error = vmm_destroy(sc);
mtx_unlock(&vmmdev_mtx);
@@ -1085,11 +1092,63 @@
};
static int
-sysctl_vmm_create(SYSCTL_HANDLER_ARGS)
+vmm_create(const char *name, bool persistent, struct vmmdev_softc **sc)
{
- struct vm *vm;
struct cdev *cdev;
- struct vmmdev_softc *sc, *sc2;
+ struct vm *vm;
+ struct vmmdev_softc *tsc;
+ int error;
+
+ error = vm_create(name, &vm);
+ if (error != 0)
+ return (error);
+
+ tsc = malloc(sizeof(struct vmmdev_softc), M_VMMDEV, M_WAITOK | M_ZERO);
+ tsc->ucred = crhold(curthread->td_ucred);
+ tsc->vm = vm;
+ tsc->persistent = persistent;
+ SLIST_INIT(&tsc->devmem);
+
+ error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &vmmdevsw, tsc->ucred,
+ UID_ROOT, GID_WHEEL, 0600, "vmm/%s", name);
+ if (error != 0) {
+ vmmdev_destroy(tsc);
+ return (error);
+ }
+
+ tsc->cdev = cdev;
+ tsc->cdev->si_drv1 = tsc;
+ *sc = tsc;
+
+ return (0);
+}
+
+static int
+vmm_add(struct vmmdev_softc *sc)
+{
+ struct vmmdev_softc *tsc;
+
+ mtx_assert(&vmmdev_mtx, MA_OWNED);
+
+ /*
+ * Lookup the name just in case somebody sneaked in.
+ */
+ tsc = vmmdev_lookup(vm_name(sc->vm));
+ if (tsc == NULL) {
+ SLIST_INSERT_HEAD(&head, sc, link);
+ sc->flags |= VSC_LINKED;
+ }
+
+ if (tsc != NULL)
+ return (EEXIST);
+
+ return (0);
+}
+
+static int
+sysctl_vmm_create(SYSCTL_HANDLER_ARGS)
+{
+ struct vmmdev_softc *sc;
char *buf;
int error;
size_t buflen;
@@ -1105,52 +1164,21 @@
if (error != 0 || req->newptr == NULL)
goto out;
- mtx_lock(&vmmdev_mtx);
sc = vmmdev_lookup(buf);
- mtx_unlock(&vmmdev_mtx);
if (sc != NULL) {
error = EEXIST;
goto out;
}
- error = vm_create(buf, &vm);
+ error = vmm_create(buf, true, &sc);
if (error != 0)
goto out;
- sc = malloc(sizeof(struct vmmdev_softc), M_VMMDEV, M_WAITOK | M_ZERO);
- sc->ucred = crhold(curthread->td_ucred);
- sc->vm = vm;
- SLIST_INIT(&sc->devmem);
-
- /*
- * Lookup the name again just in case somebody sneaked in when we
- * dropped the lock.
- */
- mtx_lock(&vmmdev_mtx);
- sc2 = vmmdev_lookup(buf);
- if (sc2 == NULL) {
- SLIST_INSERT_HEAD(&head, sc, link);
- sc->flags |= VSC_LINKED;
- }
- mtx_unlock(&vmmdev_mtx);
-
- if (sc2 != NULL) {
- vmmdev_destroy(sc);
- error = EEXIST;
- goto out;
- }
-
- error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &vmmdevsw, sc->ucred,
- UID_ROOT, GID_WHEEL, 0600, "vmm/%s", buf);
- if (error != 0) {
- vmmdev_destroy(sc);
- goto out;
- }
-
mtx_lock(&vmmdev_mtx);
- sc->cdev = cdev;
- sc->cdev->si_drv1 = sc;
+ error = vmm_add(sc);
mtx_unlock(&vmmdev_mtx);
+ if (error != 0)
+ vmm_destroy(sc);
out:
free(buf, M_VMMDEV);
@@ -1161,73 +1189,6 @@
NULL, 0, sysctl_vmm_create, "A",
NULL);
-static void
-vmmdev_prison_cleanup(struct prison *pr)
-{
- struct vmmdev_softc *sc;
- struct vmmdev_softc *tsc;
-
- mtx_lock(&vmmdev_mtx);
-
- SLIST_FOREACH_SAFE(sc, &head, link, tsc) {
- if (sc->ucred->cr_prison == pr)
- vmm_destroy(sc);
- }
-
- mtx_unlock(&vmmdev_mtx);
-}
-
-static int
-vmmdev_prison_remove(void *obj, void *data __unused)
-{
- struct prison *pr = obj;
-
- vmmdev_prison_cleanup(pr);
- return (0);
-}
-
-static int
-vmmdev_prison_set(void *obj, void *data)
-{
- struct prison *pr = obj;
- struct vfsoptlist *opts = data;
-
- if (vfs_flagopt(opts, "allow.novmm", NULL, 0))
- vmmdev_prison_cleanup(pr);
-
- return (0);
-}
-
-void
-vmmdev_init(void)
-{
- osd_method_t methods[PR_MAXMETHOD] = {
- [PR_METHOD_SET] = vmmdev_prison_set,
- [PR_METHOD_REMOVE] = vmmdev_prison_remove,
- };
-
- mtx_init(&vmmdev_mtx, "vmm device mutex", NULL, MTX_DEF);
- pr_allow_flag = prison_add_allow(NULL, "vmm", NULL,
- "Allow use of vmm in a jail.");
-
- vmmdev_prison_slot = osd_jail_register(NULL, methods);
-}
-
-int
-vmmdev_cleanup(void)
-{
- int error;
-
- if (SLIST_EMPTY(&head)) {
- osd_jail_deregister(vmmdev_prison_slot);
- error = 0;
- } else {
- error = EBUSY;
- }
-
- return (error);
-}
-
static int
devmem_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, vm_size_t len,
struct vm_object **objp, int nprot)
@@ -1322,3 +1283,184 @@
dsc->cdev = NULL;
dsc->sc = NULL;
}
+
+struct fvmm {
+ TAILQ_HEAD(softc_list, vmmdev_softc) scs;
+};
+
+static int
+fvmm_destroy(struct fvmm *fvmm, const char *name)
+{
+ struct vmmdev_softc *sc, *tsc;
+ int error = ENOENT;
+
+ mtx_lock(&vmmdev_mtx);
+ TAILQ_FOREACH_SAFE(sc, &fvmm->scs, fvmm_next, tsc) {
+ if (strcmp(vm_name(sc->vm), name) == 0) {
+ vmm_destroy(sc);
+ TAILQ_REMOVE(&fvmm->scs, sc, fvmm_next);
+ error = 0;
+ }
+ }
+ mtx_unlock(&vmmdev_mtx);
+
+ return (error);
+}
+
+static void
+fvmm_dtor(void *data)
+{
+ struct fvmm *fvmm = data;
+ struct vmmdev_softc *sc;
+
+ mtx_lock(&vmmdev_mtx);
+ while ((sc = TAILQ_FIRST(&fvmm->scs))) {
+ TAILQ_REMOVE(&fvmm->scs, sc, fvmm_next);
+ if (!sc->persistent)
+ vmm_destroy(sc);
+ }
+ mtx_unlock(&vmmdev_mtx);
+ free(fvmm, M_VMMDEV);
+}
+
+static int
+vmmctl_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ struct fvmm *fvmm;
+ int error;
+
+ fvmm = malloc(sizeof(struct fvmm), M_VMMDEV, M_WAITOK | M_ZERO);
+ TAILQ_INIT(&fvmm->scs);
+ error = devfs_set_cdevpriv(fvmm, fvmm_dtor);
+ if (error)
+ fvmm_dtor(fvmm);
+ return (error);
+}
+
+static int
+vmmctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
+ struct thread *td)
+{
+ struct fvmm *fvmm;
+ struct vmmdev_softc *sc;
+ struct vmmctl_create_op *create_op;
+ struct vmmctl_destroy_op *destroy_op;
+ bool persistent;
+ int error = 0;
+
+ devfs_get_cdevpriv((void **)&fvmm);
+
+ switch (cmd) {
+ case VMMCTL_CREATE:
+ create_op = (struct vmmctl_create_op *)data;
+ if (strnlen(create_op->name, VM_MAX_NAMELEN + 1) ==
+ VM_MAX_NAMELEN + 1) {
+ error = EINVAL;
+ break;
+ }
+ persistent = create_op->flags & VMMCTL_CREATE_PERSISTENT;
+ error = vmm_create(create_op->name, persistent, &sc);
+ if (error)
+ break;
+ mtx_lock(&vmmdev_mtx);
+ error = vmm_add(sc);
+ if (error) {
+ vmm_destroy(sc);
+ mtx_unlock(&vmmdev_mtx);
+ break;
+ }
+ TAILQ_INSERT_HEAD(&fvmm->scs, sc, fvmm_next);
+ mtx_unlock(&vmmdev_mtx);
+ break;
+ case VMMCTL_DESTROY:
+ destroy_op = (struct vmmctl_destroy_op *)data;
+ if (strnlen(destroy_op->name, VM_MAX_NAMELEN + 1) ==
+ VM_MAX_NAMELEN + 1) {
+ error = EINVAL;
+ break;
+ }
+ error = fvmm_destroy(fvmm, destroy_op->name);
+ break;
+ }
+
+ return (error);
+}
+
+static void
+vmmdev_prison_cleanup(struct prison *pr)
+{
+ struct vmmdev_softc *sc;
+ struct vmmdev_softc *tsc;
+
+ mtx_lock(&vmmdev_mtx);
+
+ SLIST_FOREACH_SAFE(sc, &head, link, tsc) {
+ if (sc->ucred->cr_prison == pr)
+ vmm_destroy(sc);
+ }
+
+ mtx_unlock(&vmmdev_mtx);
+}
+
+static int
+vmmdev_prison_remove(void *obj, void *data __unused)
+{
+ struct prison *pr = obj;
+
+ vmmdev_prison_cleanup(pr);
+ return (0);
+}
+
+static int
+vmmdev_prison_set(void *obj, void *data)
+{
+ struct prison *pr = obj;
+ struct vfsoptlist *opts = data;
+
+ if (vfs_flagopt(opts, "allow.novmm", NULL, 0))
+ vmmdev_prison_cleanup(pr);
+
+ return (0);
+}
+
+static struct cdevsw vmmctl_cdevsw = {
+ .d_version = D_VERSION,
+ .d_open = vmmctl_open,
+ .d_ioctl = vmmctl_ioctl,
+ .d_name = "vmmctl",
+};
+static struct cdev *vmmctl_dev;
+
+void
+vmmdev_init(void)
+{
+ osd_method_t methods[PR_MAXMETHOD] = {
+ [PR_METHOD_SET] = vmmdev_prison_set,
+ [PR_METHOD_REMOVE] = vmmdev_prison_remove,
+ };
+
+ mtx_init(&vmmdev_mtx, "vmm device mutex", NULL, MTX_DEF);
+ pr_allow_flag = prison_add_allow(NULL, "vmm", NULL,
+ "Allow use of vmm in a jail.");
+
+ vmmdev_prison_slot = osd_jail_register(NULL, methods);
+
+ vmmctl_dev = make_dev(&vmmctl_cdevsw, 0,
+ UID_ROOT, GID_WHEEL, 0600, "vmmctl");
+}
+
+int
+vmmdev_cleanup(void)
+{
+ int error;
+
+ if (SLIST_EMPTY(&head)) {
+ osd_jail_deregister(vmmdev_prison_slot);
+ destroy_dev(vmmctl_dev);
+ error = 0;
+ } else {
+ error = EBUSY;
+ }
+
+ return (error);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 16, 12:39 AM (21 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14650021
Default Alt Text
D31325.diff (10 KB)
Attached To
Mode
D31325: vmm: Add new device file that handles creation/destruction of VMs
Attached
Detach File
Event Timeline
Log In to Comment