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