bhyve: Remove vmctx member from struct vm_snapshot_meta.

This is a userland-only pointer that isn't relevant to the kernel and
doesn't belong in the ioctl structure shared between userland and the
kernel.  For the kernel, the old structure for the ioctl is still
supported under COMPAT_FREEBSD13.

This changes vm_snapshot_req() in libvmmapi to accept an explicit
vmctx argument.

It also changes vm_snapshot_guest2host_addr to take an explicit vmctx
argument.  As part of this change, move the declaration for this
function and its wrapper macro from vmm_snapshot.h to snapshot.h as it
is a userland-only API.

Reviewed by:	corvink, markj
Differential Revision:	https://reviews.freebsd.org/D38125
This commit is contained in:
John Baldwin 2023-03-24 11:49:06 -07:00
parent 7d9ef309bd
commit 0f735657aa
11 changed files with 107 additions and 75 deletions

View file

@ -1712,10 +1712,10 @@ vm_restart_instruction(struct vcpu *vcpu)
}
int
vm_snapshot_req(struct vm_snapshot_meta *meta)
vm_snapshot_req(struct vmctx *ctx, struct vm_snapshot_meta *meta)
{
if (ioctl(meta->ctx->fd, VM_SNAPSHOT_REQ, meta) == -1) {
if (ioctl(ctx->fd, VM_SNAPSHOT_REQ, meta) == -1) {
#ifdef SNAPSHOT_DEBUG
fprintf(stderr, "%s: snapshot failed for %s: %d\r\n",
__func__, meta->dev_name, errno);

View file

@ -265,7 +265,7 @@ void vm_setup_freebsd_gdt(uint64_t *gdtr);
/*
* Save and restore
*/
int vm_snapshot_req(struct vm_snapshot_meta *meta);
int vm_snapshot_req(struct vmctx *ctx, struct vm_snapshot_meta *meta);
int vm_restore_time(struct vmctx *ctx);
/*

View file

@ -44,8 +44,6 @@
#include <stdbool.h>
#endif
struct vmctx;
enum snapshot_req {
STRUCT_VIOAPIC = 1,
STRUCT_VM,
@ -89,7 +87,6 @@ enum vm_snapshot_op {
};
struct vm_snapshot_meta {
struct vmctx *ctx;
void *dev_data;
const char *dev_name; /* identify userspace devices */
enum snapshot_req dev_req; /* identify kernel structs */
@ -103,8 +100,6 @@ void vm_snapshot_buf_err(const char *bufname, const enum vm_snapshot_op op);
int vm_snapshot_buf(void *data, size_t data_size,
struct vm_snapshot_meta *meta);
size_t vm_get_snapshot_size(struct vm_snapshot_meta *meta);
int vm_snapshot_guest2host_addr(void **addrp, size_t len, bool restore_null,
struct vm_snapshot_meta *meta);
int vm_snapshot_buf_cmp(void *data, size_t data_size,
struct vm_snapshot_meta *meta);
@ -120,24 +115,6 @@ do { \
#define SNAPSHOT_VAR_OR_LEAVE(DATA, META, RES, LABEL) \
SNAPSHOT_BUF_OR_LEAVE(&(DATA), sizeof(DATA), (META), (RES), LABEL)
/*
* Address variables are pointers to guest memory.
*
* When RNULL != 0, do not enforce invalid address checks; instead, make the
* pointer NULL at restore time.
*/
#define SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(ADDR, LEN, RNULL, META, RES, LABEL) \
do { \
(RES) = vm_snapshot_guest2host_addr((void **)&(ADDR), (LEN), (RNULL), \
(META)); \
if ((RES) != 0) { \
if ((RES) == EFAULT) \
fprintf(stderr, "%s: invalid address: %s\r\n", \
__func__, #ADDR); \
goto LABEL; \
} \
} while (0)
/* compare the value in the meta buffer with the data */
#define SNAPSHOT_BUF_CMP_OR_LEAVE(DATA, LEN, META, RES, LABEL) \
do { \

View file

@ -79,6 +79,20 @@ struct vm_stats_old {
#define VM_STATS_OLD \
_IOWR('v', IOCNUM_VM_STATS, struct vm_stats_old)
struct vm_snapshot_meta_old {
void *ctx; /* unused */
void *dev_data;
const char *dev_name; /* identify userspace devices */
enum snapshot_req dev_req; /* identify kernel structs */
struct vm_snapshot_buffer buffer;
enum vm_snapshot_op op;
};
#define VM_SNAPSHOT_REQ_OLD \
_IOWR('v', IOCNUM_SNAPSHOT_REQ, struct vm_snapshot_meta_old)
#endif
struct devmem_softc {
@ -416,6 +430,9 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
bool memsegs_locked;
#ifdef BHYVE_SNAPSHOT
struct vm_snapshot_meta *snapshot_meta;
#ifdef COMPAT_FREEBSD13
struct vm_snapshot_meta_old *snapshot_old;
#endif
#endif
error = vmm_priv_check(curthread->td_ucred);
@ -495,6 +512,9 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
case VM_UNMAP_PPTDEV_MMIO:
#ifdef BHYVE_SNAPSHOT
case VM_SNAPSHOT_REQ:
#ifdef COMPAT_FREEBSD13
case VM_SNAPSHOT_REQ_OLD:
#endif
case VM_RESTORE_TIME:
#endif
/*
@ -951,6 +971,18 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
snapshot_meta = (struct vm_snapshot_meta *)data;
error = vm_snapshot_req(sc->vm, snapshot_meta);
break;
#ifdef COMPAT_FREEBSD13
case VM_SNAPSHOT_REQ_OLD:
/*
* The old structure just has an additional pointer at
* the start that is ignored.
*/
snapshot_old = (struct vm_snapshot_meta_old *)data;
snapshot_meta =
(struct vm_snapshot_meta *)&snapshot_old->dev_data;
error = vm_snapshot_req(sc->vm, snapshot_meta);
break;
#endif
case VM_RESTORE_TIME:
error = vm_restore_time(sc->vm);
break;

View file

@ -1534,7 +1534,7 @@ main(int argc, char *argv[])
}
fprintf(stdout, "Restoring pci devs...\r\n");
if (vm_restore_user_devs(ctx, &rstate) != 0) {
if (vm_restore_user_devs(&rstate) != 0) {
fprintf(stderr, "Failed to restore PCI device state.\n");
exit(1);
}

View file

@ -41,8 +41,6 @@ __FBSDID("$FreeBSD$");
#include <sys/ata.h>
#include <sys/endian.h>
#include <machine/vmm_snapshot.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
@ -61,6 +59,9 @@ __FBSDID("$FreeBSD$");
#include "config.h"
#include "debug.h"
#include "pci_emul.h"
#ifdef BHYVE_SNAPSHOT
#include "snapshot.h"
#endif
#include "ahci.h"
#include "block_if.h"
@ -2623,10 +2624,10 @@ pci_ahci_snapshot(struct vm_snapshot_meta *meta)
goto done;
}
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(port->cmd_lst,
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, port->cmd_lst,
AHCI_CL_SIZE * AHCI_MAX_SLOTS, false, meta, ret, done);
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(port->rfis, 256, false, meta,
ret, done);
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, port->rfis, 256,
false, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(port->ata_ident, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(port->atapi, meta, ret, done);

View file

@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$");
#ifndef WITHOUT_CAPSICUM
#include <capsicum_helpers.h>
#endif
#include <machine/vmm_snapshot.h>
#include <err.h>
#include <errno.h>
@ -68,6 +67,9 @@ __FBSDID("$FreeBSD$");
#include "config.h"
#include "debug.h"
#include "pci_emul.h"
#ifdef BHYVE_SNAPSHOT
#include "snapshot.h"
#endif
#include "mevent.h"
#include "net_utils.h"
#include "net_backends.h"
@ -2436,8 +2438,8 @@ e82545_snapshot(struct vm_snapshot_meta *meta)
SNAPSHOT_VAR_OR_LEAVE(sc->esc_TADV, meta, ret, done);
/* Has dependency on esc_TDLEN; reoreder of fields from struct. */
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->esc_txdesc, sc->esc_TDLEN,
true, meta, ret, done);
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->esc_txdesc,
sc->esc_TDLEN, true, meta, ret, done);
/* L2 frame acceptance */
for (i = 0; i < (int)nitems(sc->esc_uni); i++) {
@ -2471,8 +2473,8 @@ e82545_snapshot(struct vm_snapshot_meta *meta)
SNAPSHOT_VAR_OR_LEAVE(sc->esc_RXCSUM, meta, ret, done);
/* Has dependency on esc_RDLEN; reoreder of fields from struct. */
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->esc_rxdesc, sc->esc_TDLEN,
true, meta, ret, done);
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->esc_rxdesc,
sc->esc_TDLEN, true, meta, ret, done);
/* IO Port register access */
SNAPSHOT_VAR_OR_LEAVE(sc->io_addr, meta, ret, done);

View file

@ -48,8 +48,6 @@ __FBSDID("$FreeBSD$");
#include <pthread.h>
#include <unistd.h>
#include <machine/vmm_snapshot.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usb.h>
#include <dev/usb/usb_freebsd.h>
@ -60,6 +58,9 @@ __FBSDID("$FreeBSD$");
#include "debug.h"
#include "pci_emul.h"
#include "pci_xhci.h"
#ifdef BHYVE_SNAPSHOT
#include "snapshot.h"
#endif
#include "usb_emul.h"
@ -2965,8 +2966,8 @@ pci_xhci_map_devs_slots(struct pci_xhci_softc *sc, int maps[])
}
static int
pci_xhci_snapshot_ep(struct pci_xhci_softc *sc __unused,
struct pci_xhci_dev_emu *dev, int idx, struct vm_snapshot_meta *meta)
pci_xhci_snapshot_ep(struct pci_xhci_softc *sc, struct pci_xhci_dev_emu *dev,
int idx, struct vm_snapshot_meta *meta)
{
int k;
int ret;
@ -2992,9 +2993,9 @@ pci_xhci_snapshot_ep(struct pci_xhci_softc *sc __unused,
for (k = 0; k < USB_MAX_XFER_BLOCKS; k++) {
xfer_block = &xfer->data[k];
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(xfer_block->buf,
XHCI_GADDR_SIZE(xfer_block->buf), true, meta, ret,
done);
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->xsc_pi->pi_vmctx,
xfer_block->buf, XHCI_GADDR_SIZE(xfer_block->buf), true,
meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(xfer_block->blen, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(xfer_block->bdone, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(xfer_block->processed, meta, ret, done);
@ -3059,11 +3060,11 @@ pci_xhci_snapshot(struct vm_snapshot_meta *meta)
SNAPSHOT_VAR_OR_LEAVE(sc->opregs.config, meta, ret, done);
/* opregs.cr_p */
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->opregs.cr_p,
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->opregs.cr_p,
XHCI_GADDR_SIZE(sc->opregs.cr_p), true, meta, ret, done);
/* opregs.dcbaa_p */
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->opregs.dcbaa_p,
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->opregs.dcbaa_p,
XHCI_GADDR_SIZE(sc->opregs.dcbaa_p), true, meta, ret, done);
/* rtsregs */
@ -3078,11 +3079,11 @@ pci_xhci_snapshot(struct vm_snapshot_meta *meta)
SNAPSHOT_VAR_OR_LEAVE(sc->rtsregs.intrreg.erdp, meta, ret, done);
/* rtsregs.erstba_p */
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->rtsregs.erstba_p,
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->rtsregs.erstba_p,
XHCI_GADDR_SIZE(sc->rtsregs.erstba_p), true, meta, ret, done);
/* rtsregs.erst_p */
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->rtsregs.erst_p,
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->rtsregs.erst_p,
XHCI_GADDR_SIZE(sc->rtsregs.erst_p), true, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(sc->rtsregs.er_deq_seg, meta, ret, done);
@ -3168,7 +3169,7 @@ pci_xhci_snapshot(struct vm_snapshot_meta *meta)
if (dev == NULL)
continue;
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(dev->dev_ctx,
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, dev->dev_ctx,
XHCI_GADDR_SIZE(dev->dev_ctx), true, meta, ret, done);
if (dev->dev_ctx != NULL) {

View file

@ -886,7 +886,6 @@ vm_restore_kern_struct(struct vmctx *ctx, struct restore_state *rstate,
}
meta = &(struct vm_snapshot_meta) {
.ctx = ctx,
.dev_name = info->struct_name,
.dev_req = info->req,
@ -899,7 +898,7 @@ vm_restore_kern_struct(struct vmctx *ctx, struct restore_state *rstate,
.op = VM_SNAPSHOT_RESTORE,
};
ret = vm_snapshot_req(meta);
ret = vm_snapshot_req(ctx, meta);
if (ret != 0) {
fprintf(stderr, "%s: Failed to restore struct: %s\r\n",
__func__, info->struct_name);
@ -927,7 +926,7 @@ vm_restore_kern_structs(struct vmctx *ctx, struct restore_state *rstate)
}
static int
vm_restore_user_dev(struct vmctx *ctx, struct restore_state *rstate,
vm_restore_user_dev(struct restore_state *rstate,
const struct vm_snapshot_dev_info *info)
{
void *dev_ptr;
@ -950,7 +949,6 @@ vm_restore_user_dev(struct vmctx *ctx, struct restore_state *rstate,
}
meta = &(struct vm_snapshot_meta) {
.ctx = ctx,
.dev_name = info->dev_name,
.buffer.buf_start = dev_ptr,
@ -974,13 +972,13 @@ vm_restore_user_dev(struct vmctx *ctx, struct restore_state *rstate,
int
vm_restore_user_devs(struct vmctx *ctx, struct restore_state *rstate)
vm_restore_user_devs(struct restore_state *rstate)
{
size_t i;
int ret;
for (i = 0; i < nitems(snapshot_devs); i++) {
ret = vm_restore_user_dev(ctx, rstate, &snapshot_devs[i]);
ret = vm_restore_user_dev(rstate, &snapshot_devs[i]);
if (ret != 0)
return (ret);
}
@ -1029,14 +1027,14 @@ vm_resume_user_devs(void)
}
static int
vm_snapshot_kern_struct(int data_fd, xo_handle_t *xop, const char *array_key,
struct vm_snapshot_meta *meta, off_t *offset)
vm_snapshot_kern_struct(struct vmctx *ctx, int data_fd, xo_handle_t *xop,
const char *array_key, struct vm_snapshot_meta *meta, off_t *offset)
{
int ret;
size_t data_size;
ssize_t write_cnt;
ret = vm_snapshot_req(meta);
ret = vm_snapshot_req(ctx, meta);
if (ret != 0) {
fprintf(stderr, "%s: Failed to snapshot struct %s\r\n",
__func__, meta->dev_name);
@ -1089,8 +1087,6 @@ vm_snapshot_kern_structs(struct vmctx *ctx, int data_fd, xo_handle_t *xop)
}
meta = &(struct vm_snapshot_meta) {
.ctx = ctx,
.buffer.buf_start = buffer,
.buffer.buf_size = buf_size,
@ -1106,8 +1102,8 @@ vm_snapshot_kern_structs(struct vmctx *ctx, int data_fd, xo_handle_t *xop)
meta->buffer.buf = meta->buffer.buf_start;
meta->buffer.buf_rem = meta->buffer.buf_size;
ret = vm_snapshot_kern_struct(data_fd, xop, JSON_DEV_ARR_KEY,
meta, &offset);
ret = vm_snapshot_kern_struct(ctx, data_fd, xop,
JSON_DEV_ARR_KEY, meta, &offset);
if (ret != 0) {
error = -1;
goto err_vm_snapshot_kern_data;
@ -1186,7 +1182,7 @@ vm_snapshot_user_dev(const struct vm_snapshot_dev_info *info,
}
static int
vm_snapshot_user_devs(struct vmctx *ctx, int data_fd, xo_handle_t *xop)
vm_snapshot_user_devs(int data_fd, xo_handle_t *xop)
{
int ret;
off_t offset;
@ -1210,8 +1206,6 @@ vm_snapshot_user_devs(struct vmctx *ctx, int data_fd, xo_handle_t *xop)
}
meta = &(struct vm_snapshot_meta) {
.ctx = ctx,
.buffer.buf_start = buffer,
.buffer.buf_size = buf_size,
@ -1395,7 +1389,7 @@ vm_checkpoint(struct vmctx *ctx, const char *checkpoint_file, bool stop_vm)
goto done;
}
ret = vm_snapshot_user_devs(ctx, kdata_fd, xop);
ret = vm_snapshot_user_devs(kdata_fd, xop);
if (ret != 0) {
fprintf(stderr, "Failed to snapshot device state.\n");
error = -1;
@ -1639,14 +1633,14 @@ vm_get_snapshot_size(struct vm_snapshot_meta *meta)
}
int
vm_snapshot_guest2host_addr(void **addrp, size_t len, bool restore_null,
struct vm_snapshot_meta *meta)
vm_snapshot_guest2host_addr(struct vmctx *ctx, void **addrp, size_t len,
bool restore_null, struct vm_snapshot_meta *meta)
{
int ret;
vm_paddr_t gaddr;
if (meta->op == VM_SNAPSHOT_SAVE) {
gaddr = paddr_host2guest(meta->ctx, *addrp);
gaddr = paddr_host2guest(ctx, *addrp);
if (gaddr == (vm_paddr_t) -1) {
if (!restore_null ||
(restore_null && (*addrp != NULL))) {
@ -1665,7 +1659,7 @@ vm_snapshot_guest2host_addr(void **addrp, size_t len, bool restore_null,
}
}
*addrp = paddr_guest2host(meta->ctx, gaddr, len);
*addrp = paddr_guest2host(ctx, gaddr, len);
} else {
ret = EINVAL;
}

View file

@ -95,7 +95,7 @@ void checkpoint_cpu_suspend(int vcpu);
int restore_vm_mem(struct vmctx *ctx, struct restore_state *rstate);
int vm_restore_kern_structs(struct vmctx *ctx, struct restore_state *rstate);
int vm_restore_user_devs(struct vmctx *ctx, struct restore_state *rstate);
int vm_restore_user_devs(struct restore_state *rstate);
int vm_pause_user_devs(void);
int vm_resume_user_devs(void);
@ -106,4 +106,25 @@ void init_snapshot(void);
int load_restore_file(const char *filename, struct restore_state *rstate);
int vm_snapshot_guest2host_addr(struct vmctx *ctx, void **addrp, size_t len,
bool restore_null, struct vm_snapshot_meta *meta);
/*
* Address variables are pointers to guest memory.
*
* When RNULL != 0, do not enforce invalid address checks; instead, make the
* pointer NULL at restore time.
*/
#define SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(CTX, ADDR, LEN, RNULL, META, RES, LABEL) \
do { \
(RES) = vm_snapshot_guest2host_addr((CTX), (void **)&(ADDR), (LEN), \
(RNULL), (META)); \
if ((RES) != 0) { \
if ((RES) == EFAULT) \
fprintf(stderr, "%s: invalid address: %s\r\n", \
__func__, #ADDR); \
goto LABEL; \
} \
} while (0)
#endif

View file

@ -34,7 +34,6 @@ __FBSDID("$FreeBSD$");
#include <sys/uio.h>
#include <machine/atomic.h>
#include <machine/vmm_snapshot.h>
#include <dev/virtio/pci/virtio_pci_legacy_var.h>
@ -47,6 +46,9 @@ __FBSDID("$FreeBSD$");
#include "bhyverun.h"
#include "debug.h"
#include "pci_emul.h"
#ifdef BHYVE_SNAPSHOT
#include "snapshot.h"
#endif
#include "virtio.h"
/*
@ -880,8 +882,10 @@ vi_pci_snapshot_queues(struct virtio_softc *vs, struct vm_snapshot_meta *meta)
int ret;
struct virtio_consts *vc;
struct vqueue_info *vq;
struct vmctx *ctx;
uint64_t addr_size;
ctx = vs->vs_pi->pi_vmctx;
vc = vs->vs_vc;
/* Save virtio queue info */
@ -903,15 +907,15 @@ vi_pci_snapshot_queues(struct virtio_softc *vs, struct vm_snapshot_meta *meta)
continue;
addr_size = vq->vq_qsize * sizeof(struct vring_desc);
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(vq->vq_desc, addr_size,
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(ctx, vq->vq_desc, addr_size,
false, meta, ret, done);
addr_size = (2 + vq->vq_qsize + 1) * sizeof(uint16_t);
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(vq->vq_avail, addr_size,
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(ctx, vq->vq_avail, addr_size,
false, meta, ret, done);
addr_size = (2 + 2 * vq->vq_qsize + 1) * sizeof(uint16_t);
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(vq->vq_used, addr_size,
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(ctx, vq->vq_used, addr_size,
false, meta, ret, done);
SNAPSHOT_BUF_OR_LEAVE(vq->vq_desc,