#include <sys/select.h>
#ifdef CONFIG_BSD
#include <sys/stat.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
#include <libutil.h>
#else
#include <util.h>
#endif
-#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
-#include <freebsd/stdlib.h>
-#else
#ifdef __linux__
#include <pty.h>
#include <malloc.h>
return 60; /* len (FCS will be added by hardware) */
}
-static void qemu_announce_self_once(void *opaque)
+static void qemu_announce_self_iter(NICState *nic, void *opaque)
{
- int i, len;
- VLANState *vlan;
- VLANClientState *vc;
uint8_t buf[60];
+ int len;
+
+ len = announce_self_create(buf, nic->conf->macaddr.a);
+
+ qemu_send_packet_raw(&nic->nc, buf, len);
+}
+
+
+static void qemu_announce_self_once(void *opaque)
+{
static int count = SELF_ANNOUNCE_ROUNDS;
QEMUTimer *timer = *(QEMUTimer **)opaque;
- for (i = 0; i < MAX_NICS; i++) {
- if (!nd_table[i].used)
- continue;
- len = announce_self_create(buf, nd_table[i].macaddr);
- vlan = nd_table[i].vlan;
- QTAILQ_FOREACH(vc, &vlan->clients, next) {
- qemu_send_packet_raw(vc, buf, len);
- }
- }
+ qemu_foreach_nic(qemu_announce_self_iter, NULL);
+
if (--count) {
/* delay 50ms, 150ms, 250ms, ... */
qemu_mod_timer(timer, qemu_get_clock(rt_clock) +
QEMUFileCloseFunc *close;
QEMUFileRateLimit *rate_limit;
QEMUFileSetRateLimit *set_rate_limit;
+ QEMUFileGetRateLimit *get_rate_limit;
void *opaque;
int is_write;
s->stdio_file = stdio_file;
if(mode[0] == 'r') {
- s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_pclose, NULL, NULL);
+ s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_pclose,
+ NULL, NULL, NULL);
} else {
- s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_pclose, NULL, NULL);
+ s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_pclose,
+ NULL, NULL, NULL);
}
return s->file;
}
goto fail;
if(mode[0] == 'r') {
- s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose, NULL, NULL);
+ s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose,
+ NULL, NULL, NULL);
} else {
- s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose, NULL, NULL);
+ s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose,
+ NULL, NULL, NULL);
}
return s->file;
QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
s->fd = fd;
- s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, socket_close, NULL, NULL);
+ s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, socket_close,
+ NULL, NULL, NULL);
return s->file;
}
{
QEMUFileStdio *s = opaque;
fseek(s->stdio_file, pos, SEEK_SET);
- fwrite(buf, 1, size, s->stdio_file);
- return size;
+ return fwrite(buf, 1, size, s->stdio_file);
}
static int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
s->stdio_file = fopen(filename, mode);
if (!s->stdio_file)
goto fail;
-
+
if(mode[0] == 'w') {
- s->file = qemu_fopen_ops(s, file_put_buffer, NULL, stdio_fclose, NULL, NULL);
+ s->file = qemu_fopen_ops(s, file_put_buffer, NULL, stdio_fclose,
+ NULL, NULL, NULL);
} else {
- s->file = qemu_fopen_ops(s, NULL, file_get_buffer, stdio_fclose, NULL, NULL);
+ s->file = qemu_fopen_ops(s, NULL, file_get_buffer, stdio_fclose,
+ NULL, NULL, NULL);
}
return s->file;
fail:
static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
{
if (is_writable)
- return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose, NULL, NULL);
- return qemu_fopen_ops(bs, NULL, block_get_buffer, bdrv_fclose, NULL, NULL);
+ return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose,
+ NULL, NULL, NULL);
+ return qemu_fopen_ops(bs, NULL, block_get_buffer, bdrv_fclose, NULL, NULL, NULL);
}
QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
QEMUFileGetBufferFunc *get_buffer,
QEMUFileCloseFunc *close,
QEMUFileRateLimit *rate_limit,
- QEMUFileSetRateLimit *set_rate_limit)
+ QEMUFileSetRateLimit *set_rate_limit,
+ QEMUFileGetRateLimit *get_rate_limit)
{
QEMUFile *f;
f->close = close;
f->rate_limit = rate_limit;
f->set_rate_limit = set_rate_limit;
+ f->get_rate_limit = get_rate_limit;
f->is_write = 0;
return f;
return 0;
}
+size_t qemu_file_get_rate_limit(QEMUFile *f)
+{
+ if (f->get_rate_limit)
+ return f->get_rate_limit(f->opaque);
+
+ return 0;
+}
+
size_t qemu_file_set_rate_limit(QEMUFile *f, size_t new_rate)
{
/* any failed or completed migration keeps its state to allow probing of
static int get_unused_buffer(QEMUFile *f, void *pv, size_t size)
{
- qemu_fseek(f, size, SEEK_CUR);
- return 0;
+ uint8_t buf[1024];
+ int block_len;
+
+ while (size > 0) {
+ block_len = MIN(sizeof(buf), size);
+ size -= block_len;
+ qemu_get_buffer(f, buf, block_len);
+ }
+ return 0;
}
static void put_unused_buffer(QEMUFile *f, void *pv, size_t size)
{
- qemu_fseek(f, size, SEEK_CUR);
+ static const uint8_t buf[1024];
+ int block_len;
+
+ while (size > 0) {
+ block_len = MIN(sizeof(buf), size);
+ size -= block_len;
+ qemu_put_buffer(f, buf, block_len);
+ }
}
const VMStateInfo vmstate_info_unused_buffer = {
int instance_id;
int version_id;
int section_id;
+ SaveSetParamsHandler *set_params;
SaveLiveStateHandler *save_live_state;
SaveStateHandler *save_state;
LoadStateHandler *load_state;
void *opaque;
} SaveStateEntry;
+
static QTAILQ_HEAD(savevm_handlers, SaveStateEntry) savevm_handlers =
QTAILQ_HEAD_INITIALIZER(savevm_handlers);
static int global_section_id;
int register_savevm_live(const char *idstr,
int instance_id,
int version_id,
+ SaveSetParamsHandler *set_params,
SaveLiveStateHandler *save_live_state,
SaveStateHandler *save_state,
LoadStateHandler *load_state,
{
SaveStateEntry *se;
- se = qemu_malloc(sizeof(SaveStateEntry));
+ se = qemu_mallocz(sizeof(SaveStateEntry));
pstrcpy(se->idstr, sizeof(se->idstr), idstr);
se->version_id = version_id;
se->section_id = global_section_id++;
+ se->set_params = set_params;
se->save_live_state = save_live_state;
se->save_state = save_state;
se->load_state = load_state;
void *opaque)
{
return register_savevm_live(idstr, instance_id, version_id,
- NULL, save_state, load_state, opaque);
+ NULL, NULL, save_state, load_state, opaque);
}
void unregister_savevm(const char *idstr, void *opaque)
{
SaveStateEntry *se;
- se = qemu_malloc(sizeof(SaveStateEntry));
+ se = qemu_mallocz(sizeof(SaveStateEntry));
pstrcpy(se->idstr, sizeof(se->idstr), vmsd->name);
se->version_id = vmsd->version_id;
se->section_id = global_section_id++;
field->version_id <= version_id)) {
void *base_addr = opaque + field->offset;
int ret, i, n_elems = 1;
+ int size = field->size;
+ if (field->flags & VMS_VBUFFER) {
+ size = *(int32_t *)(opaque+field->size_offset);
+ if (field->flags & VMS_MULTIPLY) {
+ size *= field->size;
+ }
+ }
if (field->flags & VMS_ARRAY) {
n_elems = field->num;
} else if (field->flags & VMS_VARRAY_INT32) {
n_elems = *(uint16_t *)(opaque+field->num_offset);
}
if (field->flags & VMS_POINTER) {
- base_addr = *(void **)base_addr;
+ base_addr = *(void **)base_addr + field->start;
}
for (i = 0; i < n_elems; i++) {
- void *addr = base_addr + field->size * i;
+ void *addr = base_addr + size * i;
if (field->flags & VMS_ARRAY_OF_POINTER) {
addr = *(void **)addr;
if (field->flags & VMS_STRUCT) {
ret = vmstate_load_state(f, field->vmsd, addr, field->vmsd->version_id);
} else {
- ret = field->info->get(f, addr, field->size);
+ ret = field->info->get(f, addr, size);
}
if (ret < 0) {
field->field_exists(opaque, vmsd->version_id)) {
void *base_addr = opaque + field->offset;
int i, n_elems = 1;
+ int size = field->size;
+ if (field->flags & VMS_VBUFFER) {
+ size = *(int32_t *)(opaque+field->size_offset);
+ if (field->flags & VMS_MULTIPLY) {
+ size *= field->size;
+ }
+ }
if (field->flags & VMS_ARRAY) {
n_elems = field->num;
} else if (field->flags & VMS_VARRAY_INT32) {
n_elems = *(uint16_t *)(opaque+field->num_offset);
}
if (field->flags & VMS_POINTER) {
- base_addr = *(void **)base_addr;
+ base_addr = *(void **)base_addr + field->start;
}
for (i = 0; i < n_elems; i++) {
- void *addr = base_addr + field->size * i;
+ void *addr = base_addr + size * i;
+ if (field->flags & VMS_ARRAY_OF_POINTER) {
+ addr = *(void **)addr;
+ }
if (field->flags & VMS_STRUCT) {
vmstate_save_state(f, field->vmsd, addr);
} else {
- field->info->put(f, addr, field->size);
+ field->info->put(f, addr, size);
}
}
}
#define QEMU_VM_SECTION_END 0x03
#define QEMU_VM_SECTION_FULL 0x04
-int qemu_savevm_state_begin(QEMUFile *f)
+int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
+ int shared)
{
SaveStateEntry *se;
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ if(se->set_params == NULL) {
+ continue;
+ }
+ se->set_params(blk_enable, shared, se->opaque);
+ }
+
qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
qemu_put_be32(f, QEMU_VM_FILE_VERSION);
qemu_put_be32(f, se->instance_id);
qemu_put_be32(f, se->version_id);
- se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
+ se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
}
- if (qemu_file_has_error(f))
+ if (qemu_file_has_error(f)) {
+ qemu_savevm_state_cancel(mon, f);
return -EIO;
+ }
return 0;
}
-int qemu_savevm_state_iterate(QEMUFile *f)
+int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
{
SaveStateEntry *se;
int ret = 1;
qemu_put_byte(f, QEMU_VM_SECTION_PART);
qemu_put_be32(f, se->section_id);
- ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque);
+ ret = se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque);
+ if (!ret) {
+ /* Do not proceed to the next vmstate before this one reported
+ completion of the current stage. This serializes the migration
+ and reduces the probability that a faster changing state is
+ synchronized over and over again. */
+ break;
+ }
}
if (ret)
return 1;
- if (qemu_file_has_error(f))
+ if (qemu_file_has_error(f)) {
+ qemu_savevm_state_cancel(mon, f);
return -EIO;
+ }
return 0;
}
-int qemu_savevm_state_complete(QEMUFile *f)
+int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
{
SaveStateEntry *se;
qemu_put_byte(f, QEMU_VM_SECTION_END);
qemu_put_be32(f, se->section_id);
- se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
+ se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
}
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
return 0;
}
-int qemu_savevm_state(QEMUFile *f)
+void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f)
+{
+ SaveStateEntry *se;
+
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ if (se->save_live_state) {
+ se->save_live_state(mon, f, -1, se->opaque);
+ }
+ }
+}
+
+static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
{
int saved_vm_running;
int ret;
bdrv_flush_all();
- ret = qemu_savevm_state_begin(f);
+ ret = qemu_savevm_state_begin(mon, f, 0, 0);
if (ret < 0)
goto out;
do {
- ret = qemu_savevm_state_iterate(f);
+ ret = qemu_savevm_state_iterate(mon, f);
if (ret < 0)
goto out;
} while (ret == 0);
- ret = qemu_savevm_state_complete(f);
+ ret = qemu_savevm_state_complete(mon, f);
out:
if (qemu_file_has_error(f))
sn->vm_clock_nsec = qemu_get_clock(vm_clock);
/* Delete old snapshots of the same name */
- if (del_existing_snapshots(mon, name) < 0) {
+ if (name && del_existing_snapshots(mon, name) < 0) {
goto the_end;
}
monitor_printf(mon, "Could not open VM state file\n");
goto the_end;
}
- ret = qemu_savevm_state(f);
+ ret = qemu_savevm_state(mon, f);
vm_state_size = qemu_ftell(f);
qemu_fclose(f);
if (ret < 0) {