The following patch will use these functions to write cached data into vmcore. Header is cached in DumpState, and bitmap and page are cached in tmp files.
Signed-off-by: Qiao Nuohan <qiaonuo...@cn.fujitsu.com> Reviewed-by: Zhang Xiaohe <zhan...@cn.fujitsu.com> --- dump.c | 247 +++++++++++++++++++++++++++++++++++++++++++++++++ include/sysemu/dump.h | 1 + 2 files changed, 248 insertions(+), 0 deletions(-) diff --git a/dump.c b/dump.c index c372113..aa83744 100644 --- a/dump.c +++ b/dump.c @@ -66,6 +66,34 @@ static void dump_error(DumpState *s, const char *reason) dump_cleanup(s); } +/* + * write 'size' of 'c' to dump file + */ +static int fill_space(size_t size, int c, void *opaque) +{ + DumpState *s = opaque; + char tmpbuf[TMP_BUF_SIZE]; + size_t fill_size; + size_t written_size; + + memset(&tmpbuf, c, TMP_BUF_SIZE); + + while (size) { + if (size > TMP_BUF_SIZE) + fill_size = TMP_BUF_SIZE; + else + fill_size = size; + + size -= fill_size; + + written_size = qemu_write_full(s->fd, tmpbuf, fill_size); + if (written_size != fill_size) + return -1; + } + + return 0; +} + static int fd_write_vmcore(void *buf, size_t size, void *opaque) { DumpState *s = opaque; @@ -671,6 +699,225 @@ static ram_addr_t get_start_block(DumpState *s) return -1; } +static int write_dump_header(DumpState *s) +{ + int ret; + void *dh; + void *kh; + + /* write common header */ + dh = s->dh; + + if (s->dump_info.d_machine == EM_386) { + ret = fd_write_vmcore(dh, sizeof(struct disk_dump_header32), s); + if (ret < 0) { + dump_error(s, "dump: failed to write disk dump header.\n"); + return -1; + } + } else { + ret = fd_write_vmcore(dh, sizeof(struct disk_dump_header64), s); + if (ret < 0) { + dump_error(s, "dump: failed to write disk dump header.\n"); + return -1; + } + } + + /* fill gap between command header and sub header */ + ret = fill_space(s->offset_sub_header, 0, s); + if (ret < 0) { + dump_error(s, "dump: failed to fill the space between header and sub header.\n"); + return -1; + } + + /* write sub header */ + kh = s->kh; + + if (s->dump_info.d_machine == EM_386) { + ret = fd_write_vmcore(kh, sizeof(struct kdump_sub_header32), s); + if (ret < 0) { + dump_error(s, "dump: failed to write kdump sub header.\n"); + return -1; + } + } else { + ret = fd_write_vmcore(kh, sizeof(struct kdump_sub_header64), s); + if (ret < 0) { + dump_error(s, "dump: failed to write kdump sub header.\n"); + return -1; + } + } + + /* write note */ + if (s->dump_info.d_class == ELFCLASS64) { + if (write_elf64_notes(s) < 0) { + return -1; + } + } else { + if (write_elf32_notes(s) < 0) { + return -1; + } + } + + return 0; +} + +static int write_dump_bitmap(DumpState *s) +{ + struct cache_data bm; + long buf_size; + int ret; + int no_bitmap; + + /* fill gap between header and dump_bitmap */ + ret = fill_space(s->offset_dump_bitmap, 0, s); + if (ret < 0) { + dump_error(s, "dump: failed to fill the space between header and dump_bitmap.\n"); + goto out; + } + + bm.buf = g_malloc0(TMP_BUF_SIZE); + + /* write dump_bitmap1 */ + bm.fd = s->dump_bitmap1->fd; + no_bitmap = 1; + +again: + buf_size = s->len_dump_bitmap / 2; + bm.offset = 0; + + while (buf_size > 0) { + if (buf_size >= TMP_BUF_SIZE) + bm.cache_size = TMP_BUF_SIZE; + else + bm.cache_size = buf_size; + + ret = read_cache(&bm); + if (ret < 0) + goto out; + + ret = fd_write_vmcore(bm.buf, bm.cache_size, s); + if (ret < 0) + goto out; + + buf_size -= bm.cache_size; + } + + /* switch to dump_bitmap2 */ + if (no_bitmap == 1) { + no_bitmap = 2; + bm.fd = s->dump_bitmap2->fd; + goto again; + } + + return 0; + +out: + if (bm.buf) + g_free(bm.buf); + + return -1; +} + +static int write_dump_pages(DumpState *s) +{ + struct cache_data page; + unsigned long long total_size; + int is_page_desc; + int ret; + + page.buf = g_malloc0(TMP_BUF_SIZE); + + /* write page_desc */ + is_page_desc = 1; + total_size = s->page_desc_size; + page.fd = s->page_desc->fd; + page.offset = s->page_desc->offset; + +again: + while (total_size > 0) { + if (total_size > TMP_BUF_SIZE) + page.cache_size = TMP_BUF_SIZE; + else + page.cache_size = total_size; + + ret = read_cache(&page); + if (ret < 0) + goto out; + + ret = fd_write_vmcore(page.buf, page.cache_size, s); + if (ret < 0) + goto out; + + total_size -= page.cache_size; + } + + /* switch to page_data */ + if (is_page_desc) { + is_page_desc = 0; + total_size = s->page_data_size; + page.fd = s->page_data->fd; + page.offset = s->page_data->offset; + goto again; + } + + return 0; + +out: + if (page.buf) + g_free(page.buf); + + return -1; +} + +static int create_kdump_vmcore(DumpState *s) +{ + int ret; + + /* + * the kdump-compressed format is: + * File offset + * +------------------------------------------+ 0x0 + * | main header (struct disk_dump_header) | + * |------------------------------------------+ block 1 + * | sub header (struct kdump_sub_header) | + * |------------------------------------------+ block 2 + * | 1st-dump_bitmap | + * |------------------------------------------+ block 2 + X blocks + * | 2nd-dump_bitmap | (aligned by block) + * |------------------------------------------+ block 2 + 2 * X blocks + * | page desc for pfn 0 (struct page_desc) | (aligned by block) + * | page desc for pfn 1 (struct page_desc) | + * | : | + * | page desc for pfn Z (struct page_desc) | + * |------------------------------------------| (not aligned by block) + * | page data (pfn 0) | + * | page data (pfn 1) | + * | : | + * | page data (pfn Z) | + * +------------------------------------------+ offset_eraseinfo + * | : | + * +------------------------------------------+ + */ + + ret = write_dump_header(s); + if (ret < 0) { + return -1; + } + + ret = write_dump_bitmap(s); + if (ret < 0) { + return -1; + } + + ret = write_dump_pages(s); + if (ret < 0) { + return -1; + } + + dump_completed(s); + + return 0; +} + static int create_header32(DumpState *s) { struct disk_dump_header32 *dh; diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index b61c9ba..4913468 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -49,6 +49,7 @@ #define DISKDUMP_HEADER_BLOCKS (1) #define PHYS_BASE (0) #define DUMP_LEVEL (1) +#define TMP_BUF_SIZE (1024) #define ARCH_PFN_OFFSET (0) #define FILENAME_BITMAP1 "kdump_bitmap1_XXXXXX" #define FILENAME_BITMAP2 "kdump_bitmap2_XXXXXX" -- 1.7.1