[PATCH 3/3] makedumpfile: Rewrite readpage_elf
Petr Tesarik
ptesarik at suse.cz
Mon Feb 29 10:55:14 PST 2016
Hi,
I just found a silly typo in my patch, see below.
On Wed, 10 Feb 2016 08:50:09 +0100
Petr Tesarik <ptesarik at suse.cz> wrote:
> The current code in readpage_elf (and readpage_elf_parallel) is extremely
> hard to follow. Additionally, it still does not cover all possible cases.
> For example, attempts to read outside of any ELF segment will end up with
> phys_start being 0, frac_head a negative number, interpreted as a large
> positive number by memset() and write past buffer end.
>
> Instead of trying to handle even more "corner cases", I rewrote the
> algorithm from scratch. The basic idea is simple: set a goal to fill the
> page buffer with data, then work towards that goal by:
>
> - filling holes with zeroes (see Note below),
> - p_filesz portions with file data and
> - remaining p_memsz portions again with zeroes.
>
> Repeat this method for each LOAD until the goal is achieved, or an error
> occurs. In most cases, the loop runs only once.
>
> Note: A "hole" is data at a physical address that is not covered by any
> ELF LOAD program header. In other words, the ELF file does not specify
> any data for such a hole (not even zeroes). So, why does makedumpfile
> fill them with zeroes? It's because makedumpfile works with page
> granularity (the compressed format does not even have a way to store
> a partial page), so if only part of a page is stored, a complete page
> must be provided to make this partial data accessible.
>
> Credits to Ivan Delalande <colona at arista.com> who first found the
> problem and wrote the original fix.
>
> Signed-off-by: Petr Tesarik <ptesarik at suse.com>
>
> ---
> elf_info.c | 28 +++++++
> elf_info.h | 1
> makedumpfile.c | 208 ++++++++++++++++++++++-----------------------------------
> 3 files changed, 110 insertions(+), 127 deletions(-)
>
>[...]
> --- a/makedumpfile.c
> +++ b/makedumpfile.c
> @@ -648,73 +648,51 @@ read_from_vmcore_parallel(int fd_memory,
> static int
> readpage_elf(unsigned long long paddr, void *bufptr)
> {
> - off_t offset1, offset2;
> - size_t size1, size2;
> - unsigned long long phys_start, phys_end, frac_head = 0;
> -
> - offset1 = paddr_to_offset(paddr);
> - offset2 = paddr_to_offset(paddr + info->page_size);
> - phys_start = paddr;
> - phys_end = paddr + info->page_size;
> -
> - /*
> - * Check the case phys_start isn't aligned by page size like below:
> - *
> - * phys_start
> - * = 0x40ffda7000
> - * |<-- frac_head -->|------------- PT_LOAD -------------
> - * ----+-----------------------+---------------------+----
> - * | pfn:N | pfn:N+1 | ...
> - * ----+-----------------------+---------------------+----
> - * |
> - * pfn_to_paddr(pfn:N) # page size = 16k
> - * = 0x40ffda4000
> - */
> - if (!offset1) {
> - phys_start = page_head_to_phys_start(paddr);
> - offset1 = paddr_to_offset(phys_start);
> - frac_head = phys_start - paddr;
> - memset(bufptr, 0, frac_head);
> - }
> -
> - /*
> - * Check the case phys_end isn't aligned by page size like the
> - * phys_start's case.
> - */
> - if (!offset2) {
> - phys_end = page_head_to_phys_end(paddr);
> - offset2 = paddr_to_offset(phys_end);
> - memset(bufptr + (phys_end - paddr), 0, info->page_size - (phys_end - paddr));
> - }
> + int idx;
> + off_t offset, size;
> + void *p, *endp;
> + unsigned long long phys_start, phys_end;
> +
> + p = bufptr;
> + endp = p + info->page_size;
> + while (p < endp) {
> + idx = closest_pt_load(paddr + (p - bufptr), endp - p);
> + if (idx < 0)
> + break;
> +
> + get_pt_load_extents(idx, &phys_start, &phys_end, &offset, &size);
> + if (phys_start > paddr + (p - bufptr)) {
> + memset(p, 0, phys_start - paddr);
> + p += phys_start - paddr;
> + }
>
> - /*
> - * Check the separated page on different PT_LOAD segments.
> - */
> - if (offset1 + (phys_end - phys_start) == offset2) {
> - size1 = phys_end - phys_start;
> - } else {
> - for (size1 = 1; size1 < info->page_size - frac_head; size1++) {
> - offset2 = paddr_to_offset(phys_start + size1);
> - if (offset1 + size1 != offset2)
> - break;
> + offset += paddr - phys_start;
> + if (size > paddr - phys_start) {
> + size -= paddr - phys_start;
> + if (size > endp - p)
> + size = endp - p;
> + if (!read_from_vmcore(offset, p, size)) {
> + ERRMSG("Can't read the dump memory(%s).\n",
> + info->name_memory);
> + return FALSE;
> + }
> + p += size;
> + }
> + if (p < endp) {
> + size = phys_end - paddr;
> + if (size > endp - p)
> + size = endp - p;
> + memset(p, 0, size);
> + p += size;
> }
> }
>
> - if(!read_from_vmcore(offset1, bufptr + frac_head, size1)) {
> - ERRMSG("Can't read the dump memory(%s).\n",
> - info->name_memory);
> + if (p == bufptr) {
> + ERRMSG("Attempt to read non-existent page at 0x%llx.\n",
> + paddr);
> return FALSE;
> - }
> -
> - if (size1 + frac_head != info->page_size) {
> - size2 = phys_end - (phys_start + size1);
> -
> - if(!read_from_vmcore(offset2, bufptr + frac_head + size1, size2)) {
> - ERRMSG("Can't read the dump memory(%s).\n",
> - info->name_memory);
> - return FALSE;
> - }
> - }
> + } else if (p < bufptr)
Here, of course, it should be:
} else if (p < endp)
> + memset(p, 0, endp - p);
>
> return TRUE;
> }
And same in the second hunk.
I'm sending a patch in a minute.
Petr Tesarik
More information about the kexec
mailing list