xref: /openbmc/linux/fs/jffs2/compr.c (revision da320f05)
1 /*
2  * JFFS2 -- Journalling Flash File System, Version 2.
3  *
4  * Copyright © 2001-2007 Red Hat, Inc.
5  * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
6  * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
7  *		    University of Szeged, Hungary
8  *
9  * Created by Arjan van de Ven <arjan@infradead.org>
10  *
11  * For licensing information, see the file 'LICENCE' in this directory.
12  *
13  */
14 
15 #include "compr.h"
16 
17 static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
18 
19 /* Available compressors are on this list */
20 static LIST_HEAD(jffs2_compressor_list);
21 
22 /* Actual compression mode */
23 static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
24 
25 /* Statistics for blocks stored without compression */
26 static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
27 
28 
29 /*
30  * Return 1 to use this compression
31  */
32 static int jffs2_is_best_compression(struct jffs2_compressor *this,
33 		struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
34 {
35 	switch (jffs2_compression_mode) {
36 	case JFFS2_COMPR_MODE_SIZE:
37 		if (bestsize > size)
38 			return 1;
39 		return 0;
40 	case JFFS2_COMPR_MODE_FAVOURLZO:
41 		if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size))
42 			return 1;
43 		if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
44 			return 1;
45 		if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
46 			return 1;
47 		if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size)
48 			return 1;
49 
50 		return 0;
51 	}
52 	/* Shouldn't happen */
53 	return 0;
54 }
55 
56 /*
57  * jffs2_selected_compress:
58  * @compr: Explicit compression type to use (ie, JFFS2_COMPR_ZLIB).
59  *	If 0, just take the first available compression mode.
60  * @data_in: Pointer to uncompressed data
61  * @cpage_out: Pointer to returned pointer to buffer for compressed data
62  * @datalen: On entry, holds the amount of data available for compression.
63  *	On exit, expected to hold the amount of data actually compressed.
64  * @cdatalen: On entry, holds the amount of space available for compressed
65  *	data. On exit, expected to hold the actual size of the compressed
66  *	data.
67  *
68  * Returns: the compression type used.  Zero is used to show that the data
69  * could not be compressed; probably because we couldn't find the requested
70  * compression mode.
71  */
72 static int jffs2_selected_compress(u8 compr, unsigned char *data_in,
73 		unsigned char **cpage_out, u32 *datalen, u32 *cdatalen)
74 {
75 	struct jffs2_compressor *this;
76 	int err, ret = JFFS2_COMPR_NONE;
77 	uint32_t orig_slen, orig_dlen;
78 	char *output_buf;
79 
80 	output_buf = kmalloc(*cdatalen, GFP_KERNEL);
81 	if (!output_buf) {
82 		pr_warn("JFFS2: No memory for compressor allocation. Compression failed.\n");
83 		return ret;
84 	}
85 	orig_slen = *datalen;
86 	orig_dlen = *cdatalen;
87 	spin_lock(&jffs2_compressor_list_lock);
88 	list_for_each_entry(this, &jffs2_compressor_list, list) {
89 		/* Skip decompress-only and disabled modules */
90 		if (!this->compress || this->disabled)
91 			continue;
92 
93 		/* Skip if not the desired compression type */
94 		if (compr && (compr != this->compr))
95 			continue;
96 
97 		/*
98 		 * Either compression type was unspecified, or we found our
99 		 * compressor; either way, we're good to go.
100 		 */
101 		this->usecount++;
102 		spin_unlock(&jffs2_compressor_list_lock);
103 
104 		*datalen  = orig_slen;
105 		*cdatalen = orig_dlen;
106 		err = this->compress(data_in, output_buf, datalen, cdatalen);
107 
108 		spin_lock(&jffs2_compressor_list_lock);
109 		this->usecount--;
110 		if (!err) {
111 			/* Success */
112 			ret = this->compr;
113 			this->stat_compr_blocks++;
114 			this->stat_compr_orig_size += *datalen;
115 			this->stat_compr_new_size += *cdatalen;
116 			break;
117 		}
118 	}
119 	spin_unlock(&jffs2_compressor_list_lock);
120 	if (ret == JFFS2_COMPR_NONE)
121 		kfree(output_buf);
122 	else
123 		*cpage_out = output_buf;
124 
125 	return ret;
126 }
127 
128 /* jffs2_compress:
129  * @data_in: Pointer to uncompressed data
130  * @cpage_out: Pointer to returned pointer to buffer for compressed data
131  * @datalen: On entry, holds the amount of data available for compression.
132  *	On exit, expected to hold the amount of data actually compressed.
133  * @cdatalen: On entry, holds the amount of space available for compressed
134  *	data. On exit, expected to hold the actual size of the compressed
135  *	data.
136  *
137  * Returns: Lower byte to be stored with data indicating compression type used.
138  * Zero is used to show that the data could not be compressed - the
139  * compressed version was actually larger than the original.
140  * Upper byte will be used later. (soon)
141  *
142  * If the cdata buffer isn't large enough to hold all the uncompressed data,
143  * jffs2_compress should compress as much as will fit, and should set
144  * *datalen accordingly to show the amount of data which were compressed.
145  */
146 uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
147 			unsigned char *data_in, unsigned char **cpage_out,
148 			uint32_t *datalen, uint32_t *cdatalen)
149 {
150 	int ret = JFFS2_COMPR_NONE;
151 	int mode, compr_ret;
152 	struct jffs2_compressor *this, *best=NULL;
153 	unsigned char *output_buf = NULL, *tmp_buf;
154 	uint32_t orig_slen, orig_dlen;
155 	uint32_t best_slen=0, best_dlen=0;
156 
157 	if (c->mount_opts.override_compr)
158 		mode = c->mount_opts.compr;
159 	else
160 		mode = jffs2_compression_mode;
161 
162 	switch (mode) {
163 	case JFFS2_COMPR_MODE_NONE:
164 		break;
165 	case JFFS2_COMPR_MODE_PRIORITY:
166 		ret = jffs2_selected_compress(0, data_in, cpage_out, datalen,
167 				cdatalen);
168 		break;
169 	case JFFS2_COMPR_MODE_SIZE:
170 	case JFFS2_COMPR_MODE_FAVOURLZO:
171 		orig_slen = *datalen;
172 		orig_dlen = *cdatalen;
173 		spin_lock(&jffs2_compressor_list_lock);
174 		list_for_each_entry(this, &jffs2_compressor_list, list) {
175 			/* Skip decompress-only backwards-compatibility and disabled modules */
176 			if ((!this->compress)||(this->disabled))
177 				continue;
178 			/* Allocating memory for output buffer if necessary */
179 			if ((this->compr_buf_size < orig_slen) && (this->compr_buf)) {
180 				spin_unlock(&jffs2_compressor_list_lock);
181 				kfree(this->compr_buf);
182 				spin_lock(&jffs2_compressor_list_lock);
183 				this->compr_buf_size=0;
184 				this->compr_buf=NULL;
185 			}
186 			if (!this->compr_buf) {
187 				spin_unlock(&jffs2_compressor_list_lock);
188 				tmp_buf = kmalloc(orig_slen, GFP_KERNEL);
189 				spin_lock(&jffs2_compressor_list_lock);
190 				if (!tmp_buf) {
191 					pr_warn("JFFS2: No memory for compressor allocation. (%d bytes)\n",
192 						orig_slen);
193 					continue;
194 				}
195 				else {
196 					this->compr_buf = tmp_buf;
197 					this->compr_buf_size = orig_slen;
198 				}
199 			}
200 			this->usecount++;
201 			spin_unlock(&jffs2_compressor_list_lock);
202 			*datalen  = orig_slen;
203 			*cdatalen = orig_dlen;
204 			compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
205 			spin_lock(&jffs2_compressor_list_lock);
206 			this->usecount--;
207 			if (!compr_ret) {
208 				if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
209 						&& (*cdatalen < *datalen)) {
210 					best_dlen = *cdatalen;
211 					best_slen = *datalen;
212 					best = this;
213 				}
214 			}
215 		}
216 		if (best_dlen) {
217 			*cdatalen = best_dlen;
218 			*datalen  = best_slen;
219 			output_buf = best->compr_buf;
220 			best->compr_buf = NULL;
221 			best->compr_buf_size = 0;
222 			best->stat_compr_blocks++;
223 			best->stat_compr_orig_size += best_slen;
224 			best->stat_compr_new_size  += best_dlen;
225 			ret = best->compr;
226 			*cpage_out = output_buf;
227 		}
228 		spin_unlock(&jffs2_compressor_list_lock);
229 		break;
230 	case JFFS2_COMPR_MODE_FORCELZO:
231 		ret = jffs2_selected_compress(JFFS2_COMPR_LZO, data_in,
232 				cpage_out, datalen, cdatalen);
233 		break;
234 	case JFFS2_COMPR_MODE_FORCEZLIB:
235 		ret = jffs2_selected_compress(JFFS2_COMPR_ZLIB, data_in,
236 				cpage_out, datalen, cdatalen);
237 		break;
238 	default:
239 		pr_err("JFFS2: unknown compression mode\n");
240 	}
241 
242 	if (ret == JFFS2_COMPR_NONE) {
243 		*cpage_out = data_in;
244 		*datalen = *cdatalen;
245 		none_stat_compr_blocks++;
246 		none_stat_compr_size += *datalen;
247 	}
248 	return ret;
249 }
250 
251 int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
252 		     uint16_t comprtype, unsigned char *cdata_in,
253 		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
254 {
255 	struct jffs2_compressor *this;
256 	int ret;
257 
258 	/* Older code had a bug where it would write non-zero 'usercompr'
259 	   fields. Deal with it. */
260 	if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB)
261 		comprtype &= 0xff;
262 
263 	switch (comprtype & 0xff) {
264 	case JFFS2_COMPR_NONE:
265 		/* This should be special-cased elsewhere, but we might as well deal with it */
266 		memcpy(data_out, cdata_in, datalen);
267 		none_stat_decompr_blocks++;
268 		break;
269 	case JFFS2_COMPR_ZERO:
270 		memset(data_out, 0, datalen);
271 		break;
272 	default:
273 		spin_lock(&jffs2_compressor_list_lock);
274 		list_for_each_entry(this, &jffs2_compressor_list, list) {
275 			if (comprtype == this->compr) {
276 				this->usecount++;
277 				spin_unlock(&jffs2_compressor_list_lock);
278 				ret = this->decompress(cdata_in, data_out, cdatalen, datalen);
279 				spin_lock(&jffs2_compressor_list_lock);
280 				if (ret) {
281 					pr_warn("Decompressor \"%s\" returned %d\n",
282 						this->name, ret);
283 				}
284 				else {
285 					this->stat_decompr_blocks++;
286 				}
287 				this->usecount--;
288 				spin_unlock(&jffs2_compressor_list_lock);
289 				return ret;
290 			}
291 		}
292 		pr_warn("JFFS2 compression type 0x%02x not available\n",
293 			comprtype);
294 		spin_unlock(&jffs2_compressor_list_lock);
295 		return -EIO;
296 	}
297 	return 0;
298 }
299 
300 int jffs2_register_compressor(struct jffs2_compressor *comp)
301 {
302 	struct jffs2_compressor *this;
303 
304 	if (!comp->name) {
305 		pr_warn("NULL compressor name at registering JFFS2 compressor. Failed.\n");
306 		return -1;
307 	}
308 	comp->compr_buf_size=0;
309 	comp->compr_buf=NULL;
310 	comp->usecount=0;
311 	comp->stat_compr_orig_size=0;
312 	comp->stat_compr_new_size=0;
313 	comp->stat_compr_blocks=0;
314 	comp->stat_decompr_blocks=0;
315 	jffs2_dbg(1, "Registering JFFS2 compressor \"%s\"\n", comp->name);
316 
317 	spin_lock(&jffs2_compressor_list_lock);
318 
319 	list_for_each_entry(this, &jffs2_compressor_list, list) {
320 		if (this->priority < comp->priority) {
321 			list_add(&comp->list, this->list.prev);
322 			goto out;
323 		}
324 	}
325 	list_add_tail(&comp->list, &jffs2_compressor_list);
326 out:
327 	D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
328 		printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
329 	})
330 
331 	spin_unlock(&jffs2_compressor_list_lock);
332 
333 	return 0;
334 }
335 
336 int jffs2_unregister_compressor(struct jffs2_compressor *comp)
337 {
338 	D2(struct jffs2_compressor *this);
339 
340 	jffs2_dbg(1, "Unregistering JFFS2 compressor \"%s\"\n", comp->name);
341 
342 	spin_lock(&jffs2_compressor_list_lock);
343 
344 	if (comp->usecount) {
345 		spin_unlock(&jffs2_compressor_list_lock);
346 		pr_warn("JFFS2: Compressor module is in use. Unregister failed.\n");
347 		return -1;
348 	}
349 	list_del(&comp->list);
350 
351 	D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
352 		printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
353 	})
354 	spin_unlock(&jffs2_compressor_list_lock);
355 	return 0;
356 }
357 
358 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
359 {
360 	if (orig != comprbuf)
361 		kfree(comprbuf);
362 }
363 
364 int __init jffs2_compressors_init(void)
365 {
366 /* Registering compressors */
367 #ifdef CONFIG_JFFS2_ZLIB
368 	jffs2_zlib_init();
369 #endif
370 #ifdef CONFIG_JFFS2_RTIME
371 	jffs2_rtime_init();
372 #endif
373 #ifdef CONFIG_JFFS2_RUBIN
374 	jffs2_rubinmips_init();
375 	jffs2_dynrubin_init();
376 #endif
377 #ifdef CONFIG_JFFS2_LZO
378 	jffs2_lzo_init();
379 #endif
380 /* Setting default compression mode */
381 #ifdef CONFIG_JFFS2_CMODE_NONE
382 	jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
383 	jffs2_dbg(1, "JFFS2: default compression mode: none\n");
384 #else
385 #ifdef CONFIG_JFFS2_CMODE_SIZE
386 	jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
387 	jffs2_dbg(1, "JFFS2: default compression mode: size\n");
388 #else
389 #ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
390 	jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
391 	jffs2_dbg(1, "JFFS2: default compression mode: favourlzo\n");
392 #else
393 	jffs2_dbg(1, "JFFS2: default compression mode: priority\n");
394 #endif
395 #endif
396 #endif
397 	return 0;
398 }
399 
400 int jffs2_compressors_exit(void)
401 {
402 /* Unregistering compressors */
403 #ifdef CONFIG_JFFS2_LZO
404 	jffs2_lzo_exit();
405 #endif
406 #ifdef CONFIG_JFFS2_RUBIN
407 	jffs2_dynrubin_exit();
408 	jffs2_rubinmips_exit();
409 #endif
410 #ifdef CONFIG_JFFS2_RTIME
411 	jffs2_rtime_exit();
412 #endif
413 #ifdef CONFIG_JFFS2_ZLIB
414 	jffs2_zlib_exit();
415 #endif
416 	return 0;
417 }
418