Page MenuHomeFreeBSD

D35590.diff
No OneTemporary

D35590.diff

diff --git a/usr.sbin/bhyve/atkbdc.h b/usr.sbin/bhyve/atkbdc.h
--- a/usr.sbin/bhyve/atkbdc.h
+++ b/usr.sbin/bhyve/atkbdc.h
@@ -30,14 +30,9 @@
#define _ATKBDC_H_
struct atkbdc_softc;
-struct vm_snapshot_meta;
struct vmctx;
void atkbdc_init(struct vmctx *ctx);
void atkbdc_event(struct atkbdc_softc *sc, int iskbd);
-#ifdef BHYVE_SNAPSHOT
-int atkbdc_snapshot(struct vm_snapshot_meta *meta);
-#endif
-
#endif /* _ATKBDC_H_ */
diff --git a/usr.sbin/bhyve/atkbdc.c b/usr.sbin/bhyve/atkbdc.c
--- a/usr.sbin/bhyve/atkbdc.c
+++ b/usr.sbin/bhyve/atkbdc.c
@@ -56,6 +56,10 @@
#include "ps2kbd.h"
#include "ps2mouse.h"
+#ifdef BHYVE_SNAPSHOT
+#include "snapshot.h"
+#endif
+
#define KBD_DATA_PORT 0x60
#define KBD_STS_CTL_PORT 0x64
@@ -138,10 +142,6 @@
struct aux_dev aux;
};
-#ifdef BHYVE_SNAPSHOT
-static struct atkbdc_softc *atkbdc_sc = NULL;
-#endif
-
static void
atkbdc_assert_kbd_intr(struct atkbdc_softc *sc)
{
@@ -511,6 +511,14 @@
pthread_mutex_unlock(&sc->mtx);
}
+#ifdef BHYVE_SNAPSHOT
+extern int atkbdc_snapshot(struct vm_snapshot_meta *, void *);
+
+static struct snapshot_ops atkbdc_snapshot_ops = {
+ .snapshot_cb = atkbdc_snapshot,
+};
+#endif
+
void
atkbdc_init(struct vmctx *ctx)
{
@@ -555,42 +563,40 @@
sc->ps2mouse_sc = ps2mouse_init(sc);
#ifdef BHYVE_SNAPSHOT
- assert(atkbdc_sc == NULL);
- atkbdc_sc = sc;
+ register_snapshot_dev("atkbdc", &atkbdc_snapshot_ops, sc);
#endif
}
#ifdef BHYVE_SNAPSHOT
int
-atkbdc_snapshot(struct vm_snapshot_meta *meta)
+atkbdc_snapshot(struct vm_snapshot_meta *meta, void *cbdata)
{
int ret;
-
- SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->status, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->outport, meta, ret, done);
- SNAPSHOT_BUF_OR_LEAVE(atkbdc_sc->ram,
- sizeof(atkbdc_sc->ram), meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->curcmd, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->ctrlbyte, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->kbd, meta, ret, done);
-
- SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->kbd.irq_active, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->kbd.irq, meta, ret, done);
- SNAPSHOT_BUF_OR_LEAVE(atkbdc_sc->kbd.buffer,
- sizeof(atkbdc_sc->kbd.buffer), meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->kbd.brd, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->kbd.bwr, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->kbd.bcnt, meta, ret, done);
-
- SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->aux.irq_active, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->aux.irq, meta, ret, done);
-
- ret = ps2kbd_snapshot(atkbdc_sc->ps2kbd_sc, meta);
- if (ret != 0)
- goto done;
-
- ret = ps2mouse_snapshot(atkbdc_sc->ps2mouse_sc, meta);
-
+ struct atkbdc_softc *sc = (struct atkbdc_softc *)cbdata;
+
+ assert(sc != NULL);
+
+ SNAPSHOT_VAR_OR_LEAVE(sc->status, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(sc->outport, meta, ret, done);
+ SNAPSHOT_BUF_OR_LEAVE(sc->ram, sizeof (sc->ram), meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(sc->curcmd, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(sc->ctrlbyte, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(sc->kbd, meta, ret, done);
+
+ SNAPSHOT_VAR_OR_LEAVE(sc->kbd.irq_active, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(sc->kbd.irq, meta, ret, done);
+ SNAPSHOT_BUF_OR_LEAVE(sc->kbd.buffer,
+ sizeof (sc->kbd.buffer), meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(sc->kbd.brd, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(sc->kbd.bwr, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(sc->kbd.bcnt, meta, ret, done);
+
+ SNAPSHOT_VAR_OR_LEAVE(sc->aux.irq_active, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(sc->aux.irq, meta, ret, done);
+
+ ret = ps2kbd_snapshot(sc->ps2kbd_sc, meta);
+ if (ret == 0)
+ ret = ps2mouse_snapshot(sc->ps2mouse_sc, meta);
done:
return (ret);
}
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -1498,7 +1498,7 @@
}
fprintf(stdout, "Pausing pci devs...\r\n");
- if (vm_pause_user_devs() != 0) {
+ if (vm_pause_devices() != 0) {
fprintf(stderr, "Failed to pause PCI device state.\n");
exit(1);
}
@@ -1510,7 +1510,7 @@
}
fprintf(stdout, "Restoring pci devs...\r\n");
- if (vm_restore_user_devs(ctx, &rstate) != 0) {
+ if (vm_restore_devices(ctx, &rstate) != 0) {
fprintf(stderr, "Failed to restore PCI device state.\n");
exit(1);
}
@@ -1522,7 +1522,7 @@
}
fprintf(stdout, "Resuming pci devs...\r\n");
- if (vm_resume_user_devs() != 0) {
+ if (vm_resume_devices() != 0) {
fprintf(stderr, "Failed to resume PCI device state.\n");
exit(1);
}
diff --git a/usr.sbin/bhyve/pci_emul.h b/usr.sbin/bhyve/pci_emul.h
--- a/usr.sbin/bhyve/pci_emul.h
+++ b/usr.sbin/bhyve/pci_emul.h
@@ -80,7 +80,6 @@
int (*pe_snapshot)(struct vm_snapshot_meta *meta);
int (*pe_pause)(struct pci_devinst *pi);
int (*pe_resume)(struct pci_devinst *pi);
-
};
#define PCI_EMUL_SET(x) DATA_SET(pci_devemu_set, x);
@@ -259,11 +258,6 @@
void pci_write_dsdt(void);
uint64_t pci_ecfg_base(void);
int pci_bus_configured(int bus);
-#ifdef BHYVE_SNAPSHOT
-int pci_snapshot(struct vm_snapshot_meta *meta);
-int pci_pause(const char *dev_name);
-int pci_resume(const char *dev_name);
-#endif
static __inline void
pci_set_cfgdata8(struct pci_devinst *pi, int offset, uint8_t val)
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -62,6 +62,10 @@
#include "pci_irq.h"
#include "pci_lpc.h"
+#ifdef BHYVE_SNAPSHOT
+#include "snapshot.h"
+#endif
+
#define CONF1_ADDR_PORT 0x0cf8
#define CONF1_DATA_PORT 0x0cfc
@@ -985,7 +989,9 @@
pdi->pi_lintr.pirq_pin = 0;
pdi->pi_lintr.ioapic_irq = 0;
pdi->pi_d = pde;
- snprintf(pdi->pi_name, PI_NAMESZ, "%s-pci-%d", pde->pe_emu, slot);
+
+ snprintf(pdi->pi_name, PI_NAMESZ, "%s-pci-%d-%d-%d", pde->pe_emu, bus,
+ slot, func);
/* Disable legacy interrupts */
pci_set_cfgdata8(pdi, PCIR_INTLINE, 255);
@@ -1322,6 +1328,18 @@
#define BUSMEM32_ROUNDUP (1024 * 1024)
#define BUSMEM64_ROUNDUP (512 * 1024 * 1024)
+#ifdef BHYVE_SNAPSHOT
+static int pci_snapshot(struct vm_snapshot_meta *, void *);
+static int pci_pause(void *);
+static int pci_resume(void *);
+
+static struct snapshot_ops pci_snapshot_ops = {
+ .snapshot_cb = pci_snapshot,
+ .pause_cb = pci_pause,
+ .resume_cb = pci_resume,
+};
+#endif
+
int
init_pci(struct vmctx *ctx)
{
@@ -1400,6 +1418,10 @@
func, fi);
if (error)
return (error);
+#ifdef BHYVE_SNAPSHOT
+ register_snapshot_dev(fi->fi_devi->pi_name,
+ &pci_snapshot_ops, fi->fi_devi);
+#endif
}
}
@@ -2321,58 +2343,15 @@
}
static int
-pci_find_slotted_dev(const char *dev_name, struct pci_devemu **pde,
- struct pci_devinst **pdi)
-{
- struct businfo *bi;
- struct slotinfo *si;
- struct funcinfo *fi;
- int bus, slot, func;
-
- assert(dev_name != NULL);
- assert(pde != NULL);
- assert(pdi != NULL);
-
- for (bus = 0; bus < MAXBUSES; bus++) {
- if ((bi = pci_businfo[bus]) == NULL)
- continue;
-
- for (slot = 0; slot < MAXSLOTS; slot++) {
- si = &bi->slotinfo[slot];
- for (func = 0; func < MAXFUNCS; func++) {
- fi = &si->si_funcs[func];
- if (fi->fi_pde == NULL)
- continue;
- if (strcmp(dev_name, fi->fi_pde->pe_emu) != 0)
- continue;
-
- *pde = fi->fi_pde;
- *pdi = fi->fi_devi;
- return (0);
- }
- }
- }
-
- return (EINVAL);
-}
-
-int
-pci_snapshot(struct vm_snapshot_meta *meta)
+pci_snapshot(struct vm_snapshot_meta *meta, void *cbdata)
{
struct pci_devemu *pde;
- struct pci_devinst *pdi;
+ struct pci_devinst *pdi = (struct pci_devinst *)cbdata;
int ret;
- assert(meta->dev_name != NULL);
-
- ret = pci_find_slotted_dev(meta->dev_name, &pde, &pdi);
- if (ret != 0) {
- fprintf(stderr, "%s: no such name: %s\r\n",
- __func__, meta->dev_name);
- memset(meta->buffer.buf_start, 0, meta->buffer.buf_size);
- return (0);
- }
+ assert(pdi != NULL);
+ pde = pdi->pi_d;
meta->dev_data = pdi;
if (pde->pe_snapshot == NULL) {
@@ -2383,8 +2362,8 @@
ret = pci_snapshot_pci_dev(meta);
if (ret != 0) {
- fprintf(stderr, "%s: failed to snapshot pci dev\r\n",
- __func__);
+ fprintf(stderr, "%s: failed to snapshot pci dev %s: %d\n",
+ __func__, meta->dev_name, ret);
return (-1);
}
@@ -2393,58 +2372,40 @@
return (ret);
}
-int
-pci_pause(const char *dev_name)
+static int
+pci_pause(void *cbdata)
{
struct pci_devemu *pde;
- struct pci_devinst *pdi;
- int ret;
+ struct pci_devinst *pdi = (struct pci_devinst *)cbdata;
- assert(dev_name != NULL);
+ assert(pdi != NULL);
- ret = pci_find_slotted_dev(dev_name, &pde, &pdi);
- if (ret != 0) {
- /*
- * It is possible to call this function without
- * checking that the device is inserted first.
- */
- fprintf(stderr, "%s: no such name: %s\n", __func__, dev_name);
- return (0);
- }
+ pde = pdi->pi_d;
if (pde->pe_pause == NULL) {
/* The pause/resume functionality is optional. */
fprintf(stderr, "%s: not implemented for: %s\n",
- __func__, dev_name);
+ __func__, pdi->pi_name);
return (0);
}
return (*pde->pe_pause)(pdi);
}
-int
-pci_resume(const char *dev_name)
+static int
+pci_resume(void *cbdata)
{
struct pci_devemu *pde;
- struct pci_devinst *pdi;
- int ret;
+ struct pci_devinst *pdi = (struct pci_devinst *)cbdata;
- assert(dev_name != NULL);
+ assert(pdi != NULL);
- ret = pci_find_slotted_dev(dev_name, &pde, &pdi);
- if (ret != 0) {
- /*
- * It is possible to call this function without
- * checking that the device is inserted first.
- */
- fprintf(stderr, "%s: no such name: %s\n", __func__, dev_name);
- return (0);
- }
+ pde = pdi->pi_d;
if (pde->pe_resume == NULL) {
/* The pause/resume functionality is optional. */
fprintf(stderr, "%s: not implemented for: %s\n",
- __func__, dev_name);
+ __func__, pdi->pi_name);
return (0);
}
diff --git a/usr.sbin/bhyve/pci_hostbridge.c b/usr.sbin/bhyve/pci_hostbridge.c
--- a/usr.sbin/bhyve/pci_hostbridge.c
+++ b/usr.sbin/bhyve/pci_hostbridge.c
@@ -64,6 +64,14 @@
return (0);
}
+#ifdef BHYVE_SNAPSHOT
+static int
+pci_hostbridge_snapshot(struct vm_snapshot_meta *meta __unused)
+{
+ return (0);
+}
+#endif
+
static int
pci_amd_hostbridge_legacy_config(nvlist_t *nvl, const char *opts __unused)
{
@@ -77,11 +85,17 @@
.pe_emu = "amd_hostbridge",
.pe_legacy_config = pci_amd_hostbridge_legacy_config,
.pe_alias = "hostbridge",
+#ifdef BHYVE_SNAPSHOT
+ .pe_snapshot = pci_hostbridge_snapshot,
+#endif
};
PCI_EMUL_SET(pci_de_amd_hostbridge);
static const struct pci_devemu pci_de_hostbridge = {
.pe_emu = "hostbridge",
.pe_init = pci_hostbridge_init,
+#ifdef BHYVE_SNAPSHOT
+ .pe_snapshot = pci_hostbridge_snapshot,
+#endif
};
PCI_EMUL_SET(pci_de_hostbridge);
diff --git a/usr.sbin/bhyve/snapshot.h b/usr.sbin/bhyve/snapshot.h
--- a/usr.sbin/bhyve/snapshot.h
+++ b/usr.sbin/bhyve/snapshot.h
@@ -65,22 +65,25 @@
int socket_fd;
};
-typedef int (*vm_snapshot_dev_cb)(struct vm_snapshot_meta *);
-typedef int (*vm_pause_dev_cb) (const char *);
-typedef int (*vm_resume_dev_cb) (const char *);
-
-struct vm_snapshot_dev_info {
- const char *dev_name; /* device name */
- vm_snapshot_dev_cb snapshot_cb; /* callback for device snapshot */
- vm_pause_dev_cb pause_cb; /* callback for device pause */
- vm_resume_dev_cb resume_cb; /* callback for device resume */
+typedef int (*snapshot_dev_cb)(struct vm_snapshot_meta *meta, void *cbdata);
+typedef int (*pause_dev_cb)(void *cbdata);
+typedef int (*resume_dev_cb)(void *cbdata);
+
+struct snapshot_ops {
+ snapshot_dev_cb snapshot_cb; /* callback for device save/restore */
+ pause_dev_cb pause_cb; /* callback for device pause (optional) */
+ resume_dev_cb resume_cb; /* callback for device resume (optional) */
};
struct vm_snapshot_kern_info {
- const char *struct_name; /* kernel structure name*/
+ const char *dev_name; /* kernel device name */
enum snapshot_req req; /* request type */
};
+struct snapshot_ops;
+
+void register_snapshot_dev(const char *devname, struct snapshot_ops *ops,
+ void *cbdata);
void destroy_restore_state(struct restore_state *rstate);
const char *lookup_vmname(struct restore_state *rstate);
@@ -95,9 +98,9 @@
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_pause_user_devs(void);
-int vm_resume_user_devs(void);
+int vm_restore_devices(struct vmctx *ctx, struct restore_state *rstate);
+int vm_pause_devices(void);
+int vm_resume_devices(void);
int get_checkpoint_msg(int conn_fd, struct vmctx *ctx);
void *checkpoint_thread(void *param);
diff --git a/usr.sbin/bhyve/snapshot.c b/usr.sbin/bhyve/snapshot.c
--- a/usr.sbin/bhyve/snapshot.c
+++ b/usr.sbin/bhyve/snapshot.c
@@ -119,12 +119,12 @@
#define SNAPSHOT_BUFFER_SIZE (20 * MB)
-#define JSON_STRUCT_ARR_KEY "structs"
+#define JSON_KERNEL_ARR_KEY "kern_structs"
#define JSON_DEV_ARR_KEY "devices"
-#define JSON_BASIC_METADATA_KEY "basic metadata"
-#define JSON_SNAPSHOT_REQ_KEY "snapshot_req"
+#define JSON_BASIC_METADATA_KEY "basic metadata"
+#define JSON_SNAPSHOT_REQ_KEY "device"
#define JSON_SIZE_KEY "size"
-#define JSON_FILE_OFFSET_KEY "file_offset"
+#define JSON_FILE_OFFSET_KEY "file_offset"
#define JSON_NCPUS_KEY "ncpus"
#define JSON_VMNAME_KEY "vmname"
@@ -138,20 +138,6 @@
_a < _b ? _a : _b; \
})
-static const struct vm_snapshot_dev_info snapshot_devs[] = {
- { "atkbdc", atkbdc_snapshot, NULL, NULL },
- { "virtio-net", pci_snapshot, pci_pause, pci_resume },
- { "virtio-blk", pci_snapshot, pci_pause, pci_resume },
- { "virtio-rnd", pci_snapshot, NULL, NULL },
- { "lpc", pci_snapshot, NULL, NULL },
- { "fbuf", pci_snapshot, NULL, NULL },
- { "xhci", pci_snapshot, NULL, NULL },
- { "e1000", pci_snapshot, NULL, NULL },
- { "ahci", pci_snapshot, pci_pause, pci_resume },
- { "ahci-hd", pci_snapshot, pci_pause, pci_resume },
- { "ahci-cd", pci_snapshot, pci_pause, pci_resume },
-};
-
static const struct vm_snapshot_kern_info snapshot_kern_structs[] = {
{ "vhpet", STRUCT_VHPET },
{ "vm", STRUCT_VM },
@@ -169,6 +155,31 @@
static pthread_cond_t vcpus_idle, vcpus_can_run;
static bool checkpoint_active;
+struct snapshot_dev {
+ LIST_ENTRY(snapshot_dev) dev_link;
+ const char *dev_name;
+ struct snapshot_ops *dev_ops;
+ void *dev_cbdata;
+};
+
+static LIST_HEAD(, snapshot_dev) snapshot_devices;
+
+void
+register_snapshot_dev(const char *name, struct snapshot_ops *ops,
+ void *cbdata)
+{
+ struct snapshot_dev *dev;
+
+ assert(ops != NULL && ops->snapshot_cb != NULL);
+
+ dev = calloc(1, sizeof (struct snapshot_dev));
+
+ dev->dev_name = name;
+ dev->dev_ops = ops;
+ dev->dev_cbdata = cbdata;
+ LIST_INSERT_HEAD(&snapshot_devices, dev, dev_link);
+}
+
/*
* TODO: Harden this function and all of its callers since 'base_str' is a user
* provided string.
@@ -415,50 +426,6 @@
} \
} while(0)
-static void *
-lookup_struct(enum snapshot_req struct_id, struct restore_state *rstate,
- size_t *struct_size)
-{
- const ucl_object_t *structs = NULL, *obj = NULL;
- ucl_object_iter_t it = NULL;
- int64_t snapshot_req, size, file_offset;
-
- structs = ucl_object_lookup(rstate->meta_root_obj, JSON_STRUCT_ARR_KEY);
- if (structs == NULL) {
- fprintf(stderr, "Failed to find '%s' object.\n",
- JSON_STRUCT_ARR_KEY);
- return (NULL);
- }
-
- if (ucl_object_type(structs) != UCL_ARRAY) {
- fprintf(stderr, "Object '%s' is not an array.\n",
- JSON_STRUCT_ARR_KEY);
- return (NULL);
- }
-
- while ((obj = ucl_object_iterate(structs, &it, true)) != NULL) {
- snapshot_req = -1;
- JSON_GET_INT_OR_RETURN(JSON_SNAPSHOT_REQ_KEY, obj,
- &snapshot_req, NULL);
- assert(snapshot_req >= 0);
- if ((enum snapshot_req) snapshot_req == struct_id) {
- JSON_GET_INT_OR_RETURN(JSON_SIZE_KEY, obj,
- &size, NULL);
- assert(size >= 0);
-
- JSON_GET_INT_OR_RETURN(JSON_FILE_OFFSET_KEY, obj,
- &file_offset, NULL);
- assert(file_offset >= 0);
- assert((uint64_t)file_offset + size <=
- rstate->kdata_len);
-
- *struct_size = (size_t)size;
- return ((uint8_t *)rstate->kdata_map + file_offset);
- }
- }
-
- return (NULL);
-}
static void *
lookup_check_dev(const char *dev_name, struct restore_state *rstate,
@@ -489,14 +456,14 @@
}
static void*
-lookup_dev(const char *dev_name, struct restore_state *rstate,
- size_t *data_size)
+lookup_dev(const char *dev_name, const char *key, struct restore_state *rstate,
+ size_t *data_size)
{
const ucl_object_t *devs = NULL, *obj = NULL;
ucl_object_iter_t it = NULL;
void *ret;
- devs = ucl_object_lookup(rstate->meta_root_obj, JSON_DEV_ARR_KEY);
+ devs = ucl_object_lookup(rstate->meta_root_obj, key);
if (devs == NULL) {
fprintf(stderr, "Failed to find '%s' object.\n",
JSON_DEV_ARR_KEY);
@@ -861,97 +828,71 @@
return (0);
}
-static int
-vm_restore_kern_struct(struct vmctx *ctx, struct restore_state *rstate,
- const struct vm_snapshot_kern_info *info)
+int
+vm_restore_kern_structs(struct vmctx *ctx, struct restore_state *rstate)
{
- void *struct_ptr;
- size_t struct_size;
int ret;
- struct vm_snapshot_meta *meta;
-
- struct_ptr = lookup_struct(info->req, rstate, &struct_size);
- if (struct_ptr == NULL) {
- fprintf(stderr, "%s: Failed to lookup struct %s\r\n",
- __func__, info->struct_name);
- ret = -1;
- goto done;
- }
-
- if (struct_size == 0) {
- fprintf(stderr, "%s: Kernel struct size was 0 for: %s\r\n",
- __func__, info->struct_name);
- ret = -1;
- goto done;
- }
-
- meta = &(struct vm_snapshot_meta) {
- .ctx = ctx,
- .dev_name = info->struct_name,
- .dev_req = info->req,
- .buffer.buf_start = struct_ptr,
- .buffer.buf_size = struct_size,
+ for (unsigned i = 0; i < nitems(snapshot_kern_structs); i++) {
+ const struct vm_snapshot_kern_info *info;
+ struct vm_snapshot_meta *meta;
+ void *data;
+ size_t size;
- .buffer.buf = struct_ptr,
- .buffer.buf_rem = struct_size,
+ info = &snapshot_kern_structs[i];
+ data = lookup_dev(info->dev_name, JSON_KERNEL_ARR_KEY, rstate, &size);
+ if (data == NULL)
+ errx(EX_DATAERR, "Cannot find kern struct %s", info->dev_name);
- .op = VM_SNAPSHOT_RESTORE,
- };
+ if (size == 0) {
+ warnx("data with zero size for %s", info->dev_name);
+ return (1);
+ }
+ meta = &(struct vm_snapshot_meta) {
+ .ctx = ctx,
+ .dev_name = info->dev_name,
+ .dev_req = info->req,
- ret = vm_snapshot_req(meta);
- if (ret != 0) {
- fprintf(stderr, "%s: Failed to restore struct: %s\r\n",
- __func__, info->struct_name);
- goto done;
- }
+ .buffer.buf_start = data,
+ .buffer.buf_size = size,
-done:
- return (ret);
-}
+ .buffer.buf = data,
+ .buffer.buf_rem = size,
-int
-vm_restore_kern_structs(struct vmctx *ctx, struct restore_state *rstate)
-{
- size_t i;
- int ret;
+ .op = VM_SNAPSHOT_RESTORE,
+ };
- for (i = 0; i < nitems(snapshot_kern_structs); i++) {
- ret = vm_restore_kern_struct(ctx, rstate,
- &snapshot_kern_structs[i]);
- if (ret != 0)
+ ret = vm_snapshot_req(meta);
+ if (ret != 0) {
+ warnx("%s: Failed to restore %s", __func__,
+ info->dev_name);
return (ret);
+ }
}
- return (0);
+ return (ret);
}
-static int
-vm_restore_user_dev(struct vmctx *ctx, struct restore_state *rstate,
- const struct vm_snapshot_dev_info *info)
+static void
+vm_restore_device(struct vmctx *ctx, struct restore_state *rstate,
+ struct snapshot_dev *dev)
{
void *dev_ptr;
size_t dev_size;
int ret;
struct vm_snapshot_meta *meta;
- dev_ptr = lookup_dev(info->dev_name, rstate, &dev_size);
- if (dev_ptr == NULL) {
- fprintf(stderr, "Failed to lookup dev: %s\r\n", info->dev_name);
- fprintf(stderr, "Continuing the restore/migration process\r\n");
- return (0);
- }
+ dev_ptr = lookup_dev(dev->dev_name, JSON_DEV_ARR_KEY, rstate, &dev_size);
+ if (dev_ptr == NULL)
+ err(EX_DATAERR, "Failed to lookup dev: %s\r\n", dev->dev_name);
- if (dev_size == 0) {
- fprintf(stderr, "%s: Device size is 0. "
- "Assuming %s is not used\r\n",
- __func__, info->dev_name);
- return (0);
- }
+ if (dev_size == 0)
+ err(EX_DATAERR, "%s: device size is 0: %s\n", __func__,
+ dev->dev_name);
meta = &(struct vm_snapshot_meta) {
.ctx = ctx,
- .dev_name = info->dev_name,
+ .dev_name = dev->dev_name,
.buffer.buf_start = dev_ptr,
.buffer.buf_size = dev_size,
@@ -962,74 +903,62 @@
.op = VM_SNAPSHOT_RESTORE,
};
- ret = (*info->snapshot_cb)(meta);
- if (ret != 0) {
- fprintf(stderr, "Failed to restore dev: %s\r\n",
- info->dev_name);
- return (-1);
- }
-
- return (0);
+ ret = (dev->dev_ops->snapshot_cb)(meta, dev->dev_cbdata);
+ if (ret != 0)
+ err(EX_DATAERR, "Failed to restore dev: %s", dev->dev_name);
}
int
-vm_restore_user_devs(struct vmctx *ctx, struct restore_state *rstate)
+vm_restore_devices(struct vmctx *ctx, struct restore_state *rstate)
{
- size_t i;
- int ret;
+ struct snapshot_dev *dev;
- for (i = 0; i < nitems(snapshot_devs); i++) {
- ret = vm_restore_user_dev(ctx, rstate, &snapshot_devs[i]);
- if (ret != 0)
- return (ret);
+ LIST_FOREACH(dev, &snapshot_devices, dev_link) {
+ vm_restore_device(ctx, rstate, dev);
}
return 0;
}
int
-vm_pause_user_devs(void)
+vm_pause_devices()
{
- const struct vm_snapshot_dev_info *info;
- size_t i;
- int ret;
+ struct snapshot_dev *dev;
+ int err;
- for (i = 0; i < nitems(snapshot_devs); i++) {
- info = &snapshot_devs[i];
- if (info->pause_cb == NULL)
+ LIST_FOREACH(dev, &snapshot_devices, dev_link) {
+ if (!dev->dev_ops->pause_cb)
continue;
- ret = info->pause_cb(info->dev_name);
- if (ret != 0)
- return (ret);
+ err = dev->dev_ops->pause_cb(dev->dev_cbdata);
+ if (err != 0)
+ return (err);
}
return (0);
}
int
-vm_resume_user_devs(void)
+vm_resume_devices()
{
- const struct vm_snapshot_dev_info *info;
- size_t i;
- int ret;
+ struct snapshot_dev *dev;
+ int err;
- for (i = 0; i < nitems(snapshot_devs); i++) {
- info = &snapshot_devs[i];
- if (info->resume_cb == NULL)
+ LIST_FOREACH(dev, &snapshot_devices, dev_link) {
+ if (!dev->dev_ops->resume_cb)
continue;
- ret = info->resume_cb(info->dev_name);
- if (ret != 0)
- return (ret);
+ err = dev->dev_ops->resume_cb(dev->dev_cbdata);
+ if (err != 0)
+ return (err);
}
return (0);
}
static int
-vm_snapshot_kern_struct(int data_fd, xo_handle_t *xop, const char *array_key,
+vm_save_kern_struct(int data_fd, xo_handle_t *xop, const char *array_key,
struct vm_snapshot_meta *meta, off_t *offset)
{
int ret;
@@ -1056,12 +985,10 @@
/* Write metadata. */
xo_open_instance_h(xop, array_key);
- xo_emit_h(xop, "{:debug_name/%s}\n", meta->dev_name);
- xo_emit_h(xop, "{:" JSON_SNAPSHOT_REQ_KEY "/%d}\n",
- meta->dev_req);
+ xo_emit_h(xop, "{:" JSON_SNAPSHOT_REQ_KEY "/%s}\n", meta->dev_name);
xo_emit_h(xop, "{:" JSON_SIZE_KEY "/%lu}\n", data_size);
xo_emit_h(xop, "{:" JSON_FILE_OFFSET_KEY "/%lu}\n", *offset);
- xo_close_instance_h(xop, JSON_STRUCT_ARR_KEY);
+ xo_close_instance_h(xop, JSON_KERNEL_ARR_KEY);
*offset += data_size;
@@ -1070,7 +997,7 @@
}
static int
-vm_snapshot_kern_structs(struct vmctx *ctx, int data_fd, xo_handle_t *xop)
+vm_save_kern_structs(struct vmctx *ctx, int data_fd, xo_handle_t *xop)
{
int ret, error;
size_t buf_size, i, offset;
@@ -1097,23 +1024,23 @@
.op = VM_SNAPSHOT_SAVE,
};
- xo_open_list_h(xop, JSON_STRUCT_ARR_KEY);
+ xo_open_list_h(xop, JSON_KERNEL_ARR_KEY);
for (i = 0; i < nitems(snapshot_kern_structs); i++) {
- meta->dev_name = snapshot_kern_structs[i].struct_name;
+ meta->dev_name = snapshot_kern_structs[i].dev_name;
meta->dev_req = snapshot_kern_structs[i].req;
memset(meta->buffer.buf_start, 0, meta->buffer.buf_size);
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,
+ ret = vm_save_kern_struct(data_fd, xop, JSON_DEV_ARR_KEY,
meta, &offset);
if (ret != 0) {
error = -1;
goto err_vm_snapshot_kern_data;
}
}
- xo_close_list_h(xop, JSON_STRUCT_ARR_KEY);
+ xo_close_list_h(xop, JSON_KERNEL_ARR_KEY);
err_vm_snapshot_kern_data:
if (buffer != NULL)
@@ -1122,7 +1049,7 @@
}
static int
-vm_snapshot_basic_metadata(struct vmctx *ctx, xo_handle_t *xop, size_t memsz)
+vm_save_basic_metadata(struct vmctx *ctx, xo_handle_t *xop, size_t memsz)
{
xo_open_container_h(xop, JSON_BASIC_METADATA_KEY);
@@ -1164,16 +1091,20 @@
}
static int
-vm_snapshot_user_dev(const struct vm_snapshot_dev_info *info,
- int data_fd, xo_handle_t *xop,
- struct vm_snapshot_meta *meta, off_t *offset)
+vm_save_device(struct snapshot_dev *dev,
+ int data_fd, xo_handle_t *xop,
+ struct vm_snapshot_meta *meta, off_t *offset)
{
int ret;
- ret = (*info->snapshot_cb)(meta);
+ meta->dev_name = dev->dev_name;
+ memset(meta->buffer.buf_start, 0, meta->buffer.buf_size);
+ meta->buffer.buf = meta->buffer.buf_start;
+ meta->buffer.buf_rem = meta->buffer.buf_size;
+
+ ret = (dev->dev_ops->snapshot_cb)(meta, dev->dev_cbdata);
if (ret != 0) {
- fprintf(stderr, "Failed to snapshot %s; ret=%d\r\n",
- meta->dev_name, ret);
+ warnx("Failed to snapshot %s: ret=%d", meta->dev_name, ret);
return (ret);
}
@@ -1186,13 +1117,14 @@
}
static int
-vm_snapshot_user_devs(struct vmctx *ctx, int data_fd, xo_handle_t *xop)
+vm_save_devices(struct vmctx *ctx, int data_fd, xo_handle_t *xop)
{
int ret;
off_t offset;
void *buffer;
- size_t buf_size, i;
+ size_t buf_size;
struct vm_snapshot_meta *meta;
+ struct snapshot_dev *dev;
buf_size = SNAPSHOT_BUFFER_SIZE;
@@ -1221,15 +1153,8 @@
xo_open_list_h(xop, JSON_DEV_ARR_KEY);
/* Restore other devices that support this feature */
- for (i = 0; i < nitems(snapshot_devs); i++) {
- meta->dev_name = snapshot_devs[i].dev_name;
-
- memset(meta->buffer.buf_start, 0, meta->buffer.buf_size);
- meta->buffer.buf = meta->buffer.buf_start;
- meta->buffer.buf_rem = meta->buffer.buf_size;
-
- ret = vm_snapshot_user_dev(&snapshot_devs[i], data_fd, xop,
- meta, &offset);
+ LIST_FOREACH(dev, &snapshot_devices, dev_link) {
+ ret = vm_save_device(dev, data_fd, xop, meta, &offset);
if (ret != 0)
goto snapshot_err;
}
@@ -1366,7 +1291,7 @@
vm_vcpu_pause(ctx);
- ret = vm_pause_user_devs();
+ ret = vm_pause_devices();
if (ret != 0) {
fprintf(stderr, "Could not pause devices\r\n");
error = ret;
@@ -1380,22 +1305,21 @@
goto done;
}
- ret = vm_snapshot_basic_metadata(ctx, xop, memsz);
+ ret = vm_save_basic_metadata(ctx, xop, memsz);
if (ret != 0) {
fprintf(stderr, "Failed to snapshot vm basic metadata.\n");
error = -1;
goto done;
}
-
- ret = vm_snapshot_kern_structs(ctx, kdata_fd, xop);
+ ret = vm_save_kern_structs(ctx, kdata_fd, xop);
if (ret != 0) {
fprintf(stderr, "Failed to snapshot vm kernel data.\n");
error = -1;
goto done;
}
- ret = vm_snapshot_user_devs(ctx, kdata_fd, xop);
+ ret = vm_save_devices(ctx, kdata_fd, xop);
if (ret != 0) {
fprintf(stderr, "Failed to snapshot device state.\n");
error = -1;
@@ -1410,7 +1334,7 @@
}
done:
- ret = vm_resume_user_devs();
+ ret = vm_resume_devices();
if (ret != 0)
fprintf(stderr, "Could not resume devices\r\n");
vm_vcpu_resume(ctx);

File Metadata

Mime Type
text/plain
Expires
Mon, Apr 28, 6:46 AM (14 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17826612
Default Alt Text
D35590.diff (26 KB)

Event Timeline