aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSeth Jennings <sjenning@linux.vnet.ibm.com>2012-07-02 17:15:49 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-09 14:34:59 -0400
commit5f601902c61e6cda627ec71c10609021067ed0fa (patch)
tree80dff109d1e2047501d2ae7c60dea85a2acb998c
parentc666e636ac9915f33fe175c75bc01ab994e5afa6 (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/Kconfig4
-rw-r--r--drivers/staging/zsmalloc/zsmalloc-main.c99
-rw-r--r--drivers/staging/zsmalloc/zsmalloc_int.h5
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 @@
1config ZSMALLOC 1config 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
473static 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
499static 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
474static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action, 525static 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}
734EXPORT_SYMBOL_GPL(zs_map_object); 779EXPORT_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}
764EXPORT_SYMBOL_GPL(zs_unmap_object); 805EXPORT_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 {
110static const int fullness_threshold_frac = 4; 110static const int fullness_threshold_frac = 4;
111 111
112struct mapping_area { 112struct 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
118struct size_class { 117struct size_class {