static int dump_cleanup(DumpState *s)
{
+ if (s->dump_info.arch_cleanup_fn) {
+ s->dump_info.arch_cleanup_fn(s);
+ }
+
guest_phys_blocks_free(&s->guest_phys_blocks);
memory_mapping_list_free(&s->list);
close(s->fd);
g_free(s->guest_note);
- g_array_unref(s->string_table_buf);
+ g_clear_pointer(&s->string_table_buf, g_array_unref);
s->guest_note = NULL;
if (s->resume) {
if (s->detached) {
qemu_mutex_unlock_iothread();
}
}
- migrate_del_blocker(dump_migration_blocker);
+ migrate_del_blocker(&dump_migration_blocker);
return 0;
}
dump_end(s, errp);
}
-static int write_start_flat_header(int fd)
+static int write_start_flat_header(DumpState *s)
{
MakedumpfileHeader *mh;
int ret = 0;
+ if (s->kdump_raw) {
+ return 0;
+ }
+
QEMU_BUILD_BUG_ON(sizeof *mh > MAX_SIZE_MDF_HEADER);
mh = g_malloc0(MAX_SIZE_MDF_HEADER);
mh->version = cpu_to_be64(VERSION_FLAT_HEADER);
size_t written_size;
- written_size = qemu_write_full(fd, mh, MAX_SIZE_MDF_HEADER);
+ written_size = qemu_write_full(s->fd, mh, MAX_SIZE_MDF_HEADER);
if (written_size != MAX_SIZE_MDF_HEADER) {
ret = -1;
}
return ret;
}
-static int write_end_flat_header(int fd)
+static int write_end_flat_header(DumpState *s)
{
MakedumpfileDataHeader mdh;
+ if (s->kdump_raw) {
+ return 0;
+ }
+
mdh.offset = END_FLAG_FLAT_HEADER;
mdh.buf_size = END_FLAG_FLAT_HEADER;
size_t written_size;
- written_size = qemu_write_full(fd, &mdh, sizeof(mdh));
+ written_size = qemu_write_full(s->fd, &mdh, sizeof(mdh));
if (written_size != sizeof(mdh)) {
return -1;
}
return 0;
}
-static int write_buffer(int fd, off_t offset, const void *buf, size_t size)
+static int write_buffer(DumpState *s, off_t offset, const void *buf, size_t size)
{
size_t written_size;
MakedumpfileDataHeader mdh;
+ off_t seek_loc;
- mdh.offset = cpu_to_be64(offset);
- mdh.buf_size = cpu_to_be64(size);
+ if (s->kdump_raw) {
+ seek_loc = lseek(s->fd, offset, SEEK_SET);
+ if (seek_loc == (off_t) -1) {
+ return -1;
+ }
+ } else {
+ mdh.offset = cpu_to_be64(offset);
+ mdh.buf_size = cpu_to_be64(size);
- written_size = qemu_write_full(fd, &mdh, sizeof(mdh));
- if (written_size != sizeof(mdh)) {
- return -1;
+ written_size = qemu_write_full(s->fd, &mdh, sizeof(mdh));
+ if (written_size != sizeof(mdh)) {
+ return -1;
+ }
}
- written_size = qemu_write_full(fd, buf, size);
+ written_size = qemu_write_full(s->fd, buf, size);
if (written_size != size) {
return -1;
}
#endif
dh->status = cpu_to_dump32(s, status);
- if (write_buffer(s->fd, 0, dh, size) < 0) {
+ if (write_buffer(s, 0, dh, size) < 0) {
error_setg(errp, "dump: failed to write disk dump header");
goto out;
}
kh->offset_note = cpu_to_dump64(s, offset_note);
kh->note_size = cpu_to_dump32(s, s->note_size);
- if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
+ if (write_buffer(s, DISKDUMP_HEADER_BLOCKS *
block_size, kh, size) < 0) {
error_setg(errp, "dump: failed to write kdump sub header");
goto out;
if (*errp) {
goto out;
}
- if (write_buffer(s->fd, offset_note, s->note_buf,
+ if (write_buffer(s, offset_note, s->note_buf,
s->note_size) < 0) {
error_setg(errp, "dump: failed to write notes");
goto out;
#endif
dh->status = cpu_to_dump32(s, status);
- if (write_buffer(s->fd, 0, dh, size) < 0) {
+ if (write_buffer(s, 0, dh, size) < 0) {
error_setg(errp, "dump: failed to write disk dump header");
goto out;
}
kh->offset_note = cpu_to_dump64(s, offset_note);
kh->note_size = cpu_to_dump64(s, s->note_size);
- if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
+ if (write_buffer(s, DISKDUMP_HEADER_BLOCKS *
block_size, kh, size) < 0) {
error_setg(errp, "dump: failed to write kdump sub header");
goto out;
goto out;
}
- if (write_buffer(s->fd, offset_note, s->note_buf,
+ if (write_buffer(s, offset_note, s->note_buf,
s->note_size) < 0) {
error_setg(errp, "dump: failed to write notes");
goto out;
while (old_offset < new_offset) {
/* calculate the offset and write dump_bitmap */
offset_bitmap1 = s->offset_dump_bitmap + old_offset;
- if (write_buffer(s->fd, offset_bitmap1, buf,
+ if (write_buffer(s, offset_bitmap1, buf,
bitmap_bufsize) < 0) {
return -1;
}
/* dump level 1 is chosen, so 1st and 2nd bitmap are same */
offset_bitmap2 = s->offset_dump_bitmap + s->len_dump_bitmap +
old_offset;
- if (write_buffer(s->fd, offset_bitmap2, buf,
+ if (write_buffer(s, offset_bitmap2, buf,
bitmap_bufsize) < 0) {
return -1;
}
static void prepare_data_cache(DataCache *data_cache, DumpState *s,
off_t offset)
{
- data_cache->fd = s->fd;
+ data_cache->state = s;
data_cache->data_size = 0;
data_cache->buf_size = 4 * dump_bitmap_get_bufsize(s);
data_cache->buf = g_malloc0(data_cache->buf_size);
/*
* if flag_sync is set, synchronize data in dc->buf into vmcore.
* otherwise check if the space is enough for caching data in buf, if not,
- * write the data in dc->buf to dc->fd and reset dc->buf
+ * write the data in dc->buf to dc->state->fd and reset dc->buf
*/
if ((!flag_sync && dc->data_size + size > dc->buf_size) ||
(flag_sync && dc->data_size > 0)) {
- if (write_buffer(dc->fd, dc->offset, dc->buf, dc->data_size) < 0) {
+ if (write_buffer(dc->state, dc->offset, dc->buf, dc->data_size) < 0) {
return -1;
}
* +------------------------------------------+
*/
- ret = write_start_flat_header(s->fd);
+ ret = write_start_flat_header(s);
if (ret < 0) {
error_setg(errp, "dump: failed to write start flat header");
return;
return;
}
- ret = write_end_flat_header(s->fd);
+ ret = write_end_flat_header(s);
if (ret < 0) {
error_setg(errp, "dump: failed to write end flat header");
return;
}
}
-static int validate_start_block(DumpState *s)
-{
- GuestPhysBlock *block;
-
- if (!dump_has_filter(s)) {
- return 0;
- }
-
- QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
- /* This block is out of the range */
- if (block->target_start >= s->filter_area_begin + s->filter_area_length ||
- block->target_end <= s->filter_area_begin) {
- continue;
- }
- return 0;
- }
-
- return -1;
-}
-
static void get_max_mapnr(DumpState *s)
{
GuestPhysBlock *last_block;
static void dump_init(DumpState *s, int fd, bool has_format,
DumpGuestMemoryFormat format, bool paging, bool has_filter,
- int64_t begin, int64_t length, Error **errp)
+ int64_t begin, int64_t length, bool kdump_raw,
+ Error **errp)
{
ERRP_GUARD();
VMCoreInfoState *vmci = vmcoreinfo_find();
s->has_format = has_format;
s->format = format;
s->written_size = 0;
+ s->kdump_raw = kdump_raw;
/* kdump-compressed is conflict with paging and filter */
if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
s->fd = fd;
if (has_filter && !length) {
- error_setg(errp, QERR_INVALID_PARAMETER, "length");
+ error_setg(errp, "parameter 'length' expects a non-zero size");
goto cleanup;
}
s->filter_area_begin = begin;
goto cleanup;
}
- /* Is the filter filtering everything? */
- if (validate_start_block(s) == -1) {
- error_setg(errp, QERR_INVALID_PARAMETER, "begin");
- goto cleanup;
- }
-
/* get dump info: endian, class and architecture.
* If the target architecture is not supported, cpu_get_dump_info() will
* return -1.
if (vmci) {
uint64_t addr, note_head_size, name_size, desc_size;
uint32_t size;
- uint16_t format;
+ uint16_t guest_format;
note_head_size = dump_is_64bit(s) ?
sizeof(Elf64_Nhdr) : sizeof(Elf32_Nhdr);
- format = le16_to_cpu(vmci->vmcoreinfo.guest_format);
+ guest_format = le16_to_cpu(vmci->vmcoreinfo.guest_format);
size = le32_to_cpu(vmci->vmcoreinfo.size);
addr = le64_to_cpu(vmci->vmcoreinfo.paddr);
if (!vmci->has_vmcoreinfo) {
warn_report("guest note is not present");
} else if (size < note_head_size || size > MAX_GUEST_NOTE_SIZE) {
warn_report("guest note size is invalid: %" PRIu32, size);
- } else if (format != FW_CFG_VMCOREINFO_FORMAT_ELF) {
- warn_report("guest note format is unsupported: %" PRIu16, format);
+ } else if (guest_format != FW_CFG_VMCOREINFO_FORMAT_ELF) {
+ warn_report("guest note format is unsupported: %" PRIu16, guest_format);
} else {
s->guest_note = g_malloc(size + 1); /* +1 for adding \0 */
cpu_physical_memory_read(addr, s->guest_note, size);
return result;
}
-void qmp_dump_guest_memory(bool paging, const char *file,
+void qmp_dump_guest_memory(bool paging, const char *protocol,
bool has_detach, bool detach,
- bool has_begin, int64_t begin, bool has_length,
- int64_t length, bool has_format,
- DumpGuestMemoryFormat format, Error **errp)
+ bool has_begin, int64_t begin,
+ bool has_length, int64_t length,
+ bool has_format, DumpGuestMemoryFormat format,
+ Error **errp)
{
ERRP_GUARD();
const char *p;
- int fd = -1;
+ int fd;
DumpState *s;
bool detach_p = false;
+ bool kdump_raw = false;
if (runstate_check(RUN_STATE_INMIGRATE)) {
error_setg(errp, "Dump not allowed during incoming migration.");
return;
}
+ /*
+ * externally, we represent kdump-raw-* as separate formats, but internally
+ * they are handled the same, except for the "raw" flag
+ */
+ if (has_format) {
+ switch (format) {
+ case DUMP_GUEST_MEMORY_FORMAT_KDUMP_RAW_ZLIB:
+ format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB;
+ kdump_raw = true;
+ break;
+ case DUMP_GUEST_MEMORY_FORMAT_KDUMP_RAW_LZO:
+ format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO;
+ kdump_raw = true;
+ break;
+ case DUMP_GUEST_MEMORY_FORMAT_KDUMP_RAW_SNAPPY:
+ format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY;
+ kdump_raw = true;
+ break;
+ default:
+ break;
+ }
+ }
+
/*
* kdump-compressed format need the whole memory dumped, so paging or
* filter is not supported here.
return;
}
-#if !defined(WIN32)
- if (strstart(file, "fd:", &p)) {
+ if (strstart(protocol, "fd:", &p)) {
fd = monitor_get_fd(monitor_cur(), p, errp);
if (fd == -1) {
return;
}
- }
-#endif
-
- if (strstart(file, "file:", &p)) {
- fd = qemu_open_old(p, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR);
+ } else if (strstart(protocol, "file:", &p)) {
+ fd = qemu_create(p, O_WRONLY | O_TRUNC | O_BINARY, S_IRUSR, errp);
if (fd < 0) {
- error_setg_file_open(errp, errno, p);
return;
}
+ } else {
+ error_setg(errp,
+ "parameter 'protocol' must start with 'file:' or 'fd:'");
+ return;
}
-
- if (fd == -1) {
- error_setg(errp, QERR_INVALID_PARAMETER, "protocol");
+ if (kdump_raw && lseek(fd, 0, SEEK_CUR) == (off_t) -1) {
+ close(fd);
+ error_setg(errp, "kdump-raw formats require a seekable file");
return;
}
* Allows even for -only-migratable, but forbid migration during the
* process of dump guest memory.
*/
- if (migrate_add_blocker_internal(dump_migration_blocker, errp)) {
+ if (migrate_add_blocker_internal(&dump_migration_blocker, errp)) {
/* Remember to release the fd before passing it over to dump state */
close(fd);
return;
dump_state_prepare(s);
dump_init(s, fd, has_format, format, paging, has_begin,
- begin, length, errp);
+ begin, length, kdump_raw, errp);
if (*errp) {
qatomic_set(&s->status, DUMP_STATUS_FAILED);
return;
/* kdump-zlib is always available */
QAPI_LIST_APPEND(tail, DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB);
+ QAPI_LIST_APPEND(tail, DUMP_GUEST_MEMORY_FORMAT_KDUMP_RAW_ZLIB);
/* add new item if kdump-lzo is available */
#ifdef CONFIG_LZO
QAPI_LIST_APPEND(tail, DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO);
+ QAPI_LIST_APPEND(tail, DUMP_GUEST_MEMORY_FORMAT_KDUMP_RAW_LZO);
#endif
/* add new item if kdump-snappy is available */
#ifdef CONFIG_SNAPPY
QAPI_LIST_APPEND(tail, DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY);
+ QAPI_LIST_APPEND(tail, DUMP_GUEST_MEMORY_FORMAT_KDUMP_RAW_SNAPPY);
#endif
if (win_dump_available(NULL)) {