mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-26 20:12:44 +00:00
libvmmapi: Use the vmmctl device file to create and destroy VMs
This deprecates the vm_create() and vm_open() interfaces and introduces vm_openf(), which takes flags controlling its behaviour. In particular, it will optionally create a VM first, and it can optionally reinitialize an existing VM. This enables some simplification of existing consumers. Reviewed by: jhb Differential Revision: https://reviews.freebsd.org/D47030
This commit is contained in:
parent
ebd48f1e52
commit
99127fd103
@ -16,7 +16,8 @@ enum {
|
||||
};
|
||||
|
||||
struct vmctx {
|
||||
int fd;
|
||||
int fd; /* device file descriptor */
|
||||
int ctlfd; /* vmm control descriptor */
|
||||
struct {
|
||||
vm_paddr_t base;
|
||||
vm_size_t size;
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <sys/cpuset.h>
|
||||
|
||||
#include <capsicum_helpers.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
@ -50,11 +51,12 @@
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <machine/vmm.h>
|
||||
#include <machine/vmm_dev.h>
|
||||
#ifdef WITH_VMMAPI_SNAPSHOT
|
||||
#include <machine/vmm_snapshot.h>
|
||||
#endif
|
||||
|
||||
#include <dev/vmm/vmm_dev.h>
|
||||
|
||||
#include "vmmapi.h"
|
||||
#include "internal.h"
|
||||
|
||||
@ -78,58 +80,104 @@
|
||||
#define PROT_RW (PROT_READ | PROT_WRITE)
|
||||
#define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC)
|
||||
|
||||
#define CREATE(x) sysctlbyname("hw.vmm.create", NULL, NULL, (x), strlen((x)))
|
||||
#define DESTROY(x) sysctlbyname("hw.vmm.destroy", NULL, NULL, (x), strlen((x)))
|
||||
|
||||
static int
|
||||
vm_device_open(const char *name)
|
||||
{
|
||||
int fd, len;
|
||||
char *vmfile;
|
||||
char devpath[PATH_MAX];
|
||||
|
||||
len = strlen("/dev/vmm/") + strlen(name) + 1;
|
||||
vmfile = malloc(len);
|
||||
assert(vmfile != NULL);
|
||||
snprintf(vmfile, len, "/dev/vmm/%s", name);
|
||||
assert(strlen(name) <= VM_MAX_NAMELEN);
|
||||
(void)snprintf(devpath, sizeof(devpath), "/dev/vmm/%s", name);
|
||||
return (open(devpath, O_RDWR));
|
||||
}
|
||||
|
||||
/* Open the device file */
|
||||
fd = open(vmfile, O_RDWR, 0);
|
||||
static int
|
||||
vm_ctl_create(const char *name, int ctlfd)
|
||||
{
|
||||
struct vmmctl_vm_create vmc;
|
||||
|
||||
free(vmfile);
|
||||
return (fd);
|
||||
memset(&vmc, 0, sizeof(vmc));
|
||||
if (strlcpy(vmc.name, name, sizeof(vmc.name)) >= sizeof(vmc.name)) {
|
||||
errno = ENAMETOOLONG;
|
||||
return (-1);
|
||||
}
|
||||
return (ioctl(ctlfd, VMMCTL_VM_CREATE, &vmc));
|
||||
}
|
||||
|
||||
int
|
||||
vm_create(const char *name)
|
||||
{
|
||||
int error, fd;
|
||||
|
||||
/* Try to load vmm(4) module before creating a guest. */
|
||||
if (modfind("vmm") < 0)
|
||||
kldload("vmm");
|
||||
return (CREATE(name));
|
||||
if (modfind("vmm") < 0) {
|
||||
error = kldload("vmm");
|
||||
if (error != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
fd = open("/dev/vmmctl", O_RDWR, 0);
|
||||
if (fd < 0)
|
||||
return (fd);
|
||||
error = vm_ctl_create(name, fd);
|
||||
if (error != 0) {
|
||||
error = errno;
|
||||
(void)close(fd);
|
||||
errno = error;
|
||||
return (-1);
|
||||
}
|
||||
(void)close(fd);
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct vmctx *
|
||||
vm_open(const char *name)
|
||||
{
|
||||
return (vm_openf(name, 0));
|
||||
}
|
||||
|
||||
struct vmctx *
|
||||
vm_openf(const char *name, int flags)
|
||||
{
|
||||
struct vmctx *vm;
|
||||
int saved_errno;
|
||||
bool created;
|
||||
|
||||
created = false;
|
||||
|
||||
vm = malloc(sizeof(struct vmctx) + strlen(name) + 1);
|
||||
assert(vm != NULL);
|
||||
|
||||
vm->fd = -1;
|
||||
vm->fd = vm->ctlfd = -1;
|
||||
vm->memflags = 0;
|
||||
vm->name = (char *)(vm + 1);
|
||||
strcpy(vm->name, name);
|
||||
memset(vm->memsegs, 0, sizeof(vm->memsegs));
|
||||
|
||||
if ((vm->fd = vm_device_open(vm->name)) < 0)
|
||||
if ((vm->ctlfd = open("/dev/vmmctl", O_RDWR, 0)) < 0)
|
||||
goto err;
|
||||
|
||||
vm->fd = vm_device_open(vm->name);
|
||||
if (vm->fd < 0 && errno == ENOENT) {
|
||||
if (flags & VMMAPI_OPEN_CREATE) {
|
||||
if (vm_ctl_create(vm->name, vm->ctlfd) != 0)
|
||||
goto err;
|
||||
vm->fd = vm_device_open(vm->name);
|
||||
created = true;
|
||||
}
|
||||
}
|
||||
if (vm->fd < 0)
|
||||
goto err;
|
||||
|
||||
if (!created && (flags & VMMAPI_OPEN_REINIT) != 0 && vm_reinit(vm) != 0)
|
||||
goto err;
|
||||
|
||||
return (vm);
|
||||
err:
|
||||
saved_errno = errno;
|
||||
free(vm);
|
||||
if (created)
|
||||
vm_destroy(vm);
|
||||
else
|
||||
vm_close(vm);
|
||||
errno = saved_errno;
|
||||
return (NULL);
|
||||
}
|
||||
@ -139,20 +187,24 @@ vm_close(struct vmctx *vm)
|
||||
{
|
||||
assert(vm != NULL);
|
||||
|
||||
close(vm->fd);
|
||||
if (vm->fd >= 0)
|
||||
(void)close(vm->fd);
|
||||
if (vm->ctlfd >= 0)
|
||||
(void)close(vm->ctlfd);
|
||||
free(vm);
|
||||
}
|
||||
|
||||
void
|
||||
vm_destroy(struct vmctx *vm)
|
||||
{
|
||||
assert(vm != NULL);
|
||||
struct vmmctl_vm_destroy vmd;
|
||||
|
||||
if (vm->fd >= 0)
|
||||
close(vm->fd);
|
||||
DESTROY(vm->name);
|
||||
memset(&vmd, 0, sizeof(vmd));
|
||||
(void)strlcpy(vmd.name, vm->name, sizeof(vmd.name));
|
||||
if (ioctl(vm->ctlfd, VMMCTL_VM_DESTROY, &vmd) != 0)
|
||||
warn("ioctl(VMMCTL_VM_DESTROY)");
|
||||
|
||||
free(vm);
|
||||
vm_close(vm);
|
||||
}
|
||||
|
||||
struct vcpu *
|
||||
|
@ -117,6 +117,9 @@ int vm_munmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, size_t len);
|
||||
|
||||
int vm_create(const char *name);
|
||||
struct vmctx *vm_open(const char *name);
|
||||
#define VMMAPI_OPEN_CREATE 0x01 /* create if the VM does not exist */
|
||||
#define VMMAPI_OPEN_REINIT 0x02 /* reinitialize the VM if it exists */
|
||||
struct vmctx *vm_openf(const char *name, int flags);
|
||||
void vm_close(struct vmctx *ctx);
|
||||
void vm_destroy(struct vmctx *ctx);
|
||||
int vm_limit_rights(struct vmctx *ctx);
|
||||
|
Loading…
Reference in New Issue
Block a user