aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorLarry Bassel <lbassel@codeaurora.org>2013-10-11 15:32:37 -0700
committerSimon Shields <keepcalm444@gmail.com>2016-06-12 21:19:37 +1000
commit34ea3381f760a04dab010cb94c5783c5ac78c201 (patch)
treec60524373c20df21e30a06e70ffff2ef4db67e18 /drivers/staging
parent2d2bf2aa3ee28795f6a3bc69b1de58e777e22f07 (diff)
downloadkernel_samsung_smdk4412-34ea3381f760a04dab010cb94c5783c5ac78c201.tar.gz
kernel_samsung_smdk4412-34ea3381f760a04dab010cb94c5783c5ac78c201.tar.bz2
kernel_samsung_smdk4412-34ea3381f760a04dab010cb94c5783c5ac78c201.zip
zsmalloc: use 3.10 version of zsmalloc
commit 796ce5a7e4ef88ee0bfbeaa80070a51570650d57 Author: Arnd Bergmann <arnd@arndb.de> Date: Tue Apr 23 18:30:48 2013 +0200 staging/zsmalloc: don't use pgtable-mapping from modules Building zsmalloc as a module does not work on ARM because it uses an interface that is not exported: ERROR: "flush_tlb_kernel_range" [drivers/staging/zsmalloc/zsmalloc.ko] undefined! Since this is only used as a performance optimization and only on ARM, we can avoid the problem simply by not using that optimization when building zsmalloc it is a loadable module. flush_tlb_kernel_range is often an inline function, but out of the architectures that use an extern function, only powerpc exports it. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Seth Jennings <sjenning@linux.vnet.ibm.com> Cc: Nitin Gupta <ngupta@vflare.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit d95abbbb291bf5bce078148f53603ce9c0aa1d44 Author: Joerg Roedel <joro@8bytes.org> Date: Wed Mar 27 01:43:14 2013 +0100 staging: zsmalloc: Fix link error on ARM Testing the arm chromebook config against the upstream kernel produces a linker error for the zsmalloc module from staging. The symbol flush_tlb_kernel_range is not available there. Fix this by removing the reimplementation of unmap_kernel_range in the zsmalloc module and using the function directly. The unmap_kernel_range function is not usable by modules, so also disallow building the driver as a module for now. Cc: stable <stable@vger.kernel.org> Signed-off-by: Joerg Roedel <joro@8bytes.org> Acked-by: Minchan Kim <minchan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit 22b751c3d0376e86a377e3a0aa2ddbbe9d2eefc1 Author: Mel Gorman <mgorman@suse.de> Date: Fri Feb 22 16:34:59 2013 -0800 mm: rename page struct field helpers The function names page_xchg_last_nid(), page_last_nid() and reset_page_last_nid() were judged to be inconsistent so rename them to a struct_field_op style pattern. As it looked jarring to have reset_page_mapcount() and page_nid_reset_last() beside each other in memmap_init_zone(), this patch also renames reset_page_mapcount() to page_mapcount_reset(). There are others like init_page_count() but as it is used throughout the arch code a rename would likely cause more conflicts than it is worth. [akpm@linux-foundation.org: fix zcache] Signed-off-by: Mel Gorman <mgorman@suse.de> Suggested-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> commit 0d145a501778042d0411c843ed5b468b41f8a171 Author: Seth Jennings <sjenning@linux.vnet.ibm.com> Date: Wed Jan 30 09:36:52 2013 -0600 staging: zsmalloc: remove unused pool name zs_create_pool() currently takes a name argument which is never used in any useful way. This patch removes it. Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com> Acked-by: Nitin Gupta <ngupta@vflare.org> Acked-by: Rik van Riel <riel@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit 9915518887e83764269d5b617d01782893877ed3 Author: Minchan Kim <minchan@kernel.org> Date: Mon Jan 28 10:00:08 2013 +0900 staging: zsmalloc: Fix TLB coherency and build problem Recently, Matt Sealey reported he fail to build zsmalloc caused by using of local_flush_tlb_kernel_range which are architecture dependent function so !CONFIG_SMP in ARM couldn't implement it so it ends up build error following as. MODPOST 216 modules LZMA arch/arm/boot/compressed/piggy.lzma AS arch/arm/boot/compressed/lib1funcs.o ERROR: "v7wbi_flush_kern_tlb_range" [drivers/staging/zsmalloc/zsmalloc.ko] undefined! make[1]: *** [__modpost] Error 1 make: *** [modules] Error 2 make: *** Waiting for unfinished jobs.... The reason we used that function is copy method by [1] was really slow in ARM but at that time. More severe problem is ARM can prefetch speculatively on other CPUs so under us, other TLBs can have an entry only if we do flush local CPU. Russell King pointed that. Thanks! We don't have many choices except using flush_tlb_kernel_range. My experiment in ARMv7 processor 4 core didn't make any difference with zsmapbench[2] between local_flush_tlb_kernel_range and flush_tlb_kernel_range but still page-table based is much better than copy-based. * bigger is better. 1. local_flush_tlb_kernel_range: 3918795 mappings 2. flush_tlb_kernel_range : 3989538 mappings 3. copy-based: 635158 mappings This patch replace local_flush_tlb_kernel_range with flush_tlb_kernel_range which are avaialbe in all architectures because we already have used it in vmalloc allocator which are generic one so build problem should go away and performane loss shoud be void. [1] f553646, zsmalloc: add page table mapping method [2] https://github.com/spartacus06/zsmapbench Cc: stable@vger.kernel.org Cc: Dan Magenheimer <dan.magenheimer@oracle.com> Cc: Russell King <linux@arm.linux.org.uk> Cc: Konrad Rzeszutek Wilk <konrad@darnok.org> Cc: Nitin Gupta <ngupta@vflare.org> Cc: Seth Jennings <sjenning@linux.vnet.ibm.com> Reported-by: Matt Sealey <matt@genesi-usa.com> Signed-off-by: Minchan Kim <minchan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit d662b8eba94e9f6d4c036719dbf629ef0c9309cf Author: Seth Jennings <sjenning@linux.vnet.ibm.com> Date: Fri Jan 25 11:46:18 2013 -0600 staging: zsmalloc: make CLASS_DELTA relative to PAGE_SIZE Right now ZS_SIZE_CLASS_DELTA is hardcoded to be 16. This creates 254 classes for systems with 4k pages. However, on PPC64 with 64k pages, it creates 4095 classes which is far too many. This patch makes ZS_SIZE_CLASS_DELTA relative to PAGE_SIZE so that regardless of the page size, there will be the same number of classes. Acked-by: Nitin Gupta <ngupta@vflare.org> Acked-by: Minchan Kim <minchan@kernel.org> Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com> Acked-by: Dan Magenheimer <dan.magenheimer@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit 4bbc0bc06b8b0cced31ee17beb753ad51a2e47e7 Author: Davidlohr Bueso <davidlohr.bueso@hp.com> Date: Fri Jan 4 12:14:00 2013 -0800 staging: zsmalloc: comment zs_create_pool function Just as with zs_malloc() and zs_map_object(), it is worth formally commenting the zs_create_pool() function. Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit 0959c63f11c3bbef0a7d6c5011be8d25503f547c Author: Seth Jennings <sjenning@linux.vnet.ibm.com> Date: Wed Aug 8 15:12:17 2012 +0900 zsmalloc: collapse internal .h into .c The patch collapses in the internal zsmalloc_int.h into the zsmalloc-main.c file. This is done in preparation for the promotion to mm/ where separate internal headers are discouraged. Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com> Signed-off-by: Minchan Kim <minchan@kernel.org> Acked-by: Nitin Gupta <ngupta@vflare.org> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit f553646a67cb215577402cb702b67c8cf8fdb46f Author: Seth Jennings <sjenning@linux.vnet.ibm.com> Date: Wed Jul 18 11:55:56 2012 -0500 staging: zsmalloc: add page table mapping method This patchset provides page mapping via the page table. On some archs, most notably ARM, this method has been demonstrated to be faster than copying. The logic controlling the method selection (copy vs page table) is controlled by the definition of USE_PGTABLE_MAPPING which is/can be defined for any arch that performs better with page table mapping. Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com> Acked-by: Minchan Kim <minchan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit c60369f011251c60de506994aab088f1afb90bf4 Author: Seth Jennings <sjenning@linux.vnet.ibm.com> Date: Wed Jul 18 11:55:55 2012 -0500 staging: zsmalloc: prevent mappping in interrupt context Because we use per-cpu mapping areas shared among the pools/users, we can't allow mapping in interrupt context because it can corrupt another users mappings. Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com> Acked-by: Minchan Kim <minchan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit 6539a36c0cb9ec7f1c1633b535ac83b2bdf0ae6d Author: Seth Jennings <sjenning@linux.vnet.ibm.com> Date: Wed Jul 18 11:55:54 2012 -0500 staging: zsmalloc: s/firstpage/page in new copy map funcs firstpage already has precedent and meaning the first page of a zspage. In the case of the copy mapping functions, it is the first of a pair of pages needing to be mapped. This patch just renames the firstpage argument to "page" to avoid confusion. Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com> Acked-by: Minchan Kim <minchan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit b74185108668ef966e663878adbad65e03bfcb43 Author: Seth Jennings <sjenning@linux.vnet.ibm.com> Date: Mon Jul 2 16:15:52 2012 -0500 staging: zsmalloc: add mapping modes This patch improves mapping performance in zsmalloc by getting usage information from the user in the form of a "mapping mode" and using it to avoid unnecessary copying for objects that span pages. Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit 166cfda752ca22eb6912614993b85f9a997dbd8f Author: Seth Jennings <sjenning@linux.vnet.ibm.com> Date: Mon Jul 2 16:15:51 2012 -0500 staging: zsmalloc: add details to zs_map_object boiler plate Add information on the usage limits of zs_map_object() Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit 103123305c4f695cbb11555d51a32ea14d6bed05 Author: Seth Jennings <sjenning@linux.vnet.ibm.com> Date: Mon Jul 2 16:15:50 2012 -0500 staging: zsmalloc: add single-page object fastpath in unmap Improve zs_unmap_object() performance by adding a fast path for objects that don't span pages. Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit 5f601902c61e6cda627ec71c10609021067ed0fa Author: Seth Jennings <sjenning@linux.vnet.ibm.com> Date: Mon Jul 2 16:15:49 2012 -0500 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> commit 069f101fa463351f528773d73b74e9b606b3f66a Author: Ben Hutchings <ben@decadent.org.uk> Date: Wed Jun 20 02:31:11 2012 +0100 staging: zsmalloc: Finish conversion to a separate module ZSMALLOC is tristate, but the code has no MODULE_LICENSE and since it depends on GPL-only symbols it cannot be loaded as a module. This in turn breaks zram which now depends on it. I assume it's meant to be Dual BSD/GPL like the other z-stuff. There is also no module_exit, which will make it impossible to unload. Add the appropriate module_init and module_exit declarations suggested by comments. Reported-by: Christian Ohm <chr.ohm@gmx.net> References: http://bugs.debian.org/677273 Cc: stable@vger.kernel.org # v3.4 Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit b4b700c5a61c6e6db976f60d4eb6ad369e838aa9 Author: Seth Jennings <sjenning@linux.vnet.ibm.com> Date: Wed Jun 13 16:03:42 2012 -0500 staging: zsmalloc: fix uninit'ed variable warning This patch fixes an uninitialized variable warning in alloc_zspage(). It also fixes the secondary issue of prev_page leaving scope on each loop iteration. The only reason this ever worked was because prev_page was occupying the same space on the stack on each iteration. Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com> Reported-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit 2db51dae56240b52fe08ddbb1a2eb47fe7cfd044 Author: Nitin Gupta <ngupta@vflare.org> Date: Sat Jun 9 17:41:14 2012 -0700 staging: zsmalloc documentation Documentation of various struct page fields used by zsmalloc. Changes for v2: - Regroup descriptions as suggested by Konrad Signed-off-by: Nitin Gupta <ngupta@vflare.org> Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Reviewed-by: Minchan Kim <minchan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit c234434835b1f4bad9bdbae6710044cba387c9e5 Author: Minchan Kim <minchan@kernel.org> Date: Fri Jun 8 15:39:25 2012 +0900 staging: zsmalloc: zsmalloc: use unsigned long instead of void * We should use unsigned long as handle instead of void * to avoid any confusion. Without this, users may just treat zs_malloc return value as a pointer and try to deference it. This patch passed compile test(zram, zcache and ramster) and zram is tested on qemu. changelog * from v2 - remove hval pointed out by Nitin - based on next-20120607 * from v1 - change zcache's zv_create return value - baesd on next-20120604 Cc: Dan Magenheimer <dan.magenheimer@oracle.com> Acked-by: Seth Jennings <sjenning@linux.vnet.ibm.com> Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Signed-off-by: Minchan Kim <minchan@kernel.org> Acked-by: Nitin Gupta <ngupta@vflare.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit 00a61d8618bb7314113eb3ba27c12631cd85c298 Author: Minchan Kim <minchan@kernel.org> Date: Thu May 3 15:40:40 2012 +0900 staging: zsmalloc: add/fix function comment Add/fix the comment. Signed-off-by: Minchan Kim <minchan@kernel.org> Acked-by: Nitin Gupta <ngupta@vflare.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit 2e3b61547191a5934ff6c789aaa4d7e9a9e52f5a Author: Minchan Kim <minchan@kernel.org> Date: Thu May 3 15:40:39 2012 +0900 staging: zsmalloc: rename zspage_order with zspage_pages zspage_order defines how many pages are needed to make a zspage. So _order_ is rather awkward naming. It already deceive Jonathan - http://lwn.net/Articles/477067/ " For each size, the code calculates an optimum number of pages (up to 16)" Let's change from _order_ to _pages_ and some function names. Signed-off-by: Minchan Kim <minchan@kernel.org> Acked-by: Nitin Gupta <ngupta@vflare.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit d210267741fb2a8b6d741d9040703683a39087f4 Merge: 69964ea 5bb196a Author: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Date: Wed May 2 11:48:07 2012 -0700 Merge 3.4-rc5 into staging-next This resolves the conflict in: drivers/staging/vt6656/ioctl.c Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> commit a27545bf0bab9027e5c040901b68956551d9f63e Author: Minchan Kim <minchan@kernel.org> Date: Wed Apr 25 15:23:09 2012 +0900 zsmalloc: use PageFlag macro instead of [set|test]_bit MM code always uses PageXXX to handle page flags. Let's keep the consistency. Signed-off-by: Minchan Kim <minchan@kernel.org> Acked-by: Nitin Gupta <ngupta@vflare.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Change-Id: I542f0b9eaf0264e1c9e38f9669fec8ea0debae7c Signed-off-by: Larry Bassel <lbassel@codeaurora.org>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/zsmalloc/Kconfig2
-rw-r--r--drivers/staging/zsmalloc/zsmalloc-main.c439
-rw-r--r--drivers/staging/zsmalloc/zsmalloc.h22
-rw-r--r--drivers/staging/zsmalloc/zsmalloc_int.h154
4 files changed, 383 insertions, 234 deletions
diff --git a/drivers/staging/zsmalloc/Kconfig b/drivers/staging/zsmalloc/Kconfig
index 90845656579..7fab032298f 100644
--- a/drivers/staging/zsmalloc/Kconfig
+++ b/drivers/staging/zsmalloc/Kconfig
@@ -1,5 +1,5 @@
config ZSMALLOC
- tristate "Memory allocator for compressed pages"
+ bool "Memory allocator for compressed pages"
default n
help
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 4cd0f04b76d..f82f7e69c8a 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -10,6 +10,54 @@
* Released under the terms of GNU General Public License Version 2.0
*/
+
+/*
+ * This allocator is designed for use with zcache and zram. Thus, the
+ * allocator is supposed to work well under low memory conditions. In
+ * particular, it never attempts higher order page allocation which is
+ * very likely to fail under memory pressure. On the other hand, if we
+ * just use single (0-order) pages, it would suffer from very high
+ * fragmentation -- any object of size PAGE_SIZE/2 or larger would occupy
+ * an entire page. This was one of the major issues with its predecessor
+ * (xvmalloc).
+ *
+ * To overcome these issues, zsmalloc allocates a bunch of 0-order pages
+ * and links them together using various 'struct page' fields. These linked
+ * pages act as a single higher-order page i.e. an object can span 0-order
+ * page boundaries. The code refers to these linked pages as a single entity
+ * called zspage.
+ *
+ * Following is how we use various fields and flags of underlying
+ * struct page(s) to form a zspage.
+ *
+ * Usage of struct page fields:
+ * page->first_page: points to the first component (0-order) page
+ * page->index (union with page->freelist): offset of the first object
+ * starting in this page. For the first page, this is
+ * always 0, so we use this field (aka freelist) to point
+ * to the first free object in zspage.
+ * page->lru: links together all component pages (except the first page)
+ * of a zspage
+ *
+ * For _first_ page only:
+ *
+ * page->private (union with page->first_page): refers to the
+ * component page after the first page
+ * page->freelist: points to the first free object in zspage.
+ * Free objects are linked together using in-place
+ * metadata.
+ * page->objects: maximum number of objects we can store in this
+ * zspage (class->zspage_order * PAGE_SIZE / class->size)
+ * page->lru: links together first pages of various zspages.
+ * Basically forming list of zspages in a fullness group.
+ * page->mapping: class index and fullness group of the zspage
+ *
+ * Usage of struct page flags:
+ * PG_private: identifies the first component page
+ * PG_private2: identifies the last component page
+ *
+ */
+
#ifdef CONFIG_ZSMALLOC_DEBUG
#define DEBUG
#endif
@@ -27,9 +75,139 @@
#include <linux/cpumask.h>
#include <linux/cpu.h>
#include <linux/vmalloc.h>
+#include <linux/hardirq.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
#include "zsmalloc.h"
-#include "zsmalloc_int.h"
+
+/*
+ * This must be power of 2 and greater than of equal to sizeof(link_free).
+ * These two conditions ensure that any 'struct link_free' itself doesn't
+ * span more than 1 page which avoids complex case of mapping 2 pages simply
+ * to restore link_free pointer values.
+ */
+#define ZS_ALIGN 8
+
+/*
+ * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
+ * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
+ */
+#define ZS_MAX_ZSPAGE_ORDER 2
+#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
+
+/*
+ * Object location (<PFN>, <obj_idx>) is encoded as
+ * as single (void *) handle value.
+ *
+ * Note that object index <obj_idx> is relative to system
+ * page <PFN> it is stored in, so for each sub-page belonging
+ * to a zspage, obj_idx starts with 0.
+ *
+ * This is made more complicated by various memory models and PAE.
+ */
+
+#ifndef MAX_PHYSMEM_BITS
+#ifdef CONFIG_HIGHMEM64G
+#define MAX_PHYSMEM_BITS 36
+#else /* !CONFIG_HIGHMEM64G */
+/*
+ * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
+ * be PAGE_SHIFT
+ */
+#define MAX_PHYSMEM_BITS BITS_PER_LONG
+#endif
+#endif
+#define _PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT)
+#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS)
+#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
+
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
+#define ZS_MIN_ALLOC_SIZE \
+ MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
+#define ZS_MAX_ALLOC_SIZE PAGE_SIZE
+
+/*
+ * On systems with 4K page size, this gives 254 size classes! There is a
+ * trader-off here:
+ * - Large number of size classes is potentially wasteful as free page are
+ * spread across these classes
+ * - Small number of size classes causes large internal fragmentation
+ * - Probably its better to use specific size classes (empirically
+ * determined). NOTE: all those class sizes must be set as multiple of
+ * ZS_ALIGN to make sure link_free itself never has to span 2 pages.
+ *
+ * ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
+ * (reason above)
+ */
+#define ZS_SIZE_CLASS_DELTA (PAGE_SIZE >> 8)
+#define ZS_SIZE_CLASSES ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
+ ZS_SIZE_CLASS_DELTA + 1)
+
+/*
+ * We do not maintain any list for completely empty or full pages
+ */
+enum fullness_group {
+ ZS_ALMOST_FULL,
+ ZS_ALMOST_EMPTY,
+ _ZS_NR_FULLNESS_GROUPS,
+
+ ZS_EMPTY,
+ ZS_FULL
+};
+
+/*
+ * We assign a page to ZS_ALMOST_EMPTY fullness group when:
+ * n <= N / f, where
+ * n = number of allocated objects
+ * N = total number of objects zspage can store
+ * f = 1/fullness_threshold_frac
+ *
+ * Similarly, we assign zspage to:
+ * ZS_ALMOST_FULL when n > N / f
+ * ZS_EMPTY when n == 0
+ * ZS_FULL when n == N
+ *
+ * (see: fix_fullness_group())
+ */
+static const int fullness_threshold_frac = 4;
+
+struct size_class {
+ /*
+ * Size of objects stored in this class. Must be multiple
+ * of ZS_ALIGN.
+ */
+ int size;
+ unsigned int index;
+
+ /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
+ int pages_per_zspage;
+
+ spinlock_t lock;
+
+ /* stats */
+ u64 pages_allocated;
+
+ struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
+};
+
+/*
+ * Placed within free objects to form a singly linked list.
+ * For every zspage, first_page->freelist gives head of this list.
+ *
+ * This must be power of 2 and less than or equal to ZS_ALIGN
+ */
+struct link_free {
+ /* Handle of next free chunk (encodes <PFN, obj_idx>) */
+ void *next;
+};
+
+struct zs_pool {
+ struct size_class size_class[ZS_SIZE_CLASSES];
+
+ gfp_t flags; /* allocation flags used when growing pool */
+};
/*
* A zspage's class index and fullness group
@@ -40,17 +218,39 @@
#define CLASS_IDX_MASK ((1 << CLASS_IDX_BITS) - 1)
#define FULLNESS_MASK ((1 << FULLNESS_BITS) - 1)
+/*
+ * By default, zsmalloc uses a copy-based object mapping method to access
+ * allocations that span two pages. However, if a particular architecture
+ * performs VM mapping faster than copying, then it should be added here
+ * so that USE_PGTABLE_MAPPING is defined. This causes zsmalloc to use
+ * page table mapping rather than copying for object mapping.
+*/
+#if defined(CONFIG_ARM) && !defined(MODULE)
+#define USE_PGTABLE_MAPPING
+#endif
+
+struct mapping_area {
+#ifdef USE_PGTABLE_MAPPING
+ struct vm_struct *vm; /* vm area for mapping object that span pages */
+#else
+ char *vm_buf; /* copy buffer for objects that span pages */
+#endif
+ char *vm_addr; /* address of kmap_atomic()'ed pages */
+ enum zs_mapmode vm_mm; /* mapping mode */
+};
+
+
/* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
static int is_first_page(struct page *page)
{
- return test_bit(PG_private, &page->flags);
+ return PagePrivate(page);
}
static int is_last_page(struct page *page)
{
- return test_bit(PG_private_2, &page->flags);
+ return PagePrivate2(page);
}
static void get_zspage_mapping(struct page *page, unsigned int *class_idx,
@@ -180,7 +380,7 @@ out:
* link together 3 PAGE_SIZE sized pages to form a zspage
* since then we can perfectly fit in 8 such objects.
*/
-static int get_zspage_order(int class_size)
+static int get_pages_per_zspage(int class_size)
{
int i, max_usedpc = 0;
/* zspage order which gives maximum used size per KB */
@@ -247,13 +447,11 @@ static void *obj_location_to_handle(struct page *page, unsigned long obj_idx)
}
/* Decode <page, obj_idx> pair from the given object handle */
-static void obj_handle_to_location(void *handle, struct page **page,
+static void obj_handle_to_location(unsigned long handle, struct page **page,
unsigned long *obj_idx)
{
- unsigned long hval = (unsigned long)handle;
-
- *page = pfn_to_page(hval >> OBJ_INDEX_BITS);
- *obj_idx = hval & OBJ_INDEX_MASK;
+ *page = pfn_to_page(handle >> OBJ_INDEX_BITS);
+ *obj_idx = handle & OBJ_INDEX_MASK;
}
static unsigned long obj_idx_to_offset(struct page *page,
@@ -274,7 +472,7 @@ static void reset_page(struct page *page)
set_page_private(page, 0);
page->mapping = NULL;
page->freelist = NULL;
- reset_page_mapcount(page);
+ page_mapcount_reset(page);
}
static void free_zspage(struct page *first_page)
@@ -354,7 +552,7 @@ static void init_zspage(struct page *first_page, struct size_class *class)
static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
{
int i, error;
- struct page *first_page = NULL;
+ struct page *first_page = NULL, *uninitialized_var(prev_page);
/*
* Allocate individual pages and link them together as:
@@ -368,8 +566,8 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
* identify the last page.
*/
error = -ENOMEM;
- for (i = 0; i < class->zspage_order; i++) {
- struct page *page, *prev_page;
+ for (i = 0; i < class->pages_per_zspage; i++) {
+ struct page *page;
page = alloc_page(flags);
if (!page)
@@ -377,7 +575,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
INIT_LIST_HEAD(&page->lru);
if (i == 0) { /* first page */
- set_bit(PG_private, &page->flags);
+ SetPagePrivate(page);
set_page_private(page, 0);
first_page = page;
first_page->inuse = 0;
@@ -388,9 +586,8 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
page->first_page = first_page;
if (i >= 2)
list_add(&page->lru, &prev_page->lru);
- if (i == class->zspage_order - 1) /* last page */
- set_bit(PG_private_2, &page->flags);
-
+ if (i == class->pages_per_zspage - 1) /* last page */
+ SetPagePrivate2(page);
prev_page = page;
}
@@ -398,7 +595,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
first_page->freelist = obj_location_to_handle(first_page, 0);
/* Maximum number of objects we can store in this zspage */
- first_page->objects = class->zspage_order * PAGE_SIZE / class->size;
+ first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size;
error = 0; /* Success */
@@ -425,23 +622,84 @@ static struct page *find_get_zspage(struct size_class *class)
return page;
}
-static void zs_copy_map_object(char *buf, struct page *firstpage,
- int off, int size)
+#ifdef USE_PGTABLE_MAPPING
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+ /*
+ * Make sure we don't leak memory if a cpu UP notification
+ * and zs_init() race and both call zs_cpu_up() on the same cpu
+ */
+ if (area->vm)
+ return 0;
+ area->vm = alloc_vm_area(PAGE_SIZE * 2, NULL);
+ if (!area->vm)
+ return -ENOMEM;
+ return 0;
+}
+
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+ if (area->vm)
+ free_vm_area(area->vm);
+ area->vm = NULL;
+}
+
+static inline void *__zs_map_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ BUG_ON(map_vm_area(area->vm, PAGE_KERNEL, &pages));
+ area->vm_addr = area->vm->addr;
+ return area->vm_addr + off;
+}
+
+static inline void __zs_unmap_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ unsigned long addr = (unsigned long)area->vm_addr;
+
+ unmap_kernel_range(addr, PAGE_SIZE * 2);
+}
+
+#else /* USE_PGTABLE_MAPPING */
+
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+ /*
+ * Make sure we don't leak memory if a cpu UP notification
+ * and zs_init() race and both call zs_cpu_up() on the same cpu
+ */
+ if (area->vm_buf)
+ return 0;
+ area->vm_buf = (char *)__get_free_page(GFP_KERNEL);
+ if (!area->vm_buf)
+ return -ENOMEM;
+ return 0;
+}
+
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+ if (area->vm_buf)
+ free_page((unsigned long)area->vm_buf);
+ area->vm_buf = NULL;
+}
+
+static void *__zs_map_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
{
- struct page *pages[2];
int sizes[2];
void *addr;
+ char *buf = area->vm_buf;
- pages[0] = firstpage;
- pages[1] = get_next_page(firstpage);
- BUG_ON(!pages[1]);
+ /* disable page faults to match kmap_atomic() return conditions */
+ pagefault_disable();
+
+ /* no read fastpath */
+ if (area->vm_mm == ZS_MM_WO)
+ goto out;
sizes[0] = PAGE_SIZE - off;
sizes[1] = size - sizes[0];
- /* disable page faults to match kmap_atomic() return conditions */
- pagefault_disable();
-
/* copy object to per-cpu buffer */
addr = kmap_atomic(pages[0]);
memcpy(buf, addr + off, sizes[0]);
@@ -449,18 +707,20 @@ static void zs_copy_map_object(char *buf, struct page *firstpage,
addr = kmap_atomic(pages[1]);
memcpy(buf + sizes[0], addr, sizes[1]);
kunmap_atomic(addr);
+out:
+ return area->vm_buf;
}
-static void zs_copy_unmap_object(char *buf, struct page *firstpage,
- int off, int size)
+static void __zs_unmap_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
{
- struct page *pages[2];
int sizes[2];
void *addr;
+ char *buf = area->vm_buf;
- pages[0] = firstpage;
- pages[1] = get_next_page(firstpage);
- BUG_ON(!pages[1]);
+ /* no write fastpath */
+ if (area->vm_mm == ZS_MM_RO)
+ goto out;
sizes[0] = PAGE_SIZE - off;
sizes[1] = size - sizes[0];
@@ -473,36 +733,30 @@ static void zs_copy_unmap_object(char *buf, struct page *firstpage,
memcpy(addr, buf + sizes[0], sizes[1]);
kunmap_atomic(addr);
+out:
/* enable page faults to match kunmap_atomic() return conditions */
pagefault_enable();
}
+#endif /* USE_PGTABLE_MAPPING */
+
static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action,
void *pcpu)
{
- int cpu = (long)pcpu;
+ int ret, cpu = (long)pcpu;
struct mapping_area *area;
switch (action) {
case CPU_UP_PREPARE:
area = &per_cpu(zs_map_area, cpu);
- /*
- * Make sure we don't leak memory if a cpu UP notification
- * and zs_init() race and both call zs_cpu_up() on the same cpu
- */
- if (area->vm_buf)
- return 0;
- area->vm_buf = (char *)__get_free_page(GFP_KERNEL);
- if (!area->vm_buf)
- return -ENOMEM;
- return 0;
+ ret = __zs_cpu_up(area);
+ if (ret)
+ return notifier_from_errno(ret);
break;
case CPU_DEAD:
case CPU_UP_CANCELED:
area = &per_cpu(zs_map_area, cpu);
- if (area->vm_buf)
- free_page((unsigned long)area->vm_buf);
- area->vm_buf = NULL;
+ __zs_cpu_down(area);
break;
}
@@ -538,14 +792,21 @@ fail:
return notifier_to_errno(ret);
}
-struct zs_pool *zs_create_pool(const char *name, gfp_t flags)
+/**
+ * zs_create_pool - Creates an allocation pool to work from.
+ * @flags: allocation flags used to allocate pool metadata
+ *
+ * This function must be called before anything when using
+ * the zsmalloc allocator.
+ *
+ * On success, a pointer to the newly created pool is returned,
+ * otherwise NULL.
+ */
+struct zs_pool *zs_create_pool(gfp_t flags)
{
int i, ovhd_size;
struct zs_pool *pool;
- if (!name)
- return NULL;
-
ovhd_size = roundup(sizeof(*pool), PAGE_SIZE);
pool = kzalloc(ovhd_size, GFP_KERNEL);
if (!pool)
@@ -563,12 +824,11 @@ struct zs_pool *zs_create_pool(const char *name, gfp_t flags)
class->size = size;
class->index = i;
spin_lock_init(&class->lock);
- class->zspage_order = get_zspage_order(size);
+ class->pages_per_zspage = get_pages_per_zspage(size);
}
pool->flags = flags;
- pool->name = name;
return pool;
}
@@ -598,18 +858,14 @@ EXPORT_SYMBOL_GPL(zs_destroy_pool);
* zs_malloc - Allocate block of given size from pool.
* @pool: pool to allocate from
* @size: size of block to allocate
- * @page: page no. that holds the object
- * @offset: location of object within page
- *
- * On success, <page, offset> identifies block allocated
- * and 0 is returned. On failure, <page, offset> is set to
- * 0 and -ENOMEM is returned.
*
+ * On success, handle to the allocated object is returned,
+ * otherwise 0.
* Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
*/
-void *zs_malloc(struct zs_pool *pool, size_t size)
+unsigned long zs_malloc(struct zs_pool *pool, size_t size)
{
- void *obj;
+ unsigned long obj;
struct link_free *link;
int class_idx;
struct size_class *class;
@@ -618,7 +874,7 @@ void *zs_malloc(struct zs_pool *pool, size_t size)
unsigned long m_objidx, m_offset;
if (unlikely(!size || size > ZS_MAX_ALLOC_SIZE))
- return NULL;
+ return 0;
class_idx = get_size_class_index(size);
class = &pool->size_class[class_idx];
@@ -631,14 +887,14 @@ void *zs_malloc(struct zs_pool *pool, size_t size)
spin_unlock(&class->lock);
first_page = alloc_zspage(class, pool->flags);
if (unlikely(!first_page))
- return NULL;
+ return 0;
set_zspage_mapping(first_page, class->index, ZS_EMPTY);
spin_lock(&class->lock);
- class->pages_allocated += class->zspage_order;
+ class->pages_allocated += class->pages_per_zspage;
}
- obj = first_page->freelist;
+ obj = (unsigned long)first_page->freelist;
obj_handle_to_location(obj, &m_page, &m_objidx);
m_offset = obj_idx_to_offset(m_page, m_objidx, class->size);
@@ -657,7 +913,7 @@ void *zs_malloc(struct zs_pool *pool, size_t size)
}
EXPORT_SYMBOL_GPL(zs_malloc);
-void zs_free(struct zs_pool *pool, void *obj)
+void zs_free(struct zs_pool *pool, unsigned long obj)
{
struct link_free *link;
struct page *first_page, *f_page;
@@ -684,13 +940,13 @@ void zs_free(struct zs_pool *pool, void *obj)
+ f_offset);
link->next = first_page->freelist;
kunmap_atomic(link);
- first_page->freelist = obj;
+ first_page->freelist = (void *)obj;
first_page->inuse--;
fullness = fix_fullness_group(pool, first_page);
if (fullness == ZS_EMPTY)
- class->pages_allocated -= class->zspage_order;
+ class->pages_allocated -= class->pages_per_zspage;
spin_unlock(&class->lock);
@@ -699,7 +955,22 @@ void zs_free(struct zs_pool *pool, void *obj)
}
EXPORT_SYMBOL_GPL(zs_free);
-void *zs_map_object(struct zs_pool *pool, void *handle)
+/**
+ * zs_map_object - get address of allocated object from handle.
+ * @pool: pool from which the object was allocated
+ * @handle: handle returned from zs_malloc
+ *
+ * Before using an object allocated from zs_malloc, it must be mapped using
+ * this function. When done with the object, it must be unmapped using
+ * zs_unmap_object.
+ *
+ * Only one object can be mapped per cpu at a time. There is no protection
+ * against nested mappings.
+ *
+ * This function returns with preemption and page faults disabled.
+*/
+void *zs_map_object(struct zs_pool *pool, unsigned long handle,
+ enum zs_mapmode mm)
{
struct page *page;
unsigned long obj_idx, off;
@@ -708,27 +979,40 @@ void *zs_map_object(struct zs_pool *pool, void *handle)
enum fullness_group fg;
struct size_class *class;
struct mapping_area *area;
+ struct page *pages[2];
BUG_ON(!handle);
+ /*
+ * Because we use per-cpu mapping areas shared among the
+ * pools/users, we can't allow mapping in interrupt context
+ * because it can corrupt another users mappings.
+ */
+ BUG_ON(in_interrupt());
+
obj_handle_to_location(handle, &page, &obj_idx);
get_zspage_mapping(get_first_page(page), &class_idx, &fg);
class = &pool->size_class[class_idx];
off = obj_idx_to_offset(page, obj_idx, class->size);
area = &get_cpu_var(zs_map_area);
+ area->vm_mm = mm;
if (off + class->size <= PAGE_SIZE) {
/* this object is contained entirely within a page */
area->vm_addr = kmap_atomic(page);
return area->vm_addr + off;
}
- zs_copy_map_object(area->vm_buf, page, off, class->size);
- return area->vm_buf;
+ /* this object spans two pages */
+ pages[0] = page;
+ pages[1] = get_next_page(page);
+ BUG_ON(!pages[1]);
+
+ return __zs_map_object(area, pages, off, class->size);
}
EXPORT_SYMBOL_GPL(zs_map_object);
-void zs_unmap_object(struct zs_pool *pool, void *handle)
+void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
{
struct page *page;
unsigned long obj_idx, off;
@@ -748,8 +1032,15 @@ void zs_unmap_object(struct zs_pool *pool, void *handle)
area = &__get_cpu_var(zs_map_area);
if (off + class->size <= PAGE_SIZE)
kunmap_atomic(area->vm_addr);
- else
- zs_copy_unmap_object(area->vm_buf, page, off, class->size);
+ else {
+ struct page *pages[2];
+
+ pages[0] = page;
+ pages[1] = get_next_page(page);
+ BUG_ON(!pages[1]);
+
+ __zs_unmap_object(area, pages, off, class->size);
+ }
put_cpu_var(zs_map_area);
}
EXPORT_SYMBOL_GPL(zs_unmap_object);
diff --git a/drivers/staging/zsmalloc/zsmalloc.h b/drivers/staging/zsmalloc/zsmalloc.h
index 949384ee749..46dbd0558d8 100644
--- a/drivers/staging/zsmalloc/zsmalloc.h
+++ b/drivers/staging/zsmalloc/zsmalloc.h
@@ -15,16 +15,28 @@
#include <linux/types.h>
+/*
+ * zsmalloc mapping modes
+ *
+ * NOTE: These only make a difference when a mapped object spans pages
+*/
+enum zs_mapmode {
+ ZS_MM_RW, /* normal read-write mapping */
+ ZS_MM_RO, /* read-only (no copy-out at unmap time) */
+ ZS_MM_WO /* write-only (no copy-in at map time) */
+};
+
struct zs_pool;
-struct zs_pool *zs_create_pool(const char *name, gfp_t flags);
+struct zs_pool *zs_create_pool(gfp_t flags);
void zs_destroy_pool(struct zs_pool *pool);
-void *zs_malloc(struct zs_pool *pool, size_t size);
-void zs_free(struct zs_pool *pool, void *obj);
+unsigned long zs_malloc(struct zs_pool *pool, size_t size);
+void zs_free(struct zs_pool *pool, unsigned long obj);
-void *zs_map_object(struct zs_pool *pool, void *handle);
-void zs_unmap_object(struct zs_pool *pool, void *handle);
+void *zs_map_object(struct zs_pool *pool, unsigned long handle,
+ enum zs_mapmode mm);
+void zs_unmap_object(struct zs_pool *pool, unsigned long handle);
u64 zs_get_total_size_bytes(struct zs_pool *pool);
diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h b/drivers/staging/zsmalloc/zsmalloc_int.h
deleted file mode 100644
index a6f3109c45d..00000000000
--- a/drivers/staging/zsmalloc/zsmalloc_int.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * zsmalloc memory allocator
- *
- * Copyright (C) 2011 Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the license that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- */
-
-#ifndef _ZS_MALLOC_INT_H_
-#define _ZS_MALLOC_INT_H_
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-/*
- * This must be power of 2 and greater than of equal to sizeof(link_free).
- * These two conditions ensure that any 'struct link_free' itself doesn't
- * span more than 1 page which avoids complex case of mapping 2 pages simply
- * to restore link_free pointer values.
- */
-#define ZS_ALIGN 8
-
-/*
- * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
- * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
- */
-#define ZS_MAX_ZSPAGE_ORDER 2
-#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
-
-/*
- * Object location (<PFN>, <obj_idx>) is encoded as
- * as single (void *) handle value.
- *
- * Note that object index <obj_idx> is relative to system
- * page <PFN> it is stored in, so for each sub-page belonging
- * to a zspage, obj_idx starts with 0.
- *
- * This is made more complicated by various memory models and PAE.
- */
-
-#ifndef MAX_PHYSMEM_BITS
-#ifdef CONFIG_HIGHMEM64G
-#define MAX_PHYSMEM_BITS 36
-#else /* !CONFIG_HIGHMEM64G */
-/*
- * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
- * be PAGE_SHIFT
- */
-#define MAX_PHYSMEM_BITS BITS_PER_LONG
-#endif
-#endif
-#define _PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT)
-#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS)
-#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
-
-#define MAX(a, b) ((a) >= (b) ? (a) : (b))
-/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
-#define ZS_MIN_ALLOC_SIZE \
- MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
-#define ZS_MAX_ALLOC_SIZE PAGE_SIZE
-
-/*
- * On systems with 4K page size, this gives 254 size classes! There is a
- * trader-off here:
- * - Large number of size classes is potentially wasteful as free page are
- * spread across these classes
- * - Small number of size classes causes large internal fragmentation
- * - Probably its better to use specific size classes (empirically
- * determined). NOTE: all those class sizes must be set as multiple of
- * ZS_ALIGN to make sure link_free itself never has to span 2 pages.
- *
- * ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
- * (reason above)
- */
-#define ZS_SIZE_CLASS_DELTA 16
-#define ZS_SIZE_CLASSES ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
- ZS_SIZE_CLASS_DELTA + 1)
-
-/*
- * We do not maintain any list for completely empty or full pages
- */
-enum fullness_group {
- ZS_ALMOST_FULL,
- ZS_ALMOST_EMPTY,
- _ZS_NR_FULLNESS_GROUPS,
-
- ZS_EMPTY,
- ZS_FULL
-};
-
-/*
- * We assign a page to ZS_ALMOST_EMPTY fullness group when:
- * n <= N / f, where
- * n = number of allocated objects
- * N = total number of objects zspage can store
- * f = 1/fullness_threshold_frac
- *
- * Similarly, we assign zspage to:
- * ZS_ALMOST_FULL when n > N / f
- * ZS_EMPTY when n == 0
- * ZS_FULL when n == N
- *
- * (see: fix_fullness_group())
- */
-static const int fullness_threshold_frac = 4;
-
-struct mapping_area {
- char *vm_buf; /* copy buffer for objects that span pages */
- char *vm_addr; /* address of kmap_atomic()'ed pages */
-};
-
-struct size_class {
- /*
- * Size of objects stored in this class. Must be multiple
- * of ZS_ALIGN.
- */
- int size;
- unsigned int index;
-
- /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
- int zspage_order;
-
- spinlock_t lock;
-
- /* stats */
- u64 pages_allocated;
-
- struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
-};
-
-/*
- * Placed within free objects to form a singly linked list.
- * For every zspage, first_page->freelist gives head of this list.
- *
- * This must be power of 2 and less than or equal to ZS_ALIGN
- */
-struct link_free {
- /* Handle of next free chunk (encodes <PFN, obj_idx>) */
- void *next;
-};
-
-struct zs_pool {
- struct size_class size_class[ZS_SIZE_CLASSES];
-
- gfp_t flags; /* allocation flags used when growing pool */
- const char *name;
-};
-
-#endif