diff options
Diffstat (limited to 'drivers/block/zram/zcomp.c')
-rw-r--r-- | drivers/block/zram/zcomp.c | 124 |
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 | */ | ||
30 | struct 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 | |||
27 | static struct zcomp_backend *find_backend(const char *compress) | 42 | static 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 | */ | ||
84 | static 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 */ | ||
122 | static 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 | |||
139 | static 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 | |||
153 | static 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 | |||
65 | static struct zcomp_strm *zcomp_strm_single_find(struct zcomp *comp) | 181 | static 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 | */ |
142 | struct zcomp *zcomp_create(const char *compress) | 258 | struct 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 | } |