changeset 1713:0492a413d138

* Merge from public MTD.
author asl
date Thu, 12 Aug 2004 21:35:27 +0000
parents 1cb94172ea76
children 3fc626a650ab
files packages/fs/jffs2/current/ChangeLog packages/fs/jffs2/current/cdl/jffs2.cdl packages/fs/jffs2/current/doc/TODO packages/fs/jffs2/current/doc/TODO.eCos packages/fs/jffs2/current/include/linux/jffs2.h packages/fs/jffs2/current/src/compr.c packages/fs/jffs2/current/src/compr_rtime.c packages/fs/jffs2/current/src/compr_rubin.c packages/fs/jffs2/current/src/compr_zlib.c packages/fs/jffs2/current/src/erase.c packages/fs/jffs2/current/src/fs-ecos.c packages/fs/jffs2/current/src/gc.c packages/fs/jffs2/current/src/nodelist.h packages/fs/jffs2/current/src/os-ecos.h packages/fs/jffs2/current/src/read.c packages/fs/jffs2/current/src/scan.c packages/fs/jffs2/current/src/write.c
diffstat 17 files changed, 684 insertions(+), 210 deletions(-) [+]
line wrap: on
line diff
--- a/packages/fs/jffs2/current/ChangeLog
+++ b/packages/fs/jffs2/current/ChangeLog
@@ -1,3 +1,8 @@
+2004-08-12  Andrew Lunn <andrew.lunn@ascom.ch>
+	    Gary Thomas <gary@mlbassoc.com>
+
+	* Merge from public MTD.
+	
 2004-04-19  Oyvind Harboe <oyvind.harboe@zylin.com>
 	
 	* src/build.c: JFFS2 can now be used as a write-once, read many mode
--- a/packages/fs/jffs2/current/cdl/jffs2.cdl
+++ b/packages/fs/jffs2/current/cdl/jffs2.cdl
@@ -4,7 +4,7 @@
 #
 #      JFFS2 Filesystem configuration data
 #
-#      $Id: jffs2.cdl,v 1.14 2004/02/17 15:40:36 gthomas Exp $
+#      $Id: jffs2.cdl,v 1.15 2004/04/21 18:50:52 gthomas Exp $
 #
 # ====================================================================
 #####ECOSGPLCOPYRIGHTBEGIN####
--- a/packages/fs/jffs2/current/doc/TODO
+++ b/packages/fs/jffs2/current/doc/TODO
@@ -17,7 +17,8 @@
  - test, test, test
 
  - NAND flash support:
-	- done :)
+	- almost done :)
+	- use bad block check instead of the hardwired byte check
 
  - Optimisations:
    - Split writes so they go to two separate blocks rather than just c->nextblock.
--- a/packages/fs/jffs2/current/doc/TODO.eCos
+++ b/packages/fs/jffs2/current/doc/TODO.eCos
@@ -1,4 +1,4 @@
-$Id: TODO.eCos,v 1.2 2003/11/28 11:15:56 dwmw2 Exp $
+$Id: TODO.eCos,v 1.4 2003/11/28 11:15:56 dwmw2 Exp $
 
  - Make symlinks work properly.
 
--- a/packages/fs/jffs2/current/include/linux/jffs2.h
+++ b/packages/fs/jffs2/current/include/linux/jffs2.h
@@ -8,7 +8,7 @@
  * For licensing information, see the file 'LICENCE' in the 
  * jffs2 directory.
  *
- * $Id: jffs2.h,v 1.31 2003/10/04 08:33:05 dwmw2 Exp $
+ * $Id: jffs2.h,v 1.33 2004/05/25 11:31:55 havasi Exp $
  *
  */
 
@@ -43,6 +43,8 @@
 #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
@@ -87,39 +89,6 @@ typedef struct {
 	uint16_t v16;
 } __attribute__((packed)) jint16_t;
 
-#define JFFS2_NATIVE_ENDIAN
-
-/* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from
-   whatever OS we're actually running on here too. */
-
-#if defined(JFFS2_NATIVE_ENDIAN)
-#define cpu_to_je16(x) ((jint16_t){x})
-#define cpu_to_je32(x) ((jint32_t){x})
-#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)})
-
-#define je16_to_cpu(x) ((x).v16)
-#define je32_to_cpu(x) ((x).v32)
-#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m))
-#elif defined(JFFS2_BIG_ENDIAN)
-#define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)})
-#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
-#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))})
-
-#define je16_to_cpu(x) (be16_to_cpu(x.v16))
-#define je32_to_cpu(x) (be32_to_cpu(x.v32))
-#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m)))
-#elif defined(JFFS2_LITTLE_ENDIAN)
-#define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)})
-#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
-#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))})
-
-#define je16_to_cpu(x) (le16_to_cpu(x.v16))
-#define je32_to_cpu(x) (le32_to_cpu(x.v32))
-#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m)))
-#else 
-#error wibble
-#endif
-
 struct jffs2_unknown_node
 {
 	/* All start like this */
--- a/packages/fs/jffs2/current/src/compr.c
+++ b/packages/fs/jffs2/current/src/compr.c
@@ -2,32 +2,39 @@
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Created by Arjan van de Ven <arjanv@redhat.com>
  *
- * Created by Arjan van de Ven <arjanv@redhat.com>
+ * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                    University of Szeged, Hungary
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr.c,v 1.34 2004/03/08 15:29:09 dwmw2 Exp $
+ * $Id: compr.c,v 1.41 2004/06/24 09:51:38 havasi Exp $
  *
  */
 
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/jffs2.h>
-#include "nodelist.h"
+#include "compr.h"
+
+static spinlock_t jffs2_compressor_list_lock = SPIN_LOCK_UNLOCKED;
+
+/* Available compressors are on this list */
+static LIST_HEAD(jffs2_compressor_list);
+
+/* Actual compression mode */
+static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
 
-int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
+void jffs2_set_compression_mode(int mode) 
+{
+        jffs2_compression_mode = mode;
+}
 
+int jffs2_get_compression_mode(void)
+{
+        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;
 
 /* jffs2_compress:
  * @data: Pointer to uncompressed data
@@ -38,103 +45,430 @@ void jffs2_dynrubin_decompress(unsigned 
  *	data. On exit, expected to hold the actual size of the compressed
  *	data.
  *
- * Returns: Byte to be stored with data indicating compression type used.
+ * Returns: Lower byte to be stored with data indicating compression type used.
  * Zero is used to show that the data could not be compressed - the 
  * compressed version was actually larger than the original.
+ * Upper byte will be used later. (soon)
  *
  * If the cdata buffer isn't large enough to hold all the uncompressed data,
  * jffs2_compress should compress as much as will fit, and should set 
  * *datalen accordingly to show the amount of data which were compressed.
  */
-unsigned char jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 			     unsigned char *data_in, unsigned char **cpage_out, 
 			     uint32_t *datalen, uint32_t *cdatalen)
 {
-#ifdef JFFS2_COMPRESSION
-	int ret;
+	int ret = JFFS2_COMPR_NONE;
+        int compr_ret;
+        struct jffs2_compressor *this, *best=NULL;
+        unsigned char *output_buf = NULL, *tmp_buf;
+        uint32_t orig_slen, orig_dlen;
+        uint32_t best_slen=0, best_dlen=0;
 
-	*cpage_out = kmalloc(*cdatalen, GFP_KERNEL);
-	if (!*cpage_out) {
-		printk(KERN_WARNING "No memory for compressor allocation. Compression failed\n");
-		goto out;
-	}
+        switch (jffs2_compression_mode) {
+        case JFFS2_COMPR_MODE_NONE:
+                break;
+        case JFFS2_COMPR_MODE_PRIORITY:
+                output_buf = kmalloc(*cdatalen,GFP_KERNEL);
+                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);
+                list_for_each_entry(this, &jffs2_compressor_list, list) {
+                        /* Skip decompress-only backwards-compatibility and disabled modules */
+                        if ((!this->compress)||(this->disabled))
+                                continue;
 
-#ifdef JFFS2_USE_ZLIB
-	ret = jffs2_zlib_compress(data_in, *cpage_out, datalen, cdatalen);
-	if (!ret) {
-		return JFFS2_COMPR_ZLIB;
-	}
-#endif
-#ifdef JFFS2_USE_DYNRUBIN
-	ret = jffs2_dynrubin_compress(data_in, *cpage_out, datalen, cdatalen);
-	if (!ret) {
-		return JFFS2_COMPR_DYNRUBIN;
-	}
-#endif
-#ifdef JFFS2_USE_RUBINMIPS
-	ret = jffs2_rubinmips_compress(data_in, *cpage_out, datalen, cdatalen);
-	if (!ret) {
-		return JFFS2_COMPR_RUBINMIPS;
-	}
-#endif
-#ifdef JFFS2_USE_RTIME
-	/* rtime does manage to recompress already-compressed data */
-	ret = jffs2_rtime_compress(data_in, *cpage_out, datalen, cdatalen);
-	if (!ret) {
-		return JFFS2_COMPR_RTIME;
-	}
-#endif
-	kfree(*cpage_out);
-#endif /* Compression */
+                        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;
+                        }
+                }
+                spin_unlock(&jffs2_compressor_list_lock);
+                if (ret == JFFS2_COMPR_NONE) kfree(output_buf);
+                break;
+        case JFFS2_COMPR_MODE_SIZE:
+                orig_slen = *datalen;
+                orig_dlen = *cdatalen;
+                spin_lock(&jffs2_compressor_list_lock);
+                list_for_each_entry(this, &jffs2_compressor_list, list) {
+                        /* Skip decompress-only backwards-compatibility and disabled modules */
+                        if ((!this->compress)||(this->disabled))
+                                continue;
+                        /* Allocating memory for output buffer if necessary */
+                        if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) {
+                                spin_unlock(&jffs2_compressor_list_lock);
+                                kfree(this->compr_buf);
+                                spin_lock(&jffs2_compressor_list_lock);
+                                this->compr_buf_size=0;
+                                this->compr_buf=NULL;
+                        }
+                        if (!this->compr_buf) {
+                                spin_unlock(&jffs2_compressor_list_lock);
+                                tmp_buf = kmalloc(orig_dlen,GFP_KERNEL);
+                                spin_lock(&jffs2_compressor_list_lock);
+                                if (!tmp_buf) {
+                                        printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
+                                        continue;
+                                }
+                                else {
+                                        this->compr_buf = tmp_buf;
+                                        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 (best_dlen) {
+                        *cdatalen = best_dlen;
+                        *datalen  = best_slen;
+                        output_buf = best->compr_buf;
+                        best->compr_buf = NULL;
+                        best->compr_buf_size = 0;
+                        best->stat_compr_blocks++;
+                        best->stat_compr_orig_size += best_slen;
+                        best->stat_compr_new_size  += best_dlen;
+                        ret = best->compr;
+                }
+                spin_unlock(&jffs2_compressor_list_lock);
+                break;
+        default:
+                printk(KERN_ERR "JFFS2: unknow compression mode.\n");
+        }
  out:
-	*cpage_out = data_in;
-	*datalen = *cdatalen;
-	return JFFS2_COMPR_NONE; /* We failed to compress */
-}
-
-void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
-{
-	if (orig != comprbuf)
-		kfree(comprbuf);
+        if (ret == JFFS2_COMPR_NONE) {
+	        *cpage_out = data_in;
+	        *datalen = *cdatalen;
+                none_stat_compr_blocks++;
+                none_stat_compr_size += *datalen;
+        }
+        else {
+                *cpage_out = output_buf;
+        }
+	return ret;
 }
 
 int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-		     unsigned char comprtype, unsigned char *cdata_in, 
+		     uint16_t comprtype, unsigned char *cdata_in, 
 		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
 {
-	switch (comprtype) {
+        struct jffs2_compressor *this;
+        int ret;
+
+	switch (comprtype & 0xff) {
 	case JFFS2_COMPR_NONE:
 		/* This should be special-cased elsewhere, but we might as well deal with it */
 		memcpy(data_out, cdata_in, datalen);
+                none_stat_decompr_blocks++;
 		break;
-
 	case JFFS2_COMPR_ZERO:
 		memset(data_out, 0, datalen);
 		break;
-#ifdef JFFS2_USE_ZLIB
-	case JFFS2_COMPR_ZLIB:
-		jffs2_zlib_decompress(cdata_in, data_out, cdatalen, datalen);
-		break;
-#endif
-#ifdef JFFS2_USE_RTIME
-	case JFFS2_COMPR_RTIME:
-		jffs2_rtime_decompress(cdata_in, data_out, cdatalen, datalen);
-		break;
-#endif
-#ifdef JFFS2_USE_RUBINMIPS
-	case JFFS2_COMPR_RUBINMIPS:
-		jffs2_rubinmips_decompress(cdata_in, data_out, cdatalen, datalen);
-		break;
-#endif
-#ifdef JFFS2_USE_DYNRUBIN
-	case JFFS2_COMPR_DYNRUBIN:
-
-		jffs2_dynrubin_decompress(cdata_in, data_out, cdatalen, datalen);
-		break;
-#endif
 	default:
-		printk(KERN_NOTICE "Unknown JFFS2 compression type 0x%02x\n", comprtype);
+                spin_lock(&jffs2_compressor_list_lock);
+                list_for_each_entry(this, &jffs2_compressor_list, list) {
+                        if (comprtype == this->compr) {
+                                this->usecount++;
+                                spin_unlock(&jffs2_compressor_list_lock);
+                                ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL);
+                                spin_lock(&jffs2_compressor_list_lock);
+                                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 avaiable.\n", comprtype);
+                spin_unlock(&jffs2_compressor_list_lock);
 		return -EIO;
 	}
 	return 0;
 }
+
+int jffs2_register_compressor(struct jffs2_compressor *comp)
+{
+        struct jffs2_compressor *this;
+
+        if (!comp->name) {
+                printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
+                return -1;
+        }
+        comp->compr_buf_size=0;
+        comp->compr_buf=NULL;
+        comp->usecount=0;
+        comp->stat_compr_orig_size=0;
+        comp->stat_compr_new_size=0;
+        comp->stat_compr_blocks=0;
+        comp->stat_decompr_blocks=0;
+        D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
+
+        spin_lock(&jffs2_compressor_list_lock);
+
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                if (this->priority < comp->priority) {
+                        list_add(&comp->list, this->list.prev);
+                        goto out;
+                }
+        }
+        list_add_tail(&comp->list, &jffs2_compressor_list);
+out:
+        D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
+                printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
+        })
+
+        spin_unlock(&jffs2_compressor_list_lock);
+
+        return 0;
+}
+
+int jffs2_unregister_compressor(struct jffs2_compressor *comp)
+{
+        D2(struct jffs2_compressor *this;)
+
+        D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
+
+        spin_lock(&jffs2_compressor_list_lock);
+
+        if (comp->usecount) {
+                spin_unlock(&jffs2_compressor_list_lock);
+                printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
+                return -1;
+        }
+        list_del(&comp->list);
+
+        D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
+                printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
+        })
+        spin_unlock(&jffs2_compressor_list_lock);
+        return 0;
+}
+
+#ifdef CONFIG_JFFS2_PROC
+
+#define JFFS2_STAT_BUF_SIZE 16000
+
+char *jffs2_list_compressors(void)
+{
+        struct jffs2_compressor *this;
+        char *buf, *act_buf;
+
+        act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
+                if ((this->disabled)||(!this->compress))
+                        act_buf += sprintf(act_buf,"disabled");
+                else
+                        act_buf += sprintf(act_buf,"enabled");
+                act_buf += sprintf(act_buf,"\n");
+        }
+        return buf;
+}
+
+char *jffs2_stats(void)
+{
+        struct jffs2_compressor *this;
+        char *buf, *act_buf;
+
+        act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
+
+        act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\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, 
+                           none_stat_compr_size, none_stat_decompr_blocks);
+        spin_lock(&jffs2_compressor_list_lock);
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                act_buf += sprintf(act_buf,"%10s ",this->name);
+                if ((this->disabled)||(!this->compress))
+                        act_buf += sprintf(act_buf,"- ");
+                else
+                        act_buf += sprintf(act_buf,"+ ");
+                act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d)  decompr: %d blocks ", this->stat_compr_blocks, 
+                                   this->stat_compr_new_size, this->stat_compr_orig_size, 
+                                   this->stat_decompr_blocks);
+                act_buf += sprintf(act_buf,"\n");
+        }
+        spin_unlock(&jffs2_compressor_list_lock);
+
+        return buf;
+}
+
+char *jffs2_get_compression_mode_name(void) 
+{
+        switch (jffs2_compression_mode) {
+        case JFFS2_COMPR_MODE_NONE:
+                return "none";
+        case JFFS2_COMPR_MODE_PRIORITY:
+                return "priority";
+        case JFFS2_COMPR_MODE_SIZE:
+                return "size";
+        }
+        return "unkown";
+}
+
+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;
+        spin_lock(&jffs2_compressor_list_lock);
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                if (!strcmp(this->name, name)) {
+                        this->disabled = disabled;
+                        spin_unlock(&jffs2_compressor_list_lock);
+                        return 0;                        
+                }
+        }
+        spin_unlock(&jffs2_compressor_list_lock);
+        printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
+        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;
+        spin_lock(&jffs2_compressor_list_lock);
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                if (!strcmp(this->name, name)) {
+                        this->priority = priority;
+                        comp = this;
+                        goto reinsert;
+                }
+        }
+        spin_unlock(&jffs2_compressor_list_lock);
+        printk(KERN_WARNING "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);
+                        spin_unlock(&jffs2_compressor_list_lock);
+                        return 0;
+                }
+        }
+        list_add_tail(&comp->list, &jffs2_compressor_list);
+        spin_unlock(&jffs2_compressor_list_lock);
+        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;
+}
--- a/packages/fs/jffs2/current/src/compr_rtime.c
+++ b/packages/fs/jffs2/current/src/compr_rtime.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_rtime.c,v 1.11 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: compr_rtime.c,v 1.14 2004/06/23 16:34:40 havasi Exp $
  *
  *
  * Very simple lz77-ish encoder.
@@ -25,10 +25,12 @@
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/string.h> 
+#include <linux/jffs2.h> 
+#include "compr.h"
 
 /* _compress returns the compressed size, -1 if bigger */
 int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, 
-		   uint32_t *sourcelen, uint32_t *dstlen)
+		   uint32_t *sourcelen, uint32_t *dstlen, void *model)
 {
 	short positions[256];
 	int outpos = 0;
@@ -67,8 +69,8 @@ int jffs2_rtime_compress(unsigned char *
 }		   
 
 
-void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		      uint32_t srclen, uint32_t destlen)
+int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
+		      uint32_t srclen, uint32_t destlen, void *model)
 {
 	short positions[256];
 	int outpos = 0;
@@ -98,7 +100,29 @@ void jffs2_rtime_decompress(unsigned cha
 				outpos+=repeat;		
 			}
 		}
-	}		
+	}
+        return 0;
 }		   
 
+static struct jffs2_compressor jffs2_rtime_comp = {
+    .priority = JFFS2_RTIME_PRIORITY,
+    .name = "rtime",
+    .compr = JFFS2_COMPR_RTIME,
+    .compress = &jffs2_rtime_compress,
+    .decompress = &jffs2_rtime_decompress,
+#ifdef JFFS2_RTIME_DISABLED
+    .disabled = 1,
+#else
+    .disabled = 0,
+#endif
+};
 
+int jffs2_rtime_init(void)
+{
+    return jffs2_register_compressor(&jffs2_rtime_comp);
+}
+
+void jffs2_rtime_exit(void)
+{
+    jffs2_unregister_compressor(&jffs2_rtime_comp);
+}
--- a/packages/fs/jffs2/current/src/compr_rubin.c
+++ b/packages/fs/jffs2/current/src/compr_rubin.c
@@ -7,17 +7,17 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_rubin.c,v 1.17 2002/05/20 14:56:37 dwmw2 Exp $
+ * $Id: compr_rubin.c,v 1.20 2004/06/23 16:34:40 havasi Exp $
  *
  */
 
  
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/jffs2.h>
 #include "compr_rubin.h"
 #include "histo_mips.h"
-
-
+#include "compr.h"
 
 static void init_rubin(struct rubin_state *rs, int div, int *bits)
 {	
@@ -223,13 +223,13 @@ static int rubin_do_compress(int bit_div
 #if 0
 /* _compress returns the compressed size, -1 if bigger */
 int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, 
-		   uint32_t *sourcelen, uint32_t *dstlen)
+		   uint32_t *sourcelen, uint32_t *dstlen, void *model)
 {
 	return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
 }
 #endif
 int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, 
-		   uint32_t *sourcelen, uint32_t *dstlen)
+		   uint32_t *sourcelen, uint32_t *dstlen, void *model)
 {
 	int bits[8];
 	unsigned char histo[256];
@@ -306,14 +306,15 @@ static void rubin_do_decompress(int bit_
 }		   
 
 
-void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, 
-		   uint32_t sourcelen, uint32_t dstlen)
+int jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, 
+		   uint32_t sourcelen, uint32_t dstlen, void *model)
 {
 	rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
+        return 0;
 }
 
-void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, 
-		   uint32_t sourcelen, uint32_t dstlen)
+int jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, 
+		   uint32_t sourcelen, uint32_t dstlen, void *model)
 {
 	int bits[8];
 	int c;
@@ -322,4 +323,51 @@ void jffs2_dynrubin_decompress(unsigned 
 		bits[c] = data_in[c];
 
 	rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen);
+        return 0;
 }
+
+static struct jffs2_compressor jffs2_rubinmips_comp = {
+    .priority = JFFS2_RUBINMIPS_PRIORITY,
+    .name = "rubinmips",
+    .compr = JFFS2_COMPR_DYNRUBIN,
+    .compress = NULL, /*&jffs2_rubinmips_compress,*/
+    .decompress = &jffs2_rubinmips_decompress,
+#ifdef JFFS2_RUBINMIPS_DISABLED
+    .disabled = 1,
+#else
+    .disabled = 0,
+#endif
+};
+
+int jffs2_rubinmips_init(void)
+{
+    return jffs2_register_compressor(&jffs2_rubinmips_comp);
+}
+
+void jffs2_rubinmips_exit(void)
+{
+    jffs2_unregister_compressor(&jffs2_rubinmips_comp);
+}
+
+static struct jffs2_compressor jffs2_dynrubin_comp = {
+    .priority = JFFS2_DYNRUBIN_PRIORITY,
+    .name = "dynrubin",
+    .compr = JFFS2_COMPR_RUBINMIPS,
+    .compress = jffs2_dynrubin_compress,
+    .decompress = &jffs2_dynrubin_decompress,
+#ifdef JFFS2_DYNRUBIN_DISABLED
+    .disabled = 1,
+#else
+    .disabled = 0,
+#endif
+};
+
+int jffs2_dynrubin_init(void)
+{
+    return jffs2_register_compressor(&jffs2_dynrubin_comp);
+}
+
+void jffs2_dynrubin_exit(void)
+{
+    jffs2_unregister_compressor(&jffs2_dynrubin_comp);
+}
--- a/packages/fs/jffs2/current/src/compr_zlib.c
+++ b/packages/fs/jffs2/current/src/compr_zlib.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_zlib.c,v 1.25 2003/12/03 09:25:43 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.28 2004/06/23 16:34:40 havasi Exp $
  *
  */
 
@@ -22,6 +22,7 @@
 #include <linux/zutil.h>
 #include <asm/semaphore.h>
 #include "nodelist.h"
+#include "compr.h"
 
 	/* Plan: call deflate() with avail_in == *sourcelen, 
 		avail_out = *dstlen - 12 and flush == Z_FINISH. 
@@ -40,7 +41,7 @@ static z_stream inf_strm, def_strm;
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 
-int __init jffs2_zlib_init(void)
+static int __init alloc_workspaces(void)
 {
 	def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
 	if (!def_strm.workspace) {
@@ -58,15 +59,18 @@ int __init jffs2_zlib_init(void)
 	return 0;
 }
 
-void jffs2_zlib_exit(void)
+static void free_workspaces(void)
 {
 	vfree(def_strm.workspace);
 	vfree(inf_strm.workspace);
 }
+#else
+#define alloc_workspaces() (0)
+#define free_workspaces() do { } while(0)
 #endif /* __KERNEL__ */
 
 int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, 
-		   uint32_t *sourcelen, uint32_t *dstlen)
+		   uint32_t *sourcelen, uint32_t *dstlen, void *model)
 {
 	int ret;
 
@@ -131,8 +135,8 @@ int jffs2_zlib_compress(unsigned char *d
 	return ret;
 }
 
-void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		      uint32_t srclen, uint32_t destlen)
+int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+		      uint32_t srclen, uint32_t destlen, void *model)
 {
 	int ret;
 	int wbits = MAX_WBITS;
@@ -166,7 +170,7 @@ void jffs2_zlib_decompress(unsigned char
 	if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
 		printk(KERN_WARNING "inflateInit failed\n");
 		up(&inflate_sem);
-		return;
+		return 1;
 	}
 
 	while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK)
@@ -176,4 +180,39 @@ void jffs2_zlib_decompress(unsigned char
 	}
 	zlib_inflateEnd(&inf_strm);
 	up(&inflate_sem);
+        return 0;
 }
+
+static struct jffs2_compressor jffs2_zlib_comp = {
+    .priority = JFFS2_ZLIB_PRIORITY,
+    .name = "zlib",
+    .compr = JFFS2_COMPR_ZLIB,
+    .compress = &jffs2_zlib_compress,
+    .decompress = &jffs2_zlib_decompress,
+#ifdef JFFS2_ZLIB_DISABLED
+    .disabled = 1,
+#else
+    .disabled = 0,
+#endif
+};
+
+int __init jffs2_zlib_init(void)
+{
+    int ret;
+
+    ret = alloc_workspaces();
+    if (ret)
+        return ret;
+
+    ret = jffs2_register_compressor(&jffs2_zlib_comp);
+    if (ret)
+        free_workspaces();
+
+    return ret;
+}
+
+void jffs2_zlib_exit(void)
+{
+    jffs2_unregister_compressor(&jffs2_zlib_comp);
+    free_workspaces();
+}
--- a/packages/fs/jffs2/current/src/erase.c
+++ b/packages/fs/jffs2/current/src/erase.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: erase.c,v 1.58 2003/11/26 13:02:46 dwmw2 Exp $
+ * $Id: erase.c,v 1.60 2004/06/30 17:26:15 dbrown Exp $
  *
  */
 
@@ -28,7 +28,7 @@ struct erase_priv_struct {
 #ifndef __ECOS
 static void jffs2_erase_callback(struct erase_info *);
 #endif
-static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
 static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
@@ -36,12 +36,14 @@ static void jffs2_mark_erased_block(stru
 void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
 	int ret;
+	uint32_t bad_offset;
 #ifdef __ECOS
        ret = jffs2_flash_erase(c, jeb);
        if (!ret) {
                jffs2_erase_succeeded(c, jeb);
                return;
        }
+       bad_offset = jeb->offset;
 #else /* Linux */
 	struct erase_info *instr;
 
@@ -65,18 +67,16 @@ void jffs2_erase_block(struct jffs2_sb_i
 	instr->len = c->sector_size;
 	instr->callback = jffs2_erase_callback;
 	instr->priv = (unsigned long)(&instr[1]);
+	instr->fail_addr = 0xffffffff;
 	
 	((struct erase_priv_struct *)instr->priv)->jeb = jeb;
 	((struct erase_priv_struct *)instr->priv)->c = c;
 
-	/* NAND , read out the fail counter, if possible */
-	if (!jffs2_can_mark_obsolete(c)) 
-		jffs2_nand_read_failcnt(c,jeb);
-		
 	ret = c->mtd->erase(c->mtd, instr);
 	if (!ret)
 		return;
 
+	bad_offset = instr->fail_addr;
 	kfree(instr);
 #endif /* __ECOS */
 
@@ -98,7 +98,7 @@ void jffs2_erase_block(struct jffs2_sb_i
 	else
 		printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret);
 
-	jffs2_erase_failed(c, jeb);
+	jffs2_erase_failed(c, jeb, bad_offset);
 }
 
 void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
@@ -166,16 +166,34 @@ static void jffs2_erase_succeeded(struct
 	jffs2_erase_pending_trigger(c);
 }
 
-static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset)
 {
-	 spin_lock(&c->erase_completion_lock);
-	 c->erasing_size -= c->sector_size;
-	 c->bad_size += c->sector_size;
-	 list_del(&jeb->list);
-	 list_add(&jeb->list, &c->bad_list);
-	 c->nr_erasing_blocks--;
-	 spin_unlock(&c->erase_completion_lock);
-	 wake_up(&c->erase_wait);
+	/* For NAND, if the failure did not occur at the device level for a
+	   specific physical page, don't bother updating the bad block table. */
+	if (jffs2_cleanmarker_oob(c) && (bad_offset != 0xffffffff)) {
+		/* We had a device-level failure to erase.  Let's see if we've
+		   failed too many times. */
+		if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) {
+			/* We'd like to give this block another try. */
+			spin_lock(&c->erase_completion_lock);
+			list_del(&jeb->list);
+			list_add(&jeb->list, &c->erase_pending_list);
+			c->erasing_size -= c->sector_size;
+			c->dirty_size += c->sector_size;
+			jeb->dirty_size = c->sector_size;
+			spin_unlock(&c->erase_completion_lock);
+			return;
+		}
+	}
+
+	spin_lock(&c->erase_completion_lock);
+	c->erasing_size -= c->sector_size;
+	c->bad_size += c->sector_size;
+	list_del(&jeb->list);
+	list_add(&jeb->list, &c->bad_list);
+	c->nr_erasing_blocks--;
+	spin_unlock(&c->erase_completion_lock);
+	wake_up(&c->erase_wait);
 }	 
 
 #ifndef __ECOS
@@ -185,7 +203,7 @@ static void jffs2_erase_callback(struct 
 
 	if(instr->state != MTD_ERASE_DONE) {
 		printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", instr->addr, instr->state);
-		jffs2_erase_failed(priv->c, priv->jeb);
+		jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr);
 	} else {
 		jffs2_erase_succeeded(priv->c, priv->jeb);
 	}	
@@ -289,6 +307,7 @@ static void jffs2_mark_erased_block(stru
 	unsigned char *ebuf;
 	size_t retlen;
 	int ret;
+	uint32_t bad_offset;
 
 	if (!jffs2_cleanmarker_oob(c)) {
 		marker_ref = jffs2_alloc_raw_node_ref();
@@ -313,6 +332,8 @@ static void jffs2_mark_erased_block(stru
 			uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
 			int i;
 
+			bad_offset = ofs;
+
 			ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
 			if (ret) {
 				printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
@@ -326,22 +347,21 @@ static void jffs2_mark_erased_block(stru
 				/* It's OK. We know it's properly aligned */
 				unsigned long datum = *(unsigned long *)(&ebuf[i]);
 				if (datum + 1) {
-					printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, ofs + i);
+					bad_offset += i;
+					printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset);
 				bad: 
 					if (!jffs2_cleanmarker_oob(c))
 						jffs2_free_raw_node_ref(marker_ref);
-					else 
-						jffs2_write_nand_badblock( c ,jeb );
 					kfree(ebuf);
 				bad2:
 					spin_lock(&c->erase_completion_lock);
-					c->erasing_size -= c->sector_size;
-					c->bad_size += c->sector_size;
-
-					list_add_tail(&jeb->list, &c->bad_list);
-					c->nr_erasing_blocks--;
+					/* Stick it on a list (any list) so
+					   erase_failed can take it right off
+					   again.  Silly, but shouldn't happen
+					   often. */
+					list_add(&jeb->list, &c->erasing_list);
 					spin_unlock(&c->erase_completion_lock);
-					wake_up(&c->erase_wait);
+					jffs2_erase_failed(c, jeb, bad_offset);
 					return;
 				}
 			}
@@ -350,7 +370,9 @@ static void jffs2_mark_erased_block(stru
 		}
 		kfree(ebuf);
 	}
-					
+
+	bad_offset = jeb->offset;
+
 	/* Write the erase complete marker */	
 	D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
 	if (jffs2_cleanmarker_oob(c)) {
--- a/packages/fs/jffs2/current/src/fs-ecos.c
+++ b/packages/fs/jffs2/current/src/fs-ecos.c
@@ -1420,7 +1420,7 @@ static int jffs2_fo_lseek(struct CYG_FIL
 
         // Check that pos is still within current file size, or at the
         // very end.
-        if (pos < 0 || pos > node->i_size)
+        if (pos < 0 )
                 return EINVAL;
 
 	// All OK, set fp offset and return new position.
--- a/packages/fs/jffs2/current/src/gc.c
+++ b/packages/fs/jffs2/current/src/gc.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: gc.c,v 1.133 2004/03/08 15:29:09 dwmw2 Exp $
+ * $Id: gc.c,v 1.137 2004/07/20 13:44:55 dwmw2 Exp $
  *
  */
 
@@ -19,6 +19,7 @@
 #include <linux/compiler.h>
 #include <linux/stat.h>
 #include "nodelist.h"
+#include "compr.h"
 
 static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, 
 					  struct jffs2_inode_cache *ic,
@@ -80,7 +81,7 @@ static struct jffs2_eraseblock *jffs2_fi
 		nextlist = &c->erasable_list;
 	} else {
 		/* Eep. All were empty */
-		printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n");
+		D1(printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n"));
 		return NULL;
 	}
 
@@ -204,7 +205,7 @@ int jffs2_garbage_collect_pass(struct jf
 		jeb = jffs2_find_gc_block(c);
 
 	if (!jeb) {
-		printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n");
+		D1 (printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"));
 		spin_unlock(&c->erase_completion_lock);
 		up(&c->alloc_sem);
 		return -EIO;
@@ -358,10 +359,14 @@ int jffs2_garbage_collect_pass(struct jf
 	spin_unlock(&c->inocache_lock);
 
 	f = jffs2_gc_fetch_inode(c, inum, nlink);
-	if (IS_ERR(f))
-		return PTR_ERR(f);
-	if (!f)
-		return 0;
+	if (IS_ERR(f)) {
+		ret = PTR_ERR(f);
+		goto release_sem;
+	}
+	if (!f) {
+		ret = 0;
+		goto release_sem;
+	}
 
 	ret = jffs2_garbage_collect_live(c, jeb, raw, f);
 
@@ -1176,7 +1181,7 @@ static int jffs2_garbage_collect_dnode(s
 	while(offset < orig_end) {
 		uint32_t datalen;
 		uint32_t cdatalen;
-		char comprtype = JFFS2_COMPR_NONE;
+		uint16_t comprtype = JFFS2_COMPR_NONE;
 
 		ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen);
 
@@ -1209,7 +1214,8 @@ static int jffs2_garbage_collect_dnode(s
 		ri.offset = cpu_to_je32(offset);
 		ri.csize = cpu_to_je32(cdatalen);
 		ri.dsize = cpu_to_je32(datalen);
-		ri.compr = comprtype;
+		ri.compr = comprtype & 0xff;
+		ri.usercompr = (comprtype >> 8) & 0xff;
 		ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
 		ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
 	
--- a/packages/fs/jffs2/current/src/nodelist.h
+++ b/packages/fs/jffs2/current/src/nodelist.h
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.h,v 1.116 2004/03/08 15:29:09 dwmw2 Exp $
+ * $Id: nodelist.h,v 1.119 2004/05/26 12:28:12 gleixner Exp $
  *
  */
 
@@ -44,6 +44,39 @@
 #define D2(x)
 #endif
 
+#define JFFS2_NATIVE_ENDIAN
+
+/* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from
+   whatever OS we're actually running on here too. */
+
+#if defined(JFFS2_NATIVE_ENDIAN)
+#define cpu_to_je16(x) ((jint16_t){x})
+#define cpu_to_je32(x) ((jint32_t){x})
+#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)})
+
+#define je16_to_cpu(x) ((x).v16)
+#define je32_to_cpu(x) ((x).v32)
+#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m))
+#elif defined(JFFS2_BIG_ENDIAN)
+#define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)})
+#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
+#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))})
+
+#define je16_to_cpu(x) (be16_to_cpu(x.v16))
+#define je32_to_cpu(x) (be32_to_cpu(x.v32))
+#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m)))
+#elif defined(JFFS2_LITTLE_ENDIAN)
+#define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)})
+#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
+#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))})
+
+#define je16_to_cpu(x) (le16_to_cpu(x.v16))
+#define je32_to_cpu(x) (le32_to_cpu(x.v32))
+#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m)))
+#else 
+#error wibble
+#endif
+
 /*
   This is all we need to keep in-core for each raw node during normal
   operation. As and when we do read_inode on a particular inode, we can
@@ -439,15 +472,6 @@ int jffs2_read_inode_range(struct jffs2_
 			   unsigned char *buf, uint32_t offset, uint32_t len);
 char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
 
-/* compr.c */
-unsigned char jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-			     unsigned char *data_in, unsigned char **cpage_out, 
-			     uint32_t *datalen, uint32_t *cdatalen);
-void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig);
-int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-		     unsigned char comprtype, unsigned char *cdata_in, 
-		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
-
 /* scan.c */
 int jffs2_scan_medium(struct jffs2_sb_info *c);
 void jffs2_rotate_lists(struct jffs2_sb_info *c);
@@ -465,11 +489,6 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_
 int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
 int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 #endif
 
-/* compr_zlib.c */
-int jffs2_zlib_init(void);
-void jffs2_zlib_exit(void);
-
 #endif /* __JFFS2_NODELIST_H__ */
--- a/packages/fs/jffs2/current/src/os-ecos.h
+++ b/packages/fs/jffs2/current/src/os-ecos.h
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: os-ecos.h,v 1.19 2003/11/28 11:38:45 dwmw2 Exp $
+ * $Id: os-ecos.h,v 1.20 2004/05/05 12:00:31 dwmw2 Exp $
  *
  */
 
@@ -191,8 +191,8 @@ static inline void jffs2_erase_pending_t
 #define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; })
 #define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; })
 #define jffs2_nand_read_failcnt(c,jeb) do { ; } while(0)
-#define jffs2_write_nand_badblock(c,jeb) do { ; } while(0)
-#define jffs2_nand_flash_setup(c) (0)
+#define jffs2_write_nand_badblock(c,jeb,p) (0)
+#define jffs2_flash_setup(c) (0)
 #define jffs2_nand_flash_cleanup(c) do {} while(0)
 #define jffs2_wbuf_dirty(c) (0)
 #define jffs2_flash_writev(a,b,c,d,e,f) jffs2_flash_direct_writev(a,b,c,d,e)
@@ -206,4 +206,6 @@ static inline void jffs2_erase_pending_t
 #define BUG_ON(x) do { if (unlikely(x)) BUG(); } while(0)
 #endif
 
+#define __init
+
 #endif /* __JFFS2_OS_ECOS_H__ */
--- a/packages/fs/jffs2/current/src/read.c
+++ b/packages/fs/jffs2/current/src/read.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: read.c,v 1.35 2004/03/08 15:29:09 dwmw2 Exp $
+ * $Id: read.c,v 1.36 2004/05/25 11:12:32 havasi Exp $
  *
  */
 
@@ -18,6 +18,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/compiler.h>
 #include "nodelist.h"
+#include "compr.h"
 
 int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 		     struct jffs2_full_dnode *fd, unsigned char *buf,
@@ -129,7 +130,7 @@ int jffs2_read_dnode(struct jffs2_sb_inf
 	if (ri->compr != JFFS2_COMPR_NONE) {
 		D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n",
 			  je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf)); 
-		ret = jffs2_decompress(c, f, ri->compr, readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
+		ret = jffs2_decompress(c, f, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
 		if (ret) {
 			printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret);
 			goto out_decomprbuf;
--- a/packages/fs/jffs2/current/src/scan.c
+++ b/packages/fs/jffs2/current/src/scan.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: scan.c,v 1.109 2004/03/19 16:40:50 dwmw2 Exp $
+ * $Id: scan.c,v 1.111 2004/07/27 14:13:43 gleixner Exp $
  *
  */
 #include <linux/kernel.h>
@@ -104,6 +104,10 @@ int jffs2_scan_medium(struct jffs2_sb_in
 		else
 			buf_size = PAGE_SIZE;
 
+		/* Respect kmalloc limitations */
+		if (buf_size > 128*1024)
+			buf_size = 128*1024;
+
 		D1(printk(KERN_DEBUG "Allocating readbuf of %d bytes\n", buf_size));
 		flashbuf = kmalloc(buf_size, GFP_KERNEL);
 		if (!flashbuf)
@@ -337,8 +341,6 @@ static int jffs2_scan_eraseblock (struct
 			switch (ret) {
 			case 0:		return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
 			case 1: 	return BLK_STATE_ALLDIRTY;
-			case 2: 	return BLK_STATE_BADBLOCK; /* case 2/3 are paranoia checks */
-			case 3:		return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */
 			default: 	return ret;
 			}
 		}
--- a/packages/fs/jffs2/current/src/write.c
+++ b/packages/fs/jffs2/current/src/write.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: write.c,v 1.83 2004/03/30 09:36:09 dwmw2 Exp $
+ * $Id: write.c,v 1.85 2004/07/13 08:58:25 dwmw2 Exp $
  *
  */
 
@@ -18,6 +18,7 @@
 #include <linux/pagemap.h>
 #include <linux/mtd/mtd.h>
 #include "nodelist.h"
+#include "compr.h"
 
 
 int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri)
@@ -91,7 +92,7 @@ struct jffs2_full_dnode *jffs2_write_dno
 	struct jffs2_raw_node_ref *raw;
 	struct jffs2_full_dnode *fn;
 	size_t retlen;
-	struct iovec vecs[2];
+	struct kvec vecs[2];
 	int ret;
 	int retried = 0;
 	unsigned long cnt = 2;
@@ -232,7 +233,7 @@ struct jffs2_full_dirent *jffs2_write_di
 	struct jffs2_raw_node_ref *raw;
 	struct jffs2_full_dirent *fd;
 	size_t retlen;
-	struct iovec vecs[2];
+	struct kvec vecs[2];
 	int retried = 0;
 	int ret;
 
@@ -358,7 +359,7 @@ int jffs2_write_inode_range(struct jffs2
 	while(writelen) {
 		struct jffs2_full_dnode *fn;
 		unsigned char *comprbuf = NULL;
-		unsigned char comprtype = JFFS2_COMPR_NONE;
+		uint16_t comprtype = JFFS2_COMPR_NONE;
 		uint32_t phys_ofs, alloclen;
 		uint32_t datalen, cdatalen;
 		int retried = 0;
@@ -388,7 +389,8 @@ int jffs2_write_inode_range(struct jffs2
 		ri->offset = cpu_to_je32(offset);
 		ri->csize = cpu_to_je32(cdatalen);
 		ri->dsize = cpu_to_je32(datalen);
-		ri->compr = comprtype;
+		ri->compr = comprtype & 0xff;
+		ri->usercompr = (comprtype >> 8 ) & 0xff;
 		ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
 		ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));