aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>2009-09-22 19:45:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:41 -0400
commit26562c59fa9111ae3ea7b78045889662aac9e5ac (patch)
treefe231752dcc4db5967bd798dbd9749a516678e18
parent3089aa1b0c07fb7c48f9829c619f50198307789d (diff)
kcore: register vmemmap range
Benjamin Herrenschmidt <benh@kernel.crashing.org> pointed out that vmemmap range is not included in KCORE_RAM, KCORE_VMALLOC .... This adds KCORE_VMEMMAP if SPARSEMEM_VMEMMAP is used. By this, vmemmap can be readable via /proc/kcore Because it's not vmalloc area, vread/vwrite cannot be used. But the range is static against the memory layout, this patch handles vmemmap area by the same scheme with physical memory. This patch assumes SPARSEMEM_VMEMMAP range is not in VMALLOC range. It's correct now. [akpm@linux-foundation.org: fix typo] Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: 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: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/proc/kcore.c52
-rw-r--r--include/linux/proc_fs.h1
2 files changed, 51 insertions, 2 deletions
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index 802de33d6341..78970e6f715c 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -103,7 +103,7 @@ static void free_kclist_ents(struct list_head *head)
103 } 103 }
104} 104}
105/* 105/*
106 * Replace all KCORE_RAM information with passed list. 106 * Replace all KCORE_RAM/KCORE_VMEMMAP information with passed list.
107 */ 107 */
108static void __kcore_update_ram(struct list_head *list) 108static void __kcore_update_ram(struct list_head *list)
109{ 109{
@@ -113,7 +113,8 @@ static void __kcore_update_ram(struct list_head *list)
113 write_lock(&kclist_lock); 113 write_lock(&kclist_lock);
114 if (kcore_need_update) { 114 if (kcore_need_update) {
115 list_for_each_entry_safe(pos, tmp, &kclist_head, list) { 115 list_for_each_entry_safe(pos, tmp, &kclist_head, list) {
116 if (pos->type == KCORE_RAM) 116 if (pos->type == KCORE_RAM
117 || pos->type == KCORE_VMEMMAP)
117 list_move(&pos->list, &garbage); 118 list_move(&pos->list, &garbage);
118 } 119 }
119 list_splice_tail(list, &kclist_head); 120 list_splice_tail(list, &kclist_head);
@@ -151,6 +152,47 @@ static int kcore_update_ram(void)
151 152
152#else /* !CONFIG_HIGHMEM */ 153#else /* !CONFIG_HIGHMEM */
153 154
155#ifdef CONFIG_SPARSEMEM_VMEMMAP
156/* calculate vmemmap's address from given system ram pfn and register it */
157int get_sparsemem_vmemmap_info(struct kcore_list *ent, struct list_head *head)
158{
159 unsigned long pfn = __pa(ent->addr) >> PAGE_SHIFT;
160 unsigned long nr_pages = ent->size >> PAGE_SHIFT;
161 unsigned long start, end;
162 struct kcore_list *vmm, *tmp;
163
164
165 start = ((unsigned long)pfn_to_page(pfn)) & PAGE_MASK;
166 end = ((unsigned long)pfn_to_page(pfn + nr_pages)) - 1;
167 end = ALIGN(end, PAGE_SIZE);
168 /* overlap check (because we have to align page */
169 list_for_each_entry(tmp, head, list) {
170 if (tmp->type != KCORE_VMEMMAP)
171 continue;
172 if (start < tmp->addr + tmp->size)
173 if (end > tmp->addr)
174 end = tmp->addr;
175 }
176 if (start < end) {
177 vmm = kmalloc(sizeof(*vmm), GFP_KERNEL);
178 if (!vmm)
179 return 0;
180 vmm->addr = start;
181 vmm->size = end - start;
182 vmm->type = KCORE_VMEMMAP;
183 list_add_tail(&vmm->list, head);
184 }
185 return 1;
186
187}
188#else
189int get_sparsemem_vmemmap_info(struct kcore_list *ent, struct list_head *head)
190{
191 return 1;
192}
193
194#endif
195
154static int 196static int
155kclist_add_private(unsigned long pfn, unsigned long nr_pages, void *arg) 197kclist_add_private(unsigned long pfn, unsigned long nr_pages, void *arg)
156{ 198{
@@ -181,6 +223,12 @@ kclist_add_private(unsigned long pfn, unsigned long nr_pages, void *arg)
181 223
182 ent->type = KCORE_RAM; 224 ent->type = KCORE_RAM;
183 list_add_tail(&ent->list, head); 225 list_add_tail(&ent->list, head);
226
227 if (!get_sparsemem_vmemmap_info(ent, head)) {
228 list_del(&ent->list);
229 goto free_out;
230 }
231
184 return 0; 232 return 0;
185free_out: 233free_out:
186 kfree(ent); 234 kfree(ent);
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index bd7b840765a0..379eaed72d4b 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -82,6 +82,7 @@ enum kcore_type {
82 KCORE_TEXT, 82 KCORE_TEXT,
83 KCORE_VMALLOC, 83 KCORE_VMALLOC,
84 KCORE_RAM, 84 KCORE_RAM,
85 KCORE_VMEMMAP,
85 KCORE_OTHER, 86 KCORE_OTHER,
86}; 87};
87 88