|
|
958e1b |
From 3555c9b0e05c410028022a1b1af34ad7a2e83e98 Mon Sep 17 00:00:00 2001
|
|
|
958e1b |
From: Laszlo Ersek <lersek@redhat.com>
|
|
|
958e1b |
Date: Fri, 7 Nov 2014 17:17:59 +0100
|
|
|
958e1b |
Subject: [PATCH 12/41] dump: add API to write dump_bitmap
|
|
|
958e1b |
|
|
|
958e1b |
Message-id: <1415380693-16593-13-git-send-email-lersek@redhat.com>
|
|
|
958e1b |
Patchwork-id: 62198
|
|
|
958e1b |
O-Subject: [RHEL-7.1 qemu-kvm PATCH 12/26] dump: add API to write dump_bitmap
|
|
|
958e1b |
Bugzilla: 1157798
|
|
|
958e1b |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
958e1b |
RH-Acked-by: Luiz Capitulino <lcapitulino@redhat.com>
|
|
|
958e1b |
RH-Acked-by: dgibson <dgibson@redhat.com>
|
|
|
958e1b |
|
|
|
958e1b |
From: qiaonuohan <qiaonuohan@cn.fujitsu.com>
|
|
|
958e1b |
|
|
|
958e1b |
functions are used to write 1st and 2nd dump_bitmap of kdump-compressed format,
|
|
|
958e1b |
which is used to indicate whether the corresponded page is existed in vmcore.
|
|
|
958e1b |
1st and 2nd dump_bitmap are same, because dump level is specified to 1 here.
|
|
|
958e1b |
|
|
|
958e1b |
Signed-off-by: Qiao Nuohan <qiaonuohan@cn.fujitsu.com>
|
|
|
958e1b |
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
958e1b |
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
|
|
|
958e1b |
(cherry picked from commit d0686c7291fe8f0210e7a666f80892fa71395510)
|
|
|
958e1b |
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
958e1b |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
958e1b |
---
|
|
|
958e1b |
dump.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
958e1b |
include/sysemu/dump.h | 2 +
|
|
|
958e1b |
2 files changed, 166 insertions(+)
|
|
|
958e1b |
|
|
|
958e1b |
diff --git a/dump.c b/dump.c
|
|
|
958e1b |
index 4d135fd..f416093 100644
|
|
|
958e1b |
--- a/dump.c
|
|
|
958e1b |
+++ b/dump.c
|
|
|
958e1b |
@@ -1007,6 +1007,170 @@ static int write_dump_header(DumpState *s)
|
|
|
958e1b |
}
|
|
|
958e1b |
}
|
|
|
958e1b |
|
|
|
958e1b |
+/*
|
|
|
958e1b |
+ * set dump_bitmap sequencely. the bit before last_pfn is not allowed to be
|
|
|
958e1b |
+ * rewritten, so if need to set the first bit, set last_pfn and pfn to 0.
|
|
|
958e1b |
+ * set_dump_bitmap will always leave the recently set bit un-sync. And setting
|
|
|
958e1b |
+ * (last bit + sizeof(buf) * 8) to 0 will do flushing the content in buf into
|
|
|
958e1b |
+ * vmcore, ie. synchronizing un-sync bit into vmcore.
|
|
|
958e1b |
+ */
|
|
|
958e1b |
+static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value,
|
|
|
958e1b |
+ uint8_t *buf, DumpState *s)
|
|
|
958e1b |
+{
|
|
|
958e1b |
+ off_t old_offset, new_offset;
|
|
|
958e1b |
+ off_t offset_bitmap1, offset_bitmap2;
|
|
|
958e1b |
+ uint32_t byte, bit;
|
|
|
958e1b |
+
|
|
|
958e1b |
+ /* should not set the previous place */
|
|
|
958e1b |
+ assert(last_pfn <= pfn);
|
|
|
958e1b |
+
|
|
|
958e1b |
+ /*
|
|
|
958e1b |
+ * if the bit needed to be set is not cached in buf, flush the data in buf
|
|
|
958e1b |
+ * to vmcore firstly.
|
|
|
958e1b |
+ * making new_offset be bigger than old_offset can also sync remained data
|
|
|
958e1b |
+ * into vmcore.
|
|
|
958e1b |
+ */
|
|
|
958e1b |
+ old_offset = BUFSIZE_BITMAP * (last_pfn / PFN_BUFBITMAP);
|
|
|
958e1b |
+ new_offset = BUFSIZE_BITMAP * (pfn / PFN_BUFBITMAP);
|
|
|
958e1b |
+
|
|
|
958e1b |
+ while (old_offset < new_offset) {
|
|
|
958e1b |
+ /* calculate the offset and write dump_bitmap */
|
|
|
958e1b |
+ offset_bitmap1 = s->offset_dump_bitmap + old_offset;
|
|
|
958e1b |
+ if (write_buffer(s->fd, offset_bitmap1, buf,
|
|
|
958e1b |
+ BUFSIZE_BITMAP) < 0) {
|
|
|
958e1b |
+ return -1;
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+
|
|
|
958e1b |
+ /* dump level 1 is chosen, so 1st and 2nd bitmap are same */
|
|
|
958e1b |
+ offset_bitmap2 = s->offset_dump_bitmap + s->len_dump_bitmap +
|
|
|
958e1b |
+ old_offset;
|
|
|
958e1b |
+ if (write_buffer(s->fd, offset_bitmap2, buf,
|
|
|
958e1b |
+ BUFSIZE_BITMAP) < 0) {
|
|
|
958e1b |
+ return -1;
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+
|
|
|
958e1b |
+ memset(buf, 0, BUFSIZE_BITMAP);
|
|
|
958e1b |
+ old_offset += BUFSIZE_BITMAP;
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+
|
|
|
958e1b |
+ /* get the exact place of the bit in the buf, and set it */
|
|
|
958e1b |
+ byte = (pfn % PFN_BUFBITMAP) / CHAR_BIT;
|
|
|
958e1b |
+ bit = (pfn % PFN_BUFBITMAP) % CHAR_BIT;
|
|
|
958e1b |
+ if (value) {
|
|
|
958e1b |
+ buf[byte] |= 1u << bit;
|
|
|
958e1b |
+ } else {
|
|
|
958e1b |
+ buf[byte] &= ~(1u << bit);
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+
|
|
|
958e1b |
+ return 0;
|
|
|
958e1b |
+}
|
|
|
958e1b |
+
|
|
|
958e1b |
+/*
|
|
|
958e1b |
+ * exam every page and return the page frame number and the address of the page.
|
|
|
958e1b |
+ * bufptr can be NULL. note: the blocks here is supposed to reflect guest-phys
|
|
|
958e1b |
+ * blocks, so block->target_start and block->target_end should be interal
|
|
|
958e1b |
+ * multiples of the target page size.
|
|
|
958e1b |
+ */
|
|
|
958e1b |
+static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
|
|
|
958e1b |
+ uint8_t **bufptr, DumpState *s)
|
|
|
958e1b |
+{
|
|
|
958e1b |
+ GuestPhysBlock *block = *blockptr;
|
|
|
958e1b |
+ hwaddr addr;
|
|
|
958e1b |
+ uint8_t *buf;
|
|
|
958e1b |
+
|
|
|
958e1b |
+ /* block == NULL means the start of the iteration */
|
|
|
958e1b |
+ if (!block) {
|
|
|
958e1b |
+ block = QTAILQ_FIRST(&s->guest_phys_blocks.head);
|
|
|
958e1b |
+ *blockptr = block;
|
|
|
958e1b |
+ assert(block->target_start % s->page_size == 0);
|
|
|
958e1b |
+ assert(block->target_end % s->page_size == 0);
|
|
|
958e1b |
+ *pfnptr = paddr_to_pfn(block->target_start, s->page_shift);
|
|
|
958e1b |
+ if (bufptr) {
|
|
|
958e1b |
+ *bufptr = block->host_addr;
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+ return true;
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+
|
|
|
958e1b |
+ *pfnptr = *pfnptr + 1;
|
|
|
958e1b |
+ addr = pfn_to_paddr(*pfnptr, s->page_shift);
|
|
|
958e1b |
+
|
|
|
958e1b |
+ if ((addr >= block->target_start) &&
|
|
|
958e1b |
+ (addr + s->page_size <= block->target_end)) {
|
|
|
958e1b |
+ buf = block->host_addr + (addr - block->target_start);
|
|
|
958e1b |
+ } else {
|
|
|
958e1b |
+ /* the next page is in the next block */
|
|
|
958e1b |
+ block = QTAILQ_NEXT(block, next);
|
|
|
958e1b |
+ *blockptr = block;
|
|
|
958e1b |
+ if (!block) {
|
|
|
958e1b |
+ return false;
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+ assert(block->target_start % s->page_size == 0);
|
|
|
958e1b |
+ assert(block->target_end % s->page_size == 0);
|
|
|
958e1b |
+ *pfnptr = paddr_to_pfn(block->target_start, s->page_shift);
|
|
|
958e1b |
+ buf = block->host_addr;
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+
|
|
|
958e1b |
+ if (bufptr) {
|
|
|
958e1b |
+ *bufptr = buf;
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+
|
|
|
958e1b |
+ return true;
|
|
|
958e1b |
+}
|
|
|
958e1b |
+
|
|
|
958e1b |
+static int write_dump_bitmap(DumpState *s)
|
|
|
958e1b |
+{
|
|
|
958e1b |
+ int ret = 0;
|
|
|
958e1b |
+ uint64_t last_pfn, pfn;
|
|
|
958e1b |
+ void *dump_bitmap_buf;
|
|
|
958e1b |
+ size_t num_dumpable;
|
|
|
958e1b |
+ GuestPhysBlock *block_iter = NULL;
|
|
|
958e1b |
+
|
|
|
958e1b |
+ /* dump_bitmap_buf is used to store dump_bitmap temporarily */
|
|
|
958e1b |
+ dump_bitmap_buf = g_malloc0(BUFSIZE_BITMAP);
|
|
|
958e1b |
+
|
|
|
958e1b |
+ num_dumpable = 0;
|
|
|
958e1b |
+ last_pfn = 0;
|
|
|
958e1b |
+
|
|
|
958e1b |
+ /*
|
|
|
958e1b |
+ * exam memory page by page, and set the bit in dump_bitmap corresponded
|
|
|
958e1b |
+ * to the existing page.
|
|
|
958e1b |
+ */
|
|
|
958e1b |
+ while (get_next_page(&block_iter, &pfn, NULL, s)) {
|
|
|
958e1b |
+ ret = set_dump_bitmap(last_pfn, pfn, true, dump_bitmap_buf, s);
|
|
|
958e1b |
+ if (ret < 0) {
|
|
|
958e1b |
+ dump_error(s, "dump: failed to set dump_bitmap.\n");
|
|
|
958e1b |
+ ret = -1;
|
|
|
958e1b |
+ goto out;
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+
|
|
|
958e1b |
+ last_pfn = pfn;
|
|
|
958e1b |
+ num_dumpable++;
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+
|
|
|
958e1b |
+ /*
|
|
|
958e1b |
+ * set_dump_bitmap will always leave the recently set bit un-sync. Here we
|
|
|
958e1b |
+ * set last_pfn + PFN_BUFBITMAP to 0 and those set but un-sync bit will be
|
|
|
958e1b |
+ * synchronized into vmcore.
|
|
|
958e1b |
+ */
|
|
|
958e1b |
+ if (num_dumpable > 0) {
|
|
|
958e1b |
+ ret = set_dump_bitmap(last_pfn, last_pfn + PFN_BUFBITMAP, false,
|
|
|
958e1b |
+ dump_bitmap_buf, s);
|
|
|
958e1b |
+ if (ret < 0) {
|
|
|
958e1b |
+ dump_error(s, "dump: failed to sync dump_bitmap.\n");
|
|
|
958e1b |
+ ret = -1;
|
|
|
958e1b |
+ goto out;
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+ }
|
|
|
958e1b |
+
|
|
|
958e1b |
+ /* number of dumpable pages that will be dumped later */
|
|
|
958e1b |
+ s->num_dumpable = num_dumpable;
|
|
|
958e1b |
+
|
|
|
958e1b |
+out:
|
|
|
958e1b |
+ g_free(dump_bitmap_buf);
|
|
|
958e1b |
+
|
|
|
958e1b |
+ return ret;
|
|
|
958e1b |
+}
|
|
|
958e1b |
+
|
|
|
958e1b |
static ram_addr_t get_start_block(DumpState *s)
|
|
|
958e1b |
{
|
|
|
958e1b |
GuestPhysBlock *block;
|
|
|
958e1b |
diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h
|
|
|
958e1b |
index dfee238..6d4d0bc 100644
|
|
|
958e1b |
--- a/include/sysemu/dump.h
|
|
|
958e1b |
+++ b/include/sysemu/dump.h
|
|
|
958e1b |
@@ -39,6 +39,8 @@
|
|
|
958e1b |
#define PHYS_BASE (0)
|
|
|
958e1b |
#define DUMP_LEVEL (1)
|
|
|
958e1b |
#define DISKDUMP_HEADER_BLOCKS (1)
|
|
|
958e1b |
+#define BUFSIZE_BITMAP (TARGET_PAGE_SIZE)
|
|
|
958e1b |
+#define PFN_BUFBITMAP (CHAR_BIT * BUFSIZE_BITMAP)
|
|
|
958e1b |
|
|
|
958e1b |
typedef struct ArchDumpInfo {
|
|
|
958e1b |
int d_machine; /* Architecture */
|
|
|
958e1b |
--
|
|
|
958e1b |
1.8.3.1
|
|
|
958e1b |
|