Merge remote-tracking branch 'remotes/juanquintela/tags/migration/20141015' into staging

migration/next for 20141015

# gpg: Signature made Wed 15 Oct 2014 09:21:54 BST using RSA key ID 5872D723
# gpg: Can't check signature: public key not found

* remotes/juanquintela/tags/migration/20141015:
  migration: catch unknown flag combinations in ram_load
  qemu-file: Move stdio implementation to qemu-file-stdio.c
  qemu-file: Move unix and socket implementations to qemu-file-unix.c
  qemu-file: Use qemu_file_is_writable() on stdio_fclose()
  qemu-file: Make qemu_file_is_writable() non-static
  qemu-file: Add copyright header to qemu-file.c
  vmstate: Allow dynamic allocation for VBUFFER during migration
  block/migration: Disable cache invalidate for incoming migration
  Tests: QEMUSizedBuffer/QEMUBuffer
  QEMUSizedBuffer based QEMUFile

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2014-10-15 11:55:54 +01:00
14 changed files with 1029 additions and 450 deletions
+1 -1
View File
@@ -50,7 +50,7 @@ common-obj-$(CONFIG_LINUX) += fsdev/
common-obj-y += migration.o migration-tcp.o
common-obj-y += vmstate.o
common-obj-y += qemu-file.o
common-obj-y += qemu-file.o qemu-file-unix.o qemu-file-stdio.o
common-obj-$(CONFIG_RDMA) += migration-rdma.o
common-obj-y += qemu-char.o #aio.o
common-obj-y += block-migration.o
+32 -30
View File
@@ -1040,8 +1040,7 @@ void ram_handle_compressed(void *host, uint8_t ch, uint64_t size)
static int ram_load(QEMUFile *f, void *opaque, int version_id)
{
ram_addr_t addr;
int flags, ret = 0;
int flags = 0, ret = 0;
static uint64_t seq_iter;
seq_iter++;
@@ -1050,21 +1049,24 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
ret = -EINVAL;
}
while (!ret) {
addr = qemu_get_be64(f);
while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) {
ram_addr_t addr, total_ram_bytes;
void *host;
uint8_t ch;
addr = qemu_get_be64(f);
flags = addr & ~TARGET_PAGE_MASK;
addr &= TARGET_PAGE_MASK;
if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
switch (flags & ~RAM_SAVE_FLAG_CONTINUE) {
case RAM_SAVE_FLAG_MEM_SIZE:
/* Synchronize RAM block list */
char id[256];
ram_addr_t length;
ram_addr_t total_ram_bytes = addr;
while (total_ram_bytes) {
total_ram_bytes = addr;
while (!ret && total_ram_bytes) {
RAMBlock *block;
uint8_t len;
char id[256];
ram_addr_t length;
len = qemu_get_byte(f);
qemu_get_buffer(f, (uint8_t *)id, len);
@@ -1088,16 +1090,11 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
"accept migration", id);
ret = -EINVAL;
}
if (ret) {
break;
}
total_ram_bytes -= length;
}
} else if (flags & RAM_SAVE_FLAG_COMPRESS) {
void *host;
uint8_t ch;
break;
case RAM_SAVE_FLAG_COMPRESS:
host = host_from_stream_offset(f, addr, flags);
if (!host) {
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
@@ -1107,9 +1104,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
ch = qemu_get_byte(f);
ram_handle_compressed(host, ch, TARGET_PAGE_SIZE);
} else if (flags & RAM_SAVE_FLAG_PAGE) {
void *host;
break;
case RAM_SAVE_FLAG_PAGE:
host = host_from_stream_offset(f, addr, flags);
if (!host) {
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
@@ -1118,8 +1114,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
}
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
} else if (flags & RAM_SAVE_FLAG_XBZRLE) {
void *host = host_from_stream_offset(f, addr, flags);
break;
case RAM_SAVE_FLAG_XBZRLE:
host = host_from_stream_offset(f, addr, flags);
if (!host) {
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
ret = -EINVAL;
@@ -1132,17 +1129,22 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
ret = -EINVAL;
break;
}
} else if (flags & RAM_SAVE_FLAG_HOOK) {
ram_control_load_hook(f, flags);
} else if (flags & RAM_SAVE_FLAG_EOS) {
break;
case RAM_SAVE_FLAG_EOS:
/* normal exit */
break;
} else {
error_report("Unknown migration flags: %#x", flags);
ret = -EINVAL;
break;
default:
if (flags & RAM_SAVE_FLAG_HOOK) {
ram_control_load_hook(f, flags);
} else {
error_report("Unknown combination of migration flags: %#x",
flags);
ret = -EINVAL;
}
}
if (!ret) {
ret = qemu_file_get_error(f);
}
ret = qemu_file_get_error(f);
}
DPRINTF("Completed load of VM with exit code %d seq iteration "
+5 -13
View File
@@ -5043,6 +5043,11 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
return;
}
if (!(bs->open_flags & BDRV_O_INCOMING)) {
return;
}
bs->open_flags &= ~BDRV_O_INCOMING;
if (bs->drv->bdrv_invalidate_cache) {
bs->drv->bdrv_invalidate_cache(bs, &local_err);
} else if (bs->file) {
@@ -5078,19 +5083,6 @@ void bdrv_invalidate_cache_all(Error **errp)
}
}
void bdrv_clear_incoming_migration_all(void)
{
BlockDriverState *bs;
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
AioContext *aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
bs->open_flags = bs->open_flags & ~(BDRV_O_INCOMING);
aio_context_release(aio_context);
}
}
int bdrv_flush(BlockDriverState *bs)
{
Coroutine *co;
+27
View File
@@ -25,6 +25,8 @@
#define QEMU_FILE_H 1
#include "exec/cpu-common.h"
#include <stdint.h>
/* This function writes a chunk of data to a file at the given position.
* The pos argument can be ignored if the file is only being used for
* streaming. The handler should try to write all of the data it can.
@@ -94,11 +96,19 @@ typedef struct QEMUFileOps {
QEMURamSaveFunc *save_page;
} QEMUFileOps;
struct QEMUSizedBuffer {
struct iovec *iov;
size_t n_iov;
size_t size; /* total allocated size in all iov's */
size_t used; /* number of used bytes */
};
QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
QEMUFile *qemu_fopen(const char *filename, const char *mode);
QEMUFile *qemu_fdopen(int fd, const char *mode);
QEMUFile *qemu_fopen_socket(int fd, const char *mode);
QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input);
int qemu_get_fd(QEMUFile *f);
int qemu_fclose(QEMUFile *f);
int64_t qemu_ftell(QEMUFile *f);
@@ -110,6 +120,23 @@ void qemu_put_byte(QEMUFile *f, int v);
*/
void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size);
bool qemu_file_mode_is_not_valid(const char *mode);
bool qemu_file_is_writable(QEMUFile *f);
QEMUSizedBuffer *qsb_create(const uint8_t *buffer, size_t len);
QEMUSizedBuffer *qsb_clone(const QEMUSizedBuffer *);
void qsb_free(QEMUSizedBuffer *);
size_t qsb_set_length(QEMUSizedBuffer *qsb, size_t length);
size_t qsb_get_length(const QEMUSizedBuffer *qsb);
ssize_t qsb_get_buffer(const QEMUSizedBuffer *, off_t start, size_t count,
uint8_t *buf);
ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *buf,
off_t pos, size_t count);
/*
* For use on files opened with qemu_bufopen
*/
const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f);
static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v)
{
+11
View File
@@ -484,6 +484,17 @@ extern const VMStateInfo vmstate_info_bitmap;
.start = (_start), \
}
#define VMSTATE_VBUFFER_ALLOC_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|VMS_ALLOC, \
.offset = offsetof(_state, _field), \
.start = (_start), \
}
#define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \
.name = (stringify(_field)), \
.version_id = (_version), \
+1
View File
@@ -71,6 +71,7 @@ typedef struct SSIBus SSIBus;
typedef struct EventNotifier EventNotifier;
typedef struct VirtIODevice VirtIODevice;
typedef struct QEMUSGList QEMUSGList;
typedef struct QEMUSizedBuffer QEMUSizedBuffer;
typedef struct SHPCDevice SHPCDevice;
typedef struct FWCfgState FWCfgState;
typedef struct PcGuestInfo PcGuestInfo;
-1
View File
@@ -103,7 +103,6 @@ static void process_incoming_migration_co(void *opaque)
}
qemu_announce_self();
bdrv_clear_incoming_migration_all();
/* Make sure all file formats flush their mutable metadata */
bdrv_invalidate_cache_all(&local_err);
if (local_err) {
+6
View File
@@ -972,6 +972,12 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset,
exp->ctx = bdrv_get_aio_context(bs);
bdrv_ref(bs);
bdrv_add_aio_context_notifier(bs, bs_aio_attached, bs_aio_detach, exp);
/*
* NBD exports are used for non-shared storage migration. Make sure
* that BDRV_O_INCOMING is cleared and the image is ready for write
* access since the export could be available before migration handover.
*/
bdrv_invalidate_cache(bs, NULL);
return exp;
}
+194
View File
@@ -0,0 +1,194 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* 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.
*/
#include "qemu-common.h"
#include "block/coroutine.h"
#include "migration/qemu-file.h"
typedef struct QEMUFileStdio {
FILE *stdio_file;
QEMUFile *file;
} QEMUFileStdio;
static int stdio_get_fd(void *opaque)
{
QEMUFileStdio *s = opaque;
return fileno(s->stdio_file);
}
static int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos,
int size)
{
QEMUFileStdio *s = opaque;
int res;
res = fwrite(buf, 1, size, s->stdio_file);
if (res != size) {
return -errno;
}
return res;
}
static int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
{
QEMUFileStdio *s = opaque;
FILE *fp = s->stdio_file;
int bytes;
for (;;) {
clearerr(fp);
bytes = fread(buf, 1, size, fp);
if (bytes != 0 || !ferror(fp)) {
break;
}
if (errno == EAGAIN) {
yield_until_fd_readable(fileno(fp));
} else if (errno != EINTR) {
break;
}
}
return bytes;
}
static int stdio_pclose(void *opaque)
{
QEMUFileStdio *s = opaque;
int ret;
ret = pclose(s->stdio_file);
if (ret == -1) {
ret = -errno;
} else if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) {
/* close succeeded, but non-zero exit code: */
ret = -EIO; /* fake errno value */
}
g_free(s);
return ret;
}
static int stdio_fclose(void *opaque)
{
QEMUFileStdio *s = opaque;
int ret = 0;
if (qemu_file_is_writable(s->file)) {
int fd = fileno(s->stdio_file);
struct stat st;
ret = fstat(fd, &st);
if (ret == 0 && S_ISREG(st.st_mode)) {
/*
* If the file handle is a regular file make sure the
* data is flushed to disk before signaling success.
*/
ret = fsync(fd);
if (ret != 0) {
ret = -errno;
return ret;
}
}
}
if (fclose(s->stdio_file) == EOF) {
ret = -errno;
}
g_free(s);
return ret;
}
static const QEMUFileOps stdio_pipe_read_ops = {
.get_fd = stdio_get_fd,
.get_buffer = stdio_get_buffer,
.close = stdio_pclose
};
static const QEMUFileOps stdio_pipe_write_ops = {
.get_fd = stdio_get_fd,
.put_buffer = stdio_put_buffer,
.close = stdio_pclose
};
QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
{
FILE *stdio_file;
QEMUFileStdio *s;
if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
fprintf(stderr, "qemu_popen: Argument validity check failed\n");
return NULL;
}
stdio_file = popen(command, mode);
if (stdio_file == NULL) {
return NULL;
}
s = g_malloc0(sizeof(QEMUFileStdio));
s->stdio_file = stdio_file;
if (mode[0] == 'r') {
s->file = qemu_fopen_ops(s, &stdio_pipe_read_ops);
} else {
s->file = qemu_fopen_ops(s, &stdio_pipe_write_ops);
}
return s->file;
}
static const QEMUFileOps stdio_file_read_ops = {
.get_fd = stdio_get_fd,
.get_buffer = stdio_get_buffer,
.close = stdio_fclose
};
static const QEMUFileOps stdio_file_write_ops = {
.get_fd = stdio_get_fd,
.put_buffer = stdio_put_buffer,
.close = stdio_fclose
};
QEMUFile *qemu_fopen(const char *filename, const char *mode)
{
QEMUFileStdio *s;
if (qemu_file_mode_is_not_valid(mode)) {
return NULL;
}
s = g_malloc0(sizeof(QEMUFileStdio));
s->stdio_file = fopen(filename, mode);
if (!s->stdio_file) {
goto fail;
}
if (mode[0] == 'w') {
s->file = qemu_fopen_ops(s, &stdio_file_write_ops);
} else {
s->file = qemu_fopen_ops(s, &stdio_file_read_ops);
}
return s->file;
fail:
g_free(s);
return NULL;
}
+223
View File
@@ -0,0 +1,223 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* 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.
*/
#include "qemu-common.h"
#include "qemu/iov.h"
#include "qemu/sockets.h"
#include "block/coroutine.h"
#include "migration/qemu-file.h"
typedef struct QEMUFileSocket {
int fd;
QEMUFile *file;
} QEMUFileSocket;
static ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
int64_t pos)
{
QEMUFileSocket *s = opaque;
ssize_t len;
ssize_t size = iov_size(iov, iovcnt);
len = iov_send(s->fd, iov, iovcnt, 0, size);
if (len < size) {
len = -socket_error();
}
return len;
}
static int socket_get_fd(void *opaque)
{
QEMUFileSocket *s = opaque;
return s->fd;
}
static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
{
QEMUFileSocket *s = opaque;
ssize_t len;
for (;;) {
len = qemu_recv(s->fd, buf, size, 0);
if (len != -1) {
break;
}
if (socket_error() == EAGAIN) {
yield_until_fd_readable(s->fd);
} else if (socket_error() != EINTR) {
break;
}
}
if (len == -1) {
len = -socket_error();
}
return len;
}
static int socket_close(void *opaque)
{
QEMUFileSocket *s = opaque;
closesocket(s->fd);
g_free(s);
return 0;
}
static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
int64_t pos)
{
QEMUFileSocket *s = opaque;
ssize_t len, offset;
ssize_t size = iov_size(iov, iovcnt);
ssize_t total = 0;
assert(iovcnt > 0);
offset = 0;
while (size > 0) {
/* Find the next start position; skip all full-sized vector elements */
while (offset >= iov[0].iov_len) {
offset -= iov[0].iov_len;
iov++, iovcnt--;
}
/* skip `offset' bytes from the (now) first element, undo it on exit */
assert(iovcnt > 0);
iov[0].iov_base += offset;
iov[0].iov_len -= offset;
do {
len = writev(s->fd, iov, iovcnt);
} while (len == -1 && errno == EINTR);
if (len == -1) {
return -errno;
}
/* Undo the changes above */
iov[0].iov_base -= offset;
iov[0].iov_len += offset;
/* Prepare for the next iteration */
offset += len;
total += len;
size -= len;
}
return total;
}
static int unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
{
QEMUFileSocket *s = opaque;
ssize_t len;
for (;;) {
len = read(s->fd, buf, size);
if (len != -1) {
break;
}
if (errno == EAGAIN) {
yield_until_fd_readable(s->fd);
} else if (errno != EINTR) {
break;
}
}
if (len == -1) {
len = -errno;
}
return len;
}
static int unix_close(void *opaque)
{
QEMUFileSocket *s = opaque;
close(s->fd);
g_free(s);
return 0;
}
static const QEMUFileOps unix_read_ops = {
.get_fd = socket_get_fd,
.get_buffer = unix_get_buffer,
.close = unix_close
};
static const QEMUFileOps unix_write_ops = {
.get_fd = socket_get_fd,
.writev_buffer = unix_writev_buffer,
.close = unix_close
};
QEMUFile *qemu_fdopen(int fd, const char *mode)
{
QEMUFileSocket *s;
if (mode == NULL ||
(mode[0] != 'r' && mode[0] != 'w') ||
mode[1] != 'b' || mode[2] != 0) {
fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
return NULL;
}
s = g_malloc0(sizeof(QEMUFileSocket));
s->fd = fd;
if (mode[0] == 'r') {
s->file = qemu_fopen_ops(s, &unix_read_ops);
} else {
s->file = qemu_fopen_ops(s, &unix_write_ops);
}
return s->file;
}
static const QEMUFileOps socket_read_ops = {
.get_fd = socket_get_fd,
.get_buffer = socket_get_buffer,
.close = socket_close
};
static const QEMUFileOps socket_write_ops = {
.get_fd = socket_get_fd,
.writev_buffer = socket_writev_buffer,
.close = socket_close
};
QEMUFile *qemu_fopen_socket(int fd, const char *mode)
{
QEMUFileSocket *s;
if (qemu_file_mode_is_not_valid(mode)) {
return NULL;
}
s = g_malloc0(sizeof(QEMUFileSocket));
s->fd = fd;
if (mode[0] == 'w') {
qemu_set_block(s->fd);
s->file = qemu_fopen_ops(s, &socket_write_ops);
} else {
s->file = qemu_fopen_ops(s, &socket_read_ops);
}
return s->file;
}
+479 -364
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -258,8 +258,8 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
$(test-qapi-obj-y) \
libqemuutil.a libqemustub.a
tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
vmstate.o qemu-file.o \
libqemuutil.a
vmstate.o qemu-file.o qemu-file-unix.o \
libqemuutil.a libqemustub.a
tests/test-qapi-types.c tests/test-qapi-types.h :\
$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
+38 -36
View File
@@ -43,6 +43,12 @@ void yield_until_fd_readable(int fd)
select(fd + 1, &fds, NULL, NULL, NULL);
}
/*
* Some tests use 'open_test_file' to work on a real fd, some use
* an in memory file (QEMUSizedBuffer+qemu_bufopen); we could pick one
* but this way we test both.
*/
/* Duplicate temp_fd and seek to the beginning of the file */
static QEMUFile *open_test_file(bool write)
{
@@ -54,6 +60,30 @@ static QEMUFile *open_test_file(bool write)
return qemu_fdopen(fd, write ? "wb" : "rb");
}
/* Open a read-only qemu-file from an existing memory block */
static QEMUFile *open_mem_file_read(const void *data, size_t len)
{
/* The qsb gets freed by qemu_fclose */
QEMUSizedBuffer *qsb = qsb_create(data, len);
g_assert(qsb);
return qemu_bufopen("r", qsb);
}
/*
* Check that the contents of the memory-buffered file f match
* the given size/data.
*/
static void check_mem_file(QEMUFile *f, void *data, size_t size)
{
uint8_t *result = g_malloc(size);
const QEMUSizedBuffer *qsb = qemu_buf_get(f);
g_assert_cmpint(qsb_get_length(qsb), ==, size);
g_assert_cmpint(qsb_get_buffer(qsb, 0, size, result), ==, size);
g_assert_cmpint(memcmp(result, data, size), ==, 0);
g_free(result);
}
#define SUCCESS(val) \
g_assert_cmpint((val), ==, 0)
@@ -371,14 +401,12 @@ static const VMStateDescription vmstate_skipping = {
static void test_save_noskip(void)
{
QEMUFile *fsave = open_test_file(true);
QEMUFile *fsave = qemu_bufopen("w", NULL);
TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
.skip_c_e = false };
vmstate_save_state(fsave, &vmstate_skipping, &obj);
g_assert(!qemu_file_get_error(fsave));
qemu_fclose(fsave);
QEMUFile *loading = open_test_file(false);
uint8_t expected[] = {
0, 0, 0, 1, /* a */
0, 0, 0, 2, /* b */
@@ -387,52 +415,31 @@ static void test_save_noskip(void)
0, 0, 0, 5, /* e */
0, 0, 0, 0, 0, 0, 0, 6, /* f */
};
uint8_t result[sizeof(expected)];
g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
sizeof(result));
g_assert(!qemu_file_get_error(loading));
g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
/* Must reach EOF */
qemu_get_byte(loading);
g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
qemu_fclose(loading);
check_mem_file(fsave, expected, sizeof(expected));
qemu_fclose(fsave);
}
static void test_save_skip(void)
{
QEMUFile *fsave = open_test_file(true);
QEMUFile *fsave = qemu_bufopen("w", NULL);
TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
.skip_c_e = true };
vmstate_save_state(fsave, &vmstate_skipping, &obj);
g_assert(!qemu_file_get_error(fsave));
qemu_fclose(fsave);
QEMUFile *loading = open_test_file(false);
uint8_t expected[] = {
0, 0, 0, 1, /* a */
0, 0, 0, 2, /* b */
0, 0, 0, 0, 0, 0, 0, 4, /* d */
0, 0, 0, 0, 0, 0, 0, 6, /* f */
};
uint8_t result[sizeof(expected)];
g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
sizeof(result));
g_assert(!qemu_file_get_error(loading));
g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
check_mem_file(fsave, expected, sizeof(expected));
/* Must reach EOF */
qemu_get_byte(loading);
g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
qemu_fclose(loading);
qemu_fclose(fsave);
}
static void test_load_noskip(void)
{
QEMUFile *fsave = open_test_file(true);
uint8_t buf[] = {
0, 0, 0, 10, /* a */
0, 0, 0, 20, /* b */
@@ -442,10 +449,8 @@ static void test_load_noskip(void)
0, 0, 0, 0, 0, 0, 0, 60, /* f */
QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
};
qemu_put_buffer(fsave, buf, sizeof(buf));
qemu_fclose(fsave);
QEMUFile *loading = open_test_file(false);
QEMUFile *loading = open_mem_file_read(buf, sizeof(buf));
TestStruct obj = { .skip_c_e = false };
vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
g_assert(!qemu_file_get_error(loading));
@@ -460,7 +465,6 @@ static void test_load_noskip(void)
static void test_load_skip(void)
{
QEMUFile *fsave = open_test_file(true);
uint8_t buf[] = {
0, 0, 0, 10, /* a */
0, 0, 0, 20, /* b */
@@ -468,10 +472,8 @@ static void test_load_skip(void)
0, 0, 0, 0, 0, 0, 0, 60, /* f */
QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
};
qemu_put_buffer(fsave, buf, sizeof(buf));
qemu_fclose(fsave);
QEMUFile *loading = open_test_file(false);
QEMUFile *loading = open_mem_file_read(buf, sizeof(buf));
TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
g_assert(!qemu_file_get_error(loading));
+10 -3
View File
@@ -49,9 +49,16 @@ static void *vmstate_base_addr(void *opaque, VMStateField *field, bool alloc)
if (field->flags & VMS_POINTER) {
if (alloc && (field->flags & VMS_ALLOC)) {
int n_elems = vmstate_n_elems(opaque, field);
if (n_elems) {
gsize size = n_elems * field->size;
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 + field->start) = g_malloc(size);
}
}