From nobody Fri Apr 19 20:01:38 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) client-ip=63.128.21.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=bytedance.com ARC-Seal: i=1; a=rsa-sha256; t=1602313061; cv=none; d=zohomail.com; s=zohoarc; b=NoAemCF9o1gDul/PSjES5ymi9mHM7yokFRFYMHR6/v4Hp3ILL7AkYwJ8IYQXMKzSKg489iOTPARZwIxND7Z/G3/YXp3WrLCHuvKBwvFt7lEx21bnRNO5ii38VacfHihFBjsvwhKEOV1reNi53UPJTknTe+XscpRcLCrP/wihBKs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1602313061; h=Content-Type:Cc:Date:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:Sender:Subject:To; bh=19GcpaapEmgsDmZ1p7N75ul0lmlfpHHP4tl+7WTPC98=; b=YsDlNBJEb0t7WTHxbPElOKNOxcyiYdG+iFxmWf+qLGVHpjwJYE/lIiZyRA3IlADNUdRBcKqCjq6mx5UWqJfQ3s0j6qH1DhMu91VkEnSdhpyKNiY3hPyA/MTayi3uKTlLSQywlW/hzV1dgxGcxmeixh2IOvjVV5BbfIv82R4prvA= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [63.128.21.124]) by mx.zohomail.com with SMTPS id 1602313061339481.62554333513924; Fri, 9 Oct 2020 23:57:41 -0700 (PDT) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-336-P9iw0kAnMEO7WlxpRpYoZQ-1; Sat, 10 Oct 2020 02:57:36 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 97875805F05; Sat, 10 Oct 2020 06:57:29 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 7960810027AA; Sat, 10 Oct 2020 06:57:27 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 88B8F8C7C9; Sat, 10 Oct 2020 06:57:22 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 09A6uufA026766 for ; Sat, 10 Oct 2020 02:56:56 -0400 Received: by smtp.corp.redhat.com (Postfix) id 56B6E16544A; Sat, 10 Oct 2020 06:56:56 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast01.extmail.prod.ext.rdu2.redhat.com [10.11.55.17]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 4E20C16756A for ; Sat, 10 Oct 2020 06:56:54 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [207.211.31.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id EC0A8858294 for ; Sat, 10 Oct 2020 06:56:53 +0000 (UTC) Received: from mail-pf1-f196.google.com (mail-pf1-f196.google.com [209.85.210.196]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-585-UQ-NuZ5XO7GiC7II3C6mgQ-1; Sat, 10 Oct 2020 02:56:51 -0400 Received: by mail-pf1-f196.google.com with SMTP id x13so6149055pfa.9 for ; Fri, 09 Oct 2020 23:56:51 -0700 (PDT) Received: from libai.bytedance.net ([61.120.150.71]) by smtp.gmail.com with ESMTPSA id y5sm7093547pgo.5.2020.10.09.23.56.47 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 09 Oct 2020 23:56:49 -0700 (PDT) X-MC-Unique: P9iw0kAnMEO7WlxpRpYoZQ-1 X-MC-Unique: UQ-NuZ5XO7GiC7II3C6mgQ-1 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=19GcpaapEmgsDmZ1p7N75ul0lmlfpHHP4tl+7WTPC98=; b=C74UxJVIekLVfoub2c0VhwLHijMhIadf+uWRo5lbzlgEWT5GU+TKBGPlLrG9AuOcRX qzYwJutL29scZOiMWbaxG8T9aBR+/1wZ/JyCb7s1dwo5myvp+prxCn465E6ZN6VU1TrZ 31GgesD42UEbWRKcdvhw1ckXAH/1FyqZHjLDJtTeANmHbEIJiZ60hb0/VngWhpIOTbeY N4bwO7dxstgxCVvqx/eSPjhtp0XGcdYu9P5Jm7+0NqHcJ1RAEXTVnrAWT0qmIxdM/VEj rY2BmQDby+U9vsf2Atuu7wirOQbYQfAWakoGbIXDcAguo3xlU9AYJCUyhB0IPdRwcLwy JXeA== X-Gm-Message-State: AOAM5321tfPvd3NWvx+NqzgG3xqQpR4KYOGkjs1283yNAVx3ekt/qiuN V9WPp5mKG4CpF4i9fgm9JFmd4g== X-Google-Smtp-Source: ABdhPJyJFvhGvWmy6r856tgBwp5juWBzQr7pyOUVhHSoj1CoMWf252PurmfQQpYN4B/Sf7s3lFsECA== X-Received: by 2002:a63:1665:: with SMTP id 37mr6248609pgw.383.1602313010247; Fri, 09 Oct 2020 23:56:50 -0700 (PDT) From: zhenwei pi To: berrange@redhat.com Subject: [PATCH] libvirt: add memory failure event Date: Sat, 10 Oct 2020 14:56:43 +0800 Message-Id: <20201010065643.784126-1-pizhenwei@bytedance.com> X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-loop: libvir-list@redhat.com Cc: libvir-list@redhat.com, pizhenwei@bytedance.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 2 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Since QEMU 5.2 (commit-77b285f7f6), QEMU supports 'memory failure' event, posts event to monitor if hitting a hardware memory error. Several changes in this patch: Add a new event 'memory failure' for libvirt domain. Implement memory failure event handling for QEMU from QMP. Also implement virsh command callback functions. Test case: ~# virsh event stretch --event memory-failure event 'memory-failure' for domain stretch: recipient: guest action: inject flags: action required: 0 recursive: 0 events received: 1 Signed-off-by: zhenwei pi --- examples/c/misc/event-test.c | 17 ++++++++ include/libvirt/libvirt-domain.h | 84 +++++++++++++++++++++++++++++++++= ++++ src/conf/domain_event.c | 82 +++++++++++++++++++++++++++++++++= +++ src/conf/domain_event.h | 12 ++++++ src/libvirt_private.syms | 2 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 57 +++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 21 +++++++++- src/qemu/qemu_monitor.h | 39 +++++++++++++++++ src/qemu/qemu_monitor_json.c | 50 ++++++++++++++++++++++ src/qemu/qemu_process.c | 28 +++++++++++++ src/remote/remote_daemon_dispatch.c | 33 +++++++++++++++ src/remote/remote_driver.c | 35 ++++++++++++++++ src/remote/remote_protocol.x | 21 +++++++++- src/remote_protocol-structs | 12 ++++++ tools/virsh-domain.c | 37 ++++++++++++++++ 17 files changed, 530 insertions(+), 2 deletions(-) diff --git a/examples/c/misc/event-test.c b/examples/c/misc/event-test.c index 52caa8ffa8..b10946d569 100644 --- a/examples/c/misc/event-test.c +++ b/examples/c/misc/event-test.c @@ -964,6 +964,22 @@ myDomainEventBlockThresholdCallback(virConnectPtr conn= G_GNUC_UNUSED, =20 =20 static int +myDomainEventMemoryFailureCallback(virConnectPtr conn G_GNUC_UNUSED, + virDomainPtr dom, + virDomainMemoryFailureRecipientType rec= ipient, + virDomainMemoryFailureActionType action, + virDomainMemoryFailureFlagsPtr flags, + void *opaque G_GNUC_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) memory failure: recipient '%d', " + "aciont '%d', action_required '%d', recursive '%d'", + __func__, virDomainGetName(dom), virDomainGetID(dom), recipient, + action, flags->action_required, flags->recursive); + return 0; +} + + +static int myDomainEventMigrationIterationCallback(virConnectPtr conn G_GNUC_UNUSED, virDomainPtr dom, int iteration, @@ -1093,6 +1109,7 @@ struct domainEventData domainEvents[] =3D { DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED, myDomainEventD= eviceRemovalFailedCallback), DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_METADATA_CHANGE, myDomainEventMetadat= aChangeCallback), DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD, myDomainEventBlockTh= resholdCallback), + DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE, myDomainEventMemoryFa= ilureCallback), }; =20 struct storagePoolEventData { diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-dom= ain.h index 77f9116675..a9170d9a7e 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -3196,6 +3196,66 @@ typedef enum { } virDomainEventCrashedDetailType; =20 /** + * virDomainMemoryFailureRecipientType: + * + * Recipient of a memory failure event. + */ +typedef enum { + /* memory failure at hypersivor memory address space */ + VIR_DOMAIN_EVENT_MEMORY_FAILURE_RECIPIENT_HYPERVISOR =3D 0, + + /* memory failure at guest memory address space */ + VIR_DOMAIN_EVENT_MEMORY_FAILURE_RECIPIENT_GUEST =3D 1, + +# ifdef VIR_ENUM_SENTINELS + VIR_DOMAIN_EVENT_MEMORY_FAILURE_RECIPIENT_LAST +# endif +} virDomainMemoryFailureRecipientType; + + +/** + * virDomainMemoryFailureActionType: + * + * Action of a memory failure event. + */ +typedef enum { + /* the memory failure could be ignored. This will only be the case for + * action-optional failures. */ + VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_IGNORE =3D 0, + + /* memory failure occurred in guest memory, the guest enabled MCE hand= ling + * mechanism, and hypervisor could inject the MCE into the guest + * successfully. */ + VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_INJECT =3D 1, + + /* the failure is unrecoverable. This occurs for action-required fail= ures + * if the recipient is the hypervisor; hypervisor will exit. */ + VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_FATAL =3D 2, + + /* the failure is unrecoverable but confined to the guest. This occurs= if + * the recipient is a guest which is not ready to handle memory failur= es. */ + VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_RESET =3D 3, + +# ifdef VIR_ENUM_SENTINELS + VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_LAST +# endif +} virDomainMemoryFailureActionType; + + +typedef struct _virDomainMemoryFailureFlags virDomainMemoryFailureFlags; +typedef virDomainMemoryFailureFlags *virDomainMemoryFailureFlagsPtr; +struct _virDomainMemoryFailureFlags { + /* whether a memory failure event is action-required or action-optional + * (e.g. a failure during memory scrub). */ + int action_required; + + /* whether the failure occurred while the previous failure was still in + * progress. */ + int recursive; +}; + + +/** * virConnectDomainEventCallback: * @conn: virConnect connection * @dom: The domain on which the event occurred @@ -4565,6 +4625,29 @@ typedef void (*virConnectDomainEventBlockThresholdCa= llback)(virConnectPtr conn, void *opaque); =20 /** + * virConnectDomainEventMemoryFailureCallback: + * @conn: connection object + * @dom: domain on which the event occurred + * @recipient: the recipient of hardware memory failure + * @action: the action of hardware memory failure + * @flags: the flags of hardware memory failure + * @opaque: application specified data + * + * The callback occurs when the hypervisor handles the hardware memory + * corrupted event. + * + * The callback signature to use when registering for an event of type + * VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE with virConnectDomainEventRegisterAn= y() + */ +typedef void (*virConnectDomainEventMemoryFailureCallback)(virConnectPtr c= onn, + virDomainPtr do= m, + virDomainMemory= FailureRecipientType recipient, + virDomainMemory= FailureActionType action, + virDomainMemory= FailureFlagsPtr flags, + void *opaque); + + +/** * VIR_DOMAIN_EVENT_CALLBACK: * * Used to cast the event specific callback into the generic one @@ -4606,6 +4689,7 @@ typedef enum { VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED =3D 22, /* virConnectDomainE= ventDeviceRemovalFailedCallback */ VIR_DOMAIN_EVENT_ID_METADATA_CHANGE =3D 23, /* virConnectDomainEventMe= tadataChangeCallback */ VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD =3D 24, /* virConnectDomainEventBl= ockThresholdCallback */ + VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE =3D 25, /* virConnectDomainEventMem= oryFailureCallback */ =20 # ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_EVENT_ID_LAST diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index a8bd9f1595..20c5590835 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -57,6 +57,7 @@ static virClassPtr virDomainEventJobCompletedClass; static virClassPtr virDomainEventDeviceRemovalFailedClass; static virClassPtr virDomainEventMetadataChangeClass; static virClassPtr virDomainEventBlockThresholdClass; +static virClassPtr virDomainEventMemoryFailureClass; =20 static void virDomainEventDispose(void *obj); static void virDomainEventLifecycleDispose(void *obj); @@ -79,6 +80,7 @@ static void virDomainEventJobCompletedDispose(void *obj); static void virDomainEventDeviceRemovalFailedDispose(void *obj); static void virDomainEventMetadataChangeDispose(void *obj); static void virDomainEventBlockThresholdDispose(void *obj); +static void virDomainEventMemoryFailureDispose(void *obj); =20 static void virDomainEventDispatchDefaultFunc(virConnectPtr conn, @@ -287,6 +289,16 @@ struct _virDomainEventBlockThreshold { typedef struct _virDomainEventBlockThreshold virDomainEventBlockThreshold; typedef virDomainEventBlockThreshold *virDomainEventBlockThresholdPtr; =20 +struct _virDomainEventMemoryFailure { + virDomainEvent parent; + + virDomainMemoryFailureRecipientType recipient; + virDomainMemoryFailureActionType action; + virDomainMemoryFailureFlags flags; +}; +typedef struct _virDomainEventMemoryFailure virDomainEventMemoryFailure; +typedef virDomainEventMemoryFailure *virDomainEventMemoryFailurePtr; + =20 static int virDomainEventsOnceInit(void) @@ -333,6 +345,8 @@ virDomainEventsOnceInit(void) return -1; if (!VIR_CLASS_NEW(virDomainEventBlockThreshold, virDomainEventClass)) return -1; + if (!VIR_CLASS_NEW(virDomainEventMemoryFailure, virDomainEventClass)) + return -1; return 0; } =20 @@ -542,6 +556,14 @@ virDomainEventBlockThresholdDispose(void *obj) } =20 =20 +static void +virDomainEventMemoryFailureDispose(void *obj) +{ + virDomainEventMemoryFailurePtr event =3D obj; + VIR_DEBUG("obj=3D%p", event); +} + + static void * virDomainEventNew(virClassPtr klass, int eventID, @@ -1619,6 +1641,53 @@ virDomainEventBlockThresholdNewFromDom(virDomainPtr = dom, } =20 =20 +static virObjectEventPtr +virDomainEventMemoryFailureNew(int id, + const char *name, + unsigned char *uuid, + virDomainMemoryFailureRecipientType recipie= nt, + virDomainMemoryFailureActionType action, + virDomainMemoryFailureFlagsPtr flags) +{ + virDomainEventMemoryFailurePtr ev; + + if (virDomainEventsInitialize() < 0) + return NULL; + + if (!(ev =3D virDomainEventNew(virDomainEventMemoryFailureClass, + VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE, + id, name, uuid))) + return NULL; + + ev->recipient =3D recipient; + ev->action =3D action; + ev->flags.action_required =3D flags->action_required; + ev->flags.recursive =3D flags->recursive; + + return (virObjectEventPtr)ev; +} + +virObjectEventPtr +virDomainEventMemoryFailureNewFromObj(virDomainObjPtr obj, + virDomainMemoryFailureRecipientType = recipient, + virDomainMemoryFailureActionType act= ion, + virDomainMemoryFailureFlagsPtr flags) +{ + return virDomainEventMemoryFailureNew(obj->def->id, obj->def->name, + obj->def->uuid, recipient, actio= n, + flags); +} + +virObjectEventPtr +virDomainEventMemoryFailureNewFromDom(virDomainPtr dom, + virDomainMemoryFailureRecipientType = recipient, + virDomainMemoryFailureActionType act= ion, + virDomainMemoryFailureFlagsPtr flags) +{ + return virDomainEventMemoryFailureNew(dom->id, dom->name, dom->uuid, + recipient, action, flags); +} + static void virDomainEventDispatchDefaultFunc(virConnectPtr conn, virObjectEventPtr event, @@ -1902,6 +1971,19 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, cbopaque); goto cleanup; } + case VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE: + { + virDomainEventMemoryFailurePtr memoryFailureEvent; + + memoryFailureEvent =3D (virDomainEventMemoryFailurePtr)event; + ((virConnectDomainEventMemoryFailureCallback)cb)(conn, dom, + memoryFailure= Event->recipient, + memoryFailure= Event->action, + &memoryFailur= eEvent->flags, + cbopaque); + goto cleanup; + } + case VIR_DOMAIN_EVENT_ID_LAST: break; } diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index d1cfb81d62..5b317e8d30 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -255,6 +255,18 @@ virDomainEventBlockThresholdNewFromDom(virDomainPtr do= m, unsigned long long threshold, unsigned long long excess); =20 +virObjectEventPtr +virDomainEventMemoryFailureNewFromObj(virDomainObjPtr obj, + virDomainMemoryFailureRecipientType = recipient, + virDomainMemoryFailureActionType act= ion, + virDomainMemoryFailureFlagsPtr flags= ); + +virObjectEventPtr +virDomainEventMemoryFailureNewFromDom(virDomainPtr dom, + virDomainMemoryFailureRecipientType = recipient, + virDomainMemoryFailureActionType act= ion, + virDomainMemoryFailureFlagsPtr flags= ); + int virDomainEventStateRegister(virConnectPtr conn, virObjectEventStatePtr state, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 152083d220..927de5001a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -704,6 +704,8 @@ virDomainEventLifecycleNew; virDomainEventLifecycleNewFromDef; virDomainEventLifecycleNewFromDom; virDomainEventLifecycleNewFromObj; +virDomainEventMemoryFailureNewFromDom; +virDomainEventMemoryFailureNewFromObj; virDomainEventMetadataChangeNewFromDom; virDomainEventMetadataChangeNewFromObj; virDomainEventMigrationIterationNewFromDom; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 9623123d3c..5b5316fadd 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -10551,6 +10551,7 @@ qemuProcessEventFree(struct qemuProcessEvent *event) case QEMU_PROCESS_EVENT_BLOCK_JOB: case QEMU_PROCESS_EVENT_MONITOR_EOF: case QEMU_PROCESS_EVENT_GUEST_CRASHLOADED: + case QEMU_PROCESS_EVENT_MEMORY_FAILURE: VIR_FREE(event->data); break; case QEMU_PROCESS_EVENT_JOB_STATUS_CHANGE: diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 9bf32e16c9..51d5963f25 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -441,6 +441,7 @@ typedef enum { QEMU_PROCESS_EVENT_PR_DISCONNECT, QEMU_PROCESS_EVENT_RDMA_GID_STATUS_CHANGED, QEMU_PROCESS_EVENT_GUEST_CRASHLOADED, + QEMU_PROCESS_EVENT_MEMORY_FAILURE, =20 QEMU_PROCESS_EVENT_LAST } qemuProcessEventType; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8ef812cd94..aecd947836 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4292,6 +4292,59 @@ processGuestCrashloadedEvent(virQEMUDriverPtr driver, } =20 =20 +static void +processMemoryFailureEvent(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuMonitorEventMemoryFailurePtr mfp) +{ + virObjectEventPtr event =3D NULL; + virDomainMemoryFailureRecipientType recipient; + virDomainMemoryFailureActionType action; + virDomainMemoryFailureFlags flags; + + switch (mfp->recipient) { + case QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_HYPERVISOR: + recipient =3D VIR_DOMAIN_EVENT_MEMORY_FAILURE_RECIPIENT_HYPERVISOR; + break; + case QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_GUEST: + recipient =3D VIR_DOMAIN_EVENT_MEMORY_FAILURE_RECIPIENT_GUEST; + break; + case QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_LAST: + default: + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("requested unknown memory failure recipient")); + return; + } + + switch (mfp->action) { + case QEMU_MONITOR_MEMORY_FAILURE_ACTION_IGNORE: + action =3D VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_IGNORE; + break; + case QEMU_MONITOR_MEMORY_FAILURE_ACTION_INJECT: + action =3D VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_INJECT; + break; + case QEMU_MONITOR_MEMORY_FAILURE_ACTION_FATAL: + action =3D VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_FATAL; + break; + case QEMU_MONITOR_MEMORY_FAILURE_ACTION_RESET: + action =3D VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_RESET; + break; + case QEMU_MONITOR_MEMORY_FAILURE_ACTION_LAST: + default: + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("requested unknown memory failure action")); + return; + } + + flags.action_required =3D mfp->action_required; + flags.recursive =3D mfp->recursive; + event =3D virDomainEventMemoryFailureNewFromObj(vm, recipient, action, + &flags); + + virObjectEventStateQueue(driver->domainEventState, event); +} + + static void qemuProcessEventHandler(void *data, void *opaque) { struct qemuProcessEvent *processEvent =3D data; @@ -4341,6 +4394,10 @@ static void qemuProcessEventHandler(void *data, void= *opaque) case QEMU_PROCESS_EVENT_GUEST_CRASHLOADED: processGuestCrashloadedEvent(driver, vm); break; + case QEMU_PROCESS_EVENT_MEMORY_FAILURE: + processMemoryFailureEvent(driver, vm, processEvent->data); + break; + case QEMU_PROCESS_EVENT_LAST: break; } diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 8c991fefbb..189b789bb8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -159,7 +159,6 @@ static int qemuMonitorOnceInit(void) =20 VIR_ONCE_GLOBAL_INIT(qemuMonitor); =20 - VIR_ENUM_IMPL(qemuMonitorMigrationStatus, QEMU_MONITOR_MIGRATION_STATUS_LAST, "inactive", "setup", @@ -197,6 +196,14 @@ VIR_ENUM_IMPL(qemuMonitorDumpStatus, "none", "active", "completed", "failed", ); =20 +VIR_ENUM_IMPL(qemuMonitorMemoryFailureRecipient, + QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_LAST, + "hypervisor", "guest"); + +VIR_ENUM_IMPL(qemuMonitorMemoryFailureAction, + QEMU_MONITOR_MEMORY_FAILURE_ACTION_LAST, + "ignore", "inject", + "fatal", "reset"); =20 #if DEBUG_RAW_IO static char * @@ -1428,6 +1435,18 @@ qemuMonitorEmitSpiceMigrated(qemuMonitorPtr mon) =20 =20 int +qemuMonitorEmitMemoryFailure(qemuMonitorPtr mon, + qemuMonitorEventMemoryFailurePtr mfp) +{ + int ret =3D -1; + + QEMU_MONITOR_CALLBACK(mon, ret, domainMemoryFailure, mon->vm, mfp); + + return ret; +} + + +int qemuMonitorEmitMigrationStatus(qemuMonitorPtr mon, int status) { diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index a744c8975b..17ba006a2f 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -340,6 +340,40 @@ typedef int (*qemuMonitorDomainGuestCrashloadedCallbac= k)(qemuMonitorPtr mon, virDomainObjPtr v= m, void *opaque); =20 +typedef enum { + QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_HYPERVISOR, + QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_GUEST, + + QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_LAST +} qemuMonitorMemoryFailureRecipient; + +VIR_ENUM_DECL(qemuMonitorMemoryFailureRecipient); + +typedef enum { + QEMU_MONITOR_MEMORY_FAILURE_ACTION_IGNORE, + QEMU_MONITOR_MEMORY_FAILURE_ACTION_INJECT, + QEMU_MONITOR_MEMORY_FAILURE_ACTION_FATAL, + QEMU_MONITOR_MEMORY_FAILURE_ACTION_RESET, + + QEMU_MONITOR_MEMORY_FAILURE_ACTION_LAST +} qemuMonitorMemoryFailureAction; + +VIR_ENUM_DECL(qemuMonitorMemoryFailureAction); + +typedef struct _qemuMonitorEventMemoryFailure qemuMonitorEventMemoryFailur= e; +typedef qemuMonitorEventMemoryFailure *qemuMonitorEventMemoryFailurePtr; +struct _qemuMonitorEventMemoryFailure { + qemuMonitorMemoryFailureRecipient recipient; + qemuMonitorMemoryFailureAction action; + bool action_required; + bool recursive; +}; + +typedef int (*qemuMonitorDomainMemoryFailureCallback)(qemuMonitorPtr mon, + virDomainObjPtr vm, + qemuMonitorEventMemo= ryFailurePtr mfp, + void *opaque); + typedef struct _qemuMonitorCallbacks qemuMonitorCallbacks; typedef qemuMonitorCallbacks *qemuMonitorCallbacksPtr; struct _qemuMonitorCallbacks { @@ -376,6 +410,7 @@ struct _qemuMonitorCallbacks { qemuMonitorDomainPRManagerStatusChangedCallback domainPRManagerStatusC= hanged; qemuMonitorDomainRdmaGidStatusChangedCallback domainRdmaGidStatusChang= ed; qemuMonitorDomainGuestCrashloadedCallback domainGuestCrashloaded; + qemuMonitorDomainMemoryFailureCallback domainMemoryFailure; }; =20 qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm, @@ -475,6 +510,10 @@ int qemuMonitorEmitSerialChange(qemuMonitorPtr mon, const char *devAlias, bool connected); int qemuMonitorEmitSpiceMigrated(qemuMonitorPtr mon); + +int qemuMonitorEmitMemoryFailure(qemuMonitorPtr mon, + qemuMonitorEventMemoryFailurePtr mfp); + int qemuMonitorEmitMigrationStatus(qemuMonitorPtr mon, int status); int qemuMonitorEmitMigrationPass(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 26ac499fc5..8e2659dc21 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -112,6 +112,7 @@ static void qemuMonitorJSONHandleBlockThreshold(qemuMon= itorPtr mon, virJSONValue static void qemuMonitorJSONHandleDumpCompleted(qemuMonitorPtr mon, virJSON= ValuePtr data); static void qemuMonitorJSONHandlePRManagerStatusChanged(qemuMonitorPtr mon= , virJSONValuePtr data); static void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitorPtr mon, = virJSONValuePtr data); +static void qemuMonitorJSONHandleMemoryFailure(qemuMonitorPtr mon, virJSON= ValuePtr data); =20 typedef struct { const char *type; @@ -132,6 +133,7 @@ static qemuEventHandler eventHandlers[] =3D { { "GUEST_CRASHLOADED", qemuMonitorJSONHandleGuestCrashloaded, }, { "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, }, { "JOB_STATUS_CHANGE", qemuMonitorJSONHandleJobStatusChange, }, + { "MEMORY_FAILURE", qemuMonitorJSONHandleMemoryFailure, }, { "MIGRATION", qemuMonitorJSONHandleMigrationStatus, }, { "MIGRATION_PASS", qemuMonitorJSONHandleMigrationPass, }, { "NIC_RX_FILTER_CHANGED", qemuMonitorJSONHandleNicRxFilterChanged, }, @@ -1336,6 +1338,54 @@ qemuMonitorJSONHandleSpiceMigrated(qemuMonitorPtr mo= n, =20 =20 static void +qemuMonitorJSONHandleMemoryFailure(qemuMonitorPtr mon, + virJSONValuePtr data) +{ + virJSONValuePtr flagsjson =3D virJSONValueObjectGetObject(data, "flags= "); + const char *str; + int recipient; + int action; + bool ar =3D false; + bool recursive =3D false; + qemuMonitorEventMemoryFailurePtr mfp; + + if (!(str =3D virJSONValueObjectGetString(data, "recipient"))) { + VIR_WARN("missing recipient in memory failure event"); + return; + } + + recipient =3D qemuMonitorMemoryFailureRecipientTypeFromString(str); + if (recipient =3D=3D -1) { + VIR_WARN("unknown recipient '%s' in memory_failure event", str); + return; + } + + if (!(str =3D virJSONValueObjectGetString(data, "action"))) { + VIR_WARN("missing action in memory failure event"); + return; + } + + action =3D qemuMonitorMemoryFailureActionTypeFromString(str); + if (action =3D=3D -1) { + VIR_WARN("unknown action '%s' in memory_failure event", str); + return; + } + + if (flagsjson) { + virJSONValueObjectGetBoolean(flagsjson, "action-required", &ar); + virJSONValueObjectGetBoolean(flagsjson, "recursive", &recursive); + } + + mfp =3D g_new0(qemuMonitorEventMemoryFailure, 1); + mfp->recipient =3D recipient; + mfp->action =3D action; + mfp->action_required =3D ar; + mfp->recursive =3D recursive; + qemuMonitorEmitMemoryFailure(mon, mfp); +} + + +static void qemuMonitorJSONHandleMigrationStatus(qemuMonitorPtr mon, virJSONValuePtr data) { diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 6b5de29fdb..abcbab0f06 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1878,6 +1878,33 @@ qemuProcessHandleGuestCrashloaded(qemuMonitorPtr mon= G_GNUC_UNUSED, } =20 =20 +static int +qemuProcessHandleMemoryFailure(qemuMonitorPtr mon G_GNUC_UNUSED, + virDomainObjPtr vm, + qemuMonitorEventMemoryFailurePtr mfp, + void *opaque) +{ + virQEMUDriverPtr driver =3D opaque; + struct qemuProcessEvent *processEvent; + + virObjectLock(vm); + processEvent =3D g_new0(struct qemuProcessEvent, 1); + + processEvent->eventType =3D QEMU_PROCESS_EVENT_MEMORY_FAILURE; + processEvent->data =3D mfp; + processEvent->vm =3D virObjectRef(vm); + + if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) { + virObjectUnref(vm); + qemuProcessEventFree(processEvent); + } + + virObjectUnlock(vm); + + return 0; +} + + static qemuMonitorCallbacks monitorCallbacks =3D { .eofNotify =3D qemuProcessHandleMonitorEOF, .errorNotify =3D qemuProcessHandleMonitorError, @@ -1910,6 +1937,7 @@ static qemuMonitorCallbacks monitorCallbacks =3D { .domainPRManagerStatusChanged =3D qemuProcessHandlePRManagerStatusChan= ged, .domainRdmaGidStatusChanged =3D qemuProcessHandleRdmaGidStatusChanged, .domainGuestCrashloaded =3D qemuProcessHandleGuestCrashloaded, + .domainMemoryFailure =3D qemuProcessHandleMemoryFailure, }; =20 static void diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon= _dispatch.c index 32ebcd8f36..45a8ab3c05 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -1302,6 +1302,38 @@ remoteRelayDomainEventBlockThreshold(virConnectPtr c= onn, } =20 =20 +static int +remoteRelayDomainEventMemoryFailure(virConnectPtr conn, + virDomainPtr dom, + virDomainMemoryFailureRecipientType re= cipient, + virDomainMemoryFailureActionType actio= n, + virDomainMemoryFailureFlagsPtr flags, + void *opaque) +{ + daemonClientEventCallbackPtr callback =3D opaque; + remote_domain_event_memory_failure_msg data; + + if (callback->callbackID < 0 || + !remoteRelayDomainEventCheckACL(callback->client, conn, dom)) + return -1; + + /* build return data */ + memset(&data, 0, sizeof(data)); + data.callbackID =3D callback->callbackID; + data.recipient =3D recipient; + data.action =3D action; + data.flags.action_required =3D flags->action_required; + data.flags.recursive =3D flags->recursive; + make_nonnull_domain(&data.dom, dom); + + remoteDispatchObjectEventSend(callback->client, remoteProgram, + REMOTE_PROC_DOMAIN_EVENT_MEMORY_FAILURE, + (xdrproc_t)xdr_remote_domain_event_memor= y_failure_msg, &data); + + return 0; +} + + static virConnectDomainEventGenericCallback domainEventCallbacks[] =3D { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot), @@ -1328,6 +1360,7 @@ static virConnectDomainEventGenericCallback domainEve= ntCallbacks[] =3D { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemovalFailed), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMetadataChange), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockThreshold), + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMemoryFailure), }; =20 G_STATIC_ASSERT(G_N_ELEMENTS(domainEventCallbacks) =3D=3D VIR_DOMAIN_EVENT= _ID_LAST); diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index d318224605..5b29161a22 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -405,6 +405,11 @@ remoteDomainBuildEventBlockThreshold(virNetClientProgr= amPtr prog, void *evdata, void *opaque); =20 static void +remoteDomainBuildEventMemoryFailure(virNetClientProgramPtr prog, + virNetClientPtr client, + void *evdata, void *opaque); + +static void remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog G_GNU= C_UNUSED, virNetClientPtr client G_GNUC_UNU= SED, void *evdata, void *opaque); @@ -615,6 +620,10 @@ static virNetClientProgramEvent remoteEvents[] =3D { remoteDomainBuildEventBlockThreshold, sizeof(remote_domain_event_block_threshold_msg), (xdrproc_t)xdr_remote_domain_event_block_threshold_msg }, + { REMOTE_PROC_DOMAIN_EVENT_MEMORY_FAILURE, + remoteDomainBuildEventMemoryFailure, + sizeof(remote_domain_event_memory_failure_msg), + (xdrproc_t)xdr_remote_domain_event_memory_failure_msg }, }; =20 static void @@ -5440,6 +5449,32 @@ remoteDomainBuildEventBlockThreshold(virNetClientPro= gramPtr prog G_GNUC_UNUSED, } =20 =20 +static void +remoteDomainBuildEventMemoryFailure(virNetClientProgramPtr prog G_GNUC_UNU= SED, + virNetClientPtr client G_GNUC_UNUSED, + void *evdata, void *opaque) +{ + virConnectPtr conn =3D opaque; + remote_domain_event_memory_failure_msg *msg =3D evdata; + struct private_data *priv =3D conn->privateData; + virDomainPtr dom; + virDomainMemoryFailureFlags flags; + virObjectEventPtr event =3D NULL; + + if (!(dom =3D get_nonnull_domain(conn, msg->dom))) + return; + + flags.action_required =3D msg->flags.action_required; + flags.recursive =3D msg->flags.recursive; + event =3D virDomainEventMemoryFailureNewFromDom(dom, msg->recipient, + msg->action, &flags); + + virObjectUnref(dom); + + virObjectEventStateQueueRemote(priv->eventState, event, msg->callbackI= D); +} + + static int remoteStreamSend(virStreamPtr st, const char *data, diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index f4d6147676..a3fda24807 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3469,6 +3469,19 @@ struct remote_domain_event_callback_metadata_change_= msg { remote_string nsuri; }; =20 +struct remote_domain_event_memory_failure_flags { + int action_required; + int recursive; +}; + +struct remote_domain_event_memory_failure_msg { + int callbackID; + remote_nonnull_domain dom; + int recipient; + int action; + remote_domain_event_memory_failure_flags flags; +}; + struct remote_connect_secret_event_register_any_args { int eventID; remote_secret secret; @@ -6668,5 +6681,11 @@ enum remote_procedure { * @priority: high * @acl: domain:read */ - REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC =3D 422 + REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC =3D 422, + + /** + * @generate: both + * @acl: none + */ + REMOTE_PROC_DOMAIN_EVENT_MEMORY_FAILURE =3D 423 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index bae0f0b545..1b74fb330d 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2862,6 +2862,17 @@ struct remote_domain_event_callback_metadata_change_= msg { int type; remote_string nsuri; }; +struct remote_domain_event_memory_failure_flags { + int action_required; + int recursive; +}; +struct remote_domain_event_memory_failure_msg { + int callbackID; + remote_nonnull_domain dom; + int recipient; + int action; + remote_domain_event_memory_failure_flags flags; +}; struct remote_connect_secret_event_register_any_args { int eventID; remote_secret secret; @@ -3558,4 +3569,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_AGENT_SET_RESPONSE_TIMEOUT =3D 420, REMOTE_PROC_DOMAIN_BACKUP_BEGIN =3D 421, REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC =3D 422, + REMOTE_PROC_DOMAIN_EVENT_MEMORY_FAILURE =3D 423, }; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 8f11393197..7c6b19a54b 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -13590,6 +13590,41 @@ virshEventBlockThresholdPrint(virConnectPtr conn G= _GNUC_UNUSED, } =20 =20 +VIR_ENUM_DECL(virshEventMemoryFailureRecipientType); +VIR_ENUM_IMPL(virshEventMemoryFailureRecipientType, + VIR_DOMAIN_EVENT_MEMORY_FAILURE_RECIPIENT_LAST, + N_("hypervisor"), + N_("guest")); + +VIR_ENUM_DECL(virshEventMemoryFailureActionType); +VIR_ENUM_IMPL(virshEventMemoryFailureActionType, + VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_LAST, + N_("ignore"), + N_("inject"), + N_("fatal"), + N_("reset")); + +static void +virshEventMemoryFailurePrint(virConnectPtr conn G_GNUC_UNUSED, + virDomainPtr dom, + virDomainMemoryFailureRecipientType recipient, + virDomainMemoryFailureActionType action, + virDomainMemoryFailureFlagsPtr flags, + void *opaque) +{ + g_auto(virBuffer) buf =3D VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&buf, _("event 'memory-failure' for domain %s:\n" + "recipient: %s\naction: %s\nflags:\n" + "\taction required: %d\n\trecursive: %d\n"), + virDomainGetName(dom), + UNKNOWNSTR(virshEventMemoryFailureRecipientTypeTypeT= oString(recipient)), + UNKNOWNSTR(virshEventMemoryFailureActionTypeTypeToSt= ring(action)), + !!(flags->action_required), !!(flags->recursive)); + virshEventPrint(opaque, &buf); +} + + virshDomainEventCallback virshDomainEventCallbacks[] =3D { { "lifecycle", VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), }, @@ -13639,6 +13674,8 @@ virshDomainEventCallback virshDomainEventCallbacks[= ] =3D { VIR_DOMAIN_EVENT_CALLBACK(virshEventMetadataChangePrint), }, { "block-threshold", VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockThresholdPrint), }, + { "memory-failure", + VIR_DOMAIN_EVENT_CALLBACK(virshEventMemoryFailurePrint), }, }; G_STATIC_ASSERT(VIR_DOMAIN_EVENT_ID_LAST =3D=3D G_N_ELEMENTS(virshDomainEv= entCallbacks)); =20 --=20 2.11.0