diff options
-rw-r--r-- | include/linux/vmalloc.h | 8 | ||||
-rw-r--r-- | mm/vmalloc.c | 73 |
2 files changed, 64 insertions, 17 deletions
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 3701a0673d2c..1d5577b2b752 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h | |||
@@ -32,10 +32,14 @@ struct vm_struct { | |||
32 | * Highlevel APIs for driver use | 32 | * Highlevel APIs for driver use |
33 | */ | 33 | */ |
34 | extern void *vmalloc(unsigned long size); | 34 | extern void *vmalloc(unsigned long size); |
35 | extern void *vmalloc_node(unsigned long size, int node); | ||
35 | extern void *vmalloc_exec(unsigned long size); | 36 | extern void *vmalloc_exec(unsigned long size); |
36 | extern void *vmalloc_32(unsigned long size); | 37 | extern void *vmalloc_32(unsigned long size); |
37 | extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot); | 38 | extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot); |
38 | extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot); | 39 | extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, |
40 | pgprot_t prot); | ||
41 | extern void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, | ||
42 | pgprot_t prot, int node); | ||
39 | extern void vfree(void *addr); | 43 | extern void vfree(void *addr); |
40 | 44 | ||
41 | extern void *vmap(struct page **pages, unsigned int count, | 45 | extern void *vmap(struct page **pages, unsigned int count, |
@@ -48,6 +52,8 @@ extern void vunmap(void *addr); | |||
48 | extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags); | 52 | extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags); |
49 | extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, | 53 | extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, |
50 | unsigned long start, unsigned long end); | 54 | unsigned long start, unsigned long end); |
55 | extern struct vm_struct *get_vm_area_node(unsigned long size, | ||
56 | unsigned long flags, int node); | ||
51 | extern struct vm_struct *remove_vm_area(void *addr); | 57 | extern struct vm_struct *remove_vm_area(void *addr); |
52 | extern struct vm_struct *__remove_vm_area(void *addr); | 58 | extern struct vm_struct *__remove_vm_area(void *addr); |
53 | extern int map_vm_area(struct vm_struct *area, pgprot_t prot, | 59 | extern int map_vm_area(struct vm_struct *area, pgprot_t prot, |
diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 1150229b6366..5e9120598799 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 | 5 | * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 |
6 | * SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian <tigran@veritas.com>, May 2000 | 6 | * SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian <tigran@veritas.com>, May 2000 |
7 | * Major rework to support vmap/vunmap, Christoph Hellwig, SGI, August 2002 | 7 | * Major rework to support vmap/vunmap, Christoph Hellwig, SGI, August 2002 |
8 | * Numa awareness, Christoph Lameter, SGI, June 2005 | ||
8 | */ | 9 | */ |
9 | 10 | ||
10 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
@@ -158,8 +159,8 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages) | |||
158 | return err; | 159 | return err; |
159 | } | 160 | } |
160 | 161 | ||
161 | struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, | 162 | struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags, |
162 | unsigned long start, unsigned long end) | 163 | unsigned long start, unsigned long end, int node) |
163 | { | 164 | { |
164 | struct vm_struct **p, *tmp, *area; | 165 | struct vm_struct **p, *tmp, *area; |
165 | unsigned long align = 1; | 166 | unsigned long align = 1; |
@@ -178,7 +179,7 @@ struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, | |||
178 | addr = ALIGN(start, align); | 179 | addr = ALIGN(start, align); |
179 | size = PAGE_ALIGN(size); | 180 | size = PAGE_ALIGN(size); |
180 | 181 | ||
181 | area = kmalloc(sizeof(*area), GFP_KERNEL); | 182 | area = kmalloc_node(sizeof(*area), GFP_KERNEL, node); |
182 | if (unlikely(!area)) | 183 | if (unlikely(!area)) |
183 | return NULL; | 184 | return NULL; |
184 | 185 | ||
@@ -231,6 +232,12 @@ out: | |||
231 | return NULL; | 232 | return NULL; |
232 | } | 233 | } |
233 | 234 | ||
235 | struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, | ||
236 | unsigned long start, unsigned long end) | ||
237 | { | ||
238 | return __get_vm_area_node(size, flags, start, end, -1); | ||
239 | } | ||
240 | |||
234 | /** | 241 | /** |
235 | * get_vm_area - reserve a contingous kernel virtual area | 242 | * get_vm_area - reserve a contingous kernel virtual area |
236 | * | 243 | * |
@@ -246,6 +253,11 @@ struct vm_struct *get_vm_area(unsigned long size, unsigned long flags) | |||
246 | return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END); | 253 | return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END); |
247 | } | 254 | } |
248 | 255 | ||
256 | struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, int node) | ||
257 | { | ||
258 | return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node); | ||
259 | } | ||
260 | |||
249 | /* Caller must hold vmlist_lock */ | 261 | /* Caller must hold vmlist_lock */ |
250 | struct vm_struct *__remove_vm_area(void *addr) | 262 | struct vm_struct *__remove_vm_area(void *addr) |
251 | { | 263 | { |
@@ -342,7 +354,6 @@ void vfree(void *addr) | |||
342 | BUG_ON(in_interrupt()); | 354 | BUG_ON(in_interrupt()); |
343 | __vunmap(addr, 1); | 355 | __vunmap(addr, 1); |
344 | } | 356 | } |
345 | |||
346 | EXPORT_SYMBOL(vfree); | 357 | EXPORT_SYMBOL(vfree); |
347 | 358 | ||
348 | /** | 359 | /** |
@@ -360,7 +371,6 @@ void vunmap(void *addr) | |||
360 | BUG_ON(in_interrupt()); | 371 | BUG_ON(in_interrupt()); |
361 | __vunmap(addr, 0); | 372 | __vunmap(addr, 0); |
362 | } | 373 | } |
363 | |||
364 | EXPORT_SYMBOL(vunmap); | 374 | EXPORT_SYMBOL(vunmap); |
365 | 375 | ||
366 | /** | 376 | /** |
@@ -392,10 +402,10 @@ void *vmap(struct page **pages, unsigned int count, | |||
392 | 402 | ||
393 | return area->addr; | 403 | return area->addr; |
394 | } | 404 | } |
395 | |||
396 | EXPORT_SYMBOL(vmap); | 405 | EXPORT_SYMBOL(vmap); |
397 | 406 | ||
398 | void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot) | 407 | void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, |
408 | pgprot_t prot, int node) | ||
399 | { | 409 | { |
400 | struct page **pages; | 410 | struct page **pages; |
401 | unsigned int nr_pages, array_size, i; | 411 | unsigned int nr_pages, array_size, i; |
@@ -406,9 +416,9 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot) | |||
406 | area->nr_pages = nr_pages; | 416 | area->nr_pages = nr_pages; |
407 | /* Please note that the recursion is strictly bounded. */ | 417 | /* Please note that the recursion is strictly bounded. */ |
408 | if (array_size > PAGE_SIZE) | 418 | if (array_size > PAGE_SIZE) |
409 | pages = __vmalloc(array_size, gfp_mask, PAGE_KERNEL); | 419 | pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node); |
410 | else | 420 | else |
411 | pages = kmalloc(array_size, (gfp_mask & ~__GFP_HIGHMEM)); | 421 | pages = kmalloc_node(array_size, (gfp_mask & ~__GFP_HIGHMEM), node); |
412 | area->pages = pages; | 422 | area->pages = pages; |
413 | if (!area->pages) { | 423 | if (!area->pages) { |
414 | remove_vm_area(area->addr); | 424 | remove_vm_area(area->addr); |
@@ -418,7 +428,10 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot) | |||
418 | memset(area->pages, 0, array_size); | 428 | memset(area->pages, 0, array_size); |
419 | 429 | ||
420 | for (i = 0; i < area->nr_pages; i++) { | 430 | for (i = 0; i < area->nr_pages; i++) { |
421 | area->pages[i] = alloc_page(gfp_mask); | 431 | if (node < 0) |
432 | area->pages[i] = alloc_page(gfp_mask); | ||
433 | else | ||
434 | area->pages[i] = alloc_pages_node(node, gfp_mask, 0); | ||
422 | if (unlikely(!area->pages[i])) { | 435 | if (unlikely(!area->pages[i])) { |
423 | /* Successfully allocated i pages, free them in __vunmap() */ | 436 | /* Successfully allocated i pages, free them in __vunmap() */ |
424 | area->nr_pages = i; | 437 | area->nr_pages = i; |
@@ -435,18 +448,25 @@ fail: | |||
435 | return NULL; | 448 | return NULL; |
436 | } | 449 | } |
437 | 450 | ||
451 | void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot) | ||
452 | { | ||
453 | return __vmalloc_area_node(area, gfp_mask, prot, -1); | ||
454 | } | ||
455 | |||
438 | /** | 456 | /** |
439 | * __vmalloc - allocate virtually contiguous memory | 457 | * __vmalloc_node - allocate virtually contiguous memory |
440 | * | 458 | * |
441 | * @size: allocation size | 459 | * @size: allocation size |
442 | * @gfp_mask: flags for the page level allocator | 460 | * @gfp_mask: flags for the page level allocator |
443 | * @prot: protection mask for the allocated pages | 461 | * @prot: protection mask for the allocated pages |
462 | * @node node to use for allocation or -1 | ||
444 | * | 463 | * |
445 | * Allocate enough pages to cover @size from the page level | 464 | * Allocate enough pages to cover @size from the page level |
446 | * allocator with @gfp_mask flags. Map them into contiguous | 465 | * allocator with @gfp_mask flags. Map them into contiguous |
447 | * kernel virtual space, using a pagetable protection of @prot. | 466 | * kernel virtual space, using a pagetable protection of @prot. |
448 | */ | 467 | */ |
449 | void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) | 468 | void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot, |
469 | int node) | ||
450 | { | 470 | { |
451 | struct vm_struct *area; | 471 | struct vm_struct *area; |
452 | 472 | ||
@@ -454,13 +474,18 @@ void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) | |||
454 | if (!size || (size >> PAGE_SHIFT) > num_physpages) | 474 | if (!size || (size >> PAGE_SHIFT) > num_physpages) |
455 | return NULL; | 475 | return NULL; |
456 | 476 | ||
457 | area = get_vm_area(size, VM_ALLOC); | 477 | area = get_vm_area_node(size, VM_ALLOC, node); |
458 | if (!area) | 478 | if (!area) |
459 | return NULL; | 479 | return NULL; |
460 | 480 | ||
461 | return __vmalloc_area(area, gfp_mask, prot); | 481 | return __vmalloc_area_node(area, gfp_mask, prot, node); |
462 | } | 482 | } |
483 | EXPORT_SYMBOL(__vmalloc_node); | ||
463 | 484 | ||
485 | void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) | ||
486 | { | ||
487 | return __vmalloc_node(size, gfp_mask, prot, -1); | ||
488 | } | ||
464 | EXPORT_SYMBOL(__vmalloc); | 489 | EXPORT_SYMBOL(__vmalloc); |
465 | 490 | ||
466 | /** | 491 | /** |
@@ -478,9 +503,26 @@ void *vmalloc(unsigned long size) | |||
478 | { | 503 | { |
479 | return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); | 504 | return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); |
480 | } | 505 | } |
481 | |||
482 | EXPORT_SYMBOL(vmalloc); | 506 | EXPORT_SYMBOL(vmalloc); |
483 | 507 | ||
508 | /** | ||
509 | * vmalloc_node - allocate memory on a specific node | ||
510 | * | ||
511 | * @size: allocation size | ||
512 | * @node; numa node | ||
513 | * | ||
514 | * Allocate enough pages to cover @size from the page level | ||
515 | * allocator and map them into contiguous kernel virtual space. | ||
516 | * | ||
517 | * For tight cotrol over page level allocator and protection flags | ||
518 | * use __vmalloc() instead. | ||
519 | */ | ||
520 | void *vmalloc_node(unsigned long size, int node) | ||
521 | { | ||
522 | return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL, node); | ||
523 | } | ||
524 | EXPORT_SYMBOL(vmalloc_node); | ||
525 | |||
484 | #ifndef PAGE_KERNEL_EXEC | 526 | #ifndef PAGE_KERNEL_EXEC |
485 | # define PAGE_KERNEL_EXEC PAGE_KERNEL | 527 | # define PAGE_KERNEL_EXEC PAGE_KERNEL |
486 | #endif | 528 | #endif |
@@ -515,7 +557,6 @@ void *vmalloc_32(unsigned long size) | |||
515 | { | 557 | { |
516 | return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL); | 558 | return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL); |
517 | } | 559 | } |
518 | |||
519 | EXPORT_SYMBOL(vmalloc_32); | 560 | EXPORT_SYMBOL(vmalloc_32); |
520 | 561 | ||
521 | long vread(char *buf, char *addr, unsigned long count) | 562 | long vread(char *buf, char *addr, unsigned long count) |