aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorDan Streetman <ddstreet@ieee.org>2014-08-06 19:08:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-06 21:01:23 -0400
commitaf8d417a04564bca0348e7e3c749ab12a3e837ad (patch)
treece222a9643ba4a0afa675ed1f2d1b1447ec5174b /mm
parent99eef8e9369abe009006b4fa7f6ca5086c09cf46 (diff)
mm/zpool: implement common zpool api to zbud/zsmalloc
Add zpool api. zpool provides an interface for memory storage, typically of compressed memory. Users can select what backend to use; currently the only implementations are zbud, a low density implementation with up to two compressed pages per storage page, and zsmalloc, a higher density implementation with multiple compressed pages per storage page. Signed-off-by: Dan Streetman <ddstreet@ieee.org> Tested-by: Seth Jennings <sjennings@variantweb.net> Cc: Minchan Kim <minchan@kernel.org> Cc: Nitin Gupta <ngupta@vflare.org> Cc: Weijie Yang <weijie.yang@samsung.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/Kconfig41
-rw-r--r--mm/Makefile1
-rw-r--r--mm/zpool.c364
-rw-r--r--mm/zsmalloc.c1
4 files changed, 389 insertions, 18 deletions
diff --git a/mm/Kconfig b/mm/Kconfig
index f4899ec39cf4..12179b8c3b89 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -519,15 +519,17 @@ config CMA_AREAS
519 519
520 If unsure, leave the default value "7". 520 If unsure, leave the default value "7".
521 521
522config ZBUD 522config MEM_SOFT_DIRTY
523 tristate 523 bool "Track memory changes"
524 default n 524 depends on CHECKPOINT_RESTORE && HAVE_ARCH_SOFT_DIRTY && PROC_FS
525 select PROC_PAGE_MONITOR
525 help 526 help
526 A special purpose allocator for storing compressed pages. 527 This option enables memory changes tracking by introducing a
527 It is designed to store up to two compressed pages per physical 528 soft-dirty bit on pte-s. This bit it set when someone writes
528 page. While this design limits storage density, it has simple and 529 into a page just as regular dirty bit, but unlike the latter
529 deterministic reclaim properties that make it preferable to a higher 530 it can be cleared by hands.
530 density approach when reclaim will be used. 531
532 See Documentation/vm/soft-dirty.txt for more details.
531 533
532config ZSWAP 534config ZSWAP
533 bool "Compressed cache for swap pages (EXPERIMENTAL)" 535 bool "Compressed cache for swap pages (EXPERIMENTAL)"
@@ -549,17 +551,22 @@ config ZSWAP
549 they have not be fully explored on the large set of potential 551 they have not be fully explored on the large set of potential
550 configurations and workloads that exist. 552 configurations and workloads that exist.
551 553
552config MEM_SOFT_DIRTY 554config ZPOOL
553 bool "Track memory changes" 555 tristate "Common API for compressed memory storage"
554 depends on CHECKPOINT_RESTORE && HAVE_ARCH_SOFT_DIRTY && PROC_FS 556 default n
555 select PROC_PAGE_MONITOR
556 help 557 help
557 This option enables memory changes tracking by introducing a 558 Compressed memory storage API. This allows using either zbud or
558 soft-dirty bit on pte-s. This bit it set when someone writes 559 zsmalloc.
559 into a page just as regular dirty bit, but unlike the latter
560 it can be cleared by hands.
561 560
562 See Documentation/vm/soft-dirty.txt for more details. 561config ZBUD
562 tristate "Low density storage for compressed pages"
563 default n
564 help
565 A special purpose allocator for storing compressed pages.
566 It is designed to store up to two compressed pages per physical
567 page. While this design limits storage density, it has simple and
568 deterministic reclaim properties that make it preferable to a higher
569 density approach when reclaim will be used.
563 570
564config ZSMALLOC 571config ZSMALLOC
565 tristate "Memory allocator for compressed pages" 572 tristate "Memory allocator for compressed pages"
diff --git a/mm/Makefile b/mm/Makefile
index 8338473c329a..632ae77e6070 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o
59obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o 59obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o
60obj-$(CONFIG_CLEANCACHE) += cleancache.o 60obj-$(CONFIG_CLEANCACHE) += cleancache.o
61obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o 61obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o
62obj-$(CONFIG_ZPOOL) += zpool.o
62obj-$(CONFIG_ZBUD) += zbud.o 63obj-$(CONFIG_ZBUD) += zbud.o
63obj-$(CONFIG_ZSMALLOC) += zsmalloc.o 64obj-$(CONFIG_ZSMALLOC) += zsmalloc.o
64obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o 65obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o
diff --git a/mm/zpool.c b/mm/zpool.c
new file mode 100644
index 000000000000..e40612a1df00
--- /dev/null
+++ b/mm/zpool.c
@@ -0,0 +1,364 @@
1/*
2 * zpool memory storage api
3 *
4 * Copyright (C) 2014 Dan Streetman
5 *
6 * This is a common frontend for memory storage pool implementations.
7 * Typically, this is used to store compressed memory.
8 */
9
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
12#include <linux/list.h>
13#include <linux/types.h>
14#include <linux/mm.h>
15#include <linux/slab.h>
16#include <linux/spinlock.h>
17#include <linux/module.h>
18#include <linux/zpool.h>
19
20struct zpool {
21 char *type;
22
23 struct zpool_driver *driver;
24 void *pool;
25 struct zpool_ops *ops;
26
27 struct list_head list;
28};
29
30static LIST_HEAD(drivers_head);
31static DEFINE_SPINLOCK(drivers_lock);
32
33static LIST_HEAD(pools_head);
34static DEFINE_SPINLOCK(pools_lock);
35
36/**
37 * zpool_register_driver() - register a zpool implementation.
38 * @driver: driver to register
39 */
40void zpool_register_driver(struct zpool_driver *driver)
41{
42 spin_lock(&drivers_lock);
43 atomic_set(&driver->refcount, 0);
44 list_add(&driver->list, &drivers_head);
45 spin_unlock(&drivers_lock);
46}
47EXPORT_SYMBOL(zpool_register_driver);
48
49/**
50 * zpool_unregister_driver() - unregister a zpool implementation.
51 * @driver: driver to unregister.
52 *
53 * Module usage counting is used to prevent using a driver
54 * while/after unloading, so if this is called from module
55 * exit function, this should never fail; if called from
56 * other than the module exit function, and this returns
57 * failure, the driver is in use and must remain available.
58 */
59int zpool_unregister_driver(struct zpool_driver *driver)
60{
61 int ret = 0, refcount;
62
63 spin_lock(&drivers_lock);
64 refcount = atomic_read(&driver->refcount);
65 WARN_ON(refcount < 0);
66 if (refcount > 0)
67 ret = -EBUSY;
68 else
69 list_del(&driver->list);
70 spin_unlock(&drivers_lock);
71
72 return ret;
73}
74EXPORT_SYMBOL(zpool_unregister_driver);
75
76/**
77 * zpool_evict() - evict callback from a zpool implementation.
78 * @pool: pool to evict from.
79 * @handle: handle to evict.
80 *
81 * This can be used by zpool implementations to call the
82 * user's evict zpool_ops struct evict callback.
83 */
84int zpool_evict(void *pool, unsigned long handle)
85{
86 struct zpool *zpool;
87
88 spin_lock(&pools_lock);
89 list_for_each_entry(zpool, &pools_head, list) {
90 if (zpool->pool == pool) {
91 spin_unlock(&pools_lock);
92 if (!zpool->ops || !zpool->ops->evict)
93 return -EINVAL;
94 return zpool->ops->evict(zpool, handle);
95 }
96 }
97 spin_unlock(&pools_lock);
98
99 return -ENOENT;
100}
101EXPORT_SYMBOL(zpool_evict);
102
103static struct zpool_driver *zpool_get_driver(char *type)
104{
105 struct zpool_driver *driver;
106
107 spin_lock(&drivers_lock);
108 list_for_each_entry(driver, &drivers_head, list) {
109 if (!strcmp(driver->type, type)) {
110 bool got = try_module_get(driver->owner);
111
112 if (got)
113 atomic_inc(&driver->refcount);
114 spin_unlock(&drivers_lock);
115 return got ? driver : NULL;
116 }
117 }
118
119 spin_unlock(&drivers_lock);
120 return NULL;
121}
122
123static void zpool_put_driver(struct zpool_driver *driver)
124{
125 atomic_dec(&driver->refcount);
126 module_put(driver->owner);
127}
128
129/**
130 * zpool_create_pool() - Create a new zpool
131 * @type The type of the zpool to create (e.g. zbud, zsmalloc)
132 * @gfp The GFP flags to use when allocating the pool.
133 * @ops The optional ops callback.
134 *
135 * This creates a new zpool of the specified type. The gfp flags will be
136 * used when allocating memory, if the implementation supports it. If the
137 * ops param is NULL, then the created zpool will not be shrinkable.
138 *
139 * Implementations must guarantee this to be thread-safe.
140 *
141 * Returns: New zpool on success, NULL on failure.
142 */
143struct zpool *zpool_create_pool(char *type, gfp_t gfp, struct zpool_ops *ops)
144{
145 struct zpool_driver *driver;
146 struct zpool *zpool;
147
148 pr_info("creating pool type %s\n", type);
149
150 driver = zpool_get_driver(type);
151
152 if (!driver) {
153 request_module(type);
154 driver = zpool_get_driver(type);
155 }
156
157 if (!driver) {
158 pr_err("no driver for type %s\n", type);
159 return NULL;
160 }
161
162 zpool = kmalloc(sizeof(*zpool), gfp);
163 if (!zpool) {
164 pr_err("couldn't create zpool - out of memory\n");
165 zpool_put_driver(driver);
166 return NULL;
167 }
168
169 zpool->type = driver->type;
170 zpool->driver = driver;
171 zpool->pool = driver->create(gfp, ops);
172 zpool->ops = ops;
173
174 if (!zpool->pool) {
175 pr_err("couldn't create %s pool\n", type);
176 zpool_put_driver(driver);
177 kfree(zpool);
178 return NULL;
179 }
180
181 pr_info("created %s pool\n", type);
182
183 spin_lock(&pools_lock);
184 list_add(&zpool->list, &pools_head);
185 spin_unlock(&pools_lock);
186
187 return zpool;
188}
189
190/**
191 * zpool_destroy_pool() - Destroy a zpool
192 * @pool The zpool to destroy.
193 *
194 * Implementations must guarantee this to be thread-safe,
195 * however only when destroying different pools. The same
196 * pool should only be destroyed once, and should not be used
197 * after it is destroyed.
198 *
199 * This destroys an existing zpool. The zpool should not be in use.
200 */
201void zpool_destroy_pool(struct zpool *zpool)
202{
203 pr_info("destroying pool type %s\n", zpool->type);
204
205 spin_lock(&pools_lock);
206 list_del(&zpool->list);
207 spin_unlock(&pools_lock);
208 zpool->driver->destroy(zpool->pool);
209 zpool_put_driver(zpool->driver);
210 kfree(zpool);
211}
212
213/**
214 * zpool_get_type() - Get the type of the zpool
215 * @pool The zpool to check
216 *
217 * This returns the type of the pool.
218 *
219 * Implementations must guarantee this to be thread-safe.
220 *
221 * Returns: The type of zpool.
222 */
223char *zpool_get_type(struct zpool *zpool)
224{
225 return zpool->type;
226}
227
228/**
229 * zpool_malloc() - Allocate memory
230 * @pool The zpool to allocate from.
231 * @size The amount of memory to allocate.
232 * @gfp The GFP flags to use when allocating memory.
233 * @handle Pointer to the handle to set
234 *
235 * This allocates the requested amount of memory from the pool.
236 * The gfp flags will be used when allocating memory, if the
237 * implementation supports it. The provided @handle will be
238 * set to the allocated object handle.
239 *
240 * Implementations must guarantee this to be thread-safe.
241 *
242 * Returns: 0 on success, negative value on error.
243 */
244int zpool_malloc(struct zpool *zpool, size_t size, gfp_t gfp,
245 unsigned long *handle)
246{
247 return zpool->driver->malloc(zpool->pool, size, gfp, handle);
248}
249
250/**
251 * zpool_free() - Free previously allocated memory
252 * @pool The zpool that allocated the memory.
253 * @handle The handle to the memory to free.
254 *
255 * This frees previously allocated memory. This does not guarantee
256 * that the pool will actually free memory, only that the memory
257 * in the pool will become available for use by the pool.
258 *
259 * Implementations must guarantee this to be thread-safe,
260 * however only when freeing different handles. The same
261 * handle should only be freed once, and should not be used
262 * after freeing.
263 */
264void zpool_free(struct zpool *zpool, unsigned long handle)
265{
266 zpool->driver->free(zpool->pool, handle);
267}
268
269/**
270 * zpool_shrink() - Shrink the pool size
271 * @pool The zpool to shrink.
272 * @pages The number of pages to shrink the pool.
273 * @reclaimed The number of pages successfully evicted.
274 *
275 * This attempts to shrink the actual memory size of the pool
276 * by evicting currently used handle(s). If the pool was
277 * created with no zpool_ops, or the evict call fails for any
278 * of the handles, this will fail. If non-NULL, the @reclaimed
279 * parameter will be set to the number of pages reclaimed,
280 * which may be more than the number of pages requested.
281 *
282 * Implementations must guarantee this to be thread-safe.
283 *
284 * Returns: 0 on success, negative value on error/failure.
285 */
286int zpool_shrink(struct zpool *zpool, unsigned int pages,
287 unsigned int *reclaimed)
288{
289 return zpool->driver->shrink(zpool->pool, pages, reclaimed);
290}
291
292/**
293 * zpool_map_handle() - Map a previously allocated handle into memory
294 * @pool The zpool that the handle was allocated from
295 * @handle The handle to map
296 * @mm How the memory should be mapped
297 *
298 * This maps a previously allocated handle into memory. The @mm
299 * param indicates to the implementation how the memory will be
300 * used, i.e. read-only, write-only, read-write. If the
301 * implementation does not support it, the memory will be treated
302 * as read-write.
303 *
304 * This may hold locks, disable interrupts, and/or preemption,
305 * and the zpool_unmap_handle() must be called to undo those
306 * actions. The code that uses the mapped handle should complete
307 * its operatons on the mapped handle memory quickly and unmap
308 * as soon as possible. As the implementation may use per-cpu
309 * data, multiple handles should not be mapped concurrently on
310 * any cpu.
311 *
312 * Returns: A pointer to the handle's mapped memory area.
313 */
314void *zpool_map_handle(struct zpool *zpool, unsigned long handle,
315 enum zpool_mapmode mapmode)
316{
317 return zpool->driver->map(zpool->pool, handle, mapmode);
318}
319
320/**
321 * zpool_unmap_handle() - Unmap a previously mapped handle
322 * @pool The zpool that the handle was allocated from
323 * @handle The handle to unmap
324 *
325 * This unmaps a previously mapped handle. Any locks or other
326 * actions that the implementation took in zpool_map_handle()
327 * will be undone here. The memory area returned from
328 * zpool_map_handle() should no longer be used after this.
329 */
330void zpool_unmap_handle(struct zpool *zpool, unsigned long handle)
331{
332 zpool->driver->unmap(zpool->pool, handle);
333}
334
335/**
336 * zpool_get_total_size() - The total size of the pool
337 * @pool The zpool to check
338 *
339 * This returns the total size in bytes of the pool.
340 *
341 * Returns: Total size of the zpool in bytes.
342 */
343u64 zpool_get_total_size(struct zpool *zpool)
344{
345 return zpool->driver->total_size(zpool->pool);
346}
347
348static int __init init_zpool(void)
349{
350 pr_info("loaded\n");
351 return 0;
352}
353
354static void __exit exit_zpool(void)
355{
356 pr_info("unloaded\n");
357}
358
359module_init(init_zpool);
360module_exit(exit_zpool);
361
362MODULE_LICENSE("GPL");
363MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>");
364MODULE_DESCRIPTION("Common API for compressed memory storage");
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index bb62a4adc328..6a1827d3d231 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -240,7 +240,6 @@ struct mapping_area {
240 enum zs_mapmode vm_mm; /* mapping mode */ 240 enum zs_mapmode vm_mm; /* mapping mode */
241}; 241};
242 242
243
244/* per-cpu VM mapping areas for zspage accesses that cross page boundaries */ 243/* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
245static DEFINE_PER_CPU(struct mapping_area, zs_map_area); 244static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
246 245