functions are used to write page desc and page data to vmcore. Signed-off-by: Qiao Nuohan <qiaonuo...@cn.fujitsu.com> Reviewed-by: Zhang Xiaohe <zhan...@cn.fujitsu.com> --- configure | 50 +++++++++ dump.c | 264 +++++++++++++++++++++++++++++++++++++++++++++++++ include/sysemu/dump.h | 16 +++ 3 files changed, 330 insertions(+), 0 deletions(-)
diff --git a/configure b/configure index 0e0adde..0927972 100755 --- a/configure +++ b/configure @@ -231,6 +231,8 @@ libusb="" usb_redir="" glx="" zlib="yes" +lzo="no" +snappy="no" guest_agent="yes" want_tools="yes" libiscsi="" @@ -912,6 +914,10 @@ for opt do ;; --disable-zlib-test) zlib="no" ;; + --enable-lzo) lzo="yes" + ;; + --enable-snappy) snappy="yes" + ;; --enable-guest-agent) guest_agent="yes" ;; --disable-guest-agent) guest_agent="no" @@ -1471,6 +1477,42 @@ fi libs_softmmu="$libs_softmmu -lz" ########################################## +# lzo check + +if test "$lzo" != "no" ; then + cat > $TMPC << EOF +#include <lzo/lzo1x.h> +int main(void) { lzo_version(); return 0; } +EOF + if compile_prog "" "-llzo2" ; then + : + else + error_exit "lzo check failed" \ + "Make sure to have the lzo libs and headers installed." + fi + + libs_softmmu="$libs_softmmu -llzo2" +fi + +########################################## +# snappy check + +if test "$snappy" != "no" ; then + cat > $TMPC << EOF +#include <snappy-c.h> +int main(void) { snappy_max_compressed_length(4096); return 0; } +EOF + if compile_prog "" "-lsnappy" ; then + : + else + error_exit "snappy check failed" \ + "Make sure to have the snappy libs and headers installed." + fi + + libs_softmmu="$libs_softmmu -lsnappy" +fi + +########################################## # libseccomp check if test "$seccomp" != "no" ; then @@ -3872,6 +3914,14 @@ if test "$glx" = "yes" ; then echo "GLX_LIBS=$glx_libs" >> $config_host_mak fi +if test "$lzo" = "yes" ; then + echo "CONFIG_LZO=y" >> $config_host_mak +fi + +if test "$snappy" = "yes" ; then + echo "CONFIG_SNAPPY=y" >> $config_host_mak +fi + if test "$libiscsi" = "yes" ; then echo "CONFIG_LIBISCSI=y" >> $config_host_mak fi diff --git a/dump.c b/dump.c index 9537f2d..a28e162 100644 --- a/dump.c +++ b/dump.c @@ -25,6 +25,14 @@ #include "qapi/error.h" #include "qmp-commands.h" +#include <zlib.h> +#ifdef CONFIG_LZO +#include <lzo/lzo1x.h> +#endif +#ifdef CONFIG_SNAPPY +#include <snappy-c.h> +#endif + static uint16_t cpu_convert_to_target16(uint16_t val, int endian) { if (endian == ELFDATA2LSB) { @@ -87,6 +95,7 @@ typedef struct DumpState { off_t offset_dump_bitmap; off_t offset_page; size_t num_dumpable; + uint32_t flag_compress; } DumpState; static int dump_cleanup(DumpState *s) @@ -1113,6 +1122,261 @@ static void free_data_cache(DataCache *data_cache) g_free(data_cache->buf); } +static size_t get_len_buf_out(size_t page_size, uint32_t flag_compress) +{ + size_t len_buf_out_zlib, len_buf_out_lzo, len_buf_out_snappy; + size_t len_buf_out; + + /* init buf_out */ + len_buf_out_zlib = len_buf_out_lzo = len_buf_out_snappy = 0; + + /* buf size for zlib */ + len_buf_out_zlib = compressBound(page_size); + + /* buf size for lzo */ +#ifdef CONFIG_LZO + if (flag_compress & DUMP_DH_COMPRESSED_LZO) { + if (lzo_init() != LZO_E_OK) { + /* return 0 to indicate lzo is unavailable */ + return 0; + } + } + + len_buf_out_lzo = page_size + page_size / 16 + 64 + 3; +#endif + +#ifdef CONFIG_SNAPPY + /* buf size for snappy */ + len_buf_out_snappy = snappy_max_compressed_length(page_size); +#endif + + /* get the biggest that can store all kinds of compressed page */ + len_buf_out = MAX(len_buf_out_zlib, + MAX(len_buf_out_lzo, len_buf_out_snappy)); + + return len_buf_out; +} + +/* + * search memory blocks to find the exact place of the specified page, then + * dump the page into buf. memory should be read page by page, or it may exceed + * the boundary and fail to read + */ +static int readmem(void *bufptr, ram_addr_t addr, size_t size, DumpState *s) +{ + RAMBlock *block; + + block = s->block; + + while (block) { + if ((addr >= block->offset) && + (addr + size <= block->offset + block->length)) { + memcpy(bufptr, block->host + (addr - block->offset), size); + return 0; + } else { + block = QTAILQ_NEXT(block, next); + } + } + + return -1; +} + +/* + * check if the page is all 0 + */ +static inline bool is_zero_page(unsigned char *buf, long page_size) +{ + size_t i; + + for (i = 0; i < page_size; i++) { + if (buf[i]) { + return false; + } + } + + return true; +} + +static int write_dump_pages(DumpState *s) +{ + int ret = 0; + DataCache page_desc, page_data; + size_t len_buf_out, size_out; + unsigned char *buf_out = NULL; + off_t offset_desc, offset_data; + PageDesc pd, pd_zero; + uint64_t pfn_start, pfn_end, pfn; + unsigned char buf[s->page_size]; + MemoryMapping *memory_mapping; + bool zero_page; + + prepare_data_cache(&page_desc, s); + prepare_data_cache(&page_data, s); + + /* prepare buffer to store compressed data */ + len_buf_out = get_len_buf_out(s->page_size, s->flag_compress); + if (len_buf_out == 0) { + dump_error(s, "dump: failed to get length of output buffer.\n"); + goto out; + } + +#ifdef CONFIG_LZO + lzo_bytep wrkmem; + + wrkmem = g_malloc(LZO1X_1_MEM_COMPRESS); +#endif + + buf_out = g_malloc(len_buf_out); + + /* get offset of page_desc and page_data in dump file */ + offset_desc = s->offset_page; + offset_data = offset_desc + sizeof(PageDesc) * s->num_dumpable; + page_desc.offset = offset_desc; + page_data.offset = offset_data; + + /* + * init zero page's page_desc and page_data, because every zero page + * uses the same page_data + */ + pd_zero.size = s->page_size; + pd_zero.flags = 0; + pd_zero.offset = offset_data; + pd_zero.page_flags = 0; + memset(buf, 0, pd_zero.size); + ret = write_cache(&page_data, s->flag_flatten, buf, pd_zero.size); + if (ret < 0) { + dump_error(s, "dump: failed to write page data(zero page).\n"); + goto out; + } + + offset_data += pd_zero.size; + + /* dump memory to vmcore page by 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++) { + memset(buf, 0, s->page_size); + ret = readmem(buf, pfn_to_paddr(pfn, s->page_shift), s->page_size, + s); + if (ret < 0) { + dump_error(s, "dump: failed to read memory.\n"); + goto out; + } + + /* check zero page */ + zero_page = is_zero_page(buf, s->page_size); + if (zero_page) { + ret = write_cache(&page_desc, s->flag_flatten, &pd_zero, + sizeof(PageDesc)); + if (ret < 0) { + dump_error(s, "dump: failed to write page desc.\n"); + goto out; + } + } else { + /* + * not zero page, then: + * 1. compress the page + * 2. write the compressed page into the cache of page_data + * 3. get page desc of the compressed page and write it into the + * cache of page_desc + */ + size_out = len_buf_out; + if ((s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) && + (compress2(buf_out, &size_out, buf, s->page_size, + Z_BEST_SPEED) == Z_OK) && (size_out < s->page_size)) { + pd.flags = DUMP_DH_COMPRESSED_ZLIB; + pd.size = size_out; + + ret = write_cache(&page_data, s->flag_flatten, buf_out, + pd.size); + if (ret < 0) { + dump_error(s, "dump: failed to write page data.\n"); + goto out; + } +#ifdef CONFIG_LZO + } else if ((s->flag_compress & DUMP_DH_COMPRESSED_LZO) && + (lzo1x_1_compress(buf, s->page_size, buf_out, + &size_out, wrkmem) == LZO_E_OK) && + (size_out < s->page_size)) { + pd.flags = DUMP_DH_COMPRESSED_LZO; + pd.size = size_out; + + ret = write_cache(&page_data, s->flag_flatten, buf_out, + pd.size); + if (ret < 0) { + dump_error(s, "dump: failed to write page data.\n"); + goto out; + } +#endif +#ifdef CONFIG_SNAPPY + } else if ((s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) && + (snappy_compress((char *)buf, s->page_size, + (char *)buf_out, (size_t *)&size_out) == SNAPPY_OK) && + (size_out < s->page_size)) { + pd.flags = DUMP_DH_COMPRESSED_SNAPPY; + pd.size = size_out; + + ret = write_cache(&page_data, s->flag_flatten, buf_out, + pd.size); + if (ret < 0) { + dump_error(s, "dump: failed to write page data.\n"); + goto out; + } +#endif + } else { + pd.flags = 0; + pd.size = s->page_size; + + ret = write_cache(&page_data, s->flag_flatten, buf, + pd.size); + if (ret < 0) { + dump_error(s, "dump: failed to write page data.\n"); + goto out; + } + } + + /* get and write page desc here */ + pd.page_flags = 0; + pd.offset = offset_data; + offset_data += pd.size; + + ret = write_cache(&page_desc, s->flag_flatten, &pd, + sizeof(PageDesc)); + if (ret < 0) { + dump_error(s, "dump: failed to write page desc.\n"); + goto out; + } + } + } + } + + ret = sync_data_cache(&page_desc, s->flag_flatten); + if (ret < 0) { + dump_error(s, "dump: failed to sync cache for page_desc.\n"); + goto out; + } + ret = sync_data_cache(&page_data, s->flag_flatten); + if (ret < 0) { + dump_error(s, "dump: failed to sync cache for page_data.\n"); + goto out; + } + +out: + free_data_cache(&page_desc); + free_data_cache(&page_data); + +#ifdef CONFIG_LZO + g_free(wrkmem); +#endif + + g_free(buf_out); + + 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 9704b28..c30fcc2 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -20,6 +20,13 @@ #define VERSION_FLAT_HEADER (1) /* version of flattened format */ #define END_FLAG_FLAT_HEADER (-1) +/* + * flag for compressed format + */ +#define DUMP_DH_COMPRESSED_ZLIB (0x1) +#define DUMP_DH_COMPRESSED_LZO (0x2) +#define DUMP_DH_COMPRESSED_SNAPPY (0x4) + #define KDUMP_SIGNATURE "KDUMP " #define SIG_LEN (sizeof(KDUMP_SIGNATURE) - 1) #define PHYS_BASE (0) @@ -33,6 +40,8 @@ #define divideup(x, y) (((x) + ((y) - 1)) / (y)) #define paddr_to_pfn(X, page_shift) \ (((unsigned long long)(X) >> (page_shift)) - ARCH_PFN_OFFSET) +#define pfn_to_paddr(X, page_shift) \ + (((unsigned long long)(X) + ARCH_PFN_OFFSET) << (page_shift)) typedef struct ArchDumpInfo { int d_machine; /* Architecture */ @@ -130,6 +139,13 @@ typedef struct DataCache { off_t offset; /* offset of the file */ } DataCache; +typedef struct PageDesc { + off_t offset; /* the offset of the page data*/ + uint32_t size; /* the size of this dump page */ + uint32_t flags; /* flags */ + uint64_t page_flags; /* page flags */ +} PageDesc; + int cpu_get_dump_info(ArchDumpInfo *info); ssize_t cpu_get_note_size(int class, int machine, int nr_cpus); -- 1.7.1