diff options
author | Frank Munzert <munzert@de.ibm.com> | 2008-07-17 11:16:40 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-07-17 11:22:07 -0400 |
commit | 12e0c95e0ca99f633c9d9f90773037eb178685ad (patch) | |
tree | 2bce91b7fb423c51074574d77f53a74ab2243291 /drivers/s390/char | |
parent | 33af79d12e0fa25545d49e86afc67ea8ad5f2f40 (diff) |
[S390] zfcpdump: Make SCSI disk dump tool recognize storage holes
The kernel part of zfcpdump establishes a new debugfs file zcore/memmap
which exports information on memory layout (start address and length of each
memory chunk) to its userspace counterpart.
Signed-off-by: Frank Munzert <munzert@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/char')
-rw-r--r-- | drivers/s390/char/zcore.c | 101 |
1 files changed, 94 insertions, 7 deletions
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 047dd92ae804..7fd84be11931 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c | |||
@@ -29,6 +29,7 @@ | |||
29 | 29 | ||
30 | #define TO_USER 0 | 30 | #define TO_USER 0 |
31 | #define TO_KERNEL 1 | 31 | #define TO_KERNEL 1 |
32 | #define CHUNK_INFO_SIZE 34 /* 2 16-byte char, each followed by blank */ | ||
32 | 33 | ||
33 | enum arch_id { | 34 | enum arch_id { |
34 | ARCH_S390 = 0, | 35 | ARCH_S390 = 0, |
@@ -51,6 +52,7 @@ static struct debug_info *zcore_dbf; | |||
51 | static int hsa_available; | 52 | static int hsa_available; |
52 | static struct dentry *zcore_dir; | 53 | static struct dentry *zcore_dir; |
53 | static struct dentry *zcore_file; | 54 | static struct dentry *zcore_file; |
55 | static struct dentry *zcore_memmap_file; | ||
54 | 56 | ||
55 | /* | 57 | /* |
56 | * Copy memory from HSA to kernel or user memory (not reentrant): | 58 | * Copy memory from HSA to kernel or user memory (not reentrant): |
@@ -476,6 +478,54 @@ static const struct file_operations zcore_fops = { | |||
476 | .release = zcore_release, | 478 | .release = zcore_release, |
477 | }; | 479 | }; |
478 | 480 | ||
481 | static ssize_t zcore_memmap_read(struct file *filp, char __user *buf, | ||
482 | size_t count, loff_t *ppos) | ||
483 | { | ||
484 | return simple_read_from_buffer(buf, count, ppos, filp->private_data, | ||
485 | MEMORY_CHUNKS * CHUNK_INFO_SIZE); | ||
486 | } | ||
487 | |||
488 | static int zcore_memmap_open(struct inode *inode, struct file *filp) | ||
489 | { | ||
490 | int i; | ||
491 | char *buf; | ||
492 | struct mem_chunk *chunk_array; | ||
493 | |||
494 | chunk_array = kzalloc(MEMORY_CHUNKS * sizeof(struct mem_chunk), | ||
495 | GFP_KERNEL); | ||
496 | if (!chunk_array) | ||
497 | return -ENOMEM; | ||
498 | detect_memory_layout(chunk_array); | ||
499 | buf = kzalloc(MEMORY_CHUNKS * CHUNK_INFO_SIZE, GFP_KERNEL); | ||
500 | if (!buf) { | ||
501 | kfree(chunk_array); | ||
502 | return -ENOMEM; | ||
503 | } | ||
504 | for (i = 0; i < MEMORY_CHUNKS; i++) { | ||
505 | sprintf(buf + (i * CHUNK_INFO_SIZE), "%016llx %016llx ", | ||
506 | (unsigned long long) chunk_array[i].addr, | ||
507 | (unsigned long long) chunk_array[i].size); | ||
508 | if (chunk_array[i].size == 0) | ||
509 | break; | ||
510 | } | ||
511 | kfree(chunk_array); | ||
512 | filp->private_data = buf; | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static int zcore_memmap_release(struct inode *inode, struct file *filp) | ||
517 | { | ||
518 | kfree(filp->private_data); | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static const struct file_operations zcore_memmap_fops = { | ||
523 | .owner = THIS_MODULE, | ||
524 | .read = zcore_memmap_read, | ||
525 | .open = zcore_memmap_open, | ||
526 | .release = zcore_memmap_release, | ||
527 | }; | ||
528 | |||
479 | 529 | ||
480 | static void __init set_s390_lc_mask(union save_area *map) | 530 | static void __init set_s390_lc_mask(union save_area *map) |
481 | { | 531 | { |
@@ -554,18 +604,44 @@ static int __init check_sdias(void) | |||
554 | return 0; | 604 | return 0; |
555 | } | 605 | } |
556 | 606 | ||
557 | static void __init zcore_header_init(int arch, struct zcore_header *hdr) | 607 | static int __init get_mem_size(unsigned long *mem) |
608 | { | ||
609 | int i; | ||
610 | struct mem_chunk *chunk_array; | ||
611 | |||
612 | chunk_array = kzalloc(MEMORY_CHUNKS * sizeof(struct mem_chunk), | ||
613 | GFP_KERNEL); | ||
614 | if (!chunk_array) | ||
615 | return -ENOMEM; | ||
616 | detect_memory_layout(chunk_array); | ||
617 | for (i = 0; i < MEMORY_CHUNKS; i++) { | ||
618 | if (chunk_array[i].size == 0) | ||
619 | break; | ||
620 | *mem += chunk_array[i].size; | ||
621 | } | ||
622 | kfree(chunk_array); | ||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | static int __init zcore_header_init(int arch, struct zcore_header *hdr) | ||
558 | { | 627 | { |
628 | int rc; | ||
629 | unsigned long memory = 0; | ||
630 | |||
559 | if (arch == ARCH_S390X) | 631 | if (arch == ARCH_S390X) |
560 | hdr->arch_id = DUMP_ARCH_S390X; | 632 | hdr->arch_id = DUMP_ARCH_S390X; |
561 | else | 633 | else |
562 | hdr->arch_id = DUMP_ARCH_S390; | 634 | hdr->arch_id = DUMP_ARCH_S390; |
563 | hdr->mem_size = sys_info.mem_size; | 635 | rc = get_mem_size(&memory); |
564 | hdr->rmem_size = sys_info.mem_size; | 636 | if (rc) |
637 | return rc; | ||
638 | hdr->mem_size = memory; | ||
639 | hdr->rmem_size = memory; | ||
565 | hdr->mem_end = sys_info.mem_size; | 640 | hdr->mem_end = sys_info.mem_size; |
566 | hdr->num_pages = sys_info.mem_size / PAGE_SIZE; | 641 | hdr->num_pages = memory / PAGE_SIZE; |
567 | hdr->tod = get_clock(); | 642 | hdr->tod = get_clock(); |
568 | get_cpu_id(&hdr->cpu_id); | 643 | get_cpu_id(&hdr->cpu_id); |
644 | return 0; | ||
569 | } | 645 | } |
570 | 646 | ||
571 | static int __init zcore_init(void) | 647 | static int __init zcore_init(void) |
@@ -608,7 +684,9 @@ static int __init zcore_init(void) | |||
608 | if (rc) | 684 | if (rc) |
609 | goto fail; | 685 | goto fail; |
610 | 686 | ||
611 | zcore_header_init(arch, &zcore_header); | 687 | rc = zcore_header_init(arch, &zcore_header); |
688 | if (rc) | ||
689 | goto fail; | ||
612 | 690 | ||
613 | zcore_dir = debugfs_create_dir("zcore" , NULL); | 691 | zcore_dir = debugfs_create_dir("zcore" , NULL); |
614 | if (!zcore_dir) { | 692 | if (!zcore_dir) { |
@@ -618,13 +696,22 @@ static int __init zcore_init(void) | |||
618 | zcore_file = debugfs_create_file("mem", S_IRUSR, zcore_dir, NULL, | 696 | zcore_file = debugfs_create_file("mem", S_IRUSR, zcore_dir, NULL, |
619 | &zcore_fops); | 697 | &zcore_fops); |
620 | if (!zcore_file) { | 698 | if (!zcore_file) { |
621 | debugfs_remove(zcore_dir); | ||
622 | rc = -ENOMEM; | 699 | rc = -ENOMEM; |
623 | goto fail; | 700 | goto fail_dir; |
701 | } | ||
702 | zcore_memmap_file = debugfs_create_file("memmap", S_IRUSR, zcore_dir, | ||
703 | NULL, &zcore_memmap_fops); | ||
704 | if (!zcore_memmap_file) { | ||
705 | rc = -ENOMEM; | ||
706 | goto fail_file; | ||
624 | } | 707 | } |
625 | hsa_available = 1; | 708 | hsa_available = 1; |
626 | return 0; | 709 | return 0; |
627 | 710 | ||
711 | fail_file: | ||
712 | debugfs_remove(zcore_file); | ||
713 | fail_dir: | ||
714 | debugfs_remove(zcore_dir); | ||
628 | fail: | 715 | fail: |
629 | diag308(DIAG308_REL_HSA, NULL); | 716 | diag308(DIAG308_REL_HSA, NULL); |
630 | return rc; | 717 | return rc; |