2015-10-14 07:38:31

by Joonsoo Kim

[permalink] [raw]
Subject: [PATCH v4 0/8] zram: introduce contextless compression API and use it on zram

This patchset introduce contextless compression API and use it on zram in
order to support more compression algorithm without more overhead.

The reason we need to support vairous compression algorithms is that
zram's performance is highly depend on workload and compression algorithm
and architecture. Every compression algorithm has it's own strong point.
For example, zlib is the best for compression ratio, but, it's
(de)compression speed is rather slow. Against my expectation, in my kernel
build test with zram swap, in low-memory condition on x86, zlib shows best
performance than others. In this case, I guess that compression ratio is
the most important factor.

Kernel build elapsed time in QEMU 8 CPUs 448 MB with zram swap
lzo : deflate
188.3 s : 181.9 s
(3% improvement)

Unlike this situation, on ARM, maybe fast (de)compression speed is
the most important because it's computation speed is slower than x86.

Anyway, there is a concern from Sergey to use crypto API in zram. Current
crypto API has a limitation that always require tfm object to (de)compress
something because some of (de)compression function requires scratch buffer
embedded on tfm even if some of (de)compression function doesn't
require it. Due to above reason, using crypto API rather than calling
compression library directly causes more memory footprint and this is
why zram doesn't use crypto API before.

To solve this problem, this patchset introduce contextless compression API.
This new compression API doesn't require user to use tfm one by one.
Tfm is only used for distinguishing compression algorithm and maybe
keeping algorithm parameter so can be used concurrently. Context is now
separate from tfm and user needs to allocate and manage it separately.
With this separation, we can save memory in some cases and get the best
performance.

This patchset solves Sergey's concern perfectly and provides possibility
to use various compression algorithm in zram.

Thanks.

Joonsoo Kim (6):
crypto/compress: introduce contextless compression and remove unused
pcomp
crypto/lzo: support contextless compression API
crypto/lz4: support contextless compressiona API
crypto/deflate: support contextless compression API
zram: use crypto contextless compression API to (de)compress
zram: enable contextless compression alg in zram

Sergey Senozhatsky (2):
zram: make stream find and release functions static
zram: pass zstrm down to decompression path

Documentation/blockdev/zram.txt | 29 ++-
crypto/Kconfig | 18 +-
crypto/Makefile | 3 +-
crypto/ccompress.c | 95 +++++++++
crypto/deflate.c | 96 +++++++++-
crypto/lz4.c | 77 +++++++-
crypto/lzo.c | 81 ++++++--
crypto/pcompress.c | 115 -----------
crypto/zlib.c | 381 -------------------------------------
drivers/block/zram/Kconfig | 13 +-
drivers/block/zram/Makefile | 4 +-
drivers/block/zram/zcomp.c | 104 ++++++----
drivers/block/zram/zcomp.h | 32 ++--
drivers/block/zram/zram_drv.c | 33 +++-
include/crypto/compress.h | 118 ++++--------
include/crypto/internal/compress.h | 28 ---
include/linux/crypto.h | 2 +-
17 files changed, 488 insertions(+), 741 deletions(-)
create mode 100644 crypto/ccompress.c
delete mode 100644 crypto/pcompress.c
delete mode 100644 crypto/zlib.c
delete mode 100644 include/crypto/internal/compress.h

--
1.9.1


2015-10-14 07:38:50

by Joonsoo Kim

[permalink] [raw]
Subject: [PATCH v4 6/8] zram: pass zstrm down to decompression path

From: Sergey Senozhatsky <[email protected]>

Introduce zcomp_decompress_begin()/zcomp_decompress_end() as a
preparation for crypto API-powered zcomp.

Change zcomp_decompress() signature to require zstrm parameter.

Unlike zcomp_compress_begin(), zcomp_decompress_begin() may return
zstrm if currently selected compression backend require zstrm for
decompression or NULL if it does not.

Acked-by: Minchan Kim <[email protected]>
Signed-off-by: Sergey Senozhatsky <[email protected]>
Signed-off-by: Joonsoo Kim <[email protected]>
---
drivers/block/zram/zcomp.c | 3 ++-
drivers/block/zram/zcomp.h | 3 ++-
drivers/block/zram/zram_drv.c | 20 ++++++++++++++++----
3 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 52d5b04..e3016da 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -336,7 +336,8 @@ int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
zstrm->private);
}

-int zcomp_decompress(struct zcomp *comp, const unsigned char *src,
+int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
+ const unsigned char *src,
size_t src_len, unsigned char *dst)
{
return comp->backend->decompress(src, src_len, dst);
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
index 616e013..4c09c01 100644
--- a/drivers/block/zram/zcomp.h
+++ b/drivers/block/zram/zcomp.h
@@ -66,7 +66,8 @@ int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
struct zcomp_strm *zcomp_decompress_begin(struct zcomp *comp);
void zcomp_decompress_end(struct zcomp *comp, struct zcomp_strm *zstrm);

-int zcomp_decompress(struct zcomp *comp, const unsigned char *src,
+int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
+ const unsigned char *src,
size_t src_len, unsigned char *dst);

bool zcomp_set_max_streams(struct zcomp *comp, int num_strm);
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 83a06f2..85d5301 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -560,7 +560,8 @@ static void zram_free_page(struct zram *zram, size_t index)
zram_set_obj_size(meta, index, 0);
}

-static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
+static int zram_decompress_page(struct zram *zram, struct zcomp_strm *zstrm,
+ char *mem, u32 index)
{
int ret = 0;
unsigned char *cmem;
@@ -582,7 +583,7 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
if (size == PAGE_SIZE)
copy_page(mem, cmem);
else
- ret = zcomp_decompress(zram->comp, cmem, size, mem);
+ ret = zcomp_decompress(zram->comp, zstrm, cmem, size, mem);
zs_unmap_object(meta->mem_pool, handle);
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);

@@ -602,6 +603,7 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
struct page *page;
unsigned char *user_mem, *uncmem = NULL;
struct zram_meta *meta = zram->meta;
+ struct zcomp_strm *zstrm;
page = bvec->bv_page;

bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
@@ -617,6 +619,7 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
/* Use a temporary buffer to decompress the page */
uncmem = kmalloc(PAGE_SIZE, GFP_NOIO);

+ zstrm = zcomp_decompress_begin(zram->comp);
user_mem = kmap_atomic(page);
if (!is_partial_io(bvec))
uncmem = user_mem;
@@ -627,7 +630,7 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
goto out_cleanup;
}

- ret = zram_decompress_page(zram, uncmem, index);
+ ret = zram_decompress_page(zram, zstrm, uncmem, index);
/* Should NEVER happen. Return bio error if it does. */
if (unlikely(ret))
goto out_cleanup;
@@ -636,10 +639,14 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
memcpy(user_mem + bvec->bv_offset, uncmem + offset,
bvec->bv_len);

+ zcomp_decompress_end(zram->comp, zstrm);
+ zstrm = NULL;
+
flush_dcache_page(page);
ret = 0;
out_cleanup:
kunmap_atomic(user_mem);
+ zcomp_decompress_end(zram->comp, zstrm);
if (is_partial_io(bvec))
kfree(uncmem);
return ret;
@@ -659,6 +666,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,

page = bvec->bv_page;
if (is_partial_io(bvec)) {
+ struct zcomp_strm *zstrm;
/*
* This is a partial IO. We need to read the full page
* before to write the changes.
@@ -668,7 +676,11 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
ret = -ENOMEM;
goto out;
}
- ret = zram_decompress_page(zram, uncmem, index);
+
+ zstrm = zcomp_decompress_begin(zram->comp);
+ ret = zram_decompress_page(zram, zstrm, uncmem, index);
+ zcomp_decompress_end(zram->comp, zstrm);
+
if (ret)
goto out;
}
--
1.9.1

2015-10-14 07:38:23

by Joonsoo Kim

[permalink] [raw]
Subject: [PATCH v4 7/8] zram: use crypto contextless compression API to (de)compress

Until now, zram uses compression algorithm through direct call
to core algorithm function, but, it has drawback that we need to add
compression algorithm manually to zram if needed. Without this work,
we cannot utilize various compression algorithms in the system.
Moreover, to add new compression algorithm, we need to know how to use it
and this is somewhat time-consuming.

When I tested new algorithms such as zlib, these problems make me hard
to test them. To prevent these problem in the future, I think that
using crypto API for compression is better approach and this patch
implements it.

The reason we need to support vairous compression algorithms is that
zram's performance is highly depend on workload and compression algorithm
and architecture. Every compression algorithm has it's own strong point.
For example, zlib is the best for compression ratio, but, it's
(de)compression speed is rather slow. Against my expectation, in my kernel
build test with zram swap, in low-memory condition on x86, zlib shows best
performance than others. In this case, I guess that compression ratio is
the most important factor.

Kernel build elapsed time in QEMU 8 CPUs 448 MB with zram swap
lzo : deflate
188.3 s : 181.9 s
(3% improvement)

Unlike this situation, on ARM, maybe fast (de)compression speed is
the most important because it's computation speed is slower than x86.

We can't expect what algorithm is the best fit for one's system, because
it needs too complex calculation. We need to test it in case by case and
easy to use new compression algorithm by this patch will help
that situation.

Note that this patch just convert zram to use crypto contextless
compression API but doesn't change compression algorithm selection
interface in zram. So it doesn't support zlib yet. Following patch
will change this interface and enable various compression algorithm.

Signed-off-by: Joonsoo Kim <[email protected]>
---
drivers/block/zram/Kconfig | 8 +++---
drivers/block/zram/Makefile | 4 +--
drivers/block/zram/zcomp.c | 63 ++++++++++++++++++++++++++++---------------
drivers/block/zram/zcomp.h | 21 +++------------
drivers/block/zram/zram_drv.c | 6 ++---
5 files changed, 52 insertions(+), 50 deletions(-)

diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
index 386ba3d..7619bed 100644
--- a/drivers/block/zram/Kconfig
+++ b/drivers/block/zram/Kconfig
@@ -1,8 +1,7 @@
config ZRAM
tristate "Compressed RAM block device support"
depends on BLOCK && SYSFS && ZSMALLOC
- select LZO_COMPRESS
- select LZO_DECOMPRESS
+ select CRYPTO_LZO
default n
help
Creates virtual block devices called /dev/zramX (X = 0, 1, ...).
@@ -18,9 +17,8 @@ config ZRAM
config ZRAM_LZ4_COMPRESS
bool "Enable LZ4 algorithm support"
depends on ZRAM
- select LZ4_COMPRESS
- select LZ4_DECOMPRESS
+ select CRYPTO_LZ4
default n
help
This option enables LZ4 compression algorithm support. Compression
- algorithm can be changed using `comp_algorithm' device attribute.
\ No newline at end of file
+ algorithm can be changed using `comp_algorithm' device attribute.
diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile
index be0763f..9e2b79e 100644
--- a/drivers/block/zram/Makefile
+++ b/drivers/block/zram/Makefile
@@ -1,5 +1,3 @@
-zram-y := zcomp_lzo.o zcomp.o zram_drv.o
-
-zram-$(CONFIG_ZRAM_LZ4_COMPRESS) += zcomp_lz4.o
+zram-y := zcomp.o zram_drv.o

obj-$(CONFIG_ZRAM) += zram.o
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index e3016da..9be83db 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -15,10 +15,6 @@
#include <linux/sched.h>

#include "zcomp.h"
-#include "zcomp_lzo.h"
-#ifdef CONFIG_ZRAM_LZ4_COMPRESS
-#include "zcomp_lz4.h"
-#endif

/*
* single zcomp_strm backend
@@ -43,19 +39,20 @@ struct zcomp_strm_multi {
wait_queue_head_t strm_wait;
};

-static struct zcomp_backend *backends[] = {
- &zcomp_lzo,
+static const char * const backends[] = {
+ "lzo",
#ifdef CONFIG_ZRAM_LZ4_COMPRESS
- &zcomp_lz4,
+ "lz4",
#endif
NULL
};

-static struct zcomp_backend *find_backend(const char *compress)
+static const char *find_backend(const char *compress)
{
int i = 0;
while (backends[i]) {
- if (sysfs_streq(compress, backends[i]->name))
+ if (sysfs_streq(compress, backends[i]) &&
+ crypto_has_comp(backends[i], 0, 0))
break;
i++;
}
@@ -65,7 +62,7 @@ static struct zcomp_backend *find_backend(const char *compress)
static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
{
if (zstrm->private)
- comp->backend->destroy(zstrm->private);
+ crypto_ccomp_free_context(comp->tfm, zstrm->private);
free_pages((unsigned long)zstrm->buffer, 1);
kfree(zstrm);
}
@@ -80,7 +77,13 @@ static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp)
if (!zstrm)
return NULL;

- zstrm->private = comp->backend->create();
+ zstrm->private = crypto_ccomp_alloc_context(comp->tfm);
+ if (IS_ERR(zstrm->private)) {
+ zstrm->private = NULL;
+ zcomp_strm_free(comp, zstrm);
+ return NULL;
+ }
+
/*
* allocate 2 pages. 1 for compressed data, plus 1 extra for the
* case when compressed size is larger than the original one
@@ -274,12 +277,12 @@ ssize_t zcomp_available_show(const char *comp, char *buf)
int i = 0;

while (backends[i]) {
- if (!strcmp(comp, backends[i]->name))
+ if (!strcmp(comp, backends[i]))
sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
- "[%s] ", backends[i]->name);
+ "[%s] ", backends[i]);
else
sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
- "%s ", backends[i]->name);
+ "%s ", backends[i]);
i++;
}
sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n");
@@ -320,7 +323,10 @@ void zcomp_compress_end(struct zcomp *comp, struct zcomp_strm *zstrm)
/* May return NULL, may sleep */
struct zcomp_strm *zcomp_decompress_begin(struct zcomp *comp)
{
- return NULL;
+ if (crypto_ccomp_decomp_noctx(comp->tfm))
+ return NULL;
+
+ return zcomp_strm_find(comp);
}

void zcomp_decompress_end(struct zcomp *comp, struct zcomp_strm *zstrm)
@@ -330,22 +336,29 @@ void zcomp_decompress_end(struct zcomp *comp, struct zcomp_strm *zstrm)
}

int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
- const unsigned char *src, size_t *dst_len)
+ const unsigned char *src, unsigned int *dst_len)
{
- return comp->backend->compress(src, zstrm->buffer, dst_len,
- zstrm->private);
+ *dst_len = PAGE_SIZE << 1;
+
+ return crypto_ccomp_compress(comp->tfm, src, PAGE_SIZE,
+ zstrm->buffer, dst_len, zstrm->private);
}

int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
const unsigned char *src,
- size_t src_len, unsigned char *dst)
+ unsigned int src_len, unsigned char *dst)
{
- return comp->backend->decompress(src, src_len, dst);
+ unsigned int size = PAGE_SIZE;
+ void *private = zstrm ? zstrm->private : NULL;
+
+ return crypto_ccomp_decompress(comp->tfm, src, src_len,
+ dst, &size, private);
}

void zcomp_destroy(struct zcomp *comp)
{
comp->destroy(comp);
+ crypto_free_ccomp(comp->tfm);
kfree(comp);
}

@@ -360,7 +373,7 @@ void zcomp_destroy(struct zcomp *comp)
struct zcomp *zcomp_create(const char *compress, int max_strm)
{
struct zcomp *comp;
- struct zcomp_backend *backend;
+ const char *backend;
int error;

backend = find_backend(compress);
@@ -371,12 +384,18 @@ struct zcomp *zcomp_create(const char *compress, int max_strm)
if (!comp)
return ERR_PTR(-ENOMEM);

- comp->backend = backend;
+ comp->tfm = crypto_alloc_ccomp(backend, 0, 0);
+ if (IS_ERR(comp->tfm)) {
+ kfree(comp);
+ return ERR_CAST(comp->tfm);
+ }
+
if (max_strm > 1)
error = zcomp_strm_multi_create(comp, max_strm);
else
error = zcomp_strm_single_create(comp);
if (error) {
+ crypto_free_ccomp(comp->tfm);
kfree(comp);
return ERR_PTR(error);
}
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
index 4c09c01..df9268d 100644
--- a/drivers/block/zram/zcomp.h
+++ b/drivers/block/zram/zcomp.h
@@ -11,6 +11,7 @@
#define _ZCOMP_H_

#include <linux/mutex.h>
+#include <crypto/compress.h>

struct zcomp_strm {
/* compression/decompression buffer */
@@ -25,24 +26,10 @@ struct zcomp_strm {
struct list_head list;
};

-/* static compression backend */
-struct zcomp_backend {
- int (*compress)(const unsigned char *src, unsigned char *dst,
- size_t *dst_len, void *private);
-
- int (*decompress)(const unsigned char *src, size_t src_len,
- unsigned char *dst);
-
- void *(*create)(void);
- void (*destroy)(void *private);
-
- const char *name;
-};
-
/* dynamic per-device compression frontend */
struct zcomp {
void *stream;
- struct zcomp_backend *backend;
+ struct crypto_ccomp *tfm;

struct zcomp_strm *(*strm_find)(struct zcomp *comp);
void (*strm_release)(struct zcomp *comp, struct zcomp_strm *zstrm);
@@ -61,14 +48,14 @@ struct zcomp_strm *zcomp_compress_begin(struct zcomp *comp);
void zcomp_compress_end(struct zcomp *comp, struct zcomp_strm *zstrm);

int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
- const unsigned char *src, size_t *dst_len);
+ const unsigned char *src, unsigned int *dst_len);

struct zcomp_strm *zcomp_decompress_begin(struct zcomp *comp);
void zcomp_decompress_end(struct zcomp *comp, struct zcomp_strm *zstrm);

int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
const unsigned char *src,
- size_t src_len, unsigned char *dst);
+ unsigned int src_len, unsigned char *dst);

bool zcomp_set_max_streams(struct zcomp *comp, int num_strm);
#endif /* _ZCOMP_H_ */
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 85d5301..6f04fb2 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -567,7 +567,7 @@ static int zram_decompress_page(struct zram *zram, struct zcomp_strm *zstrm,
unsigned char *cmem;
struct zram_meta *meta = zram->meta;
unsigned long handle;
- size_t size;
+ unsigned int size;

bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
handle = meta->table[index].handle;
@@ -656,7 +656,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
int offset)
{
int ret = 0;
- size_t clen;
+ unsigned int clen;
unsigned long handle;
struct page *page;
unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
@@ -731,7 +731,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,

handle = zs_malloc(meta->mem_pool, clen);
if (!handle) {
- pr_err("Error allocating memory for compressed page: %u, size=%zu\n",
+ pr_err("Error allocating memory for compressed page: %u, size=%u\n",
index, clen);
ret = -ENOMEM;
goto out;
--
1.9.1

2015-10-14 07:38:21

by Joonsoo Kim

[permalink] [raw]
Subject: [PATCH v4 5/8] zram: make stream find and release functions static

From: Sergey Senozhatsky <[email protected]>

Hide (make static) zstrm find and release function and introduce
zcomp_compress_begin()/zcomp_compress_end(). We will have begin
and end functions around compression (this patch) and decompression
(next patch). So the work flow is evolving to:

zstrm = foo_begin();
foo(zstrm);
foo_end(zstrm);

where foo is compress or decompress zcomp functions.

This patch is a preparation to make crypto API-powered zcomp
possible. The reasoning is that some crypto compression backends
require zstrm for decompression.

Acked-by: Minchan Kim <[email protected]>
Signed-off-by: Sergey Senozhatsky <[email protected]>
Signed-off-by: Joonsoo Kim <[email protected]>
---
drivers/block/zram/zcomp.c | 27 +++++++++++++++++++++++++--
drivers/block/zram/zcomp.h | 8 ++++++--
drivers/block/zram/zram_drv.c | 6 +++---
3 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 5cb13ca..52d5b04 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -296,16 +296,39 @@ bool zcomp_set_max_streams(struct zcomp *comp, int num_strm)
return comp->set_max_streams(comp, num_strm);
}

-struct zcomp_strm *zcomp_strm_find(struct zcomp *comp)
+static struct zcomp_strm *zcomp_strm_find(struct zcomp *comp)
{
return comp->strm_find(comp);
}

-void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm)
+static void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm)
{
comp->strm_release(comp, zstrm);
}

+/* Never return NULL, may sleep */
+struct zcomp_strm *zcomp_compress_begin(struct zcomp *comp)
+{
+ return zcomp_strm_find(comp);
+}
+
+void zcomp_compress_end(struct zcomp *comp, struct zcomp_strm *zstrm)
+{
+ zcomp_strm_release(comp, zstrm);
+}
+
+/* May return NULL, may sleep */
+struct zcomp_strm *zcomp_decompress_begin(struct zcomp *comp)
+{
+ return NULL;
+}
+
+void zcomp_decompress_end(struct zcomp *comp, struct zcomp_strm *zstrm)
+{
+ if (zstrm)
+ zcomp_strm_release(comp, zstrm);
+}
+
int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
const unsigned char *src, size_t *dst_len)
{
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
index 46e2b9f..616e013 100644
--- a/drivers/block/zram/zcomp.h
+++ b/drivers/block/zram/zcomp.h
@@ -56,12 +56,16 @@ bool zcomp_available_algorithm(const char *comp);
struct zcomp *zcomp_create(const char *comp, int max_strm);
void zcomp_destroy(struct zcomp *comp);

-struct zcomp_strm *zcomp_strm_find(struct zcomp *comp);
-void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm);
+
+struct zcomp_strm *zcomp_compress_begin(struct zcomp *comp);
+void zcomp_compress_end(struct zcomp *comp, struct zcomp_strm *zstrm);

int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
const unsigned char *src, size_t *dst_len);

+struct zcomp_strm *zcomp_decompress_begin(struct zcomp *comp);
+void zcomp_decompress_end(struct zcomp *comp, struct zcomp_strm *zstrm);
+
int zcomp_decompress(struct zcomp *comp, const unsigned char *src,
size_t src_len, unsigned char *dst);

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 3e8d8ff..83a06f2 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -673,7 +673,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
goto out;
}

- zstrm = zcomp_strm_find(zram->comp);
+ zstrm = zcomp_compress_begin(zram->comp);
user_mem = kmap_atomic(page);

if (is_partial_io(bvec)) {
@@ -744,7 +744,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
memcpy(cmem, src, clen);
}

- zcomp_strm_release(zram->comp, zstrm);
+ zcomp_compress_end(zram->comp, zstrm);
zstrm = NULL;
zs_unmap_object(meta->mem_pool, handle);

@@ -764,7 +764,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
atomic64_inc(&zram->stats.pages_stored);
out:
if (zstrm)
- zcomp_strm_release(zram->comp, zstrm);
+ zcomp_compress_end(zram->comp, zstrm);
if (is_partial_io(bvec))
kfree(uncmem);
return ret;
--
1.9.1

2015-10-14 07:38:17

by Joonsoo Kim

[permalink] [raw]
Subject: [PATCH v4 1/8] crypto/compress: introduce contextless compression and remove unused pcomp

Until now, tfm for crypto compression embeds (de)compression context.
According to (de)compression algorithm, requirement on context varys but
to be safe to use (de)compression API, tfm should be passed to
(de)compression API one by one.

This causes unbearable overhead in some cases. For example, if someone
want to decompress 100 data in parallel with LZO, 100 tfms are needed and
it causes large memory overhead. But, LZO algorithm doesn't require
context in decompress so if we directly use decompress on LZO lib we don't
need 100 contexts in tfms thus there is no memory overhead.

This patch tries to fix this problem by introducing new compression API,
contextless compression. Although above problem can be solved by some
modifications on existing compression API, but, crypto maintainer, Herbert
recommends introducing new API because existing compression API
is obsolete.

This new compression API doesn't require user to use tfm one by one.
Tfm is only used for distinguish compression algorithm and maybe keeping
algorithm parameter so can be used concurrently. Context is now separate
from tfm and user needs to allocate and manage it separately.

crypto_ccomp_decomp_noctx() is provided to distinguish compression
algorithm which doesn't require context in decompression. If context isn't
needed, user can decompress something without passing allocated context
and can get maximum performance without additional memory overhead.

This API will be used in zram in following patches.

Signed-off-by: Joonsoo Kim <[email protected]>
---
crypto/Kconfig | 17 +-
crypto/Makefile | 3 +-
crypto/ccompress.c | 95 +++++++++
crypto/pcompress.c | 115 -----------
crypto/zlib.c | 381 -------------------------------------
include/crypto/compress.h | 118 ++++--------
include/crypto/internal/compress.h | 28 ---
include/linux/crypto.h | 2 +-
8 files changed, 134 insertions(+), 625 deletions(-)
create mode 100644 crypto/ccompress.c
delete mode 100644 crypto/pcompress.c
delete mode 100644 crypto/zlib.c
delete mode 100644 include/crypto/internal/compress.h

diff --git a/crypto/Kconfig b/crypto/Kconfig
index fc93444..cfc42e6 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -84,14 +84,8 @@ config CRYPTO_RNG_DEFAULT
tristate
select CRYPTO_DRBG_MENU

-config CRYPTO_PCOMP
+config CRYPTO_CCOMPRESS
tristate
- select CRYPTO_PCOMP2
- select CRYPTO_ALGAPI
-
-config CRYPTO_PCOMP2
- tristate
- select CRYPTO_ALGAPI2

config CRYPTO_AKCIPHER2
tristate
@@ -1497,15 +1491,6 @@ config CRYPTO_DEFLATE

You will most probably want this if using IPSec.

-config CRYPTO_ZLIB
- tristate "Zlib compression algorithm"
- select CRYPTO_PCOMP
- select ZLIB_INFLATE
- select ZLIB_DEFLATE
- select NLATTR
- help
- This is the zlib algorithm.
-
config CRYPTO_LZO
tristate "LZO compression algorithm"
select CRYPTO_ALGAPI
diff --git a/crypto/Makefile b/crypto/Makefile
index e2c5981..93adbfe 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -28,7 +28,7 @@ crypto_hash-y += ahash.o
crypto_hash-y += shash.o
obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o

-obj-$(CONFIG_CRYPTO_PCOMP2) += pcompress.o
+obj-$(CONFIG_CRYPTO_CCOMPRESS) += ccompress.o
obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o

$(obj)/rsakey-asn1.o: $(obj)/rsakey-asn1.c $(obj)/rsakey-asn1.h
@@ -94,7 +94,6 @@ obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
obj-$(CONFIG_CRYPTO_CHACHA20) += chacha20_generic.o
obj-$(CONFIG_CRYPTO_POLY1305) += poly1305_generic.o
obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
-obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o
obj-$(CONFIG_CRYPTO_CRC32) += crc32.o
diff --git a/crypto/ccompress.c b/crypto/ccompress.c
new file mode 100644
index 0000000..1983372
--- /dev/null
+++ b/crypto/ccompress.c
@@ -0,0 +1,95 @@
+/*
+ * Cryptographic API.
+ *
+ * Contextless (de)compression operations.
+ *
+ * Copyright 2015 LG Electronics Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ * If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/crypto.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+
+#include <crypto/compress.h>
+
+#include "internal.h"
+
+
+static int crypto_ccomp_init(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+ return 0;
+}
+
+static int crypto_ccomp_init_tfm(struct crypto_tfm *tfm)
+{
+ return 0;
+}
+
+static int crypto_ccomp_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+ return -EINVAL;
+}
+
+static void crypto_ccomp_show(struct seq_file *m, struct crypto_alg *alg)
+ __attribute__ ((unused));
+static void crypto_ccomp_show(struct seq_file *m, struct crypto_alg *alg)
+{
+ seq_puts(m, "type : ccomp\n");
+}
+
+static const struct crypto_type crypto_ccomp_type = {
+ .extsize = crypto_alg_extsize,
+ .init = crypto_ccomp_init,
+ .init_tfm = crypto_ccomp_init_tfm,
+#ifdef CONFIG_PROC_FS
+ .show = crypto_ccomp_show,
+#endif
+ .report = crypto_ccomp_report,
+ .maskclear = ~CRYPTO_ALG_TYPE_MASK,
+ .maskset = CRYPTO_ALG_TYPE_MASK,
+ .type = CRYPTO_ALG_TYPE_CCOMPRESS,
+ .tfmsize = offsetof(struct crypto_ccomp, base),
+};
+
+struct crypto_ccomp *crypto_alloc_ccomp(const char *alg_name, u32 type,
+ u32 mask)
+{
+ return crypto_alloc_tfm(alg_name, &crypto_ccomp_type, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_ccomp);
+
+int crypto_register_ccomp(struct ccomp_alg *alg)
+{
+ struct crypto_alg *base = &alg->base;
+
+ base->cra_type = &crypto_ccomp_type;
+ base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
+ base->cra_flags |= CRYPTO_ALG_TYPE_CCOMPRESS;
+
+ return crypto_register_alg(base);
+}
+EXPORT_SYMBOL_GPL(crypto_register_ccomp);
+
+int crypto_unregister_ccomp(struct ccomp_alg *alg)
+{
+ return crypto_unregister_alg(&alg->base);
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_ccomp);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Contextless (de)compression operations");
+MODULE_AUTHOR("LG Electronics Inc.");
diff --git a/crypto/pcompress.c b/crypto/pcompress.c
deleted file mode 100644
index 7a13b40..0000000
--- a/crypto/pcompress.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Partial (de)compression operations.
- *
- * Copyright 2008 Sony Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.
- * If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/crypto.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/seq_file.h>
-#include <linux/string.h>
-#include <linux/cryptouser.h>
-#include <net/netlink.h>
-
-#include <crypto/compress.h>
-#include <crypto/internal/compress.h>
-
-#include "internal.h"
-
-
-static int crypto_pcomp_init(struct crypto_tfm *tfm, u32 type, u32 mask)
-{
- return 0;
-}
-
-static int crypto_pcomp_init_tfm(struct crypto_tfm *tfm)
-{
- return 0;
-}
-
-#ifdef CONFIG_NET
-static int crypto_pcomp_report(struct sk_buff *skb, struct crypto_alg *alg)
-{
- struct crypto_report_comp rpcomp;
-
- strncpy(rpcomp.type, "pcomp", sizeof(rpcomp.type));
- if (nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS,
- sizeof(struct crypto_report_comp), &rpcomp))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -EMSGSIZE;
-}
-#else
-static int crypto_pcomp_report(struct sk_buff *skb, struct crypto_alg *alg)
-{
- return -ENOSYS;
-}
-#endif
-
-static void crypto_pcomp_show(struct seq_file *m, struct crypto_alg *alg)
- __attribute__ ((unused));
-static void crypto_pcomp_show(struct seq_file *m, struct crypto_alg *alg)
-{
- seq_printf(m, "type : pcomp\n");
-}
-
-static const struct crypto_type crypto_pcomp_type = {
- .extsize = crypto_alg_extsize,
- .init = crypto_pcomp_init,
- .init_tfm = crypto_pcomp_init_tfm,
-#ifdef CONFIG_PROC_FS
- .show = crypto_pcomp_show,
-#endif
- .report = crypto_pcomp_report,
- .maskclear = ~CRYPTO_ALG_TYPE_MASK,
- .maskset = CRYPTO_ALG_TYPE_MASK,
- .type = CRYPTO_ALG_TYPE_PCOMPRESS,
- .tfmsize = offsetof(struct crypto_pcomp, base),
-};
-
-struct crypto_pcomp *crypto_alloc_pcomp(const char *alg_name, u32 type,
- u32 mask)
-{
- return crypto_alloc_tfm(alg_name, &crypto_pcomp_type, type, mask);
-}
-EXPORT_SYMBOL_GPL(crypto_alloc_pcomp);
-
-int crypto_register_pcomp(struct pcomp_alg *alg)
-{
- struct crypto_alg *base = &alg->base;
-
- base->cra_type = &crypto_pcomp_type;
- base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
- base->cra_flags |= CRYPTO_ALG_TYPE_PCOMPRESS;
-
- return crypto_register_alg(base);
-}
-EXPORT_SYMBOL_GPL(crypto_register_pcomp);
-
-int crypto_unregister_pcomp(struct pcomp_alg *alg)
-{
- return crypto_unregister_alg(&alg->base);
-}
-EXPORT_SYMBOL_GPL(crypto_unregister_pcomp);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Partial (de)compression type");
-MODULE_AUTHOR("Sony Corporation");
diff --git a/crypto/zlib.c b/crypto/zlib.c
deleted file mode 100644
index d51a30a..0000000
--- a/crypto/zlib.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Zlib algorithm
- *
- * Copyright 2008 Sony Corporation
- *
- * Based on deflate.c, which is
- * Copyright (c) 2003 James Morris <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * FIXME: deflate transforms will require up to a total of about 436k of kernel
- * memory on i386 (390k for compression, the rest for decompression), as the
- * current zlib kernel code uses a worst case pre-allocation system by default.
- * This needs to be fixed so that the amount of memory required is properly
- * related to the winbits and memlevel parameters.
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/zlib.h>
-#include <linux/vmalloc.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/net.h>
-
-#include <crypto/internal/compress.h>
-
-#include <net/netlink.h>
-
-
-struct zlib_ctx {
- struct z_stream_s comp_stream;
- struct z_stream_s decomp_stream;
- int decomp_windowBits;
-};
-
-
-static void zlib_comp_exit(struct zlib_ctx *ctx)
-{
- struct z_stream_s *stream = &ctx->comp_stream;
-
- if (stream->workspace) {
- zlib_deflateEnd(stream);
- vfree(stream->workspace);
- stream->workspace = NULL;
- }
-}
-
-static void zlib_decomp_exit(struct zlib_ctx *ctx)
-{
- struct z_stream_s *stream = &ctx->decomp_stream;
-
- if (stream->workspace) {
- zlib_inflateEnd(stream);
- vfree(stream->workspace);
- stream->workspace = NULL;
- }
-}
-
-static int zlib_init(struct crypto_tfm *tfm)
-{
- return 0;
-}
-
-static void zlib_exit(struct crypto_tfm *tfm)
-{
- struct zlib_ctx *ctx = crypto_tfm_ctx(tfm);
-
- zlib_comp_exit(ctx);
- zlib_decomp_exit(ctx);
-}
-
-
-static int zlib_compress_setup(struct crypto_pcomp *tfm, const void *params,
- unsigned int len)
-{
- struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
- struct z_stream_s *stream = &ctx->comp_stream;
- struct nlattr *tb[ZLIB_COMP_MAX + 1];
- int window_bits, mem_level;
- size_t workspacesize;
- int ret;
-
- ret = nla_parse(tb, ZLIB_COMP_MAX, params, len, NULL);
- if (ret)
- return ret;
-
- zlib_comp_exit(ctx);
-
- window_bits = tb[ZLIB_COMP_WINDOWBITS]
- ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
- : MAX_WBITS;
- mem_level = tb[ZLIB_COMP_MEMLEVEL]
- ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
- : DEF_MEM_LEVEL;
-
- workspacesize = zlib_deflate_workspacesize(window_bits, mem_level);
- stream->workspace = vzalloc(workspacesize);
- if (!stream->workspace)
- return -ENOMEM;
-
- ret = zlib_deflateInit2(stream,
- tb[ZLIB_COMP_LEVEL]
- ? nla_get_u32(tb[ZLIB_COMP_LEVEL])
- : Z_DEFAULT_COMPRESSION,
- tb[ZLIB_COMP_METHOD]
- ? nla_get_u32(tb[ZLIB_COMP_METHOD])
- : Z_DEFLATED,
- window_bits,
- mem_level,
- tb[ZLIB_COMP_STRATEGY]
- ? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
- : Z_DEFAULT_STRATEGY);
- if (ret != Z_OK) {
- vfree(stream->workspace);
- stream->workspace = NULL;
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int zlib_compress_init(struct crypto_pcomp *tfm)
-{
- int ret;
- struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
- struct z_stream_s *stream = &dctx->comp_stream;
-
- ret = zlib_deflateReset(stream);
- if (ret != Z_OK)
- return -EINVAL;
-
- return 0;
-}
-
-static int zlib_compress_update(struct crypto_pcomp *tfm,
- struct comp_request *req)
-{
- int ret;
- struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
- struct z_stream_s *stream = &dctx->comp_stream;
-
- pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
- stream->next_in = req->next_in;
- stream->avail_in = req->avail_in;
- stream->next_out = req->next_out;
- stream->avail_out = req->avail_out;
-
- ret = zlib_deflate(stream, Z_NO_FLUSH);
- switch (ret) {
- case Z_OK:
- break;
-
- case Z_BUF_ERROR:
- pr_debug("zlib_deflate could not make progress\n");
- return -EAGAIN;
-
- default:
- pr_debug("zlib_deflate failed %d\n", ret);
- return -EINVAL;
- }
-
- ret = req->avail_out - stream->avail_out;
- pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
- stream->avail_in, stream->avail_out,
- req->avail_in - stream->avail_in, ret);
- req->next_in = stream->next_in;
- req->avail_in = stream->avail_in;
- req->next_out = stream->next_out;
- req->avail_out = stream->avail_out;
- return ret;
-}
-
-static int zlib_compress_final(struct crypto_pcomp *tfm,
- struct comp_request *req)
-{
- int ret;
- struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
- struct z_stream_s *stream = &dctx->comp_stream;
-
- pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
- stream->next_in = req->next_in;
- stream->avail_in = req->avail_in;
- stream->next_out = req->next_out;
- stream->avail_out = req->avail_out;
-
- ret = zlib_deflate(stream, Z_FINISH);
- if (ret != Z_STREAM_END) {
- pr_debug("zlib_deflate failed %d\n", ret);
- return -EINVAL;
- }
-
- ret = req->avail_out - stream->avail_out;
- pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
- stream->avail_in, stream->avail_out,
- req->avail_in - stream->avail_in, ret);
- req->next_in = stream->next_in;
- req->avail_in = stream->avail_in;
- req->next_out = stream->next_out;
- req->avail_out = stream->avail_out;
- return ret;
-}
-
-
-static int zlib_decompress_setup(struct crypto_pcomp *tfm, const void *params,
- unsigned int len)
-{
- struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
- struct z_stream_s *stream = &ctx->decomp_stream;
- struct nlattr *tb[ZLIB_DECOMP_MAX + 1];
- int ret = 0;
-
- ret = nla_parse(tb, ZLIB_DECOMP_MAX, params, len, NULL);
- if (ret)
- return ret;
-
- zlib_decomp_exit(ctx);
-
- ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS]
- ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS])
- : DEF_WBITS;
-
- stream->workspace = vzalloc(zlib_inflate_workspacesize());
- if (!stream->workspace)
- return -ENOMEM;
-
- ret = zlib_inflateInit2(stream, ctx->decomp_windowBits);
- if (ret != Z_OK) {
- vfree(stream->workspace);
- stream->workspace = NULL;
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int zlib_decompress_init(struct crypto_pcomp *tfm)
-{
- int ret;
- struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
- struct z_stream_s *stream = &dctx->decomp_stream;
-
- ret = zlib_inflateReset(stream);
- if (ret != Z_OK)
- return -EINVAL;
-
- return 0;
-}
-
-static int zlib_decompress_update(struct crypto_pcomp *tfm,
- struct comp_request *req)
-{
- int ret;
- struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
- struct z_stream_s *stream = &dctx->decomp_stream;
-
- pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
- stream->next_in = req->next_in;
- stream->avail_in = req->avail_in;
- stream->next_out = req->next_out;
- stream->avail_out = req->avail_out;
-
- ret = zlib_inflate(stream, Z_SYNC_FLUSH);
- switch (ret) {
- case Z_OK:
- case Z_STREAM_END:
- break;
-
- case Z_BUF_ERROR:
- pr_debug("zlib_inflate could not make progress\n");
- return -EAGAIN;
-
- default:
- pr_debug("zlib_inflate failed %d\n", ret);
- return -EINVAL;
- }
-
- ret = req->avail_out - stream->avail_out;
- pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
- stream->avail_in, stream->avail_out,
- req->avail_in - stream->avail_in, ret);
- req->next_in = stream->next_in;
- req->avail_in = stream->avail_in;
- req->next_out = stream->next_out;
- req->avail_out = stream->avail_out;
- return ret;
-}
-
-static int zlib_decompress_final(struct crypto_pcomp *tfm,
- struct comp_request *req)
-{
- int ret;
- struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
- struct z_stream_s *stream = &dctx->decomp_stream;
-
- pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
- stream->next_in = req->next_in;
- stream->avail_in = req->avail_in;
- stream->next_out = req->next_out;
- stream->avail_out = req->avail_out;
-
- if (dctx->decomp_windowBits < 0) {
- ret = zlib_inflate(stream, Z_SYNC_FLUSH);
- /*
- * Work around a bug in zlib, which sometimes wants to taste an
- * extra byte when being used in the (undocumented) raw deflate
- * mode. (From USAGI).
- */
- if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
- const void *saved_next_in = stream->next_in;
- u8 zerostuff = 0;
-
- stream->next_in = &zerostuff;
- stream->avail_in = 1;
- ret = zlib_inflate(stream, Z_FINISH);
- stream->next_in = saved_next_in;
- stream->avail_in = 0;
- }
- } else
- ret = zlib_inflate(stream, Z_FINISH);
- if (ret != Z_STREAM_END) {
- pr_debug("zlib_inflate failed %d\n", ret);
- return -EINVAL;
- }
-
- ret = req->avail_out - stream->avail_out;
- pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
- stream->avail_in, stream->avail_out,
- req->avail_in - stream->avail_in, ret);
- req->next_in = stream->next_in;
- req->avail_in = stream->avail_in;
- req->next_out = stream->next_out;
- req->avail_out = stream->avail_out;
- return ret;
-}
-
-
-static struct pcomp_alg zlib_alg = {
- .compress_setup = zlib_compress_setup,
- .compress_init = zlib_compress_init,
- .compress_update = zlib_compress_update,
- .compress_final = zlib_compress_final,
- .decompress_setup = zlib_decompress_setup,
- .decompress_init = zlib_decompress_init,
- .decompress_update = zlib_decompress_update,
- .decompress_final = zlib_decompress_final,
-
- .base = {
- .cra_name = "zlib",
- .cra_flags = CRYPTO_ALG_TYPE_PCOMPRESS,
- .cra_ctxsize = sizeof(struct zlib_ctx),
- .cra_module = THIS_MODULE,
- .cra_init = zlib_init,
- .cra_exit = zlib_exit,
- }
-};
-
-static int __init zlib_mod_init(void)
-{
- return crypto_register_pcomp(&zlib_alg);
-}
-
-static void __exit zlib_mod_fini(void)
-{
- crypto_unregister_pcomp(&zlib_alg);
-}
-
-module_init(zlib_mod_init);
-module_exit(zlib_mod_fini);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Zlib Compression Algorithm");
-MODULE_AUTHOR("Sony Corporation");
-MODULE_ALIAS_CRYPTO("zlib");
diff --git a/include/crypto/compress.h b/include/crypto/compress.h
index 5b67af8..1ae35ee 100644
--- a/include/crypto/compress.h
+++ b/include/crypto/compress.h
@@ -2,6 +2,7 @@
* Compress: Compression algorithms under the cryptographic API.
*
* Copyright 2008 Sony Corporation
+ * Copyright 2015 LG Electronics Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,124 +23,77 @@

#include <linux/crypto.h>

+#define CCOMP_TYPE_DECOMP_NOCTX 0x000000001

-struct comp_request {
- const void *next_in; /* next input byte */
- void *next_out; /* next output byte */
- unsigned int avail_in; /* bytes available at next_in */
- unsigned int avail_out; /* bytes available at next_out */
-};
-
-enum zlib_comp_params {
- ZLIB_COMP_LEVEL = 1, /* e.g. Z_DEFAULT_COMPRESSION */
- ZLIB_COMP_METHOD, /* e.g. Z_DEFLATED */
- ZLIB_COMP_WINDOWBITS, /* e.g. MAX_WBITS */
- ZLIB_COMP_MEMLEVEL, /* e.g. DEF_MEM_LEVEL */
- ZLIB_COMP_STRATEGY, /* e.g. Z_DEFAULT_STRATEGY */
- __ZLIB_COMP_MAX,
-};
-
-#define ZLIB_COMP_MAX (__ZLIB_COMP_MAX - 1)
-
-
-enum zlib_decomp_params {
- ZLIB_DECOMP_WINDOWBITS = 1, /* e.g. DEF_WBITS */
- __ZLIB_DECOMP_MAX,
-};
-
-#define ZLIB_DECOMP_MAX (__ZLIB_DECOMP_MAX - 1)
-
-
-struct crypto_pcomp {
+struct crypto_ccomp {
struct crypto_tfm base;
};

-struct pcomp_alg {
- int (*compress_setup)(struct crypto_pcomp *tfm, const void *params,
- unsigned int len);
- int (*compress_init)(struct crypto_pcomp *tfm);
- int (*compress_update)(struct crypto_pcomp *tfm,
- struct comp_request *req);
- int (*compress_final)(struct crypto_pcomp *tfm,
- struct comp_request *req);
- int (*decompress_setup)(struct crypto_pcomp *tfm, const void *params,
- unsigned int len);
- int (*decompress_init)(struct crypto_pcomp *tfm);
- int (*decompress_update)(struct crypto_pcomp *tfm,
- struct comp_request *req);
- int (*decompress_final)(struct crypto_pcomp *tfm,
- struct comp_request *req);
+struct ccomp_alg {
+ void *(*alloc_context)(struct crypto_ccomp *tfm);
+ void (*free_context)(struct crypto_ccomp *tfm, void *ctx);
+ int (*compress)(const u8 *src, unsigned int slen, u8 *dst,
+ unsigned int *dlen, void *ctx);
+ int (*decompress)(const u8 *src, unsigned int slen, u8 *dst,
+ unsigned int *dlen, void *ctx);

+ unsigned long flags;
struct crypto_alg base;
};

-extern struct crypto_pcomp *crypto_alloc_pcomp(const char *alg_name, u32 type,
+extern struct crypto_ccomp *crypto_alloc_ccomp(const char *alg_name, u32 type,
u32 mask);

-static inline struct crypto_tfm *crypto_pcomp_tfm(struct crypto_pcomp *tfm)
+static inline struct crypto_tfm *crypto_ccomp_tfm(struct crypto_ccomp *tfm)
{
return &tfm->base;
}

-static inline void crypto_free_pcomp(struct crypto_pcomp *tfm)
-{
- crypto_destroy_tfm(tfm, crypto_pcomp_tfm(tfm));
-}
-
-static inline struct pcomp_alg *__crypto_pcomp_alg(struct crypto_alg *alg)
-{
- return container_of(alg, struct pcomp_alg, base);
-}
-
-static inline struct pcomp_alg *crypto_pcomp_alg(struct crypto_pcomp *tfm)
-{
- return __crypto_pcomp_alg(crypto_pcomp_tfm(tfm)->__crt_alg);
-}
-
-static inline int crypto_compress_setup(struct crypto_pcomp *tfm,
- const void *params, unsigned int len)
+static inline void crypto_free_ccomp(struct crypto_ccomp *tfm)
{
- return crypto_pcomp_alg(tfm)->compress_setup(tfm, params, len);
+ crypto_destroy_tfm(tfm, crypto_ccomp_tfm(tfm));
}

-static inline int crypto_compress_init(struct crypto_pcomp *tfm)
+static inline struct ccomp_alg *__crypto_ccomp_alg(struct crypto_alg *alg)
{
- return crypto_pcomp_alg(tfm)->compress_init(tfm);
+ return container_of(alg, struct ccomp_alg, base);
}

-static inline int crypto_compress_update(struct crypto_pcomp *tfm,
- struct comp_request *req)
+static inline struct ccomp_alg *crypto_ccomp_alg(struct crypto_ccomp *tfm)
{
- return crypto_pcomp_alg(tfm)->compress_update(tfm, req);
+ return __crypto_ccomp_alg(crypto_ccomp_tfm(tfm)->__crt_alg);
}

-static inline int crypto_compress_final(struct crypto_pcomp *tfm,
- struct comp_request *req)
+static inline void *crypto_ccomp_alloc_context(struct crypto_ccomp *tfm)
{
- return crypto_pcomp_alg(tfm)->compress_final(tfm, req);
+ return crypto_ccomp_alg(tfm)->alloc_context(tfm);
}

-static inline int crypto_decompress_setup(struct crypto_pcomp *tfm,
- const void *params, unsigned int len)
+static inline void crypto_ccomp_free_context(struct crypto_ccomp *tfm,
+ void *ctx)
{
- return crypto_pcomp_alg(tfm)->decompress_setup(tfm, params, len);
+ return crypto_ccomp_alg(tfm)->free_context(tfm, ctx);
}

-static inline int crypto_decompress_init(struct crypto_pcomp *tfm)
+static inline int crypto_ccomp_compress(struct crypto_ccomp *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen, void *ctx)
{
- return crypto_pcomp_alg(tfm)->decompress_init(tfm);
+ return crypto_ccomp_alg(tfm)->compress(src, slen, dst, dlen, ctx);
}

-static inline int crypto_decompress_update(struct crypto_pcomp *tfm,
- struct comp_request *req)
+static inline int crypto_ccomp_decompress(struct crypto_ccomp *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen, void *ctx)
{
- return crypto_pcomp_alg(tfm)->decompress_update(tfm, req);
+ return crypto_ccomp_alg(tfm)->decompress(src, slen, dst, dlen, ctx);
}

-static inline int crypto_decompress_final(struct crypto_pcomp *tfm,
- struct comp_request *req)
+static inline bool crypto_ccomp_decomp_noctx(struct crypto_ccomp *tfm)
{
- return crypto_pcomp_alg(tfm)->decompress_final(tfm, req);
+ return crypto_ccomp_alg(tfm)->flags & CCOMP_TYPE_DECOMP_NOCTX;
}

+extern int crypto_register_ccomp(struct ccomp_alg *alg);
+extern int crypto_unregister_ccomp(struct ccomp_alg *alg);
#endif /* _CRYPTO_COMPRESS_H */
diff --git a/include/crypto/internal/compress.h b/include/crypto/internal/compress.h
deleted file mode 100644
index 178a888..0000000
--- a/include/crypto/internal/compress.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Compress: Compression algorithms under the cryptographic API.
- *
- * Copyright 2008 Sony Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.
- * If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _CRYPTO_INTERNAL_COMPRESS_H
-#define _CRYPTO_INTERNAL_COMPRESS_H
-
-#include <crypto/compress.h>
-
-extern int crypto_register_pcomp(struct pcomp_alg *alg);
-extern int crypto_unregister_pcomp(struct pcomp_alg *alg);
-
-#endif /* _CRYPTO_INTERNAL_COMPRESS_H */
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index e71cb70..a581b1e 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -54,7 +54,7 @@
#define CRYPTO_ALG_TYPE_AHASH 0x0000000a
#define CRYPTO_ALG_TYPE_RNG 0x0000000c
#define CRYPTO_ALG_TYPE_AKCIPHER 0x0000000d
-#define CRYPTO_ALG_TYPE_PCOMPRESS 0x0000000f
+#define CRYPTO_ALG_TYPE_CCOMPRESS 0x0000000f

#define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e
#define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000c
--
1.9.1

2015-10-14 07:38:24

by Joonsoo Kim

[permalink] [raw]
Subject: [PATCH v4 8/8] zram: enable contextless compression alg in zram

Now, zram uses contextless compression API and there is no reason
to limit compression algorithm through hard-wired string. This patch
remove it so enable all contextless compression algorithm in the
system.

After this patch, available compression algorithm for zram can be
retrieved by searching contextless compression in /proc/crypto.

cat /proc/crypto | grep ccomp -B 7
name : lz4
[snip...]
type : ccomp

Previous interface comp_algorithm attr will remain to set new algorithm.
Read from previous interface also works for compatibility but it will
be wrong.

Note that after this patch is applied, there is no way to know current
compression algorithm so it's really bad thing. Please let me know proper
solution if someone have better idea.

Signed-off-by: Joonsoo Kim <[email protected]>
---
Documentation/blockdev/zram.txt | 29 +++++++++++++++++++++++------
drivers/block/zram/Kconfig | 9 ---------
drivers/block/zram/zcomp.c | 17 +++++++----------
drivers/block/zram/zram_drv.c | 1 +
4 files changed, 31 insertions(+), 25 deletions(-)

diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt
index 5bda503..7a165c2 100644
--- a/Documentation/blockdev/zram.txt
+++ b/Documentation/blockdev/zram.txt
@@ -81,15 +81,32 @@ dynamic max_comp_streams. Only multi stream backend supports dynamic
max_comp_streams adjustment.

3) Select compression algorithm
- Using comp_algorithm device attribute one can see available and
- currently selected (shown in square brackets) compression algorithms,
- change selected compression algorithm (once the device is initialised
- there is no way to change compression algorithm).
+ You can find available compression algorithms by searching contextless
+ compression algorithm (type: ccomp) in /proc/crypto.
+ Using comp_algorithm device attribute one can change selected
+ compression algorithm (once the device is initialised there is no way
+ to change compression algorithm).

Examples:
#show supported compression algorithms
- cat /sys/block/zram0/comp_algorithm
- lzo [lz4]
+ cat /proc/crypto | grep ccomp -B 7
+ name : lz4
+ driver : lz4-generic
+ module : kernel
+ priority : 0
+ refcnt : 1
+ selftest : passed
+ internal : no
+ type : ccomp
+ --
+ name : lzo
+ driver : lzo-generic
+ module : kernel
+ priority : 0
+ refcnt : 1
+ selftest : passed
+ internal : no
+ type : ccomp

#select lzo compression algorithm
echo lzo > /sys/block/zram0/comp_algorithm
diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
index 7619bed..36ec96f 100644
--- a/drivers/block/zram/Kconfig
+++ b/drivers/block/zram/Kconfig
@@ -13,12 +13,3 @@ config ZRAM
disks and maybe many more.

See zram.txt for more information.
-
-config ZRAM_LZ4_COMPRESS
- bool "Enable LZ4 algorithm support"
- depends on ZRAM
- select CRYPTO_LZ4
- default n
- help
- This option enables LZ4 compression algorithm support. Compression
- algorithm can be changed using `comp_algorithm' device attribute.
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 9be83db..f91c0659 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -41,22 +41,16 @@ struct zcomp_strm_multi {

static const char * const backends[] = {
"lzo",
-#ifdef CONFIG_ZRAM_LZ4_COMPRESS
"lz4",
-#endif
NULL
};

static const char *find_backend(const char *compress)
{
- int i = 0;
- while (backends[i]) {
- if (sysfs_streq(compress, backends[i]) &&
- crypto_has_comp(backends[i], 0, 0))
- break;
- i++;
- }
- return backends[i];
+ if (crypto_has_comp(compress, 0, 0))
+ return compress;
+
+ return NULL;
}

static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
@@ -277,6 +271,9 @@ ssize_t zcomp_available_show(const char *comp, char *buf)
int i = 0;

while (backends[i]) {
+ if (!crypto_has_comp(backends[i], 0, 0))
+ continue;
+
if (!strcmp(comp, backends[i]))
sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
"[%s] ", backends[i]);
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 6f04fb2..6b4cf85 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -352,6 +352,7 @@ static ssize_t comp_algorithm_show(struct device *dev,
size_t sz;
struct zram *zram = dev_to_zram(dev);

+ deprecated_attr_warn("comp_algorithm");
down_read(&zram->init_lock);
sz = zcomp_available_show(zram->compressor, buf);
up_read(&zram->init_lock);
--
1.9.1

2015-10-14 07:38:20

by Joonsoo Kim

[permalink] [raw]
Subject: [PATCH v4 4/8] crypto/deflate: support contextless compression API

Now, contextless compression API is introduced and it can reduce
memory overhead in some cases. All compression algorithm will
support it.

Signed-off-by: Joonsoo Kim <[email protected]>
---
crypto/deflate.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 86 insertions(+), 10 deletions(-)

diff --git a/crypto/deflate.c b/crypto/deflate.c
index 95d8d37..7070438 100644
--- a/crypto/deflate.c
+++ b/crypto/deflate.c
@@ -32,6 +32,7 @@
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/net.h>
+#include <crypto/compress.h>

#define DEFLATE_DEF_LEVEL Z_DEFAULT_COMPRESSION
#define DEFLATE_DEF_WINBITS 11
@@ -101,9 +102,8 @@ static void deflate_decomp_exit(struct deflate_ctx *ctx)
vfree(ctx->decomp_stream.workspace);
}

-static int deflate_init(struct crypto_tfm *tfm)
+static int __deflate_init(void *ctx)
{
- struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
int ret;

ret = deflate_comp_init(ctx);
@@ -116,19 +116,54 @@ out:
return ret;
}

-static void deflate_exit(struct crypto_tfm *tfm)
+static void *deflate_alloc_context(struct crypto_ccomp *tfm)
+{
+ void *ctx;
+ int ret;
+
+ ctx = kzalloc(sizeof(struct deflate_ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ ret = __deflate_init(ctx);
+ if (ret) {
+ kfree(ctx);
+ return ERR_PTR(ret);
+ }
+
+ return ctx;
+}
+
+static int deflate_init(struct crypto_tfm *tfm)
{
struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);

+ return __deflate_init(ctx);
+}
+
+static void __deflate_exit(void *ctx)
+{
deflate_comp_exit(ctx);
deflate_decomp_exit(ctx);
}

-static int deflate_compress(struct crypto_tfm *tfm, const u8 *src,
- unsigned int slen, u8 *dst, unsigned int *dlen)
+static void deflate_free_context(struct crypto_ccomp *tfm, void *ctx)
+{
+ __deflate_exit(ctx);
+}
+
+static void deflate_exit(struct crypto_tfm *tfm)
+{
+ struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ __deflate_exit(ctx);
+}
+
+static int __deflate_compress(const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen, void *ctx)
{
int ret = 0;
- struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
+ struct deflate_ctx *dctx = ctx;
struct z_stream_s *stream = &dctx->comp_stream;

ret = zlib_deflateReset(stream);
@@ -153,12 +188,20 @@ out:
return ret;
}

-static int deflate_decompress(struct crypto_tfm *tfm, const u8 *src,
- unsigned int slen, u8 *dst, unsigned int *dlen)
+static int deflate_compress(struct crypto_tfm *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+ struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
+
+ return __deflate_compress(src, slen, dst, dlen, dctx);
+}
+
+static int __deflate_decompress(const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen, void *ctx)
{

int ret = 0;
- struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
+ struct deflate_ctx *dctx = ctx;
struct z_stream_s *stream = &dctx->decomp_stream;

ret = zlib_inflateReset(stream);
@@ -194,6 +237,14 @@ out:
return ret;
}

+static int deflate_decompress(struct crypto_tfm *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+ struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
+
+ return __deflate_compress(src, slen, dst, dlen, dctx);
+}
+
static struct crypto_alg alg = {
.cra_name = "deflate",
.cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
@@ -206,14 +257,39 @@ static struct crypto_alg alg = {
.coa_decompress = deflate_decompress } }
};

+static struct ccomp_alg ccomp = {
+ .alloc_context = deflate_alloc_context,
+ .free_context = deflate_free_context,
+ .compress = __deflate_compress,
+ .decompress = __deflate_decompress,
+ .base = {
+ .cra_name = "deflate",
+ .cra_flags = CRYPTO_ALG_TYPE_CCOMPRESS,
+ .cra_module = THIS_MODULE,
+ }
+};
+
static int __init deflate_mod_init(void)
{
- return crypto_register_alg(&alg);
+ int ret;
+
+ ret = crypto_register_alg(&alg);
+ if (ret)
+ return ret;
+
+ ret = crypto_register_ccomp(&ccomp);
+ if (ret) {
+ crypto_unregister_alg(&alg);
+ return ret;
+ }
+
+ return ret;
}

static void __exit deflate_mod_fini(void)
{
crypto_unregister_alg(&alg);
+ crypto_unregister_ccomp(&ccomp);
}

module_init(deflate_mod_init);
--
1.9.1

2015-10-14 07:38:18

by Joonsoo Kim

[permalink] [raw]
Subject: [PATCH v4 2/8] crypto/lzo: support contextless compression API

Now, contextless compression API is introduced and it can reduce
memory overhead in some cases. All compression algorithm will
support it.

Signed-off-by: Joonsoo Kim <[email protected]>
---
crypto/Kconfig | 1 +
crypto/lzo.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 69 insertions(+), 13 deletions(-)

diff --git a/crypto/Kconfig b/crypto/Kconfig
index cfc42e6..d25746f 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1494,6 +1494,7 @@ config CRYPTO_DEFLATE
config CRYPTO_LZO
tristate "LZO compression algorithm"
select CRYPTO_ALGAPI
+ select CRYPTO_CCOMPRESS
select LZO_COMPRESS
select LZO_DECOMPRESS
help
diff --git a/crypto/lzo.c b/crypto/lzo.c
index 4b3e925..a6ae752 100644
--- a/crypto/lzo.c
+++ b/crypto/lzo.c
@@ -22,40 +22,56 @@
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/lzo.h>
+#include <crypto/compress.h>

struct lzo_ctx {
void *lzo_comp_mem;
};

+static void *lzo_alloc_context(struct crypto_ccomp *tfm)
+{
+ void *ctx;
+
+ ctx = kmalloc(LZO1X_MEM_COMPRESS,
+ GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
+ if (!ctx)
+ ctx = vmalloc(LZO1X_MEM_COMPRESS);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ return ctx;
+}
+
static int lzo_init(struct crypto_tfm *tfm)
{
struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);

- ctx->lzo_comp_mem = kmalloc(LZO1X_MEM_COMPRESS,
- GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
- if (!ctx->lzo_comp_mem)
- ctx->lzo_comp_mem = vmalloc(LZO1X_MEM_COMPRESS);
- if (!ctx->lzo_comp_mem)
+ ctx->lzo_comp_mem = lzo_alloc_context(NULL);
+ if (IS_ERR(ctx->lzo_comp_mem))
return -ENOMEM;

return 0;
}

+static void lzo_free_context(struct crypto_ccomp *tfm, void *ctx)
+{
+ kvfree(ctx);
+}
+
static void lzo_exit(struct crypto_tfm *tfm)
{
struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);

- kvfree(ctx->lzo_comp_mem);
+ lzo_free_context(NULL, ctx->lzo_comp_mem);
}

-static int lzo_compress(struct crypto_tfm *tfm, const u8 *src,
- unsigned int slen, u8 *dst, unsigned int *dlen)
+static int __lzo_compress(const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen, void *ctx)
{
- struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */
int err;

- err = lzo1x_1_compress(src, slen, dst, &tmp_len, ctx->lzo_comp_mem);
+ err = lzo1x_1_compress(src, slen, dst, &tmp_len, ctx);

if (err != LZO_E_OK)
return -EINVAL;
@@ -64,8 +80,16 @@ static int lzo_compress(struct crypto_tfm *tfm, const u8 *src,
return 0;
}

-static int lzo_decompress(struct crypto_tfm *tfm, const u8 *src,
- unsigned int slen, u8 *dst, unsigned int *dlen)
+static int lzo_compress(struct crypto_tfm *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+ struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ return __lzo_compress(src, slen, dst, dlen, ctx->lzo_comp_mem);
+}
+
+static int __lzo_decompress(const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen, void *ctx)
{
int err;
size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */
@@ -77,7 +101,12 @@ static int lzo_decompress(struct crypto_tfm *tfm, const u8 *src,

*dlen = tmp_len;
return 0;
+}

+static int lzo_decompress(struct crypto_tfm *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+ return __lzo_decompress(src, slen, dst, dlen, NULL);
}

static struct crypto_alg alg = {
@@ -92,14 +121,40 @@ static struct crypto_alg alg = {
.coa_decompress = lzo_decompress } }
};

+static struct ccomp_alg ccomp = {
+ .alloc_context = lzo_alloc_context,
+ .free_context = lzo_free_context,
+ .compress = __lzo_compress,
+ .decompress = __lzo_decompress,
+ .flags = CCOMP_TYPE_DECOMP_NOCTX,
+ .base = {
+ .cra_name = "lzo",
+ .cra_flags = CRYPTO_ALG_TYPE_CCOMPRESS,
+ .cra_module = THIS_MODULE,
+ }
+};
+
static int __init lzo_mod_init(void)
{
- return crypto_register_alg(&alg);
+ int ret;
+
+ ret = crypto_register_alg(&alg);
+ if (ret)
+ return ret;
+
+ ret = crypto_register_ccomp(&ccomp);
+ if (ret) {
+ crypto_unregister_alg(&alg);
+ return ret;
+ }
+
+ return ret;
}

static void __exit lzo_mod_fini(void)
{
crypto_unregister_alg(&alg);
+ crypto_unregister_ccomp(&ccomp);
}

module_init(lzo_mod_init);
--
1.9.1

2015-10-14 07:38:19

by Joonsoo Kim

[permalink] [raw]
Subject: [PATCH v4 3/8] crypto/lz4: support contextless compressiona API

Now, contextless compression API is introduced and it can reduce
memory overhead in some cases. All compression algorithm will
support it.

Signed-off-by: Joonsoo Kim <[email protected]>
---
crypto/lz4.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 67 insertions(+), 10 deletions(-)

diff --git a/crypto/lz4.c b/crypto/lz4.c
index aefbcea..9720409 100644
--- a/crypto/lz4.c
+++ b/crypto/lz4.c
@@ -23,36 +23,53 @@
#include <linux/crypto.h>
#include <linux/vmalloc.h>
#include <linux/lz4.h>
+#include <crypto/compress.h>

struct lz4_ctx {
void *lz4_comp_mem;
};

+static void *lz4_alloc_context(struct crypto_ccomp *tfm)
+{
+ void *ctx;
+
+ ctx = vmalloc(LZ4_MEM_COMPRESS);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ return ctx;
+}
+
static int lz4_init(struct crypto_tfm *tfm)
{
struct lz4_ctx *ctx = crypto_tfm_ctx(tfm);

- ctx->lz4_comp_mem = vmalloc(LZ4_MEM_COMPRESS);
- if (!ctx->lz4_comp_mem)
+ ctx->lz4_comp_mem = lz4_alloc_context(NULL);
+ if (IS_ERR(ctx->lz4_comp_mem))
return -ENOMEM;

return 0;
}

+static void lz4_free_context(struct crypto_ccomp *tfm, void *ctx)
+{
+ vfree(ctx);
+}
+
static void lz4_exit(struct crypto_tfm *tfm)
{
struct lz4_ctx *ctx = crypto_tfm_ctx(tfm);
- vfree(ctx->lz4_comp_mem);
+
+ lz4_free_context(NULL, ctx->lz4_comp_mem);
}

-static int lz4_compress_crypto(struct crypto_tfm *tfm, const u8 *src,
- unsigned int slen, u8 *dst, unsigned int *dlen)
+static int __lz4_compress_crypto(const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen, void *ctx)
{
- struct lz4_ctx *ctx = crypto_tfm_ctx(tfm);
size_t tmp_len = *dlen;
int err;

- err = lz4_compress(src, slen, dst, &tmp_len, ctx->lz4_comp_mem);
+ err = lz4_compress(src, slen, dst, &tmp_len, ctx);

if (err < 0)
return -EINVAL;
@@ -61,8 +78,16 @@ static int lz4_compress_crypto(struct crypto_tfm *tfm, const u8 *src,
return 0;
}

-static int lz4_decompress_crypto(struct crypto_tfm *tfm, const u8 *src,
- unsigned int slen, u8 *dst, unsigned int *dlen)
+static int lz4_compress_crypto(struct crypto_tfm *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+ struct lz4_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ return __lz4_compress_crypto(src, slen, dst, dlen, ctx->lz4_comp_mem);
+}
+
+static int __lz4_decompress_crypto(const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen, void *ctx)
{
int err;
size_t tmp_len = *dlen;
@@ -76,6 +101,12 @@ static int lz4_decompress_crypto(struct crypto_tfm *tfm, const u8 *src,
return err;
}

+static int lz4_decompress_crypto(struct crypto_tfm *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+ return __lz4_decompress_crypto(src, slen, dst, dlen, NULL);
+}
+
static struct crypto_alg alg_lz4 = {
.cra_name = "lz4",
.cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
@@ -89,14 +120,40 @@ static struct crypto_alg alg_lz4 = {
.coa_decompress = lz4_decompress_crypto } }
};

+static struct ccomp_alg ccomp = {
+ .alloc_context = lz4_alloc_context,
+ .free_context = lz4_free_context,
+ .compress = __lz4_compress_crypto,
+ .decompress = __lz4_decompress_crypto,
+ .flags = CCOMP_TYPE_DECOMP_NOCTX,
+ .base = {
+ .cra_name = "lz4",
+ .cra_flags = CRYPTO_ALG_TYPE_CCOMPRESS,
+ .cra_module = THIS_MODULE,
+ }
+};
+
static int __init lz4_mod_init(void)
{
- return crypto_register_alg(&alg_lz4);
+ int ret;
+
+ ret = crypto_register_alg(&alg_lz4);
+ if (ret)
+ return ret;
+
+ ret = crypto_register_ccomp(&ccomp);
+ if (ret) {
+ crypto_unregister_alg(&alg_lz4);
+ return ret;
+ }
+
+ return ret;
}

static void __exit lz4_mod_fini(void)
{
crypto_unregister_alg(&alg_lz4);
+ crypto_unregister_ccomp(&ccomp);
}

module_init(lz4_mod_init);
--
1.9.1

2015-10-14 08:32:54

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v4 4/8] crypto/deflate: support contextless compression API

Hi Joonsoo,

[auto build test ERROR on next-20151013 -- if it's inappropriate base, please suggest rules for selecting the more suitable base]

url: https://github.com/0day-ci/linux/commits/Joonsoo-Kim/zram-introduce-contextless-compression-API-and-use-it-on-zram/20151014-154649
config: i386-randconfig-i0-201541 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All errors (new ones prefixed by >>):

crypto/built-in.o: In function `deflate_mod_fini':
>> deflate.c:(.exit.text+0x2a0): undefined reference to `crypto_unregister_ccomp'
crypto/built-in.o: In function `deflate_mod_init':
>> deflate.c:(.init.text+0x525): undefined reference to `crypto_register_ccomp'

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (901.00 B)
.config.gz (15.86 kB)
Download all attachments

2015-10-14 08:40:06

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v4 3/8] crypto/lz4: support contextless compressiona API

Hi Joonsoo,

[auto build test ERROR on next-20151013 -- if it's inappropriate base, please suggest rules for selecting the more suitable base]

url: https://github.com/0day-ci/linux/commits/Joonsoo-Kim/zram-introduce-contextless-compression-API-and-use-it-on-zram/20151014-154649
config: i386-randconfig-s1-201541 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All errors (new ones prefixed by >>):

crypto/built-in.o: In function `lz4_mod_fini':
>> lz4.c:(.exit.text+0x249): undefined reference to `crypto_unregister_ccomp'
crypto/built-in.o: In function `lz4_mod_init':
>> lz4.c:(.init.text+0x2f5): undefined reference to `crypto_register_ccomp'

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (885.00 B)
.config.gz (24.49 kB)
Download all attachments

2015-10-14 10:09:45

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v4 4/8] crypto/deflate: support contextless compression API

Hi Joonsoo,

[auto build test ERROR on next-20151013 -- if it's inappropriate base, please suggest rules for selecting the more suitable base]

url: https://github.com/0day-ci/linux/commits/Joonsoo-Kim/zram-introduce-contextless-compression-API-and-use-it-on-zram/20151014-154649
config: parisc-defconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=parisc

All errors (new ones prefixed by >>):

crypto/built-in.o: In function `deflate_mod_fini':
>> crypto/deflate.o:(.exit.text+0x278): undefined reference to `crypto_unregister_ccomp'
crypto/built-in.o: In function `deflate_mod_init':
>> crypto/deflate.o:(.init.text+0x31c): undefined reference to `crypto_register_ccomp'

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (1.04 kB)
.config.gz (13.85 kB)
Download all attachments

2015-10-14 10:26:50

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v4 4/8] crypto/deflate: support contextless compression API

Hi Joonsoo,

[auto build test ERROR on next-20151013 -- if it's inappropriate base, please suggest rules for selecting the more suitable base]

url: https://github.com/0day-ci/linux/commits/Joonsoo-Kim/zram-introduce-contextless-compression-API-and-use-it-on-zram/20151014-154649
config: m32r-usrv_defconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=m32r

All errors (new ones prefixed by >>):

crypto/built-in.o: In function `deflate_mod_init':
>> crypto/deflate.c:280: undefined reference to `crypto_register_ccomp'
crypto/deflate.c:280:(.init.text+0x244): relocation truncated to fit: R_M32R_26_PCREL_RELA against undefined symbol `crypto_register_ccomp'

vim +280 crypto/deflate.c

274 int ret;
275
276 ret = crypto_register_alg(&alg);
277 if (ret)
278 return ret;
279
> 280 ret = crypto_register_ccomp(&ccomp);
281 if (ret) {
282 crypto_unregister_alg(&alg);
283 return ret;

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (1.28 kB)
.config.gz (7.79 kB)
Download all attachments

2015-10-15 00:28:12

by Sergey Senozhatsky

[permalink] [raw]
Subject: Re: [PATCH v4 8/8] zram: enable contextless compression alg in zram

Hi,

On (10/14/15 16:38), Joonsoo Kim wrote:
[..]
> static const char * const backends[] = {
> "lzo",
> -#ifdef CONFIG_ZRAM_LZ4_COMPRESS
> "lz4",
> -#endif
> NULL
> };
>
> static const char *find_backend(const char *compress)
> {
> - int i = 0;
> - while (backends[i]) {
> - if (sysfs_streq(compress, backends[i]) &&
> - crypto_has_comp(backends[i], 0, 0))
> - break;
> - i++;
> - }
> - return backends[i];
> + if (crypto_has_comp(compress, 0, 0))
> + return compress;
> +
> + return NULL;
> }
>
> static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
> @@ -277,6 +271,9 @@ ssize_t zcomp_available_show(const char *comp, char *buf)
> int i = 0;
>
> while (backends[i]) {
> + if (!crypto_has_comp(backends[i], 0, 0))
> + continue;
> +

hm... this sort of looks a bit `unnatural' to me. we have two _independent_
sets -- what zram supports and what crypto supports. that's why you have
to do extra work and consult crypto. can we return back the old scheme:
use ifdef CONFIG in backends, but replace CONFIG_ZRAM with CONFIG_CRYPTO?

e.g.

static const char * const backends[] = {
"lzo",
#ifdef CONFIG_CRYPTO_LZ4
"lz4",
#endif
NULL
};


so you can remove `crypto_has_comp(backends[i], 0, 0)' from
zcomp_available_show(), because zram will support *only* what
crypto supports.

-ss


> if (!strcmp(comp, backends[i]))
> sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
> "[%s] ", backends[i]);
> diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
> index 6f04fb2..6b4cf85 100644
> --- a/drivers/block/zram/zram_drv.c
> +++ b/drivers/block/zram/zram_drv.c
> @@ -352,6 +352,7 @@ static ssize_t comp_algorithm_show(struct device *dev,
> size_t sz;
> struct zram *zram = dev_to_zram(dev);
>
> + deprecated_attr_warn("comp_algorithm");
> down_read(&zram->init_lock);
> sz = zcomp_available_show(zram->compressor, buf);
> up_read(&zram->init_lock);
> --
> 1.9.1
>

2015-10-15 00:37:51

by Sergey Senozhatsky

[permalink] [raw]
Subject: Re: [PATCH v4 7/8] zram: use crypto contextless compression API to (de)compress

Hi,

On (10/14/15 16:38), Joonsoo Kim wrote:
[..]
> Creates virtual block devices called /dev/zramX (X = 0, 1, ...).
> @@ -18,9 +17,8 @@ config ZRAM
> config ZRAM_LZ4_COMPRESS
> bool "Enable LZ4 algorithm support"
> depends on ZRAM
> - select LZ4_COMPRESS
> - select LZ4_DECOMPRESS
> + select CRYPTO_LZ4
> default n
> help
> This option enables LZ4 compression algorithm support. Compression
> - algorithm can be changed using `comp_algorithm' device attribute.
> \ No newline at end of file
> + algorithm can be changed using `comp_algorithm' device attribute.
> diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile
> index be0763f..9e2b79e 100644
> --- a/drivers/block/zram/Makefile
> +++ b/drivers/block/zram/Makefile
> @@ -1,5 +1,3 @@
> -zram-y := zcomp_lzo.o zcomp.o zram_drv.o
> -
> -zram-$(CONFIG_ZRAM_LZ4_COMPRESS) += zcomp_lz4.o
> +zram-y := zcomp.o zram_drv.o

+ git rm zcomp_lzo.* zcomp_lz4.* :)


> obj-$(CONFIG_ZRAM) += zram.o
> diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
> index e3016da..9be83db 100644
> --- a/drivers/block/zram/zcomp.c
> +++ b/drivers/block/zram/zcomp.c
> @@ -15,10 +15,6 @@
> #include <linux/sched.h>
>
> #include "zcomp.h"
> -#include "zcomp_lzo.h"
> -#ifdef CONFIG_ZRAM_LZ4_COMPRESS
> -#include "zcomp_lz4.h"
> -#endif
>
> /*
> * single zcomp_strm backend
> @@ -43,19 +39,20 @@ struct zcomp_strm_multi {
> wait_queue_head_t strm_wait;
> };
>
> -static struct zcomp_backend *backends[] = {
> - &zcomp_lzo,
> +static const char * const backends[] = {
> + "lzo",
> #ifdef CONFIG_ZRAM_LZ4_COMPRESS

a nitpick -- this CONFIG option does not exist at this point.

> - &zcomp_lz4,
> + "lz4",
> #endif
> NULL
> };
>
> -static struct zcomp_backend *find_backend(const char *compress)
> +static const char *find_backend(const char *compress)
> {
> int i = 0;
> while (backends[i]) {
> - if (sysfs_streq(compress, backends[i]->name))
> + if (sysfs_streq(compress, backends[i]) &&
> + crypto_has_comp(backends[i], 0, 0))

again (the same as in my previous email). I'd rather prefer to have
FOO backends in ` const char * const backends[]' array only when the
corresponding CONFIG_CRYPTO_FOO option has been selected. otherwise you
have to find an intersection of two independent sets. sort of unreasonable
to me.


> break;
> i++;
> }
> @@ -65,7 +62,7 @@ static struct zcomp_backend *find_backend(const char *compress)
> static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
> {
> if (zstrm->private)
> - comp->backend->destroy(zstrm->private);
> + crypto_ccomp_free_context(comp->tfm, zstrm->private);
> free_pages((unsigned long)zstrm->buffer, 1);
> kfree(zstrm);
> }
> @@ -80,7 +77,13 @@ static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp)
> if (!zstrm)
> return NULL;
>
> - zstrm->private = comp->backend->create();
> + zstrm->private = crypto_ccomp_alloc_context(comp->tfm);
> + if (IS_ERR(zstrm->private)) {
> + zstrm->private = NULL;
> + zcomp_strm_free(comp, zstrm);
> + return NULL;
> + }
> +
> /*
> * allocate 2 pages. 1 for compressed data, plus 1 extra for the
> * case when compressed size is larger than the original one
> @@ -274,12 +277,12 @@ ssize_t zcomp_available_show(const char *comp, char *buf)
> int i = 0;
>
> while (backends[i]) {
> - if (!strcmp(comp, backends[i]->name))
> + if (!strcmp(comp, backends[i]))
> sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
> - "[%s] ", backends[i]->name);
> + "[%s] ", backends[i]);
> else
> sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
> - "%s ", backends[i]->name);
> + "%s ", backends[i]);
> i++;
> }
> sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n");
> @@ -320,7 +323,10 @@ void zcomp_compress_end(struct zcomp *comp, struct zcomp_strm *zstrm)
> /* May return NULL, may sleep */
> struct zcomp_strm *zcomp_decompress_begin(struct zcomp *comp)
> {
> - return NULL;
> + if (crypto_ccomp_decomp_noctx(comp->tfm))
> + return NULL;
> +
> + return zcomp_strm_find(comp);
> }
>
> void zcomp_decompress_end(struct zcomp *comp, struct zcomp_strm *zstrm)
> @@ -330,22 +336,29 @@ void zcomp_decompress_end(struct zcomp *comp, struct zcomp_strm *zstrm)
> }
>
> int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
> - const unsigned char *src, size_t *dst_len)
> + const unsigned char *src, unsigned int *dst_len)
> {
> - return comp->backend->compress(src, zstrm->buffer, dst_len,
> - zstrm->private);
> + *dst_len = PAGE_SIZE << 1;
> +
> + return crypto_ccomp_compress(comp->tfm, src, PAGE_SIZE,
> + zstrm->buffer, dst_len, zstrm->private);
> }
>
> int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
> const unsigned char *src,
> - size_t src_len, unsigned char *dst)
> + unsigned int src_len, unsigned char *dst)
> {
> - return comp->backend->decompress(src, src_len, dst);
> + unsigned int size = PAGE_SIZE;
> + void *private = zstrm ? zstrm->private : NULL;
> +
> + return crypto_ccomp_decompress(comp->tfm, src, src_len,
> + dst, &size, private);
> }
>
> void zcomp_destroy(struct zcomp *comp)
> {
> comp->destroy(comp);
> + crypto_free_ccomp(comp->tfm);
> kfree(comp);
> }
>
> @@ -360,7 +373,7 @@ void zcomp_destroy(struct zcomp *comp)
> struct zcomp *zcomp_create(const char *compress, int max_strm)
> {
> struct zcomp *comp;
> - struct zcomp_backend *backend;
> + const char *backend;
> int error;
>
> backend = find_backend(compress);
> @@ -371,12 +384,18 @@ struct zcomp *zcomp_create(const char *compress, int max_strm)
> if (!comp)
> return ERR_PTR(-ENOMEM);
>
> - comp->backend = backend;
> + comp->tfm = crypto_alloc_ccomp(backend, 0, 0);
> + if (IS_ERR(comp->tfm)) {
> + kfree(comp);
> + return ERR_CAST(comp->tfm);
> + }
> +
> if (max_strm > 1)
> error = zcomp_strm_multi_create(comp, max_strm);
> else
> error = zcomp_strm_single_create(comp);
> if (error) {
> + crypto_free_ccomp(comp->tfm);
> kfree(comp);

hm... zcomp_destroy(comp) ?

> return ERR_PTR(error);
> }
> diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
> index 4c09c01..df9268d 100644
> --- a/drivers/block/zram/zcomp.h
> +++ b/drivers/block/zram/zcomp.h
> @@ -11,6 +11,7 @@
> #define _ZCOMP_H_
>
> #include <linux/mutex.h>
> +#include <crypto/compress.h>
>
> struct zcomp_strm {
> /* compression/decompression buffer */
> @@ -25,24 +26,10 @@ struct zcomp_strm {
> struct list_head list;
> };
>
> -/* static compression backend */
> -struct zcomp_backend {
> - int (*compress)(const unsigned char *src, unsigned char *dst,
> - size_t *dst_len, void *private);
> -
> - int (*decompress)(const unsigned char *src, size_t src_len,
> - unsigned char *dst);
> -
> - void *(*create)(void);
> - void (*destroy)(void *private);
> -
> - const char *name;
> -};
> -
> /* dynamic per-device compression frontend */
> struct zcomp {
> void *stream;
> - struct zcomp_backend *backend;
> + struct crypto_ccomp *tfm;
>
> struct zcomp_strm *(*strm_find)(struct zcomp *comp);
> void (*strm_release)(struct zcomp *comp, struct zcomp_strm *zstrm);
> @@ -61,14 +48,14 @@ struct zcomp_strm *zcomp_compress_begin(struct zcomp *comp);
> void zcomp_compress_end(struct zcomp *comp, struct zcomp_strm *zstrm);
>
> int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
> - const unsigned char *src, size_t *dst_len);
> + const unsigned char *src, unsigned int *dst_len);
>
> struct zcomp_strm *zcomp_decompress_begin(struct zcomp *comp);
> void zcomp_decompress_end(struct zcomp *comp, struct zcomp_strm *zstrm);
>
> int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
> const unsigned char *src,
> - size_t src_len, unsigned char *dst);
> + unsigned int src_len, unsigned char *dst);
>
> bool zcomp_set_max_streams(struct zcomp *comp, int num_strm);
> #endif /* _ZCOMP_H_ */
> diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
> index 85d5301..6f04fb2 100644
> --- a/drivers/block/zram/zram_drv.c
> +++ b/drivers/block/zram/zram_drv.c
> @@ -567,7 +567,7 @@ static int zram_decompress_page(struct zram *zram, struct zcomp_strm *zstrm,
> unsigned char *cmem;
> struct zram_meta *meta = zram->meta;
> unsigned long handle;
> - size_t size;
> + unsigned int size;
>
> bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
> handle = meta->table[index].handle;
> @@ -656,7 +656,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
> int offset)
> {
> int ret = 0;
> - size_t clen;
> + unsigned int clen;
> unsigned long handle;
> struct page *page;
> unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
> @@ -731,7 +731,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
>
> handle = zs_malloc(meta->mem_pool, clen);
> if (!handle) {
> - pr_err("Error allocating memory for compressed page: %u, size=%zu\n",
> + pr_err("Error allocating memory for compressed page: %u, size=%u\n",
> index, clen);
> ret = -ENOMEM;
> goto out;
> --
> 1.9.1
>

2015-10-15 00:45:22

by Joonsoo Kim

[permalink] [raw]
Subject: Re: [PATCH v4 8/8] zram: enable contextless compression alg in zram

On Thu, Oct 15, 2015 at 09:29:03AM +0900, Sergey Senozhatsky wrote:
> Hi,
>
> On (10/14/15 16:38), Joonsoo Kim wrote:
> [..]
> > static const char * const backends[] = {
> > "lzo",
> > -#ifdef CONFIG_ZRAM_LZ4_COMPRESS
> > "lz4",
> > -#endif
> > NULL
> > };
> >
> > static const char *find_backend(const char *compress)
> > {
> > - int i = 0;
> > - while (backends[i]) {
> > - if (sysfs_streq(compress, backends[i]) &&
> > - crypto_has_comp(backends[i], 0, 0))
> > - break;
> > - i++;
> > - }
> > - return backends[i];
> > + if (crypto_has_comp(compress, 0, 0))
> > + return compress;
> > +
> > + return NULL;
> > }
> >
> > static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
> > @@ -277,6 +271,9 @@ ssize_t zcomp_available_show(const char *comp, char *buf)
> > int i = 0;
> >
> > while (backends[i]) {
> > + if (!crypto_has_comp(backends[i], 0, 0))
> > + continue;
> > +
>
> hm... this sort of looks a bit `unnatural' to me. we have two _independent_
> sets -- what zram supports and what crypto supports. that's why you have
> to do extra work and consult crypto. can we return back the old scheme:
> use ifdef CONFIG in backends, but replace CONFIG_ZRAM with CONFIG_CRYPTO?
>
> e.g.
>
> static const char * const backends[] = {
> "lzo",
> #ifdef CONFIG_CRYPTO_LZ4
> "lz4",
> #endif
> NULL
> };
>
>
> so you can remove `crypto_has_comp(backends[i], 0, 0)' from
> zcomp_available_show(), because zram will support *only* what
> crypto supports.

Hello, Sergey.

Okay. I will change it in next spin.

Anyway, now I noticed that crypto_has_comp() is not proper API to
check contextless compression algorithm. I will change it, too.

Thanks.

2015-10-15 01:06:44

by Joonsoo Kim

[permalink] [raw]
Subject: Re: [PATCH v4 7/8] zram: use crypto contextless compression API to (de)compress

On Thu, Oct 15, 2015 at 09:38:41AM +0900, Sergey Senozhatsky wrote:
> Hi,
>
> On (10/14/15 16:38), Joonsoo Kim wrote:
> [..]
> > Creates virtual block devices called /dev/zramX (X = 0, 1, ...).
> > @@ -18,9 +17,8 @@ config ZRAM
> > config ZRAM_LZ4_COMPRESS
> > bool "Enable LZ4 algorithm support"
> > depends on ZRAM
> > - select LZ4_COMPRESS
> > - select LZ4_DECOMPRESS
> > + select CRYPTO_LZ4
> > default n
> > help
> > This option enables LZ4 compression algorithm support. Compression
> > - algorithm can be changed using `comp_algorithm' device attribute.
> > \ No newline at end of file
> > + algorithm can be changed using `comp_algorithm' device attribute.
> > diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile
> > index be0763f..9e2b79e 100644
> > --- a/drivers/block/zram/Makefile
> > +++ b/drivers/block/zram/Makefile
> > @@ -1,5 +1,3 @@
> > -zram-y := zcomp_lzo.o zcomp.o zram_drv.o
> > -
> > -zram-$(CONFIG_ZRAM_LZ4_COMPRESS) += zcomp_lz4.o
> > +zram-y := zcomp.o zram_drv.o
>
> + git rm zcomp_lzo.* zcomp_lz4.* :)

Will do. :)

>
>
> > obj-$(CONFIG_ZRAM) += zram.o
> > diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
> > index e3016da..9be83db 100644
> > --- a/drivers/block/zram/zcomp.c
> > +++ b/drivers/block/zram/zcomp.c
> > @@ -15,10 +15,6 @@
> > #include <linux/sched.h>
> >
> > #include "zcomp.h"
> > -#include "zcomp_lzo.h"
> > -#ifdef CONFIG_ZRAM_LZ4_COMPRESS
> > -#include "zcomp_lz4.h"
> > -#endif
> >
> > /*
> > * single zcomp_strm backend
> > @@ -43,19 +39,20 @@ struct zcomp_strm_multi {
> > wait_queue_head_t strm_wait;
> > };
> >
> > -static struct zcomp_backend *backends[] = {
> > - &zcomp_lzo,
> > +static const char * const backends[] = {
> > + "lzo",
> > #ifdef CONFIG_ZRAM_LZ4_COMPRESS
>
> a nitpick -- this CONFIG option does not exist at this point.

Will fix.

>
> > - &zcomp_lz4,
> > + "lz4",
> > #endif
> > NULL
> > };
> >
> > -static struct zcomp_backend *find_backend(const char *compress)
> > +static const char *find_backend(const char *compress)
> > {
> > int i = 0;
> > while (backends[i]) {
> > - if (sysfs_streq(compress, backends[i]->name))
> > + if (sysfs_streq(compress, backends[i]) &&
> > + crypto_has_comp(backends[i], 0, 0))
>
> again (the same as in my previous email). I'd rather prefer to have
> FOO backends in ` const char * const backends[]' array only when the
> corresponding CONFIG_CRYPTO_FOO option has been selected. otherwise you
> have to find an intersection of two independent sets. sort of unreasonable
> to me.

Okay.

>
> > break;
> > i++;
> > }
> > @@ -65,7 +62,7 @@ static struct zcomp_backend *find_backend(const char *compress)
> > static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
> > {
> > if (zstrm->private)
> > - comp->backend->destroy(zstrm->private);
> > + crypto_ccomp_free_context(comp->tfm, zstrm->private);
> > free_pages((unsigned long)zstrm->buffer, 1);
> > kfree(zstrm);
> > }
> > @@ -80,7 +77,13 @@ static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp)
> > if (!zstrm)
> > return NULL;
> >
> > - zstrm->private = comp->backend->create();
> > + zstrm->private = crypto_ccomp_alloc_context(comp->tfm);
> > + if (IS_ERR(zstrm->private)) {
> > + zstrm->private = NULL;
> > + zcomp_strm_free(comp, zstrm);
> > + return NULL;
> > + }
> > +
> > /*
> > * allocate 2 pages. 1 for compressed data, plus 1 extra for the
> > * case when compressed size is larger than the original one
> > @@ -274,12 +277,12 @@ ssize_t zcomp_available_show(const char *comp, char *buf)
> > int i = 0;
> >
> > while (backends[i]) {
> > - if (!strcmp(comp, backends[i]->name))
> > + if (!strcmp(comp, backends[i]))
> > sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
> > - "[%s] ", backends[i]->name);
> > + "[%s] ", backends[i]);
> > else
> > sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
> > - "%s ", backends[i]->name);
> > + "%s ", backends[i]);
> > i++;
> > }
> > sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n");
> > @@ -320,7 +323,10 @@ void zcomp_compress_end(struct zcomp *comp, struct zcomp_strm *zstrm)
> > /* May return NULL, may sleep */
> > struct zcomp_strm *zcomp_decompress_begin(struct zcomp *comp)
> > {
> > - return NULL;
> > + if (crypto_ccomp_decomp_noctx(comp->tfm))
> > + return NULL;
> > +
> > + return zcomp_strm_find(comp);
> > }
> >
> > void zcomp_decompress_end(struct zcomp *comp, struct zcomp_strm *zstrm)
> > @@ -330,22 +336,29 @@ void zcomp_decompress_end(struct zcomp *comp, struct zcomp_strm *zstrm)
> > }
> >
> > int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
> > - const unsigned char *src, size_t *dst_len)
> > + const unsigned char *src, unsigned int *dst_len)
> > {
> > - return comp->backend->compress(src, zstrm->buffer, dst_len,
> > - zstrm->private);
> > + *dst_len = PAGE_SIZE << 1;
> > +
> > + return crypto_ccomp_compress(comp->tfm, src, PAGE_SIZE,
> > + zstrm->buffer, dst_len, zstrm->private);
> > }
> >
> > int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
> > const unsigned char *src,
> > - size_t src_len, unsigned char *dst)
> > + unsigned int src_len, unsigned char *dst)
> > {
> > - return comp->backend->decompress(src, src_len, dst);
> > + unsigned int size = PAGE_SIZE;
> > + void *private = zstrm ? zstrm->private : NULL;
> > +
> > + return crypto_ccomp_decompress(comp->tfm, src, src_len,
> > + dst, &size, private);
> > }
> >
> > void zcomp_destroy(struct zcomp *comp)
> > {
> > comp->destroy(comp);
> > + crypto_free_ccomp(comp->tfm);
> > kfree(comp);
> > }
> >
> > @@ -360,7 +373,7 @@ void zcomp_destroy(struct zcomp *comp)
> > struct zcomp *zcomp_create(const char *compress, int max_strm)
> > {
> > struct zcomp *comp;
> > - struct zcomp_backend *backend;
> > + const char *backend;
> > int error;
> >
> > backend = find_backend(compress);
> > @@ -371,12 +384,18 @@ struct zcomp *zcomp_create(const char *compress, int max_strm)
> > if (!comp)
> > return ERR_PTR(-ENOMEM);
> >
> > - comp->backend = backend;
> > + comp->tfm = crypto_alloc_ccomp(backend, 0, 0);
> > + if (IS_ERR(comp->tfm)) {
> > + kfree(comp);
> > + return ERR_CAST(comp->tfm);
> > + }
> > +
> > if (max_strm > 1)
> > error = zcomp_strm_multi_create(comp, max_strm);
> > else
> > error = zcomp_strm_single_create(comp);
> > if (error) {
> > + crypto_free_ccomp(comp->tfm);
> > kfree(comp);
>
> hm... zcomp_destroy(comp) ?

It's not possible to use zcomp_destroy() here. It tries to access
field of comp->stream which could be NULL.

Thanks.

2015-10-15 01:52:42

by Sergey Senozhatsky

[permalink] [raw]
Subject: Re: [PATCH v4 7/8] zram: use crypto contextless compression API to (de)compress

On (10/15/15 10:07), Joonsoo Kim wrote:
[..]
> > > if (error) {
> > > + crypto_free_ccomp(comp->tfm);
> > > kfree(comp);
> >
> > hm... zcomp_destroy(comp) ?
>
> It's not possible to use zcomp_destroy() here. It tries to access
> field of comp->stream which could be NULL.

ah, yep. my bad.

-ss

2015-10-15 02:05:49

by Sergey Senozhatsky

[permalink] [raw]
Subject: Re: [PATCH v4 8/8] zram: enable contextless compression alg in zram

On (10/14/15 16:38), Joonsoo Kim wrote:
[..]
> @@ -352,6 +352,7 @@ static ssize_t comp_algorithm_show(struct device *dev,
> size_t sz;
> struct zram *zram = dev_to_zram(dev);
>
> + deprecated_attr_warn("comp_algorithm");
> down_read(&zram->init_lock);
> sz = zcomp_available_show(zram->compressor, buf);
> up_read(&zram->init_lock);

oh, one more thing.

deprecated_attr_warn() should come with `Documentation/ABI/obsolete/sysfs-block-zram' update.
something like:

diff --git a/Documentation/ABI/obsolete/sysfs-block-zram b/Documentation/ABI/obsolete/sysfs-block-zram
index 720ea92..ad5b59d 100644
--- a/Documentation/ABI/obsolete/sysfs-block-zram
+++ b/Documentation/ABI/obsolete/sysfs-block-zram
@@ -117,3 +117,14 @@ Description:
Downgraded to write-only node: so it's possible to set new
value only; its current value is stored in zram<id>/mm_stat
node.
+
+What: /sys/block/zram<id>/comp_algorithm
+Date: XXX
+Contact: XXX
+Description:
+ The comp_algorithm file is read/write and provides information
+ on available, currently selected compression algorithm (read
+ operation) and lets one to change the compression algorithm
+ (write operation).
+ Downgraded to write-only node: use `/proc/crypto' to get the
+ list of supported compression algorithms.


---


And I guess Cc `Jonathan Corbet <[email protected]>' (doc maintainer) and
'[email protected]' will be the right thing to do here.

-ss

2015-10-15 02:47:27

by Joonsoo Kim

[permalink] [raw]
Subject: Re: [PATCH v4 8/8] zram: enable contextless compression alg in zram

On Thu, Oct 15, 2015 at 11:05:49AM +0900, Sergey Senozhatsky wrote:
> On (10/14/15 16:38), Joonsoo Kim wrote:
> [..]
> > @@ -352,6 +352,7 @@ static ssize_t comp_algorithm_show(struct device *dev,
> > size_t sz;
> > struct zram *zram = dev_to_zram(dev);
> >
> > + deprecated_attr_warn("comp_algorithm");
> > down_read(&zram->init_lock);
> > sz = zcomp_available_show(zram->compressor, buf);
> > up_read(&zram->init_lock);
>
> oh, one more thing.
>
> deprecated_attr_warn() should come with `Documentation/ABI/obsolete/sysfs-block-zram' update.
> something like:
>
> diff --git a/Documentation/ABI/obsolete/sysfs-block-zram b/Documentation/ABI/obsolete/sysfs-block-zram
> index 720ea92..ad5b59d 100644
> --- a/Documentation/ABI/obsolete/sysfs-block-zram
> +++ b/Documentation/ABI/obsolete/sysfs-block-zram
> @@ -117,3 +117,14 @@ Description:
> Downgraded to write-only node: so it's possible to set new
> value only; its current value is stored in zram<id>/mm_stat
> node.
> +
> +What: /sys/block/zram<id>/comp_algorithm
> +Date: XXX
> +Contact: XXX
> +Description:
> + The comp_algorithm file is read/write and provides information
> + on available, currently selected compression algorithm (read
> + operation) and lets one to change the compression algorithm
> + (write operation).
> + Downgraded to write-only node: use `/proc/crypto' to get the
> + list of supported compression algorithms.
>
>
> ---
>
>
> And I guess Cc `Jonathan Corbet <[email protected]>' (doc maintainer) and
> '[email protected]' will be the right thing to do here.

Okay. I will do it in next spin.

Thanks.