Commit 26562c59fa9111ae3ea7b78045889662aac9e5ac
Committed by
Linus Torvalds
1 parent
3089aa1b0c
Exists in
master
and in
7 other branches
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>
Showing 2 changed files with 51 additions and 2 deletions Side-by-side Diff
fs/proc/kcore.c
... | ... | @@ -103,7 +103,7 @@ |
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 | 108 | static void __kcore_update_ram(struct list_head *list) |
109 | 109 | { |
... | ... | @@ -113,7 +113,8 @@ |
113 | 113 | write_lock(&kclist_lock); |
114 | 114 | if (kcore_need_update) { |
115 | 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 | 118 | list_move(&pos->list, &garbage); |
118 | 119 | } |
119 | 120 | list_splice_tail(list, &kclist_head); |
... | ... | @@ -151,6 +152,47 @@ |
151 | 152 | |
152 | 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 | 196 | static int |
155 | 197 | kclist_add_private(unsigned long pfn, unsigned long nr_pages, void *arg) |
156 | 198 | { |
... | ... | @@ -181,6 +223,12 @@ |
181 | 223 | |
182 | 224 | ent->type = KCORE_RAM; |
183 | 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 | 232 | return 0; |
185 | 233 | free_out: |
186 | 234 | kfree(ent); |