xref: /openbmc/linux/fs/jffs2/compr.c (revision 088bd455)
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 /* jffs2_compress:
57  * @data_in: Pointer to uncompressed data
58  * @cpage_out: Pointer to returned pointer to buffer for compressed data
59  * @datalen: On entry, holds the amount of data available for compression.
60  *	On exit, expected to hold the amount of data actually compressed.
61  * @cdatalen: On entry, holds the amount of space available for compressed
62  *	data. On exit, expected to hold the actual size of the compressed
63  *	data.
64  *
65  * Returns: Lower byte to be stored with data indicating compression type used.
66  * Zero is used to show that the data could not be compressed - the
67  * compressed version was actually larger than the original.
68  * Upper byte will be used later. (soon)
69  *
70  * If the cdata buffer isn't large enough to hold all the uncompressed data,
71  * jffs2_compress should compress as much as will fit, and should set
72  * *datalen accordingly to show the amount of data which were compressed.
73  */
74 uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
75 			unsigned char *data_in, unsigned char **cpage_out,
76 			uint32_t *datalen, uint32_t *cdatalen)
77 {
78 	int ret = JFFS2_COMPR_NONE;
79 	int compr_ret;
80 	struct jffs2_compressor *this, *best=NULL;
81 	unsigned char *output_buf = NULL, *tmp_buf;
82 	uint32_t orig_slen, orig_dlen;
83 	uint32_t best_slen=0, best_dlen=0;
84 
85 	switch (jffs2_compression_mode) {
86 	case JFFS2_COMPR_MODE_NONE:
87 		break;
88 	case JFFS2_COMPR_MODE_PRIORITY:
89 		output_buf = kmalloc(*cdatalen,GFP_KERNEL);
90 		if (!output_buf) {
91 			printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
92 			goto out;
93 		}
94 		orig_slen = *datalen;
95 		orig_dlen = *cdatalen;
96 		spin_lock(&jffs2_compressor_list_lock);
97 		list_for_each_entry(this, &jffs2_compressor_list, list) {
98 			/* Skip decompress-only backwards-compatibility and disabled modules */
99 			if ((!this->compress)||(this->disabled))
100 				continue;
101 
102 			this->usecount++;
103 			spin_unlock(&jffs2_compressor_list_lock);
104 			*datalen  = orig_slen;
105 			*cdatalen = orig_dlen;
106 			compr_ret = this->compress(data_in, output_buf, datalen, cdatalen);
107 			spin_lock(&jffs2_compressor_list_lock);
108 			this->usecount--;
109 			if (!compr_ret) {
110 				ret = this->compr;
111 				this->stat_compr_blocks++;
112 				this->stat_compr_orig_size += *datalen;
113 				this->stat_compr_new_size  += *cdatalen;
114 				break;
115 			}
116 		}
117 		spin_unlock(&jffs2_compressor_list_lock);
118 		if (ret == JFFS2_COMPR_NONE)
119 			kfree(output_buf);
120 		break;
121 	case JFFS2_COMPR_MODE_SIZE:
122 	case JFFS2_COMPR_MODE_FAVOURLZO:
123 		orig_slen = *datalen;
124 		orig_dlen = *cdatalen;
125 		spin_lock(&jffs2_compressor_list_lock);
126 		list_for_each_entry(this, &jffs2_compressor_list, list) {
127 			/* Skip decompress-only backwards-compatibility and disabled modules */
128 			if ((!this->compress)||(this->disabled))
129 				continue;
130 			/* Allocating memory for output buffer if necessary */
131 			if ((this->compr_buf_size < orig_slen) && (this->compr_buf)) {
132 				spin_unlock(&jffs2_compressor_list_lock);
133 				kfree(this->compr_buf);
134 				spin_lock(&jffs2_compressor_list_lock);
135 				this->compr_buf_size=0;
136 				this->compr_buf=NULL;
137 			}
138 			if (!this->compr_buf) {
139 				spin_unlock(&jffs2_compressor_list_lock);
140 				tmp_buf = kmalloc(orig_slen, GFP_KERNEL);
141 				spin_lock(&jffs2_compressor_list_lock);
142 				if (!tmp_buf) {
143 					printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n", orig_slen);
144 					continue;
145 				}
146 				else {
147 					this->compr_buf = tmp_buf;
148 					this->compr_buf_size = orig_slen;
149 				}
150 			}
151 			this->usecount++;
152 			spin_unlock(&jffs2_compressor_list_lock);
153 			*datalen  = orig_slen;
154 			*cdatalen = orig_dlen;
155 			compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
156 			spin_lock(&jffs2_compressor_list_lock);
157 			this->usecount--;
158 			if (!compr_ret) {
159 				if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
160 						&& (*cdatalen < *datalen)) {
161 					best_dlen = *cdatalen;
162 					best_slen = *datalen;
163 					best = this;
164 				}
165 			}
166 		}
167 		if (best_dlen) {
168 			*cdatalen = best_dlen;
169 			*datalen  = best_slen;
170 			output_buf = best->compr_buf;
171 			best->compr_buf = NULL;
172 			best->compr_buf_size = 0;
173 			best->stat_compr_blocks++;
174 			best->stat_compr_orig_size += best_slen;
175 			best->stat_compr_new_size  += best_dlen;
176 			ret = best->compr;
177 		}
178 		spin_unlock(&jffs2_compressor_list_lock);
179 		break;
180 	default:
181 		printk(KERN_ERR "JFFS2: unknown compression mode.\n");
182 	}
183  out:
184 	if (ret == JFFS2_COMPR_NONE) {
185 		*cpage_out = data_in;
186 		*datalen = *cdatalen;
187 		none_stat_compr_blocks++;
188 		none_stat_compr_size += *datalen;
189 	}
190 	else {
191 		*cpage_out = output_buf;
192 	}
193 	return ret;
194 }
195 
196 int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
197 		     uint16_t comprtype, unsigned char *cdata_in,
198 		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
199 {
200 	struct jffs2_compressor *this;
201 	int ret;
202 
203 	/* Older code had a bug where it would write non-zero 'usercompr'
204 	   fields. Deal with it. */
205 	if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB)
206 		comprtype &= 0xff;
207 
208 	switch (comprtype & 0xff) {
209 	case JFFS2_COMPR_NONE:
210 		/* This should be special-cased elsewhere, but we might as well deal with it */
211 		memcpy(data_out, cdata_in, datalen);
212 		none_stat_decompr_blocks++;
213 		break;
214 	case JFFS2_COMPR_ZERO:
215 		memset(data_out, 0, datalen);
216 		break;
217 	default:
218 		spin_lock(&jffs2_compressor_list_lock);
219 		list_for_each_entry(this, &jffs2_compressor_list, list) {
220 			if (comprtype == this->compr) {
221 				this->usecount++;
222 				spin_unlock(&jffs2_compressor_list_lock);
223 				ret = this->decompress(cdata_in, data_out, cdatalen, datalen);
224 				spin_lock(&jffs2_compressor_list_lock);
225 				if (ret) {
226 					printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
227 				}
228 				else {
229 					this->stat_decompr_blocks++;
230 				}
231 				this->usecount--;
232 				spin_unlock(&jffs2_compressor_list_lock);
233 				return ret;
234 			}
235 		}
236 		printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype);
237 		spin_unlock(&jffs2_compressor_list_lock);
238 		return -EIO;
239 	}
240 	return 0;
241 }
242 
243 int jffs2_register_compressor(struct jffs2_compressor *comp)
244 {
245 	struct jffs2_compressor *this;
246 
247 	if (!comp->name) {
248 		printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
249 		return -1;
250 	}
251 	comp->compr_buf_size=0;
252 	comp->compr_buf=NULL;
253 	comp->usecount=0;
254 	comp->stat_compr_orig_size=0;
255 	comp->stat_compr_new_size=0;
256 	comp->stat_compr_blocks=0;
257 	comp->stat_decompr_blocks=0;
258 	D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
259 
260 	spin_lock(&jffs2_compressor_list_lock);
261 
262 	list_for_each_entry(this, &jffs2_compressor_list, list) {
263 		if (this->priority < comp->priority) {
264 			list_add(&comp->list, this->list.prev);
265 			goto out;
266 		}
267 	}
268 	list_add_tail(&comp->list, &jffs2_compressor_list);
269 out:
270 	D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
271 		printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
272 	})
273 
274 	spin_unlock(&jffs2_compressor_list_lock);
275 
276 	return 0;
277 }
278 
279 int jffs2_unregister_compressor(struct jffs2_compressor *comp)
280 {
281 	D2(struct jffs2_compressor *this;)
282 
283 	D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
284 
285 	spin_lock(&jffs2_compressor_list_lock);
286 
287 	if (comp->usecount) {
288 		spin_unlock(&jffs2_compressor_list_lock);
289 		printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
290 		return -1;
291 	}
292 	list_del(&comp->list);
293 
294 	D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
295 		printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
296 	})
297 	spin_unlock(&jffs2_compressor_list_lock);
298 	return 0;
299 }
300 
301 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
302 {
303 	if (orig != comprbuf)
304 		kfree(comprbuf);
305 }
306 
307 int __init jffs2_compressors_init(void)
308 {
309 /* Registering compressors */
310 #ifdef CONFIG_JFFS2_ZLIB
311 	jffs2_zlib_init();
312 #endif
313 #ifdef CONFIG_JFFS2_RTIME
314 	jffs2_rtime_init();
315 #endif
316 #ifdef CONFIG_JFFS2_RUBIN
317 	jffs2_rubinmips_init();
318 	jffs2_dynrubin_init();
319 #endif
320 #ifdef CONFIG_JFFS2_LZO
321 	jffs2_lzo_init();
322 #endif
323 /* Setting default compression mode */
324 #ifdef CONFIG_JFFS2_CMODE_NONE
325 	jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
326 	D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
327 #else
328 #ifdef CONFIG_JFFS2_CMODE_SIZE
329 	jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
330 	D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
331 #else
332 #ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
333 	jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
334 	D1(printk(KERN_INFO "JFFS2: default compression mode: favourlzo\n");)
335 #else
336 	D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
337 #endif
338 #endif
339 #endif
340 	return 0;
341 }
342 
343 int jffs2_compressors_exit(void)
344 {
345 /* Unregistering compressors */
346 #ifdef CONFIG_JFFS2_LZO
347 	jffs2_lzo_exit();
348 #endif
349 #ifdef CONFIG_JFFS2_RUBIN
350 	jffs2_dynrubin_exit();
351 	jffs2_rubinmips_exit();
352 #endif
353 #ifdef CONFIG_JFFS2_RTIME
354 	jffs2_rtime_exit();
355 #endif
356 #ifdef CONFIG_JFFS2_ZLIB
357 	jffs2_zlib_exit();
358 #endif
359 	return 0;
360 }
361