diff options
author | KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> | 2009-09-22 19:45:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 10:39:41 -0400 |
commit | 26562c59fa9111ae3ea7b78045889662aac9e5ac (patch) | |
tree | fe231752dcc4db5967bd798dbd9749a516678e18 | |
parent | 3089aa1b0c07fb7c48f9829c619f50198307789d (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.c | 52 | ||||
-rw-r--r-- | include/linux/proc_fs.h | 1 |
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 | */ |
108 | static void __kcore_update_ram(struct list_head *list) | 108 | static 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 */ | ||
157 | int 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 | ||
189 | int get_sparsemem_vmemmap_info(struct kcore_list *ent, struct list_head *head) | ||
190 | { | ||
191 | return 1; | ||
192 | } | ||
193 | |||
194 | #endif | ||
195 | |||
154 | static int | 196 | static int |
155 | kclist_add_private(unsigned long pfn, unsigned long nr_pages, void *arg) | 197 | kclist_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; |
185 | free_out: | 233 | free_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 | ||