functions are used to write 1st and 2nd dump_bitmap of kdump-compressed format, which is used to indicate whether the corresponded page is existed in vmcore. Dump level 1 is chosen, so 1st and 2nd dump_bitmap are same.
Signed-off-by: Qiao Nuohan <qiaonuo...@cn.fujitsu.com> Reviewed-by: Zhang Xiaohe <zhan...@cn.fujitsu.com> --- dump.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ include/sysemu/dump.h | 5 ++ 2 files changed, 141 insertions(+), 0 deletions(-) diff --git a/dump.c b/dump.c index cb2f866..40a5ea5 100644 --- a/dump.c +++ b/dump.c @@ -79,12 +79,14 @@ typedef struct DumpState { bool flag_flatten; uint32_t nr_cpus; size_t page_size; + uint32_t page_shift; size_t max_mapnr; size_t len_dump_bitmap; void *note_buf; size_t note_buf_offset; off_t offset_dump_bitmap; off_t offset_page; + size_t num_dumpable; } DumpState; static int dump_cleanup(DumpState *s) @@ -925,6 +927,140 @@ static int write_dump_header(DumpState *s) } } +/* set dump_bitmap sequencely */ +static int set_dump_bitmap(int64_t last_pfn, int64_t pfn, uint32_t value, + void *buf, DumpState *s) +{ + off_t old_offset, new_offset; + off_t offset_bitmap1, offset_bitmap2; + uint32_t byte, bit; + + /* should not set the previous place */ + if (last_pfn > pfn) { + return -1; + } + + /* + * if the block needed to be set is not same as the one cached in buf, flush + * the cached buf to vmcore firstly + */ + old_offset = BUFSIZE_BITMAP * (last_pfn / PFN_BUFBITMAP); + new_offset = BUFSIZE_BITMAP * (pfn / PFN_BUFBITMAP); + + 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, s->flag_flatten, offset_bitmap1, buf, + BUFSIZE_BITMAP) < 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 / 2 + + old_offset; + if (write_buffer(s->fd, s->flag_flatten, offset_bitmap2, buf, + BUFSIZE_BITMAP) < 0) { + return -1; + } + + memset(buf, 0, BUFSIZE_BITMAP); + old_offset += BUFSIZE_BITMAP; + } + + /* get the exact place of the bit in the buf, and set it */ + byte = (pfn % PFN_BUFBITMAP) >> 3; + bit = (pfn % PFN_BUFBITMAP) & 7; + if (value) { + ((char *)buf)[byte] |= 1<<bit; + } else { + ((char *)buf)[byte] &= ~(1<<bit); + } + + return 0; +} + +/* write the remaining dump_bitmap in buf to s->fd */ +static int sync_dump_bitmap(int64_t last_pfn, void *buf, DumpState *s) +{ + off_t last_offset, offset_bitmap1, offset_bitmap2; + + /* nothing is stored in buf */ + if (last_pfn < 0) { + return 0; + } + + last_offset = BUFSIZE_BITMAP * (last_pfn / PFN_BUFBITMAP); + + /* calculate the offset and write dump_bitmap */ + offset_bitmap1 = s->offset_dump_bitmap + last_offset; + if (write_buffer(s->fd, s->flag_flatten, offset_bitmap1, buf, + BUFSIZE_BITMAP) < 0) { + return -1; + } + + offset_bitmap2 = s->offset_dump_bitmap + s->len_dump_bitmap / 2 + + last_offset; + if (write_buffer(s->fd, s->flag_flatten, offset_bitmap2, buf, + BUFSIZE_BITMAP) < 0) { + return -1; + } + + return 0; +} + +static int write_dump_bitmap(DumpState *s) +{ + int ret = 0; + int64_t pfn_start, pfn_end, pfn; + int64_t last_pfn; + void *dump_bitmap_buf; + size_t num_dumpable; + MemoryMapping *memory_mapping; + + /* dump_bitmap_buf is used to store dump_bitmap temporarily */ + dump_bitmap_buf = g_malloc0(BUFSIZE_BITMAP); + + num_dumpable = 0; + last_pfn = -1; + + /* + * exam memory page by page, and set the bit in dump_bitmap corresponded + * to the existing page + */ + QTAILQ_FOREACH(memory_mapping, &s->list.head, next) { + pfn_start = paddr_to_pfn(memory_mapping->phys_addr, s->page_shift); + pfn_end = paddr_to_pfn(memory_mapping->phys_addr + + memory_mapping->length, s->page_shift); + + for (pfn = pfn_start; pfn < pfn_end; pfn++) { + ret = set_dump_bitmap(last_pfn, pfn, 1, dump_bitmap_buf, s); + if (ret < 0) { + dump_error(s, "dump: failed to set dump_bitmap.\n"); + ret = -1; + goto out; + } + + last_pfn = pfn; + num_dumpable++; + } + } + + ret = sync_dump_bitmap(last_pfn, dump_bitmap_buf, s); + if (ret < 0) { + dump_error(s, "dump: failed to sync dump_bitmap.\n"); + ret = -1; + goto out; + } + + /* number of dumpable pages that will be dumped later */ + s->num_dumpable = num_dumpable; + +out: + g_free(dump_bitmap_buf); + + return ret; +} + static ram_addr_t get_start_block(DumpState *s) { RAMBlock *block; diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index 54ae4e5..e67927d 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -25,8 +25,13 @@ #define PHYS_BASE (0) #define DUMP_LEVEL (1) #define DISKDUMP_HEADER_BLOCKS (1) +#define BUFSIZE_BITMAP (4096) +#define PFN_BUFBITMAP (CHAR_BIT * BUFSIZE_BITMAP) +#define ARCH_PFN_OFFSET (0) #define divideup(x, y) (((x) + ((y) - 1)) / (y)) +#define paddr_to_pfn(X, page_shift) \ + (((unsigned long long)(X) >> (page_shift)) - ARCH_PFN_OFFSET) typedef struct ArchDumpInfo { int d_machine; /* Architecture */ -- 1.7.1