diff --unified --recursive --new-file mtd2/fs/Kconfig mtd/fs/Kconfig --- mtd2/fs/Kconfig 2004-07-17 00:00:11.000000000 +0200 +++ mtd/fs/Kconfig 2004-10-06 10:56:20.000000000 +0200 @@ -80,6 +80,43 @@ If unsure, you should _definitely_ say 'N'. +choice + prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS + default JFFS2_CMODE_PRIORITY + depends on JFFS2_FS + help + You can set here the default compression mode of JFFS2 from + the avaiable compression modes. Don't touch if unsure. + +config JFFS2_CMODE_NONE + bool "no compression" + help + Uses no compression. + +config JFFS2_CMODE_PRIORITY + bool "priority" + help + Tries the compressors in a predefinied order and chooses the first + successful one. + +config JFFS2_CMODE_SIZE + bool "size (EXPERIMENTAL)" + help + Tries all compressors and chooses the one which has the smallest + result. + +endchoice + +config JFFS2_MODEL + bool "JFFS2 model based compression support" if JFFS2_COMPRESSION_OPTIONS + depends on JFFS2_FS + default y + help + This feature makes it possible to use model based compressors + such as armib. + + Say 'Y' if unsure. + config JFFS2_ZLIB bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS select ZLIB_INFLATE @@ -94,6 +131,12 @@ Say 'Y' if unsure. +config JFFS2_ZLIB_PRIORITY + int "JFFS2 ZLIB compressor priority" if JFFS2_ZLIB + default "70" + help + This prirority used by priority compression mode. + config JFFS2_RTIME bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS depends on JFFS2_FS @@ -101,6 +144,12 @@ help Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. +config JFFS2_RTIME_PRIORITY + int "JFFS2 RTIME compressor priority" if JFFS2_RTIME + default "60" + help + This prirority used by priority compression mode. + config JFFS2_RUBIN bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS depends on JFFS2_FS @@ -108,29 +157,24 @@ help RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. -choice - prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS - default JFFS2_CMODE_PRIORITY - depends on JFFS2_FS - help - You can set here the default compression mode of JFFS2 from - the avaiable compression modes. Don't touch if unsure. - -config JFFS2_CMODE_NONE - bool "no compression" - help - Uses no compression. - -config JFFS2_CMODE_PRIORITY - bool "priority" +config JFFS2_RUBIN_PRIORITY + int "JFFS2 RUBIN compressor priority" if JFFS2_RUBIN + default "20" + help + This prirority used by priority compression mode. + +config JFFS2_ARMLIB + bool "JFFS2 ARMLIB compression support" if JFFS2_COMPRESSION_OPTIONS + depends on JFFS2_MODEL + default y help - Tries the compressors in a predefinied order and chooses the first - successful one. + ARMLIB is a model based compressor. It is designed for code compression. + Read its manual for more information! -config JFFS2_CMODE_SIZE - bool "size (EXPERIMENTAL)" - help - Tries all compressors and chooses the one which has the smallest - result. +config JFFS2_ARMLIB_PRIORITY + int "JFFS2 ARMLIB compressor priority" if JFFS2_ARMLIB + default "50" + help + This prirority used by priority compression mode. -endchoice + diff --unified --recursive --new-file mtd2/fs/jffs2/Makefile.common mtd/fs/jffs2/Makefile.common --- mtd2/fs/jffs2/Makefile.common 2004-07-17 00:00:11.000000000 +0200 +++ mtd/fs/jffs2/Makefile.common 2004-10-06 11:36:26.000000000 +0200 @@ -9,9 +9,10 @@ jffs2-y := compr.o dir.o file.o ioctl.o nodelist.o malloc.o jffs2-y += read.o nodemgmt.o readinode.o write.o scan.o gc.o jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o -jffs2-y += super.o +jffs2-y += super.o jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o +jffs2-$(CONFIG_JFFS2_ARMLIB) += compr_armlib.o diff --unified --recursive --new-file mtd2/fs/jffs2/build.c mtd/fs/jffs2/build.c --- mtd2/fs/jffs2/build.c 2003-10-29 00:00:34.000000000 +0100 +++ mtd/fs/jffs2/build.c 2004-10-06 10:52:09.000000000 +0200 @@ -15,6 +15,7 @@ #include #include #include "nodelist.h" +#include "compr.h" static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **); @@ -95,6 +96,9 @@ c->flags |= JFFS2_SB_FLAG_MOUNTING; ret = jffs2_scan_medium(c); +#ifdef CONFIG_JFFS2_MODEL + jffs2_link_model_files(c); /* sets their nlink to 1 */ +#endif c->flags &= ~JFFS2_SB_FLAG_MOUNTING; if (ret) diff --unified --recursive --new-file mtd2/fs/jffs2/compr.c mtd/fs/jffs2/compr.c --- mtd2/fs/jffs2/compr.c 2004-08-08 00:00:11.000000000 +0200 +++ mtd/fs/jffs2/compr.c 2004-10-06 11:28:52.000000000 +0200 @@ -13,15 +13,94 @@ * */ +#include #include "compr.h" -static spinlock_t jffs2_compressor_list_lock = SPIN_LOCK_UNLOCKED; - +/* Actual compression mode */ +static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; /* Available compressors are on this list */ static LIST_HEAD(jffs2_compressor_list); +/* Available models are on this list */ +static LIST_HEAD(jffs2_model_list); +/* Lock for compressor list */ +static spinlock_t jffs2_compressor_list_lock = SPIN_LOCK_UNLOCKED; +/* Lock for model list */ +static spinlock_t jffs2_model_list_lock = SPIN_LOCK_UNLOCKED; +/* Statistics for blocks stored without compression */ +static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0; -/* Actual compression mode */ -static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; +/* Init and exit function headers for compressors */ +int jffs2_rubinmips_init(void); void jffs2_rubinmips_exit(void); +int jffs2_dynrubin_init(void); void jffs2_dynrubin_exit(void); +int jffs2_rtime_init(void); void jffs2_rtime_exit(void); +int jffs2_zlib_init(void); void jffs2_zlib_exit(void); +int jffs2_armlib_init(void); void jffs2_armlib_exit(void); +int jffs2_lzari_init(void); void jffs2_lzari_exit(void); +int jffs2_lzo_init(void); void jffs2_lzo_exit(void); + +/* Registering compressors and setting the default compression mode */ + +int jffs2_compressors_init(void) +{ +#ifdef CONFIG_JFFS2_ZLIB + jffs2_zlib_init(); +#endif +#ifdef CONFIG_JFFS2_RTIME + jffs2_rtime_init(); +#endif +#ifdef CONFIG_JFFS2_RUBIN + jffs2_rubinmips_init(); + jffs2_dynrubin_init(); +#endif +#ifdef CONFIG_JFFS2_ARMLIB + jffs2_armlib_init(); +#endif +#ifdef CONFIG_JFFS2_LZARI + jffs2_lzari_init(); +#endif +#ifdef CONFIG_JFFS2_LZO + jffs2_lzo_init(); +#endif +/* Setting default compression mode */ +#ifdef CONFIG_JFFS2_CMODE_NONE + jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; + D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");) +#else +#ifdef CONFIG_JFFS2_CMODE_SIZE + jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; + D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");) +#else + D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");) +#endif +#endif + return 0; +} + +/* Unregistering compressors */ + +int jffs2_compressors_exit(void) +{ +#ifdef CONFIG_JFFS2_LZO + jffs2_lzo_exit(); +#endif +#ifdef CONFIG_JFFS2_LZARI + jffs2_lzari_exit(); +#endif +#ifdef CONFIG_JFFS2_RUBIN + jffs2_dynrubin_exit(); + jffs2_rubinmips_exit(); +#endif +#ifdef CONFIG_JFFS2_ARMLIB + jffs2_armlib_exit(); +#endif +#ifdef CONFIG_JFFS2_RTIME + jffs2_rtime_exit(); +#endif +#ifdef CONFIG_JFFS2_ZLIB + jffs2_zlib_exit(); +#endif + return 0; +} void jffs2_set_compression_mode(int mode) { @@ -33,12 +112,278 @@ return jffs2_compression_mode; } -/* Statistics for blocks stored without compression */ -static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0; +#ifdef CONFIG_JFFS2_MODEL + +int jffs2_model_add(struct jffs2_sb_info *c, uint32_t inode, uint32_t size) +{ + struct jffs2_model *m; + + m = kmalloc(sizeof(*m),GFP_KERNEL); + if (!m) { + printk(KERN_WARNING "JFFS2: No memory for model allocation. Failed.\n"); + return 1; + } + m->sb_info = c; + m->ino = inode; + m->size = size; + m->model = NULL; + m->compr = 0; /* mark as "not asociated yet" */ + spin_lock(&jffs2_model_list_lock); + list_add_tail(&m->list, &jffs2_model_list); + spin_unlock(&jffs2_model_list_lock); + return 0; +} + +static int jffs2_model_init(struct jffs2_model *m) +{ + struct jffs2_compressor *this; + unsigned char *p; + int ret; + + p = m->model; + if ((p[0]!='J')||(p[1]!='2')||(p[2]!='M')||(p[3]!='F')) { + printk(KERN_WARNING "JFFS2: Bad magic (%c%c%c%c) in model file ino %d.\n",p[0],p[1],p[2],p[3],m->ino); + return 1; + } + m->compr = p[4]; + m->serial = p[5]; + printk(KERN_DEBUG "JFFS2 model: compr=%d serial=%d\n",(int)m->compr,(int)m->serial); + spin_lock(&jffs2_compressor_list_lock); + list_for_each_entry(this, &jffs2_compressor_list, list) { + if (m->compr == this->compr) { + spin_unlock(&jffs2_compressor_list_lock); + if (!this->model_init) return 0; + ret = this->model_init(&(m->model)); + return ret; + } + } + spin_unlock(&jffs2_compressor_list_lock); + printk(KERN_WARNING "JFFS2: compressor (%d) not found for ino %d.\n", m->compr, m->ino); + return 1; +} + +static char *jffs2_model_load_inode(struct jffs2_sb_info *c, int ino, int size) +{ + struct jffs2_inode_cache *ic; + struct jffs2_raw_node_ref *raw; + struct jffs2_raw_inode *ri; + char *buf = NULL, *readbuf, *decomprbuf; + size_t readlen; + int ret; + uint32_t offset,clen,dlen,crc; + + ic = jffs2_get_ino_cache(c, ino); + if (ic) { + buf = vmalloc(size); + raw = ic->nodes; + while (raw&&((char*)raw!=(char*)ic)) { + ri = jffs2_alloc_raw_inode(); + ret = jffs2_flash_read(c,ref_offset(raw),sizeof(*ri),&readlen,(char*)ri); + if (ret) { + jffs2_free_raw_inode(ri); + vfree(buf); + return NULL; + } + offset = je32_to_cpu(ri->offset); + clen = je32_to_cpu(ri->csize); + dlen = je32_to_cpu(ri->dsize); + + if (ri->compr == JFFS2_COMPR_ZERO) { + memset(buf+offset, 0, dlen); + goto out_ri; + } + readbuf = NULL; + if (ri->compr == JFFS2_COMPR_NONE) + readbuf = buf+offset; + else readbuf = kmalloc(clen, GFP_KERNEL); + if (!readbuf) goto out_ri; + + decomprbuf = buf+offset; + + ret = jffs2_flash_read(c, (ref_offset(raw)) + sizeof(*ri), + clen, &readlen, readbuf); + + if (!ret && readlen != clen) { + printk("JFFS2: model: cannot read enough data!\n"); + goto out_readbuf; + } + if (ret) goto out_readbuf; + + crc = crc32(0, readbuf, clen); + if (crc != je32_to_cpu(ri->data_crc)) { + printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n", + je32_to_cpu(ri->data_crc), crc, ref_offset(raw)); + goto out_readbuf; + } + if (ri->compr & 0x80) { + printk(KERN_WARNING "JFFS2: model files must be comperessed by non model based compressors!\n"); + goto out_readbuf; + } + if (ri->compr != JFFS2_COMPR_NONE) { + D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", + clen, readbuf, dlen, decomprbuf)); + ret = jffs2_decompress(c, NULL, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, clen, dlen); + if (ret) { + printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret); + goto out_readbuf; + } + } + + if(readbuf != buf+offset) + kfree(readbuf); + jffs2_free_raw_inode(ri); + raw = raw->next_in_ino; + } + } + else printk(KERN_WARNING "JFFS2: cannot find model in inode cache.\n"); + return buf; +out_readbuf: + if(readbuf != buf+offset) + kfree(readbuf); +out_ri: + jffs2_free_raw_inode(ri); + vfree(buf); + return NULL; +} + +void jffs2_model_load(struct super_block *sb) +{ + struct jffs2_sb_info *c; + struct jffs2_model *this; + + c = JFFS2_SB_INFO(sb); + printk(KERN_DEBUG "JFFS2: loading model files for %x %x\n", (int)sb, (int)c); + spin_lock(&jffs2_model_list_lock); + list_for_each_entry(this, &jffs2_model_list, list) { + if ((this->sb_info == c) && (this->compr == 0)) { + spin_unlock(&jffs2_model_list_lock); + printk(KERN_INFO "JFFS2: loading model files from ino %d, size %d.\n", (int)(this->ino),(int)(this->size)); + this->model = jffs2_model_load_inode(c, this->ino, this->size); + if (this->model) { + if (jffs2_model_init(this)) { + printk(KERN_WARNING "JFFS2: Unable to init file ino %d\n",this->ino); + } + else { + printk(KERN_DEBUG "JFFS2: model loaded and inited correctly.\n"); + } + } + else { + printk(KERN_WARNING "JFFS2: Unable to load model file ino %d\n",this->ino); + } + spin_lock(&jffs2_model_list_lock); + } + } + spin_unlock(&jffs2_model_list_lock); +} + +void jffs2_model_release(struct super_block *sb) +{ + struct jffs2_sb_info *c; + struct jffs2_model *this, *m; + struct jffs2_compressor *comp; + + c = JFFS2_SB_INFO(sb); + printk(KERN_DEBUG "JFFS2: releasing model files for %x %x\n", (int)sb, (int)c); + + do { + m = NULL; + spin_lock(&jffs2_model_list_lock); + list_for_each_entry(this, &jffs2_model_list, list) { + if ((this->sb_info == c)) { + m = this; + } + } + spin_unlock(&jffs2_model_list_lock); + if (m) { + /* free m->model */ + spin_lock(&jffs2_compressor_list_lock); + list_for_each_entry(comp, &jffs2_compressor_list, list) { + if (comp->compr == m->compr) { + spin_unlock(&jffs2_compressor_list_lock); + if (comp->model_destroy) comp->model_destroy(&m->model); + spin_lock(&jffs2_compressor_list_lock); + } + } + spin_unlock(&jffs2_compressor_list_lock); + if (m->model) { + /* if model_destroy did not do its job let's do it */ + vfree(m->model); + m->model = NULL; + } + spin_lock(&jffs2_model_list_lock); + list_del(&m->list); + spin_unlock(&jffs2_model_list_lock); + kfree(m); + } + } while (m); +} + +static struct jffs2_model *jffs2_model_get(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + unsigned char compr, unsigned char min_serial) +{ + struct jffs2_model *this; + + spin_lock(&jffs2_model_list_lock); + list_for_each_entry(this, &jffs2_model_list, list) { + if ((this->sb_info == c) && (this->compr == compr) && (this->serial >= min_serial)) { + spin_unlock(&jffs2_model_list_lock); + return this; + } + } + spin_unlock(&jffs2_model_list_lock); + return NULL; +} + +void jffs2_link_model_files(struct jffs2_sb_info *c) +{ + struct jffs2_model *this; + struct jffs2_inode_cache *ic; + + spin_lock(&jffs2_model_list_lock); + list_for_each_entry(this, &jffs2_model_list, list) { + if (this->sb_info == c) { + ic = jffs2_get_ino_cache(c, this->ino); + if (ic) { + ic->nlink = 1; /* mark it not to delete */ + } + else { + printk(KERN_WARNING "JFFS2: Unable to file model %d in inode cache.\n",this->ino); + } + } + } + spin_unlock(&jffs2_model_list_lock); +} + +int jffs2_is_model_ino(struct jffs2_sb_info *c, uint32_t ino) +{ + struct jffs2_model *this; + + spin_lock(&jffs2_model_list_lock); + list_for_each_entry(this, &jffs2_model_list, list) { + if ((this->sb_info == c) && (this->ino == ino)) { + spin_unlock(&jffs2_model_list_lock); + return 1; + } + } + spin_unlock(&jffs2_model_list_lock); + return 0; +} + +#else /* CONFIG_JFFS2_MODEL */ + +int jffs2_is_model_ino(struct jffs2_sb_info *c, uint32_t inode) +{ + return 0; +} + +#endif /* CONFIG_JFFS2_MODEL */ + /* jffs2_compress: - * @data: Pointer to uncompressed data - * @cdata: Pointer to returned pointer to buffer for compressed data + * @c: sb_info + * @f: inode_info + * @data_in: Pointer to uncompressed data + * @cpage_out: Pointer to returned pointer to buffer for compressed data * @datalen: On entry, holds the amount of data available for compression. * On exit, expected to hold the amount of data actually compressed. * @cdatalen: On entry, holds the amount of space available for compressed @@ -64,6 +409,7 @@ unsigned char *output_buf = NULL, *tmp_buf; uint32_t orig_slen, orig_dlen; uint32_t best_slen=0, best_dlen=0; + int best_serial=0; switch (jffs2_compression_mode) { case JFFS2_COMPR_MODE_NONE: @@ -73,7 +419,7 @@ if (!output_buf) { printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n"); goto out; - } + } orig_slen = *datalen; orig_dlen = *cdatalen; spin_lock(&jffs2_compressor_list_lock); @@ -82,20 +428,49 @@ if ((!this->compress)||(this->disabled)) continue; - this->usecount++; - spin_unlock(&jffs2_compressor_list_lock); - *datalen = orig_slen; - *cdatalen = orig_dlen; - compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); - spin_lock(&jffs2_compressor_list_lock); - this->usecount--; - if (!compr_ret) { - ret = this->compr; - this->stat_compr_blocks++; - this->stat_compr_orig_size += *datalen; - this->stat_compr_new_size += *cdatalen; - break; + if (!(this->compr & 0x80)) { + /* OK, this is a non-model-based compressor */ + *datalen = orig_slen; + *cdatalen = orig_dlen; + spin_unlock(&jffs2_compressor_list_lock); + this->usecount++; + compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); + this->usecount--; + spin_lock(&jffs2_compressor_list_lock); + if (!compr_ret) { + ret = this->compr; + this->stat_compr_blocks++; + this->stat_compr_orig_size += *datalen; + this->stat_compr_new_size += *cdatalen; + break; + } } +#ifdef CONFIG_JFFS2_MODEL + else { + /* It is model-based compressor, let's search model for it */ + int serial = 0; + struct jffs2_model *m= jffs2_model_get(c,f,this->compr,serial); + while (m) { + *datalen = orig_slen; + *cdatalen = orig_dlen; + spin_unlock(&jffs2_compressor_list_lock); + this->usecount++; + compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, m->model); + this->usecount--; + spin_lock(&jffs2_compressor_list_lock); + if (!compr_ret) { + ret = (uint16_t)this->compr | ((uint16_t)m->serial << 8); + this->stat_compr_blocks++; + this->stat_compr_orig_size += *datalen; + this->stat_compr_new_size += *cdatalen; + break; + } + serial = m->serial+1; + m = jffs2_model_get(c, f, this->compr, serial); + } + if (ret!=JFFS2_COMPR_NONE) break; + } +#endif } spin_unlock(&jffs2_compressor_list_lock); if (ret == JFFS2_COMPR_NONE) kfree(output_buf); @@ -129,20 +504,49 @@ this->compr_buf_size = orig_dlen; } } - this->usecount++; - spin_unlock(&jffs2_compressor_list_lock); - *datalen = orig_slen; - *cdatalen = orig_dlen; - compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); - spin_lock(&jffs2_compressor_list_lock); - this->usecount--; - if (!compr_ret) { - if ((!best_dlen)||(best_dlen>*cdatalen)) { - best_dlen = *cdatalen; - best_slen = *datalen; - best = this; + if (!(this->compr & 0x80)) { + /* OK, this is a non-model-based compressor */ + *datalen = orig_slen; + *cdatalen = orig_dlen; + spin_unlock(&jffs2_compressor_list_lock); + this->usecount++; + compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); + this->usecount--; + spin_lock(&jffs2_compressor_list_lock); + if (!compr_ret) { + if ((!best_dlen)||(best_dlen>*cdatalen)) { + best_dlen = *cdatalen; + best_slen = *datalen; + best = this; + } + } + } +#ifdef CONFIG_JFFS2_MODEL + else { + /* It is model-based compressor, let's search model for it */ + int serial = 0; + struct jffs2_model *m = jffs2_model_get(c, f, this->compr,serial); + while (m) { + *datalen = orig_slen; + *cdatalen = orig_dlen; + spin_unlock(&jffs2_compressor_list_lock); + this->usecount++; + compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, m->model); + this->usecount--; + spin_lock(&jffs2_compressor_list_lock); + if (!compr_ret) { + if ((!best_dlen)||(best_dlen>*cdatalen)) { + best_dlen = *cdatalen; + best_slen = *datalen; + best = this; + best_serial = m->serial; + } + } + serial = m->serial+1; + m = jffs2_model_get(c, f, this->compr, serial); } } +#endif } if (best_dlen) { *cdatalen = best_dlen; @@ -153,7 +557,7 @@ best->stat_compr_blocks++; best->stat_compr_orig_size += best_slen; best->stat_compr_new_size += best_dlen; - ret = best->compr; + ret = (uint16_t)best->compr | ((uint16_t)best_serial << 8); } spin_unlock(&jffs2_compressor_list_lock); break; @@ -179,13 +583,16 @@ { struct jffs2_compressor *this; int ret; + unsigned char compr, model_serial; + void *model = NULL; +#ifdef CONFIG_JFFS2_MODEL + struct jffs2_model *m; +#endif - /* Older code had a bug where it would write non-zero 'usercompr' - fields. Deal with it. */ - if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB) - comprtype &= 0xff; - - switch (comprtype & 0xff) { + compr = comprtype & 0xff; + model_serial = (comprtype >> 8) & 0xff; + + switch (compr) { case JFFS2_COMPR_NONE: /* This should be special-cased elsewhere, but we might as well deal with it */ memcpy(data_out, cdata_in, datalen); @@ -197,24 +604,37 @@ default: spin_lock(&jffs2_compressor_list_lock); list_for_each_entry(this, &jffs2_compressor_list, list) { - if (comprtype == this->compr) { - this->usecount++; + if (compr == this->compr) { + if (compr & 0x80) { /* it is a model based compressor? */ +#ifdef CONFIG_JFFS2_MODEL + m = jffs2_model_get(c,f,compr,model_serial); + if ((m == NULL) || (m->compr != compr) || (m->serial != model_serial)) { + spin_unlock(&jffs2_compressor_list_lock); + printk(KERN_WARNING "JFFS2 model 0x%02x,0x%02x not available.\n", compr, model_serial); + return -EIO; + } + model = m->model; +#else + spin_unlock(&jffs2_compressor_list_lock); + printk(KERN_WARNING "JFFS2 model support (0x%02x,0x%02x) not available.\n", compr, model_serial); + return -EIO; +#endif + } spin_unlock(&jffs2_compressor_list_lock); - ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL); - spin_lock(&jffs2_compressor_list_lock); + this->usecount++; + ret = this->decompress(cdata_in, data_out, cdatalen, datalen, model); + this->usecount--; if (ret) { printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret); } else { this->stat_decompr_blocks++; } - this->usecount--; - spin_unlock(&jffs2_compressor_list_lock); return ret; } } - printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype); spin_unlock(&jffs2_compressor_list_lock); + printk(KERN_WARNING "JFFS2 compression type 0x%02x,0x%02x not available.\n", compr, model_serial); return -EIO; } return 0; @@ -225,9 +645,15 @@ struct jffs2_compressor *this; if (!comp->name) { - printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n"); + printk(KERN_WARNING "JFFS2: NULL compressor name at registering compressor. Failed.\n"); + return -1; + } +#ifndef CONFIG_JFFS2_MODEL + if ((comp->compr & 0x80)) { + printk(KERN_WARNING "JFFS2: model support is not active (%s). Recompile!\n", comp->name); return -1; } +#endif comp->compr_buf_size=0; comp->compr_buf=NULL; comp->usecount=0; @@ -278,6 +704,12 @@ return 0; } +void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) +{ + if (orig != comprbuf) + kfree(comprbuf); +} + #ifdef CONFIG_JFFS2_PROC #define JFFS2_STAT_BUF_SIZE 16000 @@ -414,66 +846,4 @@ return 0; } -#endif - -void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) -{ - if (orig != comprbuf) - kfree(comprbuf); -} - -int jffs2_compressors_init(void) -{ -/* Registering compressors */ -#ifdef CONFIG_JFFS2_ZLIB - jffs2_zlib_init(); -#endif -#ifdef CONFIG_JFFS2_RTIME - jffs2_rtime_init(); -#endif -#ifdef CONFIG_JFFS2_RUBIN - jffs2_rubinmips_init(); - jffs2_dynrubin_init(); -#endif -#ifdef CONFIG_JFFS2_LZARI - jffs2_lzari_init(); -#endif -#ifdef CONFIG_JFFS2_LZO - jffs2_lzo_init(); -#endif -/* Setting default compression mode */ -#ifdef CONFIG_JFFS2_CMODE_NONE - jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; - D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");) -#else -#ifdef CONFIG_JFFS2_CMODE_SIZE - jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; - D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");) -#else - D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");) -#endif -#endif - return 0; -} - -int jffs2_compressors_exit(void) -{ -/* Unregistering compressors */ -#ifdef CONFIG_JFFS2_LZO - jffs2_lzo_exit(); -#endif -#ifdef CONFIG_JFFS2_LZARI - jffs2_lzari_exit(); -#endif -#ifdef CONFIG_JFFS2_RUBIN - jffs2_dynrubin_exit(); - jffs2_rubinmips_exit(); -#endif -#ifdef CONFIG_JFFS2_RTIME - jffs2_rtime_exit(); -#endif -#ifdef CONFIG_JFFS2_ZLIB - jffs2_zlib_exit(); -#endif - return 0; -} +#endif /* CONFIG_JFFS2_PROC */ diff --unified --recursive --new-file mtd2/fs/jffs2/compr.h mtd/fs/jffs2/compr.h --- mtd2/fs/jffs2/compr.h 2004-07-17 00:00:11.000000000 +0200 +++ mtd/fs/jffs2/compr.h 2004-10-06 10:56:35.000000000 +0200 @@ -27,12 +27,18 @@ #include #include "nodelist.h" -#define JFFS2_RUBINMIPS_PRIORITY 10 -#define JFFS2_DYNRUBIN_PRIORITY 20 -#define JFFS2_LZARI_PRIORITY 30 -#define JFFS2_LZO_PRIORITY 40 -#define JFFS2_RTIME_PRIORITY 50 -#define JFFS2_ZLIB_PRIORITY 60 +/* Non-model-based compressors */ +#define JFFS2_COMPR_NONE 0x00 +#define JFFS2_COMPR_ZERO 0x01 +#define JFFS2_COMPR_RTIME 0x02 +#define JFFS2_COMPR_RUBINMIPS 0x03 +#define JFFS2_COMPR_COPY 0x04 +#define JFFS2_COMPR_DYNRUBIN 0x05 +#define JFFS2_COMPR_ZLIB 0x06 +#define JFFS2_COMPR_LZO 0x07 +#define JFFS2_COMPR_LZARI 0x08 +/* Model-based compressors */ +#define JFFS2_COMPR_ARMLIB 0x81 #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */ #define JFFS2_DYNRUBIN_DISABLED /* for decompression */ @@ -48,11 +54,16 @@ struct list_head list; int priority; /* used by prirority comr. mode */ char *name; - char compr; /* JFFS2_COMPR_XXX */ + unsigned char compr; /* JFFS2_COMPR_XXX */ int (*compress)(unsigned char *data_in, unsigned char *cpage_out, uint32_t *srclen, uint32_t *destlen, void *model); int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, uint32_t cdatalen, uint32_t datalen, void *model); + int (*model_init)(void **model); + /* called to init model data */ + int (*model_destroy)(void **model); + /* called to free model data, + it should set *model to NULL */ int usecount; int disabled; /* if seted the compressor won't compress */ unsigned char *compr_buf; /* used by size compr. mode */ @@ -63,6 +74,17 @@ uint32_t stat_decompr_blocks; }; +struct jffs2_model { + struct list_head list; + struct jffs2_sb_info *sb_info; /* jffs2 sb_info */ + void *sb; /* real super block */ + uint32_t ino; + uint32_t size; + void *model; /* model data */ + unsigned char compr; /* JFFS2_COMPR_XXX */ + unsigned char serial; +}; + int jffs2_register_compressor(struct jffs2_compressor *comp); int jffs2_unregister_compressor(struct jffs2_compressor *comp); @@ -79,6 +101,14 @@ void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig); +#ifdef CONFIG_JFFS2_MODEL +int jffs2_model_add(struct jffs2_sb_info *c, uint32_t inode, uint32_t size); +void jffs2_model_load(struct super_block *sb); +void jffs2_model_release(struct super_block *sb); +void jffs2_link_model_files(struct jffs2_sb_info *c); +#endif +int jffs2_is_model_ino(struct jffs2_sb_info *c, uint32_t ino); + #ifdef CONFIG_JFFS2_PROC int jffs2_enable_compressor_name(const char *name); int jffs2_disable_compressor_name(const char *name); @@ -89,30 +119,4 @@ char *jffs2_stats(void); #endif -/* Compressor modules */ -/* These functions will be called by jffs2_compressors_init/exit */ - -#ifdef CONFIG_JFFS2_RUBIN -int jffs2_rubinmips_init(void); -void jffs2_rubinmips_exit(void); -int jffs2_dynrubin_init(void); -void jffs2_dynrubin_exit(void); -#endif -#ifdef CONFIG_JFFS2_RTIME -int jffs2_rtime_init(void); -void jffs2_rtime_exit(void); -#endif -#ifdef CONFIG_JFFS2_ZLIB -int jffs2_zlib_init(void); -void jffs2_zlib_exit(void); -#endif -#ifdef CONFIG_JFFS2_LZARI -int jffs2_lzari_init(void); -void jffs2_lzari_exit(void); -#endif -#ifdef CONFIG_JFFS2_LZO -int jffs2_lzo_init(void); -void jffs2_lzo_exit(void); -#endif - #endif /* __JFFS2_COMPR_H__ */ diff --unified --recursive --new-file mtd2/fs/jffs2/compr_lzari.c mtd/fs/jffs2/compr_lzari.c --- mtd2/fs/jffs2/compr_lzari.c 2004-06-24 00:00:12.000000000 +0200 +++ mtd/fs/jffs2/compr_lzari.c 2004-10-06 10:52:09.000000000 +0200 @@ -680,7 +680,7 @@ uint32_t dstlen, void *model); struct jffs2_compressor jffs2_lzari_comp = { - .priority = JFFS2_LZARI_PRIORITY, + .priority = CONFIG_JFFS2_LZARI_PRIORITY, .name = "lzari", .compr = JFFS2_COMPR_LZARI, .compress = &jffs2_lzari_compress, diff --unified --recursive --new-file mtd2/fs/jffs2/compr_lzo.c mtd/fs/jffs2/compr_lzo.c --- mtd2/fs/jffs2/compr_lzo.c 2004-06-24 00:00:12.000000000 +0200 +++ mtd/fs/jffs2/compr_lzo.c 2004-10-06 10:52:09.000000000 +0200 @@ -2220,7 +2220,7 @@ uint32_t dstlen, void *model); static struct jffs2_compressor jffs2_lzo_comp = { - .priority = JFFS2_LZO_PRIORITY, + .priority = CONFIG_JFFS2_LZO_PRIORITY, .name = "lzo", .compr = JFFS2_COMPR_LZO, .compress = &jffs2_lzo_compress, diff --unified --recursive --new-file mtd2/fs/jffs2/compr_rtime.c mtd/fs/jffs2/compr_rtime.c --- mtd2/fs/jffs2/compr_rtime.c 2004-06-24 00:00:12.000000000 +0200 +++ mtd/fs/jffs2/compr_rtime.c 2004-10-06 10:52:09.000000000 +0200 @@ -105,7 +105,7 @@ } static struct jffs2_compressor jffs2_rtime_comp = { - .priority = JFFS2_RTIME_PRIORITY, + .priority = CONFIG_JFFS2_RTIME_PRIORITY, .name = "rtime", .compr = JFFS2_COMPR_RTIME, .compress = &jffs2_rtime_compress, diff --unified --recursive --new-file mtd2/fs/jffs2/compr_rubin.c mtd/fs/jffs2/compr_rubin.c --- mtd2/fs/jffs2/compr_rubin.c 2004-06-24 00:00:12.000000000 +0200 +++ mtd/fs/jffs2/compr_rubin.c 2004-10-06 10:52:09.000000000 +0200 @@ -327,7 +327,7 @@ } static struct jffs2_compressor jffs2_rubinmips_comp = { - .priority = JFFS2_RUBINMIPS_PRIORITY, + .priority = CONFIG_JFFS2_RUBIN_PRIORITY, .name = "rubinmips", .compr = JFFS2_COMPR_DYNRUBIN, .compress = NULL, /*&jffs2_rubinmips_compress,*/ @@ -350,7 +350,7 @@ } static struct jffs2_compressor jffs2_dynrubin_comp = { - .priority = JFFS2_DYNRUBIN_PRIORITY, + .priority = CONFIG_JFFS2_RUBIN_PRIORITY, .name = "dynrubin", .compr = JFFS2_COMPR_RUBINMIPS, .compress = jffs2_dynrubin_compress, diff --unified --recursive --new-file mtd2/fs/jffs2/compr_zlib.c mtd/fs/jffs2/compr_zlib.c --- mtd2/fs/jffs2/compr_zlib.c 2004-06-24 00:00:12.000000000 +0200 +++ mtd/fs/jffs2/compr_zlib.c 2004-10-06 10:52:09.000000000 +0200 @@ -184,7 +184,7 @@ } static struct jffs2_compressor jffs2_zlib_comp = { - .priority = JFFS2_ZLIB_PRIORITY, + .priority = CONFIG_JFFS2_ZLIB_PRIORITY, .name = "zlib", .compr = JFFS2_COMPR_ZLIB, .compress = &jffs2_zlib_compress, diff --unified --recursive --new-file mtd2/fs/jffs2/dir.c mtd/fs/jffs2/dir.c --- mtd2/fs/jffs2/dir.c 2003-10-12 00:00:05.000000000 +0200 +++ mtd/fs/jffs2/dir.c 2004-10-06 10:52:09.000000000 +0200 @@ -21,6 +21,7 @@ #include #include #include "nodelist.h" +#include "compr.h" /* Urgh. Please tell me there's a nicer way of doing these. */ #include diff --unified --recursive --new-file mtd2/fs/jffs2/ecos/src/fs-ecos.c mtd/fs/jffs2/ecos/src/fs-ecos.c --- mtd2/fs/jffs2/ecos/src/fs-ecos.c 2004-04-22 00:00:32.000000000 +0200 +++ mtd/fs/jffs2/ecos/src/fs-ecos.c 2004-10-06 10:52:09.000000000 +0200 @@ -21,6 +21,7 @@ #include #include #include "nodelist.h" +#include "compr.h" #include #include diff --unified --recursive --new-file mtd2/fs/jffs2/file.c mtd/fs/jffs2/file.c --- mtd2/fs/jffs2/file.c 2004-03-20 00:00:06.000000000 +0100 +++ mtd/fs/jffs2/file.c 2004-10-06 10:52:09.000000000 +0200 @@ -21,6 +21,7 @@ #include #include #include "nodelist.h" +#include "compr.h" extern int generic_file_open(struct inode *, struct file *) __attribute__((weak)); extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak)); diff --unified --recursive --new-file mtd2/fs/jffs2/fs.c mtd/fs/jffs2/fs.c --- mtd2/fs/jffs2/fs.c 2004-07-14 00:00:17.000000000 +0200 +++ mtd/fs/jffs2/fs.c 2004-10-06 10:52:09.000000000 +0200 @@ -23,7 +23,7 @@ #include #include #include "nodelist.h" - +#include "compr.h" static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) { diff --unified --recursive --new-file mtd2/fs/jffs2/gc.c mtd/fs/jffs2/gc.c --- mtd2/fs/jffs2/gc.c 2004-07-21 00:00:13.000000000 +0200 +++ mtd/fs/jffs2/gc.c 2004-10-06 15:40:36.000000000 +0200 @@ -21,6 +21,8 @@ #include "nodelist.h" #include "compr.h" +static int jffs2_garbage_handle_inodeless(struct jffs2_sb_info *c, + struct jffs2_raw_node_ref *raw); static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_raw_node_ref *raw); @@ -240,12 +242,11 @@ D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", ref_offset(raw))); if (!raw->next_in_ino) { - /* Inode-less node. Clean marker, snapshot or something like that */ - /* FIXME: If it's something that needs to be copied, including something - we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */ + /* Inode-less node. Clean marker, snapshot, modelinfo or something like that */ spin_unlock(&c->erase_completion_lock); - jffs2_mark_node_obsolete(c, raw); up(&c->alloc_sem); + jffs2_garbage_handle_inodeless(c, raw); + jffs2_mark_node_obsolete(c, raw); goto eraseit_lock; } @@ -486,6 +487,153 @@ return ret; } +static int jffs2_garbage_handle_inodeless(struct jffs2_sb_info *c, + struct jffs2_raw_node_ref *raw) +{ + union jffs2_node_union *node; + struct jffs2_raw_node_ref *nraw; + size_t retlen; + int ret; + uint32_t phys_ofs, alloclen; + uint32_t crc, rawlen; + int retried = 0; + + D1(printk(KERN_DEBUG "Going to GC and inode-less node at 0x%08x\n", ref_offset(raw))); + + rawlen = ref_totlen(c, c->gcblock, raw); + + /* Ask for a small amount of space (or the totlen if smaller) because we + don't want to force wastage of the end of a block if splitting would + work. */ + ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, + rawlen), &phys_ofs, &alloclen); + if (ret) + return ret; + + if (alloclen < rawlen) { + /* Doesn't fit untouched. We'll go the old route and split it */ + return -EBADFD; + } + + node = kmalloc(rawlen, GFP_KERNEL); + if (!node) + return -ENOMEM; + + ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); + + if (!ret && retlen != rawlen) + ret = -EIO; + if (ret) + goto il_out_node; + + crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4); + if (je32_to_cpu(node->u.hdr_crc) != crc) { + printk(KERN_WARNING "Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc); + goto il_bail; + } + + if (je16_to_cpu(node->u.nodetype)==JFFS2_NODETYPE_MODELINFO) { + crc = crc32(0, node, sizeof(node->m)-8); + if (je32_to_cpu(node->m.node_crc) != crc) { + printk(KERN_WARNING "Node CRC failed on modelinfo node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->m.node_crc), crc); + goto il_bail; + } + if (je32_to_cpu(node->m.model_num)) { + crc = crc32(0, node->m.models, je32_to_cpu(node->m.model_num) * 2 * sizeof(jint32_t)); + if (je32_to_cpu(node->m.models_crc) != crc) { + printk(KERN_WARNING "Name CRC failed on modelinfo node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->m.models_crc), crc); + goto il_bail; + } + } + } + else if ((je16_to_cpu(node->u.nodetype))&JFFS2_FEATURE_RWCOMPAT_COPY) { + printk(KERN_DEBUG "Unknown but RWCOMPAT_COPY node at 0x%08x: 0x%04x\n", + ref_offset(raw), je16_to_cpu(node->u.nodetype)); + printk("Unknown but RWCOMPAT_COPY node at 0x%08x: 0x%04x\n", + ref_offset(raw), je16_to_cpu(node->u.nodetype)); + } + else { + printk(KERN_DEBUG "Not important inodeless node at 0x%08x: 0x%04x\n", + ref_offset(raw), je16_to_cpu(node->u.nodetype)); + goto il_bail; + } + + nraw = jffs2_alloc_raw_node_ref(); + if (!nraw) { + ret = -ENOMEM; + goto il_out_node; + } + + /* OK, all the CRCs are good; this node can just be copied as-is. */ + il_retry: + nraw->flash_offset = phys_ofs; + nraw->__totlen = rawlen; + nraw->next_phys = NULL; + + ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node); + + if (ret || (retlen != rawlen)) { + printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", + rawlen, phys_ofs, ret, retlen); + if (retlen) { + /* Doesn't belong to any inode */ + nraw->next_in_ino = NULL; + + nraw->flash_offset |= REF_OBSOLETE; + jffs2_add_physical_node_ref(c, nraw); + jffs2_mark_node_obsolete(c, nraw); + } else { + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset); + jffs2_free_raw_node_ref(nraw); + } + if (!retried && (nraw == jffs2_alloc_raw_node_ref())) { + /* Try to reallocate space and retry */ + uint32_t dummy; + struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size]; + + retried = 1; + + D1(printk(KERN_DEBUG "Retrying failed write of inode-less node.\n")); + + ACCT_SANITY_CHECK(c,jeb); + D1(ACCT_PARANOIA_CHECK(jeb)); + + ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy); + + if (!ret) { + D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs)); + + ACCT_SANITY_CHECK(c,jeb); + D1(ACCT_PARANOIA_CHECK(jeb)); + + goto il_retry; + } + D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); + jffs2_free_raw_node_ref(nraw); + } + + if (!ret) + ret = -EIO; + goto il_out_node; + } + nraw->flash_offset |= REF_PRISTINE; + jffs2_add_physical_node_ref(c, nraw); + + D1(printk(KERN_DEBUG "WHEEE! GC inodless node at 0x%08x succeeded\n", ref_offset(raw))); + + il_out_node: + kfree(node); + return ret; + il_bail: + ret = -EBADFD; + goto il_out_node; + return 0; +} + + static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_raw_node_ref *raw) @@ -520,6 +668,8 @@ return -ENOMEM; ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); + + if (je16_to_cpu(node->u.nodetype)==JFFS2_NODETYPE_MODELINFO) printk("YES!!!\n"); if (!ret && retlen != rawlen) ret = -EIO; if (ret) @@ -558,7 +708,7 @@ ref_offset(raw), je32_to_cpu(node->d.node_crc), crc); goto bail; } - + if (node->d.nsize) { crc = crc32(0, node->d.name, node->d.nsize); if (je32_to_cpu(node->d.name_crc) != crc) { diff --unified --recursive --new-file mtd2/fs/jffs2/nodelist.c mtd/fs/jffs2/nodelist.c --- mtd2/fs/jffs2/nodelist.c 2003-11-01 00:00:35.000000000 +0100 +++ mtd/fs/jffs2/nodelist.c 2004-10-06 10:52:09.000000000 +0200 @@ -20,6 +20,7 @@ #include #include #include "nodelist.h" +#include "compr.h" void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list) { diff --unified --recursive --new-file mtd2/fs/jffs2/nodelist.h mtd/fs/jffs2/nodelist.h --- mtd2/fs/jffs2/nodelist.h 2004-05-28 12:51:05.000000000 +0200 +++ mtd/fs/jffs2/nodelist.h 2004-10-07 12:36:23.000000000 +0200 @@ -281,9 +281,14 @@ else if (!ref_obsolete(ref2)) \ my_used_size += ref_totlen(c, jeb, ref2); \ if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \ - printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \ - ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \ - jeb->last_node, ref_offset(jeb->last_node)); \ + if (!ref2->next_phys) \ + printk("ref for node at %p (phys %08x) has next_phys->%p (----), last_node->%p (phys %08x)\n", \ + ref2, ref_offset(ref2), ref2->next_phys, \ + jeb->last_node, ref_offset(jeb->last_node)); \ + else \ + printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \ + ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \ + jeb->last_node, ref_offset(jeb->last_node)); \ paranoia_failed_dump(jeb); \ BUG(); \ } \ diff --unified --recursive --new-file mtd2/fs/jffs2/nodemgmt.c mtd/fs/jffs2/nodemgmt.c --- mtd2/fs/jffs2/nodemgmt.c 2004-09-22 00:00:12.000000000 +0200 +++ mtd/fs/jffs2/nodemgmt.c 2004-10-06 17:06:56.000000000 +0200 @@ -573,6 +573,7 @@ ref->__totlen += n->__totlen; /* we don't need to check jeb->last_node */ ref->next_phys = n->next_phys; + if (jeb->last_node == n) jeb->last_node=ref; if (jeb->gc_node == n) { /* gc will be happy continuing gc on this node */ jeb->gc_node=ref; diff --unified --recursive --new-file mtd2/fs/jffs2/readinode.c mtd/fs/jffs2/readinode.c --- mtd2/fs/jffs2/readinode.c 2003-11-04 00:00:36.000000000 +0100 +++ mtd/fs/jffs2/readinode.c 2004-10-06 10:52:09.000000000 +0200 @@ -19,6 +19,7 @@ #include #include #include "nodelist.h" +#include "compr.h" static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag); @@ -561,7 +562,7 @@ if (!fn) { /* No data nodes for this inode. */ - if (f->inocache->ino != 1) { + if ((f->inocache->ino != 1) && (!jffs2_is_model_ino(c, f->inocache->ino))) { printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", f->inocache->ino); if (!fd_list) { if (f->inocache->state == INO_STATE_READING) diff --unified --recursive --new-file mtd2/fs/jffs2/scan.c mtd/fs/jffs2/scan.c --- mtd2/fs/jffs2/scan.c 2004-09-13 00:00:12.000000000 +0200 +++ mtd/fs/jffs2/scan.c 2004-10-06 10:52:09.000000000 +0200 @@ -18,6 +18,7 @@ #include #include #include "nodelist.h" +#include "compr.h" #define EMPTY_SCAN_SIZE 1024 @@ -58,6 +59,11 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_dirent *rd, uint32_t ofs); +#ifdef CONFIG_JFFS2_MODEL +static int jffs2_scan_modelinfo_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_modelinfo *rd, uint32_t ofs); +#endif + #define BLK_STATE_ALLFF 0 #define BLK_STATE_CLEAN 1 #define BLK_STATE_PARTDIRTY 2 @@ -578,6 +584,26 @@ ofs += PAD(je32_to_cpu(node->totlen)); break; + case JFFS2_NODETYPE_MODELINFO: +#ifdef CONFIG_JFFS2_MODEL + if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) { + buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); + D1(printk(KERN_DEBUG "Fewer than %d bytes (modelinfo node) left to end of buf. Reading 0x%x at 0x%08x\n", + je32_to_cpu(node->totlen), buf_len, ofs)); + err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); + if (err) + return err; + buf_ofs = ofs; + node = (void *)buf; + } + err = jffs2_scan_modelinfo_node(c, jeb, (void *)node, ofs); + if (err) return err; + ofs += PAD(je32_to_cpu(node->totlen)); + break; +#else + printk(KERN_WARNING "JFFS2: you should recompile jffs2 with model file support!\n"); +#endif + default: switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) { case JFFS2_FEATURE_ROCOMPAT: @@ -812,6 +838,61 @@ return 0; } +#ifdef CONFIG_JFFS2_MODEL +static int jffs2_scan_modelinfo_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_modelinfo *rm, uint32_t ofs) +{ + struct jffs2_raw_node_ref *raw; + uint32_t crc; + int model_num, ino, i, size; + + D1(printk(KERN_DEBUG "jffs2_scan_modelinfo_node(): Node at 0x%08x\n", ofs)); + + /* We don't get here unless the node is still valid, so we don't have to + mask in the ACCURATE bit any more. */ + crc = crc32(0, rm, sizeof(*rm)-8); + + if (crc != je32_to_cpu(rm->node_crc)) { + printk(KERN_NOTICE "jffs2_scan_modelinfo_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ofs, je32_to_cpu(rm->node_crc), crc); + /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ + DIRTY_SPACE(PAD(je32_to_cpu(rm->totlen))); + return 0; + } + model_num = je32_to_cpu(rm->model_num); + printk(KERN_DEBUG "jffs2_scan_modelinfo_node(): Found %d model inode number.\n", model_num); + crc = crc32(0, rm->models, model_num * 2 * sizeof(jint32_t)); + if (crc != je32_to_cpu(rm->models_crc)) { + printk(KERN_NOTICE "jffs2_scan_modelinfo_node(): Models CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ofs, je32_to_cpu(rm->models_crc), crc); + DIRTY_SPACE(PAD(je32_to_cpu(rm->totlen))); + return 0; + } + for (i=0;imodels[i*2]); + size = je32_to_cpu(rm->models[i*2+1]); + printk(KERN_INFO "JFFS2 adding ino %d to modellist.\n", ino); + jffs2_model_add(c, ino, size); + } + raw = jffs2_alloc_raw_node_ref(); + if (!raw) { + printk(KERN_NOTICE "jffs2_scan_modelinfo_node(): allocation of node reference failed\n"); + return -ENOMEM; + } + raw->__totlen = PAD(je32_to_cpu(rm->totlen)); + raw->flash_offset = ofs | REF_PRISTINE; + raw->next_phys = NULL; + raw->next_in_ino = NULL; + if (!jeb->first_node) + jeb->first_node = raw; + if (jeb->last_node) + jeb->last_node->next_phys = raw; + jeb->last_node = raw; + USED_SPACE(PAD(je32_to_cpu(rm->totlen))); + return 0; +} +#endif + static int count_list(struct list_head *l) { uint32_t count = 0; diff --unified --recursive --new-file mtd2/fs/jffs2/super-v24.c mtd/fs/jffs2/super-v24.c --- mtd2/fs/jffs2/super-v24.c 2004-07-17 00:00:11.000000000 +0200 +++ mtd/fs/jffs2/super-v24.c 2004-10-06 10:52:09.000000000 +0200 @@ -72,7 +72,11 @@ put_mtd_device(c->mtd); return NULL; } - +#ifdef CONFIG_JFFS2_MODEL + else { + jffs2_model_load(sb); + } +#endif return sb; } @@ -82,6 +86,9 @@ D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); +#ifdef CONFIG_JFFS2_MODEL + jffs2_model_release(sb); +#endif if (!(sb->s_flags & MS_RDONLY)) jffs2_stop_garbage_collect_thread(c); diff --unified --recursive --new-file mtd2/fs/jffs2/super.c mtd/fs/jffs2/super.c --- mtd2/fs/jffs2/super.c 2004-08-25 00:00:14.000000000 +0200 +++ mtd/fs/jffs2/super.c 2004-10-06 10:52:09.000000000 +0200 @@ -142,6 +142,11 @@ } sb->s_flags |= MS_ACTIVE; + +#ifdef CONFIG_JFFS2_MODEL + jffs2_model_load(sb); +#endif + return sb; out_put: @@ -259,6 +264,10 @@ D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); +#ifdef CONFIG_JFFS2_MODEL + jffs2_model_release(sb); +#endif + if (!(sb->s_flags & MS_RDONLY)) jffs2_stop_garbage_collect_thread(c); down(&c->alloc_sem); diff --unified --recursive --new-file mtd2/include/linux/jffs2.h mtd/include/linux/jffs2.h --- mtd2/include/linux/jffs2.h 2004-05-28 12:51:10.000000000 +0200 +++ mtd/include/linux/jffs2.h 2004-10-06 10:52:09.000000000 +0200 @@ -36,15 +36,6 @@ /* How small can we sensibly write nodes? */ #define JFFS2_MIN_DATA_LEN 128 -#define JFFS2_COMPR_NONE 0x00 -#define JFFS2_COMPR_ZERO 0x01 -#define JFFS2_COMPR_RTIME 0x02 -#define JFFS2_COMPR_RUBINMIPS 0x03 -#define JFFS2_COMPR_COPY 0x04 -#define JFFS2_COMPR_DYNRUBIN 0x05 -#define JFFS2_COMPR_ZLIB 0x06 -#define JFFS2_COMPR_LZO 0x07 -#define JFFS2_COMPR_LZARI 0x08 /* Compatibility flags. */ #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ #define JFFS2_NODE_ACCURATE 0x2000 @@ -61,12 +52,12 @@ #define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2) #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) #define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) +#define JFFS2_NODETYPE_MODELINFO (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 5) // Maybe later... //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) - #define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at mount time, don't wait for it to happen later */ @@ -148,7 +139,22 @@ uint8_t data[0]; } __attribute__((packed)); + +struct jffs2_raw_modelinfo +{ + jint16_t magic; + jint16_t nodetype; /* == JFFS_NODETYPE_MODELINFO */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t model_num; /* number of model files */ + jint32_t node_crc; + jint32_t models_crc; + jint32_t models[0]; /* inode and size list of the model files */ +} __attribute__((packed)); + + union jffs2_node_union { + struct jffs2_raw_modelinfo m; struct jffs2_raw_inode i; struct jffs2_raw_dirent d; struct jffs2_unknown_node u; diff --unified --recursive --new-file mtd2/util/Makefile mtd/util/Makefile --- mtd2/util/Makefile 2004-07-14 00:00:18.000000000 +0200 +++ mtd/util/Makefile 2004-10-06 10:55:01.000000000 +0200 @@ -13,9 +13,9 @@ TARGETS = ftl_format flash_erase flash_eraseall nanddump doc_loadbios \ mkfs.jffs ftl_check mkfs.jffs2 flash_lock flash_unlock \ flash_info mtd_debug flashcp nandwrite jffs2dump \ - nftldump nftl_format docfdisk #jffs2reader + nftldump nftl_format docfdisk modelgen.armlib #jffs2reader -SYMLINKS = compr_lzari.c compr_lzo.c +SYMLINKS = compr_lzari.c compr_lzo.c compr_armlib.c %: %.o $(CC) $(LDFLAGS) -g -o $@ $^ @@ -36,9 +36,12 @@ $(SYMLINKS): ln -sf ../fs/jffs2/$@ $@ -mkfs.jffs2: crc32.o compr_rtime.o mkfs.jffs2.o compr_zlib.o compr.o compr_lzari.o compr_lzo.o +mkfs.jffs2: crc32.o compr_rtime.o mkfs.jffs2.o compr_zlib.o compr.o compr_lzari.o compr_lzo.o compr_armlib.o $(CC) $(LDFLAGS) -o $@ $^ -lz +modelgen.armlib: modelgen.armlib.o + $(CC) $(LDFLAGS) -o $@ $^ -lm + flash_eraseall: crc32.o flash_eraseall.o $(CC) $(LDFLAGS) -o $@ $^ diff --unified --recursive --new-file mtd2/util/compr.c mtd/util/compr.c --- mtd2/util/compr.c 2004-06-25 00:00:13.000000000 +0200 +++ mtd/util/compr.c 2004-10-06 11:26:42.000000000 +0200 @@ -15,13 +15,43 @@ #include #include #include +#include + +/* COMPRESSOR INIT AND EXIT */ + +/* Init and exit function headers for compressors */ +int jffs2_zlib_init(void); void jffs2_zlib_exit(void); +int jffs2_rtime_init(void); void jffs2_rtime_exit(void); +int jffs2_armlib_init(void); void jffs2_armlib_exit(void); +int jffs2_lzari_init(void); void jffs2_lzari_exit(void); +int jffs2_lzo_init(void); void jffs2_lzo_exit(void); + +int jffs2_compressors_init(void) +{ + jffs2_zlib_init(); + jffs2_rtime_init(); + jffs2_armlib_init(); + jffs2_lzari_init(); + jffs2_lzo_init(); + return 0; +} + +int jffs2_compressors_exit(void) +{ + jffs2_lzo_exit(); + jffs2_lzari_exit(); + jffs2_armlib_exit(); + jffs2_rtime_exit(); + jffs2_zlib_exit(); + return 0; +} + +/* END OF COMPRESSOR INIT AND EXIT */ -extern int page_size; /* LIST IMPLEMENTATION (from linux/list.h) */ #define LIST_HEAD_INIT(name) { &(name), &(name) } - #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) @@ -66,32 +96,31 @@ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) +/* END OF LIST IMPLEMENTATION (from linux/list.h) */ + +/* GLOBAL VARIABLES */ +extern int page_size; /* Available compressors are on this list */ static LIST_HEAD(jffs2_compressor_list); - +/* Available models are on this list */ +static LIST_HEAD(jffs2_model_list); /* Actual compression mode */ static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; - -void jffs2_set_compression_mode(int mode) -{ - jffs2_compression_mode = mode; -} - -int jffs2_get_compression_mode(void) -{ - return jffs2_compression_mode; -} - +/* Default comprssion configuration */ +static char *jffs2_default_compression_config = DEFAULT_COMPRESSION_CONFIG; +/* Compressor configs for files */ +static LIST_HEAD(jffs2_compression_configs); /* Statistics for blocks stored without compression */ static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0; - /* Compression test stuffs */ - static int jffs2_compression_check = 0; - static unsigned char *jffs2_compression_check_buf = NULL; +/* END OF GLOBAL VARIABLES */ + +/* COMPRESSION TEST FUNCTIONS */ + void jffs2_compression_check_set(int yesno) { jffs2_compression_check = yesno; @@ -121,7 +150,7 @@ /* Called after compression (if compression_check is setted) to test the result */ static void jffs2_decompression_test(struct jffs2_compressor *compr, unsigned char *data_in, unsigned char *output_buf, - uint32_t cdatalen, uint32_t datalen, uint32_t buf_size) + uint32_t cdatalen, uint32_t datalen, void *model, uint32_t buf_size) { uint32_t i; @@ -150,7 +179,7 @@ jffs2_error_cnt++; return; } - if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen,NULL)) { + if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen,model)) { fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name); jffs2_error_cnt++; } @@ -166,6 +195,341 @@ } } +/* END OF COMPRESSION TEST FUNCTIONS */ + +/* COMPRESSOR CONFIG AND MODEL PROCESSING */ + +static char *config_str_find_next(char *from, char d) +{ + if (from==NULL) return NULL; + while (1) { + if (*from==0) return NULL; /* end of string */ + if ((*from==13)||(*from==10)) { /* end of line */ + *from=0; + return NULL; + } + if (*from==d) { /* delimiter found */ + *from=0; from++; + return from; + } + from++; + } +} + +static int jffs2_set_compression_mode_name(const char *name) +{ + if (!strcmp("none",name)) { + jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; + return 0; + } + if (!strcmp("priority",name)) { + jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; + return 0; + } + if (!strcmp("size",name)) { + jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; + return 0; + } + return 1; +} + +static int jffs2_compressor_Xable(const char *name, int disabled) +{ + struct jffs2_compressor *this; + list_for_each_entry(this, &jffs2_compressor_list, list) { + if (!strcmp(this->name, name)) { + this->disabled = disabled; + return 0; + } + } + return 1; +} + +static int jffs2_set_compressor_priority(const char *name, int priority) +{ + struct jffs2_compressor *this,*comp; + list_for_each_entry(this, &jffs2_compressor_list, list) { + if (!strcmp(this->name, name)) { + this->priority = priority; + comp = this; + goto reinsert; + } + } + fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name); + return 1; +reinsert: + /* list is sorted in the order of priority, so if + we change it we have to reinsert it into the + good place */ + list_del(&comp->list); + list_for_each_entry(this, &jffs2_compressor_list, list) { + if (this->priority < comp->priority) { + list_add(&comp->list, this->list.prev); + return 0; + } + } + list_add_tail(&comp->list, &jffs2_compressor_list); + return 0; +} + +static void jffs2_disable_compressors(void) { + struct jffs2_compressor *this; + list_for_each_entry(this, &jffs2_compressor_list, list) { + this->disabled = 1; + } +} + +int jffs2_activate_compression_config(const char *compr_config) +{ + char *str_dup, *compr, *next_compr, *prio_str; + int prio; + + if (compr_config==NULL) { + fprintf(stderr, "Compression config not found.\n"); + return 1; + } + str_dup = (char*)malloc(strlen(compr_config)+1); + strcpy(str_dup,compr_config); + compr = str_dup; + jffs2_disable_compressors(); + while (compr != NULL) { + next_compr = config_str_find_next(compr, ','); + if (jffs2_set_compression_mode_name(compr)) { + prio_str = config_str_find_next(compr, ':'); + prio = -1; if (prio_str != NULL) prio = atoi(prio_str); + if (jffs2_compressor_Xable(compr,0)) { /* enable */ + fprintf(stderr,"Unknow compressor of mode %s.\n",compr); + return 1; + } + if (prio>=0) jffs2_set_compressor_priority(compr,prio); + } + compr = next_compr; + } + free(str_dup); + return 0; +} + +void jffs2_activate_default_compression_config(void) +{ + jffs2_activate_compression_config(jffs2_default_compression_config); +} + +int jffs2_set_default_compression_config(const char *config) +{ + if (jffs2_activate_compression_config(config)) { + return 1; + } + jffs2_default_compression_config = strdup(config); + return 0; +} + +int jffs2_compression_read_config_file(const char *config_filename) +{ + FILE *f; + char line[501]; + char *filename=NULL,*type,*compr_config; + struct jffs2_compression_config_for_file *c; + int is_model=-1; + + f = fopen(config_filename,"r"); + if (f==NULL) { + fprintf(stderr, "Cannot open file: %s\n",filename); + return 1; + } + while (!feof(f)) { + if (fgets(line,500,f)==NULL) break; + type = compr_config = NULL; + filename=line; + type = config_str_find_next(filename,';'); + if (type!=NULL) { + compr_config = config_str_find_next(type,';'); + if (compr_config!=NULL) config_str_find_next(compr_config,';'); /* for later compatibilty */ + } + else break; + if (!strcmp(type, "file")) is_model=0; + if (!strcmp(type, "model")) is_model=1; + if (is_model<0) { + fprintf(stderr, "In %s type must be file or model (not %s).\n", filename, type); + return 1; + } + if (jffs2_activate_compression_config(compr_config)) { + fprintf(stderr,"Error processing config for file %s.\n", filename); + return 1; + } + c = malloc(sizeof(*c)); + c->compr_config = strdup(compr_config); + c->filename = strdup(filename); + c->path = NULL; + c->is_model = is_model; + c->ino = 0; + c->len = 0; + list_add_tail(&c->list, &jffs2_compression_configs); + } + fclose(f); + jffs2_activate_default_compression_config(); + return 0; +} + +struct jffs2_compression_config_for_file *jffs2_get_compression_config_for_file(const char *name, const char *path) +{ + struct jffs2_compression_config_for_file *this; + + if (*name=='/') name++; + list_for_each_entry(this, &jffs2_compression_configs, list) { + if (!strcmp(this->filename, name)) { + this->path = strdup(path); + return this; + } + } + return NULL; +} + +static int jffs2_model_init(struct jffs2_model *m) +{ + struct jffs2_compressor *this; + unsigned char *p; + + p = m->model; + if ((p[0]!='J')||(p[1]!='2')||(p[2]!='M')||(p[3]!='F')) { + fprintf(stderr, "Bad magic (%c%c%c%c) in model file %s.\n",p[0],p[1],p[2],p[3],m->filename); + return 1; + } + m->compr = p[4]; + m->serial = p[5]; + list_for_each_entry(this, &jffs2_compressor_list, list) { + if (m->compr == this->compr) { + if (!this->model_init) return 0; + return this->model_init(&(m->model)); + } + } + fprintf(stderr, "Compressor (%d) not found for model %s.\n", m->compr, m->filename); + return 1; +} + +static int jffs2_do_load_model(const char *path, const char *filename) +{ + struct stat st; + FILE *f; + char *buff; + struct jffs2_model *m; + int ret=0; + + if (stat(path,&st)) return 1; + buff = malloc(st.st_size); if (!buff) return 2; + f = fopen(path,"r"); if (!f) return 3; + if (fread(buff,1,st.st_size,f)!=st.st_size) return 4; + fclose(f); + m = malloc(sizeof(*m)); + if (!m) return 5; + m->model = buff; + m->filename = filename; + if ((ret=jffs2_model_init(m))!=0) { + fprintf(stderr,"Error %d at init model file %s.\n",ret,filename); + return ret; + } + list_add_tail(&m->list, &jffs2_model_list); + return 0; +} + +int jffs2_model_load(void) +{ + int ret = 0; + struct jffs2_compression_config_for_file *this; + list_for_each_entry(this, &jffs2_compression_configs, list) { + if ((this->is_model) && (this->path)) { + fprintf(stderr,"Load model file %s %s\n",this->path,this->filename); + ret = jffs2_do_load_model(this->path,this->filename); + if (ret) return ret; + } + } + return 0; +} + +int jffs2_compressors_before_file(struct jffs2_compression_config_for_file *conf, int ino, int len) +{ + conf->ino = ino; + conf->len = len; + jffs2_activate_compression_config(conf->compr_config); + return conf->is_model; +} + +/* + Returns the array of inode number of the model files. + The first element of the array is the size of it. +*/ +int *jffs2_get_model_ino_array(void) +{ + struct jffs2_compression_config_for_file *this; + int model_num = 0; + int *ino_array,i; + + list_for_each_entry(this, &jffs2_compression_configs, list) { + if (this->is_model) { + if (this->ino) model_num++; + else fprintf(stderr,"Warning: model file %s not found.\n",this->filename); + } + else { + if (!this->ino) fprintf(stderr,"Warning: file %s not found.\n",this->filename); + } + } + ino_array = malloc(sizeof(int)*model_num*2+1); + if (!ino_array) { + fprintf(stderr,"jffs2_get_model_ino_array(): cannot allocate memory\n"); + return NULL; + } + i=0; + ino_array[i++] = model_num; + list_for_each_entry(this, &jffs2_compression_configs, list) { + if ((this->is_model)&&(this->ino)) { + ino_array[i++]=this->ino; + ino_array[i++]=this->len; + } + } + return ino_array; +} + +void jffs2_model_release(void) +{ + struct jffs2_model *this, *m; + struct jffs2_compressor *comp; + + do { + m = NULL; + /* not the most optimal but analog with kernel */ + list_for_each_entry(this, &jffs2_model_list, list) { + m = this; + } + if (m) { + list_for_each_entry(comp, &jffs2_compressor_list, list) { + if (comp->compr == m->compr) { + if (comp->model_destroy) comp->model_destroy(&m->model); + } + } + if (m->model) { + /* if model_destroy did not do its job let's do it */ + vfree(m->model); + m->model = NULL; + } + list_del(&m->list); + kfree(m); + } + } while (m); +} + +static struct jffs2_model *jffs2_model_get(unsigned char compr, unsigned char min_serial) +{ + struct jffs2_model *this; + + list_for_each_entry(this, &jffs2_model_list, list) { + if ((this->compr == compr) && (this->serial >= min_serial)) { + return this; + } + } + return NULL; +} + +/* END OF COMPRESSOR CONFIG AND MODEL PROCESSING */ + /* jffs2_compress: * @data: Pointer to uncompressed data * @cdata: Pointer to returned pointer to buffer for compressed data @@ -193,6 +557,7 @@ unsigned char *output_buf = NULL, *tmp_buf; uint32_t orig_slen, orig_dlen; uint32_t best_slen=0, best_dlen=0; + struct jffs2_model *m; int serial, best_serial=0; switch (jffs2_compression_mode) { case JFFS2_COMPR_MODE_NONE: @@ -210,23 +575,52 @@ if ((!this->compress)||(this->disabled)) continue; - this->usecount++; - - if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */ - jffs2_decompression_test_prepare(output_buf, orig_dlen); - - *datalen = orig_slen; - *cdatalen = orig_dlen; - compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); - this->usecount--; - if (!compr_ret) { - ret = this->compr; - this->stat_compr_blocks++; - this->stat_compr_orig_size += *datalen; - this->stat_compr_new_size += *cdatalen; - if (jffs2_compression_check) - jffs2_decompression_test(this, data_in, output_buf, *cdatalen, *datalen, orig_dlen); - break; + if (!(this->compr & 0x80)) { + /* OK, this is a non-model-based compressor */ + if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */ + jffs2_decompression_test_prepare(output_buf, orig_dlen); + + *datalen = orig_slen; + *cdatalen = orig_dlen; + this->usecount++; + compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); + this->usecount--; + if (!compr_ret) { + ret = this->compr; + this->stat_compr_blocks++; + this->stat_compr_orig_size += *datalen; + this->stat_compr_new_size += *cdatalen; + if (jffs2_compression_check) + jffs2_decompression_test(this, data_in, output_buf, *cdatalen, *datalen, NULL, orig_dlen); + break; + } + } + else { + /* It is model-based compressor, let's search model for it */ + serial = 0; + m = jffs2_model_get(this->compr,serial); + while (m) { + if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */ + jffs2_decompression_test_prepare(output_buf, orig_dlen); + + *datalen = orig_slen; + *cdatalen = orig_dlen; + this->usecount++; + compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, m->model); + this->usecount--; + if (!compr_ret) { + ret = (uint16_t)this->compr | ((uint16_t)m->serial << 8); + this->stat_compr_blocks++; + this->stat_compr_orig_size += *datalen; + this->stat_compr_new_size += *cdatalen; + if (jffs2_compression_check) + jffs2_decompression_test(this, data_in, output_buf, *cdatalen, *datalen, m->model, orig_dlen); + break; + } + serial = m->serial+1; + m = jffs2_model_get(this->compr,serial); + } + if (ret!=JFFS2_COMPR_NONE) break; } } if (ret == JFFS2_COMPR_NONE) free(output_buf); @@ -255,20 +649,50 @@ this->compr_buf_size = orig_dlen; } } - this->usecount++; - if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */ - jffs2_decompression_test_prepare(this->compr_buf,this->compr_buf_size); - *datalen = orig_slen; - *cdatalen = orig_dlen; - compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); - this->usecount--; - if (!compr_ret) { - if (jffs2_compression_check) - jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen, this->compr_buf_size); - if ((!best_dlen)||(best_dlen>*cdatalen)) { - best_dlen = *cdatalen; - best_slen = *datalen; - best = this; + + if (!(this->compr & 0x80)) { + /* OK, this is a non-model-based compressor */ + if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */ + jffs2_decompression_test_prepare(this->compr_buf,this->compr_buf_size); + *datalen = orig_slen; + *cdatalen = orig_dlen; + this->usecount++; + compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); + this->usecount--; + if (!compr_ret) { + if (jffs2_compression_check) + jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen, NULL, this->compr_buf_size); + if ((!best_dlen)||(best_dlen>*cdatalen)) { + best_dlen = *cdatalen; + best_slen = *datalen; + best = this; + } + } + } + else { + /* It is model-based compressor, let's search model for it */ + serial = 0; + m = jffs2_model_get(this->compr,serial); + while (m) { + if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */ + jffs2_decompression_test_prepare(this->compr_buf,this->compr_buf_size); + *datalen = orig_slen; + *cdatalen = orig_dlen; + this->usecount++; + compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, m->model); + this->usecount--; + if (!compr_ret) { + if (jffs2_compression_check) + jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen, m->model, this->compr_buf_size); + if ((!best_dlen)||(best_dlen>*cdatalen)) { + best_dlen = *cdatalen; + best_slen = *datalen; + best = this; + best_serial = m->serial; + } + } + serial = m->serial+1; + m = jffs2_model_get(this->compr,serial); } } } @@ -281,7 +705,7 @@ best->stat_compr_blocks++; best->stat_compr_orig_size += best_slen; best->stat_compr_new_size += best_dlen; - ret = best->compr; + ret = (uint16_t)best->compr | ((uint16_t)best_serial << 8); } break; default: @@ -300,6 +724,7 @@ return ret; } +/* COMPRESSOR (UN)REGISTRATION */ int jffs2_register_compressor(struct jffs2_compressor *comp) { @@ -332,7 +757,7 @@ { if (comp->usecount) { - fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n"); + fprintf(stderr,"mkfs.jffs2: Compressor modul %s is in use. Unregister failed.\n",comp->name); return -1; } list_del(&comp->list); @@ -340,6 +765,10 @@ return 0; } +/* END OF COMPRESSOR (UN)REGISTRATION */ + +/* COMPRESSOR STATISTICS */ + #define JFFS2_STAT_BUF_SIZE 16000 char *jffs2_list_compressors(void) @@ -366,21 +795,7 @@ act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE); - act_buf += sprintf(act_buf,"Compression mode: "); - switch (jffs2_compression_mode) { - case JFFS2_COMPR_MODE_NONE: - act_buf += sprintf(act_buf,"none"); - break; - case JFFS2_COMPR_MODE_PRIORITY: - act_buf += sprintf(act_buf,"priority"); - break; - case JFFS2_COMPR_MODE_SIZE: - act_buf += sprintf(act_buf,"size"); - break; - default: - act_buf += sprintf(act_buf,"unkown"); - break; - } + act_buf += sprintf(act_buf,"Default compression config:\n %s\n",jffs2_default_compression_config); act_buf += sprintf(act_buf,"\nCompressors:\n"); act_buf += sprintf(act_buf,"%10s ","none"); act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks, @@ -399,103 +814,4 @@ return buf; } -int jffs2_set_compression_mode_name(const char *name) -{ - if (!strcmp("none",name)) { - jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; - return 0; - } - if (!strcmp("priority",name)) { - jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; - return 0; - } - if (!strcmp("size",name)) { - jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; - return 0; - } - return 1; -} - -static int jffs2_compressor_Xable(const char *name, int disabled) -{ - struct jffs2_compressor *this; - list_for_each_entry(this, &jffs2_compressor_list, list) { - if (!strcmp(this->name, name)) { - this->disabled = disabled; - return 0; - } - } - return 1; -} - -int jffs2_enable_compressor_name(const char *name) -{ - return jffs2_compressor_Xable(name, 0); -} - -int jffs2_disable_compressor_name(const char *name) -{ - return jffs2_compressor_Xable(name, 1); -} - -int jffs2_set_compressor_priority(const char *name, int priority) -{ - struct jffs2_compressor *this,*comp; - list_for_each_entry(this, &jffs2_compressor_list, list) { - if (!strcmp(this->name, name)) { - this->priority = priority; - comp = this; - goto reinsert; - } - } - fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name); - return 1; -reinsert: - /* list is sorted in the order of priority, so if - we change it we have to reinsert it into the - good place */ - list_del(&comp->list); - list_for_each_entry(this, &jffs2_compressor_list, list) { - if (this->priority < comp->priority) { - list_add(&comp->list, this->list.prev); - return 0; - } - } - list_add_tail(&comp->list, &jffs2_compressor_list); - return 0; -} - - -int jffs2_compressors_init(void) -{ -#ifdef CONFIG_JFFS2_ZLIB - jffs2_zlib_init(); -#endif -#ifdef CONFIG_JFFS2_RTIME - jffs2_rtime_init(); -#endif -#ifdef CONFIG_JFFS2_LZARI - jffs2_lzari_init(); -#endif -#ifdef CONFIG_JFFS2_LZO - jffs2_lzo_init(); -#endif - return 0; -} - -int jffs2_compressors_exit(void) -{ -#ifdef CONFIG_JFFS2_LZO - jffs2_lzo_exit(); -#endif -#ifdef CONFIG_JFFS2_LZARI - jffs2_lzari_exit(); -#endif -#ifdef CONFIG_JFFS2_RTIME - jffs2_rtime_exit(); -#endif -#ifdef CONFIG_JFFS2_ZLIB - jffs2_zlib_exit(); -#endif - return 0; -} +/* END OF COMPRESSOR STATISTICS */ diff --unified --recursive --new-file mtd2/util/compr.h mtd/util/compr.h --- mtd2/util/compr.h 2004-06-25 00:00:13.000000000 +0200 +++ mtd/util/compr.h 2004-10-06 10:56:02.000000000 +0200 @@ -17,21 +17,28 @@ #include #include #include -#include "linux/jffs2.h" -#define CONFIG_JFFS2_ZLIB -#define CONFIG_JFFS2_RTIME -#define CONFIG_JFFS2_LZARI -#define CONFIG_JFFS2_LZO -#define JFFS2_LZARI_DISABLED -#define JFFS2_LZO_DISABLED - -#define JFFS2_RUBINMIPS_PRIORITY 10 -#define JFFS2_DYNRUBIN_PRIORITY 20 -#define JFFS2_LZARI_PRIORITY 30 -#define JFFS2_LZO_PRIORITY 40 -#define JFFS2_RTIME_PRIORITY 50 -#define JFFS2_ZLIB_PRIORITY 60 +#define JFFS2_COMPR_NONE 0x00 +#define JFFS2_COMPR_ZERO 0x01 +#define JFFS2_COMPR_RTIME 0x02 +#define JFFS2_COMPR_RUBINMIPS 0x03 +#define JFFS2_COMPR_COPY 0x04 +#define JFFS2_COMPR_DYNRUBIN 0x05 +#define JFFS2_COMPR_ZLIB 0x06 +#define JFFS2_COMPR_LZO 0x07 +#define JFFS2_COMPR_LZARI 0x08 +/* Model based compressors */ +#define JFFS2_COMPR_ARMLIB 0x81 + +#define DEFAULT_COMPRESSION_CONFIG "priority,zlib:70,rtime:60" + +/* Default compressor priorities (compression config overrides them) */ +#define CONFIG_JFFS2_RUBIN_PRIORITY 20 +#define CONFIG_JFFS2_LZARI_PRIORITY 30 +#define CONFIG_JFFS2_LZO_PRIORITY 40 +#define CONFIG_JFFS2_ARMLIB_PRIORITY 50 +#define CONFIG_JFFS2_RTIME_PRIORITY 60 +#define CONFIG_JFFS2_ZLIB_PRIORITY 70 #define JFFS2_COMPR_MODE_NONE 0 #define JFFS2_COMPR_MODE_PRIORITY 1 @@ -61,24 +68,20 @@ struct list_head *next, *prev; }; -void jffs2_set_compression_mode(int mode); -int jffs2_get_compression_mode(void); -int jffs2_set_compression_mode_name(const char *mode_name); - -int jffs2_enable_compressor_name(const char *name); -int jffs2_disable_compressor_name(const char *name); - -int jffs2_set_compressor_priority(const char *name, int priority); - struct jffs2_compressor { struct list_head list; int priority; /* used by prirority comr. mode */ char *name; - char compr; /* JFFS2_COMPR_XXX */ + unsigned char compr; /* JFFS2_COMPR_XXX */ int (*compress)(unsigned char *data_in, unsigned char *cpage_out, uint32_t *srclen, uint32_t *destlen, void *model); int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, uint32_t cdatalen, uint32_t datalen, void *model); + int (*model_init)(void **model); + /* called to init model data */ + int (*model_destroy)(void **model); + /* called to free model data, + it should set *model to NULL */ int usecount; int disabled; /* if seted the compressor won't compress */ unsigned char *compr_buf; /* used by size compr. mode */ @@ -89,6 +92,26 @@ uint32_t stat_decompr_blocks; }; +/* Structure for model files and regular files which will compressed + by not the default compressor config */ +struct jffs2_compression_config_for_file { + struct list_head list; + char *compr_config; + const char *filename; + const char *path; /* filled by jffs2_get_compression_config_for_file() */ + int is_model; + int ino; /* filled by jffs2_compressors_before_file() */ + int len; /* filled by jffs2_compressors_before_file() */ +}; + +struct jffs2_model { + struct list_head list; + const char *filename; + void *model; /* model information */ + unsigned char compr; /* JFFS2_COMPR_XXX */ + unsigned char serial; +}; + int jffs2_register_compressor(struct jffs2_compressor *comp); int jffs2_unregister_compressor(struct jffs2_compressor *comp); @@ -98,6 +121,21 @@ uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out, uint32_t *datalen, uint32_t *cdatalen); +int jffs2_compression_read_config_file(const char *filename); +int jffs2_set_default_compression_config(const char *config); + +int jffs2_activate_compression_config(const char *config); +void jffs2_activate_default_compression_config(void); + +struct jffs2_compression_config_for_file *jffs2_get_compression_config_for_file(const char *name, const char *path); +int jffs2_model_load(void); +void jffs2_model_release(void); +/* Sets the corresponding compressor config and fill the ino field + Returns 1 if the file is a model file, otherwise 0 */ +int jffs2_compressors_before_file(struct jffs2_compression_config_for_file *conf, int ino, int len); +/* Returns the inodes of the model files */ +int *jffs2_get_model_ino_array(void); + /* If it is setted, a decompress will be called after every compress */ void jffs2_compression_check_set(int yesno); int jffs2_compression_check_get(void); @@ -106,24 +144,4 @@ char *jffs2_list_compressors(void); char *jffs2_stats(void); -/* Compressor modules */ - -/* These functions will be called by jffs2_compressors_init/exit */ -#ifdef CONFIG_JFFS2_ZLIB -int jffs2_zlib_init(void); -void jffs2_zlib_exit(void); -#endif -#ifdef CONFIG_JFFS2_RTIME -int jffs2_rtime_init(void); -void jffs2_rtime_exit(void); -#endif -#ifdef CONFIG_JFFS2_LZARI -int jffs2_lzari_init(void); -void jffs2_lzari_exit(void); -#endif -#ifdef CONFIG_JFFS2_LZO -int jffs2_lzo_init(void); -void jffs2_lzo_exit(void); -#endif - #endif /* __JFFS2_COMPR_H__ */ diff --unified --recursive --new-file mtd2/util/compr_rtime.c mtd/util/compr_rtime.c --- mtd2/util/compr_rtime.c 2004-06-24 00:00:14.000000000 +0200 +++ mtd/util/compr_rtime.c 2004-10-06 10:52:09.000000000 +0200 @@ -103,7 +103,7 @@ static struct jffs2_compressor jffs2_rtime_comp = { - .priority = JFFS2_RTIME_PRIORITY, + .priority = CONFIG_JFFS2_RTIME_PRIORITY, .name = "rtime", .disabled = 0, .compr = JFFS2_COMPR_RTIME, diff --unified --recursive --new-file mtd2/util/compr_zlib.c mtd/util/compr_zlib.c --- mtd2/util/compr_zlib.c 2004-06-24 00:00:14.000000000 +0200 +++ mtd/util/compr_zlib.c 2004-10-06 10:52:09.000000000 +0200 @@ -129,7 +129,7 @@ } static struct jffs2_compressor jffs2_zlib_comp = { - .priority = JFFS2_ZLIB_PRIORITY, + .priority = CONFIG_JFFS2_ZLIB_PRIORITY, .name = "zlib", .disabled = 0, .compr = JFFS2_COMPR_ZLIB, diff --unified --recursive --new-file mtd2/util/config mtd/util/config --- mtd2/util/config 1970-01-01 01:00:00.000000000 +0100 +++ mtd/util/config 2004-10-06 12:11:01.000000000 +0200 @@ -0,0 +1 @@ +model.armlib;model;zlib:60,rtime:50 diff --unified --recursive --new-file mtd2/util/jffs2dump.c mtd/util/jffs2dump.c --- mtd2/util/jffs2dump.c 2004-06-20 00:00:57.000000000 +0200 +++ mtd/util/jffs2dump.c 2004-10-06 10:52:09.000000000 +0200 @@ -185,6 +185,7 @@ uint16_t type; int bitchbitmask = 0; int obsolete; + uint32_t i; while ( p < (data + imglen)) { node = (union jffs2_node_union*) p; @@ -277,6 +278,37 @@ p += PAD(je32_to_cpu (node->d.totlen)); break; + + case JFFS2_NODETYPE_MODELINFO: + printf ("%8s Modelinfo node at 0x%08x, totlen 0x%08x, model_num %2d, models: ", + obsolete ? "Obsolete" : "", + p - data, je32_to_cpu (node->m.totlen), + je32_to_cpu(node->m.model_num)); + for (i=0 ; im.model_num) ; i++) { + printf("ino=%d,size=%d ", + je32_to_cpu(node->m.models[i*2]), + je32_to_cpu(node->m.models[i*2+1])); + } + printf("\n"); + + crc = crc32 (0, node, sizeof (struct jffs2_raw_modelinfo) - 8); + if (crc != je32_to_cpu (node->m.node_crc)) { + printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->m.node_crc), crc); + p += PAD(je32_to_cpu (node->m.totlen)); + dirty += PAD(je32_to_cpu (node->m.totlen));; + continue; + } + + crc = crc32(0, p + sizeof (struct jffs2_raw_modelinfo), je32_to_cpu(node->m.model_num)*2*sizeof(jint32_t)); + if (crc != je32_to_cpu(node->m.models_crc)) { + printf ("Wrong name_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->m.models_crc), crc); + p += PAD(je32_to_cpu (node->m.totlen)); + dirty += PAD(je32_to_cpu (node->m.totlen));; + continue; + } + + p += PAD(je32_to_cpu (node->m.totlen)); + break; case JFFS2_NODETYPE_CLEANMARKER: if (verbose) { @@ -325,8 +357,8 @@ char *p = data; union jffs2_node_union *node, newnode; int fd, len; - jint32_t mode; - uint32_t crc; + jint32_t mode, m_ino, m_size; + uint32_t crc, i; fd = open (cnvfile, O_WRONLY | O_CREAT, 0644); if (fd < 0) { @@ -418,9 +450,29 @@ write (fd, &newnode, sizeof (struct jffs2_raw_dirent)); write (fd, p + sizeof (struct jffs2_raw_dirent), PAD (je32_to_cpu (node->d.totlen) - sizeof (struct jffs2_raw_dirent))); - p += PAD(je32_to_cpu (node->d.totlen)); + p += PAD(je32_to_cpu (node->d.totlen)); break; + case JFFS2_NODETYPE_MODELINFO: + newnode.m.magic = cnv_e16 (node->m.magic); + newnode.m.nodetype = cnv_e16 (node->m.nodetype); + newnode.m.totlen = cnv_e32 (node->m.totlen); + newnode.m.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); + newnode.m.model_num = cnv_e32 (node->m.model_num); + if (recalccrc) + newnode.m.models_crc = cpu_to_e32 ( crc32(0, p + sizeof (struct jffs2_raw_modelinfo), 2 * je32_to_cpu(node->m.model_num) * sizeof(jint32_t))); + else + newnode.m.models_crc = cnv_e32 (node->m.models_crc); + write (fd, &newnode, sizeof (struct jffs2_raw_modelinfo)); + for (i=0 ; i < je32_to_cpu(node->m.model_num) ; i++) { + m_ino = cnv_e32 (node->m.models[i*2]); + m_size = cnv_e32 (node->m.models[i*2+1]); + write (fd, &m_ino, sizeof(m_ino)); + write (fd, &m_size, sizeof(m_size)); + } + p += PAD(je32_to_cpu (node->m.totlen)); + break; + case JFFS2_NODETYPE_CLEANMARKER: case JFFS2_NODETYPE_PADDING: newnode.u.magic = cnv_e16 (node->u.magic); diff --unified --recursive --new-file mtd2/util/mkfs.jffs2.1 mtd/util/mkfs.jffs2.1 --- mtd2/util/mkfs.jffs2.1 2004-05-28 12:51:11.000000000 +0200 +++ mtd/util/mkfs.jffs2.1 2004-10-06 10:52:09.000000000 +0200 @@ -49,16 +49,10 @@ .B -P,--squash-perms ] [ -.B -m,--compression-mode=MODE +.B -C,--default-compr-config=CONFIG ] [ -.B -x,--disable-compressor=NAME -] -[ -.B -X,--enable-compressor=NAME -] -[ -.B -y,--compressor-priority=PRIORITY:NAME +.B -F,--compressor-config-file=FILENAME ] [ .B -L,--list-compressors @@ -173,31 +167,45 @@ .B -P, --squash-perms Squash permissions, removing write permission for \'group\' and \'other\'. .TP -.B -m, --compression-mode=MODE -Set the default compression mode. The default mode is -.B priority -which tries the compressors in a predefinied order and chooses the first -successful one. The alternatives are: +.B -C, --default-compr-config=CONFIG +Set the default compression configuration. The CONFIG is a comma separated +string. Every word in this string can be the name of a compressor +or the name of a compression mode: .B none -(mkfs will not compress) and +(mkfs will not compress), +.B priority +(which tries the compressors in priority order and chooses the first +successful one) or .B size -(mkfs will try all compressor and chooses the one which have the smallest result). -.TP -.B -x, --disable-compressor=NAME -Disable a compressor. Use -.B -L -to see the list of the avaiable compressors and their default states. -.TP -.B -X, --enable-compressor=NAME -Enable a compressor. Use -.B -L -to see the list of the avaiable compressors and their default states. -.TP -.B -y, --compressor-priority=PRIORITY:NAME -Set the priority of a compressor. Use -.B -L -to see the list of the avaiable compressors and their default priority. -Priorities are used by priority compression mode. +(mkfs will try all compressors and chooses the one which have the smallest result). +The name of a compressor can be in format +.B compressor_name +or +.B compressor_name:PRIORITY +, where PRIORITY is an integer. +All none declarated compressors will be disabled. +The default config is "priority,zlib:70,rtime:60". +.TP +.B -F, --compressor-config-file=FILENAME +Specifies a compression config file. In this config file every line must be +in format "FILENAME;TYPE;COMPRESSION_CONFIG", where +.B FILENAME +is a relative file name, +.B TYPE +can be only one of the +.B file +or +.B model +keywords, and +.B COMPRESSOIN_CONFIG +must be a valid compression configuration (see +.B -C +option!). This specified file will be compressed the specified compressor +configuration. All of the non specified files will be compressed by +the default compression configuration. +For example a line of this config file can be: +"boot/zImage;file;priority,zlib:60,rtime:50", an other +example: "model.armlib;model;zlib:60". .TP .B -L, --list-compressors Show the list of the avaiable compressors and their states. diff --unified --recursive --new-file mtd2/util/mkfs.jffs2.c mtd/util/mkfs.jffs2.c --- mtd2/util/mkfs.jffs2.c 2004-05-28 12:51:11.000000000 +0200 +++ mtd/util/mkfs.jffs2.c 2004-10-06 11:32:23.000000000 +0200 @@ -6,6 +6,8 @@ * 2001 David A. Schleef * 2002 Axis Communications AB * 2001, 2002 Erik Andersen + * 2004 Ferenc Havasi , + * University of Szeged, Hungary * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -76,6 +78,8 @@ #define mkfs_debug_msg(a...) { } #define min(x,y) ({ typeof((x)) _x = (x); typeof((y)) _y = (y); (_x>_y)?_y:_x; }) +#include "compr.h" + struct filesystem_entry { char *name; /* Name of this directory (think basename) */ char *path; /* Path of this directory (think dirname) */ @@ -87,6 +91,7 @@ struct filesystem_entry *prev; /* Only relevant to non-directories */ struct filesystem_entry *next; /* Only relevant to non-directories */ struct filesystem_entry *files; /* Only relevant to directories */ + struct jffs2_compression_config_for_file *compr_config; /* If it is NULL the default compressor config will be used */ }; @@ -337,6 +342,8 @@ entry->sb.st_size = strlen(entry->link); } + entry->compr_config = jffs2_get_compression_config_for_file(name, path); + /* This happens only for root */ if (!parent) return (entry); @@ -666,7 +673,6 @@ * 64-bit arches and whatnot, use the --pagesize=SIZE option */ int page_size = 4096; -#include "compr.h" static void full_write(int fd, const void *buf, int len) { @@ -791,7 +797,17 @@ mkfs_debug_msg("writing file '%s' ino=%lu parent_ino=%lu", e->name, (unsigned long) statbuf->st_ino, (unsigned long) e->parent->sb.st_ino); - write_dirent(e); + + if (e->compr_config) { + /* It sets the special compression config if specified for this file. + If it is a model file we don't store its dirent. */ + if (!jffs2_compressors_before_file(e->compr_config, statbuf->st_ino, statbuf->st_size)) { + write_dirent(e); + } + } + else { + write_dirent(e); + } buf = xmalloc(page_size); cbuf = NULL; @@ -881,6 +897,8 @@ } free(buf); close(fd); + + if (e->compr_config) jffs2_activate_default_compression_config(); } static void write_symlink(struct filesystem_entry *e) @@ -1105,6 +1123,54 @@ } } +static void write_modelinfo() +{ + int *model_inodes; + struct jffs2_raw_modelinfo *rm; + unsigned int model_num, fullsize, i; + + model_inodes = jffs2_get_model_ino_array(); + if (!model_inodes) return; + if (model_inodes[0] == 0) { + free(model_inodes); + return; + } + + model_num = model_inodes[0]; + fullsize = sizeof(*rm) + model_num * sizeof(int) * 2; + + rm = malloc(fullsize); + + memset(rm, 0, fullsize); + + rm->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rm->nodetype = cpu_to_je16(JFFS2_NODETYPE_MODELINFO); + rm->totlen = cpu_to_je32(fullsize); + + rm->hdr_crc = cpu_to_je32(crc32(0, rm, + sizeof(struct jffs2_unknown_node) - 4)); + + rm->model_num = cpu_to_je32(model_num); + + rm->node_crc = cpu_to_je32(crc32(0, rm, sizeof(*rm) - 8)); + + if (verbose) fprintf(stderr,"\nModel file inodes: "); + for (i=0;imodels[i*2] = cpu_to_je32(model_inodes[i*2+1]); + rm->models[i*2+1] = cpu_to_je32(model_inodes[i*2+2]); + } + if (verbose) fprintf(stderr,"\n"); + + rm->models_crc = cpu_to_je32(crc32(0, &(rm->models[0]), 2 * model_num * sizeof(int))); + + pad_block_if_less_than(fullsize); + full_write(out_fd, rm, fullsize); + free(rm); + padword(); + free(model_inodes); +} + static void create_target_filesystem(struct filesystem_entry *root) { cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -1115,6 +1181,8 @@ ino = root->sb.st_ino = 1; recursive_populate_directory(root); + write_modelinfo(); + if (pad_fs_size == -1) { padblock(); } else { @@ -1152,8 +1220,8 @@ {"squash-perms", 0, NULL, 'P'}, {"faketime", 0, NULL, 'f'}, {"devtable", 1, NULL, 'D'}, - {"compression-mode", 1, NULL, 'm'}, - {"disable-compressor", 1, NULL, 'x'}, + {"default-compr-config", 1, NULL, 'C'}, + {"compressor-config-file", 1, NULL, 'F'}, {"test-compression", 0, NULL, 't'}, {"compressor-priority", 1, NULL, 'y'}, {NULL, 0, NULL, 0} @@ -1170,13 +1238,13 @@ " -s, --pagesize=SIZE Use page size (max data node size) SIZE (default: 4KiB)\n" " -e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB)\n" " -c, --cleanmarker=SIZE Size of cleanmarker (default 12)\n" - " -m, --compr-mode=MODE Select compression mode (default: priortiry)\n" - " -x, --disable-compressor=COMPRESSOR_NAME\n" - " Disable a compressor\n" - " -X, --enable-compressor=COMPRESSOR_NAME\n" - " Enable a compressor\n" - " -y, --compressor-priority=PRIORITY:COMPRESSOR_NAME\n" - " Set the priority of a compressor\n" + " -C, --default-compr-config=MODE\n" + " Select default compression mode & active compressor\n" + " Default value: \"priority,zlib:60,rtime:50\"\n" + " -F, --compressor-config-file=FILE\n" + " The name of the compressor config file to define\n" + " different compressor configuration for files.\n" + " Default: not used.\n" " -L, --list-compressors Show the list of the avaiable compressors\n" " -t, --test-compression Call decompress and compare with the original (for test)\n" " -n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock\n" @@ -1193,7 +1261,7 @@ " -V, --version Display version information\n\n"; -static char *revtext = "$Revision: 1.42 $"; +static char *revtext = "$Revision: 1.43 $"; int main(int argc, char **argv) { @@ -1202,13 +1270,11 @@ struct stat sb; FILE *devtable = NULL; struct filesystem_entry *root; - char *compr_name = NULL; - int compr_prior = -1; jffs2_compressors_init(); while ((opt = getopt_long(argc, argv, - "D:d:r:s:o:qUPfh?vVe:lbp::nc:m:x:X:Lty:", long_options, &c)) >= 0) + "D:d:r:s:o:qUPfh?vVe:lbp::nc:C:F:Lt", long_options, &c)) >= 0) { switch (opt) { case 'D': @@ -1316,9 +1382,11 @@ else pad_fs_size = -1; break; + case 'n': add_cleanmarkers = 0; break; + case 'c': cleanmarker_size = strtol(optarg, NULL, 0); if (cleanmarker_size < sizeof(cleanmarker)) { @@ -1328,39 +1396,26 @@ error_msg_and_die("cleanmarker size must be < eraseblock size"); } break; - case 'm': - if (jffs2_set_compression_mode_name(optarg)) { - error_msg_and_die("Unknown compression mode %s", optarg); + case 'C': + if (jffs2_set_default_compression_config(optarg)) { + error_msg_and_die("Invalid compression configuration \"%s\"", optarg); } break; - case 'x': - if (jffs2_disable_compressor_name(optarg)) { - error_msg_and_die("Unknown compressor name %s",optarg); - } - break; - case 'X': - if (jffs2_enable_compressor_name(optarg)) { - error_msg_and_die("Unknown compressor name %s",optarg); - } - break; + case 'L': error_msg_and_die("\n%s",jffs2_list_compressors()); break; + case 't': jffs2_compression_check_set(1); break; - case 'y': - compr_name = malloc(strlen(optarg)); - sscanf(optarg,"%d:%s",&compr_prior,compr_name); - if ((compr_prior>=0)&&(compr_name)) { - if (jffs2_set_compressor_priority(compr_name, compr_prior)) - exit(EXIT_FAILURE); - } - else { - error_msg_and_die("Cannot parse %s",optarg); + + case 'F': + if (jffs2_compression_read_config_file(optarg)) { + error_msg_and_die("Unable to read or process compressor config file %s.\n",optarg); } - free(compr_name); break; + } } if (out_fd == -1) { @@ -1383,6 +1438,8 @@ if (devtable) parse_device_table(root, devtable); + jffs2_model_load(); + create_target_filesystem(root); cleanup(root); @@ -1394,13 +1451,14 @@ if (verbose) { char *s = jffs2_stats(); - fprintf(stderr,"\n\n%s",s); + fprintf(stderr,"\n%s",s); free(s); } if ((verbose)||(jffs2_compression_check_get()&&(jffs2_compression_check_errorcnt_get()))) { fprintf(stderr,"Compression errors: %d\n",jffs2_compression_check_errorcnt_get()); } + jffs2_model_release(); jffs2_compressors_exit(); return 0;