Commit f0aa6617903648077dffe5cfcf7c4458f4610fa7

Authored by Tejun Heo
1 parent f2a8205c4e

vmalloc: implement vm_area_register_early()

Impact: allow multiple early vm areas

There are places where kernel VM area needs to be allocated before
vmalloc is initialized.  This is done by allocating static vm_struct,
initializing several fields and linking it to vmlist and later vmalloc
initialization picking up these from vmlist.  This is currently done
manually and if there's more than one such areas, there's no defined
way to arbitrate who gets which address.

This patch implements vm_area_register_early(), which takes vm_area
struct with flags and size initialized, assigns address to it and puts
it on the vmlist.  This way, multiple early vm areas can determine
which addresses they should use.  The only current user - alpha mm
init - is converted to use it.

Signed-off-by: Tejun Heo <tj@kernel.org>

Showing 3 changed files with 38 additions and 7 deletions Side-by-side Diff

arch/alpha/mm/init.c
... ... @@ -189,9 +189,21 @@
189 189  
190 190 if (alpha_using_srm) {
191 191 static struct vm_struct console_remap_vm;
192   - unsigned long vaddr = VMALLOC_START;
  192 + unsigned long nr_pages = 0;
  193 + unsigned long vaddr;
193 194 unsigned long i, j;
194 195  
  196 + /* calculate needed size */
  197 + for (i = 0; i < crb->map_entries; ++i)
  198 + nr_pages += crb->map[i].count;
  199 +
  200 + /* register the vm area */
  201 + console_remap_vm.flags = VM_ALLOC;
  202 + console_remap_vm.size = nr_pages << PAGE_SHIFT;
  203 + vm_area_register_early(&console_remap_vm);
  204 +
  205 + vaddr = (unsigned long)consle_remap_vm.addr;
  206 +
195 207 /* Set up the third level PTEs and update the virtual
196 208 addresses of the CRB entries. */
197 209 for (i = 0; i < crb->map_entries; ++i) {
... ... @@ -213,12 +225,6 @@
213 225 vaddr += PAGE_SIZE;
214 226 }
215 227 }
216   -
217   - /* Let vmalloc know that we've allocated some space. */
218   - console_remap_vm.flags = VM_ALLOC;
219   - console_remap_vm.addr = (void *) VMALLOC_START;
220   - console_remap_vm.size = vaddr - VMALLOC_START;
221   - vmlist = &console_remap_vm;
222 228 }
223 229  
224 230 callback_init_done = 1;
include/linux/vmalloc.h
... ... @@ -106,6 +106,7 @@
106 106 */
107 107 extern rwlock_t vmlist_lock;
108 108 extern struct vm_struct *vmlist;
  109 +extern __init void vm_area_register_early(struct vm_struct *vm);
109 110  
110 111 #endif /* _LINUX_VMALLOC_H */
... ... @@ -24,6 +24,7 @@
24 24 #include <linux/radix-tree.h>
25 25 #include <linux/rcupdate.h>
26 26 #include <linux/bootmem.h>
  27 +#include <linux/pfn.h>
27 28  
28 29 #include <asm/atomic.h>
29 30 #include <asm/uaccess.h>
... ... @@ -981,6 +982,29 @@
981 982 return mem;
982 983 }
983 984 EXPORT_SYMBOL(vm_map_ram);
  985 +
  986 +/**
  987 + * vm_area_register_early - register vmap area early during boot
  988 + * @vm: vm_struct to register
  989 + * @size: size of area to register
  990 + *
  991 + * This function is used to register kernel vm area before
  992 + * vmalloc_init() is called. @vm->size and @vm->flags should contain
  993 + * proper values on entry and other fields should be zero. On return,
  994 + * vm->addr contains the allocated address.
  995 + *
  996 + * DO NOT USE THIS FUNCTION UNLESS YOU KNOW WHAT YOU'RE DOING.
  997 + */
  998 +void __init vm_area_register_early(struct vm_struct *vm)
  999 +{
  1000 + static size_t vm_init_off __initdata;
  1001 +
  1002 + vm->addr = (void *)VMALLOC_START + vm_init_off;
  1003 + vm_init_off = PFN_ALIGN(vm_init_off + vm->size);
  1004 +
  1005 + vm->next = vmlist;
  1006 + vmlist = vm;
  1007 +}
984 1008  
985 1009 void __init vmalloc_init(void)
986 1010 {