[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: BBC patch



Hi,

Here is the patch for mkfs.jffs2. Now the compr.c and compr.h are 
completly separated from the kernel space version. Without usage of 
extra parameters it produces exactly the same image as the old 
mkfs.jffs2. The documentations of new swithces are in the manual page.

I resend the bbc core patch too, becauseof some cleanups.

BR,
Ferenc

diff --unified --recursive --new-file mtd/util/Makefile mtd-new-7/util/Makefile
--- mtd/util/Makefile	2004-05-05 23:32:06.000000000 +0200
+++ mtd-new-7/util/Makefile	2004-05-10 17:01:47.000000000 +0200
@@ -32,7 +32,7 @@
 clean:
 	rm -f *.o $(TARGETS) .*.c.dep
 
-mkfs.jffs2: crc32.o compr_rtime.o mkfs.jffs2.o compr_zlib.o
+mkfs.jffs2: crc32.o compr_rtime.o mkfs.jffs2.o compr_zlib.o compr.o
 	$(CC) $(LDFLAGS) -o $@ $^ -lz
 
 flash_eraseall: crc32.o flash_eraseall.o
diff --unified --recursive --new-file mtd/util/compr.c mtd-new-7/util/compr.c
--- mtd/util/compr.c	1970-01-01 01:00:00.000000000 +0100
+++ mtd-new-7/util/compr.c	2004-05-10 17:58:26.000000000 +0200
@@ -0,0 +1,420 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by Ferenc Havasi <havasi@xxxxxxx.hu>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory
+ * in the jffs2 directory.
+ *
+ * $Id$
+ *
+ */
+
+#include "compr.h"
+#include <string.h>
+#include <stdlib.h>
+#include <linux/jffs2.h>
+
+#define MALLOC(a)              malloc(a)
+#define FREE(a)                free(a)
+
+/* 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)
+
+static inline void __list_add(struct list_head *new,
+                              struct list_head *prev,
+                              struct list_head *next)
+{
+        next->prev = new;
+        new->next = next;
+        new->prev = prev;
+        prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+        __list_add(new, head, head->next);
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+        __list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+        next->prev = prev;
+        prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+        __list_del(entry->prev, entry->next);
+        entry->next = (void *) 0;
+        entry->prev = (void *) 0;
+}
+
+#define list_entry(ptr, type, member) \
+        ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#define list_for_each_entry(pos, head, member)                          \
+        for (pos = list_entry((head)->next, typeof(*pos), member);      \
+             &pos->member != (head);                                    \
+             pos = list_entry(pos->member.next, typeof(*pos), member))
+
+
+/* Available compressors are on this list */
+static LIST_HEAD(jffs2_compressor_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;
+}
+
+
+/* Statistics for blocks stored without compression */
+static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
+
+static int jffs2_compression_check = 0;
+
+static unsigned char *jffs2_compression_check_buf = NULL;
+
+void jffs2_compression_check_set(int yesno)
+{
+        jffs2_compression_check = yesno;
+}
+
+extern int page_size;
+
+/* 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 i;
+
+        if (!jffs2_compression_check_buf) {
+                jffs2_compression_check_buf = MALLOC(page_size);
+                if (!jffs2_compression_check_buf) {
+                        fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n");
+                        jffs2_compression_check = 0;
+                        return;
+                }
+        }
+        if (!compr->decompress) {
+                fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name);
+                return;
+        }
+        if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen)) {
+                fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name);
+        }
+        else {
+                for (i=0;i<datalen;i++) {
+                        if (data_in[i]!=jffs2_compression_check_buf[i]) {
+                                fprintf(stderr,"JFFS2 compression check: data mismatch at %s (pos %d).\n", compr->name, i);
+                                break;
+                        }
+                }
+        }
+}
+
+/* jffs2_compress:
+ * @data: Pointer to uncompressed data
+ * @cdata: Pointer to returned pointer to buffer for compressed data
+ * @xxxxxxx.
+ *	On exit, expected to hold the amount of data actually compressed.
+ * @cdatalen: On entry, holds the amount of space available for compressed
+ *	data. On exit, expected to hold the actual size of the compressed
+ *	data.
+ *
+ * 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.
+ */
+uint16_t jffs2_compress( unsigned char *data_in, unsigned char **cpage_out,
+			 uint32_t *datalen, uint32_t *cdatalen)
+{
+	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;
+
+        switch (jffs2_compression_mode) {
+        case JFFS2_COMPR_MODE_NONE:
+                break;
+        case JFFS2_COMPR_MODE_PRIORITY:
+                output_buf = MALLOC(*cdatalen);
+                if (!output_buf) {
+                        fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. Compression failed.\n");
+                        goto out;
+                }
+                orig_slen = *datalen;
+                orig_dlen = *cdatalen;
+                list_for_each_entry(this, &jffs2_compressor_list, list) {
+                        /* Skip decompress-only backwards-compatibility and disabled modules */
+                        if ((!this->compress)||(this->disabled))
+                                continue;
+
+                        this->usecount++;
+                        *datalen  = orig_slen;
+                        *cdatalen = orig_dlen;
+                        compr_ret = this->compress(data_in, output_buf, datalen, cdatalen);
+                        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);
+                                break;
+                        }
+                }
+                break;
+        case JFFS2_COMPR_MODE_SIZE:
+                orig_slen = *datalen;
+                orig_dlen = *cdatalen;
+                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)) {
+                                FREE(this->compr_buf);
+                                this->compr_buf_size=0;
+                                this->compr_buf=NULL;
+                        }
+                        if (!this->compr_buf) {
+                                tmp_buf = MALLOC(orig_dlen);
+                                if (!tmp_buf) {
+                                        fprintf(stderr,"mkfs.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++;
+                        *datalen  = orig_slen;
+                        *cdatalen = orig_dlen;
+                        compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
+                        this->usecount--;
+                        if (!compr_ret) {
+                                if (jffs2_compression_check)
+                                    jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen);
+                                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;
+                }
+                break;
+        default:
+                fprintf(stderr,"mkfs.jffs2: unknow compression mode.\n");
+        }
+ out:
+        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_register_compressor(struct jffs2_compressor *comp)
+{
+        struct jffs2_compressor *this;
+
+        if (!comp->name) {
+                fprintf(stderr,"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;
+
+        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:
+        return 0;
+}
+
+int jffs2_unregister_compressor(struct jffs2_compressor *comp)
+{
+
+        if (comp->usecount) {
+                fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n");
+                return -1;
+        }
+        list_del(&comp->list);
+
+        return 0;
+}
+
+#define JFFS2_STAT_BUF_SIZE 16000
+
+char *jffs2_list_compressors(void)
+{
+        struct jffs2_compressor *this;
+        char *buf, *act_buf;
+
+        act_buf = buf = MALLOC(JFFS2_STAT_BUF_SIZE);
+        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 = 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,"\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, 
+                           none_stat_compr_size, none_stat_decompr_blocks);
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                act_buf += sprintf(act_buf,"%10s (prio:%d) ",this->name,this->priority);
+                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");
+        }
+        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_compressors_init(void) 
+{
+#ifdef CONFIG_JFFS2_ZLIB
+        jffs2_zlib_init();
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+        jffs2_rtime_init();
+#endif
+        return 0;
+}
+
+int jffs2_compressors_exit(void) 
+{
+#ifdef CONFIG_JFFS2_RTIME
+        jffs2_rtime_exit();
+#endif
+#ifdef CONFIG_JFFS2_ZLIB
+        jffs2_zlib_exit();
+#endif
+        return 0;
+}
diff --unified --recursive --new-file mtd/util/compr.h mtd-new-7/util/compr.h
--- mtd/util/compr.h	1970-01-01 01:00:00.000000000 +0100
+++ mtd-new-7/util/compr.h	2004-05-10 17:58:46.000000000 +0200
@@ -0,0 +1,93 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by Ferenc Havasi <havasi@xxxxxxx.hu>
+ *
+ * For licensing information, see the file 'LICENCE' in the 
+ * jffs2 directory.
+ *
+ * $Id$
+ *
+ */
+
+#ifndef __JFFS2_COMPR_H__
+#define __JFFS2_COMPR_H__
+
+#include <stdio.h>
+#include <stdint.h>
+#include "linux/jffs2.h"
+
+/* Configuration */
+
+#define CONFIG_JFFS2_ZLIB
+#define CONFIG_JFFS2_RTIME
+
+#define JFFS2_RUBINMIPS_PRIORITY 10
+#define JFFS2_DYNRUBIN_PRIORITY  20
+#define JFFS2_RTIME_PRIORITY     50
+#define JFFS2_ZLIB_PRIORITY      60
+
+#define JFFS2_COMPR_MODE_NONE       0
+#define JFFS2_COMPR_MODE_PRIORITY   1
+#define JFFS2_COMPR_MODE_SIZE       2
+
+struct list_head {
+        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);
+
+struct jffs2_compressor {
+        struct list_head list;
+        int priority;             /* used by prirority comr. mode */
+        char *name;
+        char compr;               /* JFFS2_COMPR_XXX */
+        int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
+                        uint32_t *srclen, uint32_t *destlen);
+        int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
+                        uint32_t cdatalen, uint32_t datalen);
+        int usecount;
+        int disabled;             /* if seted the compressor won't compress */
+        unsigned char *compr_buf; /* used by size compr. mode */
+        uint32_t compr_buf_size;  /* used by size compr. mode */
+        uint32_t stat_compr_orig_size;
+        uint32_t stat_compr_new_size;
+        uint32_t stat_compr_blocks;
+        uint32_t stat_decompr_blocks;
+};
+
+int jffs2_register_compressor(struct jffs2_compressor *comp);
+int jffs2_unregister_compressor(struct jffs2_compressor *comp);
+
+int jffs2_compressors_init(void);
+int jffs2_compressors_exit(void);
+
+uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out,
+                             uint32_t *datalen, uint32_t *cdatalen);
+
+/* If it is setted, a decompress will be called after every compress */
+void jffs2_compression_check_set(int yesno);
+
+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
+
+#endif /* __JFFS2_COMPR_H__ */
diff --unified --recursive --new-file mtd/util/compr_rtime.c mtd-new-7/util/compr_rtime.c
--- mtd/util/compr_rtime.c	2004-05-05 13:57:54.000000000 +0200
+++ mtd-new-7/util/compr_rtime.c	2004-05-10 17:09:27.000000000 +0200
@@ -23,9 +23,10 @@
 
 #include <stdint.h>
 #include <string.h>
+#include "compr.h"
 
 /* _compress returns the compressed size, -1 if bigger */
-int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, 
+static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, 
 		   uint32_t *sourcelen, uint32_t *dstlen)
 {
 	short positions[256];
@@ -65,7 +66,7 @@
 }		   
 
 
-void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
+static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
 		      uint32_t srclen, uint32_t destlen)
 {
 	short positions[256];
@@ -96,7 +97,26 @@
 				outpos+=repeat;		
 			}
 		}
-	}		
+	}
+        return 0;
 }		   
 
 
+static struct jffs2_compressor jffs2_rtime_comp = {
+    .priority = JFFS2_RTIME_PRIORITY,
+    .name = "rtime",
+    .disabled = 0,
+    .compr = JFFS2_COMPR_RTIME,
+    .compress = &jffs2_rtime_compress,
+    .decompress = &jffs2_rtime_decompress,
+};
+
+int jffs2_rtime_init(void)
+{
+    return jffs2_register_compressor(&jffs2_rtime_comp);
+}
+
+void jffs2_rtime_exit(void)
+{
+    jffs2_unregister_compressor(&jffs2_rtime_comp);
+}
diff --unified --recursive --new-file mtd/util/compr_zlib.c mtd-new-7/util/compr_zlib.c
--- mtd/util/compr_zlib.c	2002-03-03 17:14:24.000000000 +0100
+++ mtd-new-7/util/compr_zlib.c	2004-05-10 16:53:00.000000000 +0200
@@ -39,6 +39,8 @@
 #include <zlib.h>
 #include <stdio.h>
 #include <asm/types.h>
+#include <linux/jffs2.h>
+#include "compr.h"
 
 #define min(x,y) ((x)<(y)?(x):(y))
 
@@ -99,7 +101,7 @@
 	return 0;
 }
 
-void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
 		      uint32_t srclen, uint32_t destlen)
 {
 	z_stream strm;
@@ -109,7 +111,7 @@
 	strm.zfree = (void *)0;
 
 	if (Z_OK != inflateInit(&strm)) {
-		return;
+		return 1;
 	}
 	strm.next_in = data_in;
 	strm.avail_in = srclen;
@@ -123,4 +125,24 @@
 		;
 
 	inflateEnd(&strm);
+        return 0;
+}
+
+static struct jffs2_compressor jffs2_zlib_comp = {
+    .priority = JFFS2_ZLIB_PRIORITY,
+    .name = "zlib",
+    .disabled = 0,
+    .compr = JFFS2_COMPR_ZLIB,
+    .compress = &jffs2_zlib_compress,
+    .decompress = &jffs2_zlib_decompress,
+};
+
+int jffs2_zlib_init(void)
+{
+    return jffs2_register_compressor(&jffs2_zlib_comp);
+}
+
+void jffs2_zlib_exit(void)
+{
+    jffs2_unregister_compressor(&jffs2_zlib_comp);
 }
diff --unified --recursive --new-file mtd/util/mkfs.jffs2.1 mtd-new-7/util/mkfs.jffs2.1
--- mtd/util/mkfs.jffs2.1	2003-01-12 16:41:23.000000000 +0100
+++ mtd-new-7/util/mkfs.jffs2.1	2004-05-10 16:27:03.000000000 +0200
@@ -49,6 +49,21 @@
 .B -P,--squash-perms
 ]
 [
+.B -m,--compression-mode=MODE
+]
+[
+.B -x,--disable-compressor=NAME
+]
+[
+.B -X,--enable-compressor=NAME
+]
+[
+.B -L,--list-compressors
+]
+[
+.B -t,--test-compression
+]
+[
 .B -h,--help
 ]
 [
@@ -73,10 +88,9 @@
 .B -r
 option is not specified.
 
-Files to be placed into the file system image are compressed
-using the
-.B zlib
-compression library.
+Each block of the files to be placed into the file system image 
+are compressed using one of the avaiable compressors depending
+on the selected compression mode.
 
 File systems are created with the same endianness as the host,
 unless the
@@ -156,6 +170,32 @@
 .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. Other alternatives are:
+.B none
+(mkfs will not compress) and
+.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 -L, --list-compressors
+Show the list of the avaiable compressors and their states.
+.TP
+.B -t, --test-compression
+Call decompress after every compress - and compare the result with the original data.
+.TP
 .B -h, --help
 Display help text.
 .TP
diff --unified --recursive --new-file mtd/util/mkfs.jffs2.c mtd-new-7/util/mkfs.jffs2.c
--- mtd/util/mkfs.jffs2.c	2004-05-05 13:57:55.000000000 +0200
+++ mtd-new-7/util/mkfs.jffs2.c	2004-05-10 17:25:38.000000000 +0200
@@ -661,29 +661,12 @@
 	{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xff, 0xff, 0xff
 };
+
 /* We default to 4096, per x86.  When building a fs for 
  * 64-bit arches and whatnot, use the --pagesize=SIZE option */
-static int page_size = 4096;
-
-extern int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-extern int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
+int page_size = 4096;
 
-unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, 
-		    uint32_t *datalen, uint32_t *cdatalen)
-{
-	int ret;
-
-	ret = jffs2_zlib_compress(data_in, cpage_out, datalen, cdatalen);
-	if (!ret) {
-		return JFFS2_COMPR_ZLIB;
-	}
-	/* rtime does manage to recompress already-compressed data */
-	ret = jffs2_rtime_compress(data_in, cpage_out, datalen, cdatalen);
-	if (!ret) {
-		return JFFS2_COMPR_RTIME;
-	}
-	return JFFS2_COMPR_NONE; /* We failed to compress */
-}
+#include "compr.h"
 
 static void full_write(int fd, const void *buf, int len)
 {
@@ -811,7 +794,7 @@
 	write_dirent(e);
 
 	buf = xmalloc(page_size);
-	cbuf = xmalloc(page_size);
+	cbuf = NULL;
 
 	ver = 0;
 	offset = 0;
@@ -838,7 +821,8 @@
 
 		while (len) {
 			uint32_t dsize, space;
-
+                        uint16_t compression;
+                        
 			pad_block_if_less_than(sizeof(ri) + JFFS2_MIN_DATA_LEN);
 
 			dsize = len;
@@ -848,7 +832,9 @@
 			if (space > dsize)
 				space = dsize;
 
-			ri.compr = jffs2_compress(tbuf, cbuf, &dsize, &space);
+			compression = jffs2_compress(tbuf, &cbuf, &dsize, &space);
+                        ri.compr = compression & 0xff;
+                        ri.usercompr = (compression >> 8) & 0xff;
 			if (ri.compr) {
 				wbuf = cbuf;
 			} else {
@@ -874,6 +860,8 @@
 			tbuf += dsize;
 			len -= dsize;
 			offset += dsize;
+
+                        if (tbuf!=cbuf) if (!cbuf) free(cbuf);
 		}
 	}
 	if (!je32_to_cpu(ri.version)) {
@@ -892,7 +880,6 @@
 		padword();
 	}
 	free(buf);
-	free(cbuf);
 	close(fd);
 }
 
@@ -1165,6 +1152,9 @@
 	{"squash-perms", 0, NULL, 'P'},
 	{"faketime", 0, NULL, 'f'},
 	{"devtable", 1, NULL, 'D'},
+	{"compression-mode", 1, NULL, 'm'},
+	{"disable-compressor", 1, NULL, 'x'},
+	{"test-compression", 0, NULL, 't'},
 	{NULL, 0, NULL, 0}
 };
 
@@ -1172,25 +1162,30 @@
 	"Usage: mkfs.jffs2 [OPTIONS]\n"
 	"Make a JFFS2 file system image from an existing directory tree\n\n"
 	"Options:\n"
-	"  -p, --pad[=SIZE]       Pad output to SIZE bytes with 0xFF. If SIZE is\n"
-	"                         not specified, the output is padded to the end of\n"
-	"                         the final erase block\n"
-	"  -r, -d, --root=DIR     Build file system from directory DIR (default: cwd)\n"
-	"  -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"
-	"  -n, --no-cleanmarkers  Don't add a cleanmarker to every eraseblock\n"
-	"  -o, --output=FILE      Output to FILE (default: stdout)\n"
-	"  -l, --little-endian    Create a little-endian filesystem\n"
-	"  -b, --big-endian       Create a big-endian filesystem\n"
-	"  -D, --devtable=FILE    Use the named FILE as a device table file\n"
-	"  -f, --faketime         Change all file times to '0' for regression testing\n"
-	"  -q, --squash           Squash permissions and owners making all files be owned by root\n"
-	"  -U, --squash-uids      Squash owners making all files be owned by root\n"
-	"  -P, --squash-perms     Squash permissions on all files\n"
-	"  -h, --help             Display this help text\n"
-	"  -v, --verbose          Verbose operation\n"
-	"  -V, --version          Display version information\n\n";
+	"  -p, --pad[=SIZE]         Pad output to SIZE bytes with 0xFF. If SIZE is\n"
+	"                           not specified, the output is padded to the end of\n"
+	"                           the final erase block\n"
+	"  -r, -d, --root=DIR       Build file system from directory DIR (default: cwd)\n"
+	"  -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, --compression-mode   Select compression mode (default: priortiry)\n"
+	"  -x, --disable-compressor Disable a compressor\n"
+	"  -X, --enable-compressor  Enable a compressor\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"
+	"  -o, --output=FILE        Output to FILE (default: stdout)\n"
+	"  -l, --little-endian      Create a little-endian filesystem\n"
+	"  -b, --big-endian         Create a big-endian filesystem\n"
+	"  -D, --devtable=FILE      Use the named FILE as a device table file\n"
+	"  -f, --faketime           Change all file times to '0' for regression testing\n"
+	"  -q, --squash             Squash permissions and owners making all files be owned by root\n"
+	"  -U, --squash-uids        Squash owners making all files be owned by root\n"
+	"  -P, --squash-perms       Squash permissions on all files\n"
+	"  -h, --help               Display this help text\n"
+	"  -v, --verbose            Verbose operation\n"
+	"  -V, --version            Display version information\n\n";
 
 
 static char *revtext = "$Revision: 1.41 $";
@@ -1203,8 +1198,10 @@
 	FILE *devtable = NULL;
 	struct filesystem_entry *root;
 
+        jffs2_compressors_init();
+
 	while ((opt = getopt_long(argc, argv, 
-					"D:d:r:s:o:qUPfh?vVe:lbp::nc:", long_options, &c)) >= 0) 
+					"D:d:r:s:o:qUPfh?vVe:lbp::nc:m:x:X:Lt", long_options, &c)) >= 0) 
 	{
 		switch (opt) {
 			case 'D':
@@ -1324,6 +1321,27 @@
 					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);
+				}
+                                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;
 		}
 	}
 	if (out_fd == -1) {
@@ -1354,5 +1372,14 @@
 		free(rootdir);
 
 	close(out_fd);
+
+        if (verbose) {
+                char *s = jffs2_stats();
+                fprintf(stderr,"\n\n%s",s);
+                free(s);
+        }
+
+        jffs2_compressors_exit();
+
 	return 0;
 }
diff --unified --recursive --new-file mtd/fs/Config.in mtd-new-8/fs/Config.in
--- mtd/fs/Config.in	2002-11-26 23:25:55.000000000 +0100
+++ mtd-new-8/fs/Config.in	2004-05-10 18:24:34.000000000 +0200
@@ -7,4 +7,12 @@
 if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFIG_JFFS2_FS" = "m" ] ; then
    int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0
    bool 'JFFS2 support for NAND chips' CONFIG_JFFS2_FS_NAND
+   bool 'ZLIB compression support (recommended)' CONFIG_JFFS2_ZLIB
+   bool 'RTIME compression support (recommended)' CONFIG_JFFS2_RTIME
+   bool 'RUBIN compression support' CONFIG_JFFS2_RUBIN
+   
+   choice 'Default JFFS2 compression mode' \
+        "none                                   CONFIG_JFFS2_CMODE_NONE \
+         priority                               CONFIG_JFFS2_CMODE_PRIORITY \
+         size                                   CONFIG_JFFS2_CMODE_SIZE" priority
 fi
diff --unified --recursive --new-file mtd/fs/Kconfig mtd-new-8/fs/Kconfig
--- mtd/fs/Kconfig	2002-11-26 23:25:55.000000000 +0100
+++ mtd-new-8/fs/Kconfig	2004-05-10 18:25:54.000000000 +0200
@@ -66,3 +66,56 @@
 
 	  Say 'N' unless you have NAND flash and you are willing to test and
 	  develop JFFS2 support for it.
+
+config JFFS2_ZLIB
+	bool "ZLIB compression support"
+	depends on JFFS2_FS
+	default y
+        help
+          Zlib is designed to be a free, general-purpose, legally unencumbered,
+          lossless data-compression library for use on virtually any computer 
+          hardware and operating system. See http://www.gzip.org/zlib/ for
+          further information.
+          
+          Say 'Y' if unsure.
+
+config JFFS2_RTIME
+	bool "RTIME compression support"
+	depends on JFFS2_FS
+	default y
+        help
+          Rtime does manage to recompress already-compressed data. Say 'Y' if unsure.
+
+config JFFS2_RUBIN
+	bool "RUBIN compression support"
+	depends on JFFS2_FS
+	default n
+        help
+          RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
+
+choice
+        prompt "Default compression mode"
+        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
diff --unified --recursive --new-file mtd/fs/jffs2/Makefile.common mtd-new-8/fs/jffs2/Makefile.common
--- mtd/fs/jffs2/Makefile.common	2003-05-27 11:34:41.000000000 +0200
+++ mtd-new-8/fs/jffs2/Makefile.common	2004-05-10 17:38:18.000000000 +0200
@@ -12,8 +12,10 @@
 
 obj-$(CONFIG_JFFS2_FS) := jffs2.o
 
-COMPR_OBJS	:= compr.o compr_rubin.o compr_rtime.o compr_zlib.o
-JFFS2_OBJS	:= dir.o file.o ioctl.o nodelist.o malloc.o \
+JRUBIN_OBJS-$(CONFIG_JFFS2_RUBIN) := compr_rubin.o
+JRTIME_OBJS-$(CONFIG_JFFS2_RTIME) := compr_rtime.o
+JZLIB_OBJS-$(CONFIG_JFFS2_ZLIB)  := compr_zlib.o
+JFFS2_OBJS	:= compr.o dir.o file.o ioctl.o nodelist.o malloc.o \
 	read.o nodemgmt.o readinode.o write.o scan.o gc.o \
 	symlink.o build.o erase.o background.o fs.o writev.o
 
@@ -28,8 +30,7 @@
 NAND_OBJS-$(CONFIG_JFFS2_FS_NAND)	:= wbuf.o
 
 jffs2-objs := $(COMPR_OBJS) $(JFFS2_OBJS) $(VERS_OBJS) $(NAND_OBJS-y) \
-	$(LINUX_OBJS)
-
+	$(LINUX_OBJS) $(JRUBIN_OBJS-y) $(JRTIME_OBJS-y) $(JZLIB_OBJS-y)
 
 # 2.4 build compatibility
 ifeq ($(BELOW25),y)
@@ -37,4 +38,3 @@
 O_TARGET := jffs2.o
 include $(TOPDIR)/Rules.make
 endif
-
diff --unified --recursive --new-file mtd/fs/jffs2/compr.c mtd-new-8/fs/jffs2/compr.c
--- mtd/fs/jffs2/compr.c	2004-03-08 16:29:09.000000000 +0100
+++ mtd-new-8/fs/jffs2/compr.c	2004-05-10 19:01:17.000000000 +0200
@@ -5,29 +5,41 @@
  *
  * Created by Arjan van de Ven <arjanv@xxxxxxx.com>
  *
+ * Compressor interface by Ferenc Havasi <havasi@xxxxxxx.hu>
+ *
  * 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$
  *
  */
 
-#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"
-
-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);
+#include "compr.h"
+
+#define MALLOC(a)              kmalloc(a,GFP_KERNEL)
+#define FREE(a)                kfree(a)
+#define COMPRESSOR_LIST_LOCK   spin_lock(&jffs2_compressor_list_lock)
+#define COMPRESSOR_LIST_UNLOCK spin_unlock(&jffs2_compressor_list_lock)
+
+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;
+
+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 +50,385 @@
  *	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 = MALLOC(*cdatalen);
+                if (!output_buf) {
+                        printk("JFFS2: No memory for compressor allocation. Compression failed.\n");
+                        goto out;
+                }
+                orig_slen = *datalen;
+                orig_dlen = *cdatalen;
+                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++;
+                        COMPRESSOR_LIST_UNLOCK;
+                        *datalen  = orig_slen;
+                        *cdatalen = orig_dlen;
+                        compr_ret = this->compress(data_in, output_buf, datalen, cdatalen);
+                        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;
+                        }
+                }
+                COMPRESSOR_LIST_UNLOCK;
+                break;
+        case JFFS2_COMPR_MODE_SIZE:
+                orig_slen = *datalen;
+                orig_dlen = *cdatalen;
+                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)) {
+                                COMPRESSOR_LIST_UNLOCK;
+                                FREE(this->compr_buf);
+                                COMPRESSOR_LIST_LOCK;
+                                this->compr_buf_size=0;
+                                this->compr_buf=NULL;
+                        }
+                        if (!this->compr_buf) {
+                                COMPRESSOR_LIST_UNLOCK;
+                                tmp_buf = MALLOC(orig_dlen);
+                                COMPRESSOR_LIST_LOCK;
+                                if (!tmp_buf) {
+                                        printk("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++;
+                        COMPRESSOR_LIST_UNLOCK;
+                        *datalen  = orig_slen;
+                        *cdatalen = orig_dlen;
+                        compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
+                        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;
+                }
+                COMPRESSOR_LIST_UNLOCK;
+                break;
+        default:
+                printk("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;
+	default:
+                COMPRESSOR_LIST_LOCK;
+                list_for_each_entry(this, &jffs2_compressor_list, list) {
+                        if (comprtype == this->compr) {
+                                this->usecount++;
+                                COMPRESSOR_LIST_UNLOCK;
+                                ret = this->decompress(cdata_in, data_out, cdatalen, datalen);
+                                COMPRESSOR_LIST_LOCK;
+                                if (ret) {
+                                        printk("Decompressor \"%s\" returned %d\n", this->name, ret);
+                                }
+                                else {
+                                        this->stat_decompr_blocks++;
+                                }
+                                this->usecount--;
+                                COMPRESSOR_LIST_UNLOCK;
+                                return ret;
+                        }
+                }
+		printk("JFFS2 compression type 0x%02x not avaiable.\n", comprtype);
+                COMPRESSOR_LIST_UNLOCK;
+		return -EIO;
+	}
+	return 0;
+}
+
+int jffs2_register_compressor(struct jffs2_compressor *comp)
+{
+        struct jffs2_compressor *this;
+
+        if (!comp->name) {
+                printk("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("Registering JFFS2 compressor \"%s\"\n", comp->name));
+
+        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("Compressor \"%s\", prio %d\n", this->name, this->priority);
+        })
+
+        COMPRESSOR_LIST_UNLOCK;
+
+        return 0;
+}
+
+int jffs2_unregister_compressor(struct jffs2_compressor *comp)
+{
+        D2(struct jffs2_compressor *this;)
+
+        D1(printk("Unregistering JFFS2 compressor \"%s\"\n", comp->name));
+
+        COMPRESSOR_LIST_LOCK;
+
+        if (comp->usecount) {
+                COMPRESSOR_LIST_UNLOCK;
+                printk("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("Compressor \"%s\", prio %d\n", this->name, this->priority);
+        })
+        COMPRESSOR_LIST_UNLOCK;
+        return 0;
+}
+
+/* proc interface supporter functions - they are not in use yet */
+
+#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 = MALLOC(JFFS2_STAT_BUF_SIZE);
+        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 = 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,"\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, 
+                           none_stat_compr_size, none_stat_decompr_blocks);
+        COMPRESSOR_LIST_LOCK;
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                act_buf += sprintf(act_buf,"%10s (prio:%d) ",this->name,this->priority);
+                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");
+        }
+        COMPRESSOR_LIST_UNLOCK;
+        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;
+        COMPRESSOR_LIST_LOCK;
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                if (!strcmp(this->name, name)) {
+                        this->disabled = disabled;
+                        COMPRESSOR_LIST_UNLOCK;
+                        return 0;                        
+                }
+        }
+        COMPRESSOR_LIST_UNLOCK;
+        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);
+}
+
 #endif
-#ifdef JFFS2_USE_RTIME
-	case JFFS2_COMPR_RTIME:
-		jffs2_rtime_decompress(cdata_in, data_out, cdatalen, datalen);
-		break;
+
+void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
+{
+        if (orig != comprbuf)
+                FREE(comprbuf);
+}
+
+int jffs2_compressors_init(void) 
+{
+#ifdef CONFIG_JFFS2_ZLIB
+        jffs2_zlib_init();
 #endif
-#ifdef JFFS2_USE_RUBINMIPS
-	case JFFS2_COMPR_RUBINMIPS:
-		jffs2_rubinmips_decompress(cdata_in, data_out, cdatalen, datalen);
-		break;
+#ifdef CONFIG_JFFS2_RTIME
+        jffs2_rtime_init();
+#endif
+#ifdef CONFIG_JFFS2_RUBIN
+        jffs2_rubinmips_init();
+        jffs2_dynrubin_init();
 #endif
-#ifdef JFFS2_USE_DYNRUBIN
-	case JFFS2_COMPR_DYNRUBIN:
+#ifdef CONFIG_JFFS2_CMODE_NONE
+        jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+        D1(printk("JFFS2: default compression mode: none\n");)
+#else
+#ifdef CONFIG_JFFS2_CMODE_SIZE
+        jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
+        D1(printk("JFFS2: default compression mode: size\n");)
+#else
+        D1(printk("JFFS2: default compression mode: priority\n");)
+#endif
+#endif
+        return 0;
+}
 
-		jffs2_dynrubin_decompress(cdata_in, data_out, cdatalen, datalen);
-		break;
+int jffs2_compressors_exit(void) 
+{
+#ifdef CONFIG_JFFS2_RUBIN
+        jffs2_dynrubin_exit();
+        jffs2_rubinmips_exit();
 #endif
-	default:
-		printk(KERN_NOTICE "Unknown JFFS2 compression type 0x%02x\n", comprtype);
-		return -EIO;
-	}
-	return 0;
+#ifdef CONFIG_JFFS2_RTIME
+        jffs2_rtime_exit();
+#endif
+#ifdef CONFIG_JFFS2_ZLIB
+        jffs2_zlib_exit();
+#endif
+        return 0;
 }
diff --unified --recursive --new-file mtd/fs/jffs2/compr.h mtd-new-8/fs/jffs2/compr.h
--- mtd/fs/jffs2/compr.h	1970-01-01 01:00:00.000000000 +0100
+++ mtd-new-8/fs/jffs2/compr.h	2004-05-10 18:24:00.000000000 +0200
@@ -0,0 +1,109 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by Ferenc Havasi <havasi@xxxxxxx.hu>
+ *
+ * For licensing information, see the file 'LICENCE' in the 
+ * jffs2 directory.
+ *
+ * $Id$
+ *
+ */
+
+#ifndef __JFFS2_COMPR_H__
+#define __JFFS2_COMPR_H__
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/jffs2.h>
+#include <linux/jffs2_fs_i.h>
+#include <linux/jffs2_fs_sb.h>
+#include "nodelist.h"
+
+#define JFFS2_RUBINMIPS_PRIORITY 10
+#define JFFS2_DYNRUBIN_PRIORITY  20
+#define JFFS2_RTIME_PRIORITY     50
+#define JFFS2_ZLIB_PRIORITY      60
+
+#define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
+#define JFFS2_DYNRUBIN_DISABLED  /*        for decompression */
+
+#define JFFS2_COMPR_MODE_NONE       0
+#define JFFS2_COMPR_MODE_PRIORITY   1
+#define JFFS2_COMPR_MODE_SIZE       2
+
+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);
+
+struct jffs2_compressor {
+        struct list_head list;
+        int priority;             /* used by prirority comr. mode */
+        char *name;
+        char compr;               /* JFFS2_COMPR_XXX */
+        int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
+                        uint32_t *srclen, uint32_t *destlen);
+        int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
+                        uint32_t cdatalen, uint32_t datalen);
+        int usecount;
+        int disabled;             /* if seted the compressor won't compress */
+        unsigned char *compr_buf; /* used by size compr. mode */
+        uint32_t compr_buf_size;  /* used by size compr. mode */
+        uint32_t stat_compr_orig_size;
+        uint32_t stat_compr_new_size;
+        uint32_t stat_compr_blocks;
+        uint32_t stat_decompr_blocks;
+};
+
+int jffs2_register_compressor(struct jffs2_compressor *comp);
+int jffs2_unregister_compressor(struct jffs2_compressor *comp);
+
+int jffs2_compressors_init(void);
+int jffs2_compressors_exit(void);
+
+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);
+
+int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+                     uint16_t comprtype, unsigned char *cdata_in,
+                     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
+
+/* If it is setted, a decompress will be called after every compress */
+void jffs2_compression_check_set(int yesno);
+
+void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig);
+
+char *jffs2_list_compressors(void);
+char *jffs2_stats(void);
+
+/* 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
+
+#endif /* __JFFS2_COMPR_H__ */
diff --unified --recursive --new-file mtd/fs/jffs2/compr_rtime.c mtd-new-8/fs/jffs2/compr_rtime.c
--- mtd/fs/jffs2/compr_rtime.c	2003-10-04 10:33:06.000000000 +0200
+++ mtd-new-8/fs/jffs2/compr_rtime.c	2004-05-10 17:38:18.000000000 +0200
@@ -25,6 +25,8 @@
 #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, 
@@ -67,7 +69,7 @@
 }		   
 
 
-void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
+int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
 		      uint32_t srclen, uint32_t destlen)
 {
 	short positions[256];
@@ -98,7 +100,29 @@
 				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);
+}
diff --unified --recursive --new-file mtd/fs/jffs2/compr_rubin.c mtd-new-8/fs/jffs2/compr_rubin.c
--- mtd/fs/jffs2/compr_rubin.c	2002-05-20 16:56:37.000000000 +0200
+++ mtd-new-8/fs/jffs2/compr_rubin.c	2004-05-10 17:38:18.000000000 +0200
@@ -14,10 +14,10 @@
  
 #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)
 {	
@@ -306,13 +306,14 @@
 }		   
 
 
-void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, 
+int jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, 
 		   uint32_t sourcelen, uint32_t dstlen)
 {
 	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, 
+int jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, 
 		   uint32_t sourcelen, uint32_t dstlen)
 {
 	int bits[8];
@@ -322,4 +323,51 @@
 		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);
 }
diff --unified --recursive --new-file mtd/fs/jffs2/compr_zlib.c mtd-new-8/fs/jffs2/compr_zlib.c
--- mtd/fs/jffs2/compr_zlib.c	2003-12-03 10:25:43.000000000 +0100
+++ mtd-new-8/fs/jffs2/compr_zlib.c	2004-05-10 17:38:18.000000000 +0200
@@ -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 @@
 #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,11 +59,14 @@
 	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, 
@@ -131,7 +135,7 @@
 	return ret;
 }
 
-void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
 		      uint32_t srclen, uint32_t destlen)
 {
 	int ret;
@@ -166,7 +170,7 @@
 	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 @@
 	}
 	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();
 }
diff --unified --recursive --new-file mtd/fs/jffs2/gc.c mtd-new-8/fs/jffs2/gc.c
--- mtd/fs/jffs2/gc.c	2004-03-08 16:29:09.000000000 +0100
+++ mtd-new-8/fs/jffs2/gc.c	2004-05-10 17:38:18.000000000 +0200
@@ -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,
@@ -1176,7 +1177,7 @@
 	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 +1210,8 @@
 		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));
 	
diff --unified --recursive --new-file mtd/fs/jffs2/nodelist.h mtd-new-8/fs/jffs2/nodelist.h
--- mtd/fs/jffs2/nodelist.h	2004-05-05 13:57:52.000000000 +0200
+++ mtd-new-8/fs/jffs2/nodelist.h	2004-05-10 17:38:18.000000000 +0200
@@ -472,15 +472,6 @@
 			   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);
@@ -501,8 +492,4 @@
 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__ */
diff --unified --recursive --new-file mtd/fs/jffs2/os-linux.h mtd-new-8/fs/jffs2/os-linux.h
--- mtd/fs/jffs2/os-linux.h	2004-05-05 14:00:31.000000000 +0200
+++ mtd-new-8/fs/jffs2/os-linux.h	2004-05-10 17:38:18.000000000 +0200
@@ -201,13 +201,6 @@
 int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs, 
 		       unsigned long count, loff_t to, size_t *retlen);
 
-/* Compression config */
-#define JFFS2_COMPRESSION
-#undef JFFS2_USE_DYNRUBIN /* Disabled 23/9/1. With zlib it hardly ever gets a look in */
-#undef JFFS2_USE_RUBINMIPS /* Disabled 26/2/1. Obsoleted by dynrubin */
-#define JFFS2_USE_ZLIB
-#define JFFS2_USE_RTIME /* rtime does manage to recompress already-compressed data */
-
 
 #endif /* __JFFS2_OS_LINUX_H__ */
 
diff --unified --recursive --new-file mtd/fs/jffs2/read.c mtd-new-8/fs/jffs2/read.c
--- mtd/fs/jffs2/read.c	2004-03-08 16:29:09.000000000 +0100
+++ mtd-new-8/fs/jffs2/read.c	2004-05-10 17:38:18.000000000 +0200
@@ -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 @@
 	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;
diff --unified --recursive --new-file mtd/fs/jffs2/super-v24.c mtd-new-8/fs/jffs2/super-v24.c
--- mtd/fs/jffs2/super-v24.c	2004-05-05 14:00:31.000000000 +0200
+++ mtd-new-8/fs/jffs2/super-v24.c	2004-05-10 17:38:18.000000000 +0200
@@ -22,6 +22,7 @@
 #include <linux/jffs2.h>
 #include <linux/pagemap.h>
 #include <linux/mtd/mtd.h>
+#include "compr.h"
 #include "nodelist.h"
 
 #ifndef MTD_BLOCK_MAJOR
@@ -125,15 +126,15 @@
 		return -EIO;
 	}
 #endif
-	ret = jffs2_zlib_init();
+	ret = jffs2_compressors_init();
 	if (ret) {
-		printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n");
+		printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
 		goto out;
 	}
 	ret = jffs2_create_slab_caches();
 	if (ret) {
 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
-		goto out_zlib;
+		goto out_compressors;
 	}
 	ret = register_filesystem(&jffs2_fs_type);
 	if (ret) {
@@ -144,8 +145,8 @@
 
  out_slab:
 	jffs2_destroy_slab_caches();
- out_zlib:
-	jffs2_zlib_exit();
+ out_compressors:
+	jffs2_compressors_exit();
  out:
 
 	return ret;
@@ -154,7 +155,7 @@
 static void __exit exit_jffs2_fs(void)
 {
 	jffs2_destroy_slab_caches();
-	jffs2_zlib_exit();
+	jffs2_compressors_exit();
 	unregister_filesystem(&jffs2_fs_type);
 }
 
diff --unified --recursive --new-file mtd/fs/jffs2/super.c mtd-new-8/fs/jffs2/super.c
--- mtd/fs/jffs2/super.c	2004-05-05 14:00:31.000000000 +0200
+++ mtd-new-8/fs/jffs2/super.c	2004-05-10 17:38:18.000000000 +0200
@@ -24,6 +24,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/ctype.h>
 #include <linux/namei.h>
+#include "compr.h"
 #include "nodelist.h"
 
 static void jffs2_put_super(struct super_block *);
@@ -307,15 +308,15 @@
 		printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
 		return -ENOMEM;
 	}
-	ret = jffs2_zlib_init();
+	ret = jffs2_compressors_init();
 	if (ret) {
-		printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n");
+		printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
 		goto out;
 	}
 	ret = jffs2_create_slab_caches();
 	if (ret) {
 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
-		goto out_zlib;
+		goto out_compressors;
 	}
 	ret = register_filesystem(&jffs2_fs_type);
 	if (ret) {
@@ -326,8 +327,8 @@
 
  out_slab:
 	jffs2_destroy_slab_caches();
- out_zlib:
-	jffs2_zlib_exit();
+ out_compressors:
+	jffs2_compressors_exit();
  out:
 	return ret;
 }
@@ -336,7 +337,7 @@
 {
 	unregister_filesystem(&jffs2_fs_type);
 	jffs2_destroy_slab_caches();
-	jffs2_zlib_exit();
+	jffs2_compressors_exit();
 	kmem_cache_destroy(jffs2_inode_cachep);
 }
 
diff --unified --recursive --new-file mtd/fs/jffs2/write.c mtd-new-8/fs/jffs2/write.c
--- mtd/fs/jffs2/write.c	2004-03-30 11:36:09.000000000 +0200
+++ mtd-new-8/fs/jffs2/write.c	2004-05-10 17:38:18.000000000 +0200
@@ -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)
@@ -358,7 +359,7 @@
 	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 @@
 		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));
 
diff --unified --recursive --new-file mtd/patches/patchin.sh mtd-new-8/patches/patchin.sh
--- mtd/patches/patchin.sh	2004-05-05 22:42:55.000000000 +0200
+++ mtd-new-8/patches/patchin.sh	2004-05-10 17:38:18.000000000 +0200
@@ -241,7 +241,17 @@
 				rm -f include/linux/crc32.h
 				$LNCP $TOPDIR/fs/jffs2/crc32.h include/linux
 			fi
-		fi
+		
+                else
+			JFFS=`grep -n JFFS fs/Kconfig | head -n 1 | sed s/:.*//`
+			CRAMFS=`grep -n CRAMFS fs/Kconfig | head -n 1 | sed s/:.*//`
+			let JFFS=JFFS-1
+			let CRAMFS=CRAMFS-1
+			sed "$JFFS"q fs/Kconfig >Kconfig.tmp
+			cat $TOPDIR/fs/Kconfig >>Kconfig.tmp
+			sed 1,"$CRAMFS"d fs/Kconfig >>Kconfig.tmp
+			mv -f Kconfig.tmp fs/Kconfig
+                fi
 	fi
 fi