void ram_control_before_iterate(QEMUFile *f, uint64_t flags) { int ret = 0; if (f->hooks && f->hooks->before_ram_iterate) { ret = f->hooks->before_ram_iterate(f, f->opaque, flags, NULL); if (ret < 0) { qemu_file_set_error(f, ret); } } }
/** * Copies the current contents of a disk image into the snapshot file. * * TODO optimize this using some kind of copy-on-write mechanism for * unchanged disk sections. */ static void nand_dev_save_disk_state(QEMUFile *f, nand_dev *dev) { int buf_size = NAND_DEV_SAVE_DISK_BUF_SIZE; uint8_t buffer[NAND_DEV_SAVE_DISK_BUF_SIZE] = {0}; int ret; uint64_t total_copied = 0; /* Size of file to restore, hence size of data block following. * TODO Work out whether to use lseek64 here. */ ret = do_lseek(dev->fd, 0, SEEK_END); if (ret < 0) { XLOG("%s EOF seek failed: %s\n", __FUNCTION__, strerror(errno)); qemu_file_set_error(f); return; } const uint64_t total_size = ret; qemu_put_be64(f, total_size); /* copy all data from the stream to the stored image */ ret = do_lseek(dev->fd, 0, SEEK_SET); if (ret < 0) { XLOG("%s seek failed: %s\n", __FUNCTION__, strerror(errno)); qemu_file_set_error(f); return; } do { ret = do_read(dev->fd, buffer, buf_size); if (ret < 0) { XLOG("%s read failed: %s\n", __FUNCTION__, strerror(errno)); qemu_file_set_error(f); return; } qemu_put_buffer(f, buffer, ret); total_copied += ret; } while (ret == buf_size && total_copied < dev->max_size); /* TODO Maybe check that we've written total_size bytes */ }
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 migrate_fd_wait_for_unfreeze(void *opaque) { MigrationState *s = opaque; int ret; DPRINTF("wait for unfreeze\n"); if (s->state != MIG_STATE_ACTIVE) return; do { fd_set wfds; FD_ZERO(&wfds); FD_SET(s->fd, &wfds); ret = select(s->fd + 1, NULL, &wfds, NULL, NULL); } while (ret == -1 && (s->get_error(s)) == EINTR); if (ret == -1) { qemu_file_set_error(s->file, -s->get_error(s)); } }
static void buffered_flush(QEMUFileBuffered *s) { size_t offset = 0; int error; error = qemu_file_get_error(s->file); if (error != 0) { DPRINTF("flush when error, bailing: %s\n", strerror(-error)); return; } DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size); while (offset < s->buffer_size) { ssize_t ret; ret = s->put_buffer(s->opaque, s->buffer + offset, s->buffer_size - offset); if (ret == -EAGAIN) { DPRINTF("backend not ready, freezing\n"); s->freeze_output = 1; break; } if (ret <= 0) { DPRINTF("error flushing data, %zd\n", ret); qemu_file_set_error(s->file, ret); break; } else { DPRINTF("flushed %zd byte(s)\n", ret); offset += ret; } } DPRINTF("flushed %zu of %zu byte(s)\n", offset, s->buffer_size); memmove(s->buffer, s->buffer + offset, s->buffer_size - offset); s->buffer_size -= offset; }
static void buffered_flush(QEMUFileBuffered *s) { size_t offset = 0; int error; error = qemu_file_get_error(s->file); if (error != 0) { DPRINTF("flush when error, bailing: %s\n", strerror(-error)); return; } DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size); while (offset < s->buffer_size) { ssize_t ret; ret = s->put_buffer(s->opaque, s->buffer + offset, s->buffer_size - offset); if (ret == -EAGAIN) { DPRINTF("backend not ready, freezing\n"); DVERYDETAIL{ printf("bflush : backend not ready, freezing\n"); fflush(stdout);} s->freeze_output = 1; break; } if (ret <= 0) { DPRINTF("error flushing data, %zd\n", ret); DVERYDETAIL{ printf("bflush :error flushing data, %zd\n", ret); fflush(stdout);} qemu_file_set_error(s->file, ret); break; } else {
int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) { ram_addr_t addr; uint64_t bytes_transferred_last; double bwidth = 0; uint64_t expected_time = 0; if (stage < 0) { cpu_physical_memory_set_dirty_tracking(0); return 0; } if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) { qemu_file_set_error(f); return 0; } if (stage == 1) { bytes_transferred = 0; /* Make sure all dirty bits are set */ for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) { if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) { cpu_physical_memory_set_dirty(addr); } } /* Enable dirty memory tracking */ cpu_physical_memory_set_dirty_tracking(1); qemu_put_be64(f, last_ram_offset | RAM_SAVE_FLAG_MEM_SIZE); } bytes_transferred_last = bytes_transferred; bwidth = qemu_get_clock_ns(rt_clock); while (!qemu_file_rate_limit(f)) { int ret; ret = ram_save_block(f); bytes_transferred += ret * TARGET_PAGE_SIZE; if (ret == 0) { /* no more blocks */ break; } } bwidth = qemu_get_clock_ns(rt_clock) - bwidth; bwidth = (bytes_transferred - bytes_transferred_last) / bwidth; /* if we haven't transferred anything this round, force expected_time to a * a very high value, but without crashing */ if (bwidth == 0) { bwidth = 0.000001; } /* try transferring iterative blocks of memory */ if (stage == 3) { /* flush all remaining blocks regardless of rate limiting */ while (ram_save_block(f) != 0) { bytes_transferred += TARGET_PAGE_SIZE; } cpu_physical_memory_set_dirty_tracking(0); } qemu_put_be64(f, RAM_SAVE_FLAG_EOS); expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; return (stage == 2) && (expected_time <= migrate_max_downtime()); }
int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, int version_id) { const VMStateField *field = vmsd->fields; int ret = 0; trace_vmstate_load_state(vmsd->name, version_id); if (version_id > vmsd->version_id) { error_report("%s: incoming version_id %d is too new " "for local version_id %d", vmsd->name, version_id, vmsd->version_id); trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL); return -EINVAL; } if (version_id < vmsd->minimum_version_id) { if (vmsd->load_state_old && version_id >= vmsd->minimum_version_id_old) { ret = vmsd->load_state_old(f, opaque, version_id); trace_vmstate_load_state_end(vmsd->name, "old path", ret); return ret; } error_report("%s: incoming version_id %d is too old " "for local minimum version_id %d", vmsd->name, version_id, vmsd->minimum_version_id); trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL); return -EINVAL; } if (vmsd->pre_load) { int ret = vmsd->pre_load(opaque); if (ret) { return ret; } } while (field->name) { trace_vmstate_load_state_field(vmsd->name, field->name); if ((field->field_exists && field->field_exists(opaque, version_id)) || (!field->field_exists && field->version_id <= version_id)) { void *first_elem = opaque + field->offset; int i, n_elems = vmstate_n_elems(opaque, field); int size = vmstate_size(opaque, field); vmstate_handle_alloc(first_elem, field, opaque); if (field->flags & VMS_POINTER) { first_elem = *(void **)first_elem; assert(first_elem || !n_elems || !size); } for (i = 0; i < n_elems; i++) { void *curr_elem = first_elem + size * i; if (field->flags & VMS_ARRAY_OF_POINTER) { curr_elem = *(void **)curr_elem; } if (!curr_elem && size) { /* if null pointer check placeholder and do not follow */ assert(field->flags & VMS_ARRAY_OF_POINTER); ret = vmstate_info_nullptr.get(f, curr_elem, size, NULL); } else if (field->flags & VMS_STRUCT) { ret = vmstate_load_state(f, field->vmsd, curr_elem, field->vmsd->version_id); } else if (field->flags & VMS_VSTRUCT) { ret = vmstate_load_state(f, field->vmsd, curr_elem, field->struct_version_id); } else { ret = field->info->get(f, curr_elem, size, field); } if (ret >= 0) { ret = qemu_file_get_error(f); } if (ret < 0) { qemu_file_set_error(f, ret); error_report("Failed to load %s:%s", vmsd->name, field->name); trace_vmstate_load_field_error(field->name, ret); return ret; } } } else if (field->flags & VMS_MUST_EXIST) { error_report("Input validation failed: %s/%s", vmsd->name, field->name); return -1; } field++; } ret = vmstate_subsection_load(f, vmsd, opaque); if (ret != 0) { return ret; } if (vmsd->post_load) { ret = vmsd->post_load(opaque, version_id); } trace_vmstate_load_state_end(vmsd->name, "end", ret); return ret; }
int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, int version_id) { VMStateField *field = vmsd->fields; int ret = 0; trace_vmstate_load_state(vmsd->name, version_id); if (version_id > vmsd->version_id) { error_report("%s: incoming version_id %d is too new " "for local version_id %d", vmsd->name, version_id, vmsd->version_id); trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL); return -EINVAL; } if (version_id < vmsd->minimum_version_id) { if (vmsd->load_state_old && version_id >= vmsd->minimum_version_id_old) { ret = vmsd->load_state_old(f, opaque, version_id); trace_vmstate_load_state_end(vmsd->name, "old path", ret); return ret; } error_report("%s: incoming version_id %d is too old " "for local minimum version_id %d", vmsd->name, version_id, vmsd->minimum_version_id); trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL); return -EINVAL; } if (vmsd->pre_load) { int ret = vmsd->pre_load(opaque); if (ret) { return ret; } } while (field->name) { trace_vmstate_load_state_field(vmsd->name, field->name); if ((field->field_exists && field->field_exists(opaque, version_id)) || (!field->field_exists && field->version_id <= version_id)) { void *base_addr = vmstate_base_addr(opaque, field, true); int i, n_elems = vmstate_n_elems(opaque, field); int size = vmstate_size(opaque, field); for (i = 0; i < n_elems; 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, size, field); } if (ret >= 0) { ret = qemu_file_get_error(f); } if (ret < 0) { qemu_file_set_error(f, ret); error_report("Failed to load %s:%s", vmsd->name, field->name); trace_vmstate_load_field_error(field->name, ret); return ret; } } } else if (field->flags & VMS_MUST_EXIST) { error_report("Input validation failed: %s/%s", vmsd->name, field->name); return -1; } field++; } ret = vmstate_subsection_load(f, vmsd, opaque); if (ret != 0) { return ret; } if (vmsd->post_load) { ret = vmsd->post_load(opaque, version_id); } trace_vmstate_load_state_end(vmsd->name, "end", ret); return ret; }
int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, int version_id) { VMStateField *field = vmsd->fields; int ret; if (version_id > vmsd->version_id) { return -EINVAL; } if (version_id < vmsd->minimum_version_id) { if (vmsd->load_state_old && version_id >= vmsd->minimum_version_id_old) { return vmsd->load_state_old(f, opaque, version_id); } return -EINVAL; } if (vmsd->pre_load) { int ret = vmsd->pre_load(opaque); if (ret) { return ret; } } while (field->name) { if ((field->field_exists && field->field_exists(opaque, version_id)) || (!field->field_exists && field->version_id <= version_id)) { void *base_addr = vmstate_base_addr(opaque, field, true); int i, n_elems = vmstate_n_elems(opaque, field); int size = vmstate_size(opaque, field); for (i = 0; i < n_elems; 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, size); } if (ret >= 0) { ret = qemu_file_get_error(f); } if (ret < 0) { qemu_file_set_error(f, ret); trace_vmstate_load_field_error(field->name, ret); return ret; } } } else if (field->flags & VMS_MUST_EXIST) { fprintf(stderr, "Input validation failed: %s/%s\n", vmsd->name, field->name); return -1; } field++; } ret = vmstate_subsection_load(f, vmsd, opaque); if (ret != 0) { return ret; } if (vmsd->post_load) { return vmsd->post_load(opaque, version_id); } return 0; }