#include "config-host.h"
#include "qemu-common.h"
+#include "hw/boards.h"
#include "hw/hw.h"
#include "hw/qdev.h"
#include "net/net.h"
#include "block/snapshot.h"
#include "block/qapi.h"
-#define SELF_ANNOUNCE_ROUNDS 5
#ifndef ETH_P_RARP
#define ETH_P_RARP 0x8035
uint8_t buf[60];
int len;
+ trace_qemu_announce_self_iter(qemu_ether_ntoa(&nic->conf->macaddr));
len = announce_self_create(buf, nic->conf->macaddr.a);
qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
if (--count) {
/* delay 50ms, 150ms, 250ms, ... */
timer_mod(timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) +
- 50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100);
+ self_announce_delay(count));
} else {
timer_del(timer);
timer_free(timer);
/***********************************************************/
/* savevm/loadvm support */
-#define IO_BUF_SIZE 32768
-#define MAX_IOV_SIZE MIN(IOV_MAX, 64)
-
-struct QEMUFile {
- const QEMUFileOps *ops;
- void *opaque;
-
- int64_t bytes_xfer;
- int64_t xfer_limit;
-
- int64_t pos; /* start of buffer when writing, end of buffer
- when reading */
- int buf_index;
- int buf_size; /* 0 when writing */
- uint8_t buf[IO_BUF_SIZE];
-
- struct iovec iov[MAX_IOV_SIZE];
- unsigned int iovcnt;
-
- int last_error;
-};
-
-typedef struct QEMUFileStdio {
- FILE *stdio_file;
- QEMUFile *file;
-} QEMUFileStdio;
-
-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 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;
- return fwrite(buf, 1, size, s->stdio_file);
-}
-
-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 (s->file->ops->put_buffer || s->file->ops->writev_buffer) {
- 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
-};
-
-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
-};
-
-bool qemu_file_mode_is_not_valid(const char *mode)
-{
- if (mode == NULL ||
- (mode[0] != 'r' && mode[0] != 'w') ||
- mode[1] != 'b' || mode[2] != 0) {
- fprintf(stderr, "qemu_fopen: Argument validity check failed\n");
- return true;
- }
-
- return false;
-}
-
-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;
-}
-
-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;
-}
-
static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
int64_t pos)
{
return qemu_fopen_ops(bs, &bdrv_read_ops);
}
-QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops)
-{
- QEMUFile *f;
-
- f = g_malloc0(sizeof(QEMUFile));
-
- f->opaque = opaque;
- f->ops = ops;
- return f;
-}
-
-/*
- * Get last error for stream f
- *
- * Return negative error value if there has been an error on previous
- * operations, return 0 if no error happened.
- *
- */
-int qemu_file_get_error(QEMUFile *f)
-{
- return f->last_error;
-}
-
-void qemu_file_set_error(QEMUFile *f, int ret)
-{
- if (f->last_error == 0) {
- f->last_error = ret;
- }
-}
-
-static inline bool qemu_file_is_writable(QEMUFile *f)
-{
- return f->ops->writev_buffer || f->ops->put_buffer;
-}
-
-/**
- * Flushes QEMUFile buffer
- *
- * If there is writev_buffer QEMUFileOps it uses it otherwise uses
- * put_buffer ops.
- */
-void qemu_fflush(QEMUFile *f)
-{
- ssize_t ret = 0;
-
- if (!qemu_file_is_writable(f)) {
- return;
- }
-
- if (f->ops->writev_buffer) {
- if (f->iovcnt > 0) {
- ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
- }
- } else {
- if (f->buf_index > 0) {
- ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index);
- }
- }
- if (ret >= 0) {
- f->pos += ret;
- }
- f->buf_index = 0;
- f->iovcnt = 0;
- if (ret < 0) {
- qemu_file_set_error(f, ret);
- }
-}
-
-void ram_control_before_iterate(QEMUFile *f, uint64_t flags)
-{
- int ret = 0;
-
- if (f->ops->before_ram_iterate) {
- ret = f->ops->before_ram_iterate(f, f->opaque, flags);
- if (ret < 0) {
- qemu_file_set_error(f, ret);
- }
- }
-}
-
-void ram_control_after_iterate(QEMUFile *f, uint64_t flags)
-{
- int ret = 0;
-
- if (f->ops->after_ram_iterate) {
- ret = f->ops->after_ram_iterate(f, f->opaque, flags);
- if (ret < 0) {
- qemu_file_set_error(f, ret);
- }
- }
-}
-
-void ram_control_load_hook(QEMUFile *f, uint64_t flags)
-{
- int ret = -EINVAL;
-
- if (f->ops->hook_ram_load) {
- ret = f->ops->hook_ram_load(f, f->opaque, flags);
- if (ret < 0) {
- qemu_file_set_error(f, ret);
- }
- } else {
- qemu_file_set_error(f, ret);
- }
-}
-
-size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset,
- ram_addr_t offset, size_t size, int *bytes_sent)
-{
- if (f->ops->save_page) {
- int ret = f->ops->save_page(f, f->opaque, block_offset,
- offset, size, bytes_sent);
-
- if (ret != RAM_SAVE_CONTROL_DELAYED) {
- if (bytes_sent && *bytes_sent > 0) {
- qemu_update_position(f, *bytes_sent);
- } else if (ret < 0) {
- qemu_file_set_error(f, ret);
- }
- }
-
- return ret;
- }
-
- return RAM_SAVE_CONTROL_NOT_SUPP;
-}
-
-static void qemu_fill_buffer(QEMUFile *f)
-{
- int len;
- int pending;
-
- assert(!qemu_file_is_writable(f));
- pending = f->buf_size - f->buf_index;
- if (pending > 0) {
- memmove(f->buf, f->buf + f->buf_index, pending);
- }
- f->buf_index = 0;
- f->buf_size = pending;
-
- len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
- IO_BUF_SIZE - pending);
- if (len > 0) {
- f->buf_size += len;
- f->pos += len;
- } else if (len == 0) {
- qemu_file_set_error(f, -EIO);
- } else if (len != -EAGAIN) {
- qemu_file_set_error(f, len);
- }
-}
-
-int qemu_get_fd(QEMUFile *f)
-{
- if (f->ops->get_fd) {
- return f->ops->get_fd(f->opaque);
- }
- return -1;
-}
-
-void qemu_update_position(QEMUFile *f, size_t size)
-{
- f->pos += size;
-}
-
-/** Closes the file
- *
- * Returns negative error value if any error happened on previous operations or
- * while closing the file. Returns 0 or positive number on success.
- *
- * The meaning of return value on success depends on the specific backend
- * being used.
+/* QEMUFile timer support.
+ * Not in qemu-file.c to not add qemu-timer.c as dependency to qemu-file.c
*/
-int qemu_fclose(QEMUFile *f)
-{
- int ret;
- qemu_fflush(f);
- ret = qemu_file_get_error(f);
-
- if (f->ops->close) {
- int ret2 = f->ops->close(f->opaque);
- if (ret >= 0) {
- ret = ret2;
- }
- }
- /* If any error was spotted before closing, we should report it
- * instead of the close() return value.
- */
- if (f->last_error) {
- ret = f->last_error;
- }
- g_free(f);
- return ret;
-}
-
-static void add_to_iovec(QEMUFile *f, const uint8_t *buf, int size)
-{
- /* check for adjacent buffer and coalesce them */
- if (f->iovcnt > 0 && buf == f->iov[f->iovcnt - 1].iov_base +
- f->iov[f->iovcnt - 1].iov_len) {
- f->iov[f->iovcnt - 1].iov_len += size;
- } else {
- f->iov[f->iovcnt].iov_base = (uint8_t *)buf;
- f->iov[f->iovcnt++].iov_len = size;
- }
-
- if (f->iovcnt >= MAX_IOV_SIZE) {
- qemu_fflush(f);
- }
-}
-
-void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size)
-{
- if (!f->ops->writev_buffer) {
- qemu_put_buffer(f, buf, size);
- return;
- }
-
- if (f->last_error) {
- return;
- }
-
- f->bytes_xfer += size;
- add_to_iovec(f, buf, size);
-}
-
-void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
-{
- int l;
-
- if (f->last_error) {
- return;
- }
-
- while (size > 0) {
- l = IO_BUF_SIZE - f->buf_index;
- if (l > size) {
- l = size;
- }
- memcpy(f->buf + f->buf_index, buf, l);
- f->bytes_xfer += l;
- if (f->ops->writev_buffer) {
- add_to_iovec(f, f->buf + f->buf_index, l);
- }
- f->buf_index += l;
- if (f->buf_index == IO_BUF_SIZE) {
- qemu_fflush(f);
- }
- if (qemu_file_get_error(f)) {
- break;
- }
- buf += l;
- size -= l;
- }
-}
-
-void qemu_put_byte(QEMUFile *f, int v)
-{
- if (f->last_error) {
- return;
- }
-
- f->buf[f->buf_index] = v;
- f->bytes_xfer++;
- if (f->ops->writev_buffer) {
- add_to_iovec(f, f->buf + f->buf_index, 1);
- }
- f->buf_index++;
- if (f->buf_index == IO_BUF_SIZE) {
- qemu_fflush(f);
- }
-}
-
-void qemu_file_skip(QEMUFile *f, int size)
-{
- if (f->buf_index + size <= f->buf_size) {
- f->buf_index += size;
- }
-}
-
-int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
-{
- int pending;
- int index;
-
- assert(!qemu_file_is_writable(f));
-
- index = f->buf_index + offset;
- pending = f->buf_size - index;
- if (pending < size) {
- qemu_fill_buffer(f);
- index = f->buf_index + offset;
- pending = f->buf_size - index;
- }
-
- if (pending <= 0) {
- return 0;
- }
- if (size > pending) {
- size = pending;
- }
-
- memcpy(buf, f->buf + index, size);
- return size;
-}
-
-int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
-{
- int pending = size;
- int done = 0;
-
- while (pending > 0) {
- int res;
-
- res = qemu_peek_buffer(f, buf, pending, 0);
- if (res == 0) {
- return done;
- }
- qemu_file_skip(f, res);
- buf += res;
- pending -= res;
- done += res;
- }
- return done;
-}
-
-int qemu_peek_byte(QEMUFile *f, int offset)
-{
- int index = f->buf_index + offset;
-
- assert(!qemu_file_is_writable(f));
-
- if (index >= f->buf_size) {
- qemu_fill_buffer(f);
- index = f->buf_index + offset;
- if (index >= f->buf_size) {
- return 0;
- }
- }
- return f->buf[index];
-}
-
-int qemu_get_byte(QEMUFile *f)
-{
- int result;
-
- result = qemu_peek_byte(f, 0);
- qemu_file_skip(f, 1);
- return result;
-}
-
-int64_t qemu_ftell(QEMUFile *f)
-{
- qemu_fflush(f);
- return f->pos;
-}
-
-int qemu_file_rate_limit(QEMUFile *f)
-{
- if (qemu_file_get_error(f)) {
- return 1;
- }
- if (f->xfer_limit > 0 && f->bytes_xfer > f->xfer_limit) {
- return 1;
- }
- return 0;
-}
-
-int64_t qemu_file_get_rate_limit(QEMUFile *f)
-{
- return f->xfer_limit;
-}
-
-void qemu_file_set_rate_limit(QEMUFile *f, int64_t limit)
-{
- f->xfer_limit = limit;
-}
-
-void qemu_file_reset_rate_limit(QEMUFile *f)
-{
- f->bytes_xfer = 0;
-}
-
-void qemu_put_be16(QEMUFile *f, unsigned int v)
-{
- qemu_put_byte(f, v >> 8);
- qemu_put_byte(f, v);
-}
-
-void qemu_put_be32(QEMUFile *f, unsigned int v)
-{
- qemu_put_byte(f, v >> 24);
- qemu_put_byte(f, v >> 16);
- qemu_put_byte(f, v >> 8);
- qemu_put_byte(f, v);
-}
-
-void qemu_put_be64(QEMUFile *f, uint64_t v)
-{
- qemu_put_be32(f, v >> 32);
- qemu_put_be32(f, v);
-}
-
-unsigned int qemu_get_be16(QEMUFile *f)
-{
- unsigned int v;
- v = qemu_get_byte(f) << 8;
- v |= qemu_get_byte(f);
- return v;
-}
-
-unsigned int qemu_get_be32(QEMUFile *f)
-{
- unsigned int v;
- v = qemu_get_byte(f) << 24;
- v |= qemu_get_byte(f) << 16;
- v |= qemu_get_byte(f) << 8;
- v |= qemu_get_byte(f);
- return v;
-}
-
-uint64_t qemu_get_be64(QEMUFile *f)
-{
- uint64_t v;
- v = (uint64_t)qemu_get_be32(f) << 32;
- v |= qemu_get_be32(f);
- return v;
-}
-
-
-/* timer */
void timer_put(QEMUFile *f, QEMUTimer *ts)
{
}
-/* timers */
+/* VMState timer support.
+ * Not in vmstate.c to not add qemu-timer.c as dependency to vmstate.c
+ */
static int get_timer(QEMUFile *f, void *pv, size_t size)
{
const VMStateDescription *vmsd;
void *opaque;
CompatEntry *compat;
- int no_migrate;
int is_ram;
} SaveStateEntry;
QTAILQ_HEAD_INITIALIZER(savevm_handlers);
static int global_section_id;
+static void dump_vmstate_vmsd(FILE *out_file,
+ const VMStateDescription *vmsd, int indent,
+ bool is_subsection);
+
+static void dump_vmstate_vmsf(FILE *out_file, const VMStateField *field,
+ int indent)
+{
+ fprintf(out_file, "%*s{\n", indent, "");
+ indent += 2;
+ fprintf(out_file, "%*s\"field\": \"%s\",\n", indent, "", field->name);
+ fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "",
+ field->version_id);
+ fprintf(out_file, "%*s\"field_exists\": %s,\n", indent, "",
+ field->field_exists ? "true" : "false");
+ fprintf(out_file, "%*s\"size\": %zu", indent, "", field->size);
+ if (field->vmsd != NULL) {
+ fprintf(out_file, ",\n");
+ dump_vmstate_vmsd(out_file, field->vmsd, indent, false);
+ }
+ fprintf(out_file, "\n%*s}", indent - 2, "");
+}
+
+static void dump_vmstate_vmss(FILE *out_file,
+ const VMStateSubsection *subsection,
+ int indent)
+{
+ if (subsection->vmsd != NULL) {
+ dump_vmstate_vmsd(out_file, subsection->vmsd, indent, true);
+ }
+}
+
+static void dump_vmstate_vmsd(FILE *out_file,
+ const VMStateDescription *vmsd, int indent,
+ bool is_subsection)
+{
+ if (is_subsection) {
+ fprintf(out_file, "%*s{\n", indent, "");
+ } else {
+ fprintf(out_file, "%*s\"%s\": {\n", indent, "", "Description");
+ }
+ indent += 2;
+ fprintf(out_file, "%*s\"name\": \"%s\",\n", indent, "", vmsd->name);
+ fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "",
+ vmsd->version_id);
+ fprintf(out_file, "%*s\"minimum_version_id\": %d", indent, "",
+ vmsd->minimum_version_id);
+ if (vmsd->fields != NULL) {
+ const VMStateField *field = vmsd->fields;
+ bool first;
+
+ fprintf(out_file, ",\n%*s\"Fields\": [\n", indent, "");
+ first = true;
+ while (field->name != NULL) {
+ if (field->flags & VMS_MUST_EXIST) {
+ /* Ignore VMSTATE_VALIDATE bits; these don't get migrated */
+ field++;
+ continue;
+ }
+ if (!first) {
+ fprintf(out_file, ",\n");
+ }
+ dump_vmstate_vmsf(out_file, field, indent + 2);
+ field++;
+ first = false;
+ }
+ fprintf(out_file, "\n%*s]", indent, "");
+ }
+ if (vmsd->subsections != NULL) {
+ const VMStateSubsection *subsection = vmsd->subsections;
+ bool first;
+
+ fprintf(out_file, ",\n%*s\"Subsections\": [\n", indent, "");
+ first = true;
+ while (subsection->vmsd != NULL) {
+ if (!first) {
+ fprintf(out_file, ",\n");
+ }
+ dump_vmstate_vmss(out_file, subsection, indent + 2);
+ subsection++;
+ first = false;
+ }
+ fprintf(out_file, "\n%*s]", indent, "");
+ }
+ fprintf(out_file, "\n%*s}", indent - 2, "");
+}
+
+static void dump_machine_type(FILE *out_file)
+{
+ MachineClass *mc;
+
+ mc = MACHINE_GET_CLASS(current_machine);
+
+ fprintf(out_file, " \"vmschkmachine\": {\n");
+ fprintf(out_file, " \"Name\": \"%s\"\n", mc->name);
+ fprintf(out_file, " },\n");
+}
+
+void dump_vmstate_json_to_file(FILE *out_file)
+{
+ GSList *list, *elt;
+ bool first;
+
+ fprintf(out_file, "{\n");
+ dump_machine_type(out_file);
+
+ first = true;
+ list = object_class_get_list(TYPE_DEVICE, true);
+ for (elt = list; elt; elt = elt->next) {
+ DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data,
+ TYPE_DEVICE);
+ const char *name;
+ int indent = 2;
+
+ if (!dc->vmsd) {
+ continue;
+ }
+
+ if (!first) {
+ fprintf(out_file, ",\n");
+ }
+ name = object_class_get_name(OBJECT_CLASS(dc));
+ fprintf(out_file, "%*s\"%s\": {\n", indent, "", name);
+ indent += 2;
+ fprintf(out_file, "%*s\"Name\": \"%s\",\n", indent, "", name);
+ fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "",
+ dc->vmsd->version_id);
+ fprintf(out_file, "%*s\"minimum_version_id\": %d,\n", indent, "",
+ dc->vmsd->minimum_version_id);
+
+ dump_vmstate_vmsd(out_file, dc->vmsd, indent, false);
+
+ fprintf(out_file, "\n%*s}", indent - 2, "");
+ first = false;
+ }
+ fprintf(out_file, "\n}\n");
+ fclose(out_file);
+}
+
static int calculate_new_instance_id(const char *idstr)
{
SaveStateEntry *se;
se->ops = ops;
se->opaque = opaque;
se->vmsd = NULL;
- se->no_migrate = 0;
/* if this is a live_savem then set is_ram */
if (ops->save_live_setup != NULL) {
se->is_ram = 1;
se->opaque = opaque;
se->vmsd = vmsd;
se->alias_id = alias_id;
- se->no_migrate = vmsd->unmigratable;
if (dev) {
char *id = qdev_get_dev_path(dev);
static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
{
+ trace_vmstate_load(se->idstr, se->vmsd ? se->vmsd->name : "(old)");
if (!se->vmsd) { /* Old style */
return se->ops->load_state(f, se->opaque, version_id);
}
static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
{
+ trace_vmstate_save(se->idstr, se->vmsd ? se->vmsd->name : "(old)");
if (!se->vmsd) { /* Old style */
se->ops->save_state(f, se->opaque);
return;
SaveStateEntry *se;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
- if (se->no_migrate) {
- error_set(errp, QERR_MIGRATION_NOT_SUPPORTED, se->idstr);
+ if (se->vmsd && se->vmsd->unmigratable) {
+ error_setg(errp, "State blocked by non-migratable device '%s'",
+ se->idstr);
return true;
}
}
SaveStateEntry *se;
int ret;
+ trace_savevm_state_begin();
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if (!se->ops || !se->ops->set_params) {
continue;
SaveStateEntry *se;
int ret = 1;
+ trace_savevm_state_iterate();
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if (!se->ops || !se->ops->save_live_iterate) {
continue;
if (qemu_file_rate_limit(f)) {
return 0;
}
- trace_savevm_section_start();
+ trace_savevm_section_start(se->idstr, se->section_id);
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_PART);
qemu_put_be32(f, se->section_id);
ret = se->ops->save_live_iterate(f, se->opaque);
- trace_savevm_section_end(se->section_id);
+ trace_savevm_section_end(se->idstr, se->section_id);
if (ret < 0) {
qemu_file_set_error(f, ret);
SaveStateEntry *se;
int ret;
+ trace_savevm_state_complete();
+
cpu_synchronize_all_states();
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
continue;
}
}
- trace_savevm_section_start();
+ trace_savevm_section_start(se->idstr, se->section_id);
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_END);
qemu_put_be32(f, se->section_id);
ret = se->ops->save_live_complete(f, se->opaque);
- trace_savevm_section_end(se->section_id);
+ trace_savevm_section_end(se->idstr, se->section_id);
if (ret < 0) {
qemu_file_set_error(f, ret);
return;
if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
continue;
}
- trace_savevm_section_start();
+ trace_savevm_section_start(se->idstr, se->section_id);
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_FULL);
qemu_put_be32(f, se->section_id);
qemu_put_be32(f, se->version_id);
vmstate_save(f, se);
- trace_savevm_section_end(se->section_id);
+ trace_savevm_section_end(se->idstr, se->section_id);
}
qemu_put_byte(f, QEMU_VM_EOF);
{
SaveStateEntry *se;
+ trace_savevm_state_cancel();
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if (se->ops && se->ops->cancel) {
se->ops->cancel(se->opaque);
if (bdrv_can_snapshot(bs) &&
bdrv_snapshot_find(bs, snapshot, name) >= 0) {
bdrv_snapshot_delete_by_id_or_name(bs, name, &err);
- if (error_is_set(&err)) {
+ if (err) {
monitor_printf(mon,
"Error while deleting snapshot on device '%s':"
" %s\n",
while ((bs1 = bdrv_next(bs1))) {
if (bdrv_can_snapshot(bs1)) {
bdrv_snapshot_delete_by_id_or_name(bs, name, &err);
- if (error_is_set(&err)) {
+ if (err) {
monitor_printf(mon,
"Error while deleting snapshot on device '%s':"
" %s\n",
void vmstate_unregister_ram(MemoryRegion *mr, DeviceState *dev)
{
- /* Nothing do to while the implementation is in RAMBlock */
+ qemu_ram_unset_idstr(memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK);
}
void vmstate_register_ram_global(MemoryRegion *mr)