@@ -23,4 +23,14 @@ config ZRAM_LZ4_COMPRESS
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.
+
+config ZRAM_ZLIB_COMPRESS
+ bool "Enable ZLIB algorithm support"
+ depends on ZRAM
+ select ZLIB_INFLATE
+ select ZLIB_DEFLATE
+ default n
+ help
+ This option enables ZLIB compression algorithm support. Compression
+ algorithm can be changed using `comp_algorithm' device attribute.
@@ -1,5 +1,6 @@
zram-y := zcomp_lzo.o zcomp.o zram_drv.o
zram-$(CONFIG_ZRAM_LZ4_COMPRESS) += zcomp_lz4.o
+zram-$(CONFIG_ZRAM_ZLIB_COMPRESS) += zcomp_zlib.o
obj-$(CONFIG_ZRAM) += zram.o
@@ -19,6 +19,9 @@
#ifdef CONFIG_ZRAM_LZ4_COMPRESS
#include "zcomp_lz4.h"
#endif
+#ifdef CONFIG_ZRAM_ZLIB_COMPRESS
+#include "zcomp_zlib.h"
+#endif
/*
* single zcomp_strm backend
@@ -48,6 +51,9 @@ static struct zcomp_backend *backends[] = {
#ifdef CONFIG_ZRAM_LZ4_COMPRESS
&zcomp_lz4,
#endif
+#ifdef CONFIG_ZRAM_ZLIB_COMPRESS
+ &zcomp_zlib,
+#endif
NULL
};
@@ -313,10 +319,16 @@ 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);
+ void *private = NULL;
+
+ if (unlikely(zstrm))
+ private = zstrm->private;
+
+ return comp->backend->decompress(src, src_len, dst, private);
}
void zcomp_destroy(struct zcomp *comp)
@@ -354,5 +366,10 @@ struct zcomp *zcomp_create(const char *compress, int max_strm)
kfree(comp);
return ERR_PTR(-ENOMEM);
}
+
+ /* FIXME quick dirty and ugly. ONLY for testing purposes */
+ if (sysfs_streq(compress, "zlib"))
+ comp->flags |= ZCOMP_NEED_READ_STRM;
+
return comp;
}
@@ -12,6 +12,8 @@
#include <linux/mutex.h>
+#define ZCOMP_NEED_READ_STRM (1 << 0)
+
struct zcomp_strm {
/* compression/decompression buffer */
void *buffer;
@@ -31,7 +33,7 @@ struct zcomp_backend {
size_t *dst_len, void *private);
int (*decompress)(const unsigned char *src, size_t src_len,
- unsigned char *dst);
+ unsigned char *dst, void *private);
void *(*create)(void);
void (*destroy)(void *private);
@@ -44,6 +46,8 @@ struct zcomp {
void *stream;
struct zcomp_backend *backend;
+ int flags;
+
struct zcomp_strm *(*strm_find)(struct zcomp *comp);
void (*strm_release)(struct zcomp *comp, struct zcomp_strm *zstrm);
bool (*set_max_streams)(struct zcomp *comp, int num_strm);
@@ -62,7 +66,8 @@ void zcomp_strm_release(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);
-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);
@@ -31,7 +31,7 @@ static int zcomp_lz4_compress(const unsigned char *src, unsigned char *dst,
}
static int zcomp_lz4_decompress(const unsigned char *src, size_t src_len,
- unsigned char *dst)
+ unsigned char *dst, void *private)
{
size_t dst_len = PAGE_SIZE;
/* return : Success if return 0 */
@@ -31,7 +31,7 @@ static int lzo_compress(const unsigned char *src, unsigned char *dst,
}
static int lzo_decompress(const unsigned char *src, size_t src_len,
- unsigned char *dst)
+ unsigned char *dst, void *private)
{
size_t dst_len = PAGE_SIZE;
int ret = lzo1x_decompress_safe(src, src_len, dst, &dst_len);
new file mode 100644
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 Sergey Senozhatsky.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/zlib.h>
+
+#include "zcomp_zlib.h"
+
+#define ZLIB_COMPRESSION_LEVEL 3
+
+static void *zlib_create(void)
+{
+ z_stream *stream;
+ size_t size;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return NULL;
+
+ size = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
+ zlib_inflate_workspacesize());
+ stream->workspace = vmalloc(size);
+ if (!stream->workspace) {
+ kfree(stream);
+ stream = NULL;
+ }
+
+ return stream;
+}
+
+static void zlib_destroy(void *private)
+{
+ z_stream *stream = private;
+
+ vfree(stream->workspace);
+ kfree(stream);
+}
+
+static int zlib_compress(const unsigned char *src, unsigned char *dst,
+ size_t *dst_len, void *private)
+{
+ z_stream *stream = private;
+ int err;
+
+ err = zlib_deflateInit(stream, ZLIB_COMPRESSION_LEVEL);
+ if (err != Z_OK)
+ goto out;
+
+ stream->next_in = src;
+ stream->avail_in = PAGE_SIZE;
+ stream->total_in = 0;
+ stream->next_out = dst;
+ stream->avail_out = PAGE_SIZE;
+ stream->total_out = 0;
+
+ err = zlib_deflate(stream, Z_FINISH);
+ if (err != Z_STREAM_END)
+ goto out;
+
+ err = zlib_deflateEnd(stream);
+ if (err != Z_OK)
+ goto out;
+
+ if (stream->total_out >= stream->total_in)
+ goto out;
+
+ *dst_len = stream->total_out;
+out:
+ return err == Z_OK ? 0 : err;
+}
+
+static int zlib_decompress(const unsigned char *src, size_t src_len,
+ unsigned char *dst, void *private)
+{
+ z_stream *stream = private;
+ int err;
+
+ err = zlib_inflateInit(stream);
+ if (err != Z_OK)
+ goto out;
+
+ stream->next_in = src;
+ stream->avail_in = src_len;
+ stream->total_in = 0;
+ stream->next_out = dst;
+ stream->avail_out = PAGE_SIZE;
+ stream->total_out = 0;
+
+ err = zlib_inflate(stream, Z_FINISH);
+ if (err != Z_STREAM_END)
+ goto out;
+
+ err = zlib_inflateEnd(stream);
+ if (err != Z_OK)
+ goto out;
+
+out:
+ return err == Z_OK ? 0 : err;
+}
+
+struct zcomp_backend zcomp_zlib = {
+ .compress = zlib_compress,
+ .decompress = zlib_decompress,
+ .create = zlib_create,
+ .destroy = zlib_destroy,
+ .name = "zlib",
+};
new file mode 100644
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2015 Sergey Senozhatsky.
+ *
+ * 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.
+ */
+
+#ifndef _ZCOMP_ZLIB_H_
+#define _ZCOMP_ZLIB_H_
+
+#include "zcomp.h"
+
+extern struct zcomp_backend zcomp_zlib;
+
+#endif /* _ZCOMP_ZLIB_H_ */
@@ -587,10 +587,19 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
}
cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO);
- if (size == PAGE_SIZE)
+ if (size == PAGE_SIZE) {
copy_page(mem, cmem);
- else
- ret = zcomp_decompress(zram->comp, cmem, size, mem);
+ } else {
+ struct zcomp_strm *zstrm = NULL;
+
+ if (unlikely(zram->comp->flags & ZCOMP_NEED_READ_STRM))
+ zstrm = zcomp_strm_find(zram->comp);
+
+ ret = zcomp_decompress(zram->comp, zstrm, cmem, size, mem);
+
+ if (unlikely(zstrm))
+ zcomp_strm_release(zram->comp, zstrm);
+ }
zs_unmap_object(meta->mem_pool, handle);
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);