All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Dr. David Alan Gilbert (git)" <dgilbert@redhat.com>
To: qemu-devel@nongnu.org, quintela@redhat.com, peterx@redhat.com,
	marcel.apfelbaum@gmail.com, wei.w.wang@intel.com,
	yury-kotov@yandex-team.ru, chen.zhang@intel.com
Subject: [Qemu-devel] [PULL 08/21] migration: Add capabilities validation
Date: Tue,  5 Mar 2019 18:15:49 +0000	[thread overview]
Message-ID: <20190305181602.9051-9-dgilbert@redhat.com> (raw)
In-Reply-To: <20190305181602.9051-1-dgilbert@redhat.com>

From: Yury Kotov <yury-kotov@yandex-team.ru>

Currently we don't check which capabilities set in the source QEMU.
We just expect that the target QEMU has the same enabled capabilities.

Add explicit validation for capabilities to make sure that the target VM
has them too. This is enabled for only new capabilities to keep compatibily.

Signed-off-by: Yury Kotov <yury-kotov@yandex-team.ru>
Message-Id: <20190215174548.2630-6-yury-kotov@yandex-team.ru>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
  dgilbert: Manual merge
---
 migration/savevm.c | 137 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 137 insertions(+)

diff --git a/migration/savevm.c b/migration/savevm.c
index b3868f7fb5..013098581f 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -57,6 +57,7 @@
 #include "sysemu/replay.h"
 #include "qjson.h"
 #include "migration/colo.h"
+#include "qemu/bitmap.h"
 #include "net/announce.h"
 
 const unsigned int postcopy_ram_discard_version = 0;
@@ -249,6 +250,8 @@ typedef struct SaveState {
     uint32_t len;
     const char *name;
     uint32_t target_page_bits;
+    uint32_t caps_count;
+    MigrationCapability *capabilities;
 } SaveState;
 
 static SaveState savevm_state = {
@@ -256,15 +259,51 @@ static SaveState savevm_state = {
     .global_section_id = 0,
 };
 
+static bool should_validate_capability(int capability)
+{
+    assert(capability >= 0 && capability < MIGRATION_CAPABILITY__MAX);
+    /* Validate only new capabilities to keep compatibility. */
+    switch (capability) {
+    case MIGRATION_CAPABILITY_X_IGNORE_SHARED:
+        return true;
+    default:
+        return false;
+    }
+}
+
+static uint32_t get_validatable_capabilities_count(void)
+{
+    MigrationState *s = migrate_get_current();
+    uint32_t result = 0;
+    int i;
+    for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
+        if (should_validate_capability(i) && s->enabled_capabilities[i]) {
+            result++;
+        }
+    }
+    return result;
+}
+
 static int configuration_pre_save(void *opaque)
 {
     SaveState *state = opaque;
     const char *current_name = MACHINE_GET_CLASS(current_machine)->name;
+    MigrationState *s = migrate_get_current();
+    int i, j;
 
     state->len = strlen(current_name);
     state->name = current_name;
     state->target_page_bits = qemu_target_page_bits();
 
+    state->caps_count = get_validatable_capabilities_count();
+    state->capabilities = g_renew(MigrationCapability, state->capabilities,
+                                  state->caps_count);
+    for (i = j = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
+        if (should_validate_capability(i) && s->enabled_capabilities[i]) {
+            state->capabilities[j++] = i;
+        }
+    }
+
     return 0;
 }
 
@@ -280,6 +319,40 @@ static int configuration_pre_load(void *opaque)
     return 0;
 }
 
+static bool configuration_validate_capabilities(SaveState *state)
+{
+    bool ret = true;
+    MigrationState *s = migrate_get_current();
+    unsigned long *source_caps_bm;
+    int i;
+
+    source_caps_bm = bitmap_new(MIGRATION_CAPABILITY__MAX);
+    for (i = 0; i < state->caps_count; i++) {
+        MigrationCapability capability = state->capabilities[i];
+        set_bit(capability, source_caps_bm);
+    }
+
+    for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
+        bool source_state, target_state;
+        if (!should_validate_capability(i)) {
+            continue;
+        }
+        source_state = test_bit(i, source_caps_bm);
+        target_state = s->enabled_capabilities[i];
+        if (source_state != target_state) {
+            error_report("Capability %s is %s, but received capability is %s",
+                         MigrationCapability_str(i),
+                         target_state ? "on" : "off",
+                         source_state ? "on" : "off");
+            ret = false;
+            /* Don't break here to report all failed capabilities */
+        }
+    }
+
+    g_free(source_caps_bm);
+    return ret;
+}
+
 static int configuration_post_load(void *opaque, int version_id)
 {
     SaveState *state = opaque;
@@ -297,9 +370,53 @@ static int configuration_post_load(void *opaque, int version_id)
         return -EINVAL;
     }
 
+    if (!configuration_validate_capabilities(state)) {
+        return -EINVAL;
+    }
+
     return 0;
 }
 
+static int get_capability(QEMUFile *f, void *pv, size_t size,
+                          const VMStateField *field)
+{
+    MigrationCapability *capability = pv;
+    char capability_str[UINT8_MAX + 1];
+    uint8_t len;
+    int i;
+
+    len = qemu_get_byte(f);
+    qemu_get_buffer(f, (uint8_t *)capability_str, len);
+    capability_str[len] = '\0';
+    for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
+        if (!strcmp(MigrationCapability_str(i), capability_str)) {
+            *capability = i;
+            return 0;
+        }
+    }
+    error_report("Received unknown capability %s", capability_str);
+    return -EINVAL;
+}
+
+static int put_capability(QEMUFile *f, void *pv, size_t size,
+                          const VMStateField *field, QJSON *vmdesc)
+{
+    MigrationCapability *capability = pv;
+    const char *capability_str = MigrationCapability_str(*capability);
+    size_t len = strlen(capability_str);
+    assert(len <= UINT8_MAX);
+
+    qemu_put_byte(f, len);
+    qemu_put_buffer(f, (uint8_t *)capability_str, len);
+    return 0;
+}
+
+static const VMStateInfo vmstate_info_capability = {
+    .name = "capability",
+    .get  = get_capability,
+    .put  = put_capability,
+};
+
 /* The target-page-bits subsection is present only if the
  * target page size is not the same as the default (ie the
  * minimum page size for a variable-page-size guest CPU).
@@ -324,6 +441,25 @@ static const VMStateDescription vmstate_target_page_bits = {
     }
 };
 
+static bool vmstate_capabilites_needed(void *opaque)
+{
+    return get_validatable_capabilities_count() > 0;
+}
+
+static const VMStateDescription vmstate_capabilites = {
+    .name = "configuration/capabilities",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = vmstate_capabilites_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_V(caps_count, SaveState, 1),
+        VMSTATE_VARRAY_UINT32_ALLOC(capabilities, SaveState, caps_count, 1,
+                                    vmstate_info_capability,
+                                    MigrationCapability),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_configuration = {
     .name = "configuration",
     .version_id = 1,
@@ -337,6 +473,7 @@ static const VMStateDescription vmstate_configuration = {
     },
     .subsections = (const VMStateDescription*[]) {
         &vmstate_target_page_bits,
+        &vmstate_capabilites,
         NULL
     }
 };
-- 
2.20.1

  parent reply	other threads:[~2019-03-05 18:16 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-05 18:15 [Qemu-devel] [PULL 00/21] migration queue Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 01/21] migration: Fix cancel state Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 02/21] migration/rdma: Fix qemu_rdma_cleanup null check Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 03/21] migration/rdma: clang compilation fix Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 04/21] exec: Change RAMBlockIterFunc definition Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 05/21] migration: Introduce ignore-shared capability Dr. David Alan Gilbert (git)
2019-03-09 17:25   ` Markus Armbruster
2019-03-05 18:15 ` [Qemu-devel] [PULL 06/21] migration: Add an ability to ignore shared RAM blocks Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 07/21] tests/migration-test: Add a test for ignore-shared capability Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` Dr. David Alan Gilbert (git) [this message]
2019-03-05 18:15 ` [Qemu-devel] [PULL 09/21] tests: Add migration xbzrle test Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 10/21] migration: Create socket-address parameter Dr. David Alan Gilbert (git)
2019-03-05 18:47   ` Eric Blake
2019-03-06  5:21     ` Markus Armbruster
2019-03-06 10:40       ` Dr. David Alan Gilbert
2019-03-05 18:15 ` [Qemu-devel] [PULL 11/21] tests: Add basic migration precopy tcp test Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 12/21] bitmap: fix bitmap_count_one Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 13/21] bitmap: bitmap_count_one_with_offset Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 14/21] migration: use bitmap_mutex in migration_bitmap_clear_dirty Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 15/21] migration: API to clear bits of guest free pages from the dirty bitmap Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 16/21] migration/ram.c: add a notifier chain for precopy Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 17/21] migration/ram.c: add the free page optimization enable flag Dr. David Alan Gilbert (git)
2019-03-05 18:15 ` [Qemu-devel] [PULL 18/21] virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT Dr. David Alan Gilbert (git)
2019-03-05 18:16 ` [Qemu-devel] [PULL 19/21] Migration/colo.c: Fix double close bug when occur COLO failover Dr. David Alan Gilbert (git)
2019-03-05 18:16 ` [Qemu-devel] [PULL 20/21] Migration/colo.c: Make COLO node running after failover Dr. David Alan Gilbert (git)
2019-03-05 18:16 ` [Qemu-devel] [PULL 21/21] qapi/migration.json: Remove a variable that doesn't exist in example Dr. David Alan Gilbert (git)
2019-03-05 18:47 ` [Qemu-devel] [PULL 00/21] migration queue no-reply
2019-03-05 18:49 ` Eric Blake
2019-03-05 18:51 ` no-reply
2019-03-06 11:17 ` Philippe Mathieu-Daudé
2019-03-06 12:52   ` Markus Armbruster

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190305181602.9051-9-dgilbert@redhat.com \
    --to=dgilbert@redhat.com \
    --cc=chen.zhang@intel.com \
    --cc=marcel.apfelbaum@gmail.com \
    --cc=peterx@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=quintela@redhat.com \
    --cc=wei.w.wang@intel.com \
    --cc=yury-kotov@yandex-team.ru \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.