[PATCH v4] crash utility: fix max_mapnr issue on system has over 44-bit addressing
Jingbai Ma
jingbai.ma at hp.com
Wed Oct 16 06:16:10 EDT 2013
The patch will add support for new compressed dumpfile header_version 6.
This bug is posted here:
http://lists.infradead.org/pipermail/kexec/2013-September/009587.html
This patch will add 3 new fields in struct kdump_sub_header.
unsigned long long start_pfn_64; /* header_version 6 and later */
unsigned long long end_pfn_64; /* header_version 6 and later */
unsigned long long max_mapnr_64; /* header_version 6 and later */
The old max_mapnr, start_pfn and end_pfn are obsolete, but still be there
for compatibility purpose.
The corresponding patch for makedumpfile can be found here:
http://lists.infradead.org/pipermail/kexec/2013-October/009779.html
Changelog:
v4:
- Fix an invalid condition branch.
- Remove a piece of obsolete code.
- Display the original dh->max_mapnr as it exists in the dumpfile
header, regardless whether it is the obsolete version or not.
- Change notes for max_mapnr, start_pfn and end_pfn as obsolete.
v3:
- Fix a bug that failed to work with old split format kdumps.
v2:
- Rename max_mapnr in struct kdump_sub_header to max_mapnr_64.
- Change type of max_mapnr_64 from unsigned long to unsigned long long.
In x86 PAE mode on x86_32 kernel, the address may exceeds 44bit limit.
- Add start_pfn_64, end_pfn_64 for struct kdump_sub_header.
- Add a 64bit max_mapnr in struct diskdump_data. The max_mapnr_64 in
the sub-header only exists in compressed kdump file format, so can't
be used in diskdump file format.
- Merge a patch from Dave Anderson that fixed bitmap_len issue.
v1:
- http://lists.infradead.org/pipermail/kexec/2013-September/009663.html
Signed-off-by: Jingbai Ma <jingbai.ma at hp.com>
Tested-by: Lisa Mitchell <lisa.mitchell at hp.com>
---
diskdump.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++-------------
diskdump.h | 15 ++++++-
2 files changed, 108 insertions(+), 30 deletions(-)
diff --git a/diskdump.c b/diskdump.c
index 0819a3f..65e0210 100644
--- a/diskdump.c
+++ b/diskdump.c
@@ -40,11 +40,13 @@ struct diskdump_data {
struct disk_dump_sub_header *sub_header;
struct kdump_sub_header *sub_header_kdump;
+ unsigned long long max_mapnr; /* 64bit max_mapnr */
+
size_t data_offset;
int block_size;
int block_shift;
char *bitmap;
- int bitmap_len;
+ off_t bitmap_len;
char *dumpable_bitmap;
int byte, bit;
char *compressed_page; /* copy of compressed page data */
@@ -170,9 +172,9 @@ add_diskdump_data(char* name)
dd->filename = name;
if (CRASHDEBUG(1))
- fprintf(fp, "%s: start_pfn=%lu, end_pfn=%lu\n", name,
- dd->sub_header_kdump->start_pfn,
- dd->sub_header_kdump->end_pfn);
+ fprintf(fp, "%s: start_pfn=%llu, end_pfn=%llu\n", name,
+ dd->sub_header_kdump->start_pfn_64,
+ dd->sub_header_kdump->end_pfn_64);
}
static void
@@ -199,13 +201,13 @@ get_bit(char *map, int byte, int bit)
}
static inline int
-page_is_ram(unsigned int nr)
+page_is_ram(unsigned long nr)
{
return get_bit(dd->bitmap, nr >> 3, nr & 7);
}
static inline int
-page_is_dumpable(unsigned int nr)
+page_is_dumpable(unsigned long nr)
{
return dd->dumpable_bitmap[nr>>3] & (1 << (nr & 7));
}
@@ -214,7 +216,7 @@ static inline int
dump_is_partial(const struct disk_dump_header *header)
{
return header->bitmap_blocks >=
- divideup(divideup(header->max_mapnr, 8), dd->block_size) * 2;
+ divideup(divideup(dd->max_mapnr, 8), dd->block_size) * 2;
}
static int
@@ -321,6 +323,9 @@ x86_process_elf_notes(void *note_ptr, unsigned long size_note)
* [40] unsigned long size_note; / header_version 4 and later /
* [44] off_t offset_eraseinfo; / header_version 5 and later /
* [52] unsigned long size_eraseinfo; / header_version 5 and later /
+ * [56] unsigned long long start_pfn_64; / header_version 6 and later /
+ * [64] unsigned long long end_pfn_64; / header_version 6 and later /
+ * [72] unsigned long long max_mapnr_64; / header_version 6 and later /
* };
*
* But when compiled on an ARM processor, each 64-bit "off_t" would be pushed
@@ -337,7 +342,10 @@ x86_process_elf_notes(void *note_ptr, unsigned long size_note)
* [40] off_t offset_note; / header_version 4 and later /
* [48] unsigned long size_note; / header_version 4 and later /
* [56] off_t offset_eraseinfo; / header_version 5 and later /
- * [62] unsigned long size_eraseinfo; / header_version 5 and later /
+ * [64] unsigned long size_eraseinfo; / header_version 5 and later /
+ * [72] unsigned long long start_pfn_64; / header_version 6 and later /
+ * [80] unsigned long long end_pfn_64; / header_version 6 and later /
+ * [88] unsigned long long max_mapnr_64; / header_version 6 and later /
* };
*
*/
@@ -357,6 +365,10 @@ struct kdump_sub_header_ARM_target {
int pad3;
off_t offset_eraseinfo; /* header_version 5 and later */
unsigned long size_eraseinfo; /* header_version 5 and later */
+ int pad4;
+ unsigned long long start_pfn_64; /* header_version 6 and later */
+ unsigned long long end_pfn_64; /* header_version 6 and later */
+ unsigned long long max_mapnr_64; /* header_version 6 and later */
};
static void
@@ -380,6 +392,15 @@ arm_kdump_header_adjust(int header_version)
kdsh->offset_eraseinfo = kdsh_ARM_target->offset_eraseinfo;
kdsh->size_eraseinfo = kdsh_ARM_target->size_eraseinfo;
}
+ if (header_version >= 6) {
+ kdsh->start_pfn_64 = kdsh_ARM_target->start_pfn_64;
+ kdsh->end_pfn_64 = kdsh_ARM_target->end_pfn_64;
+ kdsh->max_mapnr_64 = kdsh_ARM_target->map_mapnr_64;
+ } else {
+ kdsh->start_pfn_64 = kdsh_ARM_target->start_pfn;
+ kdsh->end_pfn_64 = kdsh_ARM_target->end_pfn;
+ kdsh->max_mapnr_64 = dd->map_mapnr;
+ }
}
#endif /* __i386__ && ARM */
@@ -390,7 +411,10 @@ read_dump_header(char *file)
struct disk_dump_sub_header *sub_header = NULL;
struct kdump_sub_header *sub_header_kdump = NULL;
size_t size;
- int bitmap_len;
+ off_t bitmap_len;
+ char *bufptr;
+ size_t len;
+ size_t bytes_read;
int block_size = (int)sysconf(_SC_PAGESIZE);
off_t offset;
const off_t failed = (off_t)-1;
@@ -516,6 +540,13 @@ restart:
}
}
dd->sub_header = sub_header;
+
+ /* the 64bit max_mapnr only exists in sub-header of compressed
+ * kdump file, if it's not a compressed kdump file, we have to
+ * use the old 32bit max_mapnr in dumpfile header.
+ * max_mapnr may be truncated here.
+ */
+ dd->max_mapnr = header->max_mapnr;
} else if (KDUMP_CMPRS_VALID()) {
if ((sub_header_kdump = malloc(block_size)) == NULL)
error(FATAL, "compressed kdump: cannot malloc sub_header_kdump buffer\n");
@@ -540,8 +571,20 @@ restart:
#if defined(__i386__) && defined(ARM)
arm_kdump_header_adjust(header->header_version);
#endif
+ /* use 64bit max_mapnr in compressed kdump file sub-header */
+ if (header->header_version >= 6)
+ dd->max_mapnr = dd->sub_header_kdump->max_mapnr_64;
+ else {
+ dd->sub_header_kdump->start_pfn_64
+ = dd->sub_header_kdump->start_pfn;
+ dd->sub_header_kdump->end_pfn_64
+ = dd->sub_header_kdump->end_pfn;
+ }
}
+ if (header->header_version < 6)
+ dd->max_mapnr = header->max_mapnr;
+
/* read memory bitmap */
bitmap_len = block_size * header->bitmap_blocks;
dd->bitmap_len = bitmap_len;
@@ -571,10 +614,18 @@ restart:
DISKDUMP_VALID() ? "diskdump" : "compressed kdump");
goto err;
}
- if (read(dd->dfd, dd->bitmap, bitmap_len) < bitmap_len) {
- error(INFO, "%s: cannot read memory bitmap\n",
- DISKDUMP_VALID() ? "diskdump" : "compressed kdump");
- goto err;
+ bufptr = dd->bitmap;
+ len = bitmap_len;
+ while (len) {
+ bytes_read = read(dd->dfd, bufptr, len);
+ if (bytes_read < 0) {
+ error(INFO, "%s: cannot read memory bitmap\n",
+ DISKDUMP_VALID() ? "diskdump"
+ : "compressed kdump");
+ goto err;
+ }
+ len -= bytes_read;
+ bufptr += bytes_read;
}
}
@@ -679,13 +730,13 @@ restart:
}
if (!is_split) {
- max_sect_len = divideup(header->max_mapnr, BITMAP_SECT_LEN);
+ max_sect_len = divideup(dd->max_mapnr, BITMAP_SECT_LEN);
pfn = 0;
dd->filename = file;
}
else {
- ulong start = sub_header_kdump->start_pfn;
- ulong end = sub_header_kdump->end_pfn;
+ unsigned long long start = sub_header_kdump->start_pfn_64;
+ unsigned long long end = sub_header_kdump->end_pfn_64;
max_sect_len = divideup(end - start + 1, BITMAP_SECT_LEN);
pfn = start;
}
@@ -727,8 +778,9 @@ pfn_to_pos(ulong pfn)
ulong p1, p2;
if (KDUMP_SPLIT()) {
- p1 = pfn - dd->sub_header_kdump->start_pfn;
- p2 = round(p1, BITMAP_SECT_LEN) + dd->sub_header_kdump->start_pfn;
+ p1 = pfn - dd->sub_header_kdump->start_pfn_64;
+ p2 = round(p1, BITMAP_SECT_LEN)
+ + dd->sub_header_kdump->start_pfn_64;
}
else {
p1 = pfn;
@@ -1034,12 +1086,12 @@ read_diskdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr)
if (KDUMP_SPLIT()) {
/* Find proper dd */
int i;
- unsigned long start_pfn;
- unsigned long end_pfn;
+ unsigned long long start_pfn;
+ unsigned long long end_pfn;
for (i=0; i<num_dumpfiles; i++) {
- start_pfn = dd_list[i]->sub_header_kdump->start_pfn;
- end_pfn = dd_list[i]->sub_header_kdump->end_pfn;
+ start_pfn = dd_list[i]->sub_header_kdump->start_pfn_64;
+ end_pfn = dd_list[i]->sub_header_kdump->end_pfn_64;
if ((pfn >= start_pfn) && (pfn <= end_pfn)) {
dd = dd_list[i];
break;
@@ -1058,14 +1110,14 @@ read_diskdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr)
curpaddr = paddr & ~((physaddr_t)(dd->block_size-1));
page_offset = paddr & ((physaddr_t)(dd->block_size-1));
- if ((pfn >= dd->header->max_mapnr) || !page_is_ram(pfn)) {
+ if ((pfn >= dd->max_mapnr) || !page_is_ram(pfn)) {
if (CRASHDEBUG(8)) {
fprintf(fp, "read_diskdump: SEEK_ERROR: "
"paddr/pfn: %llx/%lx ",
(ulonglong)paddr, pfn);
- if (pfn >= dd->header->max_mapnr)
- fprintf(fp, "max_mapnr: %x\n",
- dd->header->max_mapnr);
+ if (pfn >= dd->max_mapnr)
+ fprintf(fp, "max_mapnr: %llx\n",
+ dd->max_mapnr);
else
fprintf(fp, "!page_is_ram\n");
}
@@ -1662,6 +1714,23 @@ __diskdump_memory_dump(FILE *fp)
dump_eraseinfo(fp);
}
}
+ if (dh->header_version >= 6) {
+ fprintf(fp, " start_pfn_64: ");
+ if (KDUMP_SPLIT())
+ fprintf(fp, "%lld (0x%llx)\n",
+ kdsh->start_pfn_64, kdsh->start_pfn_64);
+ else
+ fprintf(fp, "(unused)\n");
+ fprintf(fp, " end_pfn_64: ");
+ if (KDUMP_SPLIT())
+ fprintf(fp, "%lld (0x%llx)\n",
+ kdsh->end_pfn_64, kdsh->end_pfn_64);
+ else
+ fprintf(fp, "(unused)\n");
+
+ fprintf(fp, " max_mapnr_64: %llu (0x%llx)\n",
+ kdsh->max_mapnr_64, kdsh->max_mapnr_64);
+ }
fprintf(fp, "\n");
} else
fprintf(fp, "(n/a)\n\n");
@@ -1670,7 +1739,7 @@ __diskdump_memory_dump(FILE *fp)
fprintf(fp, " block_size: %d\n", dd->block_size);
fprintf(fp, " block_shift: %d\n", dd->block_shift);
fprintf(fp, " bitmap: %lx\n", (ulong)dd->bitmap);
- fprintf(fp, " bitmap_len: %d\n", dd->bitmap_len);
+ fprintf(fp, " bitmap_len: %ld\n", dd->bitmap_len);
fprintf(fp, " dumpable_bitmap: %lx\n", (ulong)dd->dumpable_bitmap);
fprintf(fp, " byte: %d\n", dd->byte);
fprintf(fp, " bit: %d\n", dd->bit);
diff --git a/diskdump.h b/diskdump.h
index 9ab10b6..88c5be9 100644
--- a/diskdump.h
+++ b/diskdump.h
@@ -42,7 +42,9 @@ struct disk_dump_header {
header in blocks */
unsigned int bitmap_blocks; /* Size of Memory bitmap in
block */
- unsigned int max_mapnr; /* = max_mapnr */
+ unsigned int max_mapnr; /* = max_mapnr, OBSOLETE!
+ 32bit only, full 64bit
+ in sub header. */
unsigned int total_ram_blocks;/* Number of blocks should be
written */
unsigned int device_blocks; /* Number of total blocks in
@@ -61,14 +63,21 @@ struct kdump_sub_header {
unsigned long phys_base;
int dump_level; /* header_version 1 and later */
int split; /* header_version 2 and later */
- unsigned long start_pfn; /* header_version 2 and later */
- unsigned long end_pfn; /* header_version 2 and later */
+ unsigned long start_pfn; /* header_version 2 and later,
+ OBSOLETE! 32bit only, full 64bit
+ in start_pfn_64. */
+ unsigned long end_pfn; /* header_version 2 and later,
+ OBSOLETE! 32bit only, full 64bit
+ in end_pfn_64. */
off_t offset_vmcoreinfo; /* header_version 3 and later */
unsigned long size_vmcoreinfo; /* header_version 3 and later */
off_t offset_note; /* header_version 4 and later */
unsigned long size_note; /* header_version 4 and later */
off_t offset_eraseinfo; /* header_version 5 and later */
unsigned long size_eraseinfo; /* header_version 5 and later */
+ unsigned long long start_pfn_64; /* header_version 6 and later */
+ unsigned long long end_pfn_64; /* header_version 6 and later */
+ unsigned long long max_mapnr_64; /* header_version 6 and later */
};
/* page flags */
More information about the kexec
mailing list