From patchwork Sat Jul 9 04:22:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Corneliu ZUZU X-Patchwork-Id: 9221995 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 272F160467 for ; Sat, 9 Jul 2016 04:25:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 169F328619 for ; Sat, 9 Jul 2016 04:25:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0B2F428625; Sat, 9 Jul 2016 04:25:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id E81C928619 for ; Sat, 9 Jul 2016 04:25:27 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bLjnJ-0003GQ-Kl; Sat, 09 Jul 2016 04:23:09 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bLjnI-0003G8-33 for xen-devel@lists.xen.org; Sat, 09 Jul 2016 04:23:08 +0000 Received: from [85.158.137.68] by server-13.bemta-3.messagelabs.com id 04/41-20705-B2C70875; Sat, 09 Jul 2016 04:23:07 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrNIsWRWlGSWpSXmKPExsUSfTxjoa5WTUO 4wdSp8hZLPi5mcWD0OLr7N1MAYxRrZl5SfkUCa0ZX0yXWgku1FZNer2JqYLyc0MXIySEk4C6x +PE51i5GLiB7DaPE/Fs7GSGck4wSjzafYYeocpO49+AVE0RiHaPExKXHmUASbALaEucO3QOzR QSkJa59vgzWzSzwh1Fi5+0eNpCEsECqxPaHTWCTWARUJb63/wWzeQVcJLp+djN3MXJwSAjISS y4kA4S5hRwlTj39jUrxGIXiRv7JoHNlxDIkVj5bBY7RLmUxP9WJZBVEgJLWSSalz5mhaiRkXg 08SbbBEahBYwMqxjVi1OLylKLdI30kooy0zNKchMzc3QNDYz1clOLixPTU3MSk4r1kvNzNzEC A7GegYFxB+OpZudDjJIcTEqivBdsG8KF+JLyUyozEosz4otKc1KLDzHKcHAoSfCyVAPlBItS0 1Mr0jJzgDEBk5bg4FES4b1TBZTmLS5IzC3OTIdInWJUlBLnXQCSEABJZJTmwbXB4vASo6yUMC 8jAwODEE9BalFuZgmq/CtGcQ5GJWHehyBTeDLzSuCmvwJazAS02CCgHmRxSSJCSqqBscjp/Me Wx3OnH0o7uVql6IJn1mOJCDHlx18vTpmT7aD2sc2sL+7K0a9HM1/P/rhIQuDCy93bS++YKJXf SriX+l/SK8K/+IPFYdnL5xtz2G/NirBs/nCetdTavUc28p/hw3sycgeu9s0XWjXbeMn+J9vfr jq86caDH4mfW1iklA7/dOKbFa7wfbMSS3FGoqEWc1FxIgACXctNvgIAAA== X-Env-Sender: czuzu@bitdefender.com X-Msg-Ref: server-3.tower-31.messagelabs.com!1468038186!49609263!1 X-Originating-IP: [91.199.104.161] X-SpamReason: No, hits=0.5 required=7.0 tests=BODY_RANDOM_LONG X-StarScan-Received: X-StarScan-Version: 8.46; banners=-,-,- X-VirusChecked: Checked Received: (qmail 12188 invoked from network); 9 Jul 2016 04:23:06 -0000 Received: from mx01.bbu.dsd.mx.bitdefender.com (HELO mx01.bbu.dsd.mx.bitdefender.com) (91.199.104.161) by server-3.tower-31.messagelabs.com with DHE-RSA-AES128-GCM-SHA256 encrypted SMTP; 9 Jul 2016 04:23:06 -0000 Received: (qmail 12197 invoked from network); 9 Jul 2016 07:23:05 +0300 Received: from unknown (HELO mx-sr.buh.bitdefender.com) (10.17.80.103) by mx01.bbu.dsd.mx.bitdefender.com with AES256-GCM-SHA384 encrypted SMTP; 9 Jul 2016 07:23:05 +0300 Received: from smtp03.buh.bitdefender.org (unknown [10.17.80.77]) by mx-sr.buh.bitdefender.com (Postfix) with ESMTP id 631357FC01 for ; Sat, 9 Jul 2016 07:23:05 +0300 (EEST) Received: (qmail 4628 invoked from network); 9 Jul 2016 07:23:05 +0300 Received: from 188-24-34-246.rdsnet.ro (HELO localhost.localdomain) (czuzu@bitdefender.com@188.24.34.246) by smtp03.buh.bitdefender.org with SMTP; 9 Jul 2016 07:23:05 +0300 From: Corneliu ZUZU To: xen-devel@lists.xen.org Date: Sat, 9 Jul 2016 07:22:23 +0300 Message-Id: <1468038143-7071-1-git-send-email-czuzu@bitdefender.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1468037509-6428-1-git-send-email-czuzu@bitdefender.com> References: <1468037509-6428-1-git-send-email-czuzu@bitdefender.com> X-BitDefender-Scanner: Clean, Agent: BitDefender qmail 3.1.6 on smtp03.buh.bitdefender.org, sigver: 7.66242 X-BitDefender-Spam: No (0) X-BitDefender-SpamStamp: Build: [Engines: 2.15.6.911, Dats: 425852, Stamp: 3], Multi: [Enabled, t: (0.000012, 0.012548)], BW: [Enabled, t: (0.000006,0.000001)], RBL DNSBL: [Disabled], APM: [Enabled, Score: 500, t: (0.010917), Flags: 85D2ED72; NN_NO_CONTENT_TYPE; NN_LEGIT_SUMM_400_WORDS; NN_NO_LINK_NMD; NN_LEGIT_BITDEFENDER; NN_LEGIT_S_SQARE_BRACKETS; NN_LEGIT_MAILING_LIST_TO], SGN: [Enabled, t: (0.022293)], URL: [Enabled, t: (0.000005)], RTDA: [Enabled, t: (0.024371), Hit: No, Details: v2.3.10; Id: 2m1ghm2.1an4umg8t.2jmk], total: 0(775) X-BitDefender-CF-Stamp: none Cc: Tamas K Lengyel , Razvan Cojocaru , George Dunlap , Andrew Cooper , Paul Durrant , Jan Beulich Subject: [Xen-devel] [PATCH 14/16] x86/monitor: clarify separation between monitor subsys and vm-event as a whole X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP Move fields in arch_vm_event in a structure called arch_vm_event_monitor and refactor arch_vm_event to only hold a pointer to an instance of the aforementioned. Done for a number of reasons: * to make the separation of monitor resources from other vm-event resources clearly visible * to be able to selectively allocate/free monitor-only resources in monitor init & cleanup stubs * did _not_ do a v->arch.vm_event -to- v->arch.monitor transformation because we want the guarantee of not occupying more than 1 pointer in arch_vcpu, i.e. if in the future e.g. paging vm-events would need per-vcpu resources, one would make an arch_vm_event_paging structure and add a pointer to an instance of it as a arch_vm_event.paging field, in which case we will still have only 1 pointer (arch_vm_event) consuming memory in arch_vcpu for vm-event resources Note also that this breaks the old implication 'vm-event initialized -> monitor resources (which were in arch_vm_event) initialized', so 2 extra checks on monitor_domain_initialised() had to be added: i) in vm_event_resume() before calling monitor_ctrlreg_write_resume(), also an ASSERT in monitor_ctrlreg_write_resume() ii) in vm_event_resume() before calling mem_access_resume(), also an ASSERT on that code-path in p2m_mem_access_emulate_check() Finally, also note that the definition of arch_vm_event had to be moved to asm-x86/domain.h due to a cyclic header dependency it caused between asm-x86/vm_event.h and asm-x86/monitor.h. Signed-off-by: Corneliu ZUZU --- xen/arch/x86/hvm/emulate.c | 8 +++--- xen/arch/x86/hvm/hvm.c | 31 ++++++++++++------------ xen/arch/x86/mm/p2m.c | 7 ++++-- xen/arch/x86/monitor.c | 55 ++++++++++++++++++++++++++++++++++++------ xen/arch/x86/vm_event.c | 17 +++++++++++-- xen/common/vm_event.c | 17 +++++++++++++ xen/include/asm-x86/domain.h | 15 ++++++++++++ xen/include/asm-x86/monitor.h | 7 ++++++ xen/include/asm-x86/vm_event.h | 13 +++------- 9 files changed, 128 insertions(+), 42 deletions(-) diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index a0094e9..7a9c6af 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -76,10 +76,10 @@ static int set_context_data(void *buffer, unsigned int size) if ( unlikely(monitor_domain_initialised(curr->domain)) ) { - unsigned int safe_size = - min(size, curr->arch.vm_event->emul_read_data.size); + struct arch_vm_event_monitor *vem = curr->arch.vm_event->monitor; + unsigned int safe_size = min(size, vem->emul_read_data.size); - memcpy(buffer, curr->arch.vm_event->emul_read_data.data, safe_size); + memcpy(buffer, vem->emul_read_data.data, safe_size); memset(buffer + safe_size, 0, size - safe_size); return X86EMUL_OKAY; } @@ -524,7 +524,7 @@ static int hvmemul_virtual_to_linear( * vm_event being triggered for repeated writes to a whole page. */ if ( unlikely(current->domain->arch.mem_access_emulate_each_rep) && - current->arch.vm_event->emulate_flags != 0 ) + current->arch.vm_event->monitor->emulate_flags != 0 ) max_reps = 1; /* diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 46fed33..1bfd9d4 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -65,7 +65,6 @@ #include #include #include -#include #include #include #include @@ -473,21 +472,21 @@ void hvm_do_resume(struct vcpu *v) if ( unlikely(monitor_domain_initialised(v->domain)) ) { - if ( unlikely(v->arch.vm_event->emulate_flags) ) + struct arch_vm_event_monitor *vem = v->arch.vm_event->monitor; + + if ( unlikely(vem->emulate_flags) ) { enum emul_kind kind = EMUL_KIND_NORMAL; - if ( v->arch.vm_event->emulate_flags & - VM_EVENT_FLAG_SET_EMUL_READ_DATA ) + if ( vem->emulate_flags & VM_EVENT_FLAG_SET_EMUL_READ_DATA ) kind = EMUL_KIND_SET_CONTEXT; - else if ( v->arch.vm_event->emulate_flags & - VM_EVENT_FLAG_EMULATE_NOWRITE ) + else if ( vem->emulate_flags & VM_EVENT_FLAG_EMULATE_NOWRITE ) kind = EMUL_KIND_NOWRITE; hvm_mem_access_emulate_one(kind, TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE); - v->arch.vm_event->emulate_flags = 0; + vem->emulate_flags = 0; } monitor_ctrlreg_write_data(v); @@ -2184,8 +2183,8 @@ int hvm_set_cr0(unsigned long value, bool_t may_defer) * The actual write will occur in monitor_ctrlreg_write_data(), if * permitted. */ - v->arch.vm_event->write_data.do_write.cr0 = 1; - v->arch.vm_event->write_data.cr0 = value; + v->arch.vm_event->monitor->write_data.do_write.cr0 = 1; + v->arch.vm_event->monitor->write_data.cr0 = value; return X86EMUL_OKAY; } @@ -2289,8 +2288,8 @@ int hvm_set_cr3(unsigned long value, bool_t may_defer) * The actual write will occur in monitor_ctrlreg_write_data(), if * permitted. */ - v->arch.vm_event->write_data.do_write.cr3 = 1; - v->arch.vm_event->write_data.cr3 = value; + v->arch.vm_event->monitor->write_data.do_write.cr3 = 1; + v->arch.vm_event->monitor->write_data.cr3 = value; return X86EMUL_OKAY; } @@ -2372,8 +2371,8 @@ int hvm_set_cr4(unsigned long value, bool_t may_defer) * The actual write will occur in monitor_ctrlreg_write_data(), if * permitted. */ - v->arch.vm_event->write_data.do_write.cr4 = 1; - v->arch.vm_event->write_data.cr4 = value; + v->arch.vm_event->monitor->write_data.do_write.cr4 = 1; + v->arch.vm_event->monitor->write_data.cr4 = value; return X86EMUL_OKAY; } @@ -3754,9 +3753,9 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t msr_content, * The actual write will occur in monitor_ctrlreg_write_data(), if * permitted. */ - v->arch.vm_event->write_data.do_write.msr = 1; - v->arch.vm_event->write_data.msr = msr; - v->arch.vm_event->write_data.value = msr_content; + v->arch.vm_event->monitor->write_data.do_write.msr = 1; + v->arch.vm_event->monitor->write_data.msr = msr; + v->arch.vm_event->monitor->write_data.value = msr_content; hvm_monitor_msr(msr, msr_content); return X86EMUL_OKAY; diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index 16733a4..92c0576 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -1591,12 +1591,15 @@ void p2m_mem_paging_resume(struct domain *d, vm_event_response_t *rsp) void p2m_mem_access_emulate_check(struct vcpu *v, const vm_event_response_t *rsp) { + ASSERT(monitor_domain_initialised(v->domain)); + /* Mark vcpu for skipping one instruction upon rescheduling. */ if ( rsp->flags & VM_EVENT_FLAG_EMULATE ) { xenmem_access_t access; bool_t violation = 1; const struct vm_event_mem_access *data = &rsp->u.mem_access; + struct arch_vm_event_monitor *vem = v->arch.vm_event->monitor; if ( p2m_get_mem_access(v->domain, _gfn(data->gfn), &access) == 0 ) { @@ -1639,10 +1642,10 @@ void p2m_mem_access_emulate_check(struct vcpu *v, } } - v->arch.vm_event->emulate_flags = violation ? rsp->flags : 0; + vem->emulate_flags = violation ? rsp->flags : 0; if ( (rsp->flags & VM_EVENT_FLAG_SET_EMUL_READ_DATA) ) - v->arch.vm_event->emul_read_data = rsp->data.emul_read_data; + vem->emul_read_data = rsp->data.emul_read_data; } } diff --git a/xen/arch/x86/monitor.c b/xen/arch/x86/monitor.c index 0763ed7..c3123bc 100644 --- a/xen/arch/x86/monitor.c +++ b/xen/arch/x86/monitor.c @@ -21,7 +21,6 @@ #include #include -#include #include static inline @@ -55,16 +54,43 @@ static inline void monitor_ctrlreg_disable_traps(struct domain *d) /* Implicitly serialized by the domctl lock. */ int monitor_init_domain(struct domain *d) { - if ( likely(!d->arch.monitor.msr_bitmap) ) + int rc = 0; + struct vcpu *v; + + /* Already initialised? */ + if ( unlikely(monitor_domain_initialised(d)) ) + return 0; + + /* Per-vcpu initializations. */ + for_each_vcpu(d, v) + { + ASSERT(v->arch.vm_event); + ASSERT(!v->arch.vm_event->monitor); + + v->arch.vm_event->monitor = xzalloc(struct arch_vm_event_monitor); + if ( unlikely(!v->arch.vm_event->monitor) ) + { + rc = -ENOMEM; + goto err; + } + } + + ASSERT(!d->arch.monitor.msr_bitmap); + d->arch.monitor.msr_bitmap = xzalloc(struct monitor_msr_bitmap); + if ( unlikely(!d->arch.monitor.msr_bitmap) ) { - d->arch.monitor.msr_bitmap = xzalloc(struct monitor_msr_bitmap); - if ( unlikely(!d->arch.monitor.msr_bitmap) ) - return -ENOMEM; + rc = -ENOMEM; + goto err; } d->monitor.initialised = 1; - return 0; +err: + if ( unlikely(rc) ) + /* On fail cleanup whatever resources have been partially allocated. */ + monitor_cleanup_domain(d); + + return rc; } /* @@ -73,9 +99,20 @@ int monitor_init_domain(struct domain *d) */ void monitor_cleanup_domain(struct domain *d) { + struct vcpu *v; + xfree(d->arch.monitor.msr_bitmap); d->arch.monitor.msr_bitmap = NULL; + for_each_vcpu(d, v) + { + if ( unlikely(!v->arch.vm_event || !v->arch.vm_event->monitor) ) + continue; + + xfree(v->arch.vm_event->monitor); + v->arch.vm_event->monitor = NULL; + } + monitor_ctrlreg_disable_traps(d); memset(&d->arch.monitor, 0, sizeof(d->arch.monitor)); @@ -88,6 +125,8 @@ void monitor_cleanup_domain(struct domain *d) void monitor_ctrlreg_write_resume(struct vcpu *v, vm_event_response_t *rsp) { + ASSERT(monitor_domain_initialised(v->domain)); + if ( rsp->flags & VM_EVENT_FLAG_DENY ) { struct monitor_write_data *w; @@ -98,7 +137,7 @@ void monitor_ctrlreg_write_resume(struct vcpu *v, vm_event_response_t *rsp) if ( !atomic_read(&v->vm_event_pause_count) ) return; - w = &v->arch.vm_event->write_data; + w = &v->arch.vm_event->monitor->write_data; switch ( rsp->reason ) { @@ -125,7 +164,7 @@ void monitor_ctrlreg_write_resume(struct vcpu *v, vm_event_response_t *rsp) void monitor_ctrlreg_write_data(struct vcpu *v) { - struct monitor_write_data *w = &v->arch.vm_event->write_data; + struct monitor_write_data *w = &v->arch.vm_event->monitor->write_data; if ( likely(!w->writes_pending) ) return; diff --git a/xen/arch/x86/vm_event.c b/xen/arch/x86/vm_event.c index e2b258b..20cb1b0 100644 --- a/xen/arch/x86/vm_event.c +++ b/xen/arch/x86/vm_event.c @@ -65,9 +65,22 @@ void vm_event_cleanup_domain(struct domain *d, struct vm_event_domain *ved) if ( &d->vm_event->monitor == ved ) monitor_cleanup_domain(d); - /* Per-vcpu uninitializations. */ + /* + * Per-vCPU: if all resources of all vm-event subsystems were freed, + * also free v->arch.vm_event. + */ for_each_vcpu ( d, v ) - vm_event_cleanup_vcpu_destroy(v); + { + if ( unlikely(!v->arch.vm_event) ) + continue; + + /* Are there resources of vm-event subsystems left unfreed? */ + if ( unlikely(v->arch.vm_event->monitor) ) + continue; + + xfree(v->arch.vm_event); + v->arch.vm_event = NULL; + } } void vm_event_toggle_singlestep(struct domain *d, struct vcpu *v) diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c index dafe7bf..c409b80 100644 --- a/xen/common/vm_event.c +++ b/xen/common/vm_event.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -397,11 +398,27 @@ void vm_event_resume(struct domain *d, struct vm_event_domain *ved) case VM_EVENT_REASON_MOV_TO_MSR: #endif case VM_EVENT_REASON_WRITE_CTRLREG: + if ( unlikely(!monitor_domain_initialised(d)) ) + { + printk(XENLOG_G_WARNING "Vm-event monitor subsystem not" + "initialized, cr-write ring response" + "ignored (hint: have you called" + "xc_monitor_enable()?).\n"); + continue; + } monitor_ctrlreg_write_resume(v, &rsp); break; #ifdef CONFIG_HAS_MEM_ACCESS case VM_EVENT_REASON_MEM_ACCESS: + if ( unlikely(!monitor_domain_initialised(d)) ) + { + printk(XENLOG_G_WARNING "Vm-event monitor subsystem not" + "initialized, mem-access ring response" + "ignored (hint: have you called" + "xc_monitor_enable()?).\n"); + continue; + } mem_access_resume(v, &rsp); break; #endif diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index ae1dcb4..7663da2 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #define has_32bit_shinfo(d) ((d)->arch.has_32bit_shinfo) @@ -503,6 +504,20 @@ typedef enum __packed { SMAP_CHECK_DISABLED, /* disable the check */ } smap_check_policy_t; +/* + * Should we emulate the next matching instruction on VCPU resume + * after a vm_event? + */ +struct arch_vm_event_monitor { + uint32_t emulate_flags; + struct vm_event_emul_read_data emul_read_data; + struct monitor_write_data write_data; +}; + +struct arch_vm_event { + struct arch_vm_event_monitor *monitor; +}; + struct arch_vcpu { /* diff --git a/xen/include/asm-x86/monitor.h b/xen/include/asm-x86/monitor.h index 4014f8d..11497ef 100644 --- a/xen/include/asm-x86/monitor.h +++ b/xen/include/asm-x86/monitor.h @@ -90,6 +90,13 @@ int monitor_init_domain(struct domain *d); void monitor_cleanup_domain(struct domain *d); +/* Called on vCPU destroy. */ +static inline void monitor_cleanup_vcpu_destroy(struct vcpu *v) +{ + ASSERT(v->arch.vm_event); + xfree(v->arch.vm_event->monitor); +} + void monitor_ctrlreg_write_resume(struct vcpu *v, vm_event_response_t *rsp); void monitor_ctrlreg_write_data(struct vcpu *v); diff --git a/xen/include/asm-x86/vm_event.h b/xen/include/asm-x86/vm_event.h index c1b82ab..3c14d4f 100644 --- a/xen/include/asm-x86/vm_event.h +++ b/xen/include/asm-x86/vm_event.h @@ -20,16 +20,7 @@ #define __ASM_X86_VM_EVENT_H__ #include - -/* - * Should we emulate the next matching instruction on VCPU resume - * after a vm_event? - */ -struct arch_vm_event { - uint32_t emulate_flags; - struct vm_event_emul_read_data emul_read_data; - struct monitor_write_data write_data; -}; +#include int vm_event_init_domain(struct domain *d, struct vm_event_domain *ved); @@ -41,6 +32,8 @@ static inline void vm_event_cleanup_vcpu_destroy(struct vcpu *v) if ( likely(!v->arch.vm_event) ) return; + monitor_cleanup_vcpu_destroy(v); + xfree(v->arch.vm_event); v->arch.vm_event = NULL; }