* [Qemu-devel] [PATCH 1/5] migrate: add migration blockers
@ 2011-11-14 21:09 Anthony Liguori
2011-11-14 21:09 ` [Qemu-devel] [PATCH 2/5] ivshmem: use migration blockers to prevent live migration in peer mode (v2) Anthony Liguori
` (5 more replies)
0 siblings, 6 replies; 9+ messages in thread
From: Anthony Liguori @ 2011-11-14 21:09 UTC (permalink / raw)
To: qemu-devel
Cc: Kevin Wolf, Lucas Meneghel Rodrigues, Anthony Liguori,
Stefan Hajnoczi, Juan Quintela, Avi Kivity
This lets different subsystems register an Error that is thrown whenever
migration is attempted. This works nicely because it gracefully supports
things like hotplug.
Right now, if multiple errors are registered, only one of them is reported.
I expect that for 1.1, we'll extend query-migrate to return all of the reasons
why migration is disabled at any given point in time.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
migration.c | 18 ++++++++++++++++++
migration.h | 15 +++++++++++++++
2 files changed, 33 insertions(+), 0 deletions(-)
diff --git a/migration.c b/migration.c
index 41c3c24..6764d3a 100644
--- a/migration.c
+++ b/migration.c
@@ -398,6 +398,18 @@ static MigrationState *migrate_init(Monitor *mon, int detach, int blk, int inc)
return s;
}
+static GSList *migration_blockers;
+
+void migrate_add_blocker(Error *reason)
+{
+ migration_blockers = g_slist_prepend(migration_blockers, reason);
+}
+
+void migrate_del_blocker(Error *reason)
+{
+ migration_blockers = g_slist_remove(migration_blockers, reason);
+}
+
int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
MigrationState *s = migrate_get_current();
@@ -417,6 +429,12 @@ int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
return -1;
}
+ if (migration_blockers) {
+ Error *err = migration_blockers->data;
+ qerror_report_err(err);
+ return -1;
+ }
+
s = migrate_init(mon, detach, blk, inc);
if (strstart(uri, "tcp:", &p)) {
diff --git a/migration.h b/migration.h
index 1b8ee58..0682179 100644
--- a/migration.h
+++ b/migration.h
@@ -17,6 +17,7 @@
#include "qdict.h"
#include "qemu-common.h"
#include "notify.h"
+#include "error.h"
typedef struct MigrationState MigrationState;
@@ -89,4 +90,18 @@ int ram_load(QEMUFile *f, void *opaque, int version_id);
extern int incoming_expected;
+/**
+ * @migrate_add_blocker - prevent migration from proceeding
+ *
+ * @reason - an error to be returned whenever migration is attempted
+ */
+void migrate_add_blocker(Error *reason);
+
+/**
+ * @migrate_del_blocker - remove a blocking error from migration
+ *
+ * @reason - the error blocking migration
+ */
+void migrate_del_blocker(Error *reason);
+
#endif
--
1.7.4.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 2/5] ivshmem: use migration blockers to prevent live migration in peer mode (v2)
2011-11-14 21:09 [Qemu-devel] [PATCH 1/5] migrate: add migration blockers Anthony Liguori
@ 2011-11-14 21:09 ` Anthony Liguori
2011-11-14 21:31 ` Michael Roth
2011-11-14 21:09 ` [Qemu-devel] [PATCH 3/5] block: allow migration to work with image files (v3) Anthony Liguori
` (4 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Anthony Liguori @ 2011-11-14 21:09 UTC (permalink / raw)
To: qemu-devel
Cc: Kevin Wolf, Lucas Meneghel Rodrigues, Anthony Liguori,
Stefan Hajnoczi, Juan Quintela, Avi Kivity
Now when you try to migrate with ivshmem, you get a proper QMP error:
(qemu) migrate tcp:localhost:1025
Migration is disabled when using feature 'peer mode' in device 'ivshmem'
(qemu)
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v1 -> v2
- remove register_device_unmigratable as ivshmem was the only user
---
hw/ivshmem.c | 12 +-
qerror.c | 4 +
qerror.h | 3 +
savevm.c | 25 ---
vmstate.h | 610 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 628 insertions(+), 26 deletions(-)
create mode 100644 vmstate.h
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index 242fbea..a3a0e98 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -18,6 +18,8 @@
#include "pci.h"
#include "msix.h"
#include "kvm.h"
+#include "migration.h"
+#include "qerror.h"
#include <sys/mman.h>
#include <sys/types.h>
@@ -78,6 +80,8 @@ typedef struct IVShmemState {
uint32_t features;
EventfdEntry *eventfd_table;
+ Error *migration_blocker;
+
char * shmobj;
char * sizearg;
char * role;
@@ -646,7 +650,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
}
if (s->role_val == IVSHMEM_PEER) {
- register_device_unmigratable(&s->dev.qdev, "ivshmem", s);
+ error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, "ivshmem", "peer mode");
+ migrate_add_blocker(s->migration_blocker);
}
pci_conf = s->dev.config;
@@ -741,6 +746,11 @@ static int pci_ivshmem_uninit(PCIDevice *dev)
{
IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
+ if (s->migration_blocker) {
+ migrate_del_blocker(s->migration_blocker);
+ error_free(s->migration_blocker);
+ }
+
memory_region_destroy(&s->ivshmem_mmio);
memory_region_del_subregion(&s->bar, &s->ivshmem);
memory_region_destroy(&s->ivshmem);
diff --git a/qerror.c b/qerror.c
index 4b48b39..8e30e2d 100644
--- a/qerror.c
+++ b/qerror.c
@@ -73,6 +73,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Device '%(device)' is in use",
},
{
+ .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
+ .desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
+ },
+ {
.error_fmt = QERR_DEVICE_LOCKED,
.desc = "Device '%(device)' is locked",
},
diff --git a/qerror.h b/qerror.h
index d4bfcfd..7e2eebf 100644
--- a/qerror.h
+++ b/qerror.h
@@ -72,6 +72,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_DEVICE_IN_USE \
"{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
+#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
+ "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+
#define QERR_DEVICE_LOCKED \
"{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
diff --git a/savevm.c b/savevm.c
index bee16c0..f53cd4c 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1255,31 +1255,6 @@ void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
}
}
-/* mark a device as not to be migrated, that is the device should be
- unplugged before migration */
-void register_device_unmigratable(DeviceState *dev, const char *idstr,
- void *opaque)
-{
- SaveStateEntry *se;
- char id[256] = "";
-
- if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
- char *path = dev->parent_bus->info->get_dev_path(dev);
- if (path) {
- pstrcpy(id, sizeof(id), path);
- pstrcat(id, sizeof(id), "/");
- g_free(path);
- }
- }
- pstrcat(id, sizeof(id), idstr);
-
- QTAILQ_FOREACH(se, &savevm_handlers, entry) {
- if (strcmp(se->idstr, id) == 0 && se->opaque == opaque) {
- se->no_migrate = 1;
- }
- }
-}
-
int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
const VMStateDescription *vmsd,
void *opaque, int alias_id,
diff --git a/vmstate.h b/vmstate.h
new file mode 100644
index 0000000..9ea4783
--- /dev/null
+++ b/vmstate.h
@@ -0,0 +1,610 @@
+/*
+ * QEMU migration/snapshot declarations
+ *
+ * Copyright (c) 2009-2011 Red Hat, Inc.
+ *
+ * Original author: Juan Quintela <quintela@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef QEMU_VMSTATE_H
+#define QEMU_VMSTATE_H 1
+
+typedef void SaveSetParamsHandler(int blk_enable, int shared, void * opaque);
+typedef void SaveStateHandler(QEMUFile *f, void *opaque);
+typedef int SaveLiveStateHandler(Monitor *mon, QEMUFile *f, int stage,
+ void *opaque);
+typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
+
+int register_savevm(DeviceState *dev,
+ const char *idstr,
+ int instance_id,
+ int version_id,
+ SaveStateHandler *save_state,
+ LoadStateHandler *load_state,
+ void *opaque);
+
+int register_savevm_live(DeviceState *dev,
+ const char *idstr,
+ int instance_id,
+ int version_id,
+ SaveSetParamsHandler *set_params,
+ SaveLiveStateHandler *save_live_state,
+ SaveStateHandler *save_state,
+ LoadStateHandler *load_state,
+ void *opaque);
+
+void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque);
+
+typedef struct VMStateInfo VMStateInfo;
+typedef struct VMStateDescription VMStateDescription;
+
+struct VMStateInfo {
+ const char *name;
+ int (*get)(QEMUFile *f, void *pv, size_t size);
+ void (*put)(QEMUFile *f, void *pv, size_t size);
+};
+
+enum VMStateFlags {
+ VMS_SINGLE = 0x001,
+ VMS_POINTER = 0x002,
+ VMS_ARRAY = 0x004,
+ VMS_STRUCT = 0x008,
+ VMS_VARRAY_INT32 = 0x010, /* Array with size in int32_t field*/
+ VMS_BUFFER = 0x020, /* static sized buffer */
+ VMS_ARRAY_OF_POINTER = 0x040,
+ VMS_VARRAY_UINT16 = 0x080, /* Array with size in uint16_t field */
+ VMS_VBUFFER = 0x100, /* Buffer with size in int32_t field */
+ VMS_MULTIPLY = 0x200, /* multiply "size" field by field_size */
+ VMS_VARRAY_UINT8 = 0x400, /* Array with size in uint8_t field*/
+ VMS_VARRAY_UINT32 = 0x800, /* Array with size in uint32_t field*/
+};
+
+typedef struct {
+ const char *name;
+ size_t offset;
+ size_t size;
+ size_t start;
+ int num;
+ size_t num_offset;
+ size_t size_offset;
+ const VMStateInfo *info;
+ enum VMStateFlags flags;
+ const VMStateDescription *vmsd;
+ int version_id;
+ bool (*field_exists)(void *opaque, int version_id);
+} VMStateField;
+
+typedef struct VMStateSubsection {
+ const VMStateDescription *vmsd;
+ bool (*needed)(void *opaque);
+} VMStateSubsection;
+
+struct VMStateDescription {
+ const char *name;
+ int unmigratable;
+ int version_id;
+ int minimum_version_id;
+ int minimum_version_id_old;
+ LoadStateHandler *load_state_old;
+ int (*pre_load)(void *opaque);
+ int (*post_load)(void *opaque, int version_id);
+ void (*pre_save)(void *opaque);
+ VMStateField *fields;
+ const VMStateSubsection *subsections;
+};
+
+extern const VMStateInfo vmstate_info_bool;
+
+extern const VMStateInfo vmstate_info_int8;
+extern const VMStateInfo vmstate_info_int16;
+extern const VMStateInfo vmstate_info_int32;
+extern const VMStateInfo vmstate_info_int64;
+
+extern const VMStateInfo vmstate_info_uint8_equal;
+extern const VMStateInfo vmstate_info_uint16_equal;
+extern const VMStateInfo vmstate_info_int32_equal;
+extern const VMStateInfo vmstate_info_uint32_equal;
+extern const VMStateInfo vmstate_info_int32_le;
+
+extern const VMStateInfo vmstate_info_uint8;
+extern const VMStateInfo vmstate_info_uint16;
+extern const VMStateInfo vmstate_info_uint32;
+extern const VMStateInfo vmstate_info_uint64;
+
+extern const VMStateInfo vmstate_info_timer;
+extern const VMStateInfo vmstate_info_buffer;
+extern const VMStateInfo vmstate_info_unused_buffer;
+
+#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
+#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
+
+#define vmstate_offset_value(_state, _field, _type) \
+ (offsetof(_state, _field) + \
+ type_check(_type, typeof_field(_state, _field)))
+
+#define vmstate_offset_pointer(_state, _field, _type) \
+ (offsetof(_state, _field) + \
+ type_check_pointer(_type, typeof_field(_state, _field)))
+
+#define vmstate_offset_array(_state, _field, _type, _num) \
+ (offsetof(_state, _field) + \
+ type_check_array(_type, typeof_field(_state, _field), _num))
+
+#define vmstate_offset_sub_array(_state, _field, _type, _start) \
+ (offsetof(_state, _field[_start]))
+
+#define vmstate_offset_buffer(_state, _field) \
+ vmstate_offset_array(_state, _field, uint8_t, \
+ sizeof(typeof_field(_state, _field)))
+
+#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .size = sizeof(_type), \
+ .info = &(_info), \
+ .flags = VMS_SINGLE, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
+#define VMSTATE_POINTER(_field, _state, _version, _info, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_SINGLE|VMS_POINTER, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
+#define VMSTATE_POINTER_TEST(_field, _state, _test, _info, _type) { \
+ .name = (stringify(_field)), \
+ .info = &(_info), \
+ .field_exists = (_test), \
+ .size = sizeof(_type), \
+ .flags = VMS_SINGLE|VMS_POINTER, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
+#define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) {\
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num = (_num), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_ARRAY, \
+ .offset = vmstate_offset_array(_state, _field, _type, _num), \
+}
+
+#define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\
+ .name = (stringify(_field)), \
+ .field_exists = (_test), \
+ .num = (_num), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_ARRAY, \
+ .offset = vmstate_offset_array(_state, _field, _type, _num),\
+}
+
+#define VMSTATE_SUB_ARRAY(_field, _state, _start, _num, _version, _info, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num = (_num), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_ARRAY, \
+ .offset = vmstate_offset_sub_array(_state, _field, _type, _start), \
+}
+
+#define VMSTATE_ARRAY_INT32_UNSAFE(_field, _state, _field_num, _info, _type) {\
+ .name = (stringify(_field)), \
+ .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_VARRAY_INT32, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_VARRAY_INT32|VMS_POINTER, \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
+}
+
+#define VMSTATE_VARRAY_UINT32(_field, _state, _field_num, _version, _info, _type) {\
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_VARRAY_UINT32|VMS_POINTER, \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
+}
+
+#define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_VARRAY_UINT16, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
+#define VMSTATE_STRUCT_POINTER_TEST(_field, _state, _test, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .field_exists = (_test), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_POINTER, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
+#define VMSTATE_ARRAY_OF_POINTER(_field, _state, _num, _version, _info, _type) {\
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num = (_num), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_ARRAY|VMS_ARRAY_OF_POINTER, \
+ .offset = vmstate_offset_array(_state, _field, _type, _num), \
+}
+
+#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .num = (_num), \
+ .field_exists = (_test), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_ARRAY, \
+ .offset = vmstate_offset_array(_state, _field, _type, _num),\
+}
+
+#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_VARRAY_UINT8, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_STRUCT_VARRAY_POINTER_INT32(_field, _state, _field_num, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = 0, \
+ .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .size = sizeof(_type), \
+ .vmsd = &(_vmsd), \
+ .flags = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT, \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
+}
+
+#define VMSTATE_STRUCT_VARRAY_POINTER_UINT16(_field, _state, _field_num, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = 0, \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
+ .size = sizeof(_type), \
+ .vmsd = &(_vmsd), \
+ .flags = VMS_POINTER | VMS_VARRAY_UINT16 | VMS_STRUCT, \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
+}
+
+#define VMSTATE_STRUCT_VARRAY_INT32(_field, _state, _field_num, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_VARRAY_INT32, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_VARRAY_UINT32, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .size = (_size - _start), \
+ .info = &vmstate_info_buffer, \
+ .flags = VMS_BUFFER, \
+ .offset = vmstate_offset_buffer(_state, _field) + _start, \
+}
+
+#define VMSTATE_BUFFER_MULTIPLY(_field, _state, _version, _test, _start, _field_size, _multiply) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\
+ .size = (_multiply), \
+ .info = &vmstate_info_buffer, \
+ .flags = VMS_VBUFFER|VMS_MULTIPLY, \
+ .offset = offsetof(_state, _field), \
+ .start = (_start), \
+}
+
+#define VMSTATE_VBUFFER(_field, _state, _version, _test, _start, _field_size) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .size_offset = vmstate_offset_value(_state, _field_size, int32_t),\
+ .info = &vmstate_info_buffer, \
+ .flags = VMS_VBUFFER|VMS_POINTER, \
+ .offset = offsetof(_state, _field), \
+ .start = (_start), \
+}
+
+#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _start, _field_size) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\
+ .info = &vmstate_info_buffer, \
+ .flags = VMS_VBUFFER|VMS_POINTER, \
+ .offset = offsetof(_state, _field), \
+ .start = (_start), \
+}
+
+#define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .size = (_size), \
+ .info = &(_info), \
+ .flags = VMS_BUFFER, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_UNUSED_BUFFER(_test, _version, _size) { \
+ .name = "unused", \
+ .field_exists = (_test), \
+ .version_id = (_version), \
+ .size = (_size), \
+ .info = &vmstate_info_unused_buffer, \
+ .flags = VMS_BUFFER, \
+}
+
+/* _f : field name
+ _f_n : num of elements field_name
+ _n : num of elements
+ _s : struct state name
+ _v : version
+*/
+
+#define VMSTATE_SINGLE(_field, _state, _version, _info, _type) \
+ VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type)
+
+#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \
+ VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type)
+
+#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) \
+ VMSTATE_STRUCT_POINTER_TEST(_field, _state, NULL, _vmsd, _type)
+
+#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \
+ VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version, \
+ _vmsd, _type)
+
+#define VMSTATE_BOOL_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_bool, bool)
+
+#define VMSTATE_INT8_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int8, int8_t)
+#define VMSTATE_INT16_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int16, int16_t)
+#define VMSTATE_INT32_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int32, int32_t)
+#define VMSTATE_INT64_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int64, int64_t)
+
+#define VMSTATE_UINT8_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint8, uint8_t)
+#define VMSTATE_UINT16_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16, uint16_t)
+#define VMSTATE_UINT32_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint32, uint32_t)
+#define VMSTATE_UINT64_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64, uint64_t)
+
+#define VMSTATE_BOOL(_f, _s) \
+ VMSTATE_BOOL_V(_f, _s, 0)
+
+#define VMSTATE_INT8(_f, _s) \
+ VMSTATE_INT8_V(_f, _s, 0)
+#define VMSTATE_INT16(_f, _s) \
+ VMSTATE_INT16_V(_f, _s, 0)
+#define VMSTATE_INT32(_f, _s) \
+ VMSTATE_INT32_V(_f, _s, 0)
+#define VMSTATE_INT64(_f, _s) \
+ VMSTATE_INT64_V(_f, _s, 0)
+
+#define VMSTATE_UINT8(_f, _s) \
+ VMSTATE_UINT8_V(_f, _s, 0)
+#define VMSTATE_UINT16(_f, _s) \
+ VMSTATE_UINT16_V(_f, _s, 0)
+#define VMSTATE_UINT32(_f, _s) \
+ VMSTATE_UINT32_V(_f, _s, 0)
+#define VMSTATE_UINT64(_f, _s) \
+ VMSTATE_UINT64_V(_f, _s, 0)
+
+#define VMSTATE_UINT8_EQUAL(_f, _s) \
+ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint8_equal, uint8_t)
+
+#define VMSTATE_UINT16_EQUAL(_f, _s) \
+ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint16_equal, uint16_t)
+
+#define VMSTATE_UINT16_EQUAL_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16_equal, uint16_t)
+
+#define VMSTATE_INT32_EQUAL(_f, _s) \
+ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_equal, int32_t)
+
+#define VMSTATE_UINT32_EQUAL(_f, _s) \
+ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint32_equal, uint32_t)
+
+#define VMSTATE_INT32_LE(_f, _s) \
+ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
+
+#define VMSTATE_UINT8_TEST(_f, _s, _t) \
+ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint8, uint8_t)
+
+#define VMSTATE_UINT16_TEST(_f, _s, _t) \
+ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint16, uint16_t)
+
+#define VMSTATE_UINT32_TEST(_f, _s, _t) \
+ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_TIMER_TEST(_f, _s, _test) \
+ VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *)
+
+#define VMSTATE_TIMER(_f, _s) \
+ VMSTATE_TIMER_TEST(_f, _s, NULL)
+
+#define VMSTATE_TIMER_ARRAY(_f, _s, _n) \
+ VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *)
+
+#define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool)
+
+#define VMSTATE_BOOL_ARRAY(_f, _s, _n) \
+ VMSTATE_BOOL_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t)
+
+#define VMSTATE_UINT16_ARRAY(_f, _s, _n) \
+ VMSTATE_UINT16_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT8_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint8, uint8_t)
+
+#define VMSTATE_UINT8_ARRAY(_f, _s, _n) \
+ VMSTATE_UINT8_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_UINT32_ARRAY(_f, _s, _n) \
+ VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint64, uint64_t)
+
+#define VMSTATE_UINT64_ARRAY(_f, _s, _n) \
+ VMSTATE_UINT64_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int16, int16_t)
+
+#define VMSTATE_INT16_ARRAY(_f, _s, _n) \
+ VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_INT32_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int32, int32_t)
+
+#define VMSTATE_INT32_ARRAY(_f, _s, _n) \
+ VMSTATE_INT32_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT32_SUB_ARRAY(_f, _s, _start, _num) \
+ VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_UINT32_ARRAY(_f, _s, _n) \
+ VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_INT64_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int64, int64_t)
+
+#define VMSTATE_INT64_ARRAY(_f, _s, _n) \
+ VMSTATE_INT64_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_BUFFER_V(_f, _s, _v) \
+ VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_BUFFER(_f, _s) \
+ VMSTATE_BUFFER_V(_f, _s, 0)
+
+#define VMSTATE_PARTIAL_BUFFER(_f, _s, _size) \
+ VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, 0, _size)
+
+#define VMSTATE_BUFFER_START_MIDDLE(_f, _s, _start) \
+ VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, _start, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size) \
+ VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size)
+
+#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size) \
+ VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, 0, _size)
+
+#define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size) \
+ VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size)
+
+#define VMSTATE_BUFFER_TEST(_f, _s, _test) \
+ VMSTATE_STATIC_BUFFER(_f, _s, 0, _test, 0, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_BUFFER_UNSAFE(_field, _state, _version, _size) \
+ VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, vmstate_info_buffer, _size)
+
+#define VMSTATE_UNUSED_V(_v, _size) \
+ VMSTATE_UNUSED_BUFFER(NULL, _v, _size)
+
+#define VMSTATE_UNUSED(_size) \
+ VMSTATE_UNUSED_V(0, _size)
+
+#define VMSTATE_UNUSED_TEST(_test, _size) \
+ VMSTATE_UNUSED_BUFFER(_test, 0, _size)
+
+#define VMSTATE_END_OF_LIST() \
+ {}
+
+int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque, int version_id);
+void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque);
+int vmstate_register(DeviceState *dev, int instance_id,
+ const VMStateDescription *vmsd, void *base);
+int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
+ const VMStateDescription *vmsd,
+ void *base, int alias_id,
+ int required_for_version);
+void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
+ void *opaque);
+
+#endif
--
1.7.4.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 3/5] block: allow migration to work with image files (v3)
2011-11-14 21:09 [Qemu-devel] [PATCH 1/5] migrate: add migration blockers Anthony Liguori
2011-11-14 21:09 ` [Qemu-devel] [PATCH 2/5] ivshmem: use migration blockers to prevent live migration in peer mode (v2) Anthony Liguori
@ 2011-11-14 21:09 ` Anthony Liguori
2011-11-14 21:09 ` [Qemu-devel] [PATCH 4/5] qcow2: implement bdrv_invalidate_cache (v2) Anthony Liguori
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Anthony Liguori @ 2011-11-14 21:09 UTC (permalink / raw)
To: qemu-devel
Cc: Kevin Wolf, Lucas Meneghel Rodrigues, Anthony Liguori,
Stefan Hajnoczi, Juan Quintela, Avi Kivity
Image files have two types of data: immutable data that describes things like
image size, backing files, etc. and mutable data that includes offset and
reference count tables.
Today, image formats aggressively cache mutable data to improve performance. In
some cases, this happens before a guest even starts. When dealing with live
migration, since a file is open on two machines, the caching of meta data can
lead to data corruption.
This patch addresses this by introducing a mechanism to invalidate any cached
mutable data a block driver may have which is then used by the live migration
code.
NB, this still requires coherent shared storage. Addressing migration without
coherent shared storage (i.e. NFS) requires additional work.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v2 -> v3
- remove bdrv_invalidate_cache_all() in vm_stop.
v1 -> v2
- rebase to latest master
---
block.c | 16 ++++++++++++++++
block.h | 4 ++++
block_int.h | 5 +++++
migration.c | 3 +++
4 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/block.c b/block.c
index 86910b0..d015887 100644
--- a/block.c
+++ b/block.c
@@ -2839,6 +2839,22 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
}
}
+void bdrv_invalidate_cache(BlockDriverState *bs)
+{
+ if (bs->drv && bs->drv->bdrv_invalidate_cache) {
+ bs->drv->bdrv_invalidate_cache(bs);
+ }
+}
+
+void bdrv_invalidate_cache_all(void)
+{
+ BlockDriverState *bs;
+
+ QTAILQ_FOREACH(bs, &bdrv_states, list) {
+ bdrv_invalidate_cache(bs);
+ }
+}
+
int bdrv_flush(BlockDriverState *bs)
{
Coroutine *co;
diff --git a/block.h b/block.h
index 051a25d..a826059 100644
--- a/block.h
+++ b/block.h
@@ -197,6 +197,10 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
unsigned long int req, void *buf,
BlockDriverCompletionFunc *cb, void *opaque);
+/* Invalidate any cached metadata used by image formats */
+void bdrv_invalidate_cache(BlockDriverState *bs);
+void bdrv_invalidate_cache_all(void);
+
/* Ensure contents are flushed to disk. */
int bdrv_flush(BlockDriverState *bs);
int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
diff --git a/block_int.h b/block_int.h
index 1ec4921..77c0187 100644
--- a/block_int.h
+++ b/block_int.h
@@ -88,6 +88,11 @@ struct BlockDriver {
int64_t sector_num, int nb_sectors);
/*
+ * Invalidate any cached meta-data.
+ */
+ void (*bdrv_invalidate_cache)(BlockDriverState *bs);
+
+ /*
* Flushes all data that was already written to the OS all the way down to
* the disk (for example raw-posix calls fsync()).
*/
diff --git a/migration.c b/migration.c
index 6764d3a..8280d71 100644
--- a/migration.c
+++ b/migration.c
@@ -89,6 +89,9 @@ void process_incoming_migration(QEMUFile *f)
qemu_announce_self();
DPRINTF("successfully loaded vm state\n");
+ /* Make sure all file formats flush their mutable metadata */
+ bdrv_invalidate_cache_all();
+
if (autostart) {
vm_start();
} else {
--
1.7.4.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 4/5] qcow2: implement bdrv_invalidate_cache (v2)
2011-11-14 21:09 [Qemu-devel] [PATCH 1/5] migrate: add migration blockers Anthony Liguori
2011-11-14 21:09 ` [Qemu-devel] [PATCH 2/5] ivshmem: use migration blockers to prevent live migration in peer mode (v2) Anthony Liguori
2011-11-14 21:09 ` [Qemu-devel] [PATCH 3/5] block: allow migration to work with image files (v3) Anthony Liguori
@ 2011-11-14 21:09 ` Anthony Liguori
2011-11-14 21:09 ` [Qemu-devel] [PATCH 5/5] qed: add migration blocker (v2) Anthony Liguori
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Anthony Liguori @ 2011-11-14 21:09 UTC (permalink / raw)
To: qemu-devel
Cc: Kevin Wolf, Lucas Meneghel Rodrigues, Anthony Liguori,
Stefan Hajnoczi, Juan Quintela, Avi Kivity
We don't reopen the actual file, but instead invoke the close and open routines.
We specifically ignore the backing file since it's contents are read-only and
therefore immutable.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v1 -> v2
- make invalidate_cache work with encrypted block devices
---
block/qcow2.c | 34 ++++++++++++++++++++++++++++++++++
block/qcow2.h | 2 ++
2 files changed, 36 insertions(+), 0 deletions(-)
diff --git a/block/qcow2.c b/block/qcow2.c
index 5c784ee..d7805ce 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -240,6 +240,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
s->cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
+ 512);
s->cluster_cache_offset = -1;
+ s->flags = flags;
ret = qcow2_refcount_init(bs);
if (ret != 0) {
@@ -632,6 +633,37 @@ static void qcow2_close(BlockDriverState *bs)
qcow2_refcount_close(bs);
}
+static void qcow2_invalidate_cache(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ int flags = s->flags;
+ AES_KEY aes_encrypt_key;
+ AES_KEY aes_decrypt_key;
+ uint32_t crypt_method = 0;
+
+ /*
+ * Backing files are read-only which makes all of their metadata immutable,
+ * that means we don't have to worry about reopening them here.
+ */
+
+ if (s->crypt_method) {
+ crypt_method = s->crypt_method;
+ memcpy(&aes_encrypt_key, &s->aes_encrypt_key, sizeof(aes_encrypt_key));
+ memcpy(&aes_decrypt_key, &s->aes_decrypt_key, sizeof(aes_decrypt_key));
+ }
+
+ qcow2_close(bs);
+
+ memset(s, 0, sizeof(BDRVQcowState));
+ qcow2_open(bs, flags);
+
+ if (crypt_method) {
+ s->crypt_method = crypt_method;
+ memcpy(&s->aes_encrypt_key, &aes_encrypt_key, sizeof(aes_encrypt_key));
+ memcpy(&s->aes_decrypt_key, &aes_decrypt_key, sizeof(aes_decrypt_key));
+ }
+}
+
/*
* Updates the variable length parts of the qcow2 header, i.e. the backing file
* name and all extensions. qcow2 was not designed to allow such changes, so if
@@ -1269,6 +1301,8 @@ static BlockDriver bdrv_qcow2 = {
.bdrv_change_backing_file = qcow2_change_backing_file,
+ .bdrv_invalidate_cache = qcow2_invalidate_cache,
+
.create_options = qcow2_create_options,
.bdrv_check = qcow2_check,
};
diff --git a/block/qcow2.h b/block/qcow2.h
index 531af39..4e44eea 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -125,6 +125,8 @@ typedef struct BDRVQcowState {
int snapshots_size;
int nb_snapshots;
QCowSnapshot *snapshots;
+
+ int flags;
} BDRVQcowState;
/* XXX: use std qcow open function ? */
--
1.7.4.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 5/5] qed: add migration blocker (v2)
2011-11-14 21:09 [Qemu-devel] [PATCH 1/5] migrate: add migration blockers Anthony Liguori
` (2 preceding siblings ...)
2011-11-14 21:09 ` [Qemu-devel] [PATCH 4/5] qcow2: implement bdrv_invalidate_cache (v2) Anthony Liguori
@ 2011-11-14 21:09 ` Anthony Liguori
2011-11-14 21:29 ` [Qemu-devel] [PATCH 0/5] migration: support migration with image files Anthony Liguori
2011-11-22 0:21 ` [Qemu-devel] [PATCH 1/5] migrate: add migration blockers Anthony Liguori
5 siblings, 0 replies; 9+ messages in thread
From: Anthony Liguori @ 2011-11-14 21:09 UTC (permalink / raw)
To: qemu-devel
Cc: Kevin Wolf, Lucas Meneghel Rodrigues, Anthony Liguori,
Stefan Hajnoczi, Juan Quintela, Avi Kivity
Now when you try to migrate with qed, you get:
(qemu) migrate tcp:localhost:1025
Block format 'qed' used by device 'ide0-hd0' does not support feature 'live migration'
(qemu)
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v1 -> v2
- Pull in QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED. I hope Stefan reviews this
patch and Ack's a similar approach to qcow2 so we can avoid using a blocker
for QED.
---
block/qed.c | 10 ++++++++++
block/qed.h | 2 ++
qemu-tool.c | 9 +++++++++
qerror.c | 4 ++++
qerror.h | 3 +++
5 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/block/qed.c b/block/qed.c
index d032a45..7e22e77 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -16,6 +16,7 @@
#include "trace.h"
#include "qed.h"
#include "qerror.h"
+#include "migration.h"
static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
{
@@ -504,6 +505,12 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
s->need_check_timer = qemu_new_timer_ns(vm_clock,
qed_need_check_timer_cb, s);
+ error_set(&s->migration_blocker,
+ QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
+ "qed", bs->device_name, "live migration");
+ migrate_add_blocker(s->migration_blocker);
+
+
out:
if (ret) {
qed_free_l2_cache(&s->l2_cache);
@@ -516,6 +523,9 @@ static void bdrv_qed_close(BlockDriverState *bs)
{
BDRVQEDState *s = bs->opaque;
+ migrate_del_blocker(s->migration_blocker);
+ error_free(s->migration_blocker);
+
qed_cancel_need_check_timer(s);
qemu_free_timer(s->need_check_timer);
diff --git a/block/qed.h b/block/qed.h
index 388fdb3..62cbd3b 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -164,6 +164,8 @@ typedef struct {
/* Periodic flush and clear need check flag */
QEMUTimer *need_check_timer;
+
+ Error *migration_blocker;
} BDRVQEDState;
enum {
diff --git a/qemu-tool.c b/qemu-tool.c
index e9f7fe1..5df7279 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -15,6 +15,7 @@
#include "monitor.h"
#include "qemu-timer.h"
#include "qemu-log.h"
+#include "migration.h"
#include <sys/time.h>
@@ -92,3 +93,11 @@ int64_t qemu_get_clock_ns(QEMUClock *clock)
{
return 0;
}
+
+void migrate_add_blocker(Error *reason)
+{
+}
+
+void migrate_del_blocker(Error *reason)
+{
+}
diff --git a/qerror.c b/qerror.c
index 8e30e2d..fdf62b9 100644
--- a/qerror.c
+++ b/qerror.c
@@ -49,6 +49,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Device '%(device)' can't go on a %(bad_bus_type) bus",
},
{
+ .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
+ .desc = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
+ },
+ {
.error_fmt = QERR_BUS_NOT_FOUND,
.desc = "Bus '%(bus)' not found",
},
diff --git a/qerror.h b/qerror.h
index 7e2eebf..2d3d43b 100644
--- a/qerror.h
+++ b/qerror.h
@@ -54,6 +54,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_BAD_BUS_FOR_DEVICE \
"{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
+#define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
+ "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
+
#define QERR_BUS_NOT_FOUND \
"{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
--
1.7.4.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 0/5] migration: support migration with image files
2011-11-14 21:09 [Qemu-devel] [PATCH 1/5] migrate: add migration blockers Anthony Liguori
` (3 preceding siblings ...)
2011-11-14 21:09 ` [Qemu-devel] [PATCH 5/5] qed: add migration blocker (v2) Anthony Liguori
@ 2011-11-14 21:29 ` Anthony Liguori
2011-11-22 0:21 ` [Qemu-devel] [PATCH 1/5] migrate: add migration blockers Anthony Liguori
5 siblings, 0 replies; 9+ messages in thread
From: Anthony Liguori @ 2011-11-14 21:29 UTC (permalink / raw)
Cc: Kevin Wolf, Lucas Meneghel Rodrigues, Stefan Hajnoczi,
Juan Quintela, qemu-devel, Avi Kivity
This series allows live migration to work with image formats. This series has
two parts. The first part adds a new error infrastructure to migration which
allows for different subsystems (other than qdev) to block migration when
specific features are in use.
The second part adds block interfaces to flush metadata with image formats.
The migration error infrastructure is a no brainer for 1.0. It significantly
improves the user experience and prevents a user from doing things that will
cause a VM to crash during migration.
I'm less comfortable with the block interface for flushing metadata for 1.0.
The code is completely isolated to the image formats and live migration. It
should have no impact on normal use of an image format or live migration with
raw images. That makes the risk for this very, very low.
Moreover, I'm sympathetic to the argument that this is a required feature for a
1.0 release. Image formats are a fairly normal way to use QEMU and not
supporting live migration in this scenario means that live migration won't work
for a large portion of QEMU's users.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 2/5] ivshmem: use migration blockers to prevent live migration in peer mode (v2)
2011-11-14 21:09 ` [Qemu-devel] [PATCH 2/5] ivshmem: use migration blockers to prevent live migration in peer mode (v2) Anthony Liguori
@ 2011-11-14 21:31 ` Michael Roth
2011-11-14 21:38 ` Anthony Liguori
0 siblings, 1 reply; 9+ messages in thread
From: Michael Roth @ 2011-11-14 21:31 UTC (permalink / raw)
To: Anthony Liguori
Cc: Kevin Wolf, Lucas Meneghel Rodrigues, Stefan Hajnoczi,
Juan Quintela, qemu-devel, Avi Kivity
On 11/14/2011 03:09 PM, Anthony Liguori wrote:
> Now when you try to migrate with ivshmem, you get a proper QMP error:
>
> (qemu) migrate tcp:localhost:1025
> Migration is disabled when using feature 'peer mode' in device 'ivshmem'
> (qemu)
>
> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
> ---
> v1 -> v2
> - remove register_device_unmigratable as ivshmem was the only user
> ---
> hw/ivshmem.c | 12 +-
> qerror.c | 4 +
> qerror.h | 3 +
> savevm.c | 25 ---
> vmstate.h | 610 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 628 insertions(+), 26 deletions(-)
> create mode 100644 vmstate.h
>
> diff --git a/hw/ivshmem.c b/hw/ivshmem.c
> index 242fbea..a3a0e98 100644
> --- a/hw/ivshmem.c
> +++ b/hw/ivshmem.c
> @@ -18,6 +18,8 @@
> #include "pci.h"
> #include "msix.h"
> #include "kvm.h"
> +#include "migration.h"
> +#include "qerror.h"
>
> #include<sys/mman.h>
> #include<sys/types.h>
> @@ -78,6 +80,8 @@ typedef struct IVShmemState {
> uint32_t features;
> EventfdEntry *eventfd_table;
>
> + Error *migration_blocker;
> +
> char * shmobj;
> char * sizearg;
> char * role;
> @@ -646,7 +650,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
> }
>
> if (s->role_val == IVSHMEM_PEER) {
> - register_device_unmigratable(&s->dev.qdev, "ivshmem", s);
> + error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, "ivshmem", "peer mode");
> + migrate_add_blocker(s->migration_blocker);
> }
>
> pci_conf = s->dev.config;
> @@ -741,6 +746,11 @@ static int pci_ivshmem_uninit(PCIDevice *dev)
> {
> IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
>
> + if (s->migration_blocker) {
> + migrate_del_blocker(s->migration_blocker);
> + error_free(s->migration_blocker);
> + }
> +
> memory_region_destroy(&s->ivshmem_mmio);
> memory_region_del_subregion(&s->bar,&s->ivshmem);
> memory_region_destroy(&s->ivshmem);
> diff --git a/qerror.c b/qerror.c
> index 4b48b39..8e30e2d 100644
> --- a/qerror.c
> +++ b/qerror.c
> @@ -73,6 +73,10 @@ static const QErrorStringTable qerror_table[] = {
> .desc = "Device '%(device)' is in use",
> },
> {
> + .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
> + .desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
> + },
> + {
> .error_fmt = QERR_DEVICE_LOCKED,
> .desc = "Device '%(device)' is locked",
> },
> diff --git a/qerror.h b/qerror.h
> index d4bfcfd..7e2eebf 100644
> --- a/qerror.h
> +++ b/qerror.h
> @@ -72,6 +72,9 @@ QError *qobject_to_qerror(const QObject *obj);
> #define QERR_DEVICE_IN_USE \
> "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
>
> +#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
> + "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
> +
> #define QERR_DEVICE_LOCKED \
> "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
>
> diff --git a/savevm.c b/savevm.c
> index bee16c0..f53cd4c 100644
> --- a/savevm.c
> +++ b/savevm.c
> @@ -1255,31 +1255,6 @@ void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
> }
> }
>
> -/* mark a device as not to be migrated, that is the device should be
> - unplugged before migration */
> -void register_device_unmigratable(DeviceState *dev, const char *idstr,
> - void *opaque)
> -{
> - SaveStateEntry *se;
> - char id[256] = "";
> -
> - if (dev&& dev->parent_bus&& dev->parent_bus->info->get_dev_path) {
> - char *path = dev->parent_bus->info->get_dev_path(dev);
> - if (path) {
> - pstrcpy(id, sizeof(id), path);
> - pstrcat(id, sizeof(id), "/");
> - g_free(path);
> - }
> - }
> - pstrcat(id, sizeof(id), idstr);
> -
> - QTAILQ_FOREACH(se,&savevm_handlers, entry) {
> - if (strcmp(se->idstr, id) == 0&& se->opaque == opaque) {
> - se->no_migrate = 1;
> - }
> - }
> -}
> -
> int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
> const VMStateDescription *vmsd,
> void *opaque, int alias_id,
> diff --git a/vmstate.h b/vmstate.h
> new file mode 100644
> index 0000000..9ea4783
> --- /dev/null
> +++ b/vmstate.h
> @@ -0,0 +1,610 @@
> +/*
> + * QEMU migration/snapshot declarations
> + *
I take it these were meant for a separate series? We still have these
defs in hw/hw.h
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 2/5] ivshmem: use migration blockers to prevent live migration in peer mode (v2)
2011-11-14 21:31 ` Michael Roth
@ 2011-11-14 21:38 ` Anthony Liguori
0 siblings, 0 replies; 9+ messages in thread
From: Anthony Liguori @ 2011-11-14 21:38 UTC (permalink / raw)
To: Michael Roth
Cc: Kevin Wolf, Lucas Meneghel Rodrigues, Anthony Liguori,
Stefan Hajnoczi, Juan Quintela, qemu-devel, Avi Kivity
On 11/14/2011 03:31 PM, Michael Roth wrote:
> On 11/14/2011 03:09 PM, Anthony Liguori wrote:
>> Now when you try to migrate with ivshmem, you get a proper QMP error:
>>
>> (qemu) migrate tcp:localhost:1025
>> Migration is disabled when using feature 'peer mode' in device 'ivshmem'
>> (qemu)
>>
>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>> ---
>> v1 -> v2
>> - remove register_device_unmigratable as ivshmem was the only user
>> ---
>> hw/ivshmem.c | 12 +-
>> qerror.c | 4 +
>> qerror.h | 3 +
>> savevm.c | 25 ---
>> vmstate.h | 610 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>> 5 files changed, 628 insertions(+), 26 deletions(-)
>> create mode 100644 vmstate.h
>>
>> diff --git a/hw/ivshmem.c b/hw/ivshmem.c
>> index 242fbea..a3a0e98 100644
>> --- a/hw/ivshmem.c
>> +++ b/hw/ivshmem.c
>> @@ -18,6 +18,8 @@
>> #include "pci.h"
>> #include "msix.h"
>> #include "kvm.h"
>> +#include "migration.h"
>> +#include "qerror.h"
>>
>> #include<sys/mman.h>
>> #include<sys/types.h>
>> @@ -78,6 +80,8 @@ typedef struct IVShmemState {
>> uint32_t features;
>> EventfdEntry *eventfd_table;
>>
>> + Error *migration_blocker;
>> +
>> char * shmobj;
>> char * sizearg;
>> char * role;
>> @@ -646,7 +650,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
>> }
>>
>> if (s->role_val == IVSHMEM_PEER) {
>> - register_device_unmigratable(&s->dev.qdev, "ivshmem", s);
>> + error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
>> "ivshmem", "peer mode");
>> + migrate_add_blocker(s->migration_blocker);
>> }
>>
>> pci_conf = s->dev.config;
>> @@ -741,6 +746,11 @@ static int pci_ivshmem_uninit(PCIDevice *dev)
>> {
>> IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
>>
>> + if (s->migration_blocker) {
>> + migrate_del_blocker(s->migration_blocker);
>> + error_free(s->migration_blocker);
>> + }
>> +
>> memory_region_destroy(&s->ivshmem_mmio);
>> memory_region_del_subregion(&s->bar,&s->ivshmem);
>> memory_region_destroy(&s->ivshmem);
>> diff --git a/qerror.c b/qerror.c
>> index 4b48b39..8e30e2d 100644
>> --- a/qerror.c
>> +++ b/qerror.c
>> @@ -73,6 +73,10 @@ static const QErrorStringTable qerror_table[] = {
>> .desc = "Device '%(device)' is in use",
>> },
>> {
>> + .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
>> + .desc = "Migration is disabled when using feature '%(feature)' in device
>> '%(device)'",
>> + },
>> + {
>> .error_fmt = QERR_DEVICE_LOCKED,
>> .desc = "Device '%(device)' is locked",
>> },
>> diff --git a/qerror.h b/qerror.h
>> index d4bfcfd..7e2eebf 100644
>> --- a/qerror.h
>> +++ b/qerror.h
>> @@ -72,6 +72,9 @@ QError *qobject_to_qerror(const QObject *obj);
>> #define QERR_DEVICE_IN_USE \
>> "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
>>
>> +#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
>> + "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s,
>> 'feature': %s } }"
>> +
>> #define QERR_DEVICE_LOCKED \
>> "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
>>
>> diff --git a/savevm.c b/savevm.c
>> index bee16c0..f53cd4c 100644
>> --- a/savevm.c
>> +++ b/savevm.c
>> @@ -1255,31 +1255,6 @@ void unregister_savevm(DeviceState *dev, const char
>> *idstr, void *opaque)
>> }
>> }
>>
>> -/* mark a device as not to be migrated, that is the device should be
>> - unplugged before migration */
>> -void register_device_unmigratable(DeviceState *dev, const char *idstr,
>> - void *opaque)
>> -{
>> - SaveStateEntry *se;
>> - char id[256] = "";
>> -
>> - if (dev&& dev->parent_bus&& dev->parent_bus->info->get_dev_path) {
>> - char *path = dev->parent_bus->info->get_dev_path(dev);
>> - if (path) {
>> - pstrcpy(id, sizeof(id), path);
>> - pstrcat(id, sizeof(id), "/");
>> - g_free(path);
>> - }
>> - }
>> - pstrcat(id, sizeof(id), idstr);
>> -
>> - QTAILQ_FOREACH(se,&savevm_handlers, entry) {
>> - if (strcmp(se->idstr, id) == 0&& se->opaque == opaque) {
>> - se->no_migrate = 1;
>> - }
>> - }
>> -}
>> -
>> int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
>> const VMStateDescription *vmsd,
>> void *opaque, int alias_id,
>> diff --git a/vmstate.h b/vmstate.h
>> new file mode 100644
>> index 0000000..9ea4783
>> --- /dev/null
>> +++ b/vmstate.h
>> @@ -0,0 +1,610 @@
>> +/*
>> + * QEMU migration/snapshot declarations
>> + *
>
> I take it these were meant for a separate series? We still have these defs in
> hw/hw.h
*sigh*
I have no idea where that file came from. I fixed the patch locally, thanks for
pointing it out!
Regards,
Anthony Liguori
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 1/5] migrate: add migration blockers
2011-11-14 21:09 [Qemu-devel] [PATCH 1/5] migrate: add migration blockers Anthony Liguori
` (4 preceding siblings ...)
2011-11-14 21:29 ` [Qemu-devel] [PATCH 0/5] migration: support migration with image files Anthony Liguori
@ 2011-11-22 0:21 ` Anthony Liguori
5 siblings, 0 replies; 9+ messages in thread
From: Anthony Liguori @ 2011-11-22 0:21 UTC (permalink / raw)
To: Anthony Liguori
Cc: Kevin Wolf, Lucas Meneghel Rodrigues, Stefan Hajnoczi,
Juan Quintela, qemu-devel, Avi Kivity
On 11/14/2011 03:09 PM, Anthony Liguori wrote:
> This lets different subsystems register an Error that is thrown whenever
> migration is attempted. This works nicely because it gracefully supports
> things like hotplug.
>
> Right now, if multiple errors are registered, only one of them is reported.
> I expect that for 1.1, we'll extend query-migrate to return all of the reasons
> why migration is disabled at any given point in time.
>
> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
Applied.
Regards,
Anthony Liguori
> ---
> migration.c | 18 ++++++++++++++++++
> migration.h | 15 +++++++++++++++
> 2 files changed, 33 insertions(+), 0 deletions(-)
>
> diff --git a/migration.c b/migration.c
> index 41c3c24..6764d3a 100644
> --- a/migration.c
> +++ b/migration.c
> @@ -398,6 +398,18 @@ static MigrationState *migrate_init(Monitor *mon, int detach, int blk, int inc)
> return s;
> }
>
> +static GSList *migration_blockers;
> +
> +void migrate_add_blocker(Error *reason)
> +{
> + migration_blockers = g_slist_prepend(migration_blockers, reason);
> +}
> +
> +void migrate_del_blocker(Error *reason)
> +{
> + migration_blockers = g_slist_remove(migration_blockers, reason);
> +}
> +
> int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
> {
> MigrationState *s = migrate_get_current();
> @@ -417,6 +429,12 @@ int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
> return -1;
> }
>
> + if (migration_blockers) {
> + Error *err = migration_blockers->data;
> + qerror_report_err(err);
> + return -1;
> + }
> +
> s = migrate_init(mon, detach, blk, inc);
>
> if (strstart(uri, "tcp:",&p)) {
> diff --git a/migration.h b/migration.h
> index 1b8ee58..0682179 100644
> --- a/migration.h
> +++ b/migration.h
> @@ -17,6 +17,7 @@
> #include "qdict.h"
> #include "qemu-common.h"
> #include "notify.h"
> +#include "error.h"
>
> typedef struct MigrationState MigrationState;
>
> @@ -89,4 +90,18 @@ int ram_load(QEMUFile *f, void *opaque, int version_id);
>
> extern int incoming_expected;
>
> +/**
> + * @migrate_add_blocker - prevent migration from proceeding
> + *
> + * @reason - an error to be returned whenever migration is attempted
> + */
> +void migrate_add_blocker(Error *reason);
> +
> +/**
> + * @migrate_del_blocker - remove a blocking error from migration
> + *
> + * @reason - the error blocking migration
> + */
> +void migrate_del_blocker(Error *reason);
> +
> #endif
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2011-11-22 0:21 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-14 21:09 [Qemu-devel] [PATCH 1/5] migrate: add migration blockers Anthony Liguori
2011-11-14 21:09 ` [Qemu-devel] [PATCH 2/5] ivshmem: use migration blockers to prevent live migration in peer mode (v2) Anthony Liguori
2011-11-14 21:31 ` Michael Roth
2011-11-14 21:38 ` Anthony Liguori
2011-11-14 21:09 ` [Qemu-devel] [PATCH 3/5] block: allow migration to work with image files (v3) Anthony Liguori
2011-11-14 21:09 ` [Qemu-devel] [PATCH 4/5] qcow2: implement bdrv_invalidate_cache (v2) Anthony Liguori
2011-11-14 21:09 ` [Qemu-devel] [PATCH 5/5] qed: add migration blocker (v2) Anthony Liguori
2011-11-14 21:29 ` [Qemu-devel] [PATCH 0/5] migration: support migration with image files Anthony Liguori
2011-11-22 0:21 ` [Qemu-devel] [PATCH 1/5] migrate: add migration blockers Anthony Liguori
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).