xref: /openbmc/linux/fs/jffs2/compr.c (revision 1ab142d4)
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 		printk(KERN_WARNING "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 					printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n", orig_slen);
192 					continue;
193 				}
194 				else {
195 					this->compr_buf = tmp_buf;
196 					this->compr_buf_size = orig_slen;
197 				}
198 			}
199 			this->usecount++;
200 			spin_unlock(&jffs2_compressor_list_lock);
201 			*datalen  = orig_slen;
202 			*cdatalen = orig_dlen;
203 			compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
204 			spin_lock(&jffs2_compressor_list_lock);
205 			this->usecount--;
206 			if (!compr_ret) {
207 				if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
208 						&& (*cdatalen < *datalen)) {
209 					best_dlen = *cdatalen;
210 					best_slen = *datalen;
211 					best = this;
212 				}
213 			}
214 		}
215 		if (best_dlen) {
216 			*cdatalen = best_dlen;
217 			*datalen  = best_slen;
218 			output_buf = best->compr_buf;
219 			best->compr_buf = NULL;
220 			best->compr_buf_size = 0;
221 			best->stat_compr_blocks++;
222 			best->stat_compr_orig_size += best_slen;
223 			best->stat_compr_new_size  += best_dlen;
224 			ret = best->compr;
225 			*cpage_out = output_buf;
226 		}
227 		spin_unlock(&jffs2_compressor_list_lock);
228 		break;
229 	case JFFS2_COMPR_MODE_FORCELZO:
230 		ret = jffs2_selected_compress(JFFS2_COMPR_LZO, data_in,
231 				cpage_out, datalen, cdatalen);
232 		break;
233 	case JFFS2_COMPR_MODE_FORCEZLIB:
234 		ret = jffs2_selected_compress(JFFS2_COMPR_ZLIB, data_in,
235 				cpage_out, datalen, cdatalen);
236 		break;
237 	default:
238 		printk(KERN_ERR "JFFS2: unknown compression mode.\n");
239 	}
240 
241 	if (ret == JFFS2_COMPR_NONE) {
242 		*cpage_out = data_in;
243 		*datalen = *cdatalen;
244 		none_stat_compr_blocks++;
245 		none_stat_compr_size += *datalen;
246 	}
247 	return ret;
248 }
249 
250 int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
251 		     uint16_t comprtype, unsigned char *cdata_in,
252 		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
253 {
254 	struct jffs2_compressor *this;
255 	int ret;
256 
257 	/* Older code had a bug where it would write non-zero 'usercompr'
258 	   fields. Deal with it. */
259 	if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB)
260 		comprtype &= 0xff;
261 
262 	switch (comprtype & 0xff) {
263 	case JFFS2_COMPR_NONE:
264 		/* This should be special-cased elsewhere, but we might as well deal with it */
265 		memcpy(data_out, cdata_in, datalen);
266 		none_stat_decompr_blocks++;
267 		break;
268 	case JFFS2_COMPR_ZERO:
269 		memset(data_out, 0, datalen);
270 		break;
271 	default:
272 		spin_lock(&jffs2_compressor_list_lock);
273 		list_for_each_entry(this, &jffs2_compressor_list, list) {
274 			if (comprtype == this->compr) {
275 				this->usecount++;
276 				spin_unlock(&jffs2_compressor_list_lock);
277 				ret = this->decompress(cdata_in, data_out, cdatalen, datalen);
278 				spin_lock(&jffs2_compressor_list_lock);
279 				if (ret) {
280 					printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
281 				}
282 				else {
283 					this->stat_decompr_blocks++;
284 				}
285 				this->usecount--;
286 				spin_unlock(&jffs2_compressor_list_lock);
287 				return ret;
288 			}
289 		}
290 		printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype);
291 		spin_unlock(&jffs2_compressor_list_lock);
292 		return -EIO;
293 	}
294 	return 0;
295 }
296 
297 int jffs2_register_compressor(struct jffs2_compressor *comp)
298 {
299 	struct jffs2_compressor *this;
300 
301 	if (!comp->name) {
302 		printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
303 		return -1;
304 	}
305 	comp->compr_buf_size=0;
306 	comp->compr_buf=NULL;
307 	comp->usecount=0;
308 	comp->stat_compr_orig_size=0;
309 	comp->stat_compr_new_size=0;
310 	comp->stat_compr_blocks=0;
311 	comp->stat_decompr_blocks=0;
312 	D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
313 
314 	spin_lock(&jffs2_compressor_list_lock);
315 
316 	list_for_each_entry(this, &jffs2_compressor_list, list) {
317 		if (this->priority < comp->priority) {
318 			list_add(&comp->list, this->list.prev);
319 			goto out;
320 		}
321 	}
322 	list_add_tail(&comp->list, &jffs2_compressor_list);
323 out:
324 	D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
325 		printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
326 	})
327 
328 	spin_unlock(&jffs2_compressor_list_lock);
329 
330 	return 0;
331 }
332 
333 int jffs2_unregister_compressor(struct jffs2_compressor *comp)
334 {
335 	D2(struct jffs2_compressor *this;)
336 
337 	D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
338 
339 	spin_lock(&jffs2_compressor_list_lock);
340 
341 	if (comp->usecount) {
342 		spin_unlock(&jffs2_compressor_list_lock);
343 		printk(KERN_WARNING "JFFS2: Compressor module is in use. Unregister failed.\n");
344 		return -1;
345 	}
346 	list_del(&comp->list);
347 
348 	D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
349 		printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
350 	})
351 	spin_unlock(&jffs2_compressor_list_lock);
352 	return 0;
353 }
354 
355 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
356 {
357 	if (orig != comprbuf)
358 		kfree(comprbuf);
359 }
360 
361 int __init jffs2_compressors_init(void)
362 {
363 /* Registering compressors */
364 #ifdef CONFIG_JFFS2_ZLIB
365 	jffs2_zlib_init();
366 #endif
367 #ifdef CONFIG_JFFS2_RTIME
368 	jffs2_rtime_init();
369 #endif
370 #ifdef CONFIG_JFFS2_RUBIN
371 	jffs2_rubinmips_init();
372 	jffs2_dynrubin_init();
373 #endif
374 #ifdef CONFIG_JFFS2_LZO
375 	jffs2_lzo_init();
376 #endif
377 /* Setting default compression mode */
378 #ifdef CONFIG_JFFS2_CMODE_NONE
379 	jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
380 	D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
381 #else
382 #ifdef CONFIG_JFFS2_CMODE_SIZE
383 	jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
384 	D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
385 #else
386 #ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
387 	jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
388 	D1(printk(KERN_INFO "JFFS2: default compression mode: favourlzo\n");)
389 #else
390 	D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
391 #endif
392 #endif
393 #endif
394 	return 0;
395 }
396 
397 int jffs2_compressors_exit(void)
398 {
399 /* Unregistering compressors */
400 #ifdef CONFIG_JFFS2_LZO
401 	jffs2_lzo_exit();
402 #endif
403 #ifdef CONFIG_JFFS2_RUBIN
404 	jffs2_dynrubin_exit();
405 	jffs2_rubinmips_exit();
406 #endif
407 #ifdef CONFIG_JFFS2_RTIME
408 	jffs2_rtime_exit();
409 #endif
410 #ifdef CONFIG_JFFS2_ZLIB
411 	jffs2_zlib_exit();
412 #endif
413 	return 0;
414 }
415