aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/zram/zcomp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/zram/zcomp.c')
-rw-r--r--drivers/block/zram/zcomp.c124
1 files changed, 122 insertions, 2 deletions
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 72e8071f9d73..c06f75f54718 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -24,6 +24,21 @@ struct zcomp_strm_single {
24 struct zcomp_strm *zstrm; 24 struct zcomp_strm *zstrm;
25}; 25};
26 26
27/*
28 * multi zcomp_strm backend
29 */
30struct zcomp_strm_multi {
31 /* protect strm list */
32 spinlock_t strm_lock;
33 /* max possible number of zstrm streams */
34 int max_strm;
35 /* number of available zstrm streams */
36 int avail_strm;
37 /* list of available strms */
38 struct list_head idle_strm;
39 wait_queue_head_t strm_wait;
40};
41
27static struct zcomp_backend *find_backend(const char *compress) 42static struct zcomp_backend *find_backend(const char *compress)
28{ 43{
29 if (strncmp(compress, "lzo", 3) == 0) 44 if (strncmp(compress, "lzo", 3) == 0)
@@ -62,6 +77,107 @@ static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp)
62 return zstrm; 77 return zstrm;
63} 78}
64 79
80/*
81 * get idle zcomp_strm or wait until other process release
82 * (zcomp_strm_release()) one for us
83 */
84static struct zcomp_strm *zcomp_strm_multi_find(struct zcomp *comp)
85{
86 struct zcomp_strm_multi *zs = comp->stream;
87 struct zcomp_strm *zstrm;
88
89 while (1) {
90 spin_lock(&zs->strm_lock);
91 if (!list_empty(&zs->idle_strm)) {
92 zstrm = list_entry(zs->idle_strm.next,
93 struct zcomp_strm, list);
94 list_del(&zstrm->list);
95 spin_unlock(&zs->strm_lock);
96 return zstrm;
97 }
98 /* zstrm streams limit reached, wait for idle stream */
99 if (zs->avail_strm >= zs->max_strm) {
100 spin_unlock(&zs->strm_lock);
101 wait_event(zs->strm_wait, !list_empty(&zs->idle_strm));
102 continue;
103 }
104 /* allocate new zstrm stream */
105 zs->avail_strm++;
106 spin_unlock(&zs->strm_lock);
107
108 zstrm = zcomp_strm_alloc(comp);
109 if (!zstrm) {
110 spin_lock(&zs->strm_lock);
111 zs->avail_strm--;
112 spin_unlock(&zs->strm_lock);
113 wait_event(zs->strm_wait, !list_empty(&zs->idle_strm));
114 continue;
115 }
116 break;
117 }
118 return zstrm;
119}
120
121/* add stream back to idle list and wake up waiter or free the stream */
122static void zcomp_strm_multi_release(struct zcomp *comp, struct zcomp_strm *zstrm)
123{
124 struct zcomp_strm_multi *zs = comp->stream;
125
126 spin_lock(&zs->strm_lock);
127 if (zs->avail_strm <= zs->max_strm) {
128 list_add(&zstrm->list, &zs->idle_strm);
129 spin_unlock(&zs->strm_lock);
130 wake_up(&zs->strm_wait);
131 return;
132 }
133
134 zs->avail_strm--;
135 spin_unlock(&zs->strm_lock);
136 zcomp_strm_free(comp, zstrm);
137}
138
139static void zcomp_strm_multi_destroy(struct zcomp *comp)
140{
141 struct zcomp_strm_multi *zs = comp->stream;
142 struct zcomp_strm *zstrm;
143
144 while (!list_empty(&zs->idle_strm)) {
145 zstrm = list_entry(zs->idle_strm.next,
146 struct zcomp_strm, list);
147 list_del(&zstrm->list);
148 zcomp_strm_free(comp, zstrm);
149 }
150 kfree(zs);
151}
152
153static int zcomp_strm_multi_create(struct zcomp *comp, int max_strm)
154{
155 struct zcomp_strm *zstrm;
156 struct zcomp_strm_multi *zs;
157
158 comp->destroy = zcomp_strm_multi_destroy;
159 comp->strm_find = zcomp_strm_multi_find;
160 comp->strm_release = zcomp_strm_multi_release;
161 zs = kmalloc(sizeof(struct zcomp_strm_multi), GFP_KERNEL);
162 if (!zs)
163 return -ENOMEM;
164
165 comp->stream = zs;
166 spin_lock_init(&zs->strm_lock);
167 INIT_LIST_HEAD(&zs->idle_strm);
168 init_waitqueue_head(&zs->strm_wait);
169 zs->max_strm = max_strm;
170 zs->avail_strm = 1;
171
172 zstrm = zcomp_strm_alloc(comp);
173 if (!zstrm) {
174 kfree(zs);
175 return -ENOMEM;
176 }
177 list_add(&zstrm->list, &zs->idle_strm);
178 return 0;
179}
180
65static struct zcomp_strm *zcomp_strm_single_find(struct zcomp *comp) 181static struct zcomp_strm *zcomp_strm_single_find(struct zcomp *comp)
66{ 182{
67 struct zcomp_strm_single *zs = comp->stream; 183 struct zcomp_strm_single *zs = comp->stream;
@@ -139,7 +255,7 @@ void zcomp_destroy(struct zcomp *comp)
139 * if requested algorithm is not supported or in case 255 * if requested algorithm is not supported or in case
140 * of init error 256 * of init error
141 */ 257 */
142struct zcomp *zcomp_create(const char *compress) 258struct zcomp *zcomp_create(const char *compress, int max_strm)
143{ 259{
144 struct zcomp *comp; 260 struct zcomp *comp;
145 struct zcomp_backend *backend; 261 struct zcomp_backend *backend;
@@ -153,7 +269,11 @@ struct zcomp *zcomp_create(const char *compress)
153 return NULL; 269 return NULL;
154 270
155 comp->backend = backend; 271 comp->backend = backend;
156 if (zcomp_strm_single_create(comp) != 0) { 272 if (max_strm > 1)
273 zcomp_strm_multi_create(comp, max_strm);
274 else
275 zcomp_strm_single_create(comp);
276 if (!comp->stream) {
157 kfree(comp); 277 kfree(comp);
158 return NULL; 278 return NULL;
159 } 279 }