From patchwork Mon May 30 17:27:53 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sasha Levin X-Patchwork-Id: 830692 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p4UHTG2Q018765 for ; Mon, 30 May 2011 17:29:49 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757620Ab1E3R3X (ORCPT ); Mon, 30 May 2011 13:29:23 -0400 Received: from mail-wy0-f174.google.com ([74.125.82.174]:46736 "EHLO mail-wy0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757571Ab1E3R3M (ORCPT ); Mon, 30 May 2011 13:29:12 -0400 Received: by mail-wy0-f174.google.com with SMTP id 21so2766739wya.19 for ; Mon, 30 May 2011 10:29:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references; bh=FFykPo4uSwWrqscDG2UEDQHUsQlXuKV3ZL/OekpFdUU=; b=ilCRJd8OPfGzRWrNDqlEU61xMwGNwtan+YfBxc8n0qVX3+0aR3X8hsKhhIgjuv0pY6 0IT+1yLOhC0+ZjAW341zlM6xr+ZTxASH4k+4ivzUqRwhYdSTPzQKET3AGv8Am9qgZADa I+8P0ajDPd3I3S/l11AJk8Ogz3f8Q+inPRa1s= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=piH/hqL9KNG6JHJi01oWAg6BpofWZXUmC8zsM0xWVCk5fYrcDzpwv5RDaHyk/ZRrvV u7d4ObUlgVg9IxtN0vT+SuzDT6/IbW3hQx0HBwFGAXp0PYQ1v+TqlD+1kthgZceMP7Kl DlMeeh7ttTIJoJCEIhQmh0E1JWxwrVk2uJNR4= Received: by 10.227.12.15 with SMTP id v15mr2525951wbv.77.1306776552232; Mon, 30 May 2011 10:29:12 -0700 (PDT) Received: from localhost.localdomain (bzq-79-181-201-100.red.bezeqint.net [79.181.201.100]) by mx.google.com with ESMTPS id gb6sm3194848wbb.17.2011.05.30.10.29.10 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 30 May 2011 10:29:11 -0700 (PDT) From: Sasha Levin To: penberg@kernel.org Cc: kvm@vger.kernel.org, mingo@elte.hu, asias.hejun@gmail.com, gorcunov@gmail.com, prasadjoshi124@gmail.com, Sasha Levin Subject: [PATCH v2 3/8] kvm tools: Add APIs to allow pausing guests Date: Mon, 30 May 2011 20:27:53 +0300 Message-Id: <1306776478-29613-4-git-send-email-levinsasha928@gmail.com> X-Mailer: git-send-email 1.7.5.3 In-Reply-To: <1306776478-29613-1-git-send-email-levinsasha928@gmail.com> References: <1306776478-29613-1-git-send-email-levinsasha928@gmail.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 30 May 2011 17:29:49 +0000 (UTC) Allow pausing and unpausing guests running on the host. Pausing a guest means that none of the VCPU threads are running KVM_RUN until they are unpaused. The following API functions are added: void kvm__pause(void); void kvm__continue(void); void kvm__notify_paused(void); Signed-off-by: Sasha Levin --- tools/kvm/include/kvm/kvm-cpu.h | 1 + tools/kvm/include/kvm/kvm.h | 4 +++ tools/kvm/kvm-cpu.c | 20 +++++++++++--- tools/kvm/kvm-run.c | 4 +- tools/kvm/kvm.c | 54 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 7 deletions(-) diff --git a/tools/kvm/include/kvm/kvm-cpu.h b/tools/kvm/include/kvm/kvm-cpu.h index b2b6fce..4d99246 100644 --- a/tools/kvm/include/kvm/kvm-cpu.h +++ b/tools/kvm/include/kvm/kvm-cpu.h @@ -23,6 +23,7 @@ struct kvm_cpu { struct kvm_msrs *msrs; /* dynamically allocated */ u8 is_running; + u8 paused; }; struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id); diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h index 6a17362..d22a849 100644 --- a/tools/kvm/include/kvm/kvm.h +++ b/tools/kvm/include/kvm/kvm.h @@ -12,6 +12,7 @@ #define KVM_32BIT_GAP_START ((1ULL << 32) - KVM_32BIT_GAP_SIZE) #define SIGKVMEXIT (SIGRTMIN + 0) +#define SIGKVMPAUSE (SIGRTMIN + 1) struct kvm { int sys_fd; /* For system ioctls(), i.e. /dev/kvm */ @@ -50,6 +51,9 @@ bool kvm__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int s bool kvm__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write); bool kvm__register_mmio(u64 phys_addr, u64 phys_addr_len, void (*kvm_mmio_callback_fn)(u64 addr, u8 *data, u32 len, u8 is_write)); bool kvm__deregister_mmio(u64 phys_addr); +void kvm__pause(void); +void kvm__continue(void); +void kvm__notify_paused(void); /* * Debugging diff --git a/tools/kvm/kvm-cpu.c b/tools/kvm/kvm-cpu.c index de0591f..be0528b 100644 --- a/tools/kvm/kvm-cpu.c +++ b/tools/kvm/kvm-cpu.c @@ -383,11 +383,15 @@ void kvm_cpu__run(struct kvm_cpu *vcpu) die_perror("KVM_RUN failed"); } -static void kvm_cpu_exit_handler(int signum) +static void kvm_cpu_signal_handler(int signum) { - if (current_kvm_cpu->is_running) { - current_kvm_cpu->is_running = false; - pthread_kill(pthread_self(), SIGKVMEXIT); + if (signum == SIGKVMEXIT) { + if (current_kvm_cpu->is_running) { + current_kvm_cpu->is_running = false; + pthread_kill(pthread_self(), SIGKVMEXIT); + } + } else if (signum == SIGKVMPAUSE) { + current_kvm_cpu->paused = 1; } } @@ -400,12 +404,18 @@ int kvm_cpu__start(struct kvm_cpu *cpu) pthread_sigmask(SIG_BLOCK, &sigset, NULL); - signal(SIGKVMEXIT, kvm_cpu_exit_handler); + signal(SIGKVMEXIT, kvm_cpu_signal_handler); + signal(SIGKVMPAUSE, kvm_cpu_signal_handler); kvm_cpu__setup_cpuid(cpu); kvm_cpu__reset_vcpu(cpu); for (;;) { + if (cpu->paused) { + kvm__notify_paused(); + cpu->paused = 0; + } + kvm_cpu__run(cpu); switch (cpu->kvm_run->exit_reason) { diff --git a/tools/kvm/kvm-run.c b/tools/kvm/kvm-run.c index 48b8e70..761ac0d 100644 --- a/tools/kvm/kvm-run.c +++ b/tools/kvm/kvm-run.c @@ -47,8 +47,8 @@ #define MIN_RAM_SIZE_MB (64ULL) #define MIN_RAM_SIZE_BYTE (MIN_RAM_SIZE_MB << MB_SHIFT) -static struct kvm *kvm; -static struct kvm_cpu *kvm_cpus[KVM_NR_CPUS]; +struct kvm *kvm; +struct kvm_cpu *kvm_cpus[KVM_NR_CPUS]; __thread struct kvm_cpu *current_kvm_cpu; static u64 ram_size; diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c index 1d756e0..54e3203 100644 --- a/tools/kvm/kvm.c +++ b/tools/kvm/kvm.c @@ -6,6 +6,8 @@ #include "kvm/interrupt.h" #include "kvm/mptable.h" #include "kvm/util.h" +#include "kvm/mutex.h" +#include "kvm/kvm-cpu.h" #include @@ -25,6 +27,7 @@ #include #include #include +#include #define DEFINE_KVM_EXIT_REASON(reason) [reason] = #reason @@ -68,6 +71,11 @@ struct { { DEFINE_KVM_EXT(KVM_CAP_EXT_CPUID) }, }; +extern struct kvm *kvm; +extern struct kvm_cpu *kvm_cpus[KVM_NR_CPUS]; +static int pause_event; +static DEFINE_MUTEX(pause_lock); + static bool kvm__supports_extension(struct kvm *kvm, unsigned int extension) { int ret; @@ -575,3 +583,49 @@ void kvm__dump_mem(struct kvm *kvm, unsigned long addr, unsigned long size) p[n + 4], p[n + 5], p[n + 6], p[n + 7]); } } + +void kvm__pause(void) +{ + int i, paused_vcpus = 0; + + /* Check if the guest is running */ + if (!kvm_cpus[0] || kvm_cpus[0]->thread == 0) + return; + + mutex_lock(&pause_lock); + + pause_event = eventfd(0, 0); + if (pause_event < 0) + die("Failed creating pause notification event"); + for (i = 0; i < kvm->nrcpus; i++) + pthread_kill(kvm_cpus[i]->thread, SIGKVMPAUSE); + + while (paused_vcpus < kvm->nrcpus) { + u64 cur_read; + + if (read(pause_event, &cur_read, sizeof(cur_read)) < 0) + die("Failed reading pause event"); + paused_vcpus += cur_read; + } + close(pause_event); +} + +void kvm__continue(void) +{ + /* Check if the guest is running */ + if (!kvm_cpus[0] || kvm_cpus[0]->thread == 0) + return; + + mutex_unlock(&pause_lock); +} + +void kvm__notify_paused(void) +{ + u64 p = 1; + + if (write(pause_event, &p, sizeof(p)) < 0) + die("Failed notifying of paused VCPU."); + + mutex_lock(&pause_lock); + mutex_unlock(&pause_lock); +}