[libvirt] [PATCH 0/6] Add support for injecting NMI to guest

This patch series implements a feature of injecting NMI to guest, which is accessible via new virDomainInjectNMI API and 'inject-nmi' command in virsh. Lai Jiangshan (6): inject-nmi: Defining the public API inject-nmi: Defining the internal API inject-nmi: Implementing the public API inject-nmi: Implementing the remote protocol inject-nmi: Expose the new API in virsh qemu,inject-nmi: Implement the driver methods daemon/remote.c | 26 ++++++++++++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 ++++++ daemon/remote_dispatch_table.h | 5 ++++ include/libvirt/libvirt.h.in | 2 + src/driver.h | 4 +++ src/esx/esx_driver.c | 1 + src/libvirt.c | 44 +++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++++ src/libxl/libxl_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 3 +- src/qemu/qemu_driver.c | 43 ++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 14 +++++++++++ src/qemu/qemu_monitor.h | 2 + src/qemu/qemu_monitor_json.c | 29 +++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 1 + src/qemu/qemu_monitor_text.c | 20 ++++++++++++++++ src/qemu/qemu_monitor_text.h | 1 + src/remote/remote_driver.c | 25 +++++++++++++++++++ src/remote/remote_protocol.c | 11 ++++++++ src/remote/remote_protocol.h | 10 ++++++++ src/remote/remote_protocol.x | 8 +++++- src/remote_protocol-structs | 4 +++ src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/vmware/vmware_driver.c | 1 + src/xen/xen_driver.c | 1 + src/xen/xen_driver.h | 1 + src/xen/xen_hypervisor.c | 1 + src/xen/xen_inotify.c | 1 + src/xen/xend_internal.c | 1 + src/xen/xm_internal.c | 1 + src/xen/xs_internal.c | 1 + src/xenapi/xenapi_driver.c | 1 + tools/virsh.c | 36 ++++++++++++++++++++++++++++ tools/virsh.pod | 4 +++ 39 files changed, 320 insertions(+), 2 deletions(-) -- 1.7.4

--- include/libvirt/libvirt.h.in | 2 ++ src/libvirt_public.syms | 5 +++++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 5783303..0e1e27a 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2519,6 +2519,8 @@ int virDomainOpenConsole(virDomainPtr dom, virStreamPtr st, unsigned int flags); +int virDomainInjectNMI(virDomainPtr domain, unsigned int flags); + #ifdef __cplusplus } #endif diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index b4aed41..f5bbc01 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -436,4 +436,9 @@ LIBVIRT_0.9.0 { virStorageVolUpload; } LIBVIRT_0.8.8; +LIBVIRT_0.9.1 { + global: + virDomainInjectNMI; +} LIBVIRT_0.9.0; + # .... define new API here using predicted next version number .... -- 1.7.4

--- src/driver.h | 4 ++++ src/esx/esx_driver.c | 1 + src/libxl/libxl_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 3 ++- src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/vmware/vmware_driver.c | 1 + src/xen/xen_driver.c | 1 + src/xen/xen_driver.h | 1 + src/xen/xen_hypervisor.c | 1 + src/xen/xen_inotify.c | 1 + src/xen/xend_internal.c | 1 + src/xen/xm_internal.c | 1 + src/xen/xs_internal.c | 1 + src/xenapi/xenapi_driver.c | 1 + 20 files changed, 24 insertions(+), 1 deletions(-) diff --git a/src/driver.h b/src/driver.h index a8b79e6..94cc37d 100644 --- a/src/driver.h +++ b/src/driver.h @@ -515,6 +515,9 @@ typedef int virStreamPtr st, unsigned int flags); +typedef int + (*virDrvDomainInjectNMI)(virDomainPtr dom, unsigned int flags); + /** * _virDriver: @@ -639,6 +642,7 @@ struct _virDriver { virDrvDomainSnapshotDelete domainSnapshotDelete; virDrvQemuDomainMonitorCommand qemuDomainMonitorCommand; virDrvDomainOpenConsole domainOpenConsole; + virDrvDomainInjectNMI domainInjectNMI; }; typedef int diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index deda372..061a562 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -4675,6 +4675,7 @@ static virDriver esxDriver = { esxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 3040914..35e8104 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -2663,6 +2663,7 @@ static virDriver libxlDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virStateDriver libxlStateDriver = { diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index e905302..fbbe803 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2906,6 +2906,7 @@ static virDriver lxcDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ lxcDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virStateDriver lxcStateDriver = { diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 4af28e9..96f82bb 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1667,6 +1667,7 @@ static virDriver openvzDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; int openvzRegister(void) { diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index ddbc103..dfd0463 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -4071,7 +4071,8 @@ static virDriver phypDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuMonitorCommand */ - NULL, /* domainOpenConsole */ + NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virStorageDriver phypStorageDriver = { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 04a5f65..c3ec07e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6970,6 +6970,7 @@ static virDriver qemuDriver = { qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ qemuDomainOpenConsole, /* domainOpenConsole */ + qemuDomainInjectNMI, /* domainInjectNMI */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index b979f71..795bea9 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -11301,6 +11301,7 @@ static virDriver remote_driver = { remoteDomainSnapshotDelete, /* domainSnapshotDelete */ remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ remoteDomainOpenConsole, /* domainOpenConsole */ + remoteDomainInjectNMI, /* domainInjectNMI */ }; static virNetworkDriver network_driver = { diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 17f5ad9..b4dcc5b 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5447,6 +5447,7 @@ static virDriver testDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virNetworkDriver testNetworkDriver = { diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 33849a0..73a5415 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2253,6 +2253,7 @@ static virDriver umlDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ umlDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static int diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 0fbfba5..4bcc192 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -8647,6 +8647,7 @@ virDriver NAME(Driver) = { vboxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; virNetworkDriver NAME(NetworkDriver) = { diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index b5e416b..d6fc9e8 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -1007,6 +1007,7 @@ static virDriver vmwareDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; int diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 9f47722..c9e6115 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -2141,6 +2141,7 @@ static virDriver xenUnifiedDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ xenUnifiedDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; /** diff --git a/src/xen/xen_driver.h b/src/xen/xen_driver.h index 58b8561..7cc363c 100644 --- a/src/xen/xen_driver.h +++ b/src/xen/xen_driver.h @@ -108,6 +108,7 @@ struct xenUnifiedDriver { virDrvDomainGetSchedulerType domainGetSchedulerType; virDrvDomainGetSchedulerParameters domainGetSchedulerParameters; virDrvDomainSetSchedulerParameters domainSetSchedulerParameters; + virDrvDomainInjectNMI domainInjectNMI; }; typedef struct xenXMConfCache *xenXMConfCachePtr; diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index 8a9dae5..9b0bfcc 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -839,6 +839,7 @@ struct xenUnifiedDriver xenHypervisorDriver = { xenHypervisorGetSchedulerType, /* domainGetSchedulerType */ xenHypervisorGetSchedulerParameters, /* domainGetSchedulerParameters */ xenHypervisorSetSchedulerParameters, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; #define virXenError(code, ...) \ diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index 5a997e6..9a68e6b 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -87,6 +87,7 @@ struct xenUnifiedDriver xenInotifyDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; static int diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 04122ba..783d2d1 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -3881,6 +3881,7 @@ struct xenUnifiedDriver xenDaemonDriver = { xenDaemonGetSchedulerType, /* domainGetSchedulerType */ xenDaemonGetSchedulerParameters, /* domainGetSchedulerParameters */ xenDaemonSetSchedulerParameters, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index 9225808..72bd863 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -118,6 +118,7 @@ struct xenUnifiedDriver xenXMDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; #define xenXMError(code, ...) \ diff --git a/src/xen/xs_internal.c b/src/xen/xs_internal.c index d9aad1f..0118a9e 100644 --- a/src/xen/xs_internal.c +++ b/src/xen/xs_internal.c @@ -80,6 +80,7 @@ struct xenUnifiedDriver xenStoreDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; #define virXenStoreError(code, ...) \ diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 60b23c7..7069b52 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -1889,6 +1889,7 @@ static virDriver xenapiDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; /** -- 1.7.4

--- src/libvirt.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index 0da9885..56996f9 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -5214,6 +5214,50 @@ error: } /** + * virDomainInjectNMI: + * @domain: pointer to domain object, or NULL for Domain0 + * @flags: the flags for controlling behaviours + * + * Send NMI to the guest + * + * Returns 0 in case of success, -1 in case of failure. + */ + +int virDomainInjectNMI(virDomainPtr domain, unsigned int flags) +{ + virConnectPtr conn; + VIR_DOMAIN_DEBUG(domain, "flags=%u", flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return (-1); + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + conn = domain->conn; + + if (conn->driver->domainInjectNMI) { + int ret; + ret = conn->driver->domainInjectNMI(domain, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + +/** * virDomainSetVcpus: * @domain: pointer to domain object, or NULL for Domain0 * @nvcpus: the new number of virtual CPUs for this domain -- 1.7.4

--- daemon/remote.c | 26 ++++++++++++++++++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 ++++++++ daemon/remote_dispatch_table.h | 5 +++++ src/remote/remote_driver.c | 24 ++++++++++++++++++++++++ src/remote/remote_protocol.c | 11 +++++++++++ src/remote/remote_protocol.h | 10 ++++++++++ src/remote/remote_protocol.x | 8 +++++++- src/remote_protocol-structs | 4 ++++ 9 files changed, 96 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index dd85ef1..a539d03 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -2844,6 +2844,32 @@ remoteDispatchDomainGetBlkioParameters(struct qemud_server *server } static int +remoteDispatchDomainInjectNMI(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *rerr, + remote_domain_inject_nmi_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virDomainPtr dom; + + dom = get_nonnull_domain(conn, args->dom); + if (dom == NULL) { + remoteDispatchConnError(rerr, conn); + return -1; + } + + if (virDomainInjectNMI(dom, args->flags) == -1) { + virDomainFree(dom); + remoteDispatchConnError(rerr, conn); + return -1; + } + virDomainFree(dom); + return 0; +} + +static int remoteDispatchDomainSetVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, struct qemud_client *client ATTRIBUTE_UNUSED, virConnectPtr conn, diff --git a/daemon/remote_dispatch_args.h b/daemon/remote_dispatch_args.h index f9537d7..4887d7c 100644 --- a/daemon/remote_dispatch_args.h +++ b/daemon/remote_dispatch_args.h @@ -178,3 +178,4 @@ remote_domain_migrate_set_max_speed_args val_remote_domain_migrate_set_max_speed_args; remote_storage_vol_upload_args val_remote_storage_vol_upload_args; remote_storage_vol_download_args val_remote_storage_vol_download_args; + remote_domain_inject_nmi_args val_remote_domain_inject_nmi_args; diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h index 18bf41d..4e12cb0 100644 --- a/daemon/remote_dispatch_prototypes.h +++ b/daemon/remote_dispatch_prototypes.h @@ -338,6 +338,14 @@ static int remoteDispatchDomainHasManagedSaveImage( remote_error *err, remote_domain_has_managed_save_image_args *args, remote_domain_has_managed_save_image_ret *ret); +static int remoteDispatchDomainInjectNMI( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + remote_domain_inject_nmi_args *args, + void *ret); static int remoteDispatchDomainInterfaceStats( struct qemud_server *server, struct qemud_client *client, diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index b39f7c2..b911acf 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -1052,3 +1052,8 @@ .args_filter = (xdrproc_t) xdr_remote_storage_vol_download_args, .ret_filter = (xdrproc_t) xdr_void, }, +{ /* DomainInjectNMI => 210 */ + .fn = (dispatch_fn) remoteDispatchDomainInjectNMI, + .args_filter = (xdrproc_t) xdr_remote_domain_inject_nmi_args, + .ret_filter = (xdrproc_t) xdr_void, +}, diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 795bea9..40deb52 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2933,6 +2933,30 @@ done: } static int +remoteDomainInjectNMI(virDomainPtr domain, unsigned int flags) +{ + int rv = -1; + remote_domain_inject_nmi_args args; + struct private_data *priv = domain->conn->privateData; + + remoteDriverLock(priv); + + make_nonnull_domain (&args.dom, domain); + args.flags = flags; + + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_INJECT_NMI, + (xdrproc_t) xdr_remote_domain_inject_nmi_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + goto done; + + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; +} + +static int remoteDomainSetVcpus (virDomainPtr domain, unsigned int nvcpus) { int rv = -1; diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 5604371..3ff0b1f 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -1463,6 +1463,17 @@ xdr_remote_domain_undefine_args (XDR *xdrs, remote_domain_undefine_args *objp) } bool_t +xdr_remote_domain_inject_nmi_args (XDR *xdrs, remote_domain_inject_nmi_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_domain_set_vcpus_args (XDR *xdrs, remote_domain_set_vcpus_args *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index d9bf151..4da003e 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -2200,6 +2200,13 @@ struct remote_storage_vol_download_args { u_int flags; }; typedef struct remote_storage_vol_download_args remote_storage_vol_download_args; + +struct remote_domain_inject_nmi_args { + remote_nonnull_domain dom; + u_int flags; +}; +typedef struct remote_domain_inject_nmi_args remote_domain_inject_nmi_args; + #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1 @@ -2413,6 +2420,7 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, + REMOTE_PROC_DOMAIN_INJECT_NMI = 210, }; typedef enum remote_procedure remote_procedure; @@ -2561,6 +2569,7 @@ extern bool_t xdr_remote_domain_create_with_flags_ret (XDR *, remote_domain_cre extern bool_t xdr_remote_domain_define_xml_args (XDR *, remote_domain_define_xml_args*); extern bool_t xdr_remote_domain_define_xml_ret (XDR *, remote_domain_define_xml_ret*); extern bool_t xdr_remote_domain_undefine_args (XDR *, remote_domain_undefine_args*); +extern bool_t xdr_remote_domain_inject_nmi_args (XDR *, remote_domain_inject_nmi_args*); extern bool_t xdr_remote_domain_set_vcpus_args (XDR *, remote_domain_set_vcpus_args*); extern bool_t xdr_remote_domain_set_vcpus_flags_args (XDR *, remote_domain_set_vcpus_flags_args*); extern bool_t xdr_remote_domain_get_vcpus_flags_args (XDR *, remote_domain_get_vcpus_flags_args*); @@ -2918,6 +2927,7 @@ extern bool_t xdr_remote_domain_create_with_flags_ret (); extern bool_t xdr_remote_domain_define_xml_args (); extern bool_t xdr_remote_domain_define_xml_ret (); extern bool_t xdr_remote_domain_undefine_args (); +extern bool_t xdr_remote_domain_inject_nmi_args (); extern bool_t xdr_remote_domain_set_vcpus_args (); extern bool_t xdr_remote_domain_set_vcpus_flags_args (); extern bool_t xdr_remote_domain_get_vcpus_flags_args (); diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 675eccd..1aacf99 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -817,6 +817,11 @@ struct remote_domain_undefine_args { remote_nonnull_domain dom; }; +struct remote_domain_inject_nmi_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + struct remote_domain_set_vcpus_args { remote_nonnull_domain dom; int nvcpus; @@ -2176,8 +2181,9 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_BLKIO_PARAMETERS = 206, REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, - REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209 + REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, + REMOTE_PROC_DOMAIN_INJECT_NMI = 210, /* * Notice how the entries are grouped in sets of 10 ? * Nice isn't it. Please keep it this way when adding more. diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 944553c..4b75e33 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1435,3 +1435,7 @@ struct remote_message_header { u_int serial; remote_message_status status; }; +struct remote_domain_inject_nmi_args { + remote_nonnull_domain dom; + unsigned int flags; +}; -- 1.7.4

--- tools/virsh.c | 36 ++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 4 ++++ 2 files changed, 40 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 2e35021..5e3df8a 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2919,6 +2919,41 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd) } /* + * "inject-nmi" command + */ +static const vshCmdInfo info_inject_nmi[] = { + {"help", N_("Inject NMI to the guest")}, + {"desc", N_("Inject NMI to the guest domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_inject_nmi[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + + +static int +cmdInjectNMI(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *type; + int ret = TRUE; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return FALSE; + + if (virDomainInjectNMI(dom, 0) < 0) + ret = FALSE; + + virDomainFree(dom); + return ret; +} + +/* * "setmemory" command */ static const vshCmdInfo info_setmem[] = { @@ -10733,6 +10768,7 @@ static const vshCmdDef domManagementCmds[] = { {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem}, {"setmem", cmdSetmem, opts_setmem, info_setmem}, {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus}, + {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi}, {"shutdown", cmdShutdown, opts_shutdown, info_shutdown}, {"start", cmdStart, opts_start, info_start}, {"suspend", cmdSuspend, opts_suspend, info_suspend}, diff --git a/tools/virsh.pod b/tools/virsh.pod index 2a708f6..f317c57 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -290,6 +290,10 @@ running B<virsh suspend>. When in a paused state the domain will still consume allocated resources like memory, but will not be eligible for scheduling by the hypervisor. +=item B<inject-nmi> I<domain-id> + +Inject NMI to the guest + =item B<shutdown> The domain is in the process of shutting down, i.e. the guest operating system -- 1.7.4

--- src/qemu/qemu_driver.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 14 ++++++++++++++ src/qemu/qemu_monitor.h | 2 ++ src/qemu/qemu_monitor_json.c | 29 +++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 1 + src/qemu/qemu_monitor_text.c | 20 ++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 1 + 7 files changed, 109 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c3ec07e..274d605 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1701,6 +1701,48 @@ static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long memory) return qemudDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM); } +static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags) +{ + struct qemud_driver *driver = domain->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + qemuDomainObjPrivatePtr priv; + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, domain->uuid); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(domain->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) + goto cleanup; + qemuDomainObjEnterMonitorWithDriver(driver, vm); + ret = qemuMonitorInjectNMI(priv->mon, flags); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (qemuDomainObjEndJob(vm) == 0) { + vm = NULL; + goto cleanup; + } + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + static int qemudDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 2d28f8d..de48156 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2228,3 +2228,17 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, ret = qemuMonitorTextArbitraryCommand(mon, cmd, reply); return ret; } + + +int qemuMonitorInjectNMI(qemuMonitorPtr mon, unsigned int flags) +{ + int ret; + + VIR_DEBUG("mon=%p, flags=%u", mon, flags); + + if (mon->json) + ret = qemuMonitorJSONInjectNMI(mon, flags); + else + ret = qemuMonitorTextInjectNMI(mon, flags); + return ret; +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c90219b..7acec43 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -423,6 +423,8 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, char **reply, bool hmp); +int qemuMonitorInjectNMI(qemuMonitorPtr mon, unsigned int flags); + /** * When running two dd process and using <> redirection, we need a * shell that will not truncate files. These two strings serve that diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 20a78e1..e980db2 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2513,3 +2513,32 @@ cleanup: return ret; } + +int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon, unsigned int flags ATTRIBUTE_UNUSED) +{ + int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + /* + * FIXME: qmp nmi is not supported until qemu-0.16.0, + * use human-monitor-command instead temporary. + * + * FIXME: qemu's nmi command just injects NMI to a specified CPU, + * use "nmi 0" instead temporary. + */ + cmd = qemuMonitorJSONMakeCommand("human-monitor-command", + "s:command-line", "nmi 0", + NULL); + if (!cmd) + return -1; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 086f0e1..7488100 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -204,4 +204,5 @@ int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, char **reply_str, bool hmp); +int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon, unsigned int flags); #endif /* QEMU_MONITOR_JSON_H */ diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 53781c8..e28f211 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -2628,3 +2628,23 @@ int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd, return ret; } + +int qemuMonitorTextInjectNMI(qemuMonitorPtr mon, unsigned int flags ATTRIBUTE_UNUSED) +{ + const char *cmd = "nmi 0"; + char *reply = NULL; + + /* + * FIXME: qemu's nmi command just injects NMI to a specified CPU, + * use "nmi 0" instead temporary. + */ + if (!qemuMonitorTextArbitraryCommand(mon, cmd, &reply)) { + qemuReportError(VIR_ERR_OPERATION_FAILED, + _("failed to inject NMI using command '%s'"), + cmd); + return -1; + } + + VIR_FREE(reply); + return 0; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 0838a2b..0f6afb9 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -198,4 +198,5 @@ int qemuMonitorTextDeleteSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply); +int qemuMonitorTextInjectNMI(qemuMonitorPtr mon, unsigned int flags); #endif /* QEMU_MONITOR_TEXT_H */ -- 1.7.4

On 04/12/2011 11:01 PM, Lai Jiangshan wrote:
+++ b/src/qemu/qemu_driver.c @@ -1701,6 +1701,48 @@ static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long memory) return qemudDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM); }
+static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags) +{ + struct qemud_driver *driver = domain->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + qemuDomainObjPrivatePtr priv; +
Right here, you should have a virCheckFlags(0, -1) to enforce that we don't honor any flags for now. At which point, you don't need to pass flags on down to the monitor calls.
+++ b/src/qemu/qemu_monitor_json.c @@ -2513,3 +2513,32 @@ cleanup:
return ret; } + +int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon, unsigned int flags ATTRIBUTE_UNUSED) +{
Since neither monitor needed flags this low, you don't have to propogate it any further than qemu_driver.c's virCheckFlags().
+ int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + /* + * FIXME: qmp nmi is not supported until qemu-0.16.0, + * use human-monitor-command instead temporary. + * + * FIXME: qemu's nmi command just injects NMI to a specified CPU, + * use "nmi 0" instead temporary. + */ + cmd = qemuMonitorJSONMakeCommand("human-monitor-command", + "s:command-line", "nmi 0", + NULL);
We've already got a preferred form for issuing HMP commands from JSON. Rather than building up human-monitor-command manually, you should instead be using qemuMonitorTextInjectNMI; for example, see how qemuMonitorJSONDriveDel falls back to hmp. This also covers the case of a qemu binary that has JSON but not hmp giving a more useful error message.
+++ b/src/qemu/qemu_monitor_text.c @@ -2628,3 +2628,23 @@ int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd,
return ret; } + +int qemuMonitorTextInjectNMI(qemuMonitorPtr mon, unsigned int flags ATTRIBUTE_UNUSED) +{ + const char *cmd = "nmi 0"; + char *reply = NULL; + + /* + * FIXME: qemu's nmi command just injects NMI to a specified CPU, + * use "nmi 0" instead temporary. + */
This bothers me. Is it possible to inject NMI to a particular CPU in bare-metal hardware? If so, then we ought to support that in the API. I know what Dan said:
+int virDomainSendEventNMI(virDomainPtr domain, unsigned int vcpu)
Your proposal to qemu-devel to add inject-nmi for QMP does not include any CPU index parameter anymore. Instead it will automatically inject the NMI to all present CPUs. This libvirt API would appear to be incompatible with that QMP design. For Xen, it appears the API also does not allow a CPU index to be given - it just injects to the first CPU AFAICT.
So do we really need to have a 'unsigned int vcpu' parameter in the libvirt API, or can we just leave it out and always inject to CPU==0 for HMP ?
eg simplify to
int virDomainSendNMI(virDomainPtr domain)
but if there's ever any possibility that qemu might learn how to direct an NMI to a particular vcpu, I wonder if we should instead have: enum { VIR_DOMAIN_INJECT_NMI_FIRST = 1, VIR_DOMAIN_INJECT_NMI_ALL = 2, } /** * virDomainInjectNMI: * @domain: pointer to domain object, or NULL for Domain0 * @vcpu: which vcpu to send the NMI to * @flags: the flags for controlling behaviours * * Send NMI to the guest. If @flags contains * VIR_DOMAIN_INJECT_NMI_FIRST or VIR_DOMAIN_INJECT_NMI_ALL, * then @vcpu is ignored, and the NMI is sent to the first * possible vcpu or to all vcpus, respectively. Otherwise, * the NMI is sent to the specified vcpu; it is an error if * @vcpu does not correspond to a currently online processor. * * Not all hypervisors support fine-tuned control over which * vcpu(s) can be targetted, and might succeed only for a * particular value of @flags. * * Returns 0 in case of success, -1 in case of failure. */ int virDomainInjectNMI(virDomainPtr domain, unsigned int vcpu, unsigned int flags); Then xen would be hardcoded to require flags==_FIRST (and always ignore vcpu), whereas qemu can honor a particular vcpu. Or is the first vcpu always 0? That is, are there any hypervisors that let you offline vcpu 0 while leaving vcpu1 up, so that FIRST would imply 1? Maybe we don't need a flag for FIRST, but document that vcpu is ignored if ALL is passed, and then make xen error out if ALL is passed or if vcpu != 0. That said, I haven't looked at the proposed qemu side of the patches for how the monitor command for nmi will be implemented in the first place, and until that is in a formal qemu release, we may still need to be a bit flexible here on the libvirt side. Do any other hypervisors allow NMI injection, and with what semantics? -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On 04/16/2011 02:13 AM, Eric Blake wrote:
On 04/12/2011 11:01 PM, Lai Jiangshan wrote:
+++ b/src/qemu/qemu_driver.c @@ -1701,6 +1701,48 @@ static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long memory) return qemudDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM); }
+static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags) +{ + struct qemud_driver *driver = domain->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + qemuDomainObjPrivatePtr priv; +
Right here, you should have a virCheckFlags(0, -1) to enforce that we don't honor any flags for now. At which point, you don't need to pass flags on down to the monitor calls.
+++ b/src/qemu/qemu_monitor_json.c @@ -2513,3 +2513,32 @@ cleanup:
return ret; } + +int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon, unsigned int flags ATTRIBUTE_UNUSED) +{
Since neither monitor needed flags this low, you don't have to propogate it any further than qemu_driver.c's virCheckFlags().
+ int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + /* + * FIXME: qmp nmi is not supported until qemu-0.16.0, + * use human-monitor-command instead temporary. + * + * FIXME: qemu's nmi command just injects NMI to a specified CPU, + * use "nmi 0" instead temporary. + */ + cmd = qemuMonitorJSONMakeCommand("human-monitor-command", + "s:command-line", "nmi 0", + NULL);
We've already got a preferred form for issuing HMP commands from JSON. Rather than building up human-monitor-command manually, you should instead be using qemuMonitorTextInjectNMI; for example, see how qemuMonitorJSONDriveDel falls back to hmp. This also covers the case of a qemu binary that has JSON but not hmp giving a more useful error message.
+++ b/src/qemu/qemu_monitor_text.c @@ -2628,3 +2628,23 @@ int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd,
return ret; } + +int qemuMonitorTextInjectNMI(qemuMonitorPtr mon, unsigned int flags ATTRIBUTE_UNUSED) +{ + const char *cmd = "nmi 0"; + char *reply = NULL; + + /* + * FIXME: qemu's nmi command just injects NMI to a specified CPU, + * use "nmi 0" instead temporary. + */
This bothers me. Is it possible to inject NMI to a particular CPU in bare-metal hardware? If so, then we ought to support that in the API.
The real world NMI button just sends NMI to all cpus, the qemu side code will also be modified that hmp nmi command just sends NMI to all CPU and the cpu-index parameter will be removed. My original qemu side patch lefts cpu-index parameter for kernel debugging, but the qemu guys persuade me that inject-nmi command should just send NMI to CPUs. I accepted it. I think the libvirt will handle it at the same way. Thanks, Lai.

On 04/18/2011 02:39 AM, Lai Jiangshan wrote:
+int qemuMonitorTextInjectNMI(qemuMonitorPtr mon, unsigned int flags ATTRIBUTE_UNUSED) +{ + const char *cmd = "nmi 0"; + char *reply = NULL; + + /* + * FIXME: qemu's nmi command just injects NMI to a specified CPU, + * use "nmi 0" instead temporary. + */
This bothers me. Is it possible to inject NMI to a particular CPU in bare-metal hardware? If so, then we ought to support that in the API.
The real world NMI button just sends NMI to all cpus, the qemu side code will also be modified that hmp nmi command just sends NMI to all CPU and the cpu-index parameter will be removed.
My original qemu side patch lefts cpu-index parameter for kernel debugging, but the qemu guys persuade me that inject-nmi command should just send NMI to CPUs. I accepted it. I think the libvirt will handle it at the same way.
Makes sense, and matches with what I learned on a google search about the "NMI button" on real hardware. Thus, the real fixme is that qemu's nmi command has a bogus argument during preliminary patch review that will be going away before inject-nmi is made official, and therefore, libvirt should just be sending "nmi" and not "nmi 0" once there is a released version of qemu that actually supports injecting NMI, and you are right that the API should not expose a vcpu parameter. Any timeframe on when a released qemu might support nmi injection, or even a pointer to a URL where the qemu patch stream is under discussion? It doesn't make too much sense to push this patch into libvirt until we are reasonably sure that the qemu interface is well-baked, to minimize needing later libvirt tweaks. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Mon, Apr 18, 2011 at 04:54:25PM -0600, Eric Blake wrote:
On 04/18/2011 02:39 AM, Lai Jiangshan wrote:
+int qemuMonitorTextInjectNMI(qemuMonitorPtr mon, unsigned int flags ATTRIBUTE_UNUSED) +{ + const char *cmd = "nmi 0"; + char *reply = NULL; + + /* + * FIXME: qemu's nmi command just injects NMI to a specified CPU, + * use "nmi 0" instead temporary. + */
This bothers me. Is it possible to inject NMI to a particular CPU in bare-metal hardware? If so, then we ought to support that in the API.
The real world NMI button just sends NMI to all cpus, the qemu side code will also be modified that hmp nmi command just sends NMI to all CPU and the cpu-index parameter will be removed.
My original qemu side patch lefts cpu-index parameter for kernel debugging, but the qemu guys persuade me that inject-nmi command should just send NMI to CPUs. I accepted it. I think the libvirt will handle it at the same way.
Makes sense, and matches with what I learned on a google search about the "NMI button" on real hardware. Thus, the real fixme is that qemu's nmi command has a bogus argument during preliminary patch review that will be going away before inject-nmi is made official, and therefore, libvirt should just be sending "nmi" and not "nmi 0" once there is a released version of qemu that actually supports injecting NMI, and you are right that the API should not expose a vcpu parameter.
Any timeframe on when a released qemu might support nmi injection, or even a pointer to a URL where the qemu patch stream is under discussion? It doesn't make too much sense to push this patch into libvirt until we are reasonably sure that the qemu interface is well-baked, to minimize needing later libvirt tweaks.
QEMU has included an HMP command for NMI for quite a while. We're only arguing upstream about the QMP version of it. We could take this patch with the HMP command any time we like, but it would be nice to have a little more clarity about what's going to happen to the QMP version in qemu-devel. We don't have to wait for a new QEMU release, but in ideal world we'd see them accept Lai's QMP patches into GIT. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

This patch series implements a feature of injecting NMI to guest, which is accessible via new virDomainInjectNMI API and 'inject-nmi' command in virsh. Lai Jiangshan (6): inject-nmi: Defining the public API inject-nmi: Defining the internal API inject-nmi: Implementing the public API inject-nmi: Implementing the remote protocol inject-nmi: Expose the new API in virsh qemu,inject-nmi: Implement the driver methods daemon/remote.c | 28 +++++++++++++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 ++++++ daemon/remote_dispatch_table.h | 5 ++++ include/libvirt/libvirt.h.in | 2 + src/driver.h | 4 +++ src/esx/esx_driver.c | 1 + src/libvirt.c | 44 ++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++++ src/libxl/libxl_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 3 +- src/qemu/qemu_driver.c | 45 +++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 14 +++++++++++ src/qemu/qemu_monitor.h | 2 + src/qemu/qemu_monitor_json.c | 27 +++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 1 + src/qemu/qemu_monitor_text.c | 20 +++++++++++++++ src/qemu/qemu_monitor_text.h | 1 + src/remote/remote_driver.c | 25 +++++++++++++++++++ src/remote/remote_protocol.c | 11 ++++++++ src/remote/remote_protocol.h | 10 +++++++ src/remote/remote_protocol.x | 8 +++++- src/remote_protocol-structs | 4 +++ src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/vmware/vmware_driver.c | 1 + src/xen/xen_driver.c | 1 + src/xen/xen_driver.h | 1 + src/xen/xen_hypervisor.c | 1 + src/xen/xen_inotify.c | 1 + src/xen/xend_internal.c | 1 + src/xen/xm_internal.c | 1 + src/xen/xs_internal.c | 1 + src/xenapi/xenapi_driver.c | 1 + tools/virsh.c | 35 +++++++++++++++++++++++++++ tools/virsh.pod | 4 +++ 39 files changed, 321 insertions(+), 2 deletions(-) -- 1.7.4

On 04/21/2011 02:42 PM, Lai Jiangshan wrote:
This patch series implements a feature of injecting NMI to guest, which is accessible via new virDomainInjectNMI API and 'inject-nmi' command in virsh.
Lai Jiangshan (6): inject-nmi: Defining the public API inject-nmi: Defining the internal API inject-nmi: Implementing the public API inject-nmi: Implementing the remote protocol inject-nmi: Expose the new API in virsh qemu,inject-nmi: Implement the driver methods
Hi, Eric and Daniel: In qemu community, Luiz have accepted the inject-nmi patches, could you accept these patches for libvirt? Thanks, Lai.

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- include/libvirt/libvirt.h.in | 2 ++ src/libvirt_public.syms | 5 +++++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 5783303..0e1e27a 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2519,6 +2519,8 @@ int virDomainOpenConsole(virDomainPtr dom, virStreamPtr st, unsigned int flags); +int virDomainInjectNMI(virDomainPtr domain, unsigned int flags); + #ifdef __cplusplus } #endif diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index b4aed41..f5bbc01 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -436,4 +436,9 @@ LIBVIRT_0.9.0 { virStorageVolUpload; } LIBVIRT_0.8.8; +LIBVIRT_0.9.1 { + global: + virDomainInjectNMI; +} LIBVIRT_0.9.0; + # .... define new API here using predicted next version number .... -- 1.7.4

On Thu, Apr 21, 2011 at 02:42:52PM +0800, Lai Jiangshan wrote:
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- include/libvirt/libvirt.h.in | 2 ++ src/libvirt_public.syms | 5 +++++ 2 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 5783303..0e1e27a 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2519,6 +2519,8 @@ int virDomainOpenConsole(virDomainPtr dom, virStreamPtr st, unsigned int flags);
+int virDomainInjectNMI(virDomainPtr domain, unsigned int flags); + #ifdef __cplusplus } #endif diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index b4aed41..f5bbc01 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -436,4 +436,9 @@ LIBVIRT_0.9.0 { virStorageVolUpload; } LIBVIRT_0.8.8;
+LIBVIRT_0.9.1 { + global: + virDomainInjectNMI; +} LIBVIRT_0.9.0; + # .... define new API here using predicted next version number ....
ACK, but we need to remember to change 0.9.1 to 0.9.2 when applying Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- src/driver.h | 4 ++++ src/esx/esx_driver.c | 1 + src/libxl/libxl_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 3 ++- src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/vmware/vmware_driver.c | 1 + src/xen/xen_driver.c | 1 + src/xen/xen_driver.h | 1 + src/xen/xen_hypervisor.c | 1 + src/xen/xen_inotify.c | 1 + src/xen/xend_internal.c | 1 + src/xen/xm_internal.c | 1 + src/xen/xs_internal.c | 1 + src/xenapi/xenapi_driver.c | 1 + 20 files changed, 24 insertions(+), 1 deletions(-) diff --git a/src/driver.h b/src/driver.h index a8b79e6..94cc37d 100644 --- a/src/driver.h +++ b/src/driver.h @@ -515,6 +515,9 @@ typedef int virStreamPtr st, unsigned int flags); +typedef int + (*virDrvDomainInjectNMI)(virDomainPtr dom, unsigned int flags); + /** * _virDriver: @@ -639,6 +642,7 @@ struct _virDriver { virDrvDomainSnapshotDelete domainSnapshotDelete; virDrvQemuDomainMonitorCommand qemuDomainMonitorCommand; virDrvDomainOpenConsole domainOpenConsole; + virDrvDomainInjectNMI domainInjectNMI; }; typedef int diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 50c631b..5b9edea 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -4672,6 +4672,7 @@ static virDriver esxDriver = { esxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 247d78e..bc6d0d9 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -2748,6 +2748,7 @@ static virDriver libxlDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virStateDriver libxlStateDriver = { diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index e905302..fbbe803 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2906,6 +2906,7 @@ static virDriver lxcDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ lxcDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virStateDriver lxcStateDriver = { diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 4af28e9..96f82bb 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1667,6 +1667,7 @@ static virDriver openvzDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; int openvzRegister(void) { diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index bb0e0ac..33848ff 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -3794,7 +3794,8 @@ static virDriver phypDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuMonitorCommand */ - NULL, /* domainOpenConsole */ + NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virStorageDriver phypStorageDriver = { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f6e503a..ac1adbb 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7031,6 +7031,7 @@ static virDriver qemuDriver = { qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ qemuDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index e30780c..4655338 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -11298,6 +11298,7 @@ static virDriver remote_driver = { remoteDomainSnapshotDelete, /* domainSnapshotDelete */ remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ remoteDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virNetworkDriver network_driver = { diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 0978214..f3df6a5 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5447,6 +5447,7 @@ static virDriver testDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virNetworkDriver testNetworkDriver = { diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 33849a0..73a5415 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2253,6 +2253,7 @@ static virDriver umlDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ umlDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static int diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 8241d34..6d3f533 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -8652,6 +8652,7 @@ virDriver NAME(Driver) = { vboxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; virNetworkDriver NAME(NetworkDriver) = { diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index bbfb1a4..0bf3bb5 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -1007,6 +1007,7 @@ static virDriver vmwareDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; int diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 2a07b7b..4b29c01 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -2141,6 +2141,7 @@ static virDriver xenUnifiedDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ xenUnifiedDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; /** diff --git a/src/xen/xen_driver.h b/src/xen/xen_driver.h index 58b8561..7cc363c 100644 --- a/src/xen/xen_driver.h +++ b/src/xen/xen_driver.h @@ -108,6 +108,7 @@ struct xenUnifiedDriver { virDrvDomainGetSchedulerType domainGetSchedulerType; virDrvDomainGetSchedulerParameters domainGetSchedulerParameters; virDrvDomainSetSchedulerParameters domainSetSchedulerParameters; + virDrvDomainInjectNMI domainInjectNMI; }; typedef struct xenXMConfCache *xenXMConfCachePtr; diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index 9a5b41d..959e949 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -839,6 +839,7 @@ struct xenUnifiedDriver xenHypervisorDriver = { xenHypervisorGetSchedulerType, /* domainGetSchedulerType */ xenHypervisorGetSchedulerParameters, /* domainGetSchedulerParameters */ xenHypervisorSetSchedulerParameters, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; #define virXenError(code, ...) \ diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index d809c45..a586438 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -87,6 +87,7 @@ struct xenUnifiedDriver xenInotifyDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; static int diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index b608a43..0b4432f 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -3879,6 +3879,7 @@ struct xenUnifiedDriver xenDaemonDriver = { xenDaemonGetSchedulerType, /* domainGetSchedulerType */ xenDaemonGetSchedulerParameters, /* domainGetSchedulerParameters */ xenDaemonSetSchedulerParameters, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index db47a02..9ae7d61 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -118,6 +118,7 @@ struct xenUnifiedDriver xenXMDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; #define xenXMError(code, ...) \ diff --git a/src/xen/xs_internal.c b/src/xen/xs_internal.c index c318f6c..858a321 100644 --- a/src/xen/xs_internal.c +++ b/src/xen/xs_internal.c @@ -80,6 +80,7 @@ struct xenUnifiedDriver xenStoreDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; #define virXenStoreError(code, ...) \ diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 3fbdcc6..030510c 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -1889,6 +1889,7 @@ static virDriver xenapiDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; /** -- 1.7.4

On Thu, Apr 21, 2011 at 02:42:55PM +0800, Lai Jiangshan wrote:
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- src/driver.h | 4 ++++ src/esx/esx_driver.c | 1 + src/libxl/libxl_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 3 ++- src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/vmware/vmware_driver.c | 1 + src/xen/xen_driver.c | 1 + src/xen/xen_driver.h | 1 + src/xen/xen_hypervisor.c | 1 + src/xen/xen_inotify.c | 1 + src/xen/xend_internal.c | 1 + src/xen/xm_internal.c | 1 + src/xen/xs_internal.c | 1 + src/xenapi/xenapi_driver.c | 1 + 20 files changed, 24 insertions(+), 1 deletions(-)
Trivial ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- src/libvirt.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index 9e6784b..32446d1 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -5214,6 +5214,50 @@ error: } /** + * virDomainInjectNMI: + * @domain: pointer to domain object, or NULL for Domain0 + * @flags: the flags for controlling behaviours + * + * Send NMI to the guest + * + * Returns 0 in case of success, -1 in case of failure. + */ + +int virDomainInjectNMI(virDomainPtr domain, unsigned int flags) +{ + virConnectPtr conn; + VIR_DOMAIN_DEBUG(domain, "flags=%u", flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return (-1); + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + conn = domain->conn; + + if (conn->driver->domainInjectNMI) { + int ret; + ret = conn->driver->domainInjectNMI(domain, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + +/** * virDomainSetVcpus: * @domain: pointer to domain object, or NULL for Domain0 * @nvcpus: the new number of virtual CPUs for this domain -- 1.7.4

On Thu, Apr 21, 2011 at 02:42:58PM +0800, Lai Jiangshan wrote:
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- src/libvirt.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/src/libvirt.c b/src/libvirt.c index 9e6784b..32446d1 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -5214,6 +5214,50 @@ error: }
/** + * virDomainInjectNMI: + * @domain: pointer to domain object, or NULL for Domain0 + * @flags: the flags for controlling behaviours + * + * Send NMI to the guest + * + * Returns 0 in case of success, -1 in case of failure. + */ + +int virDomainInjectNMI(virDomainPtr domain, unsigned int flags) +{ + virConnectPtr conn; + VIR_DOMAIN_DEBUG(domain, "flags=%u", flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return (-1); + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + conn = domain->conn; + + if (conn->driver->domainInjectNMI) { + int ret; + ret = conn->driver->domainInjectNMI(domain, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + +/** * virDomainSetVcpus: * @domain: pointer to domain object, or NULL for Domain0 * @nvcpus: the new number of virtual CPUs for this domain
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- daemon/remote.c | 28 ++++++++++++++++++++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 ++++++++ daemon/remote_dispatch_table.h | 5 +++++ src/remote/remote_driver.c | 26 +++++++++++++++++++++++++- src/remote/remote_protocol.c | 11 +++++++++++ src/remote/remote_protocol.h | 10 ++++++++++ src/remote/remote_protocol.x | 8 +++++++- src/remote_protocol-structs | 4 ++++ 9 files changed, 99 insertions(+), 2 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 54fef64..9ae232e 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -3288,6 +3288,34 @@ no_memory: } static int +remoteDispatchDomainInjectNmi(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *rerr, + remote_domain_inject_nmi_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virDomainPtr dom; + int rv = -1; + + if (!(dom = get_nonnull_domain(conn, args->dom))) + goto cleanup; + + if (virDomainInjectNMI(dom, args->flags) == -1) + goto cleanup; + + rv = 0; + +cleanup: + if (rv < 0) + remoteDispatchError(rerr); + if (dom) + virDomainFree(dom); + return rv; +} + +static int remoteDispatchDomainSetVcpus(struct qemud_server *server ATTRIBUTE_UNUSED, struct qemud_client *client ATTRIBUTE_UNUSED, virConnectPtr conn, diff --git a/daemon/remote_dispatch_args.h b/daemon/remote_dispatch_args.h index f9537d7..4887d7c 100644 --- a/daemon/remote_dispatch_args.h +++ b/daemon/remote_dispatch_args.h @@ -178,3 +178,4 @@ remote_domain_migrate_set_max_speed_args val_remote_domain_migrate_set_max_speed_args; remote_storage_vol_upload_args val_remote_storage_vol_upload_args; remote_storage_vol_download_args val_remote_storage_vol_download_args; + remote_domain_inject_nmi_args val_remote_domain_inject_nmi_args; diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h index 18bf41d..3de6046 100644 --- a/daemon/remote_dispatch_prototypes.h +++ b/daemon/remote_dispatch_prototypes.h @@ -338,6 +338,14 @@ static int remoteDispatchDomainHasManagedSaveImage( remote_error *err, remote_domain_has_managed_save_image_args *args, remote_domain_has_managed_save_image_ret *ret); +static int remoteDispatchDomainInjectNmi( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + remote_domain_inject_nmi_args *args, + void *ret); static int remoteDispatchDomainInterfaceStats( struct qemud_server *server, struct qemud_client *client, diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index b39f7c2..dacafdb 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -1052,3 +1052,8 @@ .args_filter = (xdrproc_t) xdr_remote_storage_vol_download_args, .ret_filter = (xdrproc_t) xdr_void, }, +{ /* DomainInjectNmi => 210 */ + .fn = (dispatch_fn) remoteDispatchDomainInjectNmi, + .args_filter = (xdrproc_t) xdr_remote_domain_inject_nmi_args, + .ret_filter = (xdrproc_t) xdr_void, +}, diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 4655338..58eb682 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2933,6 +2933,30 @@ done: } static int +remoteDomainInjectNMI(virDomainPtr domain, unsigned int flags) +{ + int rv = -1; + remote_domain_inject_nmi_args args; + struct private_data *priv = domain->conn->privateData; + + remoteDriverLock(priv); + + make_nonnull_domain (&args.dom, domain); + args.flags = flags; + + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_INJECT_NMI, + (xdrproc_t) xdr_remote_domain_inject_nmi_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + goto done; + + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; +} + +static int remoteDomainSetVcpus (virDomainPtr domain, unsigned int nvcpus) { int rv = -1; @@ -11298,7 +11322,7 @@ static virDriver remote_driver = { remoteDomainSnapshotDelete, /* domainSnapshotDelete */ remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ remoteDomainOpenConsole, /* domainOpenConsole */ - NULL, /* domainInjectNMI */ + remoteDomainInjectNMI, /* domainInjectNMI */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 5604371..3ff0b1f 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -1463,6 +1463,17 @@ xdr_remote_domain_undefine_args (XDR *xdrs, remote_domain_undefine_args *objp) } bool_t +xdr_remote_domain_inject_nmi_args (XDR *xdrs, remote_domain_inject_nmi_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_domain_set_vcpus_args (XDR *xdrs, remote_domain_set_vcpus_args *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index d9bf151..4da003e 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -2200,6 +2200,13 @@ struct remote_storage_vol_download_args { u_int flags; }; typedef struct remote_storage_vol_download_args remote_storage_vol_download_args; + +struct remote_domain_inject_nmi_args { + remote_nonnull_domain dom; + u_int flags; +}; +typedef struct remote_domain_inject_nmi_args remote_domain_inject_nmi_args; + #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1 @@ -2413,6 +2420,7 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, + REMOTE_PROC_DOMAIN_INJECT_NMI = 210, }; typedef enum remote_procedure remote_procedure; @@ -2561,6 +2569,7 @@ extern bool_t xdr_remote_domain_create_with_flags_ret (XDR *, remote_domain_cre extern bool_t xdr_remote_domain_define_xml_args (XDR *, remote_domain_define_xml_args*); extern bool_t xdr_remote_domain_define_xml_ret (XDR *, remote_domain_define_xml_ret*); extern bool_t xdr_remote_domain_undefine_args (XDR *, remote_domain_undefine_args*); +extern bool_t xdr_remote_domain_inject_nmi_args (XDR *, remote_domain_inject_nmi_args*); extern bool_t xdr_remote_domain_set_vcpus_args (XDR *, remote_domain_set_vcpus_args*); extern bool_t xdr_remote_domain_set_vcpus_flags_args (XDR *, remote_domain_set_vcpus_flags_args*); extern bool_t xdr_remote_domain_get_vcpus_flags_args (XDR *, remote_domain_get_vcpus_flags_args*); @@ -2918,6 +2927,7 @@ extern bool_t xdr_remote_domain_create_with_flags_ret (); extern bool_t xdr_remote_domain_define_xml_args (); extern bool_t xdr_remote_domain_define_xml_ret (); extern bool_t xdr_remote_domain_undefine_args (); +extern bool_t xdr_remote_domain_inject_nmi_args (); extern bool_t xdr_remote_domain_set_vcpus_args (); extern bool_t xdr_remote_domain_set_vcpus_flags_args (); extern bool_t xdr_remote_domain_get_vcpus_flags_args (); diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 675eccd..1aacf99 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -817,6 +817,11 @@ struct remote_domain_undefine_args { remote_nonnull_domain dom; }; +struct remote_domain_inject_nmi_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + struct remote_domain_set_vcpus_args { remote_nonnull_domain dom; int nvcpus; @@ -2176,8 +2181,9 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_BLKIO_PARAMETERS = 206, REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, - REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209 + REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, + REMOTE_PROC_DOMAIN_INJECT_NMI = 210, /* * Notice how the entries are grouped in sets of 10 ? * Nice isn't it. Please keep it this way when adding more. diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 944553c..4b75e33 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1435,3 +1435,7 @@ struct remote_message_header { u_int serial; remote_message_status status; }; +struct remote_domain_inject_nmi_args { + remote_nonnull_domain dom; + unsigned int flags; +}; -- 1.7.4

On Thu, Apr 21, 2011 at 02:43:01PM +0800, Lai Jiangshan wrote:
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- daemon/remote.c | 28 ++++++++++++++++++++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 ++++++++ daemon/remote_dispatch_table.h | 5 +++++ src/remote/remote_driver.c | 26 +++++++++++++++++++++++++- src/remote/remote_protocol.c | 11 +++++++++++ src/remote/remote_protocol.h | 10 ++++++++++
All these changes can be deleted, since Matthias' RPC generator code will trivially cope with virDomainInjectNMI.
src/remote/remote_protocol.x | 8 +++++++- src/remote_protocol-structs | 4 ++++ 9 files changed, 99 insertions(+), 2 deletions(-)
So want these two files only in GIT.
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 675eccd..1aacf99 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -817,6 +817,11 @@ struct remote_domain_undefine_args { remote_nonnull_domain dom; };
+struct remote_domain_inject_nmi_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + struct remote_domain_set_vcpus_args { remote_nonnull_domain dom; int nvcpus; @@ -2176,8 +2181,9 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_BLKIO_PARAMETERS = 206, REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, - REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209 + REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209,
+ REMOTE_PROC_DOMAIN_INJECT_NMI = 210, /* * Notice how the entries are grouped in sets of 10 ? * Nice isn't it. Please keep it this way when adding more. diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 944553c..4b75e33 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1435,3 +1435,7 @@ struct remote_message_header { u_int serial; remote_message_status status; }; +struct remote_domain_inject_nmi_args { + remote_nonnull_domain dom; + unsigned int flags; +};
ACK to these parts Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- tools/virsh.c | 35 +++++++++++++++++++++++++++++++++++ tools/virsh.pod | 4 ++++ 2 files changed, 39 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 9ac27b3..54fd6bf 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2912,6 +2912,40 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd) } /* + * "inject-nmi" command + */ +static const vshCmdInfo info_inject_nmi[] = { + {"help", N_("Inject NMI to the guest")}, + {"desc", N_("Inject NMI to the guest domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_inject_nmi[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + + +static bool +cmdInjectNMI(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int ret = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (virDomainInjectNMI(dom, 0) < 0) + ret = false; + + virDomainFree(dom); + return ret; +} + +/* * "setmemory" command */ static const vshCmdInfo info_setmem[] = { @@ -10730,6 +10764,7 @@ static const vshCmdDef domManagementCmds[] = { {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem}, {"setmem", cmdSetmem, opts_setmem, info_setmem}, {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus}, + {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi}, {"shutdown", cmdShutdown, opts_shutdown, info_shutdown}, {"start", cmdStart, opts_start, info_start}, {"suspend", cmdSuspend, opts_suspend, info_suspend}, diff --git a/tools/virsh.pod b/tools/virsh.pod index 2a708f6..f317c57 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -290,6 +290,10 @@ running B<virsh suspend>. When in a paused state the domain will still consume allocated resources like memory, but will not be eligible for scheduling by the hypervisor. +=item B<inject-nmi> I<domain-id> + +Inject NMI to the guest + =item B<shutdown> The domain is in the process of shutting down, i.e. the guest operating system -- 1.7.4

On Thu, Apr 21, 2011 at 02:43:04PM +0800, Lai Jiangshan wrote:
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- tools/virsh.c | 35 +++++++++++++++++++++++++++++++++++ tools/virsh.pod | 4 ++++ 2 files changed, 39 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c index 9ac27b3..54fd6bf 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2912,6 +2912,40 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd) }
/* + * "inject-nmi" command + */ +static const vshCmdInfo info_inject_nmi[] = { + {"help", N_("Inject NMI to the guest")}, + {"desc", N_("Inject NMI to the guest domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_inject_nmi[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + + +static bool +cmdInjectNMI(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int ret = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (virDomainInjectNMI(dom, 0) < 0) + ret = false; + + virDomainFree(dom); + return ret; +} + +/* * "setmemory" command */ static const vshCmdInfo info_setmem[] = { @@ -10730,6 +10764,7 @@ static const vshCmdDef domManagementCmds[] = { {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem}, {"setmem", cmdSetmem, opts_setmem, info_setmem}, {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus}, + {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi}, {"shutdown", cmdShutdown, opts_shutdown, info_shutdown}, {"start", cmdStart, opts_start, info_start}, {"suspend", cmdSuspend, opts_suspend, info_suspend}, diff --git a/tools/virsh.pod b/tools/virsh.pod index 2a708f6..f317c57 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -290,6 +290,10 @@ running B<virsh suspend>. When in a paused state the domain will still consume allocated resources like memory, but will not be eligible for scheduling by the hypervisor.
+=item B<inject-nmi> I<domain-id> + +Inject NMI to the guest + =item B<shutdown>
The domain is in the process of shutting down, i.e. the guest operating system
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- src/qemu/qemu_driver.c | 46 +++++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_monitor.c | 14 ++++++++++++ src/qemu/qemu_monitor.h | 2 + src/qemu/qemu_monitor_json.c | 27 ++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 1 + src/qemu/qemu_monitor_text.c | 20 ++++++++++++++++++ src/qemu/qemu_monitor_text.h | 1 + 7 files changed, 110 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ac1adbb..548e657 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1702,6 +1702,50 @@ static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long memory) return qemudDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM); } +static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags) +{ + struct qemud_driver *driver = domain->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + qemuDomainObjPrivatePtr priv; + + virCheckFlags(0, -1); + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, domain->uuid); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(domain->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) + goto cleanup; + qemuDomainObjEnterMonitorWithDriver(driver, vm); + ret = qemuMonitorInjectNMI(priv->mon); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (qemuDomainObjEndJob(vm) == 0) { + vm = NULL; + goto cleanup; + } + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + static int qemudDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { @@ -7031,7 +7075,7 @@ static virDriver qemuDriver = { qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ qemuDomainOpenConsole, /* domainOpenConsole */ - NULL, /* domainInjectNMI */ + qemuDomainInjectNMI, /* domainInjectNMI */ }; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 2d28f8d..5ed41e1 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2228,3 +2228,17 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, ret = qemuMonitorTextArbitraryCommand(mon, cmd, reply); return ret; } + + +int qemuMonitorInjectNMI(qemuMonitorPtr mon) +{ + int ret; + + VIR_DEBUG("mon=%p", mon); + + if (mon->json) + ret = qemuMonitorJSONInjectNMI(mon); + else + ret = qemuMonitorTextInjectNMI(mon); + return ret; +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c90219b..b84e230 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -423,6 +423,8 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, char **reply, bool hmp); +int qemuMonitorInjectNMI(qemuMonitorPtr mon); + /** * When running two dd process and using <> redirection, we need a * shell that will not truncate files. These two strings serve that diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 20a78e1..04ef077 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2513,3 +2513,30 @@ cleanup: return ret; } + +int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon) +{ + int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("inject-nmi", NULL); + if (!cmd) + return -1; + + if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0) + goto cleanup; + + if (qemuMonitorJSONHasError(reply, "CommandNotFound") && + qemuMonitorCheckHMP(mon, "inject-nmi")) { + VIR_DEBUG0("inject-nmi command not found, trying HMP"); + ret = qemuMonitorTextInjectNMI(mon); + } else { + ret = qemuMonitorJSONCheckError(cmd, reply); + } + +cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 086f0e1..f2dc4d2 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -204,4 +204,5 @@ int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, char **reply_str, bool hmp); +int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon); #endif /* QEMU_MONITOR_JSON_H */ diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 53781c8..2ce871c 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -2628,3 +2628,23 @@ int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd, return ret; } + +int qemuMonitorTextInjectNMI(qemuMonitorPtr mon) +{ + const char *cmd = "nmi 0"; + char *reply = NULL; + + /* + * FIXME: qemu's inject-nmi command is not introduced until qemu-0.15, + * use "nmi 0" instead temporary. + */ + if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) { + qemuReportError(VIR_ERR_OPERATION_FAILED, + _("failed to inject NMI using command '%s'"), + cmd); + return -1; + } + + VIR_FREE(reply); + return 0; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 0838a2b..dbae72b 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -198,4 +198,5 @@ int qemuMonitorTextDeleteSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply); +int qemuMonitorTextInjectNMI(qemuMonitorPtr mon); #endif /* QEMU_MONITOR_TEXT_H */ -- 1.7.4

On Thu, Apr 21, 2011 at 02:43:07PM +0800, Lai Jiangshan wrote:
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- src/qemu/qemu_driver.c | 46 +++++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_monitor.c | 14 ++++++++++++ src/qemu/qemu_monitor.h | 2 + src/qemu/qemu_monitor_json.c | 27 ++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 1 + src/qemu/qemu_monitor_text.c | 20 ++++++++++++++++++ src/qemu/qemu_monitor_text.h | 1 + 7 files changed, 110 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ac1adbb..548e657 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1702,6 +1702,50 @@ static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long memory) return qemudDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM); }
+static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags) +{ + struct qemud_driver *driver = domain->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + qemuDomainObjPrivatePtr priv; + + virCheckFlags(0, -1); + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, domain->uuid); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(domain->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) + goto cleanup; + qemuDomainObjEnterMonitorWithDriver(driver, vm); + ret = qemuMonitorInjectNMI(priv->mon); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (qemuDomainObjEndJob(vm) == 0) { + vm = NULL; + goto cleanup; + } + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + static int qemudDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { @@ -7031,7 +7075,7 @@ static virDriver qemuDriver = { qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ qemuDomainOpenConsole, /* domainOpenConsole */ - NULL, /* domainInjectNMI */ + qemuDomainInjectNMI, /* domainInjectNMI */ };
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 2d28f8d..5ed41e1 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2228,3 +2228,17 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, ret = qemuMonitorTextArbitraryCommand(mon, cmd, reply); return ret; } + + +int qemuMonitorInjectNMI(qemuMonitorPtr mon) +{ + int ret; + + VIR_DEBUG("mon=%p", mon); + + if (mon->json) + ret = qemuMonitorJSONInjectNMI(mon); + else + ret = qemuMonitorTextInjectNMI(mon); + return ret; +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c90219b..b84e230 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -423,6 +423,8 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, char **reply, bool hmp);
+int qemuMonitorInjectNMI(qemuMonitorPtr mon); + /** * When running two dd process and using <> redirection, we need a * shell that will not truncate files. These two strings serve that diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 20a78e1..04ef077 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2513,3 +2513,30 @@ cleanup:
return ret; } + +int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon) +{ + int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("inject-nmi", NULL); + if (!cmd) + return -1; + + if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0) + goto cleanup; + + if (qemuMonitorJSONHasError(reply, "CommandNotFound") && + qemuMonitorCheckHMP(mon, "inject-nmi")) { + VIR_DEBUG0("inject-nmi command not found, trying HMP"); + ret = qemuMonitorTextInjectNMI(mon); + } else { + ret = qemuMonitorJSONCheckError(cmd, reply); + } + +cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 086f0e1..f2dc4d2 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -204,4 +204,5 @@ int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, char **reply_str, bool hmp);
+int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon); #endif /* QEMU_MONITOR_JSON_H */ diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 53781c8..2ce871c 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -2628,3 +2628,23 @@ int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd,
return ret; } + +int qemuMonitorTextInjectNMI(qemuMonitorPtr mon) +{ + const char *cmd = "nmi 0"; + char *reply = NULL; + + /* + * FIXME: qemu's inject-nmi command is not introduced until qemu-0.15, + * use "nmi 0" instead temporary. + */
So in future if we need to support NMI in non-JSON mode, we'd want to run 'inject-nmi' in HMP, and then check for 'unknown command', and fallback to 'nmi'.
+ if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) { + qemuReportError(VIR_ERR_OPERATION_FAILED, + _("failed to inject NMI using command '%s'"), + cmd); + return -1; + } + + VIR_FREE(reply); + return 0; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 0838a2b..dbae72b 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -198,4 +198,5 @@ int qemuMonitorTextDeleteSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply);
+int qemuMonitorTextInjectNMI(qemuMonitorPtr mon); #endif /* QEMU_MONITOR_TEXT_H */
ACK, since the only issue can be dealt with later Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

This patch series implements a feature of injecting NMI to guest, which is accessible via new virDomainInjectNMI API and 'inject-nmi' command in virsh. Lai Jiangshan (6): inject-nmi: Defining the public API inject-nmi: Defining the internal API inject-nmi: Implementing the public API inject-nmi: Implementing the remote protocol inject-nmi: Expose the new API in virsh qemu,inject-nmi: Implement the driver methods daemon/remote_generator.pl | 2 +- include/libvirt/libvirt.h.in | 2 + src/driver.h | 4 +++ src/esx/esx_driver.c | 1 + src/libvirt.c | 44 +++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++++ src/libxl/libxl_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 3 +- src/qemu/qemu_driver.c | 45 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 14 +++++++++++++ src/qemu/qemu_monitor.h | 2 + src/qemu/qemu_monitor_json.c | 27 +++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 1 + src/qemu/qemu_monitor_text.c | 28 ++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 1 + src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 8 ++++++- src/remote_protocol-structs | 4 +++ src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/vmware/vmware_driver.c | 1 + src/xen/xen_driver.c | 1 + src/xen/xen_driver.h | 1 + src/xen/xen_hypervisor.c | 1 + src/xen/xen_inotify.c | 1 + src/xen/xend_internal.c | 1 + src/xen/xm_internal.c | 1 + src/xen/xs_internal.c | 1 + src/xenapi/xenapi_driver.c | 1 + tools/virsh.c | 35 ++++++++++++++++++++++++++++++++ tools/virsh.pod | 4 +++ 34 files changed, 243 insertions(+), 3 deletions(-) -- 1.7.4.4

--- include/libvirt/libvirt.h.in | 2 ++ src/libvirt_public.syms | 5 +++++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 5783303..0e1e27a 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2519,6 +2519,8 @@ int virDomainOpenConsole(virDomainPtr dom, virStreamPtr st, unsigned int flags); +int virDomainInjectNMI(virDomainPtr domain, unsigned int flags); + #ifdef __cplusplus } #endif diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index b4aed41..ababf39 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -436,4 +436,9 @@ LIBVIRT_0.9.0 { virStorageVolUpload; } LIBVIRT_0.8.8; +LIBVIRT_0.9.2 { + global: + virDomainInjectNMI; +} LIBVIRT_0.9.0; + # .... define new API here using predicted next version number .... -- 1.7.4.4

--- src/driver.h | 4 ++++ src/esx/esx_driver.c | 1 + src/libxl/libxl_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 3 ++- src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/vmware/vmware_driver.c | 1 + src/xen/xen_driver.c | 1 + src/xen/xen_driver.h | 1 + src/xen/xen_hypervisor.c | 1 + src/xen/xen_inotify.c | 1 + src/xen/xend_internal.c | 1 + src/xen/xm_internal.c | 1 + src/xen/xs_internal.c | 1 + src/xenapi/xenapi_driver.c | 1 + 20 files changed, 24 insertions(+), 1 deletions(-) diff --git a/src/driver.h b/src/driver.h index a8b79e6..94cc37d 100644 --- a/src/driver.h +++ b/src/driver.h @@ -515,6 +515,9 @@ typedef int virStreamPtr st, unsigned int flags); +typedef int + (*virDrvDomainInjectNMI)(virDomainPtr dom, unsigned int flags); + /** * _virDriver: @@ -639,6 +642,7 @@ struct _virDriver { virDrvDomainSnapshotDelete domainSnapshotDelete; virDrvQemuDomainMonitorCommand qemuDomainMonitorCommand; virDrvDomainOpenConsole domainOpenConsole; + virDrvDomainInjectNMI domainInjectNMI; }; typedef int diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 7933f11..66b70ef 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -4699,6 +4699,7 @@ static virDriver esxDriver = { esxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index a2c8467..b662e52 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -2790,6 +2790,7 @@ static virDriver libxlDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virStateDriver libxlStateDriver = { diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index b94941d..b46e494 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2905,6 +2905,7 @@ static virDriver lxcDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ lxcDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virStateDriver lxcStateDriver = { diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 0bd007a..c2a119c 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1667,6 +1667,7 @@ static virDriver openvzDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; int openvzRegister(void) { diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 30d4adf..554e530 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -3827,7 +3827,8 @@ static virDriver phypDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuMonitorCommand */ - NULL, /* domainOpenConsole */ + NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virStorageDriver phypStorageDriver = { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0fd0f10..fa4a2bd 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7192,6 +7192,7 @@ static virDriver qemuDriver = { qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ qemuDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index d076a90..c6beb3d 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -6493,6 +6493,7 @@ static virDriver remote_driver = { remoteDomainSnapshotDelete, /* domainSnapshotDelete */ remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ remoteDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virNetworkDriver network_driver = { diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 0978214..f3df6a5 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5447,6 +5447,7 @@ static virDriver testDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static virNetworkDriver testNetworkDriver = { diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 33849a0..73a5415 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2253,6 +2253,7 @@ static virDriver umlDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ umlDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; static int diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 8241d34..6d3f533 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -8652,6 +8652,7 @@ virDriver NAME(Driver) = { vboxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; virNetworkDriver NAME(NetworkDriver) = { diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index bbfb1a4..0bf3bb5 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -1007,6 +1007,7 @@ static virDriver vmwareDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; int diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index dd94fbc..f4cd63a 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -2208,6 +2208,7 @@ static virDriver xenUnifiedDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ xenUnifiedDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; /** diff --git a/src/xen/xen_driver.h b/src/xen/xen_driver.h index 58b8561..7cc363c 100644 --- a/src/xen/xen_driver.h +++ b/src/xen/xen_driver.h @@ -108,6 +108,7 @@ struct xenUnifiedDriver { virDrvDomainGetSchedulerType domainGetSchedulerType; virDrvDomainGetSchedulerParameters domainGetSchedulerParameters; virDrvDomainSetSchedulerParameters domainSetSchedulerParameters; + virDrvDomainInjectNMI domainInjectNMI; }; typedef struct xenXMConfCache *xenXMConfCachePtr; diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index 9a5b41d..959e949 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -839,6 +839,7 @@ struct xenUnifiedDriver xenHypervisorDriver = { xenHypervisorGetSchedulerType, /* domainGetSchedulerType */ xenHypervisorGetSchedulerParameters, /* domainGetSchedulerParameters */ xenHypervisorSetSchedulerParameters, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; #define virXenError(code, ...) \ diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index 9dde72c..0e1b242 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -87,6 +87,7 @@ struct xenUnifiedDriver xenInotifyDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; static int diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index a4420d8..f8b5130 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -3879,6 +3879,7 @@ struct xenUnifiedDriver xenDaemonDriver = { xenDaemonGetSchedulerType, /* domainGetSchedulerType */ xenDaemonGetSchedulerParameters, /* domainGetSchedulerParameters */ xenDaemonSetSchedulerParameters, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index 07a0c0f..c471814 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -118,6 +118,7 @@ struct xenUnifiedDriver xenXMDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; #define xenXMError(code, ...) \ diff --git a/src/xen/xs_internal.c b/src/xen/xs_internal.c index c318f6c..858a321 100644 --- a/src/xen/xs_internal.c +++ b/src/xen/xs_internal.c @@ -80,6 +80,7 @@ struct xenUnifiedDriver xenStoreDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainInjectNMI */ }; #define virXenStoreError(code, ...) \ diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 3fbdcc6..030510c 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -1889,6 +1889,7 @@ static virDriver xenapiDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainInjectNMI */ }; /** -- 1.7.4.4

On 05/10/2011 02:26 AM, Lai Jiangshan wrote:
src/xen/xen_driver.c | 1 + src/xen/xen_driver.h | 1 +
No need to modify the xenUnified callback struct.
+++ b/src/xen/xen_driver.h @@ -108,6 +108,7 @@ struct xenUnifiedDriver { virDrvDomainGetSchedulerType domainGetSchedulerType; virDrvDomainGetSchedulerParameters domainGetSchedulerParameters; virDrvDomainSetSchedulerParameters domainSetSchedulerParameters; + virDrvDomainInjectNMI domainInjectNMI; };
So I trimmed this hunk, and the corresponding fallout from other xen files. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

--- src/libvirt.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index abacf85..f468b61 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -5217,6 +5217,50 @@ error: } /** + * virDomainInjectNMI: + * @domain: pointer to domain object, or NULL for Domain0 + * @flags: the flags for controlling behaviours + * + * Send NMI to the guest + * + * Returns 0 in case of success, -1 in case of failure. + */ + +int virDomainInjectNMI(virDomainPtr domain, unsigned int flags) +{ + virConnectPtr conn; + VIR_DOMAIN_DEBUG(domain, "flags=%u", flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return (-1); + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + conn = domain->conn; + + if (conn->driver->domainInjectNMI) { + int ret; + ret = conn->driver->domainInjectNMI(domain, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + +/** * virDomainSetVcpus: * @domain: pointer to domain object, or NULL for Domain0 * @nvcpus: the new number of virtual CPUs for this domain -- 1.7.4.4

On 05/10/2011 02:26 AM, Lai Jiangshan wrote:
--- src/libvirt.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/src/libvirt.c b/src/libvirt.c index abacf85..f468b61 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -5217,6 +5217,50 @@ error: }
/** + * virDomainInjectNMI: + * @domain: pointer to domain object, or NULL for Domain0 + * @flags: the flags for controlling behaviours
s/behaviours/behavior, pass 0 for now/
+ if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return (-1);
No need for extra () on return. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

--- daemon/remote_generator.pl | 2 +- src/remote/remote_driver.c | 2 +- src/remote/remote_protocol.x | 8 +++++++- src/remote_protocol-structs | 4 ++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl index 062ccc1..74fa769 100755 --- a/daemon/remote_generator.pl +++ b/daemon/remote_generator.pl @@ -35,7 +35,7 @@ sub name_to_ProcName { @elems = map { $_ =~ s/Nwfilter/NWFilter/; $_ =~ s/Xml/XML/; $_ =~ s/Uri/URI/; $_ =~ s/Uuid/UUID/; $_ =~ s/Id/ID/; $_ =~ s/Mac/MAC/; $_ =~ s/Cpu/CPU/; $_ =~ s/Os/OS/; - $_ } @elems; + $_ =~ s/Nmi/NMI/; $_ } @elems; join "", @elems } diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index c6beb3d..0a1afde 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -6493,7 +6493,7 @@ static virDriver remote_driver = { remoteDomainSnapshotDelete, /* domainSnapshotDelete */ remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ remoteDomainOpenConsole, /* domainOpenConsole */ - NULL, /* domainInjectNMI */ + remoteDomainInjectNMI, /* domainInjectNMI */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index c706c36..cdb8369 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -817,6 +817,11 @@ struct remote_domain_undefine_args { remote_nonnull_domain dom; }; +struct remote_domain_inject_nmi_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + struct remote_domain_set_vcpus_args { remote_nonnull_domain dom; int nvcpus; @@ -2176,7 +2181,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_BLKIO_PARAMETERS = 206, REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, - REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209 + REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, + REMOTE_PROC_DOMAIN_INJECT_NMI = 210 /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index f904c4d..8a5ade0 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1435,3 +1435,7 @@ struct remote_message_header { u_int serial; remote_message_status status; }; +struct remote_domain_inject_nmi_args { + remote_nonnull_domain dom; + unsigned int flags; +}; -- 1.7.4.4

On 05/10/2011 02:26 AM, Lai Jiangshan wrote:
--- daemon/remote_generator.pl | 2 +- src/remote/remote_driver.c | 2 +- src/remote/remote_protocol.x | 8 +++++++- src/remote_protocol-structs | 4 ++++ 4 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl index 062ccc1..74fa769 100755 --- a/daemon/remote_generator.pl +++ b/daemon/remote_generator.pl @@ -35,7 +35,7 @@ sub name_to_ProcName { @elems = map { $_ =~ s/Nwfilter/NWFilter/; $_ =~ s/Xml/XML/; $_ =~ s/Uri/URI/; $_ =~ s/Uuid/UUID/; $_ =~ s/Id/ID/; $_ =~ s/Mac/MAC/; $_ =~ s/Cpu/CPU/; $_ =~ s/Os/OS/; - $_ } @elems; + $_ =~ s/Nmi/NMI/; $_ } @elems;
Do we really want yet another difference in spelling? But cleaning that up affects more than just your new API, so I'll leave it for a later patch.
+++ b/src/remote/remote_protocol.x @@ -817,6 +817,11 @@ struct remote_domain_undefine_args { remote_nonnull_domain dom; };
+struct remote_domain_inject_nmi_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + struct remote_domain_set_vcpus_args {
This file layout...
+++ b/src/remote_protocol-structs @@ -1435,3 +1435,7 @@ struct remote_message_header { u_int serial; remote_message_status status; }; +struct remote_domain_inject_nmi_args { + remote_nonnull_domain dom; + unsigned int flags; +};
didn't match this layout - I had to adjust the structs to come in the same order. On Fedora, if you install the 'dwarves' package, then 'make check' would catch this for you. Also, dwarves settles on u_int rather than unsigned int. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

2011/5/10 Eric Blake <eblake@redhat.com>:
On 05/10/2011 02:26 AM, Lai Jiangshan wrote:
--- daemon/remote_generator.pl | 2 +- src/remote/remote_driver.c | 2 +- src/remote/remote_protocol.x | 8 +++++++- src/remote_protocol-structs | 4 ++++ 4 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl index 062ccc1..74fa769 100755 --- a/daemon/remote_generator.pl +++ b/daemon/remote_generator.pl @@ -35,7 +35,7 @@ sub name_to_ProcName { @elems = map { $_ =~ s/Nwfilter/NWFilter/; $_ =~ s/Xml/XML/; $_ =~ s/Uri/URI/; $_ =~ s/Uuid/UUID/; $_ =~ s/Id/ID/; $_ =~ s/Mac/MAC/; $_ =~ s/Cpu/CPU/; $_ =~ s/Os/OS/; - $_ } @elems; + $_ =~ s/Nmi/NMI/; $_ } @elems;
Do we really want yet another difference in spelling? But cleaning that up affects more than just your new API, so I'll leave it for a later patch.
Actually the problem is different here. name_to_ProcName takes the procedure name (that is all uppercase) and splits it on underscores into words, then turns all words into all lowercase and finally make the first letter uppercase again. This is why NMI and up as Nmi and needs to be fixed afterwards. If you have a better solution for this I'd like to see it. Matthias

--- tools/virsh.c | 35 +++++++++++++++++++++++++++++++++++ tools/virsh.pod | 4 ++++ 2 files changed, 39 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 2b16714..c2dabd7 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2912,6 +2912,40 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd) } /* + * "inject-nmi" command + */ +static const vshCmdInfo info_inject_nmi[] = { + {"help", N_("Inject NMI to the guest")}, + {"desc", N_("Inject NMI to the guest domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_inject_nmi[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + + +static bool +cmdInjectNMI(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int ret = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (virDomainInjectNMI(dom, 0) < 0) + ret = false; + + virDomainFree(dom); + return ret; +} + +/* * "setmemory" command */ static const vshCmdInfo info_setmem[] = { @@ -10720,6 +10754,7 @@ static const vshCmdDef domManagementCmds[] = { {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem}, {"setmem", cmdSetmem, opts_setmem, info_setmem}, {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus}, + {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi}, {"shutdown", cmdShutdown, opts_shutdown, info_shutdown}, {"start", cmdStart, opts_start, info_start}, {"suspend", cmdSuspend, opts_suspend, info_suspend}, diff --git a/tools/virsh.pod b/tools/virsh.pod index 2a708f6..f317c57 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -290,6 +290,10 @@ running B<virsh suspend>. When in a paused state the domain will still consume allocated resources like memory, but will not be eligible for scheduling by the hypervisor. +=item B<inject-nmi> I<domain-id> + +Inject NMI to the guest + =item B<shutdown> The domain is in the process of shutting down, i.e. the guest operating system -- 1.7.4.4

--- src/qemu/qemu_driver.c | 46 +++++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_monitor.c | 14 ++++++++++++ src/qemu/qemu_monitor.h | 2 + src/qemu/qemu_monitor_json.c | 27 ++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 1 + src/qemu/qemu_monitor_text.c | 28 +++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 1 + 7 files changed, 118 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index fa4a2bd..bec0e35 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1705,6 +1705,50 @@ static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long memory) return qemudDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM); } +static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags) +{ + struct qemud_driver *driver = domain->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + qemuDomainObjPrivatePtr priv; + + virCheckFlags(0, -1); + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, domain->uuid); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(domain->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) + goto cleanup; + qemuDomainObjEnterMonitorWithDriver(driver, vm); + ret = qemuMonitorInjectNMI(priv->mon); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (qemuDomainObjEndJob(vm) == 0) { + vm = NULL; + goto cleanup; + } + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + static int qemudDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { @@ -7192,7 +7236,7 @@ static virDriver qemuDriver = { qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ qemuDomainOpenConsole, /* domainOpenConsole */ - NULL, /* domainInjectNMI */ + qemuDomainInjectNMI, /* domainInjectNMI */ }; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index f89038e..9f0f20d 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2228,3 +2228,17 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, ret = qemuMonitorTextArbitraryCommand(mon, cmd, reply); return ret; } + + +int qemuMonitorInjectNMI(qemuMonitorPtr mon) +{ + int ret; + + VIR_DEBUG("mon=%p", mon); + + if (mon->json) + ret = qemuMonitorJSONInjectNMI(mon); + else + ret = qemuMonitorTextInjectNMI(mon); + return ret; +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c90219b..b84e230 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -423,6 +423,8 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, char **reply, bool hmp); +int qemuMonitorInjectNMI(qemuMonitorPtr mon); + /** * When running two dd process and using <> redirection, we need a * shell that will not truncate files. These two strings serve that diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 20a78e1..04ef077 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2513,3 +2513,30 @@ cleanup: return ret; } + +int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon) +{ + int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("inject-nmi", NULL); + if (!cmd) + return -1; + + if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0) + goto cleanup; + + if (qemuMonitorJSONHasError(reply, "CommandNotFound") && + qemuMonitorCheckHMP(mon, "inject-nmi")) { + VIR_DEBUG0("inject-nmi command not found, trying HMP"); + ret = qemuMonitorTextInjectNMI(mon); + } else { + ret = qemuMonitorJSONCheckError(cmd, reply); + } + +cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 086f0e1..f2dc4d2 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -204,4 +204,5 @@ int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, char **reply_str, bool hmp); +int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon); #endif /* QEMU_MONITOR_JSON_H */ diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 53781c8..1a15d49 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -2628,3 +2628,31 @@ int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd, return ret; } + +int qemuMonitorTextInjectNMI(qemuMonitorPtr mon) +{ + const char *cmd = "inject-nmi"; + char *reply = NULL; + + if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) + goto fail; + + if (strstr(reply, "unknown command") != NULL) { + VIR_FREE(reply); + + /* fallback to 'nmi' if qemu has not supported "inject-nmi" yet. */ + cmd = "nmi 0"; + reply = NULL; + if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) + goto fail; + } + + VIR_FREE(reply); + return 0; + +fail: + qemuReportError(VIR_ERR_OPERATION_FAILED, + _("failed to inject NMI using command '%s'"), + cmd); + return -1; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 0838a2b..dbae72b 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -198,4 +198,5 @@ int qemuMonitorTextDeleteSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply); +int qemuMonitorTextInjectNMI(qemuMonitorPtr mon); #endif /* QEMU_MONITOR_TEXT_H */ -- 1.7.4.4

On 05/10/2011 02:26 AM, Lai Jiangshan wrote:
+int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon) +{ + int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("inject-nmi", NULL); + if (!cmd) + return -1; + + if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0) + goto cleanup; + + if (qemuMonitorJSONHasError(reply, "CommandNotFound") && + qemuMonitorCheckHMP(mon, "inject-nmi")) { + VIR_DEBUG0("inject-nmi command not found, trying HMP"); + ret = qemuMonitorTextInjectNMI(mon);
+ +int qemuMonitorTextInjectNMI(qemuMonitorPtr mon) +{ + const char *cmd = "inject-nmi"; + char *reply = NULL; + + if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) + goto fail; + + if (strstr(reply, "unknown command") != NULL) { + VIR_FREE(reply); + + /* fallback to 'nmi' if qemu has not supported "inject-nmi" yet. */ + cmd = "nmi 0"; + reply = NULL; + if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0)
I just noticed that upstream qemu now has QMP 'inject-nmi' (commit a404666), and that as a result, HMP 'nmi' command no longer takes an integer option (commit e9b4b43). If libvirt uses QMP, then this is not an issue, but if libvirt uses HMP while talking to a newer qemu, is this attempt to do 'nmi 0' going to cause a syntax error? That is, do we need a patch to libvirt to detect a usage error with 'nmi 0' on hmp that falls back to trying plain 'nmi' before giving up altogether? -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Tue, May 10, 2011 at 04:26:00PM +0800, Lai Jiangshan wrote:
This patch series implements a feature of injecting NMI to guest, which is accessible via new virDomainInjectNMI API and 'inject-nmi' command in virsh.
Lai Jiangshan (6): inject-nmi: Defining the public API inject-nmi: Defining the internal API inject-nmi: Implementing the public API inject-nmi: Implementing the remote protocol inject-nmi: Expose the new API in virsh qemu,inject-nmi: Implement the driver methods
ACK to whole series. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 05/10/2011 03:13 AM, Daniel P. Berrange wrote:
On Tue, May 10, 2011 at 04:26:00PM +0800, Lai Jiangshan wrote:
This patch series implements a feature of injecting NMI to guest, which is accessible via new virDomainInjectNMI API and 'inject-nmi' command in virsh.
Lai Jiangshan (6): inject-nmi: Defining the public API inject-nmi: Defining the internal API inject-nmi: Implementing the public API inject-nmi: Implementing the remote protocol inject-nmi: Expose the new API in virsh qemu,inject-nmi: Implement the driver methods
ACK to whole series.
Pushed, with some modifications as pointed out on individual mails. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On 04/12/2011 10:56 PM, Lai Jiangshan wrote:
This patch series implements a feature of injecting NMI to guest, which is accessible via new virDomainInjectNMI API and 'inject-nmi' command in virsh.
Lai Jiangshan (6): inject-nmi: Defining the public API inject-nmi: Defining the internal API inject-nmi: Implementing the public API inject-nmi: Implementing the remote protocol inject-nmi: Expose the new API in virsh qemu,inject-nmi: Implement the driver methods
This is v2 of: https://www.redhat.com/archives/libvir-list/2011-April/msg00036.html If you use 'git format-patch --subject-prefix=PATCHv2' (or send-email instead of format-patch), it makes it easier to see that this is a resend. Thanks for splitting it up; that helps review. My quick glance at 1-5 didn't turn up any glaring problems, but I'm still not sure we've got the semantics right. I'll reply to patch 6, and think we'll need another spin to get the API right. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org
participants (4)
-
Daniel P. Berrange
-
Eric Blake
-
Lai Jiangshan
-
Matthias Bolte