compr.c 17 KB

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