return f->last_error;
}
-void qemu_file_set_error(QEMUFile *f, int ret)
+static void qemu_file_set_error(QEMUFile *f, int ret)
{
f->last_error = ret;
}
-/** Sets last_error conditionally
- *
- * Sets last_error only if ret is negative _and_ no error
- * was set before.
- */
-static void qemu_file_set_if_error(QEMUFile *f, int ret)
-{
- if (ret < 0 && !f->last_error) {
- qemu_file_set_error(f, ret);
- }
-}
-
/** Flushes QEMUFile buffer
*
- * In case of error, last_error is set.
*/
-void qemu_fflush(QEMUFile *f)
+static int qemu_fflush(QEMUFile *f)
{
+ int ret = 0;
+
if (!f->put_buffer)
- return;
+ return 0;
if (f->is_write && f->buf_index > 0) {
- int len;
-
- len = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index);
- if (len > 0)
+ ret = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index);
+ if (ret >= 0) {
f->buf_offset += f->buf_index;
- else
- qemu_file_set_error(f, -EINVAL);
+ }
f->buf_index = 0;
}
+ return ret;
}
static void qemu_fill_buffer(QEMUFile *f)
f->buf_size += len;
f->buf_offset += len;
} else if (len == 0) {
- f->last_error = -EIO;
+ qemu_file_set_error(f, -EIO);
} else if (len != -EAGAIN)
qemu_file_set_error(f, len);
}
-/** Calls close function and set last_error if needed
- *
- * Internal function. qemu_fflush() must be called before this.
- *
- * Returns f->close() return value, or 0 if close function is not set.
- */
-static int qemu_close(QEMUFile *f)
-{
- int ret = 0;
- if (f->close) {
- ret = f->close(f->opaque);
- qemu_file_set_if_error(f, ret);
- }
- return ret;
-}
-
/** Closes the file
*
* Returns negative error value if any error happened on previous operations or
int qemu_fclose(QEMUFile *f)
{
int ret;
- qemu_fflush(f);
- ret = qemu_close(f);
+ ret = qemu_fflush(f);
+
+ if (f->close) {
+ int ret2 = f->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.
*/
return ret;
}
-void qemu_file_put_notify(QEMUFile *f)
+int qemu_file_put_notify(QEMUFile *f)
{
- f->put_buffer(f->opaque, NULL, 0, 0);
+ return f->put_buffer(f->opaque, NULL, 0, 0);
}
void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
{
int l;
- if (!f->last_error && f->is_write == 0 && f->buf_index > 0) {
+ if (f->last_error) {
+ return;
+ }
+
+ if (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->last_error && size > 0) {
+ while (size > 0) {
l = IO_BUF_SIZE - f->buf_index;
if (l > size)
l = size;
f->buf_index += l;
buf += l;
size -= l;
- if (f->buf_index >= IO_BUF_SIZE)
- qemu_fflush(f);
+ if (f->buf_index >= IO_BUF_SIZE) {
+ int ret = qemu_fflush(f);
+ if (ret < 0) {
+ qemu_file_set_error(f, ret);
+ break;
+ }
+ }
}
}
void qemu_put_byte(QEMUFile *f, int v)
{
- if (!f->last_error && f->is_write == 0 && f->buf_index > 0) {
+ if (f->last_error) {
+ return;
+ }
+
+ if (f->is_write == 0 && f->buf_index > 0) {
fprintf(stderr,
"Attempted to write to buffer while read buffer is not empty\n");
abort();
f->buf[f->buf_index++] = v;
f->is_write = 1;
- if (f->buf_index >= IO_BUF_SIZE)
- qemu_fflush(f);
+ if (f->buf_index >= IO_BUF_SIZE) {
+ int ret = qemu_fflush(f);
+ if (ret < 0) {
+ qemu_file_set_error(f, ret);
+ }
+ }
}
static void qemu_file_skip(QEMUFile *f, int size)
return result;
}
-int64_t qemu_ftell(QEMUFile *f)
+static int64_t qemu_ftell(QEMUFile *f)
{
return f->buf_offset - f->buf_size + f->buf_index;
}
-int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence)
-{
- if (whence == SEEK_SET) {
- /* nothing to do */
- } else if (whence == SEEK_CUR) {
- pos += qemu_ftell(f);
- } else {
- /* SEEK_END not supported */
- return -1;
- }
- if (f->put_buffer) {
- qemu_fflush(f);
- f->buf_offset = pos;
- } else {
- f->buf_offset = pos;
- f->buf_index = 0;
- f->buf_size = 0;
- }
- return pos;
-}
-
int qemu_file_rate_limit(QEMUFile *f)
{
if (f->rate_limit)
int alias_id;
int version_id;
int section_id;
- SaveSetParamsHandler *set_params;
- SaveLiveStateHandler *save_live_state;
- SaveStateHandler *save_state;
- LoadStateHandler *load_state;
+ SaveVMHandlers *ops;
const VMStateDescription *vmsd;
void *opaque;
CompatEntry *compat;
const char *idstr,
int instance_id,
int version_id,
- SaveSetParamsHandler *set_params,
- SaveLiveStateHandler *save_live_state,
- SaveStateHandler *save_state,
- LoadStateHandler *load_state,
+ SaveVMHandlers *ops,
void *opaque)
{
SaveStateEntry *se;
se = g_malloc0(sizeof(SaveStateEntry));
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;
+ se->ops = ops;
se->opaque = opaque;
se->vmsd = NULL;
se->no_migrate = 0;
/* if this is a live_savem then set is_ram */
- if (save_live_state != NULL) {
+ if (ops->save_live_setup != NULL) {
se->is_ram = 1;
}
LoadStateHandler *load_state,
void *opaque)
{
+ SaveVMHandlers *ops = g_malloc0(sizeof(SaveVMHandlers));
+ ops->save_state = save_state;
+ ops->load_state = load_state;
return register_savevm_live(dev, idstr, instance_id, version_id,
- NULL, NULL, save_state, load_state, opaque);
+ ops, opaque);
}
void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
if (se->compat) {
g_free(se->compat);
}
+ g_free(se->ops);
g_free(se);
}
}
se = g_malloc0(sizeof(SaveStateEntry));
se->version_id = vmsd->version_id;
se->section_id = global_section_id++;
- se->save_live_state = NULL;
- se->save_state = NULL;
- se->load_state = NULL;
se->opaque = opaque;
se->vmsd = vmsd;
se->alias_id = alias_id;
static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
{
if (!se->vmsd) { /* Old style */
- return se->load_state(f, se->opaque, version_id);
+ return se->ops->load_state(f, se->opaque, version_id);
}
return vmstate_load_state(f, se->vmsd, se->opaque, version_id);
}
static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
{
if (!se->vmsd) { /* Old style */
- se->save_state(f, se->opaque);
+ se->ops->save_state(f, se->opaque);
return;
}
vmstate_save_state(f,se->vmsd, se->opaque);
int ret;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
- if(se->set_params == NULL) {
+ if (!se->ops || !se->ops->set_params) {
continue;
}
- se->set_params(params, se->opaque);
+ se->ops->set_params(params, se->opaque);
}
qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
int len;
- if (se->save_live_state == NULL)
+ if (!se->ops || !se->ops->save_live_setup) {
continue;
-
+ }
+ if (se->ops && se->ops->is_active) {
+ if (!se->ops->is_active(se->opaque)) {
+ continue;
+ }
+ }
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_START);
qemu_put_be32(f, se->section_id);
qemu_put_be32(f, se->instance_id);
qemu_put_be32(f, se->version_id);
- ret = se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
+ ret = se->ops->save_live_setup(f, se->opaque);
if (ret < 0) {
qemu_savevm_state_cancel(f);
return ret;
int ret = 1;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
- if (se->save_live_state == NULL)
+ if (!se->ops || !se->ops->save_live_iterate) {
continue;
-
+ }
+ if (se->ops && se->ops->is_active) {
+ if (!se->ops->is_active(se->opaque)) {
+ continue;
+ }
+ }
if (qemu_file_rate_limit(f)) {
return 0;
}
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->ops->save_live_iterate(f, se->opaque);
trace_savevm_section_end(se->section_id);
if (ret <= 0) {
cpu_synchronize_all_states();
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
- if (se->save_live_state == NULL)
+ if (!se->ops || !se->ops->save_live_complete) {
continue;
-
+ }
+ if (se->ops && se->ops->is_active) {
+ if (!se->ops->is_active(se->opaque)) {
+ continue;
+ }
+ }
trace_savevm_section_start();
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_END);
qemu_put_be32(f, se->section_id);
- ret = se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
+ ret = se->ops->save_live_complete(f, se->opaque);
trace_savevm_section_end(se->section_id);
if (ret < 0) {
return ret;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
int len;
- if (se->save_state == NULL && se->vmsd == NULL)
+ if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
continue;
-
+ }
trace_savevm_section_start();
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_FULL);
SaveStateEntry *se;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
- if (se->save_live_state) {
- se->save_live_state(f, -1, se->opaque);
+ if (se->ops && se->ops->cancel) {
+ se->ops->cancel(se->opaque);
}
}
}
if (se->is_ram) {
continue;
}
- if (se->save_state == NULL && se->vmsd == NULL) {
+ if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
continue;
}
the_end:
if (saved_vm_running)
vm_start();
- return;
}
int load_vmstate(const char *name)
{
vmstate_register_ram(mr, NULL);
}
+
+/*
+ page = zrun nzrun
+ | zrun nzrun page
+
+ zrun = length
+
+ nzrun = length byte...
+
+ length = uleb128 encoded integer
+ */
+int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
+ uint8_t *dst, int dlen)
+{
+ uint32_t zrun_len = 0, nzrun_len = 0;
+ int d = 0, i = 0;
+ long res, xor;
+ uint8_t *nzrun_start = NULL;
+
+ g_assert(!(((uintptr_t)old_buf | (uintptr_t)new_buf | slen) %
+ sizeof(long)));
+
+ while (i < slen) {
+ /* overflow */
+ if (d + 2 > dlen) {
+ return -1;
+ }
+
+ /* not aligned to sizeof(long) */
+ res = (slen - i) % sizeof(long);
+ while (res && old_buf[i] == new_buf[i]) {
+ zrun_len++;
+ i++;
+ res--;
+ }
+
+ /* word at a time for speed */
+ if (!res) {
+ while (i < slen &&
+ (*(long *)(old_buf + i)) == (*(long *)(new_buf + i))) {
+ i += sizeof(long);
+ zrun_len += sizeof(long);
+ }
+
+ /* go over the rest */
+ while (i < slen && old_buf[i] == new_buf[i]) {
+ zrun_len++;
+ i++;
+ }
+ }
+
+ /* buffer unchanged */
+ if (zrun_len == slen) {
+ return 0;
+ }
+
+ /* skip last zero run */
+ if (i == slen) {
+ return d;
+ }
+
+ d += uleb128_encode_small(dst + d, zrun_len);
+
+ zrun_len = 0;
+ nzrun_start = new_buf + i;
+
+ /* overflow */
+ if (d + 2 > dlen) {
+ return -1;
+ }
+ /* not aligned to sizeof(long) */
+ res = (slen - i) % sizeof(long);
+ while (res && old_buf[i] != new_buf[i]) {
+ i++;
+ nzrun_len++;
+ res--;
+ }
+
+ /* word at a time for speed, use of 32-bit long okay */
+ if (!res) {
+ /* truncation to 32-bit long okay */
+ long mask = (long)0x0101010101010101ULL;
+ while (i < slen) {
+ xor = *(long *)(old_buf + i) ^ *(long *)(new_buf + i);
+ if ((xor - mask) & ~xor & (mask << 7)) {
+ /* found the end of an nzrun within the current long */
+ while (old_buf[i] != new_buf[i]) {
+ nzrun_len++;
+ i++;
+ }
+ break;
+ } else {
+ i += sizeof(long);
+ nzrun_len += sizeof(long);
+ }
+ }
+ }
+
+ d += uleb128_encode_small(dst + d, nzrun_len);
+ /* overflow */
+ if (d + nzrun_len > dlen) {
+ return -1;
+ }
+ memcpy(dst + d, nzrun_start, nzrun_len);
+ d += nzrun_len;
+ nzrun_len = 0;
+ }
+
+ return d;
+}
+
+int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen)
+{
+ int i = 0, d = 0;
+ int ret;
+ uint32_t count = 0;
+
+ while (i < slen) {
+
+ /* zrun */
+ if ((slen - i) < 2) {
+ return -1;
+ }
+
+ ret = uleb128_decode_small(src + i, &count);
+ if (ret < 0 || (i && !count)) {
+ return -1;
+ }
+ i += ret;
+ d += count;
+
+ /* overflow */
+ if (d > dlen) {
+ return -1;
+ }
+
+ /* nzrun */
+ if ((slen - i) < 2) {
+ return -1;
+ }
+
+ ret = uleb128_decode_small(src + i, &count);
+ if (ret < 0 || !count) {
+ return -1;
+ }
+ i += ret;
+
+ /* overflow */
+ if (d + count > dlen || i + count > slen) {
+ return -1;
+ }
+
+ memcpy(dst + d, src + i, count);
+ d += count;
+ i += count;
+ }
+
+ return d;
+}