diff options
author | Seth Jennings <sjenning@linux.vnet.ibm.com> | 2012-07-02 17:15:49 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-09 14:34:59 -0400 |
commit | 5f601902c61e6cda627ec71c10609021067ed0fa (patch) | |
tree | 80dff109d1e2047501d2ae7c60dea85a2acb998c | |
parent | c666e636ac9915f33fe175c75bc01ab994e5afa6 (diff) |
staging: zsmalloc: remove x86 dependency
This patch replaces the page table assisted object mapping
method, which has x86 dependencies, with a arch-independent
method that does a simple copy into a temporary per-cpu
buffer.
While a copy seems like it would be worse than mapping the pages,
tests demonstrate the copying is always faster and, in the case of
running inside a KVM guest, roughly 4x faster.
Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/staging/zsmalloc/Kconfig | 4 | ||||
-rw-r--r-- | drivers/staging/zsmalloc/zsmalloc-main.c | 99 | ||||
-rw-r--r-- | drivers/staging/zsmalloc/zsmalloc_int.h | 5 |
3 files changed, 72 insertions, 36 deletions
diff --git a/drivers/staging/zsmalloc/Kconfig b/drivers/staging/zsmalloc/Kconfig index a5ab7200626..90845656579 100644 --- a/drivers/staging/zsmalloc/Kconfig +++ b/drivers/staging/zsmalloc/Kconfig | |||
@@ -1,9 +1,5 @@ | |||
1 | config ZSMALLOC | 1 | config ZSMALLOC |
2 | tristate "Memory allocator for compressed pages" | 2 | tristate "Memory allocator for compressed pages" |
3 | # X86 dependency is because of the use of __flush_tlb_one and set_pte | ||
4 | # in zsmalloc-main.c. | ||
5 | # TODO: convert these to portable functions | ||
6 | depends on X86 | ||
7 | default n | 3 | default n |
8 | help | 4 | help |
9 | zsmalloc is a slab-based memory allocator designed to store | 5 | zsmalloc is a slab-based memory allocator designed to store |
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c index 10b0d600026..a7a6f225bbf 100644 --- a/drivers/staging/zsmalloc/zsmalloc-main.c +++ b/drivers/staging/zsmalloc/zsmalloc-main.c | |||
@@ -470,6 +470,57 @@ static struct page *find_get_zspage(struct size_class *class) | |||
470 | return page; | 470 | return page; |
471 | } | 471 | } |
472 | 472 | ||
473 | static void zs_copy_map_object(char *buf, struct page *firstpage, | ||
474 | int off, int size) | ||
475 | { | ||
476 | struct page *pages[2]; | ||
477 | int sizes[2]; | ||
478 | void *addr; | ||
479 | |||
480 | pages[0] = firstpage; | ||
481 | pages[1] = get_next_page(firstpage); | ||
482 | BUG_ON(!pages[1]); | ||
483 | |||
484 | sizes[0] = PAGE_SIZE - off; | ||
485 | sizes[1] = size - sizes[0]; | ||
486 | |||
487 | /* disable page faults to match kmap_atomic() return conditions */ | ||
488 | pagefault_disable(); | ||
489 | |||
490 | /* copy object to per-cpu buffer */ | ||
491 | addr = kmap_atomic(pages[0]); | ||
492 | memcpy(buf, addr + off, sizes[0]); | ||
493 | kunmap_atomic(addr); | ||
494 | addr = kmap_atomic(pages[1]); | ||
495 | memcpy(buf + sizes[0], addr, sizes[1]); | ||
496 | kunmap_atomic(addr); | ||
497 | } | ||
498 | |||
499 | static void zs_copy_unmap_object(char *buf, struct page *firstpage, | ||
500 | int off, int size) | ||
501 | { | ||
502 | struct page *pages[2]; | ||
503 | int sizes[2]; | ||
504 | void *addr; | ||
505 | |||
506 | pages[0] = firstpage; | ||
507 | pages[1] = get_next_page(firstpage); | ||
508 | BUG_ON(!pages[1]); | ||
509 | |||
510 | sizes[0] = PAGE_SIZE - off; | ||
511 | sizes[1] = size - sizes[0]; | ||
512 | |||
513 | /* copy per-cpu buffer to object */ | ||
514 | addr = kmap_atomic(pages[0]); | ||
515 | memcpy(addr + off, buf, sizes[0]); | ||
516 | kunmap_atomic(addr); | ||
517 | addr = kmap_atomic(pages[1]); | ||
518 | memcpy(addr, buf + sizes[0], sizes[1]); | ||
519 | kunmap_atomic(addr); | ||
520 | |||
521 | /* enable page faults to match kunmap_atomic() return conditions */ | ||
522 | pagefault_enable(); | ||
523 | } | ||
473 | 524 | ||
474 | static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action, | 525 | static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action, |
475 | void *pcpu) | 526 | void *pcpu) |
@@ -480,18 +531,23 @@ static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action, | |||
480 | switch (action) { | 531 | switch (action) { |
481 | case CPU_UP_PREPARE: | 532 | case CPU_UP_PREPARE: |
482 | area = &per_cpu(zs_map_area, cpu); | 533 | area = &per_cpu(zs_map_area, cpu); |
483 | if (area->vm) | 534 | /* |
484 | break; | 535 | * Make sure we don't leak memory if a cpu UP notification |
485 | area->vm = alloc_vm_area(2 * PAGE_SIZE, area->vm_ptes); | 536 | * and zs_init() race and both call zs_cpu_up() on the same cpu |
486 | if (!area->vm) | 537 | */ |
487 | return notifier_from_errno(-ENOMEM); | 538 | if (area->vm_buf) |
539 | return 0; | ||
540 | area->vm_buf = (char *)__get_free_page(GFP_KERNEL); | ||
541 | if (!area->vm_buf) | ||
542 | return -ENOMEM; | ||
543 | return 0; | ||
488 | break; | 544 | break; |
489 | case CPU_DEAD: | 545 | case CPU_DEAD: |
490 | case CPU_UP_CANCELED: | 546 | case CPU_UP_CANCELED: |
491 | area = &per_cpu(zs_map_area, cpu); | 547 | area = &per_cpu(zs_map_area, cpu); |
492 | if (area->vm) | 548 | if (area->vm_buf) |
493 | free_vm_area(area->vm); | 549 | free_page((unsigned long)area->vm_buf); |
494 | area->vm = NULL; | 550 | area->vm_buf = NULL; |
495 | break; | 551 | break; |
496 | } | 552 | } |
497 | 553 | ||
@@ -714,22 +770,11 @@ void *zs_map_object(struct zs_pool *pool, unsigned long handle) | |||
714 | if (off + class->size <= PAGE_SIZE) { | 770 | if (off + class->size <= PAGE_SIZE) { |
715 | /* this object is contained entirely within a page */ | 771 | /* this object is contained entirely within a page */ |
716 | area->vm_addr = kmap_atomic(page); | 772 | area->vm_addr = kmap_atomic(page); |
717 | } else { | 773 | return area->vm_addr + off; |
718 | /* this object spans two pages */ | ||
719 | struct page *nextp; | ||
720 | |||
721 | nextp = get_next_page(page); | ||
722 | BUG_ON(!nextp); | ||
723 | |||
724 | |||
725 | set_pte(area->vm_ptes[0], mk_pte(page, PAGE_KERNEL)); | ||
726 | set_pte(area->vm_ptes[1], mk_pte(nextp, PAGE_KERNEL)); | ||
727 | |||
728 | /* We pre-allocated VM area so mapping can never fail */ | ||
729 | area->vm_addr = area->vm->addr; | ||
730 | } | 774 | } |
731 | 775 | ||
732 | return area->vm_addr + off; | 776 | zs_copy_map_object(area->vm_buf, page, off, class->size); |
777 | return area->vm_buf; | ||
733 | } | 778 | } |
734 | EXPORT_SYMBOL_GPL(zs_map_object); | 779 | EXPORT_SYMBOL_GPL(zs_map_object); |
735 | 780 | ||
@@ -751,14 +796,10 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle) | |||
751 | off = obj_idx_to_offset(page, obj_idx, class->size); | 796 | off = obj_idx_to_offset(page, obj_idx, class->size); |
752 | 797 | ||
753 | area = &__get_cpu_var(zs_map_area); | 798 | area = &__get_cpu_var(zs_map_area); |
754 | if (off + class->size <= PAGE_SIZE) { | 799 | if (off + class->size <= PAGE_SIZE) |
755 | kunmap_atomic(area->vm_addr); | 800 | kunmap_atomic(area->vm_addr); |
756 | } else { | 801 | else |
757 | set_pte(area->vm_ptes[0], __pte(0)); | 802 | zs_copy_unmap_object(area->vm_buf, page, off, class->size); |
758 | set_pte(area->vm_ptes[1], __pte(0)); | ||
759 | __flush_tlb_one((unsigned long)area->vm_addr); | ||
760 | __flush_tlb_one((unsigned long)area->vm_addr + PAGE_SIZE); | ||
761 | } | ||
762 | put_cpu_var(zs_map_area); | 803 | put_cpu_var(zs_map_area); |
763 | } | 804 | } |
764 | EXPORT_SYMBOL_GPL(zs_unmap_object); | 805 | EXPORT_SYMBOL_GPL(zs_unmap_object); |
diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h b/drivers/staging/zsmalloc/zsmalloc_int.h index 6fd32a9e031..f760dae54f2 100644 --- a/drivers/staging/zsmalloc/zsmalloc_int.h +++ b/drivers/staging/zsmalloc/zsmalloc_int.h | |||
@@ -110,9 +110,8 @@ enum fullness_group { | |||
110 | static const int fullness_threshold_frac = 4; | 110 | static const int fullness_threshold_frac = 4; |
111 | 111 | ||
112 | struct mapping_area { | 112 | struct mapping_area { |
113 | struct vm_struct *vm; | 113 | char *vm_buf; /* copy buffer for objects that span pages */ |
114 | pte_t *vm_ptes[2]; | 114 | char *vm_addr; /* address of kmap_atomic()'ed pages */ |
115 | char *vm_addr; | ||
116 | }; | 115 | }; |
117 | 116 | ||
118 | struct size_class { | 117 | struct size_class { |