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 @@ -263,9 +263,10 @@ uint64_t pci_ecfg_base(void); int pci_bus_configured(int bus); #ifdef BHYVE_SNAPSHOT +struct pci_devinst *pci_next(const struct pci_devinst *cursor); int pci_snapshot(struct vm_snapshot_meta *meta); -int pci_pause(const char *dev_name); -int pci_resume(const char *dev_name); +int pci_pause(struct pci_devinst *pdi); +int pci_resume(struct pci_devinst *pdi); #endif static __inline void 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 @@ -2364,42 +2364,6 @@ return (ret); } -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) { @@ -2409,57 +2373,26 @@ 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); - } - - meta->dev_data = pdi; + pdi = meta->dev_data; + pde = pdi->pi_d; - if (pde->pe_snapshot == NULL) { - fprintf(stderr, "%s: not implemented yet for: %s\r\n", - __func__, meta->dev_name); - return (-1); - } + if (pde->pe_snapshot == NULL) + return (ENOTSUP); ret = pci_snapshot_pci_dev(meta); - if (ret != 0) { - fprintf(stderr, "%s: failed to snapshot pci dev\r\n", - __func__); - return (-1); - } - - ret = (*pde->pe_snapshot)(meta); + if (ret == 0) + ret = (*pde->pe_snapshot)(meta); return (ret); } int -pci_pause(const char *dev_name) +pci_pause(struct pci_devinst *pdi) { - struct pci_devemu *pde; - struct pci_devinst *pdi; - int ret; - - assert(dev_name != 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); - } + struct pci_devemu *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); return (0); } @@ -2467,28 +2400,12 @@ } int -pci_resume(const char *dev_name) +pci_resume(struct pci_devinst *pdi) { - struct pci_devemu *pde; - struct pci_devinst *pdi; - int ret; - - assert(dev_name != 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); - } + struct pci_devemu *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); return (0); } @@ -2665,6 +2582,42 @@ } #ifdef BHYVE_SNAPSHOT +struct pci_devinst * +pci_next(const struct pci_devinst *cursor) +{ + unsigned bus = 0, slot = 0, func = 0; + struct businfo *bi; + struct slotinfo *si; + struct funcinfo *fi; + + bus = cursor ? cursor->pi_bus : 0; + slot = cursor ? cursor->pi_slot : 0; + func = cursor ? (cursor->pi_func + 1) : 0; + + for (; bus < MAXBUSES; bus++) { + if ((bi = pci_businfo[bus]) == NULL) + continue; + + if (slot >= MAXSLOTS) + slot = 0; + + for (; slot < MAXSLOTS; slot++) { + si = &bi->slotinfo[slot]; + if (func >= MAXFUNCS) + func = 0; + for (; func < MAXFUNCS; func++) { + fi = &si->si_funcs[func]; + if (fi->fi_devi == NULL) + continue; + + return (fi->fi_devi); + } + } + } + + return (NULL); +} + static int pci_emul_snapshot(struct vm_snapshot_meta *meta __unused) { 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 @@ -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 }, @@ -856,31 +842,29 @@ } static int -vm_restore_device(struct restore_state *rstate, - const struct vm_snapshot_dev_info *info) +vm_restore_device(struct restore_state *rstate, vm_snapshot_dev_cb func, + const char *name, void *data) { void *dev_ptr; size_t dev_size; int ret; struct vm_snapshot_meta *meta; - dev_ptr = lookup_dev(info->dev_name, JSON_DEV_ARR_KEY, rstate, - &dev_size); + dev_ptr = lookup_dev(name, JSON_DEV_ARR_KEY, 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); + EPRINTLN("Failed to lookup dev: %s", name); + return (EINVAL); } if (dev_size == 0) { - fprintf(stderr, "%s: Device size is 0. " - "Assuming %s is not used\r\n", - __func__, info->dev_name); - return (0); + EPRINTLN("Restore device size is 0: %s", name); + return (EINVAL); } meta = &(struct vm_snapshot_meta) { - .dev_name = info->dev_name, + .dev_name = name, + .dev_data = data, .buffer.buf_start = dev_ptr, .buffer.buf_size = dev_size, @@ -891,11 +875,10 @@ .op = VM_SNAPSHOT_RESTORE, }; - ret = (*info->snapshot_cb)(meta); + ret = func(meta); if (ret != 0) { - fprintf(stderr, "Failed to restore dev: %s\r\n", - info->dev_name); - return (-1); + EPRINTLN("Failed to restore dev: %s %d", name, ret); + return (ret); } return (0); @@ -904,33 +887,30 @@ int vm_restore_devices(struct restore_state *rstate) { - size_t i; int ret; + struct pci_devinst *pdi = NULL; - for (i = 0; i < nitems(snapshot_devs); i++) { - ret = vm_restore_device(rstate, &snapshot_devs[i]); - if (ret != 0) + while ((pdi = pci_next(pdi)) != NULL) { + ret = vm_restore_device(rstate, pci_snapshot, pdi->pi_name, pdi); + if (ret) return (ret); } - return 0; + return (vm_restore_device(rstate, atkbdc_snapshot, "atkbdc", NULL)); } int vm_pause_devices(void) { - const struct vm_snapshot_dev_info *info; - size_t i; int ret; + struct pci_devinst *pdi = NULL; - for (i = 0; i < nitems(snapshot_devs); i++) { - info = &snapshot_devs[i]; - if (info->pause_cb == NULL) - continue; - - ret = info->pause_cb(info->dev_name); - if (ret != 0) + while ((pdi = pci_next(pdi)) != NULL) { + ret = pci_pause(pdi); + if (ret) { + EPRINTLN("Cannot pause dev %s: %d", pdi->pi_name, ret); return (ret); + } } return (0); @@ -939,18 +919,15 @@ int vm_resume_devices(void) { - const struct vm_snapshot_dev_info *info; - size_t i; int ret; + struct pci_devinst *pdi = NULL; - for (i = 0; i < nitems(snapshot_devs); i++) { - info = &snapshot_devs[i]; - if (info->resume_cb == NULL) - continue; - - ret = info->resume_cb(info->dev_name); - if (ret != 0) + while ((pdi = pci_next(pdi)) != NULL) { + ret = pci_resume(pdi); + if (ret) { + EPRINTLN("Cannot resume '%s': %d", pdi->pi_name, ret); return (ret); + } } return (0); @@ -1089,16 +1066,21 @@ } static int -vm_snapshot_device(const struct vm_snapshot_dev_info *info, - int data_fd, xo_handle_t *xop, - struct vm_snapshot_meta *meta, off_t *offset) +vm_snapshot_device(vm_snapshot_dev_cb func, const char *dev_name, + void *devdata, int data_fd, xo_handle_t *xop, + struct vm_snapshot_meta *meta, off_t *offset) { int ret; - ret = (*info->snapshot_cb)(meta); + 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; + meta->dev_name = dev_name; + meta->dev_data = devdata; + + ret = func(meta); if (ret != 0) { - fprintf(stderr, "Failed to snapshot %s; ret=%d\r\n", - meta->dev_name, ret); + EPRINTLN("Failed to snapshot %s; ret=%d", dev_name, ret); return (ret); } @@ -1116,8 +1098,9 @@ int ret; off_t offset; void *buffer; - size_t buf_size, i; + size_t buf_size; struct vm_snapshot_meta *meta; + struct pci_devinst *pdi; buf_size = SNAPSHOT_BUFFER_SIZE; @@ -1143,20 +1126,18 @@ 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_device(&snapshot_devs[i], data_fd, xop, - meta, &offset); + /* Save PCI devices */ + pdi = NULL; + while ((pdi = pci_next(pdi)) != NULL) { + ret = vm_snapshot_device(pci_snapshot, pdi->pi_name, pdi, + data_fd, xop, meta, &offset); if (ret != 0) goto snapshot_err; } + ret = vm_snapshot_device(atkbdc_snapshot, "atkbdc", NULL, + data_fd, xop, meta, &offset); + xo_close_list_h(xop, JSON_DEV_ARR_KEY); snapshot_err: