compr.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /*
  2. * JFFS2 -- Journalling Flash File System, Version 2.
  3. *
  4. * Copyright © 2001-2007 Red Hat, Inc.
  5. * Created by Arjan van de Ven <arjanv@redhat.com>
  6. *
  7. * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
  8. * University of Szeged, Hungary
  9. *
  10. * For licensing information, see the file 'LICENCE' in this directory.
  11. *
  12. */
  13. #include "compr.h"
  14. static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
  15. /* Available compressors are on this list */
  16. static LIST_HEAD(jffs2_compressor_list);
  17. /* Actual compression mode */
  18. static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
  19. /* Statistics for blocks stored without compression */
  20. static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
  21. /* jffs2_compress:
  22. * @data: Pointer to uncompressed data
  23. * @cdata: Pointer to returned pointer to buffer for compressed data
  24. * @datalen: On entry, holds the amount of data available for compression.
  25. * On exit, expected to hold the amount of data actually compressed.
  26. * @cdatalen: On entry, holds the amount of space available for compressed
  27. * data. On exit, expected to hold the actual size of the compressed
  28. * data.
  29. *
  30. * Returns: Lower byte to be stored with data indicating compression type used.
  31. * Zero is used to show that the data could not be compressed - the
  32. * compressed version was actually larger than the original.
  33. * Upper byte will be used later. (soon)
  34. *
  35. * If the cdata buffer isn't large enough to hold all the uncompressed data,
  36. * jffs2_compress should compress as much as will fit, and should set
  37. * *datalen accordingly to show the amount of data which were compressed.
  38. */
  39. uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
  40. unsigned char *data_in, unsigned char **cpage_out,
  41. uint32_t *datalen, uint32_t *cdatalen)
  42. {
  43. int ret = JFFS2_COMPR_NONE;
  44. int compr_ret;
  45. struct jffs2_compressor *this, *best=NULL;
  46. unsigned char *output_buf = NULL, *tmp_buf;
  47. uint32_t orig_slen, orig_dlen;
  48. uint32_t best_slen=0, best_dlen=0;
  49. switch (jffs2_compression_mode) {
  50. case JFFS2_COMPR_MODE_NONE:
  51. break;
  52. case JFFS2_COMPR_MODE_PRIORITY:
  53. output_buf = kmalloc(*cdatalen,GFP_KERNEL);
  54. if (!output_buf) {
  55. printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
  56. goto out;
  57. }
  58. orig_slen = *datalen;
  59. orig_dlen = *cdatalen;
  60. spin_lock(&jffs2_compressor_list_lock);
  61. list_for_each_entry(this, &jffs2_compressor_list, list) {
  62. /* Skip decompress-only backwards-compatibility and disabled modules */
  63. if ((!this->compress)||(this->disabled))
  64. continue;
  65. this->usecount++;
  66. spin_unlock(&jffs2_compressor_list_lock);
  67. *datalen = orig_slen;
  68. *cdatalen = orig_dlen;
  69. compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
  70. spin_lock(&jffs2_compressor_list_lock);
  71. this->usecount--;
  72. if (!compr_ret) {
  73. ret = this->compr;
  74. this->stat_compr_blocks++;
  75. this->stat_compr_orig_size += *datalen;
  76. this->stat_compr_new_size += *cdatalen;
  77. break;
  78. }
  79. }
  80. spin_unlock(&jffs2_compressor_list_lock);
  81. if (ret == JFFS2_COMPR_NONE) kfree(output_buf);
  82. break;
  83. case JFFS2_COMPR_MODE_SIZE:
  84. orig_slen = *datalen;
  85. orig_dlen = *cdatalen;
  86. spin_lock(&jffs2_compressor_list_lock);
  87. list_for_each_entry(this, &jffs2_compressor_list, list) {
  88. /* Skip decompress-only backwards-compatibility and disabled modules */
  89. if ((!this->compress)||(this->disabled))
  90. continue;
  91. /* Allocating memory for output buffer if necessary */
  92. if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) {
  93. spin_unlock(&jffs2_compressor_list_lock);
  94. kfree(this->compr_buf);
  95. spin_lock(&jffs2_compressor_list_lock);
  96. this->compr_buf_size=0;
  97. this->compr_buf=NULL;
  98. }
  99. if (!this->compr_buf) {
  100. spin_unlock(&jffs2_compressor_list_lock);
  101. tmp_buf = kmalloc(orig_dlen,GFP_KERNEL);
  102. spin_lock(&jffs2_compressor_list_lock);
  103. if (!tmp_buf) {
  104. printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
  105. continue;
  106. }
  107. else {
  108. this->compr_buf = tmp_buf;
  109. this->compr_buf_size = orig_dlen;
  110. }
  111. }
  112. this->usecount++;
  113. spin_unlock(&jffs2_compressor_list_lock);
  114. *datalen = orig_slen;
  115. *cdatalen = orig_dlen;
  116. compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
  117. spin_lock(&jffs2_compressor_list_lock);
  118. this->usecount--;
  119. if (!compr_ret) {
  120. if ((!best_dlen)||(best_dlen>*cdatalen)) {
  121. best_dlen = *cdatalen;
  122. best_slen = *datalen;
  123. best = this;
  124. }
  125. }
  126. }
  127. if (best_dlen) {
  128. *cdatalen = best_dlen;
  129. *datalen = best_slen;
  130. output_buf = best->compr_buf;
  131. best->compr_buf = NULL;
  132. best->compr_buf_size = 0;
  133. best->stat_compr_blocks++;
  134. best->stat_compr_orig_size += best_slen;
  135. best->stat_compr_new_size += best_dlen;
  136. ret = best->compr;
  137. }
  138. spin_unlock(&jffs2_compressor_list_lock);
  139. break;
  140. default:
  141. printk(KERN_ERR "JFFS2: unknow compression mode.\n");
  142. }
  143. out:
  144. if (ret == JFFS2_COMPR_NONE) {
  145. *cpage_out = data_in;
  146. *datalen = *cdatalen;
  147. none_stat_compr_blocks++;
  148. none_stat_compr_size += *datalen;
  149. }
  150. else {
  151. *cpage_out = output_buf;
  152. }
  153. return ret;
  154. }
  155. int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
  156. uint16_t comprtype, unsigned char *cdata_in,
  157. unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
  158. {
  159. struct jffs2_compressor *this;
  160. int ret;
  161. /* Older code had a bug where it would write non-zero 'usercompr'
  162. fields. Deal with it. */
  163. if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB)
  164. comprtype &= 0xff;
  165. switch (comprtype & 0xff) {
  166. case JFFS2_COMPR_NONE:
  167. /* This should be special-cased elsewhere, but we might as well deal with it */
  168. memcpy(data_out, cdata_in, datalen);
  169. none_stat_decompr_blocks++;
  170. break;
  171. case JFFS2_COMPR_ZERO:
  172. memset(data_out, 0, datalen);
  173. break;
  174. default:
  175. spin_lock(&jffs2_compressor_list_lock);
  176. list_for_each_entry(this, &jffs2_compressor_list, list) {
  177. if (comprtype == this->compr) {
  178. this->usecount++;
  179. spin_unlock(&jffs2_compressor_list_lock);
  180. ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL);
  181. spin_lock(&jffs2_compressor_list_lock);
  182. if (ret) {
  183. printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
  184. }
  185. else {
  186. this->stat_decompr_blocks++;
  187. }
  188. this->usecount--;
  189. spin_unlock(&jffs2_compressor_list_lock);
  190. return ret;
  191. }
  192. }
  193. printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype);
  194. spin_unlock(&jffs2_compressor_list_lock);
  195. return -EIO;
  196. }
  197. return 0;
  198. }
  199. int jffs2_register_compressor(struct jffs2_compressor *comp)
  200. {
  201. struct jffs2_compressor *this;
  202. if (!comp->name) {
  203. printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
  204. return -1;
  205. }
  206. comp->compr_buf_size=0;
  207. comp->compr_buf=NULL;
  208. comp->usecount=0;
  209. comp->stat_compr_orig_size=0;
  210. comp->stat_compr_new_size=0;
  211. comp->stat_compr_blocks=0;
  212. comp->stat_decompr_blocks=0;
  213. D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
  214. spin_lock(&jffs2_compressor_list_lock);
  215. list_for_each_entry(this, &jffs2_compressor_list, list) {
  216. if (this->priority < comp->priority) {
  217. list_add(&comp->list, this->list.prev);
  218. goto out;
  219. }
  220. }
  221. list_add_tail(&comp->list, &jffs2_compressor_list);
  222. out:
  223. D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
  224. printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
  225. })
  226. spin_unlock(&jffs2_compressor_list_lock);
  227. return 0;
  228. }
  229. int jffs2_unregister_compressor(struct jffs2_compressor *comp)
  230. {
  231. D2(struct jffs2_compressor *this;)
  232. D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
  233. spin_lock(&jffs2_compressor_list_lock);
  234. if (comp->usecount) {
  235. spin_unlock(&jffs2_compressor_list_lock);
  236. printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
  237. return -1;
  238. }
  239. list_del(&comp->list);
  240. D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
  241. printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
  242. })
  243. spin_unlock(&jffs2_compressor_list_lock);
  244. return 0;
  245. }
  246. void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
  247. {
  248. if (orig != comprbuf)
  249. kfree(comprbuf);
  250. }
  251. int __init jffs2_compressors_init(void)
  252. {
  253. /* Registering compressors */
  254. #ifdef CONFIG_JFFS2_ZLIB
  255. jffs2_zlib_init();
  256. #endif
  257. #ifdef CONFIG_JFFS2_RTIME
  258. jffs2_rtime_init();
  259. #endif
  260. #ifdef CONFIG_JFFS2_RUBIN
  261. jffs2_rubinmips_init();
  262. jffs2_dynrubin_init();
  263. #endif
  264. /* Setting default compression mode */
  265. #ifdef CONFIG_JFFS2_CMODE_NONE
  266. jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
  267. D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
  268. #else
  269. #ifdef CONFIG_JFFS2_CMODE_SIZE
  270. jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
  271. D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
  272. #else
  273. D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
  274. #endif
  275. #endif
  276. return 0;
  277. }
  278. int jffs2_compressors_exit(void)
  279. {
  280. /* Unregistering compressors */
  281. #ifdef CONFIG_JFFS2_RUBIN
  282. jffs2_dynrubin_exit();
  283. jffs2_rubinmips_exit();
  284. #endif
  285. #ifdef CONFIG_JFFS2_RTIME
  286. jffs2_rtime_exit();
  287. #endif
  288. #ifdef CONFIG_JFFS2_ZLIB
  289. jffs2_zlib_exit();
  290. #endif
  291. return 0;
  292. }