From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58573) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xb2yi-0005QT-Jq for qemu-devel@nongnu.org; Mon, 06 Oct 2014 03:45:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Xb2yc-0003Z1-AH for qemu-devel@nongnu.org; Mon, 06 Oct 2014 03:45:08 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57445) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xb2yc-0003Y5-3q for qemu-devel@nongnu.org; Mon, 06 Oct 2014 03:45:02 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s967j1a9024162 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Mon, 6 Oct 2014 03:45:01 -0400 From: Igor Mammedov Date: Mon, 6 Oct 2014 07:44:51 +0000 Message-Id: <1412581491-31656-3-git-send-email-imammedo@redhat.com> In-Reply-To: <1412581491-31656-1-git-send-email-imammedo@redhat.com> References: <1412581491-31656-1-git-send-email-imammedo@redhat.com> Subject: [Qemu-devel] [PATCH 2/2] guest-agent: preserve online/offline state of VCPUs on guest reboot List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: lersek@redhat.com Fixes issue when CPU was offlined via libvirt using command: virsh setvcpus --guest myguest NR_CPUS but it became onlined again after guest was rebooted. Fix issue by storing current state of CPUs online state on persistent storage when GA is being stopped and restore it when it's started at system boot time. Signed-off-by: Igor Mammedov --- qga/main.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/qga/main.c b/qga/main.c index 5afba01..1173ca9 100644 --- a/qga/main.c +++ b/qga/main.c @@ -32,6 +32,7 @@ #include "qapi/qmp/dispatch.h" #include "qga/channel.h" #include "qemu/bswap.h" +#include "qga-qmp-commands.h" #ifdef _WIN32 #include "qga/service-win32.h" #include "qga/vss-win32.h" @@ -57,6 +58,7 @@ #define QGA_FSFREEZE_HOOK_DEFAULT CONFIG_QEMU_CONFDIR "/fsfreeze-hook" #endif #define QGA_SENTINEL_BYTE 0xFF +#define QGA_CPU_STATE_GROUP "CPU online states" static struct { const char *state_dir; @@ -66,6 +68,7 @@ static struct { typedef struct GAPersistentState { #define QGA_PSTATE_DEFAULT_FD_COUNTER 1000 int64_t fd_counter; + GuestLogicalProcessorList *vcpus; } GAPersistentState; struct GAState { @@ -770,6 +773,40 @@ static void persistent_state_from_keyfile(GAPersistentState *pstate, pstate->fd_counter = g_key_file_get_integer(keyfile, "global", "fd_counter", NULL); } + + if (g_key_file_has_group(keyfile, QGA_CPU_STATE_GROUP)) { + bool state; + char **cpu_id_str; + GuestLogicalProcessor *vcpu; + GuestLogicalProcessorList *entry; + GuestLogicalProcessorList *head, **link; + char **cpus_list = g_key_file_get_keys(keyfile, QGA_CPU_STATE_GROUP, + NULL, NULL); + + head = NULL; + link = &head; + for (cpu_id_str = cpus_list; *cpu_id_str; ++cpu_id_str) { + state = g_key_file_get_boolean(keyfile, QGA_CPU_STATE_GROUP, + *cpu_id_str, NULL); + + vcpu = g_malloc0(sizeof *vcpu); + vcpu->logical_id = g_ascii_strtoll(*cpu_id_str, NULL, 0); + vcpu->online = state; + vcpu->has_can_offline = true; + + entry = g_malloc0(sizeof *entry); + entry->value = vcpu; + + *link = entry; + link = &entry->next; + } + pstate->vcpus = head; + + g_strfreev(cpus_list); + } + if (pstate->vcpus == NULL) { + pstate->vcpus = qmp_guest_get_vcpus(NULL); + } } static void persistent_state_to_keyfile(const GAPersistentState *pstate, @@ -779,6 +816,27 @@ static void persistent_state_to_keyfile(const GAPersistentState *pstate, g_assert(keyfile); g_key_file_set_integer(keyfile, "global", "fd_counter", pstate->fd_counter); + + if (pstate->vcpus) { + GuestLogicalProcessorList *vcpus = pstate->vcpus; + + while (vcpus != NULL) { + char *logical_id; + GuestLogicalProcessor *vcpu = vcpus->value; + + if (vcpu->can_offline == false) { + vcpus = vcpus->next; + continue; + } + + logical_id = g_strdup_printf("%" PRId64, vcpu->logical_id); + g_key_file_set_boolean(keyfile, QGA_CPU_STATE_GROUP, + logical_id, vcpu->online); + g_free(logical_id); + + vcpus = vcpus->next; + } + } } static gboolean write_persistent_state(const GAPersistentState *pstate, @@ -820,6 +878,47 @@ out: return ret; } +static void ga_clean_vcpu_pstate(GAPersistentState *pstate) +{ + if (pstate->vcpus) { + qapi_free_GuestLogicalProcessorList(pstate->vcpus); + pstate->vcpus = NULL; + } +} + +static void ga_clean_pstate(GAPersistentState *pstate) +{ + ga_clean_vcpu_pstate(pstate); +} + +#if defined(__linux__) + +static void ga_update_vcpu_pstate(GAPersistentState *pstate, const char *path) +{ + Error *local_err = NULL; + + ga_clean_vcpu_pstate(pstate); + pstate->vcpus = qmp_guest_get_vcpus(&local_err); + + if (local_err != NULL) { + g_critical("%s", error_get_pretty(local_err)); + error_free(local_err); + return; + } + + if (!write_persistent_state(pstate, path)) { + g_critical("failed to commit CPU persistent state to disk"); + } +} + +#else + +static void ga_update_vcpu_pstate(GAPersistentState *pstate, const char *path) +{ +} + +#endif + static gboolean read_persistent_state(GAPersistentState *pstate, const gchar *path, gboolean frozen) { @@ -878,6 +977,7 @@ static gboolean read_persistent_state(GAPersistentState *pstate, } persistent_state_from_keyfile(pstate, keyfile); + qmp_guest_set_vcpus(pstate->vcpus, &error_abort); out: if (keyfile) { @@ -1185,6 +1285,8 @@ int main(int argc, char **argv) ga_command_state_cleanup_all(ga_state->command_state); ga_channel_free(ga_state->channel); + ga_update_vcpu_pstate(&ga_state->pstate, ga_state->pstate_filepath); + ga_clean_pstate(&ga_state->pstate); if (daemonize) { unlink(pid_filepath); -- 1.8.3.1