aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>2013-07-03 18:02:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-03 19:07:30 -0400
commit087350c9dcf1b38c597b31d7761f7366e2866e6b (patch)
tree9dddb06c41aba0af9347e3c08d9f64fa3f8c685e
parente69e9d4aee712a22665f008ae0550bb3d7c7f7c1 (diff)
vmcore: allocate ELF note segment in the 2nd kernel vmalloc memory
The reasons why we don't allocate ELF note segment in the 1st kernel (old memory) on page boundary is to keep backward compatibility for old kernels, and that if doing so, we waste not a little memory due to round-up operation to fit the memory to page boundary since most of the buffers are in per-cpu area. ELF notes are per-cpu, so total size of ELF note segments depends on number of CPUs. The current maximum number of CPUs on x86_64 is 5192, and there's already system with 4192 CPUs in SGI, where total size amounts to 1MB. This can be larger in the near future or possibly even now on another architecture that has larger size of note per a single cpu. Thus, to avoid the case where memory allocation for large block fails, we allocate vmcore objects on vmalloc memory. This patch adds elfnotes_buf and elfnotes_sz variables to keep pointer to the ELF note segment buffer and its size. There's no longer the vmcore object that corresponds to the ELF note segment in vmcore_list. Accordingly, read_vmcore() has new case for ELF note segment and set_vmcore_list_offsets_elf{64,32}() and other helper functions starts calculating offset from sum of size of ELF headers and size of ELF note segment. [akpm@linux-foundation.org: use min(), fix error-path vzalloc() leaks] Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com> Acked-by: Vivek Goyal <vgoyal@redhat.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp> Cc: Lisa Mitchell <lisa.mitchell@hp.com> Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/proc/vmcore.c359
1 files changed, 286 insertions, 73 deletions
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 78c87a1ac01a..9b9270eb0599 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -34,6 +34,9 @@ static char *elfcorebuf;
34static size_t elfcorebuf_sz; 34static size_t elfcorebuf_sz;
35static size_t elfcorebuf_sz_orig; 35static size_t elfcorebuf_sz_orig;
36 36
37static char *elfnotes_buf;
38static size_t elfnotes_sz;
39
37/* Total size of vmcore file. */ 40/* Total size of vmcore file. */
38static u64 vmcore_size; 41static u64 vmcore_size;
39 42
@@ -139,9 +142,7 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
139 142
140 /* Read ELF core header */ 143 /* Read ELF core header */
141 if (*fpos < elfcorebuf_sz) { 144 if (*fpos < elfcorebuf_sz) {
142 tsz = elfcorebuf_sz - *fpos; 145 tsz = min(elfcorebuf_sz - (size_t)*fpos, buflen);
143 if (buflen < tsz)
144 tsz = buflen;
145 if (copy_to_user(buffer, elfcorebuf + *fpos, tsz)) 146 if (copy_to_user(buffer, elfcorebuf + *fpos, tsz))
146 return -EFAULT; 147 return -EFAULT;
147 buflen -= tsz; 148 buflen -= tsz;
@@ -154,11 +155,27 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
154 return acc; 155 return acc;
155 } 156 }
156 157
158 /* Read Elf note segment */
159 if (*fpos < elfcorebuf_sz + elfnotes_sz) {
160 void *kaddr;
161
162 tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)*fpos, buflen);
163 kaddr = elfnotes_buf + *fpos - elfcorebuf_sz;
164 if (copy_to_user(buffer, kaddr, tsz))
165 return -EFAULT;
166 buflen -= tsz;
167 *fpos += tsz;
168 buffer += tsz;
169 acc += tsz;
170
171 /* leave now if filled buffer already */
172 if (buflen == 0)
173 return acc;
174 }
175
157 list_for_each_entry(m, &vmcore_list, list) { 176 list_for_each_entry(m, &vmcore_list, list) {
158 if (*fpos < m->offset + m->size) { 177 if (*fpos < m->offset + m->size) {
159 tsz = m->offset + m->size - *fpos; 178 tsz = min_t(size_t, m->offset + m->size - *fpos, buflen);
160 if (buflen < tsz)
161 tsz = buflen;
162 start = m->paddr + *fpos - m->offset; 179 start = m->paddr + *fpos - m->offset;
163 tmp = read_from_oldmem(buffer, tsz, &start, 1); 180 tmp = read_from_oldmem(buffer, tsz, &start, 1);
164 if (tmp < 0) 181 if (tmp < 0)
@@ -221,27 +238,27 @@ static u64 __init get_vmcore_size_elf32(char *elfptr, size_t elfsz)
221 return size; 238 return size;
222} 239}
223 240
224/* Merges all the PT_NOTE headers into one. */ 241/**
225static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz, 242 * update_note_header_size_elf64 - update p_memsz member of each PT_NOTE entry
226 struct list_head *vc_list) 243 *
244 * @ehdr_ptr: ELF header
245 *
246 * This function updates p_memsz member of each PT_NOTE entry in the
247 * program header table pointed to by @ehdr_ptr to real size of ELF
248 * note segment.
249 */
250static int __init update_note_header_size_elf64(const Elf64_Ehdr *ehdr_ptr)
227{ 251{
228 int i, nr_ptnote=0, rc=0; 252 int i, rc=0;
229 char *tmp; 253 Elf64_Phdr *phdr_ptr;
230 Elf64_Ehdr *ehdr_ptr;
231 Elf64_Phdr phdr, *phdr_ptr;
232 Elf64_Nhdr *nhdr_ptr; 254 Elf64_Nhdr *nhdr_ptr;
233 u64 phdr_sz = 0, note_off;
234 255
235 ehdr_ptr = (Elf64_Ehdr *)elfptr; 256 phdr_ptr = (Elf64_Phdr *)(ehdr_ptr + 1);
236 phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
237 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { 257 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
238 int j;
239 void *notes_section; 258 void *notes_section;
240 struct vmcore *new;
241 u64 offset, max_sz, sz, real_sz = 0; 259 u64 offset, max_sz, sz, real_sz = 0;
242 if (phdr_ptr->p_type != PT_NOTE) 260 if (phdr_ptr->p_type != PT_NOTE)
243 continue; 261 continue;
244 nr_ptnote++;
245 max_sz = phdr_ptr->p_memsz; 262 max_sz = phdr_ptr->p_memsz;
246 offset = phdr_ptr->p_offset; 263 offset = phdr_ptr->p_offset;
247 notes_section = kmalloc(max_sz, GFP_KERNEL); 264 notes_section = kmalloc(max_sz, GFP_KERNEL);
@@ -253,7 +270,7 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
253 return rc; 270 return rc;
254 } 271 }
255 nhdr_ptr = notes_section; 272 nhdr_ptr = notes_section;
256 for (j = 0; j < max_sz; j += sz) { 273 while (real_sz < max_sz) {
257 if (nhdr_ptr->n_namesz == 0) 274 if (nhdr_ptr->n_namesz == 0)
258 break; 275 break;
259 sz = sizeof(Elf64_Nhdr) + 276 sz = sizeof(Elf64_Nhdr) +
@@ -262,26 +279,122 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
262 real_sz += sz; 279 real_sz += sz;
263 nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz); 280 nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz);
264 } 281 }
265
266 /* Add this contiguous chunk of notes section to vmcore list.*/
267 new = get_new_element();
268 if (!new) {
269 kfree(notes_section);
270 return -ENOMEM;
271 }
272 new->paddr = phdr_ptr->p_offset;
273 new->size = real_sz;
274 list_add_tail(&new->list, vc_list);
275 phdr_sz += real_sz;
276 kfree(notes_section); 282 kfree(notes_section);
283 phdr_ptr->p_memsz = real_sz;
277 } 284 }
278 285
286 return 0;
287}
288
289/**
290 * get_note_number_and_size_elf64 - get the number of PT_NOTE program
291 * headers and sum of real size of their ELF note segment headers and
292 * data.
293 *
294 * @ehdr_ptr: ELF header
295 * @nr_ptnote: buffer for the number of PT_NOTE program headers
296 * @sz_ptnote: buffer for size of unique PT_NOTE program header
297 *
298 * This function is used to merge multiple PT_NOTE program headers
299 * into a unique single one. The resulting unique entry will have
300 * @sz_ptnote in its phdr->p_mem.
301 *
302 * It is assumed that program headers with PT_NOTE type pointed to by
303 * @ehdr_ptr has already been updated by update_note_header_size_elf64
304 * and each of PT_NOTE program headers has actual ELF note segment
305 * size in its p_memsz member.
306 */
307static int __init get_note_number_and_size_elf64(const Elf64_Ehdr *ehdr_ptr,
308 int *nr_ptnote, u64 *sz_ptnote)
309{
310 int i;
311 Elf64_Phdr *phdr_ptr;
312
313 *nr_ptnote = *sz_ptnote = 0;
314
315 phdr_ptr = (Elf64_Phdr *)(ehdr_ptr + 1);
316 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
317 if (phdr_ptr->p_type != PT_NOTE)
318 continue;
319 *nr_ptnote += 1;
320 *sz_ptnote += phdr_ptr->p_memsz;
321 }
322
323 return 0;
324}
325
326/**
327 * copy_notes_elf64 - copy ELF note segments in a given buffer
328 *
329 * @ehdr_ptr: ELF header
330 * @notes_buf: buffer into which ELF note segments are copied
331 *
332 * This function is used to copy ELF note segment in the 1st kernel
333 * into the buffer @notes_buf in the 2nd kernel. It is assumed that
334 * size of the buffer @notes_buf is equal to or larger than sum of the
335 * real ELF note segment headers and data.
336 *
337 * It is assumed that program headers with PT_NOTE type pointed to by
338 * @ehdr_ptr has already been updated by update_note_header_size_elf64
339 * and each of PT_NOTE program headers has actual ELF note segment
340 * size in its p_memsz member.
341 */
342static int __init copy_notes_elf64(const Elf64_Ehdr *ehdr_ptr, char *notes_buf)
343{
344 int i, rc=0;
345 Elf64_Phdr *phdr_ptr;
346
347 phdr_ptr = (Elf64_Phdr*)(ehdr_ptr + 1);
348
349 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
350 u64 offset;
351 if (phdr_ptr->p_type != PT_NOTE)
352 continue;
353 offset = phdr_ptr->p_offset;
354 rc = read_from_oldmem(notes_buf, phdr_ptr->p_memsz, &offset, 0);
355 if (rc < 0)
356 return rc;
357 notes_buf += phdr_ptr->p_memsz;
358 }
359
360 return 0;
361}
362
363/* Merges all the PT_NOTE headers into one. */
364static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
365 char **notes_buf, size_t *notes_sz)
366{
367 int i, nr_ptnote=0, rc=0;
368 char *tmp;
369 Elf64_Ehdr *ehdr_ptr;
370 Elf64_Phdr phdr;
371 u64 phdr_sz = 0, note_off;
372
373 ehdr_ptr = (Elf64_Ehdr *)elfptr;
374
375 rc = update_note_header_size_elf64(ehdr_ptr);
376 if (rc < 0)
377 return rc;
378
379 rc = get_note_number_and_size_elf64(ehdr_ptr, &nr_ptnote, &phdr_sz);
380 if (rc < 0)
381 return rc;
382
383 *notes_sz = roundup(phdr_sz, PAGE_SIZE);
384 *notes_buf = vzalloc(*notes_sz);
385 if (!*notes_buf)
386 return -ENOMEM;
387
388 rc = copy_notes_elf64(ehdr_ptr, *notes_buf);
389 if (rc < 0)
390 return rc;
391
279 /* Prepare merged PT_NOTE program header. */ 392 /* Prepare merged PT_NOTE program header. */
280 phdr.p_type = PT_NOTE; 393 phdr.p_type = PT_NOTE;
281 phdr.p_flags = 0; 394 phdr.p_flags = 0;
282 note_off = sizeof(Elf64_Ehdr) + 395 note_off = sizeof(Elf64_Ehdr) +
283 (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr); 396 (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr);
284 phdr.p_offset = note_off; 397 phdr.p_offset = roundup(note_off, PAGE_SIZE);
285 phdr.p_vaddr = phdr.p_paddr = 0; 398 phdr.p_vaddr = phdr.p_paddr = 0;
286 phdr.p_filesz = phdr.p_memsz = phdr_sz; 399 phdr.p_filesz = phdr.p_memsz = phdr_sz;
287 phdr.p_align = 0; 400 phdr.p_align = 0;
@@ -304,27 +417,27 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
304 return 0; 417 return 0;
305} 418}
306 419
307/* Merges all the PT_NOTE headers into one. */ 420/**
308static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz, 421 * update_note_header_size_elf32 - update p_memsz member of each PT_NOTE entry
309 struct list_head *vc_list) 422 *
423 * @ehdr_ptr: ELF header
424 *
425 * This function updates p_memsz member of each PT_NOTE entry in the
426 * program header table pointed to by @ehdr_ptr to real size of ELF
427 * note segment.
428 */
429static int __init update_note_header_size_elf32(const Elf32_Ehdr *ehdr_ptr)
310{ 430{
311 int i, nr_ptnote=0, rc=0; 431 int i, rc=0;
312 char *tmp; 432 Elf32_Phdr *phdr_ptr;
313 Elf32_Ehdr *ehdr_ptr;
314 Elf32_Phdr phdr, *phdr_ptr;
315 Elf32_Nhdr *nhdr_ptr; 433 Elf32_Nhdr *nhdr_ptr;
316 u64 phdr_sz = 0, note_off;
317 434
318 ehdr_ptr = (Elf32_Ehdr *)elfptr; 435 phdr_ptr = (Elf32_Phdr *)(ehdr_ptr + 1);
319 phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
320 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { 436 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
321 int j;
322 void *notes_section; 437 void *notes_section;
323 struct vmcore *new;
324 u64 offset, max_sz, sz, real_sz = 0; 438 u64 offset, max_sz, sz, real_sz = 0;
325 if (phdr_ptr->p_type != PT_NOTE) 439 if (phdr_ptr->p_type != PT_NOTE)
326 continue; 440 continue;
327 nr_ptnote++;
328 max_sz = phdr_ptr->p_memsz; 441 max_sz = phdr_ptr->p_memsz;
329 offset = phdr_ptr->p_offset; 442 offset = phdr_ptr->p_offset;
330 notes_section = kmalloc(max_sz, GFP_KERNEL); 443 notes_section = kmalloc(max_sz, GFP_KERNEL);
@@ -336,7 +449,7 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
336 return rc; 449 return rc;
337 } 450 }
338 nhdr_ptr = notes_section; 451 nhdr_ptr = notes_section;
339 for (j = 0; j < max_sz; j += sz) { 452 while (real_sz < max_sz) {
340 if (nhdr_ptr->n_namesz == 0) 453 if (nhdr_ptr->n_namesz == 0)
341 break; 454 break;
342 sz = sizeof(Elf32_Nhdr) + 455 sz = sizeof(Elf32_Nhdr) +
@@ -345,26 +458,122 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
345 real_sz += sz; 458 real_sz += sz;
346 nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz); 459 nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz);
347 } 460 }
348
349 /* Add this contiguous chunk of notes section to vmcore list.*/
350 new = get_new_element();
351 if (!new) {
352 kfree(notes_section);
353 return -ENOMEM;
354 }
355 new->paddr = phdr_ptr->p_offset;
356 new->size = real_sz;
357 list_add_tail(&new->list, vc_list);
358 phdr_sz += real_sz;
359 kfree(notes_section); 461 kfree(notes_section);
462 phdr_ptr->p_memsz = real_sz;
463 }
464
465 return 0;
466}
467
468/**
469 * get_note_number_and_size_elf32 - get the number of PT_NOTE program
470 * headers and sum of real size of their ELF note segment headers and
471 * data.
472 *
473 * @ehdr_ptr: ELF header
474 * @nr_ptnote: buffer for the number of PT_NOTE program headers
475 * @sz_ptnote: buffer for size of unique PT_NOTE program header
476 *
477 * This function is used to merge multiple PT_NOTE program headers
478 * into a unique single one. The resulting unique entry will have
479 * @sz_ptnote in its phdr->p_mem.
480 *
481 * It is assumed that program headers with PT_NOTE type pointed to by
482 * @ehdr_ptr has already been updated by update_note_header_size_elf32
483 * and each of PT_NOTE program headers has actual ELF note segment
484 * size in its p_memsz member.
485 */
486static int __init get_note_number_and_size_elf32(const Elf32_Ehdr *ehdr_ptr,
487 int *nr_ptnote, u64 *sz_ptnote)
488{
489 int i;
490 Elf32_Phdr *phdr_ptr;
491
492 *nr_ptnote = *sz_ptnote = 0;
493
494 phdr_ptr = (Elf32_Phdr *)(ehdr_ptr + 1);
495 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
496 if (phdr_ptr->p_type != PT_NOTE)
497 continue;
498 *nr_ptnote += 1;
499 *sz_ptnote += phdr_ptr->p_memsz;
360 } 500 }
361 501
502 return 0;
503}
504
505/**
506 * copy_notes_elf32 - copy ELF note segments in a given buffer
507 *
508 * @ehdr_ptr: ELF header
509 * @notes_buf: buffer into which ELF note segments are copied
510 *
511 * This function is used to copy ELF note segment in the 1st kernel
512 * into the buffer @notes_buf in the 2nd kernel. It is assumed that
513 * size of the buffer @notes_buf is equal to or larger than sum of the
514 * real ELF note segment headers and data.
515 *
516 * It is assumed that program headers with PT_NOTE type pointed to by
517 * @ehdr_ptr has already been updated by update_note_header_size_elf32
518 * and each of PT_NOTE program headers has actual ELF note segment
519 * size in its p_memsz member.
520 */
521static int __init copy_notes_elf32(const Elf32_Ehdr *ehdr_ptr, char *notes_buf)
522{
523 int i, rc=0;
524 Elf32_Phdr *phdr_ptr;
525
526 phdr_ptr = (Elf32_Phdr*)(ehdr_ptr + 1);
527
528 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
529 u64 offset;
530 if (phdr_ptr->p_type != PT_NOTE)
531 continue;
532 offset = phdr_ptr->p_offset;
533 rc = read_from_oldmem(notes_buf, phdr_ptr->p_memsz, &offset, 0);
534 if (rc < 0)
535 return rc;
536 notes_buf += phdr_ptr->p_memsz;
537 }
538
539 return 0;
540}
541
542/* Merges all the PT_NOTE headers into one. */
543static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
544 char **notes_buf, size_t *notes_sz)
545{
546 int i, nr_ptnote=0, rc=0;
547 char *tmp;
548 Elf32_Ehdr *ehdr_ptr;
549 Elf32_Phdr phdr;
550 u64 phdr_sz = 0, note_off;
551
552 ehdr_ptr = (Elf32_Ehdr *)elfptr;
553
554 rc = update_note_header_size_elf32(ehdr_ptr);
555 if (rc < 0)
556 return rc;
557
558 rc = get_note_number_and_size_elf32(ehdr_ptr, &nr_ptnote, &phdr_sz);
559 if (rc < 0)
560 return rc;
561
562 *notes_sz = roundup(phdr_sz, PAGE_SIZE);
563 *notes_buf = vzalloc(*notes_sz);
564 if (!*notes_buf)
565 return -ENOMEM;
566
567 rc = copy_notes_elf32(ehdr_ptr, *notes_buf);
568 if (rc < 0)
569 return rc;
570
362 /* Prepare merged PT_NOTE program header. */ 571 /* Prepare merged PT_NOTE program header. */
363 phdr.p_type = PT_NOTE; 572 phdr.p_type = PT_NOTE;
364 phdr.p_flags = 0; 573 phdr.p_flags = 0;
365 note_off = sizeof(Elf32_Ehdr) + 574 note_off = sizeof(Elf32_Ehdr) +
366 (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr); 575 (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr);
367 phdr.p_offset = note_off; 576 phdr.p_offset = roundup(note_off, PAGE_SIZE);
368 phdr.p_vaddr = phdr.p_paddr = 0; 577 phdr.p_vaddr = phdr.p_paddr = 0;
369 phdr.p_filesz = phdr.p_memsz = phdr_sz; 578 phdr.p_filesz = phdr.p_memsz = phdr_sz;
370 phdr.p_align = 0; 579 phdr.p_align = 0;
@@ -391,6 +600,7 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
391 * the new offset fields of exported program headers. */ 600 * the new offset fields of exported program headers. */
392static int __init process_ptload_program_headers_elf64(char *elfptr, 601static int __init process_ptload_program_headers_elf64(char *elfptr,
393 size_t elfsz, 602 size_t elfsz,
603 size_t elfnotes_sz,
394 struct list_head *vc_list) 604 struct list_head *vc_list)
395{ 605{
396 int i; 606 int i;
@@ -402,9 +612,8 @@ static int __init process_ptload_program_headers_elf64(char *elfptr,
402 ehdr_ptr = (Elf64_Ehdr *)elfptr; 612 ehdr_ptr = (Elf64_Ehdr *)elfptr;
403 phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */ 613 phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */
404 614
405 /* First program header is PT_NOTE header. */ 615 /* Skip Elf header, program headers and Elf note segment. */
406 vmcore_off = elfsz + 616 vmcore_off = elfsz + elfnotes_sz;
407 phdr_ptr->p_memsz; /* Note sections */
408 617
409 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { 618 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
410 u64 paddr, start, end, size; 619 u64 paddr, start, end, size;
@@ -434,6 +643,7 @@ static int __init process_ptload_program_headers_elf64(char *elfptr,
434 643
435static int __init process_ptload_program_headers_elf32(char *elfptr, 644static int __init process_ptload_program_headers_elf32(char *elfptr,
436 size_t elfsz, 645 size_t elfsz,
646 size_t elfnotes_sz,
437 struct list_head *vc_list) 647 struct list_head *vc_list)
438{ 648{
439 int i; 649 int i;
@@ -445,9 +655,8 @@ static int __init process_ptload_program_headers_elf32(char *elfptr,
445 ehdr_ptr = (Elf32_Ehdr *)elfptr; 655 ehdr_ptr = (Elf32_Ehdr *)elfptr;
446 phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */ 656 phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */
447 657
448 /* First program header is PT_NOTE header. */ 658 /* Skip Elf header, program headers and Elf note segment. */
449 vmcore_off = elfsz + 659 vmcore_off = elfsz + elfnotes_sz;
450 phdr_ptr->p_memsz; /* Note sections */
451 660
452 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { 661 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
453 u64 paddr, start, end, size; 662 u64 paddr, start, end, size;
@@ -476,14 +685,14 @@ static int __init process_ptload_program_headers_elf32(char *elfptr,
476} 685}
477 686
478/* Sets offset fields of vmcore elements. */ 687/* Sets offset fields of vmcore elements. */
479static void __init set_vmcore_list_offsets(size_t elfsz, 688static void __init set_vmcore_list_offsets(size_t elfsz, size_t elfnotes_sz,
480 struct list_head *vc_list) 689 struct list_head *vc_list)
481{ 690{
482 loff_t vmcore_off; 691 loff_t vmcore_off;
483 struct vmcore *m; 692 struct vmcore *m;
484 693
485 /* Skip Elf header and program headers. */ 694 /* Skip Elf header, program headers and Elf note segment. */
486 vmcore_off = elfsz; 695 vmcore_off = elfsz + elfnotes_sz;
487 696
488 list_for_each_entry(m, vc_list, list) { 697 list_for_each_entry(m, vc_list, list) {
489 m->offset = vmcore_off; 698 m->offset = vmcore_off;
@@ -495,6 +704,8 @@ static void free_elfcorebuf(void)
495{ 704{
496 free_pages((unsigned long)elfcorebuf, get_order(elfcorebuf_sz_orig)); 705 free_pages((unsigned long)elfcorebuf, get_order(elfcorebuf_sz_orig));
497 elfcorebuf = NULL; 706 elfcorebuf = NULL;
707 vfree(elfnotes_buf);
708 elfnotes_buf = NULL;
498} 709}
499 710
500static int __init parse_crash_elf64_headers(void) 711static int __init parse_crash_elf64_headers(void)
@@ -538,14 +749,15 @@ static int __init parse_crash_elf64_headers(void)
538 goto fail; 749 goto fail;
539 750
540 /* Merge all PT_NOTE headers into one. */ 751 /* Merge all PT_NOTE headers into one. */
541 rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, &vmcore_list); 752 rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz,
753 &elfnotes_buf, &elfnotes_sz);
542 if (rc) 754 if (rc)
543 goto fail; 755 goto fail;
544 rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz, 756 rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz,
545 &vmcore_list); 757 elfnotes_sz, &vmcore_list);
546 if (rc) 758 if (rc)
547 goto fail; 759 goto fail;
548 set_vmcore_list_offsets(elfcorebuf_sz, &vmcore_list); 760 set_vmcore_list_offsets(elfcorebuf_sz, elfnotes_sz, &vmcore_list);
549 return 0; 761 return 0;
550fail: 762fail:
551 free_elfcorebuf(); 763 free_elfcorebuf();
@@ -592,14 +804,15 @@ static int __init parse_crash_elf32_headers(void)
592 goto fail; 804 goto fail;
593 805
594 /* Merge all PT_NOTE headers into one. */ 806 /* Merge all PT_NOTE headers into one. */
595 rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, &vmcore_list); 807 rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz,
808 &elfnotes_buf, &elfnotes_sz);
596 if (rc) 809 if (rc)
597 goto fail; 810 goto fail;
598 rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz, 811 rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz,
599 &vmcore_list); 812 elfnotes_sz, &vmcore_list);
600 if (rc) 813 if (rc)
601 goto fail; 814 goto fail;
602 set_vmcore_list_offsets(elfcorebuf_sz, &vmcore_list); 815 set_vmcore_list_offsets(elfcorebuf_sz, elfnotes_sz, &vmcore_list);
603 return 0; 816 return 0;
604fail: 817fail:
605 free_elfcorebuf(); 818 free_elfcorebuf();