[PATCH] introduce zram_comp

From: Minchan Kim
Date: Tue Feb 04 2014 - 03:27:25 EST


Signed-off-by: Minchan Kim <minchan@xxxxxxxxxx>
---
drivers/block/zram/Makefile | 5 ++-
drivers/block/zram/zcomp_lzo.c | 29 +++++++++++++++
drivers/block/zram/zram_comp.c | 84 ++++++++++++++++++++++++++++++++++++++++++
drivers/block/zram/zram_comp.h | 36 ++++++++++++++++++
drivers/block/zram/zram_drv.c | 45 ++++++++++------------
drivers/block/zram/zram_drv.h | 6 +--
6 files changed, 175 insertions(+), 30 deletions(-)
create mode 100644 drivers/block/zram/zcomp_lzo.c
create mode 100644 drivers/block/zram/zram_comp.c
create mode 100644 drivers/block/zram/zram_comp.h

diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile
index cb0f9ced6a93..7a4de6cce4e4 100644
--- a/drivers/block/zram/Makefile
+++ b/drivers/block/zram/Makefile
@@ -1,3 +1,4 @@
-zram-y := zram_drv.o
+zram-y := zram_drv.o
+zram-y += zcomp_lzo.o zram_comp.o

-obj-$(CONFIG_ZRAM) += zram.o
+obj-$(CONFIG_ZRAM) += zram.o
diff --git a/drivers/block/zram/zcomp_lzo.c b/drivers/block/zram/zcomp_lzo.c
new file mode 100644
index 000000000000..2a58d5392d4d
--- /dev/null
+++ b/drivers/block/zram/zcomp_lzo.c
@@ -0,0 +1,29 @@
+#include "zram_comp.h"
+
+#include <linux/lzo.h>
+
+void *lzo_init(void)
+{
+ void *private = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+ return private;
+}
+
+void lzo_free(void *private)
+{
+ kfree(private);
+}
+
+int lzo_compress_page(unsigned char *in, size_t in_len,
+ unsigned char *out, size_t *out_len,
+ void *private)
+{
+ return lzo1x_1_compress(in, in_len, out, out_len, private);
+}
+
+const struct zram_comp zcomp_lzo = {
+ .init = lzo_init,
+ .destroy = lzo_free,
+ .compress_page = lzo_compress_page,
+ .decompress_page = lzo1x_decompress_safe,
+ .name = "lzo",
+};
diff --git a/drivers/block/zram/zram_comp.c b/drivers/block/zram/zram_comp.c
new file mode 100644
index 000000000000..c6af6cda7529
--- /dev/null
+++ b/drivers/block/zram/zram_comp.c
@@ -0,0 +1,84 @@
+#include "zram_comp.h"
+#include <linux/sched.h>
+
+extern struct zram_comp zcomp_lzo;
+
+struct zcomp_strm *zcomp_get_strm(struct zram_comp *comp)
+{
+ struct zcomp_strm *strm;
+again:
+ mutex_lock(&comp->lock);
+ if (list_empty(&comp->strm_list)) {
+ mutex_unlock(&comp->lock);
+ /* wait */
+ wait_event(comp->wait, !list_empty(&comp->strm_list));
+ goto again;
+ }
+
+ strm = list_entry(comp->strm_list.prev,
+ struct zcomp_strm, list);
+ list_del(&strm->list);
+ mutex_unlock(&comp->lock);
+ return strm;
+}
+
+void zcomp_put_strm(struct zram_comp *comp, struct zcomp_strm *strm)
+{
+ mutex_lock(&comp->lock);
+ list_add(&strm->list, &comp->strm_list);
+ mutex_unlock(&comp->lock);
+ wake_up(&comp->wait);
+}
+
+static struct zram_comp *find_comp(char *comp_name)
+{
+ if (!strcmp(comp_name, "lzo"))
+ return &zcomp_lzo;
+
+ return NULL;
+}
+
+int zcomp_compress_page(struct zram_comp *comp, struct zcomp_strm *strm,
+ unsigned char *in, size_t *clen)
+{
+ return comp->compress_page(in, PAGE_SIZE, strm->compress_buffer,
+ clen, strm->private);
+}
+
+struct zram_comp *zcomp_create(char *comp_name, int nr_strm)
+{
+ int i;
+ struct zram_comp *comp;
+ /* Look up supported backend */
+ comp = find_comp(comp_name);
+ if (!comp)
+ return NULL;
+
+ INIT_LIST_HEAD(&comp->strm_list);
+ mutex_init(&comp->lock);
+ init_waitqueue_head(&comp->wait);
+
+ for (i = 0; i < nr_strm; i++) {
+ struct zcomp_strm *strm = kmalloc(sizeof(*strm), GFP_KERNEL);
+ strm->compress_buffer =
+ (void*)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
+ strm->private = comp->init();
+ list_add(&strm->list, &comp->strm_list);
+ }
+
+ return comp;
+}
+
+void zcomp_destroy(struct zram_comp *comp)
+{
+ struct zcomp_strm *strm;
+
+ while (!list_empty(&comp->strm_list)) {
+ strm = list_entry(comp->strm_list.prev,
+ struct zcomp_strm, list);
+ free_pages((unsigned long)strm->compress_buffer, 1);
+ comp->destroy(strm->private);
+ list_del(&strm->list);
+ kfree(strm);
+ }
+}
diff --git a/drivers/block/zram/zram_comp.h b/drivers/block/zram/zram_comp.h
new file mode 100644
index 000000000000..705b8231f4d5
--- /dev/null
+++ b/drivers/block/zram/zram_comp.h
@@ -0,0 +1,36 @@
+#ifndef __ZRAM_COMP_H_
+#define __ZRAM_COMP_H_
+
+#include <linux/slab.h>
+#include "zram_drv.h"
+
+struct zcomp_strm {
+ void *private;
+ void *compress_buffer;
+ struct list_head list;
+};
+
+struct zram_comp {
+
+ struct list_head strm_list;
+ struct mutex lock;
+ wait_queue_head_t wait;
+
+ int (*compress_page)(unsigned char *in, size_t in_len,
+ unsigned char *out, size_t *out_len, void *private);
+ int (*decompress_page)(const unsigned char *in, size_t in_len,
+ unsigned char *out, size_t *out_len);
+
+ void *(*init)(void);
+ void (*destroy)(void *private);
+ char name[10];
+};
+
+struct zcomp_strm *zcomp_get_strm(struct zram_comp *comp);
+void zcomp_put_strm(struct zram_comp *comp, struct zcomp_strm *strm);
+int zcomp_compress_page(struct zram_comp *comp, struct zcomp_strm *strm,
+ unsigned char *in, size_t *clen);
+struct zram_comp *zcomp_create(char *comp_name, int nr_strm);
+void zcomp_destroy(struct zram_comp *comp);
+
+#endif
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 25bbc59486ff..34a72903f808 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -33,6 +33,7 @@
#include <linux/string.h>
#include <linux/vmalloc.h>

+#include "zram_comp.h"
#include "zram_drv.h"

/* Globals */
@@ -160,35 +161,29 @@ static inline int valid_io_request(struct zram *zram, struct bio *bio)
static void zram_meta_free(struct zram_meta *meta)
{
zs_destroy_pool(meta->mem_pool);
- kfree(meta->compress_workmem);
- free_pages((unsigned long)meta->compress_buffer, 1);
vfree(meta->table);
kfree(meta);
}

-static struct zram_meta *zram_meta_alloc(u64 disksize)
+static struct zram_meta *zram_meta_alloc(u64 disksize, char *comp_name,
+ int nr_comp)
{
size_t num_pages;
+ struct zram_comp *comp;
struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+
if (!meta)
goto out;

- meta->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
- if (!meta->compress_workmem)
+ comp = zcomp_create(comp_name, 1);
+ if (!comp)
goto free_meta;

- meta->compress_buffer =
- (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
- if (!meta->compress_buffer) {
- pr_err("Error allocating compressor buffer space\n");
- goto free_workmem;
- }
-
num_pages = disksize >> PAGE_SHIFT;
meta->table = vzalloc(num_pages * sizeof(*meta->table));
if (!meta->table) {
pr_err("Error allocating zram address table\n");
- goto free_buffer;
+ goto free_comp;
}

meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM);
@@ -198,15 +193,12 @@ static struct zram_meta *zram_meta_alloc(u64 disksize)
}

rwlock_init(&meta->tb_lock);
- mutex_init(&meta->buffer_lock);
return meta;

free_table:
vfree(meta->table);
-free_buffer:
- free_pages((unsigned long)meta->compress_buffer, 1);
-free_workmem:
- kfree(meta->compress_workmem);
+free_comp:
+ zcomp_destroy(comp);
free_meta:
kfree(meta);
meta = NULL;
@@ -284,6 +276,7 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
size_t clen = PAGE_SIZE;
unsigned char *cmem;
struct zram_meta *meta = zram->meta;
+ struct zram_comp *comp = zram->comp;
unsigned long handle;
u16 size;

@@ -301,7 +294,8 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
if (size == PAGE_SIZE)
copy_page(mem, cmem);
else
- ret = lzo1x_decompress_safe(cmem, size, mem, &clen);
+ ret = comp->decompress_page(cmem, size, mem, &clen);
+
zs_unmap_object(meta->mem_pool, handle);
read_unlock(&meta->tb_lock);

@@ -373,10 +367,11 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
unsigned long handle;
struct page *page;
unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
+ struct zram_comp *comp = zram->comp;
struct zram_meta *meta = zram->meta;
+ struct zcomp_strm *strm;

page = bvec->bv_page;
- src = meta->compress_buffer;

if (is_partial_io(bvec)) {
/*
@@ -393,7 +388,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
goto free_res;
}

- mutex_lock(&meta->buffer_lock);
+ strm = zcomp_get_strm(comp);
+ src = strm->compress_buffer;
user_mem = kmap_atomic(page);

if (is_partial_io(bvec)) {
@@ -418,8 +414,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
goto free_res;
}

- ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
- meta->compress_workmem);
+ ret = zcomp_compress_page(comp, strm, uncmem, &clen);
if (!is_partial_io(bvec)) {
kunmap_atomic(user_mem);
user_mem = NULL;
@@ -471,7 +466,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
/* Update stats */
atomic64_add(clen, &zram->stats.compr_data_size);
atomic64_inc(&zram->stats.pages_stored);
- mutex_unlock(&meta->buffer_lock);
+ zcomp_put_strm(comp, strm);

free_res:
if (is_partial_io(bvec))
@@ -549,7 +544,7 @@ static ssize_t disksize_store(struct device *dev,
}

disksize = PAGE_ALIGN(disksize);
- zram->meta = zram_meta_alloc(disksize);
+ zram->meta = zram_meta_alloc(disksize, "lzo", 1);
if (!zram->meta) {
up_write(&zram->init_lock);
return -ENOMEM;
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index 1d5b1f5786a8..57d5a63456e7 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -18,6 +18,8 @@
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/zsmalloc.h>
+#include <linux/rwsem.h>
+#include <linux/wait.h>

/*
* Some arbitrary value. This is just to catch
@@ -81,15 +83,13 @@ struct zram_stats {

struct zram_meta {
rwlock_t tb_lock; /* protect table */
- void *compress_workmem;
- void *compress_buffer;
struct table *table;
struct zs_pool *mem_pool;
- struct mutex buffer_lock; /* protect compress buffers */
};

struct zram {
struct zram_meta *meta;
+ struct zram_comp *comp;
struct request_queue *queue;
struct gendisk *disk;
/* Prevent concurrent execution of device init, reset and R/W request */
--
1.8.5.2

--
Kind regards,
Minchan Kim
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/