aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>2009-09-22 19:45:48 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:41 -0400
commit3089aa1b0c07fb7c48f9829c619f50198307789d (patch)
tree63677c773c559458ba301bd448ecce6e007b6742
parent908eedc6168bd92e89f90d89fa389065a36358fa (diff)
kcore: use registerd physmem information
For /proc/kcore, each arch registers its memory range by kclist_add(). In usual, - range of physical memory - range of vmalloc area - text, etc... are registered but "range of physical memory" has some troubles. It doesn't updated at memory hotplug and it tend to include unnecessary memory holes. Now, /proc/iomem (kernel/resource.c) includes required physical memory range information and it's properly updated at memory hotplug. Then, it's good to avoid using its own code(duplicating information) and to rebuild kclist for physical memory based on /proc/iomem. Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Signed-off-by: Jiri Slaby <jirislaby@gmail.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: WANG Cong <xiyou.wangcong@gmail.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/ia64/mm/init.c3
-rw-r--r--arch/mips/mm/init.c2
-rw-r--r--arch/powerpc/mm/init_32.c32
-rw-r--r--arch/powerpc/mm/init_64.c26
-rw-r--r--arch/sh/mm/init.c4
-rw-r--r--arch/x86/mm/init_32.c4
-rw-r--r--arch/x86/mm/init_64.c3
-rw-r--r--fs/proc/kcore.c179
8 files changed, 168 insertions, 85 deletions
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 3f95ea1d6fb6..1857766a63c1 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -617,7 +617,6 @@ mem_init (void)
617 long reserved_pages, codesize, datasize, initsize; 617 long reserved_pages, codesize, datasize, initsize;
618 pg_data_t *pgdat; 618 pg_data_t *pgdat;
619 int i; 619 int i;
620 static struct kcore_list kcore_mem;
621 620
622 BUG_ON(PTRS_PER_PGD * sizeof(pgd_t) != PAGE_SIZE); 621 BUG_ON(PTRS_PER_PGD * sizeof(pgd_t) != PAGE_SIZE);
623 BUG_ON(PTRS_PER_PMD * sizeof(pmd_t) != PAGE_SIZE); 622 BUG_ON(PTRS_PER_PMD * sizeof(pmd_t) != PAGE_SIZE);
@@ -639,8 +638,6 @@ mem_init (void)
639 638
640 high_memory = __va(max_low_pfn * PAGE_SIZE); 639 high_memory = __va(max_low_pfn * PAGE_SIZE);
641 640
642 kclist_add(&kcore_mem, __va(0), max_low_pfn * PAGE_SIZE, KCORE_RAM);
643
644 for_each_online_pgdat(pgdat) 641 for_each_online_pgdat(pgdat)
645 if (pgdat->bdata->node_bootmem_map) 642 if (pgdat->bdata->node_bootmem_map)
646 totalram_pages += free_all_bootmem_node(pgdat); 643 totalram_pages += free_all_bootmem_node(pgdat);
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 4a83da499e2d..15aa1902a788 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -352,7 +352,6 @@ void __init paging_init(void)
352 free_area_init_nodes(max_zone_pfns); 352 free_area_init_nodes(max_zone_pfns);
353} 353}
354 354
355static struct kcore_list kcore_mem;
356#ifdef CONFIG_64BIT 355#ifdef CONFIG_64BIT
357static struct kcore_list kcore_kseg0; 356static struct kcore_list kcore_kseg0;
358#endif 357#endif
@@ -412,7 +411,6 @@ void __init mem_init(void)
412 kclist_add(&kcore_kseg0, (void *) CKSEG0, 411 kclist_add(&kcore_kseg0, (void *) CKSEG0,
413 0x80000000 - 4, KCORE_TEXT); 412 0x80000000 - 4, KCORE_TEXT);
414#endif 413#endif
415 kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT, KCORE_RAM);
416 414
417 printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, " 415 printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
418 "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n", 416 "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n",
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 38a450d16b27..9ddcfb4dc139 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -242,35 +242,3 @@ void free_initrd_mem(unsigned long start, unsigned long end)
242} 242}
243#endif 243#endif
244 244
245#ifdef CONFIG_PROC_KCORE
246
247static int __init setup_kcore(void)
248{
249 int i;
250
251 for (i = 0; i < lmb.memory.cnt; i++) {
252 unsigned long base;
253 unsigned long size;
254 struct kcore_list *kcore_mem;
255
256 base = lmb.memory.region[i].base;
257 size = lmb.memory.region[i].size;
258
259 kcore_mem = kmalloc(sizeof(struct kcore_list), GFP_ATOMIC);
260 if (!kcore_mem)
261 panic("%s: kmalloc failed\n", __func__);
262
263 /* must stay under 32 bits */
264 if ( 0xfffffffful - (unsigned long)__va(base) < size) {
265 size = 0xfffffffful - (unsigned long)(__va(base));
266 printk(KERN_DEBUG "setup_kcore: restrict size=%lx\n",
267 size);
268 }
269
270 kclist_add(kcore_mem, __va(base), size, KCORE_RAM);
271 }
272
273 return 0;
274}
275module_init(setup_kcore);
276#endif
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 87ef492a1a5d..335c578b9cc3 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -109,32 +109,6 @@ void free_initrd_mem(unsigned long start, unsigned long end)
109} 109}
110#endif 110#endif
111 111
112#ifdef CONFIG_PROC_KCORE
113
114static int __init setup_kcore(void)
115{
116 int i;
117
118 for (i=0; i < lmb.memory.cnt; i++) {
119 unsigned long base, size;
120 struct kcore_list *kcore_mem;
121
122 base = lmb.memory.region[i].base;
123 size = lmb.memory.region[i].size;
124
125 /* GFP_ATOMIC to avoid might_sleep warnings during boot */
126 kcore_mem = kmalloc(sizeof(struct kcore_list), GFP_ATOMIC);
127 if (!kcore_mem)
128 panic("%s: kmalloc failed\n", __func__);
129
130 kclist_add(kcore_mem, __va(base), size, KCORE_RAM);
131 }
132
133 return 0;
134}
135module_init(setup_kcore);
136#endif
137
138static void pgd_ctor(void *addr) 112static void pgd_ctor(void *addr)
139{ 113{
140 memset(addr, 0, PGD_TABLE_SIZE); 114 memset(addr, 0, PGD_TABLE_SIZE);
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index bf8bd026db55..8173e38afd38 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -186,8 +186,6 @@ void __init paging_init(void)
186 set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start)); 186 set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start));
187} 187}
188 188
189static struct kcore_list kcore_mem;
190
191void __init mem_init(void) 189void __init mem_init(void)
192{ 190{
193 int codesize, datasize, initsize; 191 int codesize, datasize, initsize;
@@ -226,8 +224,6 @@ void __init mem_init(void)
226 datasize = (unsigned long) &_edata - (unsigned long) &_etext; 224 datasize = (unsigned long) &_edata - (unsigned long) &_etext;
227 initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; 225 initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
228 226
229 kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT, KCORE_RAM);
230
231 printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, " 227 printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
232 "%dk data, %dk init)\n", 228 "%dk data, %dk init)\n",
233 nr_free_pages() << (PAGE_SHIFT-10), 229 nr_free_pages() << (PAGE_SHIFT-10),
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 7108678ca9bc..30938c1d8d5d 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -857,8 +857,6 @@ static void __init test_wp_bit(void)
857 } 857 }
858} 858}
859 859
860static struct kcore_list kcore_mem;
861
862void __init mem_init(void) 860void __init mem_init(void)
863{ 861{
864 int codesize, reservedpages, datasize, initsize; 862 int codesize, reservedpages, datasize, initsize;
@@ -886,8 +884,6 @@ void __init mem_init(void)
886 datasize = (unsigned long) &_edata - (unsigned long) &_etext; 884 datasize = (unsigned long) &_edata - (unsigned long) &_etext;
887 initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; 885 initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
888 886
889 kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT, KCORE_RAM);
890
891 printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, " 887 printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
892 "%dk reserved, %dk data, %dk init, %ldk highmem)\n", 888 "%dk reserved, %dk data, %dk init, %ldk highmem)\n",
893 nr_free_pages() << (PAGE_SHIFT-10), 889 nr_free_pages() << (PAGE_SHIFT-10),
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index a0c2efb10cbe..d5d23cc24076 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -647,7 +647,7 @@ EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
647 647
648#endif /* CONFIG_MEMORY_HOTPLUG */ 648#endif /* CONFIG_MEMORY_HOTPLUG */
649 649
650static struct kcore_list kcore_mem, kcore_modules, kcore_vsyscall; 650static struct kcore_list kcore_modules, kcore_vsyscall;
651 651
652void __init mem_init(void) 652void __init mem_init(void)
653{ 653{
@@ -676,7 +676,6 @@ void __init mem_init(void)
676 initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; 676 initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
677 677
678 /* Register memory areas for /proc/kcore */ 678 /* Register memory areas for /proc/kcore */
679 kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT, KCORE_RAM);
680 kclist_add(&kcore_modules, (void *)MODULES_VADDR, MODULES_LEN, 679 kclist_add(&kcore_modules, (void *)MODULES_VADDR, MODULES_LEN,
681 KCORE_OTHER); 680 KCORE_OTHER);
682 kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START, 681 kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START,
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index fdde1cc78392..802de33d6341 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -17,10 +17,14 @@
17#include <linux/elfcore.h> 17#include <linux/elfcore.h>
18#include <linux/vmalloc.h> 18#include <linux/vmalloc.h>
19#include <linux/highmem.h> 19#include <linux/highmem.h>
20#include <linux/bootmem.h>
20#include <linux/init.h> 21#include <linux/init.h>
21#include <asm/uaccess.h> 22#include <asm/uaccess.h>
22#include <asm/io.h> 23#include <asm/io.h>
23#include <linux/list.h> 24#include <linux/list.h>
25#include <linux/ioport.h>
26#include <linux/mm.h>
27#include <linux/memory.h>
24#include <asm/sections.h> 28#include <asm/sections.h>
25 29
26#define CORE_STR "CORE" 30#define CORE_STR "CORE"
@@ -31,17 +35,6 @@
31 35
32static struct proc_dir_entry *proc_root_kcore; 36static struct proc_dir_entry *proc_root_kcore;
33 37
34static int open_kcore(struct inode * inode, struct file * filp)
35{
36 return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
37}
38
39static ssize_t read_kcore(struct file *, char __user *, size_t, loff_t *);
40
41static const struct file_operations proc_kcore_operations = {
42 .read = read_kcore,
43 .open = open_kcore,
44};
45 38
46#ifndef kc_vaddr_to_offset 39#ifndef kc_vaddr_to_offset
47#define kc_vaddr_to_offset(v) ((v) - PAGE_OFFSET) 40#define kc_vaddr_to_offset(v) ((v) - PAGE_OFFSET)
@@ -61,6 +54,7 @@ struct memelfnote
61 54
62static LIST_HEAD(kclist_head); 55static LIST_HEAD(kclist_head);
63static DEFINE_RWLOCK(kclist_lock); 56static DEFINE_RWLOCK(kclist_lock);
57static int kcore_need_update = 1;
64 58
65void 59void
66kclist_add(struct kcore_list *new, void *addr, size_t size, int type) 60kclist_add(struct kcore_list *new, void *addr, size_t size, int type)
@@ -99,6 +93,126 @@ static size_t get_kcore_size(int *nphdr, size_t *elf_buflen)
99 return size + *elf_buflen; 93 return size + *elf_buflen;
100} 94}
101 95
96static void free_kclist_ents(struct list_head *head)
97{
98 struct kcore_list *tmp, *pos;
99
100 list_for_each_entry_safe(pos, tmp, head, list) {
101 list_del(&pos->list);
102 kfree(pos);
103 }
104}
105/*
106 * Replace all KCORE_RAM information with passed list.
107 */
108static void __kcore_update_ram(struct list_head *list)
109{
110 struct kcore_list *tmp, *pos;
111 LIST_HEAD(garbage);
112
113 write_lock(&kclist_lock);
114 if (kcore_need_update) {
115 list_for_each_entry_safe(pos, tmp, &kclist_head, list) {
116 if (pos->type == KCORE_RAM)
117 list_move(&pos->list, &garbage);
118 }
119 list_splice_tail(list, &kclist_head);
120 } else
121 list_splice(list, &garbage);
122 kcore_need_update = 0;
123 write_unlock(&kclist_lock);
124
125 free_kclist_ents(&garbage);
126}
127
128
129#ifdef CONFIG_HIGHMEM
130/*
131 * If no highmem, we can assume [0...max_low_pfn) continuous range of memory
132 * because memory hole is not as big as !HIGHMEM case.
133 * (HIGHMEM is special because part of memory is _invisible_ from the kernel.)
134 */
135static int kcore_update_ram(void)
136{
137 LIST_HEAD(head);
138 struct kcore_list *ent;
139 int ret = 0;
140
141 ent = kmalloc(sizeof(*ent), GFP_KERNEL);
142 if (!ent)
143 return -ENOMEM;
144 ent->addr = (unsigned long)__va(0);
145 ent->size = max_low_pfn << PAGE_SHIFT;
146 ent->type = KCORE_RAM;
147 list_add(&ent->list, &head);
148 __kcore_update_ram(&head);
149 return ret;
150}
151
152#else /* !CONFIG_HIGHMEM */
153
154static int
155kclist_add_private(unsigned long pfn, unsigned long nr_pages, void *arg)
156{
157 struct list_head *head = (struct list_head *)arg;
158 struct kcore_list *ent;
159
160 ent = kmalloc(sizeof(*ent), GFP_KERNEL);
161 if (!ent)
162 return -ENOMEM;
163 ent->addr = (unsigned long)__va((pfn << PAGE_SHIFT));
164 ent->size = nr_pages << PAGE_SHIFT;
165
166 /* Sanity check: Can happen in 32bit arch...maybe */
167 if (ent->addr < (unsigned long) __va(0))
168 goto free_out;
169
170 /* cut not-mapped area. ....from ppc-32 code. */
171 if (ULONG_MAX - ent->addr < ent->size)
172 ent->size = ULONG_MAX - ent->addr;
173
174 /* cut when vmalloc() area is higher than direct-map area */
175 if (VMALLOC_START > (unsigned long)__va(0)) {
176 if (ent->addr > VMALLOC_START)
177 goto free_out;
178 if (VMALLOC_START - ent->addr < ent->size)
179 ent->size = VMALLOC_START - ent->addr;
180 }
181
182 ent->type = KCORE_RAM;
183 list_add_tail(&ent->list, head);
184 return 0;
185free_out:
186 kfree(ent);
187 return 1;
188}
189
190static int kcore_update_ram(void)
191{
192 int nid, ret;
193 unsigned long end_pfn;
194 LIST_HEAD(head);
195
196 /* Not inialized....update now */
197 /* find out "max pfn" */
198 end_pfn = 0;
199 for_each_node_state(nid, N_HIGH_MEMORY) {
200 unsigned long node_end;
201 node_end = NODE_DATA(nid)->node_start_pfn +
202 NODE_DATA(nid)->node_spanned_pages;
203 if (end_pfn < node_end)
204 end_pfn = node_end;
205 }
206 /* scan 0 to max_pfn */
207 ret = walk_system_ram_range(0, end_pfn, &head, kclist_add_private);
208 if (ret) {
209 free_kclist_ents(&head);
210 return -ENOMEM;
211 }
212 __kcore_update_ram(&head);
213 return ret;
214}
215#endif /* CONFIG_HIGHMEM */
102 216
103/*****************************************************************************/ 217/*****************************************************************************/
104/* 218/*
@@ -373,6 +487,39 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
373 return acc; 487 return acc;
374} 488}
375 489
490
491static int open_kcore(struct inode *inode, struct file *filp)
492{
493 if (!capable(CAP_SYS_RAWIO))
494 return -EPERM;
495 if (kcore_need_update)
496 kcore_update_ram();
497 return 0;
498}
499
500
501static const struct file_operations proc_kcore_operations = {
502 .read = read_kcore,
503 .open = open_kcore,
504};
505
506#ifdef CONFIG_MEMORY_HOTPLUG
507/* just remember that we have to update kcore */
508static int __meminit kcore_callback(struct notifier_block *self,
509 unsigned long action, void *arg)
510{
511 switch (action) {
512 case MEM_ONLINE:
513 case MEM_OFFLINE:
514 write_lock(&kclist_lock);
515 kcore_need_update = 1;
516 write_unlock(&kclist_lock);
517 }
518 return NOTIFY_OK;
519}
520#endif
521
522
376static struct kcore_list kcore_vmalloc; 523static struct kcore_list kcore_vmalloc;
377 524
378#ifdef CONFIG_ARCH_PROC_KCORE_TEXT 525#ifdef CONFIG_ARCH_PROC_KCORE_TEXT
@@ -393,10 +540,18 @@ static void __init proc_kcore_text_init(void)
393 540
394static int __init proc_kcore_init(void) 541static int __init proc_kcore_init(void)
395{ 542{
396 proc_root_kcore = proc_create("kcore", S_IRUSR, NULL, &proc_kcore_operations); 543 proc_root_kcore = proc_create("kcore", S_IRUSR, NULL,
544 &proc_kcore_operations);
545 /* Store text area if it's special */
397 proc_kcore_text_init(); 546 proc_kcore_text_init();
547 /* Store vmalloc area */
398 kclist_add(&kcore_vmalloc, (void *)VMALLOC_START, 548 kclist_add(&kcore_vmalloc, (void *)VMALLOC_START,
399 VMALLOC_END - VMALLOC_START, KCORE_VMALLOC); 549 VMALLOC_END - VMALLOC_START, KCORE_VMALLOC);
550 /* Store direct-map area from physical memory map */
551 kcore_update_ram();
552 hotplug_memory_notifier(kcore_callback, 0);
553 /* Other special area, area-for-module etc is arch specific. */
554
400 return 0; 555 return 0;
401} 556}
402module_init(proc_kcore_init); 557module_init(proc_kcore_init);