static int write_dump_pages(DumpState *s) { int ret = 0; DataCache page_desc, page_data; size_t len_buf_out, size_out; #ifdef CONFIG_LZO lzo_bytep wrkmem = NULL; #endif uint8_t *buf_out = NULL; off_t offset_desc, offset_data; PageDescriptor pd, pd_zero; uint8_t *buf; int endian = s->dump_info.d_endian; GuestPhysBlock *block_iter = NULL; uint64_t pfn_iter; /* get offset of page_desc and page_data in dump file */ offset_desc = s->offset_page; offset_data = offset_desc + sizeof(PageDescriptor) * s->num_dumpable; prepare_data_cache(&page_desc, s, offset_desc); prepare_data_cache(&page_data, s, offset_data); /* 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 wrkmem = g_malloc(LZO1X_1_MEM_COMPRESS); #endif buf_out = g_malloc(len_buf_out); /* * init zero page's page_desc and page_data, because every zero page * uses the same page_data */ pd_zero.size = cpu_convert_to_target32(s->page_size, endian); pd_zero.flags = cpu_convert_to_target32(0, endian); pd_zero.offset = cpu_convert_to_target64(offset_data, endian); pd_zero.page_flags = cpu_convert_to_target64(0, endian); buf = g_malloc0(s->page_size); ret = write_cache(&page_data, buf, s->page_size, false); g_free(buf); if (ret < 0) { dump_error(s, "dump: failed to write page data(zero page).\n"); goto out; } offset_data += s->page_size; /* * dump memory to vmcore page by page. zero page will all be resided in the * first page of page section */ while (get_next_page(&block_iter, &pfn_iter, &buf, s)) { /* check zero page */ if (is_zero_page(buf, s->page_size)) { ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor), false); 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 * * only one compression format will be used here, for * s->flag_compress is set. But when compression fails to work, * we fall back to save in plaintext. */ size_out = len_buf_out; if ((s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) && (compress2(buf_out, (uLongf *)&size_out, buf, s->page_size, Z_BEST_SPEED) == Z_OK) && (size_out < s->page_size)) { pd.flags = cpu_convert_to_target32(DUMP_DH_COMPRESSED_ZLIB, endian); pd.size = cpu_convert_to_target32(size_out, endian); ret = write_cache(&page_data, buf_out, size_out, false); 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, (lzo_uint *)&size_out, wrkmem) == LZO_E_OK) && (size_out < s->page_size)) { pd.flags = cpu_convert_to_target32(DUMP_DH_COMPRESSED_LZO, endian); pd.size = cpu_convert_to_target32(size_out, endian); ret = write_cache(&page_data, buf_out, size_out, false); 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_out) == SNAPPY_OK) && (size_out < s->page_size)) { pd.flags = cpu_convert_to_target32( DUMP_DH_COMPRESSED_SNAPPY, endian); pd.size = cpu_convert_to_target32(size_out, endian); ret = write_cache(&page_data, buf_out, size_out, false); if (ret < 0) { dump_error(s, "dump: failed to write page data.\n"); goto out; } #endif } else { /* * fall back to save in plaintext, size_out should be * assigned to s->page_size */ pd.flags = cpu_convert_to_target32(0, endian); size_out = s->page_size; pd.size = cpu_convert_to_target32(size_out, endian); ret = write_cache(&page_data, buf, s->page_size, false); if (ret < 0) { dump_error(s, "dump: failed to write page data.\n"); goto out; } } /* get and write page desc here */ pd.page_flags = cpu_convert_to_target64(0, endian); pd.offset = cpu_convert_to_target64(offset_data, endian); offset_data += size_out; ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false); if (ret < 0) { dump_error(s, "dump: failed to write page desc.\n"); goto out; } } } ret = write_cache(&page_desc, NULL, 0, true); if (ret < 0) { dump_error(s, "dump: failed to sync cache for page_desc.\n"); goto out; } ret = write_cache(&page_data, NULL, 0, true); 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; }