[libvirt] [PATCH V4 0/5] support sending sysrq key

xend/libxl support sending sysrq key to guest kernel but not support sending any key sequence as virDomainSendKey is expected to do. To add equivalant sysrq functionality in libvirt for xen/libxl, add a new virDomainSendSysrq API and add related codes to virsh, remote driver, xen/libxl driver. Changes to V3: * fix some memory leak Not change: virDomainSendSysrq parameter still keeps "char key" rather than "enum key", main reason to keep it because: sysrq key is different to different kinds of guests, xen hypervisor doesn't know the correct enum <-> letter mapping towards different guests, it just sends the key blindly to guests. See: http://www.redhat.com/archives/libvir-list/2015-January/msg00132.html V3 is here: http://www.redhat.com/archives/libvir-list/2014-December/msg00882.html Chunyan Liu (5): Add public API virDomainSendSysrq implement remote protocol for domainSendSysrq virsh: add 'sysrq' command libxl: implement .domainSendSysrq method xen: add .domainSendSysrq method include/libvirt/libvirt-domain.h | 3 +++ src/driver-hypervisor.h | 4 +++ src/libvirt-domain.c | 39 +++++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++++ src/libxl/libxl_driver.c | 25 ++++++++++++++++++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 14 +++++++++- src/remote_protocol-structs | 6 +++++ src/rpc/gendispatch.pl | 12 +++++++++ src/xen/xen_driver.c | 21 +++++++++++++++ src/xen/xend_internal.c | 30 +++++++++++++++++++++ src/xen/xend_internal.h | 1 + tools/virsh-domain.c | 57 ++++++++++++++++++++++++++++++++++++++++ 13 files changed, 217 insertions(+), 1 deletion(-) -- 1.8.4.5

Add public API virDomainSendSysrq for sending SysRequest key. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- include/libvirt/libvirt-domain.h | 3 +++ src/driver-hypervisor.h | 4 ++++ src/libvirt-domain.c | 39 +++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 +++++ 4 files changed, 51 insertions(+) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 0b1a2d6..a762034 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -3527,6 +3527,9 @@ int virDomainGetFSInfo(virDomainPtr dom, virDomainFSInfoPtr **info, unsigned int flags); +/* virDomainSendSysrq */ +int virDomainSendSysrq(virDomainPtr dom, char key, unsigned int flags); + int virDomainGetTime(virDomainPtr dom, long long *seconds, unsigned int *nseconds, diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index 9f26b13..d260d29 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1170,6 +1170,9 @@ typedef int unsigned int cellCount, unsigned int flags); +typedef int +(*virDrvDomainSendSysrq)(virDomainPtr dom, char key, unsigned int flags); + typedef struct _virHypervisorDriver virHypervisorDriver; typedef virHypervisorDriver *virHypervisorDriverPtr; @@ -1396,6 +1399,7 @@ struct _virHypervisorDriver { virDrvConnectGetAllDomainStats connectGetAllDomainStats; virDrvNodeAllocPages nodeAllocPages; virDrvDomainGetFSInfo domainGetFSInfo; + virDrvDomainSendSysrq domainSendSysrq; }; diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 6ec68aa..83ece45 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -11201,3 +11201,42 @@ virDomainFSInfoFree(virDomainFSInfoPtr info) VIR_FREE(info->devAlias[i]); VIR_FREE(info->devAlias); } + + +/** + * virDomainSendSysrq: + * @domain: pointer to domain object, or NULL for Domain0 + * @key: SysRq key, like h, c, ... + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Send SysRq key to the guest. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virDomainSendSysrq(virDomainPtr domain, char key, unsigned int flags) +{ + virConnectPtr conn; + VIR_DOMAIN_DEBUG(domain, "key=%c, flags=%x", key, flags); + + virResetLastError(); + + virCheckDomainReturn(domain, -1); + conn = domain->conn; + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->driver->domainSendSysrq) { + int ret; + ret = conn->driver->domainSendSysrq(domain, key, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(domain->conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index e4c2df1..5d4999a 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -690,4 +690,9 @@ LIBVIRT_1.2.11 { virDomainGetFSInfo; } LIBVIRT_1.2.9; +LIBVIRT_1.2.12 { + global: + virDomainSendSysrq; +} LIBVIRT_1.2.11; + # .... define new API here using predicted next version number .... -- 1.8.4.5

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 14 +++++++++++++- src/remote_protocol-structs | 6 ++++++ src/rpc/gendispatch.pl | 12 ++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 999f16d..b24de5c 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8285,6 +8285,7 @@ static virHypervisorDriver hypervisor_driver = { .connectGetAllDomainStats = remoteConnectGetAllDomainStats, /* 1.2.8 */ .nodeAllocPages = remoteNodeAllocPages, /* 1.2.9 */ .domainGetFSInfo = remoteDomainGetFSInfo, /* 1.2.11 */ + .domainSendSysrq = remoteDomainSendSysrq, /* 1.2.12 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index cbd3ec7..708983c 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1084,6 +1084,12 @@ struct remote_domain_send_key_args { unsigned int flags; }; +struct remote_domain_send_sysrq_args { + remote_nonnull_domain dom; + char key; + unsigned int flags; +}; + struct remote_domain_send_process_signal_args { remote_nonnull_domain dom; hyper pid_value; @@ -5550,5 +5556,11 @@ enum remote_procedure { * @generate: none * @acl: domain:fs_freeze */ - REMOTE_PROC_DOMAIN_GET_FSINFO = 349 + REMOTE_PROC_DOMAIN_GET_FSINFO = 349, + + /** + * @generate: both + * @acl: domain:send_input + */ + REMOTE_PROC_DOMAIN_SEND_SYSRQ = 350 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 2907fd5..afd9a8d 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2605,6 +2605,11 @@ struct remote_domain_get_fsinfo_ret { } info; u_int ret; }; +struct remote_domain_send_sysrq_args { + remote_nonnull_domain dom; + char key; + unsigned int flags; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -2955,4 +2960,5 @@ enum remote_procedure { REMOTE_PROC_NODE_ALLOC_PAGES = 347, REMOTE_PROC_DOMAIN_EVENT_CALLBACK_AGENT_LIFECYCLE = 348, REMOTE_PROC_DOMAIN_GET_FSINFO = 349, + REMOTE_PROC_DOMAIN_SEND_SYSRQ = 350, }; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 0dc167a..cafe5ab 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -592,6 +592,12 @@ elsif ($mode eq "server") { } else { push(@args_list, "args->$arg_name"); } + } elsif ($args_member =~ m/^(unsigned )?char (\S+);/) { + if (! @args_list) { + push(@args_list, "priv->conn"); + } + + push(@args_list, "args->$2"); } elsif ($args_member =~ m/^(\/)?\*/) { # ignore comments } else { @@ -1228,6 +1234,12 @@ elsif ($mode eq "client") { push(@args_list, "$type_name $arg_name"); push(@setters_list, "args.$arg_name = $arg_name;"); + } elsif ($args_member =~ m/^((?:unsigned )?char) (\S+);/) { + my $type_name = $1; + my $arg_name = $2; + + push(@args_list, "$type_name $arg_name"); + push(@setters_list, "args.$arg_name = $arg_name;"); } elsif ($args_member =~ m/^(\/)?\*/) { # ignore comments } else { -- 1.8.4.5

All domainSendSysrq related API should be manageable from the virsh command line. So, expose 'virsh sysrq' command. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- Changes: * adjust code to follow general format and fix a memory leak tools/virsh-domain.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 750411b..43fa1d8 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -12289,6 +12289,57 @@ cmdDomFSInfo(vshControl *ctl, const vshCmd *cmd) return ret >= 0; } +/* + * "sysrq" command + */ +static const vshCmdInfo info_sysrq[] = { + {.name = "help", + .data = N_("Send SysRq key to the guest") + }, + {.name = "desc", + .data = N_("Send SysRq key to the guest") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_sysrq[] = { + {.name = "domain", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("domain name, id or uuid") + }, + {.name = "key", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("the SysRq key") + }, + {.name = NULL} +}; + +static bool +cmdSysrq(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + bool ret = false; + const char *key = NULL; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (vshCommandOptStringReq(ctl, cmd, "key", &key) < 0) + goto cleanup; + + if (virDomainSendSysrq(dom, key[0], 0) < 0) + goto cleanup; + + ret = true; + + cleanup: + virDomainFree(dom); + return ret; +} + + const vshCmdDef domManagementCmds[] = { {.name = "attach-device", .handler = cmdAttachDevice, @@ -12808,5 +12859,11 @@ const vshCmdDef domManagementCmds[] = { .info = info_vncdisplay, .flags = 0 }, + {.name = "sysrq", + .handler = cmdSysrq, + .opts = opts_sysrq, + .info = info_sysrq, + .flags = 0 + }, {.name = NULL} }; -- 1.8.4.5

Support .domainSendSysrq in libxl driver. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libxl/libxl_driver.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 4135670..5ae565e 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -4745,6 +4745,30 @@ libxlDomainMigrateConfirm3Params(virDomainPtr domain, return libxlDomainMigrationConfirm(driver, vm, flags, cancelled); } +static int +libxlDomainSendSysrq(virDomainPtr dom, char key, unsigned int flags) +{ + virDomainObjPtr vm; + libxlDomainObjPrivatePtr priv; + int ret = -1; + + virCheckFlags(0, -1); + + if (!(vm = libxlDomObjFromDomain(dom))) + goto cleanup; + + priv = vm->privateData; + + if (virDomainSendSysrqEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + ret = libxl_send_sysrq(priv->ctx, vm->def->id, key); + + cleanup: + if (vm) + virObjectUnlock(vm); + return ret; +} static virHypervisorDriver libxlDriver = { .no = VIR_DRV_LIBXL, @@ -4840,6 +4864,7 @@ static virHypervisorDriver libxlDriver = { .domainMigratePerform3Params = libxlDomainMigratePerform3Params, /* 1.2.6 */ .domainMigrateFinish3Params = libxlDomainMigrateFinish3Params, /* 1.2.6 */ .domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.6 */ + .domainSendSysrq = libxlDomainSendSysrq, /* 1.2.12 */ }; static virStateDriver libxlStateDriver = { -- 1.8.4.5

Support sending sysrq key to guest. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/xen/xen_driver.c | 21 +++++++++++++++++++++ src/xen/xend_internal.c | 30 ++++++++++++++++++++++++++++++ src/xen/xend_internal.h | 1 + 3 files changed, 52 insertions(+) diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index c9f4159..4a56b69 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -2738,6 +2738,26 @@ xenUnifiedNodeSuspendForDuration(virConnectPtr conn, return nodeSuspendForDuration(target, duration, flags); } +static int +xenUnifiedDomainSendSysrq(virDomainPtr dom, char key, unsigned int flags) +{ + int ret = -1; + virDomainDefPtr def = NULL; + + virCheckFlags(0, -1); + + if (!(def = xenGetDomainDefForDom(dom))) + goto cleanup; + + if (virDomainSendSysrqEnsureACL(dom->conn, def) < 0) + goto cleanup; + + ret = xenDaemonDomainSysrq(dom->conn, def, key); + + cleanup: + virDomainDefFree(def); + return ret; +} /*----- Register with libvirt.c, and initialize Xen drivers. -----*/ @@ -2836,6 +2856,7 @@ static virHypervisorDriver xenUnifiedDriver = { .nodeSuspendForDuration = xenUnifiedNodeSuspendForDuration, /* 0.9.8 */ .nodeGetMemoryParameters = xenUnifiedNodeGetMemoryParameters, /* 0.10.2 */ .nodeSetMemoryParameters = xenUnifiedNodeSetMemoryParameters, /* 0.10.2 */ + .domainSendSysrq = xenUnifiedDomainSendSysrq, /* 1.2.12 */ }; /** diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index b233b6b..77af8a0 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -3300,6 +3300,36 @@ xenDaemonDomainBlockPeek(virConnectPtr conn, return ret; } +/* + * xenDaemonDomainSysrq: + * <at> conn: the connection object + * <at> def: the domain to destroy + * <at> key: SysRq key + * + * Send a sysrq to a domain. + * + * Returns 0 in case of success, -1 (with errno) in case of error. + */ +int +xenDaemonDomainSysrq(virConnectPtr conn, virDomainDefPtr def, char key) +{ + char *buf; + int ret; + + if (def->id < 0) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("Domain %s isn't running."), def->name); + return -1; + } + + if (virAsprintf(&buf, "%c", key) < 0) + return -1; + + ret = xend_op(conn, def->name, "op", "sysrq", "key", buf, NULL); + + VIR_FREE(buf); + return ret; +} /** * virDomainXMLDevID: diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h index 814330d..02f9d9b 100644 --- a/src/xen/xend_internal.h +++ b/src/xen/xend_internal.h @@ -213,5 +213,6 @@ int xenDaemonSetSchedulerParameters(virConnectPtr conn, virDomainDefPtr def, virTypedParameterPtr params, int nparams); +int xenDaemonDomainSysrq(virConnectPtr conn, virDomainDefPtr def, char key); #endif /* __XEND_INTERNAL_H_ */ -- 1.8.4.5
participants (1)
-
Chunyan Liu