zram: introduce compressing backend abstraction
[linux-2.6-block.git] / drivers / block / zram / zcomp.c
CommitLineData
e7e1ef43
SS
1/*
2 * Copyright (C) 2014 Sergey Senozhatsky.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include <linux/kernel.h>
11#include <linux/string.h>
12#include <linux/slab.h>
13#include <linux/wait.h>
14#include <linux/sched.h>
15
16#include "zcomp.h"
17#include "zcomp_lzo.h"
18
19static struct zcomp_backend *find_backend(const char *compress)
20{
21 if (strncmp(compress, "lzo", 3) == 0)
22 return &zcomp_lzo;
23 return NULL;
24}
25
26static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
27{
28 if (zstrm->private)
29 comp->backend->destroy(zstrm->private);
30 free_pages((unsigned long)zstrm->buffer, 1);
31 kfree(zstrm);
32}
33
34/*
35 * allocate new zcomp_strm structure with ->private initialized by
36 * backend, return NULL on error
37 */
38static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp)
39{
40 struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_KERNEL);
41 if (!zstrm)
42 return NULL;
43
44 zstrm->private = comp->backend->create();
45 /*
46 * allocate 2 pages. 1 for compressed data, plus 1 extra for the
47 * case when compressed size is larger than the original one
48 */
49 zstrm->buffer = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
50 if (!zstrm->private || !zstrm->buffer) {
51 zcomp_strm_free(comp, zstrm);
52 zstrm = NULL;
53 }
54 return zstrm;
55}
56
57struct zcomp_strm *zcomp_strm_find(struct zcomp *comp)
58{
59 mutex_lock(&comp->strm_lock);
60 return comp->zstrm;
61}
62
63void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm)
64{
65 mutex_unlock(&comp->strm_lock);
66}
67
68int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
69 const unsigned char *src, size_t *dst_len)
70{
71 return comp->backend->compress(src, zstrm->buffer, dst_len,
72 zstrm->private);
73}
74
75int zcomp_decompress(struct zcomp *comp, const unsigned char *src,
76 size_t src_len, unsigned char *dst)
77{
78 return comp->backend->decompress(src, src_len, dst);
79}
80
81void zcomp_destroy(struct zcomp *comp)
82{
83 zcomp_strm_free(comp, comp->zstrm);
84 kfree(comp);
85}
86
87/*
88 * search available compressors for requested algorithm.
89 * allocate new zcomp and initialize it. return NULL
90 * if requested algorithm is not supported or in case
91 * of init error
92 */
93struct zcomp *zcomp_create(const char *compress)
94{
95 struct zcomp *comp;
96 struct zcomp_backend *backend;
97
98 backend = find_backend(compress);
99 if (!backend)
100 return NULL;
101
102 comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL);
103 if (!comp)
104 return NULL;
105
106 comp->backend = backend;
107 mutex_init(&comp->strm_lock);
108
109 comp->zstrm = zcomp_strm_alloc(comp);
110 if (!comp->zstrm) {
111 kfree(comp);
112 return NULL;
113 }
114 return comp;
115}