mtd/fs/jffs2 scan.c,1.84,1.85

David Woodhouse dwmw2 at infradead.org
Thu Sep 5 09:16:17 EDT 2002


Update of /home/cvs/mtd/fs/jffs2
In directory phoenix.infradead.org:/tmp/cvs-serv2464

Modified Files:
	scan.c 
Log Message:
Attempt to use 'point' to access flash directly, where that's possible, 
instead of always copying into a RAM buffer. Doesn't seem to give me
any advantage on the 'mtdram' device, but hopefully it'll work on real 
flash where it is significantly slower than RAM. Others have reported good 
results with similar changes on real hardware.


Index: scan.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/scan.c,v
retrieving revision 1.84
retrieving revision 1.85
diff -u -r1.84 -r1.85
--- scan.c	3 Sep 2002 13:46:50 -0000	1.84
+++ scan.c	5 Sep 2002 13:16:14 -0000	1.85
@@ -17,6 +17,7 @@
 #include <linux/crc32.h>
 #include "nodelist.h"
 
+#define SCAN_READ_SIZE PAGE_SIZE
 
 #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
 		c->free_size -= _x; c->dirty_size += _x; \
@@ -39,15 +40,17 @@
 
 static uint32_t pseudo_random;
 
-static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+				  unsigned char *buf, int pointed);
 
 /* These helper functions _must_ increase ofs and also do the dirty/used space accounting. 
  * Returning an error will abort the mount - bad checksums etc. should just mark the space
  * as dirty.
  */
-static int jffs2_scan_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *ofs, int *noise);
-static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *ofs);
-static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *ofs);
+static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
+				 struct jffs2_raw_inode *ri, uint32_t ofs);
+static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+				 struct jffs2_raw_dirent *rd, uint32_t ofs);
 
 #define BLK_STATE_ALLFF		0
 #define BLK_STATE_CLEAN		1
@@ -60,15 +63,40 @@
 {
 	int i, ret;
 	uint32_t empty_blocks = 0, bad_blocks = 0;
+	unsigned char *pointbuf = NULL;
+	unsigned char *readbuf = NULL;
+	size_t pointlen;
 
 	if (!c->blocks) {
 		printk(KERN_WARNING "EEEK! c->blocks is NULL!\n");
 		return -EINVAL;
 	}
+	if (c->mtd->point) {
+		ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &pointbuf);
+		if (!ret && pointlen < c->mtd->size) {
+			/* Don't muck about if it won't let us point to the whole flash */
+			D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%x\n", pointlen));
+			c->mtd->unpoint(c->mtd, pointbuf);
+			pointbuf = NULL;
+		}
+		if (ret)
+			D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
+	}
+	if (!pointbuf) {
+		D1(printk(KERN_DEBUG "Allocating readbuf\n"));
+		readbuf = kmalloc(SCAN_READ_SIZE, GFP_KERNEL);
+		if (!readbuf)
+			return -ENOMEM;
+	}
+
 	for (i=0; i<c->nr_blocks; i++) {
 		struct jffs2_eraseblock *jeb = &c->blocks[i];
 
-		ret = jffs2_scan_eraseblock(c, jeb);
+		if (pointbuf)
+			ret = jffs2_scan_eraseblock(c, jeb, pointbuf + jeb->offset, 1);
+		else
+			ret = jffs2_scan_eraseblock(c, jeb, readbuf, 0);
+
 		if (ret < 0)
 			return ret;
 
@@ -201,14 +229,39 @@
 	return 0;
 }
 
-static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) {
-	struct jffs2_unknown_node node;
+static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf,
+				uint32_t ofs, uint32_t len)
+{
+	int ret;
+	size_t retlen;
+
+	ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
+	if (ret) {
+		D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", len, ofs, ret));
+		return ret;
+	}
+	if (retlen < len) {
+		D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%x bytes\n", ofs, retlen));
+		return -EIO;
+	}
+	D2(printk(KERN_DEBUG "Read 0x%x bytes from 0x%08x into buf\n", len, ofs));
+	D2(printk(KERN_DEBUG "000: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		  buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]));
+	return 0;
+}
+
+static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+				  unsigned char *buf, int pointed) {
+	struct jffs2_unknown_node *node;
+	struct jffs2_unknown_node crcnode;
 	uint32_t ofs, prevofs;
-	uint32_t hdr_crc, nodetype;
+	uint32_t hdr_crc, buf_ofs, buf_len;
 	int err;
 	int noise = 0;
+	int wasempty = 0;
+	uint32_t empty_start = 0;
 #ifdef CONFIG_JFFS2_FS_NAND
-	int cleanmarkerfound=0;
+	int cleanmarkerfound = 0;
 #endif
 
 	ofs = jeb->offset;
@@ -232,16 +285,28 @@
 		}
 	}
 #endif
-	err = jffs2_scan_empty(c, jeb, &ofs, &noise);
-	if (err)
-		return err;
+	buf_ofs = jeb->offset;
 
-	if (ofs == jeb->offset + c->sector_size) {
+	if (pointed) {
+		buf_len = c->sector_size;
+	} else {
+		buf_len = SCAN_READ_SIZE;
+		err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
+		if (err)
+			return err;
+	}
+	
+	/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
+	ofs = 0;
+	while(ofs < SCAN_READ_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
+		ofs += 4;
+
+	if (ofs == SCAN_READ_SIZE) {
 #ifdef CONFIG_JFFS2_FS_NAND
 		if (jffs2_cleanmarker_oob(c)) {
 			/* scan oob, take care of cleanmarker */
 			int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
-			D2(printk(KERN_NOTICE "jffs_check_oob_empty returned %d\n",ret));
+			D2(printk(KERN_NOTICE "jffs2_check_oob_empty returned %d\n",ret));
 			switch (ret) {
 			case 0:		return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
 			case 1: 	return BLK_STATE_ALLDIRTY;
@@ -254,11 +319,19 @@
 		D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
 		return BLK_STATE_ALLFF;	/* OK to erase if all blocks are like this */
 	}
-	
+	if (ofs) {
+		D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
+			  jeb->offset + ofs));
+		DIRTY_SPACE(ofs);
+	}
+
+	/* Now ofs is a complete physical flash offset as it always was... */
+	ofs += jeb->offset;
+
 	noise = 10;
 
 	while(ofs < jeb->offset + c->sector_size) {
-		size_t retlen;
+
 		ACCT_PARANOIA_CHECK(jeb);
 
 		cond_resched();
@@ -275,121 +348,165 @@
 			continue;
 		}
 		prevofs = ofs;
-		
-		if (jeb->offset + c->sector_size < ofs + sizeof(node)) {
-			D1(printk(KERN_DEBUG "Fewer than %d bytes left to end of block. Not reading\n", sizeof(struct jffs2_unknown_node)));
+
+		/* FIXME: Maybe in a separate function or macro 'check_read_buf'... */
+		if (jeb->offset + c->sector_size < ofs + sizeof(*node)) {
+			D1(printk(KERN_DEBUG "Fewer than %d bytes left to end of block. (%x+%x<%x+%x) Not reading\n", sizeof(struct jffs2_unknown_node),
+				  jeb->offset, c->sector_size, ofs, sizeof(*node)));
 			DIRTY_SPACE((jeb->offset + c->sector_size)-ofs);
 			break;
 		}
 
-		err = jffs2_flash_read(c, ofs, sizeof(node), &retlen, (char *)&node);
-		if (err) {
-			D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", sizeof(node), ofs, err));
-			return err;
-		}
-		if (retlen < sizeof(node)) {
-			D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%x bytes\n", ofs, retlen));
-			DIRTY_SPACE(retlen);
-			ofs += retlen;
-			continue;
-		}
+		if (buf_ofs + buf_len < ofs + sizeof(*node)) {
+			buf_len = min_t(uint32_t, SCAN_READ_SIZE, jeb->offset + c->sector_size - ofs);
+			D1(printk(KERN_DEBUG "Fewer than %d bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n",
+				  sizeof(struct jffs2_unknown_node), buf_len, ofs));
+			err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
+			if (err)
+				return err;
+			buf_ofs = ofs;
+		}
+		/* ... to here */
+		node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];
+
+		if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
+			uint32_t inbuf_ofs = ofs - buf_ofs + 4;
+			empty_start = ofs;
+			ofs += 4;
 
-		if (je16_to_cpu(node.magic) == JFFS2_EMPTY_BITMASK && 
-		    je16_to_cpu(node.nodetype) == JFFS2_EMPTY_BITMASK) {
-			D1(printk(KERN_DEBUG "Found empty flash at 0x%x\n", ofs));
-			err = jffs2_scan_empty(c, jeb, &ofs, &noise);
-			if (err) return err;
+			D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
+			while (inbuf_ofs < buf_len) {
+				if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)
+					goto emptyends;
+
+				inbuf_ofs+=4;
+				ofs += 4;
+			}
+			/* Ran off end. */
+			D1(printk(KERN_DEBUG "Empty flash ends normally at 0x%08x\n", ofs));
+
+			if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && 
+			    !jeb->first_node->next_in_ino && !jeb->dirty_size)
+				return BLK_STATE_CLEANMARKER;
+			wasempty = 1;
+			continue;
+		} else if (wasempty) {
+		emptyends:
+			printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n", empty_start, ofs);
+			DIRTY_SPACE(ofs-empty_start);
+			wasempty = 0;
 			continue;
 		}
 
-		if (ofs == jeb->offset && je16_to_cpu(node.magic) == KSAMTIB_CIGAM_2SFFJ) {
+		if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
 			printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs);
 			DIRTY_SPACE(4);
 			ofs += 4;
 			continue;
 		}
-		if (je16_to_cpu(node.magic) == JFFS2_DIRTY_BITMASK) {
+		if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) {
 			D1(printk(KERN_DEBUG "Empty bitmask at 0x%08x\n", ofs));
 			DIRTY_SPACE(4);
 			ofs += 4;
 			continue;
 		}
-		if (je16_to_cpu(node.magic) == JFFS2_OLD_MAGIC_BITMASK) {
+		if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) {
 			printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs);
 			printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n");
 			DIRTY_SPACE(4);
 			ofs += 4;
 			continue;
 		}
-		if (je16_to_cpu(node.magic) != JFFS2_MAGIC_BITMASK) {
+		if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) {
 			/* OK. We're out of possibilities. Whinge and move on */
 			noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", 
 				     JFFS2_MAGIC_BITMASK, ofs, 
-				     je16_to_cpu(node.magic));
+				     je16_to_cpu(node->magic));
 			DIRTY_SPACE(4);
 			ofs += 4;
 			continue;
 		}
 		/* We seem to have a node of sorts. Check the CRC */
-		nodetype = je16_to_cpu(node.nodetype);
-		node.nodetype = cpu_to_je16(nodetype | JFFS2_NODE_ACCURATE);
-
-		hdr_crc = crc32(0, &node, sizeof(node)-4);
+		crcnode.magic = node->magic;
+		crcnode.nodetype = cpu_to_je16( je16_to_cpu(node->nodetype) | JFFS2_NODE_ACCURATE);
+		crcnode.totlen = node->totlen;
+		hdr_crc = crc32(0, &crcnode, sizeof(crcnode)-4);
 
-		node.nodetype = cpu_to_je16(nodetype);
-
-		if (hdr_crc != je32_to_cpu(node.hdr_crc)) {
+		if (hdr_crc != je32_to_cpu(node->hdr_crc)) {
 			noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n",
-				     ofs, je16_to_cpu(node.magic),
-				     je16_to_cpu(node.nodetype), 
-				     je32_to_cpu(node.totlen),
-				     je32_to_cpu(node.hdr_crc),
+				     ofs, je16_to_cpu(node->magic),
+				     je16_to_cpu(node->nodetype), 
+				     je32_to_cpu(node->totlen),
+				     je32_to_cpu(node->hdr_crc),
 				     hdr_crc);
 			DIRTY_SPACE(4);
 			ofs += 4;
 			continue;
 		}
 
-		if (ofs + je32_to_cpu(node.totlen) > 
+		if (ofs + je32_to_cpu(node->totlen) > 
 		    jeb->offset + c->sector_size) {
 			/* Eep. Node goes over the end of the erase block. */
 			printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
-			       ofs, je32_to_cpu(node.totlen));
+			       ofs, je32_to_cpu(node->totlen));
 			printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n");
 			DIRTY_SPACE(4);
 			ofs += 4;
 			continue;
 		}
 
-		if (!(je16_to_cpu(node.nodetype) & JFFS2_NODE_ACCURATE)) {
+		if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) {
 			/* Wheee. This is an obsoleted node */
 			D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs));
-			DIRTY_SPACE(PAD(je32_to_cpu(node.totlen)));
-			ofs += PAD(je32_to_cpu(node.totlen));
+			DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
+			ofs += PAD(je32_to_cpu(node->totlen));
 			continue;
 		}
 
-		switch(je16_to_cpu(node.nodetype)) {
+		switch(je16_to_cpu(node->nodetype)) {
 		case JFFS2_NODETYPE_INODE:
-			err = jffs2_scan_inode_node(c, jeb, &ofs);
+			if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) {
+				buf_len = min_t(uint32_t, SCAN_READ_SIZE, jeb->offset + c->sector_size - ofs);
+				D1(printk(KERN_DEBUG "Fewer than %d bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
+					  sizeof(struct jffs2_raw_inode), buf_len, ofs));
+				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
+				if (err)
+					return err;
+				buf_ofs = ofs;
+				node = (void *)buf;
+			}
+			err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs);
 			if (err) return err;
+			ofs += PAD(je32_to_cpu(node->totlen));
 			break;
 			
 		case JFFS2_NODETYPE_DIRENT:
-			err = jffs2_scan_dirent_node(c, jeb, &ofs);
+			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
+				buf_len = min_t(uint32_t, SCAN_READ_SIZE, jeb->offset + c->sector_size - ofs);
+				D1(printk(KERN_DEBUG "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n",
+					  je32_to_cpu(node->totlen), buf_len, ofs));
+				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
+				if (err)
+					return err;
+				buf_ofs = ofs;
+				node = (void *)buf;
+			}
+			err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs);
 			if (err) return err;
+			ofs += PAD(je32_to_cpu(node->totlen));
 			break;
 
 		case JFFS2_NODETYPE_CLEANMARKER:
-			if (je32_to_cpu(node.totlen) != c->cleanmarker_size) {
+			D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
+			if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
 				printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n", 
-				       ofs, je32_to_cpu(node.totlen), c->cleanmarker_size);
+				       ofs, je32_to_cpu(node->totlen), c->cleanmarker_size);
 				DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
+				ofs += PAD(sizeof(struct jffs2_unknown_node));
 			} else if (jeb->first_node) {
 				printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset);
 				DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
 				ofs += PAD(sizeof(struct jffs2_unknown_node));
-				continue;
 			} else {
 				struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
 				if (!marker_ref) {
@@ -399,44 +516,44 @@
 				marker_ref->next_in_ino = NULL;
 				marker_ref->next_phys = NULL;
 				marker_ref->flash_offset = ofs;
-				marker_ref->totlen = sizeof(struct jffs2_unknown_node);
+				marker_ref->totlen = c->cleanmarker_size;
 				jeb->first_node = jeb->last_node = marker_ref;
 			     
-				USED_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
+				USED_SPACE(PAD(c->cleanmarker_size));
+				ofs += PAD(c->cleanmarker_size);
 			}
-			ofs += PAD(sizeof(struct jffs2_unknown_node));
 			break;
 
 		case JFFS2_NODETYPE_PADDING:
-			DIRTY_SPACE(PAD(je32_to_cpu(node.totlen)));
-			ofs += PAD(je32_to_cpu(node.totlen));
+			DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
+			ofs += PAD(je32_to_cpu(node->totlen));
 			break;
 
 		default:
-			switch (je16_to_cpu(node.nodetype) & JFFS2_COMPAT_MASK) {
+			switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) {
 			case JFFS2_FEATURE_ROCOMPAT:
-				printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node.nodetype), ofs);
+				printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
 			        c->flags |= JFFS2_SB_FLAG_RO;
 				if (!(jffs2_is_readonly(c)))
 					return -EROFS;
-				DIRTY_SPACE(PAD(je32_to_cpu(node.totlen)));
-				ofs += PAD(je32_to_cpu(node.totlen));
+				DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
+				ofs += PAD(je32_to_cpu(node->totlen));
 				break;
 
 			case JFFS2_FEATURE_INCOMPAT:
-				printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node.nodetype), ofs);
+				printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
 				return -EINVAL;
 
 			case JFFS2_FEATURE_RWCOMPAT_DELETE:
-				D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node.nodetype), ofs));
-				DIRTY_SPACE(PAD(je32_to_cpu(node.totlen)));
-				ofs += PAD(je32_to_cpu(node.totlen));
+				D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
+				DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
+				ofs += PAD(je32_to_cpu(node->totlen));
 				break;
 
 			case JFFS2_FEATURE_RWCOMPAT_COPY:
-				D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node.nodetype), ofs));
-				USED_SPACE(PAD(je32_to_cpu(node.totlen)));
-				ofs += PAD(je32_to_cpu(node.totlen));
+				D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
+				USED_SPACE(PAD(je32_to_cpu(node->totlen)));
+				ofs += PAD(je32_to_cpu(node->totlen));
 				break;
 			}
 		}
@@ -454,7 +571,7 @@
 		jeb->wasted_size = 0;
 	}
 
-	if (jeb->used_size == PAD(sizeof(struct jffs2_unknown_node)) && 
+	if (jeb->used_size == PAD(c->cleanmarker_size) && 
 	    !jeb->first_node->next_in_ino && !jeb->dirty_size)
 		return BLK_STATE_CLEANMARKER;
 	/* move blocks with max 4 byte dirty space to cleanlist */	
@@ -470,53 +587,6 @@
 		return BLK_STATE_ALLDIRTY;
 }
 
-/* We're pointing at the first empty word on the flash. Scan and account for the whole dirty region */
-static int jffs2_scan_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *startofs, int *noise)
-{
-	uint32_t *buf;
-	uint32_t scanlen = (jeb->offset + c->sector_size) - *startofs;
-	uint32_t curofs = *startofs;
-	
-	buf = kmalloc(min((uint32_t)PAGE_SIZE, scanlen), GFP_KERNEL);
-	if (!buf) {
-		printk(KERN_WARNING "Scan buffer allocation failed\n");
-		return -ENOMEM;
-	}
-	while(scanlen) {
-		size_t retlen;
-		int ret, i;
-		
-		ret = jffs2_flash_read(c, curofs, min((uint32_t)PAGE_SIZE, scanlen), &retlen, (char *)buf);
-		if (ret) {
-			D1(printk(KERN_WARNING "jffs2_scan_empty(): Read 0x%x bytes at 0x%08x returned %d\n", min((uint32_t)PAGE_SIZE, scanlen), curofs, ret));
-			kfree(buf);
-			return ret;
-		}
-		if (retlen < 4) {
-			D1(printk(KERN_WARNING "Eep. too few bytes read in scan_empty()\n"));
-			kfree(buf);
-			return -EIO;
-		}
-		for (i=0; i<(retlen / 4); i++) {
-			if (buf[i] != 0xffffffff) {
-				curofs += i*4;
-				noisy_printk(noise, "jffs2_scan_empty(): Empty block at 0x%08x ends at 0x%08x (with 0x%08x)! Marking dirty\n", *startofs, curofs, buf[i]);
-				DIRTY_SPACE(curofs - (*startofs));
-				*startofs = curofs;
-				kfree(buf);
-				return 0;
-			}
-		}
-		scanlen -= retlen&~3;
-		curofs += retlen&~3;
-	}
-
-	D1(printk(KERN_DEBUG "Empty flash detected from 0x%08x to 0x%08x\n", *startofs, curofs));
-	kfree(buf);
-	*startofs = curofs;
-	return 0;
-}
-
 static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
 {
 	struct jffs2_inode_cache *ic;
@@ -546,82 +616,82 @@
 	return ic;
 }
 
-static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *ofs)
+static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
+				 struct jffs2_raw_inode *ri, uint32_t ofs)
 {
 	struct jffs2_raw_node_ref *raw;
 	struct jffs2_full_dnode *fn;
 	struct jffs2_tmp_dnode_info *tn, **tn_list;
 	struct jffs2_inode_cache *ic;
-	struct jffs2_raw_inode ri;
+	uint32_t dsize, csize;
 	uint32_t crc;
-	uint16_t oldnodetype;
 	int ret;
-	size_t retlen;
-
-	D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", *ofs));
 
-	ret = jffs2_flash_read(c, *ofs, sizeof(ri), &retlen, (char *)&ri);
-	if (ret) {
-		printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs, ret);
-		return ret;
-	}
-	if (retlen != sizeof(ri)) {
-		printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", 
-		       retlen, *ofs, sizeof(ri));
-		return -EIO;
-	}
+	D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs));
 
-	/* We sort of assume that the node was accurate when it was 
-	   first written to the medium :) */
-	oldnodetype = je16_to_cpu(ri.nodetype);
-	ri.nodetype = cpu_to_je16(oldnodetype | JFFS2_NODE_ACCURATE);
-	crc = crc32(0, &ri, sizeof(ri)-8);
-	ri.nodetype = cpu_to_je16(oldnodetype);
+	/* FIXME: Actually we don't need to do all this here. We can just make a raw_node_ref for it,
+	   and file it against ri->inode. We don't even need to check the CRC. If the CRC is valid,
+	   all was well, if the CRC was _invalid_, we're gonna drop it when we find out anyway, so
+	   it doesn't matter which inode it was filed against. Of course we have to go through and
+	   do the CRC checks for each inode some time later, but we don't have to hold up the mount
+	   for it.
+
+	   Hmm, perhaps we'd want to do the CRC check if there's not already an inocache for the inode
+	   we think it belongs to, to prevent us from ending up creating an inocache for ino #0xFFFFFFFF
+	   if that's what we see on the flash.
+	*/
+	   
+
+	/* We don't get here unless the node is still valid, so we don't have to
+	   mask in the ACCURATE bit any more. */
+	crc = crc32(0, ri, sizeof(*ri)-8);
 
-	if(crc != je32_to_cpu(ri.node_crc)) {
+	if(crc != je32_to_cpu(ri->node_crc)) {
 		printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-		       *ofs, je32_to_cpu(ri.node_crc), crc);
-		/* FIXME: Why do we believe totlen? */
-		DIRTY_SPACE(4);
-		*ofs += 4;
+		       ofs, je32_to_cpu(ri->node_crc), crc);
+		/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
+		DIRTY_SPACE(PAD(je32_to_cpu(ri->totlen)));
 		return 0;
 	}
 	/* There was a bug where we wrote hole nodes out with csize/dsize
 	   swapped. Deal with it */
-	if (ri.compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri.dsize) && je32_to_cpu(ri.csize)) {
-		ri.dsize = ri.csize;
-		ri.csize = cpu_to_je32(0);
+	if (unlikely(ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) && je32_to_cpu(ri->csize))) {
+		dsize = je32_to_cpu(ri->csize);
+		csize = 0;
+	} else {
+		csize = je32_to_cpu(ri->csize);
+		dsize = je32_to_cpu(ri->dsize);
 	}
 
-	if (je32_to_cpu(ri.csize)) {
+	if (csize) {
 		/* Check data CRC too */
 		unsigned char *dbuf;
 		uint32_t crc;
+		size_t retlen;
 
 		dbuf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
 		if (!dbuf) {
 			printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of temporary data buffer for CRC check failed\n");
 			return -ENOMEM;
 		}
-		ret = jffs2_flash_read(c, *ofs+sizeof(ri), je32_to_cpu(ri.csize), &retlen, dbuf);
+		ret = jffs2_flash_read(c, ofs+sizeof(*ri), csize, &retlen, dbuf);
 		if (ret) {
-			printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs+sizeof(ri), ret);
+			printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", ofs+sizeof(*ri), ret);
 			kfree(dbuf);
 			return ret;
 		}
-		if (retlen != je32_to_cpu(ri.csize)) {
+		if (retlen != csize) {
 			printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", 
-			       retlen, *ofs+ sizeof(ri), je32_to_cpu(ri.csize));
+			       retlen, ofs+sizeof(*ri), csize);
 			kfree(dbuf);
 			return -EIO;
 		}
-		crc = crc32(0, dbuf, je32_to_cpu(ri.csize));
+		crc = crc32(0, dbuf, csize);
 		kfree(dbuf);
-		if (crc != je32_to_cpu(ri.data_crc)) {
+		if (crc != je32_to_cpu(ri->data_crc)) {
 			printk(KERN_NOTICE "jffs2_scan_inode_node(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-			       *ofs, je32_to_cpu(ri.data_crc), crc);
-			DIRTY_SPACE(PAD(je32_to_cpu(ri.totlen)));
-			*ofs += PAD(je32_to_cpu(ri.totlen));
+			       ofs, je32_to_cpu(ri->data_crc), crc);
+			DIRTY_SPACE(PAD(je32_to_cpu(ri->totlen)));
 			return 0;
 		}
 	}
@@ -643,7 +713,7 @@
 		jffs2_free_raw_node_ref(raw);
 		return -ENOMEM;
 	}
-	ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(ri.ino));
+	ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(ri->ino));
 	if (!ic) {
 		jffs2_free_full_dnode(fn);
 		jffs2_free_tmp_dnode_info(tn);
@@ -652,8 +722,8 @@
 	}
 
 	/* Build the data structures and file them for later */
-	raw->flash_offset = *ofs;
-	raw->totlen = PAD(je32_to_cpu(ri.totlen));
+	raw->flash_offset = ofs;
+	raw->totlen = PAD(je32_to_cpu(ri->totlen));
 	raw->next_phys = NULL;
 	raw->next_in_ino = ic->nodes;
 	ic->nodes = raw;
@@ -664,153 +734,118 @@
 	jeb->last_node = raw;
 
 	D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", 
-		  je32_to_cpu(ri.ino), je32_to_cpu(ri.version),
-		  je32_to_cpu(ri.offset),
-		  je32_to_cpu(ri.offset)+je32_to_cpu(ri.dsize)));
+		  je32_to_cpu(ri->ino), je32_to_cpu(ri->version),
+		  je32_to_cpu(ri->offset),
+		  je32_to_cpu(ri->offset)+dsize));
 
-	pseudo_random += je32_to_cpu(ri.version);
+	pseudo_random += je32_to_cpu(ri->version);
 
 	for (tn_list = &ic->scan->tmpnodes; *tn_list; tn_list = &((*tn_list)->next)) {
-		if ((*tn_list)->version < je32_to_cpu(ri.version))
+		if ((*tn_list)->version < je32_to_cpu(ri->version))
 			continue;
-		if ((*tn_list)->version > je32_to_cpu(ri.version)) 
+		if ((*tn_list)->version > je32_to_cpu(ri->version)) 
 			break;
 		/* Wheee. We've found another instance of the same version number.
 		   We should obsolete one of them. 
 		*/
 		D1(printk(KERN_DEBUG "Duplicate version %d found in ino #%u. Previous one is at 0x%08x\n",
-			  je32_to_cpu(ri.version), ic->ino,
+			  je32_to_cpu(ri->version), ic->ino,
 			  (*tn_list)->fn->raw->flash_offset &~3));
 		if (!jeb->used_size) {
 			D1(printk(KERN_DEBUG "No valid nodes yet found in this eraseblock 0x%08x, so obsoleting the new instance at 0x%08x\n", 
 				  jeb->offset, raw->flash_offset & ~3));
-			/* XXX FIXME: This is now ugly */
-			ri.nodetype = cpu_to_je16(je16_to_cpu(ri.nodetype) & ~JFFS2_NODE_ACCURATE);
+			jffs2_free_full_dnode(fn);
+			jffs2_free_tmp_dnode_info(tn);
+			raw->flash_offset |= 1;
+			DIRTY_SPACE(PAD(je32_to_cpu(ri->totlen)));
 			/* Perhaps we could also mark it as such on the medium. Maybe later */
+			return 0;
 		}
 		break;
 	}
 
-	if (je16_to_cpu(ri.nodetype) & JFFS2_NODE_ACCURATE) {
-
-		/* Only do fraglist truncation in pass1 for S_IFREG inodes */
-		if (S_ISREG(je32_to_cpu(ri.mode)) && ic->scan->version < je32_to_cpu(ri.version)) {
-			ic->scan->version = je32_to_cpu(ri.version);
-			ic->scan->isize = je32_to_cpu(ri.isize);
-		}
-
-		memset(fn,0,sizeof(*fn));
-
-		fn->ofs = je32_to_cpu(ri.offset);
-		fn->size = je32_to_cpu(ri.dsize);
-		fn->frags = 0;
-		fn->raw = raw;
-
-		tn->next = NULL;
-		tn->fn = fn;
-		tn->version = je32_to_cpu(ri.version);
-
-		USED_SPACE(PAD(je32_to_cpu(ri.totlen)));
-
-		/* No need to scan from the beginning of the list again. 
-		   We can start from tn_list instead (Thanks Jocke) */
-		jffs2_add_tn_to_list(tn, tn_list);
-
-		/* Make sure the one we just added is the _last_ in the list
-		   with this version number, so the older ones get obsoleted */
-		while (tn->next && tn->next->version == tn->version) {
-
-			D1(printk(KERN_DEBUG "Shifting new node at 0x%08x after other node at 0x%08x for version %d in list\n",
-				  fn->raw->flash_offset&~3, 
-				  tn->next->fn->raw->flash_offset &~3,
-				  je32_to_cpu(ri.version)));
+	/* Only do fraglist truncation in pass1 for S_IFREG inodes */
+	if (S_ISREG(je32_to_cpu(ri->mode)) && ic->scan->version < je32_to_cpu(ri->version)) {
+		ic->scan->version = je32_to_cpu(ri->version);
+		ic->scan->isize = je32_to_cpu(ri->isize);
+	}
+
+	memset(fn,0,sizeof(*fn));
+
+	fn->ofs = je32_to_cpu(ri->offset);
+	fn->size = dsize;
+	fn->frags = 0;
+	fn->raw = raw;
+
+	tn->next = NULL;
+	tn->fn = fn;
+	tn->version = je32_to_cpu(ri->version);
+
+	USED_SPACE(PAD(je32_to_cpu(ri->totlen)));
+
+	/* No need to scan from the beginning of the list again. 
+	   We can start from tn_list instead (Thanks Jocke) */
+	jffs2_add_tn_to_list(tn, tn_list);
+
+	/* Make sure the one we just added is the _last_ in the list
+	   with this version number, so the older ones get obsoleted */
+	while (tn->next && tn->next->version == tn->version) {
+
+		D1(printk(KERN_DEBUG "Shifting new node at 0x%08x after other node at 0x%08x for version %d in list\n",
+			  fn->raw->flash_offset&~3, 
+			  tn->next->fn->raw->flash_offset &~3,
+			  je32_to_cpu(ri->version)));
+
+		if(tn->fn != fn)
+			BUG();
+		tn->fn = tn->next->fn;
+		tn->next->fn = fn;
+		tn = tn->next;
+	}
 
-			if(tn->fn != fn)
-				BUG();
-			tn->fn = tn->next->fn;
-			tn->next->fn = fn;
-			tn = tn->next;
-		}
-	} else {
-		jffs2_free_full_dnode(fn);
-		jffs2_free_tmp_dnode_info(tn);
-		raw->flash_offset |= 1;
-		DIRTY_SPACE(PAD(je32_to_cpu(ri.totlen)));
-	}		
-	*ofs += PAD(je32_to_cpu(ri.totlen));
 	return 0;
 }
 
-static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *ofs)
+static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
+				  struct jffs2_raw_dirent *rd, uint32_t ofs)
 {
 	struct jffs2_raw_node_ref *raw;
 	struct jffs2_full_dirent *fd;
 	struct jffs2_inode_cache *ic;
-	struct jffs2_raw_dirent rd;
-	uint16_t oldnodetype;
-	int ret;
 	uint32_t crc;
-	size_t retlen;
 
-	D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", *ofs));
+	D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", ofs));
 
-	ret = jffs2_flash_read(c, *ofs, sizeof(rd), &retlen, (char *)&rd);
-	if (ret) {
-		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n", *ofs, ret);
-		return ret;
-	}
-	if (retlen != sizeof(rd)) {
-		printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", 
-		       retlen, *ofs, sizeof(rd));
-		return -EIO;
-	}
-
-	/* We sort of assume that the node was accurate when it was 
-	   first written to the medium :) */
-	oldnodetype = je16_to_cpu(rd.nodetype);
-	rd.nodetype = cpu_to_je16(oldnodetype | JFFS2_NODE_ACCURATE);
-	crc = crc32(0, &rd, sizeof(rd)-8);
-	rd.nodetype = cpu_to_je16(oldnodetype);
+	/* We don't get here unless the node is still valid, so we don't have to
+	   mask in the ACCURATE bit any more. */
+	crc = crc32(0, rd, sizeof(*rd)-8);
 
-	if (crc != je32_to_cpu(rd.node_crc)) {
+	if (crc != je32_to_cpu(rd->node_crc)) {
 		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-		       *ofs, je32_to_cpu(rd.node_crc), crc);
-		/* NB: We don't believe totlen. */
-		DIRTY_SPACE(4);
-		*ofs += 4;
+		       ofs, je32_to_cpu(rd->node_crc), crc);
+		/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
+		DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen)));
 		return 0;
 	}
 
-	pseudo_random += je32_to_cpu(rd.version);
+	pseudo_random += je32_to_cpu(rd->version);
 
-	fd = jffs2_alloc_full_dirent(rd.nsize+1);
+	fd = jffs2_alloc_full_dirent(rd->nsize+1);
 	if (!fd) {
 		return -ENOMEM;
 	}
-	ret = jffs2_flash_read(c, *ofs + sizeof(rd), rd.nsize, &retlen, &fd->name[0]);
-	if (ret) {
-		jffs2_free_full_dirent(fd);
-		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n", 
-		       *ofs + sizeof(rd), ret);
-		return ret;
-	}
-	if (retlen != rd.nsize) {
-		jffs2_free_full_dirent(fd);
-		printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", 
-		       retlen, *ofs + sizeof(rd), rd.nsize);
-		return -EIO;
-	}
+	memcpy(&fd->name, rd->name, rd->nsize);
+	fd->name[rd->nsize] = 0;
 
-	crc = crc32(0, fd->name, rd.nsize);
-	if (crc != je32_to_cpu(rd.name_crc)) {
+	crc = crc32(0, fd->name, rd->nsize);
+	if (crc != je32_to_cpu(rd->name_crc)) {
 		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-		       *ofs, je32_to_cpu(rd.name_crc), crc);	
-		fd->name[rd.nsize]=0;
-		D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd.ino)));
+		       ofs, je32_to_cpu(rd->name_crc), crc);	
+		D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino)));
 		jffs2_free_full_dirent(fd);
 		/* FIXME: Why do we believe totlen? */
-		DIRTY_SPACE(PAD(je32_to_cpu(rd.totlen)));
-		*ofs += PAD(je32_to_cpu(rd.totlen));
+		/* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */
+		DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen)));
 		return 0;
 	}
 	raw = jffs2_alloc_raw_node_ref();
@@ -819,15 +854,15 @@
 		printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n");
 		return -ENOMEM;
 	}
-	ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd.pino));
+	ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino));
 	if (!ic) {
 		jffs2_free_full_dirent(fd);
 		jffs2_free_raw_node_ref(raw);
 		return -ENOMEM;
 	}
 	
-	raw->totlen = PAD(je32_to_cpu(rd.totlen));
-	raw->flash_offset = *ofs;
+	raw->totlen = PAD(je32_to_cpu(rd->totlen));
+	raw->flash_offset = ofs;
 	raw->next_phys = NULL;
 	raw->next_in_ino = ic->nodes;
 	ic->nodes = raw;
@@ -837,22 +872,15 @@
 		jeb->last_node->next_phys = raw;
 	jeb->last_node = raw;
 
-	if (je16_to_cpu(rd.nodetype) & JFFS2_NODE_ACCURATE) {
-		fd->raw = raw;
-		fd->next = NULL;
-		fd->version = je32_to_cpu(rd.version);
-		fd->ino = je32_to_cpu(rd.ino);
-		fd->name[rd.nsize]=0;
-		fd->nhash = full_name_hash(fd->name, rd.nsize);
-		fd->type = rd.type;
-		USED_SPACE(PAD(je32_to_cpu(rd.totlen)));
-		jffs2_add_fd_to_list(c, fd, &ic->scan->dents);
-	} else {
-		raw->flash_offset |= 1;
-		jffs2_free_full_dirent(fd);
-		DIRTY_SPACE(PAD(je32_to_cpu(rd.totlen)));
-	} 
-	*ofs += PAD(je32_to_cpu(rd.totlen));
+	fd->raw = raw;
+	fd->next = NULL;
+	fd->version = je32_to_cpu(rd->version);
+	fd->ino = je32_to_cpu(rd->ino);
+	fd->nhash = full_name_hash(fd->name, rd->nsize);
+	fd->type = rd->type;
+	USED_SPACE(PAD(je32_to_cpu(rd->totlen)));
+	jffs2_add_fd_to_list(c, fd, &ic->scan->dents);
+
 	return 0;
 }
 





More information about the linux-mtd-cvs mailing list