Commit 26562c59fa9111ae3ea7b78045889662aac9e5ac

Authored by KAMEZAWA Hiroyuki
Committed by Linus Torvalds
1 parent 3089aa1b0c

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

... ... @@ -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);
include/linux/proc_fs.h
... ... @@ -82,6 +82,7 @@
82 82 KCORE_TEXT,
83 83 KCORE_VMALLOC,
84 84 KCORE_RAM,
  85 + KCORE_VMEMMAP,
85 86 KCORE_OTHER,
86 87 };
87 88