* [Qemu-devel] [PATCH v2 0/5] vmstate: handle arrays with null ptrs
@ 2017-02-22 16:01 Halil Pasic
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 1/5] migration/vmstate: renames in (load|save)_state Halil Pasic
` (5 more replies)
0 siblings, 6 replies; 10+ messages in thread
From: Halil Pasic @ 2017-02-22 16:01 UTC (permalink / raw)
To: qemu-devel, Dr. David Alan Gilbert; +Cc: Juan Quintela, Amit Shah, Halil Pasic
The objective is supporting migration of arrays of pointers
holdig a mix of null and not null pointers.
v1 -> v2:
* do not ignore return value (Dave)
* change some asserts to report_error+rc (Dave)
* factor out and reuse wire_sample in patches 4 and 5 (Dave)
* minor reword of patch 2
* add r-b's
RFC v2 -> v1:
* rebase
* changed marker as suggested by Dave (incl. simplifications)
* fixed issues pointed out by Dave
* reworded some commit messages
* added a test for array of ptr to primitive
Halil Pasic (5):
migration/vmstate: renames in (load|save)_state
migration/vmstate: split up vmstate_base_addr
migration/vmstate: fix array of ptr with nullptrs
tests/test-vmstate.c: test array of ptr with null
tests/test-vmstate.c: test array of ptr to primitive
include/migration/vmstate.h | 4 ++
migration/vmstate.c | 97 +++++++++++++++++++++++------------
tests/test-vmstate.c | 122 ++++++++++++++++++++++++++++++++++++++------
3 files changed, 173 insertions(+), 50 deletions(-)
--
2.8.4
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH v2 1/5] migration/vmstate: renames in (load|save)_state
2017-02-22 16:01 [Qemu-devel] [PATCH v2 0/5] vmstate: handle arrays with null ptrs Halil Pasic
@ 2017-02-22 16:01 ` Halil Pasic
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 2/5] migration/vmstate: split up vmstate_base_addr Halil Pasic
` (4 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Halil Pasic @ 2017-02-22 16:01 UTC (permalink / raw)
To: qemu-devel, Dr. David Alan Gilbert; +Cc: Juan Quintela, Amit Shah, Halil Pasic
The vmstate_(load|save)_state start out with an a void *opaque pointing
to some struct, and manipulate one or more elements of one field within
that struct.
First the field within the struct is pinpointed as opaque + offset, then
if this is a pointer the pointer is dereferenced to obtain a pointer to
the first element of the vmstate field. Pointers to further elements if
any are calculated as first_element + i * element_size (where i is the
zero based index of the element in question).
Currently base_addr and addr is used as a variable name for the pointer
to the first element and the pointer to the current element being
processed. This is suboptimal because base_addr is somewhat
counter-intuitive (because obtained as base + offset) and both base_addr
and addr not very descriptive (that we have a pointer should be clear
from the fact that it is declared as a pointer).
Let make things easier to understand by renaming base_addr to first_elem
and addr to curr_elem. This has the additional benefit of harmonizing
with other names within the scope (n_elems, vmstate_n_elems).
Signed-off-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
This patch roots in the difficulties I faced when trying to figure out
the code in question. In the meanwhile I'm quite fine with the current
names because I have it already figured out (after a couple of months
not looking on this code however, who knows). Thus my main motivation
is making things easier for the next new guy, but if the old guys say
not worth it I can very well accept that too.
---
migration/vmstate.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/migration/vmstate.c b/migration/vmstate.c
index b4d8ae9..36efa80 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -116,21 +116,21 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
field->field_exists(opaque, version_id)) ||
(!field->field_exists &&
field->version_id <= version_id)) {
- void *base_addr = vmstate_base_addr(opaque, field, true);
+ void *first_elem = vmstate_base_addr(opaque, field, true);
int i, n_elems = vmstate_n_elems(opaque, field);
int size = vmstate_size(opaque, field);
for (i = 0; i < n_elems; i++) {
- void *addr = base_addr + size * i;
+ void *curr_elem = first_elem + size * i;
if (field->flags & VMS_ARRAY_OF_POINTER) {
- addr = *(void **)addr;
+ curr_elem = *(void **)curr_elem;
}
if (field->flags & VMS_STRUCT) {
- ret = vmstate_load_state(f, field->vmsd, addr,
+ ret = vmstate_load_state(f, field->vmsd, curr_elem,
field->vmsd->version_id);
} else {
- ret = field->info->get(f, addr, size, field);
+ ret = field->info->get(f, curr_elem, size, field);
}
if (ret >= 0) {
ret = qemu_file_get_error(f);
@@ -321,7 +321,7 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
while (field->name) {
if (!field->field_exists ||
field->field_exists(opaque, vmsd->version_id)) {
- void *base_addr = vmstate_base_addr(opaque, field, false);
+ void *first_elem = vmstate_base_addr(opaque, field, false);
int i, n_elems = vmstate_n_elems(opaque, field);
int size = vmstate_size(opaque, field);
int64_t old_offset, written_bytes;
@@ -329,18 +329,18 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems);
for (i = 0; i < n_elems; i++) {
- void *addr = base_addr + size * i;
+ void *curr_elem = first_elem + size * i;
vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems);
old_offset = qemu_ftell_fast(f);
-
if (field->flags & VMS_ARRAY_OF_POINTER) {
- addr = *(void **)addr;
+ assert(curr_elem);
+ curr_elem = *(void **)curr_elem;
}
if (field->flags & VMS_STRUCT) {
- vmstate_save_state(f, field->vmsd, addr, vmdesc_loop);
+ vmstate_save_state(f, field->vmsd, curr_elem, vmdesc_loop);
} else {
- field->info->put(f, addr, size, field, vmdesc_loop);
+ field->info->put(f, curr_elem, size, field, vmdesc_loop);
}
written_bytes = qemu_ftell_fast(f) - old_offset;
--
2.8.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH v2 2/5] migration/vmstate: split up vmstate_base_addr
2017-02-22 16:01 [Qemu-devel] [PATCH v2 0/5] vmstate: handle arrays with null ptrs Halil Pasic
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 1/5] migration/vmstate: renames in (load|save)_state Halil Pasic
@ 2017-02-22 16:01 ` Halil Pasic
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 3/5] migration/vmstate: fix array of ptr with nullptrs Halil Pasic
` (3 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Halil Pasic @ 2017-02-22 16:01 UTC (permalink / raw)
To: qemu-devel, Dr. David Alan Gilbert; +Cc: Juan Quintela, Amit Shah, Halil Pasic
Currently vmstate_base_addr does several things: it pinpoints the field
within the struct, possibly allocates memory and possibly does the first
pointer dereference. Obviously allocation is needed only for load.
Let us split up the functionality in vmstate_base_addr and move the
address manipulations (that is everything but the allocation logic) to
load and save so it becomes more obvious what is actually going on. Like
this all the address calculations (and the handling of the flags
controlling these) is in one place and the sequence is more obvious.
The newly introduced function vmstate_handle_alloc also fixes the
allocation for the unused VMS_VBUFFER|VMS_MULTIPLY|VMS_ALLOC scenario
and is substantially simpler than the original vmstate_base_addr.
In load and save some asserts are added so it's easier to debug
situations where we would end up with a null pointer dereference.
Signed-off-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
migration/vmstate.c | 39 +++++++++++++++++----------------------
1 file changed, 17 insertions(+), 22 deletions(-)
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 36efa80..836a7a4 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -52,29 +52,15 @@ static int vmstate_size(void *opaque, VMStateField *field)
return size;
}
-static void *vmstate_base_addr(void *opaque, VMStateField *field, bool alloc)
+static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque)
{
- void *base_addr = opaque + field->offset;
-
- if (field->flags & VMS_POINTER) {
- if (alloc && (field->flags & VMS_ALLOC)) {
- gsize size = 0;
- if (field->flags & VMS_VBUFFER) {
- size = vmstate_size(opaque, field);
- } else {
- int n_elems = vmstate_n_elems(opaque, field);
- if (n_elems) {
- size = n_elems * field->size;
- }
- }
- if (size) {
- *(void **)base_addr = g_malloc(size);
- }
+ if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {
+ gsize size = vmstate_size(opaque, field);
+ size *= vmstate_n_elems(opaque, field);
+ if (size) {
+ *(void **)ptr = g_malloc(size);
}
- base_addr = *(void **)base_addr;
}
-
- return base_addr;
}
int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
@@ -116,10 +102,15 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
field->field_exists(opaque, version_id)) ||
(!field->field_exists &&
field->version_id <= version_id)) {
- void *first_elem = vmstate_base_addr(opaque, field, true);
+ void *first_elem = opaque + field->offset;
int i, n_elems = vmstate_n_elems(opaque, field);
int size = vmstate_size(opaque, field);
+ vmstate_handle_alloc(first_elem, field, opaque);
+ if (field->flags & VMS_POINTER) {
+ first_elem = *(void **)first_elem;
+ assert(first_elem || !n_elems);
+ }
for (i = 0; i < n_elems; i++) {
void *curr_elem = first_elem + size * i;
@@ -321,13 +312,17 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
while (field->name) {
if (!field->field_exists ||
field->field_exists(opaque, vmsd->version_id)) {
- void *first_elem = vmstate_base_addr(opaque, field, false);
+ void *first_elem = opaque + field->offset;
int i, n_elems = vmstate_n_elems(opaque, field);
int size = vmstate_size(opaque, field);
int64_t old_offset, written_bytes;
QJSON *vmdesc_loop = vmdesc;
trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems);
+ if (field->flags & VMS_POINTER) {
+ first_elem = *(void **)first_elem;
+ assert(first_elem || !n_elems);
+ }
for (i = 0; i < n_elems; i++) {
void *curr_elem = first_elem + size * i;
--
2.8.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH v2 3/5] migration/vmstate: fix array of ptr with nullptrs
2017-02-22 16:01 [Qemu-devel] [PATCH v2 0/5] vmstate: handle arrays with null ptrs Halil Pasic
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 1/5] migration/vmstate: renames in (load|save)_state Halil Pasic
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 2/5] migration/vmstate: split up vmstate_base_addr Halil Pasic
@ 2017-02-22 16:01 ` Halil Pasic
2017-02-24 12:29 ` Dr. David Alan Gilbert
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 4/5] tests/test-vmstate.c: test array of ptr with null Halil Pasic
` (2 subsequent siblings)
5 siblings, 1 reply; 10+ messages in thread
From: Halil Pasic @ 2017-02-22 16:01 UTC (permalink / raw)
To: qemu-devel, Dr. David Alan Gilbert; +Cc: Juan Quintela, Amit Shah, Halil Pasic
Make VMS_ARRAY_OF_POINTER cope with null pointers. Previously the
reward for trying to migrate an array with some null pointers in it was
an illegal memory access, that is a swift and painless death of the
process. Let's make vmstate cope with this scenario.
The general approach is, when we encounter a null pointer (element),
instead of following the pointer to save/load the data behind it, we
save/load a placeholder. This way we can detect if we expected a null
pointer at the load side but not null data was saved instead.
Signed-off-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Guenther Hutzl <hutzl@linux.vnet.ibm.com>
---
We will need this to load/save some on demand created state in the
(s390x) channel subsystem (see ChannelSubSys.css in hw/s390x/css.c for
an example).
---
include/migration/vmstate.h | 4 ++++
migration/vmstate.c | 40 ++++++++++++++++++++++++++++++++++++++--
2 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 63e7b02..f2dbf84 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -253,6 +253,10 @@ extern const VMStateInfo vmstate_info_uint16;
extern const VMStateInfo vmstate_info_uint32;
extern const VMStateInfo vmstate_info_uint64;
+/** Put this in the stream when migrating a null pointer.*/
+#define VMS_NULLPTR_MARKER (0x30U) /* '0' */
+extern const VMStateInfo vmstate_info_nullptr;
+
extern const VMStateInfo vmstate_info_float64;
extern const VMStateInfo vmstate_info_cpudouble;
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 836a7a4..78b3cd4 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -117,7 +117,11 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
if (field->flags & VMS_ARRAY_OF_POINTER) {
curr_elem = *(void **)curr_elem;
}
- if (field->flags & VMS_STRUCT) {
+ if (!curr_elem) {
+ /* if null pointer check placeholder and do not follow */
+ assert(field->flags & VMS_ARRAY_OF_POINTER);
+ ret = vmstate_info_nullptr.get(f, curr_elem, size, NULL);
+ } else if (field->flags & VMS_STRUCT) {
ret = vmstate_load_state(f, field->vmsd, curr_elem,
field->vmsd->version_id);
} else {
@@ -332,7 +336,11 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
assert(curr_elem);
curr_elem = *(void **)curr_elem;
}
- if (field->flags & VMS_STRUCT) {
+ if (!curr_elem) {
+ /* if null pointer write placeholder and do not follow */
+ assert(field->flags & VMS_ARRAY_OF_POINTER);
+ vmstate_info_nullptr.put(f, curr_elem, size, NULL, NULL);
+ } else if (field->flags & VMS_STRUCT) {
vmstate_save_state(f, field->vmsd, curr_elem, vmdesc_loop);
} else {
field->info->put(f, curr_elem, size, field, vmdesc_loop);
@@ -747,6 +755,34 @@ const VMStateInfo vmstate_info_uint64 = {
.put = put_uint64,
};
+static int get_nullptr(QEMUFile *f, void *pv, size_t size, VMStateField *field)
+
+{
+ if (qemu_get_byte(f) == VMS_NULLPTR_MARKER) {
+ return 0;
+ }
+ error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
+ return -EINVAL;
+}
+
+static int put_nullptr(QEMUFile *f, void *pv, size_t size,
+ VMStateField *field, QJSON *vmdesc)
+
+{
+ if (pv == NULL) {
+ qemu_put_byte(f, VMS_NULLPTR_MARKER);
+ return 0;
+ }
+ error_report("vmstate: put_nullptr must be called with pv == NULL");
+ return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_nullptr = {
+ .name = "uint64",
+ .get = get_nullptr,
+ .put = put_nullptr,
+};
+
/* 64 bit unsigned int. See that the received value is the same than the one
in the field */
--
2.8.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH v2 4/5] tests/test-vmstate.c: test array of ptr with null
2017-02-22 16:01 [Qemu-devel] [PATCH v2 0/5] vmstate: handle arrays with null ptrs Halil Pasic
` (2 preceding siblings ...)
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 3/5] migration/vmstate: fix array of ptr with nullptrs Halil Pasic
@ 2017-02-22 16:01 ` Halil Pasic
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 5/5] tests/test-vmstate.c: test array of ptr to primitive Halil Pasic
2017-02-28 9:36 ` [Qemu-devel] [PATCH v2 0/5] vmstate: handle arrays with null ptrs Dr. David Alan Gilbert
5 siblings, 0 replies; 10+ messages in thread
From: Halil Pasic @ 2017-02-22 16:01 UTC (permalink / raw)
To: qemu-devel, Dr. David Alan Gilbert; +Cc: Juan Quintela, Amit Shah, Halil Pasic
Add test for VMSTATE_ARRAY_OF_POINTER_TO_STRUCT with an array
containing some null pointer.
Signed-off-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
tests/test-vmstate.c | 74 ++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 57 insertions(+), 17 deletions(-)
diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c
index 39f338a..eafef94 100644
--- a/tests/test-vmstate.c
+++ b/tests/test-vmstate.c
@@ -476,6 +476,8 @@ const VMStateDescription vmsd_tst = {
}
};
+/* test array migration */
+
#define AR_SIZE 4
typedef struct {
@@ -492,20 +494,22 @@ const VMStateDescription vmsd_arps = {
VMSTATE_END_OF_LIST()
}
};
+
+static uint8_t wire_arr_ptr_no0[] = {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x03,
+ QEMU_VM_EOF
+};
+
static void test_arr_ptr_str_no0_save(void)
{
TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
TestArrayOfPtrToStuct sample = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} };
- uint8_t wire_sample[] = {
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x03,
- QEMU_VM_EOF
- };
save_vmstate(&vmsd_arps, &sample);
- compare_vmstate(wire_sample, sizeof(wire_sample));
+ compare_vmstate(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0));
}
static void test_arr_ptr_str_no0_load(void)
@@ -514,21 +518,54 @@ static void test_arr_ptr_str_no0_load(void)
TestStructTriv ar[AR_SIZE] = {};
TestArrayOfPtrToStuct obj = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} };
int idx;
- uint8_t wire_sample[] = {
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x03,
- QEMU_VM_EOF
- };
- save_buffer(wire_sample, sizeof(wire_sample));
+ save_buffer(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0));
+ SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1,
+ wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0)));
+ for (idx = 0; idx < AR_SIZE; ++idx) {
+ /* compare the target array ar with the ground truth array ar_gt */
+ g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i);
+ }
+}
+
+static uint8_t wire_arr_ptr_0[] = {
+ 0x00, 0x00, 0x00, 0x00,
+ VMS_NULLPTR_MARKER,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x03,
+ QEMU_VM_EOF
+};
+
+static void test_arr_ptr_str_0_save(void)
+{
+ TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
+ TestArrayOfPtrToStuct sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
+
+ save_vmstate(&vmsd_arps, &sample);
+ compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
+}
+
+static void test_arr_ptr_str_0_load(void)
+{
+ TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 0}, {.i = 2}, {.i = 3} };
+ TestStructTriv ar[AR_SIZE] = {};
+ TestArrayOfPtrToStuct obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
+ int idx;
+
+ save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1,
- wire_sample, sizeof(wire_sample)));
+ wire_arr_ptr_0, sizeof(wire_arr_ptr_0)));
for (idx = 0; idx < AR_SIZE; ++idx) {
/* compare the target array ar with the ground truth array ar_gt */
g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i);
}
+ for (idx = 0; idx < AR_SIZE; ++idx) {
+ if (idx == 1) {
+ g_assert_cmpint((uint64_t)(obj.ar[idx]), ==, 0);
+ } else {
+ g_assert_cmpint((uint64_t)(obj.ar[idx]), !=, 0);
+ }
+ }
}
/* test QTAILQ migration */
@@ -781,6 +818,9 @@ int main(int argc, char **argv)
test_arr_ptr_str_no0_save);
g_test_add_func("/vmstate/array/ptr/str/no0/load",
test_arr_ptr_str_no0_load);
+ g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save);
+ g_test_add_func("/vmstate/array/ptr/str/0/load",
+ test_arr_ptr_str_0_load);
g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q);
g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q);
g_test_add_func("/vmstate/tmp_struct", test_tmp_struct);
--
2.8.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH v2 5/5] tests/test-vmstate.c: test array of ptr to primitive
2017-02-22 16:01 [Qemu-devel] [PATCH v2 0/5] vmstate: handle arrays with null ptrs Halil Pasic
` (3 preceding siblings ...)
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 4/5] tests/test-vmstate.c: test array of ptr with null Halil Pasic
@ 2017-02-22 16:01 ` Halil Pasic
2017-02-28 9:36 ` [Qemu-devel] [PATCH v2 0/5] vmstate: handle arrays with null ptrs Dr. David Alan Gilbert
5 siblings, 0 replies; 10+ messages in thread
From: Halil Pasic @ 2017-02-22 16:01 UTC (permalink / raw)
To: qemu-devel, Dr. David Alan Gilbert; +Cc: Juan Quintela, Amit Shah, Halil Pasic
Let's have a test for ptr arrays to some primitive type with some
not-null and null ptrs intermixed.
Signed-off-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
Mainly for the sake of completeness and also to demonstrate that it works
since in the previous version I wrongly stated it does not. If guys think
we do not need this, I'm happy with just dropping it.
---
tests/test-vmstate.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c
index eafef94..3abdc1a 100644
--- a/tests/test-vmstate.c
+++ b/tests/test-vmstate.c
@@ -568,6 +568,50 @@ static void test_arr_ptr_str_0_load(void)
}
}
+typedef struct TestArrayOfPtrToInt {
+ int32_t *ar[AR_SIZE];
+} TestArrayOfPtrToInt;
+
+const VMStateDescription vmsd_arpp = {
+ .name = "test/arps",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_ARRAY_OF_POINTER(ar, TestArrayOfPtrToInt,
+ AR_SIZE, 0, vmstate_info_int32, int32_t*),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void test_arr_ptr_prim_0_save(void)
+{
+ int32_t ar[AR_SIZE] = {0 , 1, 2, 3};
+ TestArrayOfPtrToInt sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
+
+ save_vmstate(&vmsd_arpp, &sample);
+ compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
+}
+
+static void test_arr_ptr_prim_0_load(void)
+{
+ int32_t ar_gt[AR_SIZE] = {0, 1, 2, 3};
+ int32_t ar[AR_SIZE] = {3 , 42, 1, 0};
+ TestArrayOfPtrToInt obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
+ int idx;
+
+ save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
+ SUCCESS(load_vmstate_one(&vmsd_arpp, &obj, 1,
+ wire_arr_ptr_0, sizeof(wire_arr_ptr_0)));
+ for (idx = 0; idx < AR_SIZE; ++idx) {
+ /* compare the target array ar with the ground truth array ar_gt */
+ if (idx == 1) {
+ g_assert_cmpint(42, ==, ar[idx]);
+ } else {
+ g_assert_cmpint(ar_gt[idx], ==, ar[idx]);
+ }
+ }
+}
+
/* test QTAILQ migration */
typedef struct TestQtailqElement TestQtailqElement;
@@ -821,6 +865,10 @@ int main(int argc, char **argv)
g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save);
g_test_add_func("/vmstate/array/ptr/str/0/load",
test_arr_ptr_str_0_load);
+ g_test_add_func("/vmstate/array/ptr/prim/0/save",
+ test_arr_ptr_prim_0_save);
+ g_test_add_func("/vmstate/array/ptr/prim/0/load",
+ test_arr_ptr_prim_0_load);
g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q);
g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q);
g_test_add_func("/vmstate/tmp_struct", test_tmp_struct);
--
2.8.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/5] migration/vmstate: fix array of ptr with nullptrs
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 3/5] migration/vmstate: fix array of ptr with nullptrs Halil Pasic
@ 2017-02-24 12:29 ` Dr. David Alan Gilbert
2017-02-27 14:02 ` Halil Pasic
0 siblings, 1 reply; 10+ messages in thread
From: Dr. David Alan Gilbert @ 2017-02-24 12:29 UTC (permalink / raw)
To: Halil Pasic; +Cc: qemu-devel, Juan Quintela
* Halil Pasic (pasic@linux.vnet.ibm.com) wrote:
> Make VMS_ARRAY_OF_POINTER cope with null pointers. Previously the
> reward for trying to migrate an array with some null pointers in it was
> an illegal memory access, that is a swift and painless death of the
> process. Let's make vmstate cope with this scenario.
>
> The general approach is, when we encounter a null pointer (element),
> instead of following the pointer to save/load the data behind it, we
> save/load a placeholder. This way we can detect if we expected a null
> pointer at the load side but not null data was saved instead.
>
> Signed-off-by: Halil Pasic <pasic@linux.vnet.ibm.com>
> Reviewed-by: Guenther Hutzl <hutzl@linux.vnet.ibm.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
> We will need this to load/save some on demand created state in the
> (s390x) channel subsystem (see ChannelSubSys.css in hw/s390x/css.c for
> an example).
> ---
> include/migration/vmstate.h | 4 ++++
> migration/vmstate.c | 40 ++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 42 insertions(+), 2 deletions(-)
>
> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> index 63e7b02..f2dbf84 100644
> --- a/include/migration/vmstate.h
> +++ b/include/migration/vmstate.h
> @@ -253,6 +253,10 @@ extern const VMStateInfo vmstate_info_uint16;
> extern const VMStateInfo vmstate_info_uint32;
> extern const VMStateInfo vmstate_info_uint64;
>
> +/** Put this in the stream when migrating a null pointer.*/
> +#define VMS_NULLPTR_MARKER (0x30U) /* '0' */
> +extern const VMStateInfo vmstate_info_nullptr;
> +
> extern const VMStateInfo vmstate_info_float64;
> extern const VMStateInfo vmstate_info_cpudouble;
>
> diff --git a/migration/vmstate.c b/migration/vmstate.c
> index 836a7a4..78b3cd4 100644
> --- a/migration/vmstate.c
> +++ b/migration/vmstate.c
> @@ -117,7 +117,11 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> if (field->flags & VMS_ARRAY_OF_POINTER) {
> curr_elem = *(void **)curr_elem;
> }
> - if (field->flags & VMS_STRUCT) {
> + if (!curr_elem) {
> + /* if null pointer check placeholder and do not follow */
> + assert(field->flags & VMS_ARRAY_OF_POINTER);
> + ret = vmstate_info_nullptr.get(f, curr_elem, size, NULL);
> + } else if (field->flags & VMS_STRUCT) {
> ret = vmstate_load_state(f, field->vmsd, curr_elem,
> field->vmsd->version_id);
> } else {
> @@ -332,7 +336,11 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
> assert(curr_elem);
> curr_elem = *(void **)curr_elem;
> }
> - if (field->flags & VMS_STRUCT) {
> + if (!curr_elem) {
> + /* if null pointer write placeholder and do not follow */
> + assert(field->flags & VMS_ARRAY_OF_POINTER);
> + vmstate_info_nullptr.put(f, curr_elem, size, NULL, NULL);
> + } else if (field->flags & VMS_STRUCT) {
> vmstate_save_state(f, field->vmsd, curr_elem, vmdesc_loop);
> } else {
> field->info->put(f, curr_elem, size, field, vmdesc_loop);
> @@ -747,6 +755,34 @@ const VMStateInfo vmstate_info_uint64 = {
> .put = put_uint64,
> };
>
> +static int get_nullptr(QEMUFile *f, void *pv, size_t size, VMStateField *field)
> +
> +{
> + if (qemu_get_byte(f) == VMS_NULLPTR_MARKER) {
> + return 0;
> + }
> + error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
> + return -EINVAL;
> +}
> +
> +static int put_nullptr(QEMUFile *f, void *pv, size_t size,
> + VMStateField *field, QJSON *vmdesc)
> +
> +{
> + if (pv == NULL) {
> + qemu_put_byte(f, VMS_NULLPTR_MARKER);
> + return 0;
> + }
> + error_report("vmstate: put_nullptr must be called with pv == NULL");
> + return -EINVAL;
> +}
> +
> +const VMStateInfo vmstate_info_nullptr = {
> + .name = "uint64",
> + .get = get_nullptr,
> + .put = put_nullptr,
> +};
> +
> /* 64 bit unsigned int. See that the received value is the same than the one
> in the field */
>
> --
> 2.8.4
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/5] migration/vmstate: fix array of ptr with nullptrs
2017-02-24 12:29 ` Dr. David Alan Gilbert
@ 2017-02-27 14:02 ` Halil Pasic
2017-02-27 19:00 ` Dr. David Alan Gilbert
0 siblings, 1 reply; 10+ messages in thread
From: Halil Pasic @ 2017-02-27 14:02 UTC (permalink / raw)
To: Dr. David Alan Gilbert; +Cc: qemu-devel, Juan Quintela
On 02/24/2017 01:29 PM, Dr. David Alan Gilbert wrote:
> * Halil Pasic (pasic@linux.vnet.ibm.com) wrote:
>> Make VMS_ARRAY_OF_POINTER cope with null pointers. Previously the
>> reward for trying to migrate an array with some null pointers in it was
>> an illegal memory access, that is a swift and painless death of the
>> process. Let's make vmstate cope with this scenario.
>>
>> The general approach is, when we encounter a null pointer (element),
>> instead of following the pointer to save/load the data behind it, we
>> save/load a placeholder. This way we can detect if we expected a null
>> pointer at the load side but not null data was saved instead.
>>
>> Signed-off-by: Halil Pasic <pasic@linux.vnet.ibm.com>
>> Reviewed-by: Guenther Hutzl <hutzl@linux.vnet.ibm.com>
>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
>
Thanks! Seems there are no further objections. Is the series going in
via your tree (softfreeze starting 28.02, me worried)?
Regards,
Halil
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/5] migration/vmstate: fix array of ptr with nullptrs
2017-02-27 14:02 ` Halil Pasic
@ 2017-02-27 19:00 ` Dr. David Alan Gilbert
0 siblings, 0 replies; 10+ messages in thread
From: Dr. David Alan Gilbert @ 2017-02-27 19:00 UTC (permalink / raw)
To: Halil Pasic; +Cc: qemu-devel, Juan Quintela
* Halil Pasic (pasic@linux.vnet.ibm.com) wrote:
>
>
> On 02/24/2017 01:29 PM, Dr. David Alan Gilbert wrote:
> > * Halil Pasic (pasic@linux.vnet.ibm.com) wrote:
> >> Make VMS_ARRAY_OF_POINTER cope with null pointers. Previously the
> >> reward for trying to migrate an array with some null pointers in it was
> >> an illegal memory access, that is a swift and painless death of the
> >> process. Let's make vmstate cope with this scenario.
> >>
> >> The general approach is, when we encounter a null pointer (element),
> >> instead of following the pointer to save/load the data behind it, we
> >> save/load a placeholder. This way we can detect if we expected a null
> >> pointer at the load side but not null data was saved instead.
> >>
> >> Signed-off-by: Halil Pasic <pasic@linux.vnet.ibm.com>
> >> Reviewed-by: Guenther Hutzl <hutzl@linux.vnet.ibm.com>
> >
> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> >
>
> Thanks! Seems there are no further objections. Is the series going in
> via your tree (softfreeze starting 28.02, me worried)?
I'm ok with that; and there will be a migration pull tomorrow.
So lets see what we can do.
Dave
>
> Regards,
> Halil
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH v2 0/5] vmstate: handle arrays with null ptrs
2017-02-22 16:01 [Qemu-devel] [PATCH v2 0/5] vmstate: handle arrays with null ptrs Halil Pasic
` (4 preceding siblings ...)
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 5/5] tests/test-vmstate.c: test array of ptr to primitive Halil Pasic
@ 2017-02-28 9:36 ` Dr. David Alan Gilbert
5 siblings, 0 replies; 10+ messages in thread
From: Dr. David Alan Gilbert @ 2017-02-28 9:36 UTC (permalink / raw)
To: Halil Pasic; +Cc: qemu-devel, Juan Quintela
* Halil Pasic (pasic@linux.vnet.ibm.com) wrote:
> The objective is supporting migration of arrays of pointers
> holdig a mix of null and not null pointers.
Queued.
> v1 -> v2:
> * do not ignore return value (Dave)
> * change some asserts to report_error+rc (Dave)
> * factor out and reuse wire_sample in patches 4 and 5 (Dave)
> * minor reword of patch 2
> * add r-b's
>
>
> RFC v2 -> v1:
> * rebase
> * changed marker as suggested by Dave (incl. simplifications)
> * fixed issues pointed out by Dave
> * reworded some commit messages
> * added a test for array of ptr to primitive
>
>
> Halil Pasic (5):
> migration/vmstate: renames in (load|save)_state
> migration/vmstate: split up vmstate_base_addr
> migration/vmstate: fix array of ptr with nullptrs
> tests/test-vmstate.c: test array of ptr with null
> tests/test-vmstate.c: test array of ptr to primitive
>
> include/migration/vmstate.h | 4 ++
> migration/vmstate.c | 97 +++++++++++++++++++++++------------
> tests/test-vmstate.c | 122 ++++++++++++++++++++++++++++++++++++++------
> 3 files changed, 173 insertions(+), 50 deletions(-)
>
> --
> 2.8.4
>
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2017-02-28 9:37 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-02-22 16:01 [Qemu-devel] [PATCH v2 0/5] vmstate: handle arrays with null ptrs Halil Pasic
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 1/5] migration/vmstate: renames in (load|save)_state Halil Pasic
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 2/5] migration/vmstate: split up vmstate_base_addr Halil Pasic
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 3/5] migration/vmstate: fix array of ptr with nullptrs Halil Pasic
2017-02-24 12:29 ` Dr. David Alan Gilbert
2017-02-27 14:02 ` Halil Pasic
2017-02-27 19:00 ` Dr. David Alan Gilbert
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 4/5] tests/test-vmstate.c: test array of ptr with null Halil Pasic
2017-02-22 16:01 ` [Qemu-devel] [PATCH v2 5/5] tests/test-vmstate.c: test array of ptr to primitive Halil Pasic
2017-02-28 9:36 ` [Qemu-devel] [PATCH v2 0/5] vmstate: handle arrays with null ptrs Dr. David Alan Gilbert
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).