mtd/util compr.c, NONE, 1.1 compr.h, NONE, 1.1 Makefile, 1.49, 1.50 compr_rtime.c, 1.1, 1.2 compr_zlib.c, 1.1, 1.2 mkfs.jffs2.1, 1.4, 1.5 mkfs.jffs2.c, 1.41, 1.42

havasi at infradead.org havasi at infradead.org
Tue May 25 07:20:48 EDT 2004


Update of /home/cvs/mtd/util
In directory phoenix.infradead.org:/home/havasi/mtd/util

Modified Files:
	Makefile compr_rtime.c compr_zlib.c mkfs.jffs2.1 mkfs.jffs2.c 
Added Files:
	compr.c compr.h 
Log Message:
BBC mkfs patch:
- new compressor interface
- new mkfs.jffs2 switches (documented in man page)
- 3 compression mode: none, priority, size



--- NEW FILE compr.c ---
/*
 * JFFS2 -- Journalling Flash File System, Version 2.
 *
 * Copyright (C) 2004 Ferenc Havasi <havasi at inf.u-szeged.hu>,
 *                    University of Szeged, Hungary
 *
 * For licensing information, see the file 'LICENCE' in this directory
 * in the jffs2 directory.
 *
 * $Id: compr.c,v 1.1 2004/05/25 11:20:45 havasi Exp $
 *
 */

#include "compr.h"
#include <string.h>
#include <stdlib.h>
#include <linux/jffs2.h>

extern int page_size;

/* LIST IMPLEMENTATION (from linux/list.h) */

#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
        struct list_head name = LIST_HEAD_INIT(name)

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;

/* Compression test stuffs */

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;
}

int jffs2_compression_check_get(void)
{
        return jffs2_compression_check;
}

static int jffs2_error_cnt = 0;

int jffs2_compression_check_errorcnt_get(void)
{
        return jffs2_error_cnt;
}

#define JFFS2_BUFFER_FILL 0x55

/* Called before compression (if compression_check is setted) to prepare 
   the buffer for buffer overflow test */
static void jffs2_decompression_test_prepare(char *buf, int size)
{
        memset(buf,JFFS2_BUFFER_FILL,size+1);
}

/* Called after compression (if compression_check is setted) to test the result */
static void jffs2_decompression_test(struct jffs2_compressor *compr,
                                     unsigned char *data_in, unsigned char *output_buf,
                                     uint32_t cdatalen, uint32_t datalen, uint32_t buf_size)
{
        uint32_t i;

        /* buffer overflow test */
        for (i=buf_size;i>cdatalen;i--) {
                if (output_buf[i]!=JFFS2_BUFFER_FILL) {
                        fprintf(stderr,"COMPR_ERROR: buffer overflow at %s. "
                                       "(bs=%d csize=%d b[%d]=%d)\n", compr->name, 
                                       buf_size, cdatalen, i, (int)(output_buf[i]));
                        jffs2_error_cnt++;
                        return;
                }
        }
        /* allocing temporary buffer for decompression */
        if (!jffs2_compression_check_buf) {
                jffs2_compression_check_buf = JFFS2_MALLOC(page_size);
                if (!jffs2_compression_check_buf) {
                        fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n");
                        jffs2_compression_check = 0;
                        return;
                }
        }
        /* decompressing */
        if (!compr->decompress) {
                fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name);
                jffs2_error_cnt++;
                return;
        }
        if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen)) {
                fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name);
                jffs2_error_cnt++;
        }
        /* validate decompression */
        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);
                                jffs2_error_cnt++;
                                break;
                        }
                }                
        }
}

/* jffs2_compress:
 * @data: Pointer to uncompressed data
 * @cdata: Pointer to returned pointer to buffer for compressed data
 * @datalen: On entry, holds the amount of data available for compression.
 *	On exit, expected to hold the amount of data actually compressed.
 * @cdatalen: On entry, holds the amount of space available for compressed
 *	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:
                orig_slen = *datalen;
                orig_dlen = *cdatalen;
                output_buf = JFFS2_MALLOC(orig_dlen+jffs2_compression_check);
                if (!output_buf) {
                        fprintf(stderr, "mkfs.jffs2: No memory for compressor allocation. Compression failed.\n");
                        goto out;
                }
                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++;

                        if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
                                jffs2_decompression_test_prepare(output_buf, orig_dlen);

                        *datalen  = orig_slen;
                        *cdatalen = orig_dlen;
                        compr_ret = this->compress(data_in, output_buf, datalen, cdatalen);
                        this->usecount--;
                        if (!compr_ret) {
                                ret = this->compr;
                                this->stat_compr_blocks++;
                                this->stat_compr_orig_size += *datalen;
                                this->stat_compr_new_size  += *cdatalen;
                                if (jffs2_compression_check)
                                        jffs2_decompression_test(this, data_in, output_buf, *cdatalen, *datalen, orig_dlen);
                                break;
                        }
                }
                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+jffs2_compression_check)&&(this->compr_buf)) {
                                JFFS2_FREE(this->compr_buf);
                                this->compr_buf_size=0;
                                this->compr_buf=NULL;
                        }
                        if (!this->compr_buf) {
                                tmp_buf = JFFS2_MALLOC(orig_dlen+jffs2_compression_check);
                                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++;
                        if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
                                jffs2_decompression_test_prepare(this->compr_buf,this->compr_buf_size);
                        *datalen  = orig_slen;
                        *cdatalen = orig_dlen;
                        compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
                        this->usecount--;
                        if (!compr_ret) {
                                if (jffs2_compression_check)
                                    jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen, this->compr_buf_size);
                                if ((!best_dlen)||(best_dlen>*cdatalen)) {
                                        best_dlen = *cdatalen;
                                        best_slen = *datalen;
                                        best = this;
                                }
                        }
                }
                if (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 = JFFS2_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 = JFFS2_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_set_compressor_priority(const char *name, int priority)
{
        struct jffs2_compressor *this,*comp;
        list_for_each_entry(this, &jffs2_compressor_list, list) {
                if (!strcmp(this->name, name)) {
                        this->priority = priority;
                        comp = this;
                        goto reinsert;
                }
        }
        fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name);
        return 1;
reinsert:
        /* list is sorted in the order of priority, so if
           we change it we have to reinsert it into the
           good place */
        list_del(&comp->list);
        list_for_each_entry(this, &jffs2_compressor_list, list) {
                if (this->priority < comp->priority) {
                        list_add(&comp->list, this->list.prev);
                        return 0;
                }
        }
        list_add_tail(&comp->list, &jffs2_compressor_list);
        return 0;
}


int jffs2_compressors_init(void) 
{
#ifdef CONFIG_JFFS2_ZLIB
        jffs2_zlib_init();
#endif
#ifdef CONFIG_JFFS2_RTIME
        jffs2_rtime_init();
#endif
        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;
}

--- NEW FILE compr.h ---
/*
 * JFFS2 -- Journalling Flash File System, Version 2.
 *
 * Copyright (C) 2004 Ferenc Havasi <havasi at inf.u-szeged.hu>,
 *                    University of Szeged, Hungary
 *
 * For licensing information, see the file 'LICENCE' in the 
 * jffs2 directory.
 *
 * $Id: compr.h,v 1.1 2004/05/25 11:20:45 havasi Exp $
 *
 */

#ifndef __JFFS2_COMPR_H__
#define __JFFS2_COMPR_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "linux/jffs2.h"

#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

#define JFFS2_MALLOC(a)             malloc(a)
#define JFFS2_FREE(a)               free(a)
#define JFFS2_MALLOC_BIG(a)         malloc(a)
#define JFFS2_FREE_BIG(a)           free(a)

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);

int jffs2_set_compressor_priority(const char *name, int priority);

struct jffs2_compressor {
        struct list_head list;
        int priority;             /* used by prirority comr. mode */
        char *name;
        char compr;               /* JFFS2_COMPR_XXX */
        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);
int jffs2_compression_check_get(void);
int jffs2_compression_check_errorcnt_get(void);

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__ */

Index: Makefile
===================================================================
RCS file: /home/cvs/mtd/util/Makefile,v
retrieving revision 1.49
retrieving revision 1.50
diff -u -r1.49 -r1.50
--- Makefile	5 May 2004 21:32:06 -0000	1.49
+++ Makefile	25 May 2004 11:20:45 -0000	1.50
@@ -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

Index: compr_rtime.c
===================================================================
RCS file: /home/cvs/mtd/util/compr_rtime.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- compr_rtime.c	5 May 2004 11:57:54 -0000	1.1
+++ compr_rtime.c	25 May 2004 11:20:45 -0000	1.2
@@ -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);
+}

Index: compr_zlib.c
===================================================================
RCS file: /home/cvs/mtd/util/compr_zlib.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- compr_zlib.c	3 Mar 2002 16:14:24 -0000	1.1
+++ compr_zlib.c	25 May 2004 11:20:45 -0000	1.2
@@ -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);
 }

Index: mkfs.jffs2.1
===================================================================
RCS file: /home/cvs/mtd/util/mkfs.jffs2.1,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- mkfs.jffs2.1	12 Jan 2003 15:41:23 -0000	1.4
+++ mkfs.jffs2.1	25 May 2004 11:20:45 -0000	1.5
@@ -49,6 +49,24 @@
 .B -P,--squash-perms
 ]
 [
+.B -m,--compression-mode=MODE
+]
+[
+.B -x,--disable-compressor=NAME
+]
+[
+.B -X,--enable-compressor=NAME
+]
+[
+.B -y,--compressor-priority=PRIORITY:NAME
+]
+[
+.B -L,--list-compressors
+]
+[
+.B -t,--test-compression
+]
+[
 .B -h,--help
 ]
 [
@@ -73,10 +91,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
@@ -155,6 +172,39 @@
 .TP
 .B -P, --squash-perms
 Squash permissions, removing write permission for \'group\' and \'other\'.
+.TP
+.B -m, --compression-mode=MODE
+Set the default compression mode. The default mode is 
+.B priority 
+which tries the compressors in a predefinied order and chooses the first
+successful one. The alternatives are:
+.B 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 -y, --compressor-priority=PRIORITY:NAME
+Set the priority of a compressor. Use
+.B -L
+to see the list of the avaiable compressors and their default priority.
+Priorities are used by priority compression mode.
+.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 -, and
+some other check.
 .TP
 .B -h, --help
 Display help text.

Index: mkfs.jffs2.c
===================================================================
RCS file: /home/cvs/mtd/util/mkfs.jffs2.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -r1.41 -r1.42
--- mkfs.jffs2.c	5 May 2004 11:57:55 -0000	1.41
+++ mkfs.jffs2.c	25 May 2004 11:20:45 -0000	1.42
@@ -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,10 @@
 	{"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'},
+	{"compressor-priority", 1, NULL, 'y'},
 	{NULL, 0, NULL, 0}
 };
 
@@ -1172,25 +1163,34 @@
 	"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, --compr-mode=MODE   Select compression mode (default: priortiry)\n"
+        "  -x, --disable-compressor=COMPRESSOR_NAME\n"
+        "                          Disable a compressor\n"
+        "  -X, --enable-compressor=COMPRESSOR_NAME\n"
+        "                          Enable a compressor\n"
+        "  -y, --compressor-priority=PRIORITY:COMPRESSOR_NAME\n"
+        "                          Set the priority of a compressor\n"
+        "  -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$";
@@ -1202,9 +1202,13 @@
 	struct stat sb;
 	FILE *devtable = NULL;
 	struct filesystem_entry *root;
+        char *compr_name = NULL;
+        int compr_prior  = -1;
+
+        jffs2_compressors_init();
 
 	while ((opt = getopt_long(argc, argv, 
-					"D:d:r:s:o:qUPfh?vVe:lbp::nc:", long_options, &c)) >= 0) 
+					"D:d:r:s:o:qUPfh?vVe:lbp::nc:m:x:X:Lty:", long_options, &c)) >= 0) 
 	{
 		switch (opt) {
 			case 'D':
@@ -1324,6 +1328,39 @@
 					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;
+                        case 'y':
+                                compr_name = malloc(strlen(optarg));
+                                sscanf(optarg,"%d:%s",&compr_prior,compr_name);
+                                if ((compr_prior>=0)&&(compr_name)) {
+                                        if (jffs2_set_compressor_priority(compr_name, compr_prior))
+	                                        exit(EXIT_FAILURE);
+                                }
+                                else {
+                                        error_msg_and_die("Cannot parse %s",optarg);
+                                }
+                                free(compr_name);
+                                break;
 		}
 	}
 	if (out_fd == -1) {
@@ -1354,5 +1391,17 @@
 		free(rootdir);
 
 	close(out_fd);
+
+        if (verbose) {
+                char *s = jffs2_stats();
+                fprintf(stderr,"\n\n%s",s);
+                free(s);
+        }
+        if ((verbose)||(jffs2_compression_check_get()&&(jffs2_compression_check_errorcnt_get()))) {
+                fprintf(stderr,"Compression errors: %d\n",jffs2_compression_check_errorcnt_get());
+        }
+
+        jffs2_compressors_exit();
+
 	return 0;
 }





More information about the linux-mtd-cvs mailing list