#include "migration.h"
#include "qemu_socket.h"
#include "qemu-queue.h"
+#include "qemu-timer.h"
#include "cpus.h"
#define SELF_ANNOUNCE_ROUNDS 5
int buf_size; /* 0 when writing */
uint8_t buf[IO_BUF_SIZE];
- int has_error;
+ int last_error;
};
typedef struct QEMUFileStdio
return f;
}
-int qemu_file_has_error(QEMUFile *f)
+int qemu_file_get_error(QEMUFile *f)
{
- return f->has_error;
+ return f->last_error;
}
-void qemu_file_set_error(QEMUFile *f)
+void qemu_file_set_error(QEMUFile *f, int ret)
{
- f->has_error = 1;
+ f->last_error = ret;
}
void qemu_fflush(QEMUFile *f)
if (len > 0)
f->buf_offset += f->buf_index;
else
- f->has_error = 1;
+ f->last_error = -EINVAL;
f->buf_index = 0;
}
}
if (len > 0) {
f->buf_size += len;
f->buf_offset += len;
+ } else if (len == 0) {
+ f->last_error = -EIO;
} else if (len != -EAGAIN)
- f->has_error = 1;
+ f->last_error = len;
}
int qemu_fclose(QEMUFile *f)
{
int l;
- if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+ if (!f->last_error && f->is_write == 0 && f->buf_index > 0) {
fprintf(stderr,
"Attempted to write to buffer while read buffer is not empty\n");
abort();
}
- while (!f->has_error && size > 0) {
+ while (!f->last_error && size > 0) {
l = IO_BUF_SIZE - f->buf_index;
if (l > size)
l = size;
void qemu_put_byte(QEMUFile *f, int v)
{
- if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+ if (!f->last_error && f->is_write == 0 && f->buf_index > 0) {
fprintf(stderr,
"Attempted to write to buffer while read buffer is not empty\n");
abort();
return v;
}
+
+/* timer */
+
+void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
+{
+ uint64_t expire_time;
+
+ expire_time = qemu_timer_expire_time_ns(ts);
+ qemu_put_be64(f, expire_time);
+}
+
+void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
+{
+ uint64_t expire_time;
+
+ expire_time = qemu_get_be64(f);
+ if (expire_time != -1) {
+ qemu_mod_timer_ns(ts, expire_time);
+ } else {
+ qemu_del_timer(ts);
+ }
+}
+
+
/* bool */
static int get_bool(QEMUFile *f, void *pv, size_t size)
int shared)
{
SaveStateEntry *se;
+ int ret;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if(se->set_params == NULL) {
qemu_put_be32(f, se->instance_id);
qemu_put_be32(f, se->version_id);
- se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
+ ret = se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
+ if (ret < 0) {
+ qemu_savevm_state_cancel(mon, f);
+ return ret;
+ }
}
-
- if (qemu_file_has_error(f)) {
+ ret = qemu_file_get_error(f);
+ if (ret != 0) {
qemu_savevm_state_cancel(mon, f);
- return -EIO;
}
- return 0;
+ return ret;
+
}
+/*
+ * this funtion has three return values:
+ * negative: there was one error, and we have -errno.
+ * 0 : We haven't finished, caller have to go again
+ * 1 : We have finished, we can go to complete phase
+ */
int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
{
SaveStateEntry *se;
qemu_put_be32(f, se->section_id);
ret = se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque);
- if (!ret) {
+ if (ret <= 0) {
/* 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
break;
}
}
-
- if (ret)
- return 1;
-
- if (qemu_file_has_error(f)) {
+ if (ret != 0) {
+ return ret;
+ }
+ ret = qemu_file_get_error(f);
+ if (ret != 0) {
qemu_savevm_state_cancel(mon, f);
- return -EIO;
}
-
- return 0;
+ return ret;
}
int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
{
SaveStateEntry *se;
+ int ret;
cpu_synchronize_all_states();
qemu_put_byte(f, QEMU_VM_SECTION_END);
qemu_put_be32(f, se->section_id);
- se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
+ ret = se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
+ if (ret < 0) {
+ return ret;
+ }
}
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
qemu_put_byte(f, QEMU_VM_EOF);
- if (qemu_file_has_error(f))
- return -EIO;
-
- return 0;
+ return qemu_file_get_error(f);
}
void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f)
static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
{
- int saved_vm_running;
int ret;
- saved_vm_running = runstate_is_running();
- vm_stop(RUN_STATE_SAVE_VM);
-
if (qemu_savevm_state_blocked(mon)) {
ret = -EINVAL;
goto out;
ret = qemu_savevm_state_complete(mon, f);
out:
- if (qemu_file_has_error(f))
- ret = -EIO;
-
- if (!ret && saved_vm_running)
- vm_start();
+ if (ret == 0) {
+ ret = qemu_file_get_error(f);
+ }
return ret;
}
g_free(le);
}
- if (qemu_file_has_error(f))
- ret = -EIO;
+ if (ret == 0) {
+ ret = qemu_file_get_error(f);
+ }
return ret;
}