Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/virtio.c
Show All 28 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/uio.h> | #include <sys/uio.h> | ||||
#include <machine/atomic.h> | #include <machine/atomic.h> | ||||
#include <machine/vmm_snapshot.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <pthread.h> | #include <pthread.h> | ||||
#include <pthread_np.h> | #include <pthread_np.h> | ||||
#include "bhyverun.h" | #include "bhyverun.h" | ||||
#include "debug.h" | #include "debug.h" | ||||
▲ Show 20 Lines • Show All 756 Lines • ▼ Show 20 Lines | |||||
bad_qindex: | bad_qindex: | ||||
EPRINTLN( | EPRINTLN( | ||||
"%s: write config reg %s: curq %d >= max %d", | "%s: write config reg %s: curq %d >= max %d", | ||||
name, cr->cr_name, vs->vs_curq, vc->vc_nvq); | name, cr->cr_name, vs->vs_curq, vc->vc_nvq); | ||||
done: | done: | ||||
if (vs->vs_mtx) | if (vs->vs_mtx) | ||||
pthread_mutex_unlock(vs->vs_mtx); | pthread_mutex_unlock(vs->vs_mtx); | ||||
} | } | ||||
#ifdef BHYVE_SNAPSHOT | |||||
int | |||||
vi_pci_pause(struct vmctx *ctx, struct pci_devinst *pi) | |||||
{ | |||||
struct virtio_softc *vs; | |||||
struct virtio_consts *vc; | |||||
vs = pi->pi_arg; | |||||
vc = vs->vs_vc; | |||||
vc = vs->vs_vc; | |||||
assert(vc->vc_pause != NULL); | |||||
(*vc->vc_pause)(DEV_SOFTC(vs)); | |||||
return (0); | |||||
} | |||||
int | |||||
vi_pci_resume(struct vmctx *ctx, struct pci_devinst *pi) | |||||
{ | |||||
struct virtio_softc *vs; | |||||
struct virtio_consts *vc; | |||||
vs = pi->pi_arg; | |||||
vc = vs->vs_vc; | |||||
vc = vs->vs_vc; | |||||
assert(vc->vc_resume != NULL); | |||||
(*vc->vc_resume)(DEV_SOFTC(vs)); | |||||
return (0); | |||||
} | |||||
static int | |||||
vi_pci_snapshot_softc(struct virtio_softc *vs, struct vm_snapshot_meta *meta) | |||||
{ | |||||
int ret; | |||||
SNAPSHOT_VAR_OR_LEAVE(vs->vs_flags, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(vs->vs_negotiated_caps, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(vs->vs_curq, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(vs->vs_status, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(vs->vs_isr, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(vs->vs_msix_cfg_idx, meta, ret, done); | |||||
done: | |||||
return (ret); | |||||
} | |||||
static int | |||||
vi_pci_snapshot_consts(struct virtio_consts *vc, struct vm_snapshot_meta *meta) | |||||
{ | |||||
int ret; | |||||
SNAPSHOT_VAR_CMP_OR_LEAVE(vc->vc_nvq, meta, ret, done); | |||||
SNAPSHOT_VAR_CMP_OR_LEAVE(vc->vc_cfgsize, meta, ret, done); | |||||
SNAPSHOT_VAR_CMP_OR_LEAVE(vc->vc_hv_caps, meta, ret, done); | |||||
done: | |||||
return (ret); | |||||
} | |||||
static int | |||||
vi_pci_snapshot_queues(struct virtio_softc *vs, struct vm_snapshot_meta *meta) | |||||
{ | |||||
int i; | |||||
int ret; | |||||
struct virtio_consts *vc; | |||||
struct vqueue_info *vq; | |||||
uint64_t addr_size; | |||||
vc = vs->vs_vc; | |||||
/* Save virtio queue info */ | |||||
for (i = 0; i < vc->vc_nvq; i++) { | |||||
vq = &vs->vs_queues[i]; | |||||
SNAPSHOT_VAR_CMP_OR_LEAVE(vq->vq_qsize, meta, ret, done); | |||||
SNAPSHOT_VAR_CMP_OR_LEAVE(vq->vq_num, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(vq->vq_flags, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(vq->vq_last_avail, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(vq->vq_next_used, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(vq->vq_save_used, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(vq->vq_msix_idx, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(vq->vq_pfn, meta, ret, done); | |||||
addr_size = vq->vq_qsize * sizeof(struct virtio_desc); | |||||
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(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, | |||||
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, | |||||
false, meta, ret, done); | |||||
pmooney_pfmooney.com: If you're taking a snapshot while the vCPUs are paused, won't copying of the virtqueues be… | |||||
Done Inline ActionsThe GUEST2HOST_ADDR macros do not save memory, but rather guest memory mappings. The pointer parameter is converted to a guest address that can be used to locate the virtual queues in the new (restored) VM's address space. darius.mihaim_gmail.com: The GUEST2HOST_ADDR macros do not save memory, but rather guest memory mappings. The pointer… | |||||
SNAPSHOT_BUF_OR_LEAVE(vq->vq_desc, vring_size(vq->vq_qsize), | |||||
meta, ret, done); | |||||
} | |||||
done: | |||||
return (ret); | |||||
} | |||||
int | |||||
vi_pci_snapshot(struct vm_snapshot_meta *meta) | |||||
{ | |||||
int ret; | |||||
struct pci_devinst *pi; | |||||
struct virtio_softc *vs; | |||||
struct virtio_consts *vc; | |||||
pi = meta->dev_data; | |||||
vs = pi->pi_arg; | |||||
vc = vs->vs_vc; | |||||
/* Save virtio softc */ | |||||
ret = vi_pci_snapshot_softc(vs, meta); | |||||
if (ret != 0) | |||||
goto done; | |||||
/* Save virtio consts */ | |||||
ret = vi_pci_snapshot_consts(vc, meta); | |||||
if (ret != 0) | |||||
goto done; | |||||
/* Save virtio queue info */ | |||||
ret = vi_pci_snapshot_queues(vs, meta); | |||||
if (ret != 0) | |||||
goto done; | |||||
/* Save device softc, if needed */ | |||||
if (vc->vc_snapshot != NULL) { | |||||
ret = (*vc->vc_snapshot)(DEV_SOFTC(vs), meta); | |||||
if (ret != 0) | |||||
goto done; | |||||
} | |||||
done: | |||||
return (ret); | |||||
} | |||||
#endif |
If you're taking a snapshot while the vCPUs are paused, won't copying of the virtqueues be redundant, as they'll be picked up in the copy of guest RAM?