[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2 28/35] libxl_pci: Use ev_qmp in do_pci_add
This patch also replaces the use of libxl__wait_for_device_model_deprecated() by its equivalent without the need for a thread. Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx> Acked-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx> --- tools/libxl/libxl_internal.h | 1 - tools/libxl/libxl_pci.c | 288 ++++++++++++++++++++++++++++++++--- tools/libxl/libxl_qmp.c | 96 ------------ 3 files changed, 265 insertions(+), 120 deletions(-) diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 18c665d3dbe2..d60b9c416abf 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -1982,7 +1982,6 @@ typedef struct libxl__qmp_handler libxl__qmp_handler; */ _hidden libxl__qmp_handler *libxl__qmp_initialize(libxl__gc *gc, uint32_t domid); -_hidden int libxl__qmp_pci_add(libxl__gc *gc, int d, libxl_device_pci *pcidev); _hidden int libxl__qmp_pci_del(libxl__gc *gc, int domid, libxl_device_pci *pcidev); /* Resume hvm domain */ diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c index 503db6c26043..3477f3aba605 100644 --- a/tools/libxl/libxl_pci.c +++ b/tools/libxl/libxl_pci.c @@ -23,6 +23,7 @@ #define PCI_BDF_VDEVFN "%04x:%02x:%02x.%01x@%02x" #define PCI_OPTIONS "msitranslate=%d,power_mgmt=%d" #define PCI_BDF_XSPATH "%04x-%02x-%02x-%01x" +#define PCI_PT_QDEV_ID "pci-pt-%02x_%02x.%01x" static unsigned int pcidev_encode_bdf(libxl_device_pci *pcidev) { @@ -991,33 +992,40 @@ typedef struct pci_add_state { void (*callback)(libxl__egc *, struct pci_add_state *, int rc); /* private to do_pci_add */ + libxl__xswait_state xswait; + libxl__ev_qmp qmp; + libxl__ev_time timeout; libxl_device_pci *pcidev; int pci_domid; } pci_add_state; +static void pci_add_qemu_trad_watch_state_cb(libxl__egc *egc, + libxl__xswait_state *xswa, int rc, const char *state); +static void pci_add_qmp_device_add(libxl__egc *, pci_add_state *); +static void pci_add_qmp_device_add_cb(libxl__egc *, + libxl__ev_qmp *, const libxl__json_object *, int rc); +static void pci_add_qmp_query_pci_cb(libxl__egc *, + libxl__ev_qmp *, const libxl__json_object *, int rc); +static void pci_add_timeout(libxl__egc *egc, libxl__ev_time *ev, + const struct timeval *requested_abs, int rc); +static void pci_add_dm_done(libxl__egc *, + pci_add_state *, int rc); + static void do_pci_add(libxl__egc *egc, libxl_domid domid, libxl_device_pci *pcidev, pci_add_state *pas) { STATE_AO_GC(pas->aodev->ao); - libxl_ctx *ctx = libxl__gc_owner(gc); libxl_domain_type type = libxl__domain_type(gc, domid); - char *sysfs_path; - FILE *f; - unsigned long long start, end, flags, size; - int irq, i, rc, hvm = 0; - uint32_t flag = XEN_DOMCTL_DEV_RDM_RELAXED; - uint32_t domainid = domid; - bool isstubdom = libxl_is_stubdom(ctx, domid, &domainid); - int r; - - /* Convenience aliases */ - bool starting = pas->starting; + int rc; /* init pci_add_state */ + libxl__xswait_init(&pas->xswait); + libxl__ev_qmp_init(&pas->qmp); pas->pcidev = pcidev; pas->pci_domid = domid; + libxl__ev_time_init(&pas->timeout); if (type == LIBXL_DOMAIN_TYPE_INVALID) { rc = ERROR_FAIL; @@ -1025,26 +1033,259 @@ static void do_pci_add(libxl__egc *egc, } if (type == LIBXL_DOMAIN_TYPE_HVM) { - hvm = 1; switch (libxl__device_model_version_running(gc, domid)) { case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL: - if (libxl__wait_for_device_model_deprecated(gc, domid, - "running", NULL, NULL, NULL) < 0) { - rc = ERROR_FAIL; - goto out; - } - rc = qemu_pci_add_xenstore(gc, domid, pcidev); - break; + pas->xswait.ao = ao; + pas->xswait.what = "Device Model"; + pas->xswait.path = DEVICE_MODEL_XS_PATH(gc, + libxl_get_stubdom_id(CTX, domid), domid, "/state"); + pas->xswait.timeout_ms = LIBXL_DEVICE_MODEL_START_TIMEOUT * 1000; + pas->xswait.callback = pci_add_qemu_trad_watch_state_cb; + rc = libxl__xswait_start(gc, &pas->xswait); + if (rc) goto out; + return; case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN: - rc = libxl__qmp_pci_add(gc, domid, pcidev); - break; + pci_add_qmp_device_add(egc, pas); /* must be last */ + return; default: rc = ERROR_INVAL; + break; } - if ( rc ) + } + + rc = 0; + +out: + pci_add_dm_done(egc, pas, rc); /* must be last */ +} + +static void pci_add_qemu_trad_watch_state_cb(libxl__egc *egc, + libxl__xswait_state *xswa, + int rc, + const char *state) +{ + pci_add_state *pas = CONTAINER_OF(xswa, *pas, xswait); + STATE_AO_GC(pas->aodev->ao); + + /* Convenience aliases */ + libxl_domid domid = pas->domid; + libxl_device_pci *pcidev = pas->pcidev; + + if (rc) { + if (rc == ERROR_TIMEDOUT) { + LOGD(ERROR, domid, "%s not ready", xswa->what); + } + goto out; + } + + if (!state) + return; + if (strcmp(state, "running")) + return; + + rc = qemu_pci_add_xenstore(gc, domid, pcidev); +out: + libxl__xswait_stop(gc, xswa); + pci_add_dm_done(egc, pas, rc); /* must be last */ +} + +static void pci_add_qmp_device_add(libxl__egc *egc, pci_add_state *pas) +{ + STATE_AO_GC(pas->aodev->ao); + libxl__json_object *args = NULL; + int rc; + + /* Convenience aliases */ + libxl_domid domid = pas->domid; + libxl_device_pci *pcidev = pas->pcidev; + libxl__ev_qmp *const qmp = &pas->qmp; + + rc = libxl__ev_time_register_rel(ao, &pas->timeout, + pci_add_timeout, + LIBXL_QMP_CMD_TIMEOUT * 1000); + if (rc) goto out; + + libxl__qmp_param_add_string(gc, &args, "driver", + "xen-pci-passthrough"); + QMP_PARAMETERS_SPRINTF(&args, "id", PCI_PT_QDEV_ID, + pcidev->bus, pcidev->dev, pcidev->func); + QMP_PARAMETERS_SPRINTF(&args, "hostaddr", + "%04x:%02x:%02x.%01x", pcidev->domain, + pcidev->bus, pcidev->dev, pcidev->func); + if (pcidev->vdevfn) { + QMP_PARAMETERS_SPRINTF(&args, "addr", "%x.%x", + PCI_SLOT(pcidev->vdevfn), + PCI_FUNC(pcidev->vdevfn)); + } + /* + * Version of QEMU prior to the XSA-131 fix did not support + * this property and were effectively always in permissive + * mode. The fix for XSA-131 switched the default to be + * restricted by default and added the permissive property. + * + * Therefore in order to support both old and new QEMU we only + * set the permissive flag if it is true. Users of older QEMU + * have no reason to set the flag so this is ok. + */ + if (pcidev->permissive) + libxl__qmp_param_add_bool(gc, &args, "permissive", true); + + qmp->ao = pas->aodev->ao; + qmp->domid = domid; + qmp->payload_fd = -1; + qmp->callback = pci_add_qmp_device_add_cb; + rc = libxl__ev_qmp_send(gc, qmp, "device_add", args); + if (rc) goto out; + return; + +out: + pci_add_dm_done(egc, pas, rc); /* must be last */ +} + +static void pci_add_qmp_device_add_cb(libxl__egc *egc, + libxl__ev_qmp *qmp, + const libxl__json_object *response, + int rc) +{ + EGC_GC; + pci_add_state *pas = CONTAINER_OF(qmp, *pas, qmp); + + if (rc) goto out; + + qmp->callback = pci_add_qmp_query_pci_cb; + rc = libxl__ev_qmp_send(gc, qmp, "query-pci", NULL); + if (rc) goto out; + return; + +out: + pci_add_dm_done(egc, pas, rc); /* must be last */ +} + +static void pci_add_qmp_query_pci_cb(libxl__egc *egc, + libxl__ev_qmp *qmp, + const libxl__json_object *response, + int rc) +{ + EGC_GC; + pci_add_state *pas = CONTAINER_OF(qmp, *pas, qmp); + const libxl__json_object *bus = NULL; + char *asked_id; + int i, j; + const libxl__json_object *devices = NULL; + const libxl__json_object *device = NULL; + const libxl__json_object *o = NULL; + const char *id = NULL; + int dev_slot, dev_func; + + /* Convenience aliases */ + libxl_device_pci *pcidev = pas->pcidev; + + if (rc) goto out; + + /* `query-pci' returns: + * [ + * {'bus': 'int', + * 'devices': [ + * {'bus': 'int', 'slot': 'int', 'function': 'int', + * 'class_info': 'PciDeviceClass', 'id': 'PciDeviceId', + * '*irq': 'int', 'qdev_id': 'str', + * '*pci_bridge': 'PciBridgeInfo', + * 'regions': ['PciMemoryRegion'] + * } + * ] + * } + * ] + * (See qemu.git/qapi/ for the struct that aren't detailed here) + */ + + asked_id = GCSPRINTF(PCI_PT_QDEV_ID, + pcidev->bus, pcidev->dev, pcidev->func); + + for (i = 0; (bus = libxl__json_array_get(response, i)); i++) { + devices = libxl__json_map_get("devices", bus, JSON_ARRAY); + if (!devices) { + rc = ERROR_QEMU_API; goto out; + } + + for (j = 0; (device = libxl__json_array_get(devices, j)); j++) { + o = libxl__json_map_get("qdev_id", device, JSON_STRING); + if (!o) { + rc = ERROR_QEMU_API; + goto out; + } + id = libxl__json_object_get_string(o); + if (!id || strcmp(asked_id, id)) + continue; + + o = libxl__json_map_get("slot", device, JSON_INTEGER); + if (!o) { + rc = ERROR_QEMU_API; + goto out; + } + dev_slot = libxl__json_object_get_integer(o); + o = libxl__json_map_get("function", device, JSON_INTEGER); + if (!o) { + rc = ERROR_QEMU_API; + goto out; + } + dev_func = libxl__json_object_get_integer(o); + + pcidev->vdevfn = PCI_DEVFN(dev_slot, dev_func); + + rc = 0; + goto out; + } } + rc = ERROR_FAIL; + LOGD(ERROR, qmp->domid, + "PCI device id '%s' wasn't found in QEMU's 'query-pci' response.", + asked_id); + +out: + if (rc == ERROR_QEMU_API) { + LOGD(ERROR, qmp->domid, + "Unexpected response to QMP cmd 'query-pci', received:\n%s", + JSON(response)); + } + pci_add_dm_done(egc, pas, rc); /* must be last */ +} + +static void pci_add_timeout(libxl__egc *egc, libxl__ev_time *ev, + const struct timeval *requested_abs, + int rc) +{ + pci_add_state *pas = CONTAINER_OF(ev, *pas, timeout); + + pci_add_dm_done(egc, pas, rc); +} + +static void pci_add_dm_done(libxl__egc *egc, + pci_add_state *pas, + int rc) +{ + STATE_AO_GC(pas->aodev->ao); + libxl_ctx *ctx = libxl__gc_owner(gc); + libxl_domid domid = pas->pci_domid; + char *sysfs_path; + FILE *f; + unsigned long long start, end, flags, size; + int irq, i; + int r; + uint32_t flag = XEN_DOMCTL_DEV_RDM_RELAXED; + uint32_t domainid = domid; + bool isstubdom = libxl_is_stubdom(ctx, domid, &domainid); + + /* Convenience aliases */ + bool starting = pas->starting; + libxl_device_pci *pcidev = pas->pcidev; + bool hvm = libxl__domain_type(gc, domid) == LIBXL_DOMAIN_TYPE_HVM; + + libxl__ev_qmp_dispose(gc, &pas->qmp); + + if (rc) goto out; + sysfs_path = GCSPRINTF(SYSFS_PCI_DEV"/"PCI_BDF"/resource", pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func); f = fopen(sysfs_path, "r"); @@ -1145,6 +1386,7 @@ static void do_pci_add(libxl__egc *egc, else rc = 0; out: + libxl__ev_time_deregister(gc, &pas->timeout); pas->callback(egc, pas, rc); } diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c index c78ef4637d0a..38ba63d5b920 100644 --- a/tools/libxl/libxl_qmp.c +++ b/tools/libxl/libxl_qmp.c @@ -736,54 +736,6 @@ void libxl__qmp_cleanup(libxl__gc *gc, uint32_t domid) } } -static int pci_add_callback(libxl__qmp_handler *qmp, - const libxl__json_object *response, void *opaque) -{ - libxl_device_pci *pcidev = opaque; - const libxl__json_object *bus = NULL; - GC_INIT(qmp->ctx); - int i, j, rc = -1; - char *asked_id = GCSPRINTF(PCI_PT_QDEV_ID, - pcidev->bus, pcidev->dev, pcidev->func); - - for (i = 0; (bus = libxl__json_array_get(response, i)); i++) { - const libxl__json_object *devices = NULL; - const libxl__json_object *device = NULL; - const libxl__json_object *o = NULL; - const char *id = NULL; - - devices = libxl__json_map_get("devices", bus, JSON_ARRAY); - - for (j = 0; (device = libxl__json_array_get(devices, j)); j++) { - o = libxl__json_map_get("qdev_id", device, JSON_STRING); - id = libxl__json_object_get_string(o); - - if (id && strcmp(asked_id, id) == 0) { - int dev_slot, dev_func; - - o = libxl__json_map_get("slot", device, JSON_INTEGER); - if (!o) - goto out; - dev_slot = libxl__json_object_get_integer(o); - o = libxl__json_map_get("function", device, JSON_INTEGER); - if (!o) - goto out; - dev_func = libxl__json_object_get_integer(o); - - pcidev->vdevfn = PCI_DEVFN(dev_slot, dev_func); - - rc = 0; - goto out; - } - } - } - - -out: - GC_FREE; - return rc; -} - static int pci_del_callback(libxl__qmp_handler *qmp, const libxl__json_object *response, void *opaque) { @@ -833,54 +785,6 @@ static int qmp_run_command(libxl__gc *gc, int domid, return rc; } -int libxl__qmp_pci_add(libxl__gc *gc, int domid, libxl_device_pci *pcidev) -{ - libxl__qmp_handler *qmp = NULL; - libxl__json_object *args = NULL; - char *hostaddr = NULL; - int rc = 0; - - qmp = libxl__qmp_initialize(gc, domid); - if (!qmp) - return -1; - - hostaddr = GCSPRINTF("%04x:%02x:%02x.%01x", pcidev->domain, - pcidev->bus, pcidev->dev, pcidev->func); - if (!hostaddr) - return -1; - - libxl__qmp_param_add_string(gc, &args, "driver", "xen-pci-passthrough"); - QMP_PARAMETERS_SPRINTF(&args, "id", PCI_PT_QDEV_ID, - pcidev->bus, pcidev->dev, pcidev->func); - libxl__qmp_param_add_string(gc, &args, "hostaddr", hostaddr); - if (pcidev->vdevfn) { - QMP_PARAMETERS_SPRINTF(&args, "addr", "%x.%x", - PCI_SLOT(pcidev->vdevfn), PCI_FUNC(pcidev->vdevfn)); - } - /* - * Version of QEMU prior to the XSA-131 fix did not support this - * property and were effectively always in permissive mode. The - * fix for XSA-131 switched the default to be restricted by - * default and added the permissive property. - * - * Therefore in order to support both old and new QEMU we only set - * the permissive flag if it is true. Users of older QEMU have no - * reason to set the flag so this is ok. - */ - if (pcidev->permissive) - libxl__qmp_param_add_bool(gc, &args, "permissive", true); - - rc = qmp_synchronous_send(qmp, "device_add", args, - NULL, NULL, qmp->timeout); - if (rc == 0) { - rc = qmp_synchronous_send(qmp, "query-pci", NULL, - pci_add_callback, pcidev, qmp->timeout); - } - - libxl__qmp_close(qmp); - return rc; -} - static int qmp_device_del(libxl__gc *gc, int domid, char *id) { libxl__json_object *args = NULL; -- Anthony PERARD _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |