aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/zram/zcomp.c
diff options
context:
space:
mode:
authorSergey Senozhatsky <sergey.senozhatsky@gmail.com>2014-04-07 18:38:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-07 19:36:01 -0400
commite7e1ef439d18f9a21521116ea9f2b976d7230e54 (patch)
treed2fdf62288f623b21f54ec255ae79bb0584c76bc /drivers/block/zram/zcomp.c
parentb67d1ec189ffb92cdad9b2bd29475fb1e0166983 (diff)
zram: introduce compressing backend abstraction
ZRAM performs direct LZO compression algorithm calls, making it the one and only option. While LZO is generally performs well, LZ4 algorithm tends to have a faster decompression (see http://code.google.com/p/lz4/ for full report) Name Ratio C.speed D.speed MB/s MB/s LZ4 (r101) 2.084 422 1820 LZO 2.06 2.106 414 600 Thus, users who have mostly read (decompress) usage scenarious or mixed workflow (writes with relatively high read ops number) will benefit from using LZ4 compression backend. Introduce compressing backend abstraction zcomp in order to support multiple compression algorithms with the following set of operations: .create .destroy .compress .decompress Schematically zram write() usually contains the following steps: 0) preparation (decompression of partioal IO, etc.) 1) lock buffer_lock mutex (protects meta compress buffers) 2) compress (using meta compress buffers) 3) alloc and map zs_pool object 4) copy compressed data (from meta compress buffers) to object allocated by 3) 5) free previous pool page, assign a new one 6) unlock buffer_lock mutex As we can see, compressing buffers must remain untouched from 1) to 4), because, otherwise, concurrent write() can overwrite data. At the same time, zram_meta must be aware of a) specific compression algorithm memory requirements and b) necessary locking to protect compression buffers. To remove requirement a) new struct zcomp_strm introduced, which contains a compress/decompress `buffer' and compression algorithm `private' part. While struct zcomp implements zcomp_strm stream handling and locking and removes requirement b) from zram meta. zcomp ->create() and ->destroy(), respectively, allocate and deallocate algorithm specific zcomp_strm `private' part. Every zcomp has zcomp stream and mutex to protect its compression stream. Stream usage semantics remains the same -- only one write can hold stream lock and use its buffers. zcomp_strm_find() turns caller into exclusive user of a stream (holding stream mutex until zram release stream), and zcomp_strm_release() makes zcomp stream available (unlock the stream mutex). Hence no concurrent write (compression) operations possible at the moment. iozone -t 3 -R -r 16K -s 60M -I +Z test base patched -------------------------------------------------- Initial write 597992.91 591660.58 Rewrite 609674.34 616054.97 Read 2404771.75 2452909.12 Re-read 2459216.81 2470074.44 Reverse Read 1652769.66 1589128.66 Stride read 2202441.81 2202173.31 Random read 2236311.47 2276565.31 Mixed workload 1423760.41 1709760.06 Random write 579584.08 615933.86 Pwrite 597550.02 594933.70 Pread 1703672.53 1718126.72 Fwrite 1330497.06 1461054.00 Fread 3922851.00 3957242.62 Usage examples: comp = zcomp_create(NAME) /* NAME e.g. "lzo" */ which initialises compressing backend if requested algorithm is supported. Compress: zstrm = zcomp_strm_find(comp) zcomp_compress(comp, zstrm, src, &dst_len) [..] /* copy compressed data */ zcomp_strm_release(comp, zstrm) Decompress: zcomp_decompress(comp, src, src_len, dst); Free compessing backend and its zcomp stream: zcomp_destroy(comp) Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Acked-by: Minchan Kim <minchan@kernel.org> Cc: Jerome Marchand <jmarchan@redhat.com> Cc: Nitin Gupta <ngupta@vflare.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/block/zram/zcomp.c')
-rw-r--r--drivers/block/zram/zcomp.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
new file mode 100644
index 000000000000..22f4ae235660
--- /dev/null
+++ b/drivers/block/zram/zcomp.c
@@ -0,0 +1,115 @@
1/*
2 * Copyright (C) 2014 Sergey Senozhatsky.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include <linux/kernel.h>
11#include <linux/string.h>
12#include <linux/slab.h>
13#include <linux/wait.h>
14#include <linux/sched.h>
15
16#include "zcomp.h"
17#include "zcomp_lzo.h"
18
19static struct zcomp_backend *find_backend(const char *compress)
20{
21 if (strncmp(compress, "lzo", 3) == 0)
22 return &zcomp_lzo;
23 return NULL;
24}
25
26static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
27{
28 if (zstrm->private)
29 comp->backend->destroy(zstrm->private);
30 free_pages((unsigned long)zstrm->buffer, 1);
31 kfree(zstrm);
32}
33
34/*
35 * allocate new zcomp_strm structure with ->private initialized by
36 * backend, return NULL on error
37 */
38static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp)
39{
40 struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_KERNEL);
41 if (!zstrm)
42 return NULL;
43
44 zstrm->private = comp->backend->create();
45 /*
46 * allocate 2 pages. 1 for compressed data, plus 1 extra for the
47 * case when compressed size is larger than the original one
48 */
49 zstrm->buffer = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
50 if (!zstrm->private || !zstrm->buffer) {
51 zcomp_strm_free(comp, zstrm);
52 zstrm = NULL;
53 }
54 return zstrm;
55}
56
57struct zcomp_strm *zcomp_strm_find(struct zcomp *comp)
58{
59 mutex_lock(&comp->strm_lock);
60 return comp->zstrm;
61}
62
63void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm)
64{
65 mutex_unlock(&comp->strm_lock);
66}
67
68int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
69 const unsigned char *src, size_t *dst_len)
70{
71 return comp->backend->compress(src, zstrm->buffer, dst_len,
72 zstrm->private);
73}
74
75int zcomp_decompress(struct zcomp *comp, const unsigned char *src,
76 size_t src_len, unsigned char *dst)
77{
78 return comp->backend->decompress(src, src_len, dst);
79}
80
81void zcomp_destroy(struct zcomp *comp)
82{
83 zcomp_strm_free(comp, comp->zstrm);
84 kfree(comp);
85}
86
87/*
88 * search available compressors for requested algorithm.
89 * allocate new zcomp and initialize it. return NULL
90 * if requested algorithm is not supported or in case
91 * of init error
92 */
93struct zcomp *zcomp_create(const char *compress)
94{
95 struct zcomp *comp;
96 struct zcomp_backend *backend;
97
98 backend = find_backend(compress);
99 if (!backend)
100 return NULL;
101
102 comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL);
103 if (!comp)
104 return NULL;
105
106 comp->backend = backend;
107 mutex_init(&comp->strm_lock);
108
109 comp->zstrm = zcomp_strm_alloc(comp);
110 if (!comp->zstrm) {
111 kfree(comp);
112 return NULL;
113 }
114 return comp;
115}