mtd/util summary.h, 1.3, 1.4 sumtool.c, 1.4, 1.5 Makefile, 1.58, 1.59 jffs2dump.c, 1.8, 1.9

havasi at infradead.org havasi at infradead.org
Wed Sep 7 04:35:00 EDT 2005


Update of /home/cvs/mtd/util
In directory phoenix.infradead.org:/tmp/cvs-serv3759/util

Modified Files:
	Makefile jffs2dump.c 
Added Files:
	summary.h sumtool.c 
Log Message:
[JFFS2] Adding erase block summary support (mount time improvement)

The goal of summary is to speed up the mount time. Erase block summary (EBS)
stores summary information at the end of every (closed) erase block. It is
no longer necessary to scan all nodes separetly (and read all pages of them)
just read this "small" summary, where every information is stored which is
needed at mount time.

This summary information is stored in a JFFS2_FEATURE_RWCOMPAT_DELETE. During
the mount process if there is no summary info the orignal scan process will 
be executed. EBS works with NAND and NOR flashes, too.

There is a user space tool called sumtool to generate this summary 
information for a JFFS2 image.



Index: summary.h
===================================================================
RCS file: summary.h
diff -N summary.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ summary.h	7 Sep 2005 08:34:57 -0000	1.4
@@ -0,0 +1,143 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004  Ferenc Havasi <havasi at inf.u-szeged.hu>,
+ *                     Zoltan Sogor <weth at inf.u-szeged.hu>,
+ *                     Patrik Kluba <pajko at halom.u-szeged.hu>,
+ *                     University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id$
+ *
+ */
+
+#ifndef JFFS2_SUMMARY_H
+#define JFFS2_SUMMARY_H
+
+#include <linux/uio.h>
+#include <linux/jffs2.h>
+
+#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
+		c->free_size -= _x; c->dirty_size += _x; \
+		jeb->free_size -= _x ; jeb->dirty_size += _x; \
+		}while(0)
+#define USED_SPACE(x) do { typeof(x) _x = (x); \
+		c->free_size -= _x; c->used_size += _x; \
+		jeb->free_size -= _x ; jeb->used_size += _x; \
+		}while(0)
+#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
+		c->free_size -= _x; c->wasted_size += _x; \
+		jeb->free_size -= _x ; jeb->wasted_size += _x; \
+		}while(0)
+#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
+		c->free_size -= _x; c->unchecked_size += _x; \
+		jeb->free_size -= _x ; jeb->unchecked_size += _x; \
+		}while(0)
+
+#define BLK_STATE_ALLFF		0
+#define BLK_STATE_CLEAN		1
+#define BLK_STATE_PARTDIRTY	2
+#define BLK_STATE_CLEANMARKER	3
+#define BLK_STATE_ALLDIRTY	4
+#define BLK_STATE_BADBLOCK	5
+
+#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
+#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
+#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
+
+/* Summary structures used on flash */
+
+struct jffs2_sum_unknown_flash
+{
+	jint16_t nodetype;	/* node type */
+};
+
+struct jffs2_sum_inode_flash
+{
+	jint16_t nodetype;	/* node type */
+	jint32_t inode;		/* inode number */
+	jint32_t version;	/* inode version */
+	jint32_t offset;	/* offset on jeb */
+	jint32_t totlen; 	/* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_flash
+{
+	jint16_t nodetype;	/* == JFFS_NODETYPE_DIRENT */
+	jint32_t totlen;	/* record length */
+	jint32_t offset;	/* ofset on jeb */
+	jint32_t pino;		/* parent inode */
+	jint32_t version;	/* dirent version */
+	jint32_t ino; 		/* == zero for unlink */
+	uint8_t nsize;		/* dirent name size */
+	uint8_t type;		/* dirent type */
+	uint8_t name[0];	/* dirent name */
+} __attribute__((packed));
+
+union jffs2_sum_flash
+{
+	struct jffs2_sum_unknown_flash u;
+	struct jffs2_sum_inode_flash i;
+	struct jffs2_sum_dirent_flash d;
+};
+
+/* Summary structures used in the memory */
+
+struct jffs2_sum_unknown_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* node type */
+};
+
+struct jffs2_sum_inode_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* node type */
+	jint32_t inode;		/* inode number */
+	jint32_t version;	/* inode version */
+	jint32_t offset;	/* offset on jeb */
+	jint32_t totlen; 	/* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* == JFFS_NODETYPE_DIRENT */
+	jint32_t totlen;	/* record length */
+	jint32_t offset;	/* ofset on jeb */
+	jint32_t pino;		/* parent inode */
+	jint32_t version;	/* dirent version */
+	jint32_t ino; 		/* == zero for unlink */
+	uint8_t nsize;		/* dirent name size */
+	uint8_t type;		/* dirent type */
+	uint8_t name[0];	/* dirent name */
+} __attribute__((packed));
+
+union jffs2_sum_mem 
+{
+	struct jffs2_sum_unknown_mem u;
+	struct jffs2_sum_inode_mem i;
+	struct jffs2_sum_dirent_mem d;
+};
+
+struct jffs2_summary
+{
+	uint32_t sum_size;
+	uint32_t sum_num;
+	uint32_t sum_padded;
+	union jffs2_sum_mem *sum_list_head;
+	union jffs2_sum_mem *sum_list_tail;
+};
+
+/* Summary marker is stored at the end of every sumarized erase block */
+
+struct jffs2_sum_marker
+{
+	jint32_t offset;	/* offset of the summary node in the jeb */
+	jint32_t magic; 	/* == JFFS2_SUM_MAGIC */
+};
+
+#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_summary_node) + sizeof(struct jffs2_sum_marker))
+
+#endif

Index: sumtool.c
===================================================================
RCS file: sumtool.c
diff -N sumtool.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sumtool.c	7 Sep 2005 08:34:57 -0000	1.5
@@ -0,0 +1,820 @@
+/*
+ *  sumtool.c
+ *
+ *  Copyright (C) 2004 Zoltan Sogor <weth at inf.u-szeged.hu>,
+ *                     Ferenc Havasi <havasi at inf.u-szeged.hu>
+ *                     University of Szeged, Hungary
+ *
+ * $Id$
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Overview:
+ *   This is a utility insert summary information into JFFS2 image for 
+ *   faster mount time
+ *
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <asm/types.h>
+#include <dirent.h>
+#include <mtd/jffs2-user.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <getopt.h>
+#include "crc32.h"
+#include "summary.h"
+
+#define PAD(x) (((x)+3)&~3)
+
+static const char *const app_name = "sumtool";
+
+static struct jffs2_summary *sum_collected = NULL;
+
+static int verbose = 0;
+static int padto = 0;				/* pad the output with 0xFF to the end of the final eraseblock */
+static int add_cleanmarkers = 1;		/* add cleanmarker to output */
+static int use_input_cleanmarker_size = 1;	/* use input file's cleanmarker size (default) */
+static int found_cleanmarkers = 0;		/* cleanmarker found in input file */
+static struct jffs2_unknown_node cleanmarker;
+static int cleanmarker_size = sizeof(cleanmarker);
+static const char *short_options = "o:i:e:hvVblnc:p";
+static int erase_block_size = 65536;
+static int target_endian = __BYTE_ORDER;
+static int out_fd = -1;
+static int in_fd = -1;
+
+static uint8_t *data_buffer = NULL; 		/* buffer for inodes */
+static unsigned int data_ofs = 0;	 	/* inode buffer offset */
+
+static uint8_t *file_buffer = NULL;		/* file buffer contains the actual erase block*/
+static unsigned int file_ofs = 0;		/* position in the buffer */
+
+static struct option long_options[] = {
+	{"output", 1, NULL, 'o'},
+	{"input", 1, NULL, 'i'},
+	{"eraseblock", 1, NULL, 'e'},
+	{"help", 0, NULL, 'h'},
+	{"verbose", 0, NULL, 'v'},
+	{"version", 0, NULL, 'V'},
+	{"bigendian", 0, NULL, 'b'},
+	{"littleendian", 0, NULL, 'l'},
+	{"no-cleanmarkers", 0, NULL, 'n'},
+	{"cleanmarker", 1, NULL, 'c'},
+	{"pad", 0, NULL, 'p'},
+	{NULL, 0, NULL, 0}
+};
+
+static char *helptext =
+	"Usage: sumtool [OPTIONS] -i inputfile -o outputfile\n\n"
+	"Convert the input JFFS2 image to a summarized JFFS2 image\n"
+	"Summary makes mounting faster - if summary support enabled in your kernel\n\n"
+	"Options:\n"
+	"  -e, --eraseblock=SIZE     Use erase block size SIZE (default: 64KiB)\n"
+	"                            (usually 16KiB on NAND)\n"
+	"  -c, --cleanmarker=SIZE    Size of cleanmarker (default 12).\n"
+	"                            (usually 16 bytes on NAND, and will be set to\n"
+	"                            this value if left at the default 12). Will be\n"
+	"                            stored in OOB after each physical page composing\n"
+	"                            a physical eraseblock.\n"
+	"  -n, --no-cleanmarkers     Don't add a cleanmarker to every eraseblock\n"
+	"  -o, --output=FILE         Output to FILE \n"
+	"  -i, --input=FILE          Input from FILE \n"
+	"  -b, --bigendian           Image is big endian\n"
+	"  -l  --littleendian        Image is little endian\n"
+	"  -h, --help                Display this help text\n"
+	"  -v, --verbose             Verbose operation\n"
+	"  -V, --version             Display version information\n"
+	"  -p, --pad                 Pad the OUTPUT with 0xFF to the end of the final\n"
+	"                            eraseblock\n\n";
+
+
+static char *revtext = "$Revision$";
+
+static unsigned char ffbuf[16] = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static void verror_msg(const char *s, va_list p)
+{
+	fflush(stdout);
+	fprintf(stderr, "%s: ", app_name);
+	vfprintf(stderr, s, p);
+}
+
+static void error_msg_and_die(const char *s, ...)
+{
+	va_list p;
+
+	va_start(p, s);
+	verror_msg(s, p);
+	va_end(p);
+	putc('\n', stderr);
+	exit(EXIT_FAILURE);
+}
+
+static void vperror_msg(const char *s, va_list p)
+{
+	int err = errno;
+
+	if (s == 0)
+		s = "";
+	verror_msg(s, p);
+	if (*s)
+		s = ": ";
+	fprintf(stderr, "%s%s\n", s, strerror(err));
+}
+
+static void perror_msg_and_die(const char *s, ...)
+{
+	va_list p;
+
+	va_start(p, s);
+	vperror_msg(s, p);
+	va_end(p);
+	exit(EXIT_FAILURE);
+}
+
+
+
+static void full_write(void *target_buff, const void *buf, int len);
+
+void setup_cleanmarker()
+{
+	cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
+	cleanmarker.totlen = cpu_to_je32(cleanmarker_size);
+	cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
+}
+
+void process_options (int argc, char **argv)
+{
+	int opt,c;
+
+	while ((opt = getopt_long(argc, argv, short_options, long_options, &c)) >= 0) {
+		switch (opt) {
+			case 'o':
+				if (out_fd != -1)
+					error_msg_and_die("output filename specified more than once");
+				out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
+				if (out_fd == -1)
+					perror_msg_and_die("open output file");
+				break;
+
+			case 'i':
+				if (in_fd != -1)
+					error_msg_and_die("input filename specified more than once");
+				in_fd = open(optarg, O_RDONLY);
+				if (in_fd == -1)
+					perror_msg_and_die("open input file");
+				break;
+			case 'b':
+				target_endian = __BIG_ENDIAN;
+				break;
+			case 'l':
+				target_endian = __LITTLE_ENDIAN;
+				break;
+			case 'h':
+			case '?':
+				error_msg_and_die(helptext);
+			case 'v':
+				verbose = 1;
+				break;
+
+			case 'V':
+				error_msg_and_die("revision %.*s\n",
+						(int) strlen(revtext) - 13, revtext + 11);
+
+			case 'e': {
+				char *next;
+				unsigned units = 0;
+				erase_block_size = strtol(optarg, &next, 0);
+				if (!erase_block_size)
+					error_msg_and_die("Unrecognisable erase size\n");
+
+				if (*next) {
+					if (!strcmp(next, "KiB")) {
+						units = 1024;
+					} else if (!strcmp(next, "MiB")) {
+						units = 1024 * 1024;
+					} else {
+						error_msg_and_die("Unknown units in erasesize\n");
+					}
+				} else {
+					if (erase_block_size < 0x1000)
+						units = 1024;
+					else
+						units = 1;
+				}
+				erase_block_size *= units;
+
+				/* If it's less than 8KiB, they're not allowed */
+				if (erase_block_size < 0x2000) {
+					fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n",
+						erase_block_size);
+					erase_block_size = 0x2000;
+				}
+				break;
+			}
+
+			case 'n':
+				add_cleanmarkers = 0;
+				break;
+			case 'c':
+				cleanmarker_size = strtol(optarg, NULL, 0);
+
+				if (cleanmarker_size < sizeof(cleanmarker)) {
+					error_msg_and_die("cleanmarker size must be >= 12");
+				}
+				if (cleanmarker_size >= erase_block_size) {
+					error_msg_and_die("cleanmarker size must be < eraseblock size");
+				}
+
+				use_input_cleanmarker_size = 0;
+				found_cleanmarkers = 1;
+				setup_cleanmarker();
+
+				break;
+			case 'p':
+				padto = 1;
+				break;
+		}
+	}
+}
+
+
+void init_buffers()
+{
+	data_buffer = malloc(erase_block_size);
+
+	if (!data_buffer) {
+		perror("out of memory");
+		close (in_fd);
+		close (out_fd);
+		exit(1);
+	}
+
+	file_buffer = malloc(erase_block_size);
+
+	if (!file_buffer) {
+		perror("out of memory");
+		close (in_fd);
+		close (out_fd);
+		exit(1);
+	}
+}
+
+void init_sumlist()
+{
+	sum_collected = (struct jffs2_summary *) malloc (sizeof(struct jffs2_summary));
+
+	if (!sum_collected)
+		error_msg_and_die("Can't allocate memory for jffs2_summary!\n");
+
+	memset(sum_collected, 0, sizeof(struct jffs2_summary));
+}
+
+void clean_buffers()
+{
+	if (data_buffer)
+		free(data_buffer);
+	if (file_buffer)
+		free(file_buffer);
+}
+
+void clean_sumlist()
+{
+	union jffs2_sum_mem *temp;
+
+	if (sum_collected) {
+
+		while (sum_collected->sum_list_head) {
+			temp = sum_collected->sum_list_head;
+			sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
+			free(temp);
+			sum_collected->sum_num--;
+		}
+
+		if (sum_collected->sum_num != 0)
+			printf("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
+
+		free(sum_collected);
+	}
+}
+
+int load_next_block()
+{
+	int ret;
+	ret = read(in_fd, file_buffer, erase_block_size);
+	file_ofs = 0;
+
+	if (verbose)
+		printf("Load next block : %d bytes read\n",ret);
+
+	return ret;
+}
+
+void write_buff_to_file()
+{
+	int ret;
+	int len = data_ofs;
+
+	uint8_t *buf = NULL;
+
+	buf = data_buffer;
+	while (len > 0) {
+		ret = write(out_fd, buf, len);
+
+		if (ret < 0)
+			perror_msg_and_die("write");
+
+		if (ret == 0)
+			perror_msg_and_die("write returned zero");
+
+		len -= ret;
+		buf += ret;
+	}
+
+	data_ofs = 0;
+}
+
+void dump_sum_records()
+{
+
+	struct jffs2_summary_node isum;
+	struct jffs2_sum_marker *sm;
+	union jffs2_sum_mem *temp;
+	jint32_t offset;
+	void *wpage;
+	int datasize, infosize, padsize;
+	jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
+
+	if (!sum_collected->sum_num || !sum_collected->sum_list_head)
+		return; 
+
+	datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker);
+	infosize = sizeof(struct jffs2_summary_node) + datasize;
+	padsize = erase_block_size - data_ofs - infosize;
+	infosize += padsize; datasize += padsize;
+	offset = cpu_to_je32(data_ofs);
+
+	jint32_t *tpage = (jint32_t *) malloc(datasize);
+
+	if(!tpage)
+		error_msg_and_die("Can't allocate memory to dump summary information!\n");
+
+	memset(tpage, 0xff, datasize);
+	memset(&isum, 0, sizeof(isum));
+
+	isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
+	isum.totlen = cpu_to_je32(infosize);
+	isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
+	isum.padded = cpu_to_je32(0);
+
+	if (add_cleanmarkers && found_cleanmarkers) {
+		isum.cln_mkr = cpu_to_je32(cleanmarker_size);
+	} else {
+		isum.cln_mkr = cpu_to_je32(0);
+	}
+
+	isum.sum_num = cpu_to_je32(sum_collected->sum_num);
+	wpage = tpage;
+
+	while (sum_collected->sum_num) {
+		switch(je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) {
+
+			case JFFS2_NODETYPE_INODE : {
+				struct jffs2_sum_inode_flash *sino_ptr = wpage;
+
+				sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype;
+				sino_ptr->inode = sum_collected->sum_list_head->i.inode;
+				sino_ptr->version = sum_collected->sum_list_head->i.version;
+				sino_ptr->offset = sum_collected->sum_list_head->i.offset;
+				sino_ptr->totlen = sum_collected->sum_list_head->i.totlen;
+
+				wpage += JFFS2_SUMMARY_INODE_SIZE;
+				break;
+			}
+
+			case JFFS2_NODETYPE_DIRENT : {
+				struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
+
+				sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype;
+				sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen;
+				sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset;
+				sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino;
+				sdrnt_ptr->version = sum_collected->sum_list_head->d.version;
+				sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino;
+				sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize;
+				sdrnt_ptr->type = sum_collected->sum_list_head->d.type;
+
+				memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name,
+						sum_collected->sum_list_head->d.nsize);
+
+				wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize);
+				break;
+			}
+
+			default : {
+				printf("Unknown node type!\n");
+			}
+		}
+
+		temp = sum_collected->sum_list_head;
+		sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
+		free(temp);
+
+		sum_collected->sum_num--;
+	}
+
+	sum_collected->sum_size = 0;
+	sum_collected->sum_num = 0;
+	sum_collected->sum_list_tail = NULL;
+
+	wpage += padsize;
+
+	sm = wpage;
+	sm->offset = offset;
+	sm->magic = magic;
+
+	isum.sum_crc = cpu_to_je32(crc32(0, tpage, datasize));
+	isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8));
+
+	full_write(data_buffer + data_ofs, &isum, sizeof(isum));
+	full_write(data_buffer + data_ofs, tpage, datasize);
+
+	free(tpage);
+}
+
+static void full_write(void *target_buff, const void *buf, int len)
+{
+	memcpy(target_buff, buf, len);
+	data_ofs += len;
+}
+
+static void pad(int req)
+{
+	while (req) {
+		if (req > sizeof(ffbuf)) {
+			full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf));
+			req -= sizeof(ffbuf);
+		} else {
+			full_write(data_buffer + data_ofs, ffbuf, req);
+			req = 0;
+		}
+	}
+}
+
+static inline void padword()
+{
+	if (data_ofs % 4)
+		full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4));
+}
+
+
+static inline void pad_block_if_less_than(int req,int plus)
+{
+
+	int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_summary_node) + 8;
+	datasize += (4 - (datasize % 4)) % 4;
+
+	if (data_ofs + req > erase_block_size - datasize) {
+		dump_sum_records();
+		write_buff_to_file();
+	}
+
+	if (add_cleanmarkers && found_cleanmarkers) {
+		if (!data_ofs) {
+			full_write(data_buffer, &cleanmarker, sizeof(cleanmarker));
+			pad(cleanmarker_size - sizeof(cleanmarker));
+			padword();
+		}
+	}
+}
+
+void flush_buffers()
+{
+
+	if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */
+		if (data_ofs != cleanmarker_size) {	/* INODE BUFFER */
+
+			int datasize = sum_collected->sum_size + sizeof(struct jffs2_summary_node) + 8;
+			datasize += (4 - (datasize % 4)) % 4;
+
+			/* If we have a full inode buffer, then write out inode and summary data  */
+			if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
+				dump_sum_records();
+				write_buff_to_file();
+			} else {	/* else just write out inode data */
+				if (padto)
+					pad(erase_block_size - data_ofs);
+				write_buff_to_file();
+			}
+		}
+	} else { /* NO CLEANMARKER */
+		if (data_ofs != 0) { /* INODE BUFFER */
+
+			int datasize = sum_collected->sum_size + sizeof(struct jffs2_summary_node) + 8;
+			datasize += (4 - (datasize % 4)) % 4;
+
+			/* If we have a full inode buffer, then write out inode and summary data */
+			if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
+				dump_sum_records();
+				write_buff_to_file();
+			} else {	/* Else just write out inode data */
+				if(padto)
+					pad(erase_block_size - data_ofs);
+				write_buff_to_file();
+			}
+		}
+	}
+}
+
+int add_sum_mem(union jffs2_sum_mem *item)
+{
+
+	if (!sum_collected->sum_list_head)
+		sum_collected->sum_list_head = (union jffs2_sum_mem *) item;
+	if (sum_collected->sum_list_tail)
+		sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
+	sum_collected->sum_list_tail = (union jffs2_sum_mem *) item;
+
+	switch (je16_to_cpu(item->u.nodetype)) {
+		case JFFS2_NODETYPE_INODE:
+			sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE;
+			sum_collected->sum_num++;
+			break;
+
+		case JFFS2_NODETYPE_DIRENT:
+			sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
+			sum_collected->sum_num++;
+			break;
+
+		default:
+			error_msg_and_die("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype));
+	}
+	return 0;
+}
+
+void add_sum_inode_mem(union jffs2_node_union *node)
+{
+	struct jffs2_sum_inode_mem *temp = (struct jffs2_sum_inode_mem *) malloc(sizeof(struct jffs2_sum_inode_mem));
+
+	if (!temp)
+		error_msg_and_die("Can't allocate memory for summary information!\n");
+
+	temp->nodetype = node->i.nodetype;
+	temp->inode = node->i.ino;
+	temp->version = node->i.version;
+	temp->offset = cpu_to_je32(data_ofs);
+	temp->totlen = node->i.totlen;
+	temp->next = NULL;
+
+	add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void add_sum_dirent_mem(union jffs2_node_union *node)
+{
+	struct jffs2_sum_dirent_mem *temp = (struct jffs2_sum_dirent_mem *)
+			malloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize);
+
+	if (!temp)
+		error_msg_and_die("Can't allocate memory for summary information!\n");
+
+	temp->nodetype = node->d.nodetype;
+	temp->totlen = node->d.totlen;
+	temp->offset = cpu_to_je32(data_ofs);
+	temp->pino = node->d.pino;
+	temp->version = node->d.version;
+	temp->ino = node->d.ino;
+	temp->nsize = node->d.nsize;
+	temp->type = node->d.type;
+	temp->next = NULL;
+
+	memcpy(temp->name,node->d.name,node->d.nsize);
+	add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void write_dirent_to_buff(union jffs2_node_union *node)
+{
+	pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize));
+	add_sum_dirent_mem(node);
+	full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen));
+	padword();
+}
+
+
+void write_inode_to_buff(union jffs2_node_union *node)
+{
+	pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE);
+	add_sum_inode_mem(node);	/* Add inode summary mem to summary list */
+	full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen));	/* Write out the inode to inode_buffer */
+	padword();
+}
+
+void create_summed_image(int inp_size)
+{
+	uint8_t *p = file_buffer;
+	union jffs2_node_union *node;
+	uint32_t crc;
+	uint16_t type;
+	int bitchbitmask = 0;
+	int obsolete;
+	char name[256];
+
+	while ( p < (file_buffer + inp_size)) {
+
+		node = (union jffs2_node_union *) p;
+
+		/* Skip empty space */
+		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+			p += 4;
+			continue;
+		}
+
+		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
+			if (!bitchbitmask++)
+				printf ("Wrong bitmask  at  0x%08x, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic));
+			p += 4;
+			continue;
+		}
+
+		bitchbitmask = 0;
+
+		type = je16_to_cpu(node->u.nodetype);
+		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+			obsolete = 1;
+			type |= JFFS2_NODE_ACCURATE;
+		} else {
+			obsolete = 0;
+		}
+
+		node->u.nodetype = cpu_to_je16(type);
+
+		crc = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+		if (crc != je32_to_cpu (node->u.hdr_crc)) {
+			printf ("Wrong hdr_crc  at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc);
+			p += 4;
+			continue;
+		}
+
+		switch(je16_to_cpu(node->u.nodetype)) {
+			case JFFS2_NODETYPE_INODE:
+				if (verbose)
+					printf ("%8s Inode      node at 0x%08x, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+						je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize), 
+						je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+				crc = crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
+				if (crc != je32_to_cpu (node->i.node_crc)) {
+					printf ("Wrong node_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->i.node_crc), crc);
+					p += PAD(je32_to_cpu (node->i.totlen));
+					continue;
+				}
+
+				crc = crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
+				if (crc != je32_to_cpu(node->i.data_crc)) {
+					printf ("Wrong data_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->i.data_crc), crc);
+					p += PAD(je32_to_cpu (node->i.totlen));
+					continue;
+				}
+
+				write_inode_to_buff(node);
+
+				p += PAD(je32_to_cpu (node->i.totlen));
+				break;
+
+			case JFFS2_NODETYPE_DIRENT:
+				memcpy (name, node->d.name, node->d.nsize);
+				name [node->d.nsize] = 0x0;
+
+				if (verbose)
+					printf ("%8s Dirent     node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+						je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
+						node->d.nsize, name);
+
+				crc = crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
+				if (crc != je32_to_cpu (node->d.node_crc)) {
+					printf ("Wrong node_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->d.node_crc), crc);
+					p += PAD(je32_to_cpu (node->d.totlen));
+					continue;
+				}
+
+				crc = crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
+				if (crc != je32_to_cpu(node->d.name_crc)) {
+					printf ("Wrong name_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->d.name_crc), crc);
+					p += PAD(je32_to_cpu (node->d.totlen));
+					continue;
+				}
+
+				write_dirent_to_buff(node);
+
+				p += PAD(je32_to_cpu (node->d.totlen));
+				break;
+
+			case JFFS2_NODETYPE_CLEANMARKER:
+				if (verbose) {
+					printf ("%8s Cleanmarker     at 0x%08x, totlen 0x%08x\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				if (!found_cleanmarkers) {
+					found_cleanmarkers = 1;
+
+					if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1){
+						cleanmarker_size = je32_to_cpu (node->u.totlen);
+						setup_cleanmarker();
+					}
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case JFFS2_NODETYPE_PADDING:
+				if (verbose) {
+					printf ("%8s Padding    node at 0x%08x, totlen 0x%08x\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case 0xffff:
+				p += 4;
+				break;
+
+			default:
+				if (verbose) {
+					printf ("%8s Unknown    node at 0x%08x, totlen 0x%08x\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int ret;
+
+	process_options(argc,argv);
+
+	if ((in_fd == -1) || (out_fd == -1)) {
+		if(in_fd != -1)
+			close(in_fd);
+		if(out_fd != -1)
+			close(out_fd);
+		fprintf(stderr,helptext);
+		error_msg_and_die("You must specify input and output files!\n");
+	}
+
+	init_buffers();
+	init_sumlist();
+
+	while ((ret = load_next_block())) {
+		create_summed_image(ret);
+	}
+
+	flush_buffers();
+	clean_buffers();
+	clean_sumlist();
+
+	if (in_fd != -1)
+		close(in_fd);
+	if (out_fd != -1)
+		close(out_fd);
+
+	return 0;
+}

Index: Makefile
===================================================================
RCS file: /home/cvs/mtd/util/Makefile,v
retrieving revision 1.58
retrieving revision 1.59
diff -u -r1.58 -r1.59
--- Makefile	18 Aug 2005 08:40:50 -0000	1.58
+++ Makefile	7 Sep 2005 08:34:57 -0000	1.59
@@ -16,7 +16,7 @@
 	jffs2dump \
 	nftldump nftl_format docfdisk \
 	rfddump rfdformat \
-	#jffs2reader 
+	sumtool #jffs2reader 
 
 SYMLINKS = 
 
@@ -51,6 +51,9 @@
 jffs2dump: jffs2dump.o crc32.o
 	$(CC) $(LDFLAGS) -o $@ $^
 
+sumtool: sumtool.o crc32.o
+	$(CC) $(LDFLAGS) -o $@ $^
+
 install: ${TARGETS}
 	mkdir -p ${DESTDIR}/${SBINDIR}
 	install -m0755 -oroot -groot ${TARGETS} ${DESTDIR}/${SBINDIR}/

Index: jffs2dump.c
===================================================================
RCS file: /home/cvs/mtd/util/jffs2dump.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- jffs2dump.c	21 Jan 2005 11:52:22 -0000	1.8
+++ jffs2dump.c	7 Sep 2005 08:34:57 -0000	1.9
@@ -34,6 +34,7 @@
 #include <byteswap.h>
 #include <getopt.h>
 #include "crc32.h"
+#include "summary.h"
 
 #define PROGRAM "jffs2dump"
 #define VERSION "$Revision$"
@@ -177,7 +178,7 @@
  */
 void do_dumpcontent (void) 
 {
-	char			*p = data;
+	char			*p = data, *p_free_begin;
 	union jffs2_node_union 	*node;
 	int			empty = 0, dirty = 0;
 	char			name[256];
@@ -186,16 +187,23 @@
 	int			bitchbitmask = 0;
 	int			obsolete;
 
+	p_free_begin = NULL;
 	while ( p < (data + imglen)) {
 		node = (union jffs2_node_union*) p;
 		
 		/* Skip empty space */
+		if (!p_free_begin)
+			p_free_begin = p;
 		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
 			p += 4;
 			empty += 4;
 			continue;
 		}
 		
+		if (p != p_free_begin)
+			printf("Empty space found from 0x%08x to 0x%08x\n", p_free_begin-data, p-data);
+		p_free_begin = NULL;
+
 		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK)	{
 			if (!bitchbitmask++)
     			    printf ("Wrong bitmask  at  0x%08x, 0x%04x\n", p - data, je16_to_cpu (node->u.magic));
@@ -278,6 +286,99 @@
 			p += PAD(je32_to_cpu (node->d.totlen));						
 			break;
 	
+		case JFFS2_NODETYPE_SUMMARY: {
+
+			int i;
+			struct jffs2_sum_marker * sm;
+
+			printf("%8s Inode Sum  node at 0x%08x, totlen 0x%08x, sum_num  %5d, cleanmarker size %5d\n",
+					obsolete ? "Obsolete" : "",
+					p - data,
+					je32_to_cpu (node->s.totlen),
+					je32_to_cpu (node->s.sum_num),
+					je32_to_cpu (node->s.cln_mkr));
+
+			crc = crc32 (0, node, sizeof (struct jffs2_summary_node) - 8);
+			if (crc != je32_to_cpu (node->s.node_crc)) {
+				printf ("Wrong node_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.node_crc), crc);
+				p += PAD(je32_to_cpu (node->s.totlen));
+				dirty += PAD(je32_to_cpu (node->s.totlen));;
+				continue;
+			}
+
+			crc = crc32(0, p + sizeof (struct jffs2_summary_node),  je32_to_cpu (node->s.totlen) - sizeof(struct jffs2_summary_node));
+			if (crc != je32_to_cpu(node->s.sum_crc)) {
+				printf ("Wrong data_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.sum_crc), crc);
+				p += PAD(je32_to_cpu (node->s.totlen));
+				dirty += PAD(je32_to_cpu (node->s.totlen));;
+				continue;
+			}
+
+			if (verbose) {
+				void *sp;
+				sp = (p + sizeof(struct jffs2_summary_node));
+
+				for(i=0; i<je32_to_cpu(node->s.sum_num); i++) {
+
+					switch(je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
+						case JFFS2_NODETYPE_INODE : {
+
+							struct jffs2_sum_inode_flash *spi;
+							spi = sp;
+
+							printf ("%14s #ino  %5d,  version %5d, offset 0x%08x, totlen 0x%08x\n",
+							"",
+							je32_to_cpu (spi->inode),
+							je32_to_cpu (spi->version),
+							je32_to_cpu (spi->offset),
+							je32_to_cpu (spi->totlen));
+
+							sp += JFFS2_SUMMARY_INODE_SIZE;
+							break;
+						}
+
+						case JFFS2_NODETYPE_DIRENT : {
+
+							char name[255];
+							struct jffs2_sum_dirent_flash *spd;
+							spd = sp;
+
+							memcpy(name,spd->name,spd->nsize);
+							name [spd->nsize] = 0x0;
+
+							printf ("%14s dirent offset 0x%08x, totlen 0x%08x, #pino  %5d,  version %5d, #ino  %8d, nsize %8d, name %s \n",
+							"",
+							je32_to_cpu (spd->offset),
+							je32_to_cpu (spd->totlen),
+							je32_to_cpu (spd->pino),
+							je32_to_cpu (spd->version),
+							je32_to_cpu (spd->ino),
+							spd->nsize,
+							name);
+
+							sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
+							break;
+						}
+
+						default :
+							printf("Unknown summary node!\n");
+							break;
+					}
+				}
+
+				sm = (struct jffs2_sum_marker *) ((char *)p + je32_to_cpu(node->s.totlen) - sizeof(struct jffs2_sum_marker));
+
+				printf("%14s Sum Node Offset  0x%08x, Magic 0x%08x, Padded size 0x%08x\n",
+					"",
+					je32_to_cpu(sm->offset),
+					je32_to_cpu(sm->magic),
+					je32_to_cpu(node->s.padded));
+			}
+
+			p += PAD(je32_to_cpu (node->s.totlen));
+			break;
+		}
+
 		case JFFS2_NODETYPE_CLEANMARKER:
 			if (verbose) {
 				printf ("%8s Cleanmarker     at 0x%08x, totlen 0x%08x\n", 
@@ -435,7 +536,85 @@
 				
 			p += PAD(je32_to_cpu (node->u.totlen));						
 			break;
-	
+
+		case JFFS2_NODETYPE_SUMMARY : {
+			struct jffs2_sum_marker *sm_ptr;
+			int i,sum_len;
+			int counter = 0;
+
+			newnode.s.magic = cnv_e16 (node->s.magic);
+			newnode.s.nodetype = cnv_e16 (node->s.nodetype);
+			newnode.s.totlen = cnv_e32 (node->s.totlen);
+			newnode.s.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+			newnode.s.sum_num = cnv_e32 (node->s.sum_num);
+			newnode.s.cln_mkr = cnv_e32 (node->s.cln_mkr);
+			newnode.s.padded = cnv_e32 (node->s.padded);
+
+			newnode.s.node_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_summary_node) - 8));
+
+			// summary header
+			p += sizeof (struct jffs2_summary_node);
+
+			// summary data
+			sum_len = je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_summary_node) - sizeof (struct jffs2_sum_marker);
+
+			for (i=0; i<je32_to_cpu (node->s.sum_num); i++) {
+				union jffs2_sum_flash *fl_ptr;
+
+				fl_ptr = (union jffs2_sum_flash *) p;
+
+				switch (je16_to_cpu (fl_ptr->u.nodetype)) {
+					case JFFS2_NODETYPE_INODE:
+
+						fl_ptr->i.nodetype = cnv_e16 (fl_ptr->i.nodetype);
+						fl_ptr->i.inode = cnv_e32 (fl_ptr->i.inode);
+						fl_ptr->i.version = cnv_e32 (fl_ptr->i.version);
+						fl_ptr->i.offset = cnv_e32 (fl_ptr->i.offset);
+						fl_ptr->i.totlen = cnv_e32 (fl_ptr->i.totlen);
+						p += sizeof (struct jffs2_sum_inode_flash);
+						counter += sizeof (struct jffs2_sum_inode_flash);
+						break;
+
+					case JFFS2_NODETYPE_DIRENT:
+						fl_ptr->d.nodetype = cnv_e16 (fl_ptr->d.nodetype);
+						fl_ptr->d.totlen = cnv_e32 (fl_ptr->d.totlen);
+						fl_ptr->d.offset = cnv_e32 (fl_ptr->d.offset);
+						fl_ptr->d.pino = cnv_e32 (fl_ptr->d.pino);
+						fl_ptr->d.version = cnv_e32 (fl_ptr->d.version);
+						fl_ptr->d.ino = cnv_e32 (fl_ptr->d.ino);
+						p += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
+						counter += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
+						break;
+
+					default :
+						printf("Unknown node in summary information!!! nodetype(%x)\n", je16_to_cpu (fl_ptr->u.nodetype));
+						exit(EXIT_FAILURE);
+						break;
+				}
+
+			}
+
+			//pad
+			p += sum_len - counter;
+
+			// summary marker
+			sm_ptr = (struct jffs2_sum_marker *) p;
+			sm_ptr->offset = cnv_e32 (sm_ptr->offset);
+			sm_ptr->magic = cnv_e32 (sm_ptr->magic);
+			p += sizeof (struct jffs2_sum_marker);
+
+			// generate new crc on sum data
+			newnode.s.sum_crc = cpu_to_e32 ( crc32(0, ((char *) node) + sizeof (struct jffs2_summary_node), 
+				je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_summary_node)));
+
+			// write out new node header
+			write(fd, &newnode, sizeof (struct jffs2_summary_node));
+			// write out new summary data
+			write(fd, &node->s.sum, sum_len + sizeof (struct jffs2_sum_marker));
+
+			break;
+		}
+
 		case 0xffff:
 			write (fd, p, 4);
 			p += 4;





More information about the linux-mtd-cvs mailing list