changeset 182:ebfd69da1173

Adding checkpoint and robustness improvements
author charles
date Tue, 15 May 2007 21:07:40 +0100
parents 7bdee2571f8f
children 95de003f27dc
files direct/dtest.c direct/yaffscfg.c direct/yaffscfg2k.c direct/ydirectenv.h yaffs_checkptrw.c yaffs_checkptrw.h yaffs_fs.c yaffs_guts.c yaffs_guts.h yportenv.h
diffstat 10 files changed, 1271 insertions(+), 204 deletions(-) [+]
line wrap: on
line diff
--- a/direct/dtest.c
+++ b/direct/dtest.c
@@ -2127,6 +2127,107 @@ void huge_array_test(const char *mountpt
 		   
 	}
 }
+
+
+void random_write(int h)
+{
+	static char buffer[12000];
+	int n;
+	
+	n = random() & 0x1FFF;
+	yaffs_write(h,buffer,n);
+}
+
+void random_seek(int h)
+{
+	int n;
+	n = random() & 0xFFFFF;
+	yaffs_lseek(h,n,SEEK_SET);
+}
+
+void random_truncate(int h, char * name)
+{
+	int n;
+	int flen;
+	n = random() & 0xFFFFF;
+	flen = yaffs_lseek(h,0,SEEK_END);
+	if(n > flen)
+		n = flen / 2;
+	yaffs_truncate(name,n);
+	yaffs_lseek(h,n,SEEK_SET);
+}
+
+
+#define NSMALLFILES 10	
+void random_small_file_test(const char *mountpt,int iterations)
+{
+
+	char a[NSMALLFILES][50];
+
+	
+	int i;
+	int n;
+	int j;
+	int h[NSMALLFILES];
+	int r;
+	int fnum;
+	
+	
+	yaffs_StartUp();
+
+	yaffs_mount(mountpt);
+	
+	for(i = 0; i < NSMALLFILES; i++){
+		h[i]=-1;
+		strcpy(a[i],"");
+	}
+	
+	for(n = 0; n < iterations; n++){
+				
+		for(i = 0; i < NSMALLFILES; i++) {
+			r = random();
+			
+			if(strlen(a[i]) == 0){
+				sprintf(a[i],"%s/%dx%d",mountpt,n,i);
+				h[i] = yaffs_open(a,O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
+			}
+			
+			if(h[i] < -1)
+				printf("Could not open yaffs file %d %d error %d\n",n,i,h[i]);
+			else {
+				r = r & 7;
+				switch(r){
+					case 0:
+					case 1:
+					case 2:
+						random_write(h[i]);
+						break;
+					case 3:
+						random_truncate(h[i],a[i]);
+						break;
+					case 4:
+					case 5:	random_seek(h[i]);
+						break;
+					case 6:
+						yaffs_close(h[i]);
+						h[i] = -1;
+						break;
+					case 7:
+						yaffs_close(h[i]);
+						yaffs_unlink(a[i]);
+						strcpy(a[i],"");
+						h[i] = -1;
+				}
+			}
+		}
+		   
+	}
+	
+	for(i = 0; i < NSMALLFILES; i++)
+		yaffs_close(h[i]);
+		
+	yaffs_unmount(mountpt);
+}
 	
 
 
@@ -2147,9 +2248,9 @@ int main(int argc, char *argv[])
 	 //scan_pattern_test("/flash",10000,10);
 	//short_scan_test("/flash/flash",40000,200);
 	  //small_mount_test("/flash/flash",1000);
-	  small_overwrite_test("/flash/flash",1000);
-	 //checkpoint_fill_test("/flash/flash",20);
-	 //checkpoint_upgrade_test("/flash/flash",20);
+	  //small_overwrite_test("/flash/flash",1000);
+	  //checkpoint_fill_test("/flash/flash",20);
+	 random_small_file_test("/flash/flash",10000);
 	 // huge_array_test("/flash/flash",10);
 
 
--- a/direct/yaffscfg.c
+++ b/direct/yaffscfg.c
@@ -44,6 +44,16 @@ void yaffsfs_Unlock(void)
 	return 0;
 }
 
+void *yaffs_malloc(size_t size)
+{
+	return malloc(size);
+}
+
+void yaffs_free(void *ptr)
+{
+	free(ptr);
+}
+
 void yaffsfs_LocalInitialisation(void)
 {
 	// Define locking semaphore.
--- a/direct/yaffscfg2k.c
+++ b/direct/yaffscfg2k.c
@@ -29,11 +29,14 @@ unsigned yaffs_traceMask =
 
 	YAFFS_TRACE_SCAN |  
 	YAFFS_TRACE_GC | YAFFS_TRACE_GC_DETAIL | 
-	YAFFS_TRACE_WRITE  | YAFFS_TRACE_ERASE | 
+	YAFFS_TRACE_ERASE | 
 	YAFFS_TRACE_TRACING | 
 	YAFFS_TRACE_ALLOCATE | 
 	YAFFS_TRACE_CHECKPOINT |
 	YAFFS_TRACE_BAD_BLOCKS |
+	YAFFS_TRACE_VERIFY |
+	YAFFS_TRACE_VERIFY_NAND |
+	YAFFS_TRACE_VERIFY_FULL |
 //	(~0) |
 	
 	0;
@@ -59,6 +62,30 @@ void yaffsfs_Unlock(void)
 	return 0;
 }
 
+
+static int yaffs_kill_alloc = 0;
+static size_t total_malloced = 0;
+static size_t malloc_limit = 0 & 6000000;
+
+void *yaffs_malloc(size_t size)
+{
+	size_t this;
+	if(yaffs_kill_alloc)
+		return NULL;
+	if(malloc_limit && malloc_limit <(total_malloced + size) )
+		return NULL;
+
+	this = malloc(size);
+	if(this)
+		total_malloced += size;
+	return this;
+}
+
+void yaffs_free(void *ptr)
+{
+	free(ptr);
+}
+
 void yaffsfs_LocalInitialisation(void)
 {
 	// Define locking semaphore.
--- a/direct/ydirectenv.h
+++ b/direct/ydirectenv.h
@@ -27,12 +27,17 @@
 #include "stdlib.h"
 #include "stdio.h"
 #include "string.h"
+#include "yaffs_malloc.h"
+
+#include "assert.h"
+#define YBUG() assert(1)
 
 #define YCHAR char
 #define YUCHAR unsigned char
 #define _Y(x) x
 #define yaffs_strcpy(a,b)    strcpy(a,b)
 #define yaffs_strncpy(a,b,c) strncpy(a,b,c)
+#define yaffs_strncmp(a,b,c) strncmp(a,b,c)
 #define yaffs_strlen(s)	     strlen(s)
 #define yaffs_sprintf	     sprintf
 #define yaffs_toupper(a)     toupper(a)
@@ -43,12 +48,12 @@
 #define Y_INLINE inline
 #endif
 
-#define YMALLOC(x) malloc(x)
+#define YMALLOC(x) yaffs_malloc(x)
 #define YFREE(x)   free(x)
-#define YMALLOC_ALT(x) malloc(x)
+#define YMALLOC_ALT(x) yaffs_malloc(x)
 #define YFREE_ALT(x)   free(x)
 
-#define YMALLOC_DMA(x) malloc(x)
+#define YMALLOC_DMA(x) yaffs_malloc(x)
 
 #define YYIELD()  do {} while(0)
 
--- a/yaffs_checkptrw.c
+++ b/yaffs_checkptrw.c
@@ -32,7 +32,6 @@ static int yaffs_CheckpointSpaceOk(yaffs
 }
 
 
-
 static int yaffs_CheckpointErase(yaffs_Device *dev)
 {
 	
@@ -153,6 +152,8 @@ int yaffs_CheckpointOpen(yaffs_Device *d
 	dev->checkpointOpenForWrite = forWriting;
 	
 	dev->checkpointByteCount = 0;
+	dev->checkpointSum = 0;
+	dev->checkpointXor = 0;
 	dev->checkpointCurrentBlock = -1;
 	dev->checkpointCurrentChunk = -1;
 	dev->checkpointNextBlock = dev->internalStartBlock;
@@ -180,6 +181,14 @@ int yaffs_CheckpointOpen(yaffs_Device *d
 	return 1;
 }
 
+int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
+{
+	__u32 compositeSum;
+	compositeSum =  (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
+	*sum = compositeSum;
+	return 1;
+}
+
 static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
 {
 
@@ -243,12 +252,18 @@ int yaffs_CheckpointWrite(yaffs_Device *
 
 	if(!dev->checkpointBuffer)
 		return 0;
+		
+	if(!dev->checkpointOpenForWrite)
+		return -1;
 
 	while(i < nBytes && ok) {
 		
 
 		
-		 dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
+		dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
+		dev->checkpointSum += *dataBytes;
+		dev->checkpointXor ^= *dataBytes;
+		 
 		dev->checkpointByteOffset++;
 		i++;
 		dataBytes++;
@@ -279,6 +294,9 @@ int yaffs_CheckpointRead(yaffs_Device *d
 	if(!dev->checkpointBuffer)
 		return 0;
 
+	if(dev->checkpointOpenForWrite)
+		return -1;
+
 	while(i < nBytes && ok) {
 	
 	
@@ -320,6 +338,8 @@ int yaffs_CheckpointRead(yaffs_Device *d
 		
 		if(ok){
 			*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
+			dev->checkpointSum += *dataBytes;
+			dev->checkpointXor ^= *dataBytes;
 			dev->checkpointByteOffset++;
 			i++;
 			dataBytes++;
--- a/yaffs_checkptrw.h
+++ b/yaffs_checkptrw.h
@@ -24,6 +24,8 @@ int yaffs_CheckpointWrite(yaffs_Device *
 
 int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes);
 
+int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
+
 int yaffs_CheckpointClose(yaffs_Device *dev);
 
 int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
--- a/yaffs_fs.c
+++ b/yaffs_fs.c
@@ -76,14 +76,20 @@ extern const char *yaffs_guts_c_version;
 
 #endif
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+#define WRITE_SIZE_STR "writesize"
+#define WRITE_SIZE(mtd) (mtd)->writesize
+#else
+#define WRITE_SIZE_STR "oobblock"
+#define WRITE_SIZE(mtd) (mtd)->oobblock
+#endif
+
 #include <asm/uaccess.h>
 
 #include "yportenv.h"
 #include "yaffs_guts.h"
 
-unsigned yaffs_traceMask = YAFFS_TRACE_ALWAYS | 
-			   YAFFS_TRACE_BAD_BLOCKS | 
-			   YAFFS_TRACE_CHECKPOINT
+unsigned yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS
 			   /* | 0xFFFFFFFF */; 
 
 #include <linux/mtd/mtd.h>
@@ -158,8 +164,6 @@ static int yaffs_sync_fs(struct super_bl
 static int yaffs_write_super(struct super_block *sb);
 #endif
 
-static int yaffs_remount_fs(struct super_block *, int *, char *);
-
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
 static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
@@ -252,7 +256,6 @@ static struct super_operations yaffs_sup
 	.read_inode = yaffs_read_inode,
 	.put_inode = yaffs_put_inode,
 	.put_super = yaffs_put_super,
-	.remount_fs = yaffs_remount_fs,
 	.delete_inode = yaffs_delete_inode,
 	.clear_inode = yaffs_clear_inode,
 	.sync_fs = yaffs_sync_fs,
@@ -1500,6 +1503,55 @@ static void yaffs_MarkSuperBlockDirty(vo
 //		sb->s_dirt = 1;
 }
 
+typedef struct {
+	int inband_tags;
+	int skip_checkpoint_read;
+	int skip_checkpoint_write;
+	int no_cache;
+} yaffs_options;
+
+#define MAX_OPT_LEN 20
+static int yaffs_parse_options(yaffs_options *options, const char *options_str)
+{
+	char cur_opt[MAX_OPT_LEN+1];
+	int p;
+	int error = 0;
+	
+	/* Parse through the options which is a comma seperated list */
+	
+	while(options_str && *options_str && !error){
+		memset(cur_opt,0,MAX_OPT_LEN+1);
+		p = 0;
+		
+		while(*options_str && *options_str != ','){
+			if(p < MAX_OPT_LEN){
+				cur_opt[p] = *options_str;
+				p++;
+			}
+			options_str++;
+		}
+		
+		if(!strcmp(cur_opt,"inband-tags"))
+			options->inband_tags = 1;
+		else if(!strcmp(cur_opt,"no-cache"))
+			options->no_cache = 1;
+		else if(!strcmp(cur_opt,"no-checkpoint-read"))
+			options->skip_checkpoint_read = 1;
+		else if(!strcmp(cur_opt,"no-checkpoint-write"))
+			options->skip_checkpoint_write = 1;
+		else if(!strcmp(cur_opt,"no-checkpoint")){
+			options->skip_checkpoint_read = 1;
+			options->skip_checkpoint_write = 1;
+		} else {
+			printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",cur_opt);
+			error = 1;
+		}
+		
+	}
+
+	return error;
+}
+
 static struct super_block *yaffs_internal_read_super(int yaffsVersion,
 						     struct super_block *sb,
 						     void *data, int silent)
@@ -1511,6 +1563,9 @@ static struct super_block *yaffs_interna
 	char devname_buf[BDEVNAME_SIZE + 1];
 	struct mtd_info *mtd;
 	int err;
+	char *data_str = (char *)data;
+	
+	yaffs_options options;
 
 	sb->s_magic = YAFFS_MAGIC;
 	sb->s_op = &yaffs_super_ops;
@@ -1525,6 +1580,19 @@ static struct super_block *yaffs_interna
 		printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
 		       sb->s_dev,
 		       yaffs_devname(sb, devname_buf));
+		    
+	if(!data_str)
+		data_str = "";
+   
+	printk(KERN_INFO "yaffs: passed flags \"%s\"\n",data_str);
+	
+	memset(&options,0,sizeof(options));
+	
+	if(yaffs_parse_options(&options,data_str)){
+		/* Option parsing failed */
+		return NULL;
+	}
+
 
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -1569,11 +1637,7 @@ static struct super_block *yaffs_interna
 	T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
 	T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
 	T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
-	T(YAFFS_TRACE_OS, (" writesize %d\n", mtd->writesize));
-#else
-	T(YAFFS_TRACE_OS, (" oobblock %d\n", mtd->oobblock));
-#endif
+	T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
 	T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
 	T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
 	T(YAFFS_TRACE_OS, (" size %d\n", mtd->size));
@@ -1650,11 +1714,7 @@ static struct super_block *yaffs_interna
 			return NULL;
 		}
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
-		if (mtd->writesize < YAFFS_BYTES_PER_CHUNK ||
-#else
-		if (mtd->oobblock < YAFFS_BYTES_PER_CHUNK ||
-#endif
+		if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
 		    mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
 			T(YAFFS_TRACE_ALWAYS,
 			  ("yaffs: MTD device does not support have the "
@@ -1693,7 +1753,7 @@ static struct super_block *yaffs_interna
 	dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
 	dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
 	dev->nReservedBlocks = 5;
-	dev->nShortOpCaches = 10;	/* Enable short op caching */
+	dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
 
 	/* ... and the functions. */
 	if (yaffsVersion == 2) {
@@ -1740,6 +1800,9 @@ static struct super_block *yaffs_interna
 	dev->wideTnodesDisabled = 1;
 #endif
 
+	dev->skipCheckpointRead = options.skip_checkpoint_read;
+	dev->skipCheckpointWrite = options.skip_checkpoint_write;
+	
 	/* we assume this is protected by lock_kernel() in mount/umount */
 	list_add_tail(&dev->devList, &yaffs_dev_list);
 
@@ -1884,9 +1947,13 @@ static char *yaffs_dump_dev(char *buf, y
 {
 	buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
 	buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
+	buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
 	buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
 	buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
 	buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
+	buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
+	buf += sprintf(buf, "nCheckptResBlocks.. %d\n", dev->nCheckpointReservedBlocks);
+	buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
 	buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
 	buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
 	buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
@@ -1902,6 +1969,7 @@ static char *yaffs_dump_dev(char *buf, y
 	    sprintf(buf, "passiveGCs......... %d\n",
 		    dev->passiveGarbageCollections);
 	buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
+	buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
 	buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
 	buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
 	buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
@@ -1964,6 +2032,7 @@ static int yaffs_proc_read(char *page,
 /**
  * Set the verbosity of the warnings and error messages.
  *
+ * Note that the names can only be a..z or _ with the current code.
  */
 
 static struct {
@@ -1975,6 +2044,7 @@ static struct {
 	{"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
 	{"buffers", YAFFS_TRACE_BUFFERS},
 	{"bug", YAFFS_TRACE_BUG},
+	{"checkpt", YAFFS_TRACE_CHECKPOINT},
 	{"deletion", YAFFS_TRACE_DELETION},
 	{"erase", YAFFS_TRACE_ERASE},
 	{"error", YAFFS_TRACE_ERROR},
@@ -1986,17 +2056,27 @@ static struct {
 	{"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
 	{"scan", YAFFS_TRACE_SCAN},
 	{"tracing", YAFFS_TRACE_TRACING},
+
+	{"verify", YAFFS_TRACE_VERIFY},
+	{"verify_nand", YAFFS_TRACE_VERIFY_NAND},
+	{"verify_full", YAFFS_TRACE_VERIFY_FULL},
+	{"verify_all", YAFFS_TRACE_VERIFY_ALL},
+
 	{"write", YAFFS_TRACE_WRITE},
 	{"all", 0xffffffff},
 	{"none", 0},
 	{NULL, 0},
 };
 
+#define MAX_MASK_NAME_LENGTH 40
 static int yaffs_proc_write(struct file *file, const char *buf,
 					 unsigned long count, void *data)
 {
 	unsigned rg = 0, mask_bitfield;
-	char *end, *mask_name;
+	char *end;
+	char *mask_name;
+	char *x; 
+	char substring[MAX_MASK_NAME_LENGTH+1];
 	int i;
 	int done = 0;
 	int add, len = 0;
@@ -2023,16 +2103,23 @@ static int yaffs_proc_write(struct file 
 			break;
 		}
 		mask_name = NULL;
+		
 		mask_bitfield = simple_strtoul(buf + pos, &end, 0);
 		if (end > buf + pos) {
 			mask_name = "numeral";
 			len = end - (buf + pos);
 			done = 0;
 		} else {
-
+			for(x = buf + pos, i = 0; 
+			    (*x == '_' || (*x >='a' && *x <= 'z')) &&
+			    i <MAX_MASK_NAME_LENGTH; x++, i++, pos++)
+			    substring[i] = *x;
+			substring[i] = '\0';
+			
 			for (i = 0; mask_flags[i].mask_name != NULL; i++) {
-				len = strlen(mask_flags[i].mask_name);
-				if (strncmp(buf + pos, mask_flags[i].mask_name, len) == 0) {
+				//len = strlen(mask_flags[i].mask_name);
+				//if (strncmp(buf + pos, mask_flags[i].mask_name, len) == 0) {
+				if(strcmp(substring,mask_flags[i].mask_name) == 0){
 					mask_name = mask_flags[i].mask_name;
 					mask_bitfield = mask_flags[i].mask_bitfield;
 					done = 0;
@@ -2042,7 +2129,7 @@ static int yaffs_proc_write(struct file 
 		}
 
 		if (mask_name != NULL) {
-			pos += len;
+			// pos += len;
 			done = 0;
 			switch(add) {
 			case '-':
@@ -2063,6 +2150,8 @@ static int yaffs_proc_write(struct file 
 
 	yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
 	
+	printk("new trace = 0x%08X\n",yaffs_traceMask);
+	
 	if (rg & YAFFS_TRACE_ALWAYS) {
 		for (i = 0; mask_flags[i].mask_name != NULL; i++) {
 			char flag;
--- a/yaffs_guts.c
+++ b/yaffs_guts.c
@@ -21,7 +21,7 @@ const char *yaffs_guts_c_version =
 #include "yaffs_tagsvalidity.h"
 
 #include "yaffs_tagscompat.h"
-#ifndef CONFIG_YAFFS_OWN_SORT
+#ifndef  CONFIG_YAFFS_USE_OWN_SORT
 #include "yaffs_qsort.h"
 #endif
 #include "yaffs_nand.h"
@@ -97,6 +97,8 @@ static int yaffs_AllocateChunk(yaffs_Dev
 
 static void yaffs_VerifyFreeChunks(yaffs_Device * dev);
 
+static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
+
 #ifdef YAFFS_PARANOID
 static int yaffs_CheckFileSanity(yaffs_Object * in);
 #else
@@ -108,6 +110,13 @@ static void yaffs_InvalidateChunkCache(y
 
 static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
 
+static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode,
+				 yaffs_ExtendedTags * tags);
+
+static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos);
+static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev,
+					  yaffs_FileStructure * fStruct,
+					  __u32 chunkId);
 
 
 /* Function to calculate chunk and offset */
@@ -181,6 +190,23 @@ static __u32 ShiftDiv(__u32 x)
  * Temporary buffer manipulations.
  */
 
+static int yaffs_InitialiseTempBuffers(yaffs_Device *dev)	
+{
+	int i;
+	__u8 *buf = (__u8 *)1;
+		
+	memset(dev->tempBuffer,0,sizeof(dev->tempBuffer));
+		
+	for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
+		dev->tempBuffer[i].line = 0;	/* not in use */
+		dev->tempBuffer[i].buffer = buf =
+		    YMALLOC_DMA(dev->nDataBytesPerChunk);
+	}
+		
+	return buf ? YAFFS_OK : YAFFS_FAIL;
+	
+}
+
 static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo)
 {
 	int i, j;
@@ -264,6 +290,8 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
     return 0;
 }
 
+
+
 /*
  * Chunk bitmap manipulations
  */
@@ -280,6 +308,16 @@ static Y_INLINE __u8 *yaffs_BlockBits(ya
 	    (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
 }
 
+static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
+{
+	if(blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
+	   chunk < 0 || chunk >= dev->nChunksPerBlock) {
+	   T(YAFFS_TRACE_ERROR,
+	    (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),blk,chunk));
+	    YBUG();
+	}
+}
+
 static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device * dev, int blk)
 {
 	__u8 *blkBits = yaffs_BlockBits(dev, blk);
@@ -291,12 +329,16 @@ static Y_INLINE void yaffs_ClearChunkBit
 {
 	__u8 *blkBits = yaffs_BlockBits(dev, blk);
 
+	yaffs_VerifyChunkBitId(dev,blk,chunk);
+
 	blkBits[chunk / 8] &= ~(1 << (chunk & 7));
 }
 
 static Y_INLINE void yaffs_SetChunkBit(yaffs_Device * dev, int blk, int chunk)
 {
 	__u8 *blkBits = yaffs_BlockBits(dev, blk);
+	
+	yaffs_VerifyChunkBitId(dev,blk,chunk);
 
 	blkBits[chunk / 8] |= (1 << (chunk & 7));
 }
@@ -304,6 +346,8 @@ static Y_INLINE void yaffs_SetChunkBit(y
 static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device * dev, int blk, int chunk)
 {
 	__u8 *blkBits = yaffs_BlockBits(dev, blk);
+	yaffs_VerifyChunkBitId(dev,blk,chunk);
+
 	return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
 }
 
@@ -319,6 +363,491 @@ static Y_INLINE int yaffs_StillSomeChunk
 	return 0;
 }
 
+static int yaffs_CountChunkBits(yaffs_Device * dev, int blk)
+{
+	__u8 *blkBits = yaffs_BlockBits(dev, blk);
+	int i;
+	int n = 0;
+	for (i = 0; i < dev->chunkBitmapStride; i++) {
+		__u8 x = *blkBits;
+		while(x){
+			if(x & 1)
+				n++;
+			x >>=1;
+		}
+			
+		blkBits++;
+	}
+	return n;
+}
+
+/* 
+ * Verification code
+ */
+ 
+static int yaffs_SkipVerification(yaffs_Device *dev)
+{
+	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
+}
+
+static int yaffs_SkipFullVerification(yaffs_Device *dev)
+{
+	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
+}
+
+static int yaffs_SkipNANDVerification(yaffs_Device *dev)
+{
+	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
+}
+
+static const char * blockStateName[] = {
+"Unknown",
+"Needs scanning",
+"Scanning",
+"Empty",
+"Allocating",
+"Full",
+"Dirty",
+"Checkpoint",
+"Collecting",
+"Dead"
+};
+
+static void yaffs_VerifyBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n)
+{
+	int actuallyUsed;
+	int inUse;
+	
+	if(yaffs_SkipVerification(dev))
+		return;
+		
+	/* Report illegal runtime states */
+	if(bi->blockState <0 || bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
+		T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has undefined state %d"TENDSTR),n,bi->blockState));
+		
+	switch(bi->blockState){
+	 case YAFFS_BLOCK_STATE_UNKNOWN:
+	 case YAFFS_BLOCK_STATE_SCANNING:
+	 case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
+		T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has bad run-state %s"TENDSTR),
+		n,blockStateName[bi->blockState]));
+	}
+	
+	/* Check pages in use and soft deletions are legal */
+	
+	actuallyUsed = bi->pagesInUse - bi->softDeletions;
+	
+	if(bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||
+	   bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||
+	   actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)
+		T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
+		n,bi->pagesInUse,bi->softDeletions));
+	
+		
+	/* Check chunk bitmap legal */
+	inUse = yaffs_CountChunkBits(dev,n);
+	if(inUse != bi->pagesInUse)
+		T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
+			n,bi->pagesInUse,inUse));
+	
+	/* Check that the sequence number is valid.
+	 * Ten million is legal, but is very unlikely 
+	 */
+	if(dev->isYaffs2 && 
+	   (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
+	   (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000 ))
+		T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has suspect sequence number of %d"TENDSTR),
+		n,bi->sequenceNumber));
+		
+}
+
+static void yaffs_VerifyCollectedBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n)
+{
+	yaffs_VerifyBlock(dev,bi,n);
+	
+	/* After collection the block should be in the erased state */
+	/* TODO: This will need to change if we do partial gc */
+	
+	if(bi->blockState != YAFFS_BLOCK_STATE_EMPTY){
+		T(YAFFS_TRACE_ERROR,(TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
+			n,bi->blockState));
+	}
+}
+
+static void yaffs_VerifyBlocks(yaffs_Device *dev)
+{
+	int i;
+	int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
+	int nIllegalBlockStates = 0;
+	
+
+	if(yaffs_SkipVerification(dev))
+		return;
+
+	memset(nBlocksPerState,0,sizeof(nBlocksPerState));
+
+		
+	for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++){
+		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
+		yaffs_VerifyBlock(dev,bi,i);
+
+		if(bi->blockState >=0 && bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
+			nBlocksPerState[bi->blockState]++;
+		else
+			nIllegalBlockStates++;
+					
+	}
+	
+	T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR)));
+	T(YAFFS_TRACE_VERIFY,(TSTR("Block summary"TENDSTR)));
+	
+	T(YAFFS_TRACE_VERIFY,(TSTR("%d blocks have illegal states"TENDSTR),nIllegalBlockStates));
+	if(nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
+		T(YAFFS_TRACE_VERIFY,(TSTR("Too many allocating blocks"TENDSTR)));
+
+	for(i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
+		T(YAFFS_TRACE_VERIFY,
+		  (TSTR("%s %d blocks"TENDSTR),
+		  blockStateName[i],nBlocksPerState[i]));
+	
+	if(dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
+		T(YAFFS_TRACE_VERIFY,
+		 (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
+		 dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
+		 
+	if(dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
+		T(YAFFS_TRACE_VERIFY,
+		 (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
+		 dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
+		 
+	if(nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
+		T(YAFFS_TRACE_VERIFY,
+		 (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
+		 nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
+
+	T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR)));
+
+}
+
+/*
+ * Verify the object header. oh must be valid, but obj and tags may be NULL in which
+ * case those tests will not be performed.
+ */
+static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
+{
+	if(yaffs_SkipVerification(obj->myDev))
+		return;
+		
+	if(!(tags && obj && oh)){
+	 	T(YAFFS_TRACE_VERIFY,
+		 		(TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),
+		 		(__u32)tags,(__u32)obj,(__u32)oh));
+		return;
+	}
+	
+	if(oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
+	   oh->type > YAFFS_OBJECT_TYPE_MAX)
+	 	T(YAFFS_TRACE_VERIFY,
+		 (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
+		 tags->objectId, oh->type));
+
+	if(tags->objectId != obj->objectId)
+	 	T(YAFFS_TRACE_VERIFY,
+		 (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
+		 tags->objectId, obj->objectId));
+
+
+	/*
+	 * Check that the object's parent ids match if parentCheck requested.
+	 * 
+	 * Tests do not apply to the root object.
+	 */
+	
+	if(parentCheck && tags->objectId > 1 && !obj->parent)
+	 	T(YAFFS_TRACE_VERIFY,
+		 (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
+	 	 tags->objectId, oh->parentObjectId));
+		
+	
+	if(parentCheck && obj->parent &&
+	   oh->parentObjectId != obj->parent->objectId && 
+	   (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
+	    obj->parent->objectId != YAFFS_OBJECTID_DELETED))
+	 	T(YAFFS_TRACE_VERIFY,
+		 (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
+	 	 tags->objectId, oh->parentObjectId, obj->parent->objectId));
+		
+	
+	if(tags->objectId > 1 && oh->name[0] == 0) /* Null name */
+		T(YAFFS_TRACE_VERIFY,
+		(TSTR("Obj %d header name is NULL"TENDSTR),
+		 obj->objectId));
+
+	if(tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
+		T(YAFFS_TRACE_VERIFY,
+		(TSTR("Obj %d header name is 0xFF"TENDSTR),
+		 obj->objectId));
+}
+
+
+
+static int yaffs_VerifyTnodeWorker(yaffs_Object * obj, yaffs_Tnode * tn,
+				  	__u32 level, int chunkOffset)
+{
+	int i;
+	yaffs_Device *dev = obj->myDev;
+	int ok = 1;
+	int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
+
+	if (tn) {
+		if (level > 0) {
+
+			for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){
+				if (tn->internal[i]) {
+					ok = yaffs_VerifyTnodeWorker(obj,
+							tn->internal[i],
+							level - 1,
+							(chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
+				}
+			}
+		} else if (level == 0) {
+			int i;
+			yaffs_ExtendedTags tags;
+			__u32 objectId = obj->objectId;
+			
+			chunkOffset <<=  YAFFS_TNODES_LEVEL0_BITS;
+			
+			for(i = 0; i < YAFFS_NTNODES_LEVEL0; i++){
+				__u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i);
+				
+				if(theChunk > 0){
+					/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
+					yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags);
+					if(tags.objectId != objectId || tags.chunkId != chunkOffset){
+						T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
+							objectId, chunkOffset, theChunk,
+							tags.objectId, tags.chunkId));
+					}
+				}
+				chunkOffset++;
+			}
+		}
+	}
+
+	return ok;
+
+}
+
+
+static void yaffs_VerifyFile(yaffs_Object *obj)
+{
+	int requiredTallness;
+	int actualTallness;
+	__u32 lastChunk;
+	__u32 x;
+	__u32 i;
+	int ok;
+	yaffs_Device *dev;
+	yaffs_ExtendedTags tags;
+	yaffs_Tnode *tn;
+	__u32 objectId;
+	
+	if(obj && yaffs_SkipVerification(obj->myDev))
+		return;
+	
+	dev = obj->myDev;
+	objectId = obj->objectId;
+	
+	/* Check file size is consistent with tnode depth */
+	lastChunk =  obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
+	x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
+	requiredTallness = 0;
+	while (x> 0) {
+		x >>= YAFFS_TNODES_INTERNAL_BITS;
+		requiredTallness++;
+	}
+	
+	actualTallness = obj->variant.fileVariant.topLevel;
+	
+	if(requiredTallness > actualTallness )
+		T(YAFFS_TRACE_VERIFY,
+		(TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
+		 obj->objectId,actualTallness, requiredTallness));
+	
+	
+	/* Check that the chunks in the tnode tree are all correct. 
+	 * We do this by scanning through the tnode tree and
+	 * checking the tags for every chunk match.
+	 */
+
+	if(yaffs_SkipNANDVerification(dev))
+		return;
+		
+	for(i = 1; i <= lastChunk; i++){
+		tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant,i);
+
+		if (tn) {
+			__u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i);
+			if(theChunk > 0){
+				/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
+				yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags);
+				if(tags.objectId != objectId || tags.chunkId != i){
+					T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
+						objectId, i, theChunk,
+						tags.objectId, tags.chunkId));
+				}
+			}
+		}
+
+	}
+
+}
+
+static void yaffs_VerifyDirectory(yaffs_Object *obj)
+{
+	if(obj && yaffs_SkipVerification(obj->myDev))
+		return;
+	
+}
+
+static void yaffs_VerifyHardLink(yaffs_Object *obj)
+{
+	if(obj && yaffs_SkipVerification(obj->myDev))
+		return;
+		
+	/* Verify sane equivalent object */
+}
+
+static void yaffs_VerifySymlink(yaffs_Object *obj)
+{
+	if(obj && yaffs_SkipVerification(obj->myDev))
+		return;
+		
+	/* Verify symlink string */
+}
+
+static void yaffs_VerifySpecial(yaffs_Object *obj)
+{
+	if(obj && yaffs_SkipVerification(obj->myDev))
+		return;
+}
+
+static void yaffs_VerifyObject(yaffs_Object *obj)
+{
+	yaffs_Device *dev;
+	
+	__u32 chunkMin;
+	__u32 chunkMax;
+	
+	__u32 chunkIdOk;
+	__u32 chunkIsLive;
+	
+	if(!obj)
+		return;
+	
+	dev = obj->myDev;
+	
+	if(yaffs_SkipVerification(dev))
+		return;
+		
+	/* Check sane object header chunk */
+	
+	chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
+	chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
+	
+	chunkIdOk = (obj->chunkId >= chunkMin && obj->chunkId <= chunkMax);
+	chunkIsLive = chunkIdOk && 
+			yaffs_CheckChunkBit(dev, 
+					    obj->chunkId / dev->nChunksPerBlock,
+					    obj->chunkId % dev->nChunksPerBlock);
+	if(!obj->fake && 
+	    (!chunkIdOk || !chunkIsLive)) {
+	   T(YAFFS_TRACE_VERIFY,
+	   (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
+	   obj->objectId,obj->chunkId,
+	   chunkIdOk ? "" : ",out of range",
+	   chunkIsLive || !chunkIdOk ? "" : ",marked as deleted"));
+	}
+	
+	if(chunkIdOk && chunkIsLive &&!yaffs_SkipNANDVerification(dev)) {
+		yaffs_ExtendedTags tags;
+		yaffs_ObjectHeader *oh;
+		__u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
+		
+		oh = (yaffs_ObjectHeader *)buffer;
+		
+		yaffs_ReadChunkWithTagsFromNAND(dev, obj->chunkId,buffer, &tags);
+		
+		yaffs_VerifyObjectHeader(obj,oh,&tags,1);
+		
+		yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
+	}
+	
+	/* Verify it has a parent */
+	if(obj && !obj->fake &&
+	   (!obj->parent || obj->parent->myDev != dev)){
+	   T(YAFFS_TRACE_VERIFY,
+	   (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
+	   obj->objectId,obj->parent));	   
+	}
+	
+	/* Verify parent is a directory */
+	if(obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY){
+	   T(YAFFS_TRACE_VERIFY,
+	   (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
+	   obj->objectId,obj->parent->variantType));	   
+	}
+	
+	switch(obj->variantType){
+	case YAFFS_OBJECT_TYPE_FILE:
+		yaffs_VerifyFile(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		yaffs_VerifySymlink(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		yaffs_VerifyDirectory(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		yaffs_VerifyHardLink(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		yaffs_VerifySpecial(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+	default:
+		T(YAFFS_TRACE_VERIFY,
+		(TSTR("Obj %d has illegaltype %d"TENDSTR),
+		obj->objectId,obj->variantType));	   
+		break;
+	}
+	
+	
+}
+
+static void yaffs_VerifyObjects(yaffs_Device *dev)
+{
+	yaffs_Object *obj;
+	int i;
+	struct list_head *lh;
+
+	if(yaffs_SkipVerification(dev))
+		return;
+	
+	/* Iterate through the objects in each hash entry */
+	 
+	 for(i = 0; i <  YAFFS_NOBJECT_BUCKETS; i++){
+	 	list_for_each(lh, &dev->objectBucket[i].list) {
+			if (lh) {
+				obj = list_entry(lh, yaffs_Object, hashLink);
+				yaffs_VerifyObject(obj);
+			}
+		}
+	 }
+
+}
+
+
 /*
  *  Simple hash function. Needs to have a reasonable spread
  */
@@ -528,21 +1057,6 @@ void yaffs_HandleChunkError(yaffs_Device
 	}
 }
 
-static void yaffs_ReportOddballBlocks(yaffs_Device *dev)
-{
-	int i;
-		
-	for(i = dev->internalStartBlock; i <= dev->internalEndBlock && (yaffs_traceMask & YAFFS_TRACE_BAD_BLOCKS); i++){
-		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
-		if(bi->needsRetiring || bi->gcPrioritise)
-			T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("yaffs block %d%s%s" TENDSTR),
-				i,
-				bi->needsRetiring ? " needs retiring" : "",
-				bi->gcPrioritise ?  " gc prioritised" : ""));
-		
-	}
-}
-
 static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk)
 {
 
@@ -575,7 +1089,7 @@ static __u16 yaffs_CalcNameSum(const YCH
 
 	YUCHAR *bname = (YUCHAR *) name;
 	if (bname) {
-		while ((*bname) && (i <= YAFFS_MAX_NAME_LENGTH)) {
+		while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
 
 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
 			sum += yaffs_toupper(*bname) * i;
@@ -683,6 +1197,7 @@ static int yaffs_CreateTnodes(yaffs_Devi
 		T(YAFFS_TRACE_ERROR,
 		  (TSTR
 		   ("yaffs: Could not add tnodes to management list" TENDSTR)));
+		   return YAFFS_FAIL;
 
 	} else {
 		tnl->tnodes = newTnodes;
@@ -807,7 +1322,7 @@ void yaffs_PutLevel0Tnode(yaffs_Device *
   }
 }
 
-__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos)
+static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos)
 {
   __u32 *map = (__u32 *)tn;
   __u32 bitInMap;
@@ -1325,8 +1840,13 @@ static int yaffs_CreateFreeObjects(yaffs
 
 	/* make these things */
 	newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
-
-	if (!newObjects) {
+	list = YMALLOC(sizeof(yaffs_ObjectList));
+
+	if (!newObjects || !list) {
+		if(newObjects)
+			YFREE(newObjects);
+		if(list)
+			YFREE(list);
 		T(YAFFS_TRACE_ALLOCATE,
 		  (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
 		return YAFFS_FAIL;
@@ -1345,15 +1865,9 @@ static int yaffs_CreateFreeObjects(yaffs
 
 	/* Now add this bunch of Objects to a list for freeing up. */
 
-	list = YMALLOC(sizeof(yaffs_ObjectList));
-	if (!list) {
-		T(YAFFS_TRACE_ALLOCATE,
-		  (TSTR("Could not add objects to management list" TENDSTR)));
-	} else {
-		list->objects = newObjects;
-		list->next = dev->allocatedObjectList;
-		dev->allocatedObjectList = list;
-	}
+	list->objects = newObjects;
+	list->next = dev->allocatedObjectList;
+	dev->allocatedObjectList = list;
 
 	return YAFFS_OK;
 }
@@ -1610,12 +2124,25 @@ yaffs_Object *yaffs_CreateNewObject(yaff
 {
 
 	yaffs_Object *theObject;
+	yaffs_Tnode *tn;
 
 	if (number < 0) {
 		number = yaffs_CreateNewObjectNumber(dev);
 	}
 
 	theObject = yaffs_AllocateEmptyObject(dev);
+	if(!theObject)
+		return NULL;
+		
+	if(type == YAFFS_OBJECT_TYPE_FILE){
+		tn = yaffs_GetTnode(dev);
+		if(!tn){
+			yaffs_FreeObject(theObject);
+			return NULL;
+		}
+	}
+		
+	
 
 	if (theObject) {
 		theObject->fake = 0;
@@ -1642,8 +2169,7 @@ yaffs_Object *yaffs_CreateNewObject(yaff
 			theObject->variant.fileVariant.scannedFileSize = 0;
 			theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF;	/* max __u32 */
 			theObject->variant.fileVariant.topLevel = 0;
-			theObject->variant.fileVariant.top =
-			    yaffs_GetTnode(dev);
+			theObject->variant.fileVariant.top = tn;
 			break;
 		case YAFFS_OBJECT_TYPE_DIRECTORY:
 			INIT_LIST_HEAD(&theObject->variant.directoryVariant.
@@ -1688,7 +2214,8 @@ static YCHAR *yaffs_CloneString(const YC
 
 	if (str && *str) {
 		newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
-		yaffs_strcpy(newStr, str);
+		if(newStr)
+			yaffs_strcpy(newStr, str);
 	}
 
 	return newStr;
@@ -1712,6 +2239,7 @@ static yaffs_Object *yaffs_MknodObject(y
 				       const YCHAR * aliasString, __u32 rdev)
 {
 	yaffs_Object *in;
+	YCHAR *str;
 
 	yaffs_Device *dev = parent->myDev;
 
@@ -1721,6 +2249,16 @@ static yaffs_Object *yaffs_MknodObject(y
 	}
 
 	in = yaffs_CreateNewObject(dev, -1, type);
+	
+	if(type == YAFFS_OBJECT_TYPE_SYMLINK){
+		str = yaffs_CloneString(aliasString);
+		if(!str){
+			yaffs_FreeObject(in);
+			return NULL;
+		}
+	}
+	
+	
 
 	if (in) {
 		in->chunkId = -1;
@@ -1752,8 +2290,7 @@ static yaffs_Object *yaffs_MknodObject(y
 
 		switch (type) {
 		case YAFFS_OBJECT_TYPE_SYMLINK:
-			in->variant.symLinkVariant.alias =
-			    yaffs_CloneString(aliasString);
+			in->variant.symLinkVariant.alias = str;
 			break;
 		case YAFFS_OBJECT_TYPE_HARDLINK:
 			in->variant.hardLinkVariant.equivalentObject =
@@ -1944,9 +2481,12 @@ static int yaffs_InitialiseBlocks(yaffs_
 {
 	int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
 	
+	dev->blockInfo = NULL;
+	dev->chunkBits = NULL;
+	
 	dev->allocationBlock = -1;	/* force it to get a new one */
 
-	/* Todo we're assuming the malloc will pass. */
+	/* If the first allocation strategy fails, thry the alternate one */
 	dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
 	if(!dev->blockInfo){
 		dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
@@ -1954,16 +2494,19 @@ static int yaffs_InitialiseBlocks(yaffs_
 	}
 	else
 		dev->blockInfoAlt = 0;
-	
-	/* Set up dynamic blockinfo stuff. */
-	dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
-	dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
-	if(!dev->chunkBits){
-		dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
-		dev->chunkBitsAlt = 1;
-	}
-	else
-		dev->chunkBitsAlt = 0;
+		
+	if(dev->blockInfo){
+	
+		/* Set up dynamic blockinfo stuff. */
+		dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
+		dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
+		if(!dev->chunkBits){
+			dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
+			dev->chunkBitsAlt = 1;
+		}
+		else
+			dev->chunkBitsAlt = 0;
+	}
 	
 	if (dev->blockInfo && dev->chunkBits) {
 		memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
@@ -1977,17 +2520,18 @@ static int yaffs_InitialiseBlocks(yaffs_
 
 static void yaffs_DeinitialiseBlocks(yaffs_Device * dev)
 {
-	if(dev->blockInfoAlt)
+	if(dev->blockInfoAlt && dev->blockInfo)
 		YFREE_ALT(dev->blockInfo);
-	else
+	else if(dev->blockInfo)
 		YFREE(dev->blockInfo);
+
 	dev->blockInfoAlt = 0;
 
 	dev->blockInfo = NULL;
 	
-	if(dev->chunkBitsAlt)
+	if(dev->chunkBitsAlt && dev->chunkBits)
 		YFREE_ALT(dev->chunkBits);
-	else
+	else if(dev->chunkBits)
 		YFREE(dev->chunkBits);
 	dev->chunkBitsAlt = 0;
 	dev->chunkBits = NULL;
@@ -2044,7 +2588,7 @@ static int yaffs_FindBlockForGarbageColl
 	int i;
 	int iterations;
 	int dirtiest = -1;
-	int pagesInUse;
+	int pagesInUse = 0;
 	int prioritised=0;
 	yaffs_BlockInfo *bi;
 	static int nonAggressiveSkip = 0;
@@ -2055,6 +2599,8 @@ static int yaffs_FindBlockForGarbageColl
 		for(i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++){
 
 			bi = yaffs_GetBlockInfo(dev, i);
+			//yaffs_VerifyBlock(dev,bi,i);
+			
 			if(bi->gcPrioritise) {
 				pendingPrioritisedExist = 1;
 				if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
@@ -2172,7 +2718,8 @@ static void yaffs_BlockBecameDirty(yaffs
 		}
 	}
 
-	if (erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE)) {
+	if (erasedOk && 
+	    ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
 		int i;
 		for (i = 0; i < dev->nChunksPerBlock; i++) {
 			if (!yaffs_CheckChunkErased
@@ -2350,6 +2897,7 @@ static int yaffs_GarbageCollectBlock(yaf
 	int cleanups = 0;
 	int i;
 	int isCheckpointBlock;
+	int matchingChunk;
 
 	int chunksBefore = yaffs_GetErasedChunks(dev);
 	int chunksAfter;
@@ -2389,6 +2937,8 @@ static int yaffs_GarbageCollectBlock(yaf
 	} else {
 
 		__u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
+		
+		yaffs_VerifyBlock(dev,bi,block);
 
 		for (chunkInBlock = 0, oldChunk = block * dev->nChunksPerBlock;
 		     chunkInBlock < dev->nChunksPerBlock
@@ -2414,12 +2964,28 @@ static int yaffs_GarbageCollectBlock(yaf
 				   ("Collecting page %d, %d %d %d " TENDSTR),
 				   chunkInBlock, tags.objectId, tags.chunkId,
 				   tags.byteCount));
+				   
+				if(object && !yaffs_SkipVerification(dev)){
+					if(tags.chunkId == 0)
+						matchingChunk = object->chunkId;
+					else if(object->softDeleted)
+						matchingChunk = oldChunk; /* Defeat the test */
+					else
+						matchingChunk = yaffs_FindChunkInFile(object,tags.chunkId,NULL);
+					
+					if(oldChunk != matchingChunk)
+						T(YAFFS_TRACE_ERROR,
+						  (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
+						  oldChunk,matchingChunk,tags.objectId, tags.chunkId));
+						
+				}
 
 				if (!object) {
 					T(YAFFS_TRACE_ERROR,
 					  (TSTR
-					   ("page %d in gc has no object "
-					    TENDSTR), oldChunk));
+					   ("page %d in gc has no object: %d %d %d "
+					    TENDSTR), oldChunk,
+					    tags.objectId, tags.chunkId, tags.byteCount));
 				}
 
 				if (object && object->deleted
@@ -2476,6 +3042,8 @@ static int yaffs_GarbageCollectBlock(yaf
 						oh->shadowsObject = -1;
 						tags.extraShadows = 0;
 						tags.extraIsShrinkHeader = 0;
+						
+						yaffs_VerifyObjectHeader(object,oh,&tags,1);
 					}
 
 					newChunk =
@@ -2532,6 +3100,8 @@ static int yaffs_GarbageCollectBlock(yaf
 
 	}
 
+	yaffs_VerifyCollectedBlock(dev,bi,block);
+	  
 	if (chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev))) {
 		T(YAFFS_TRACE_GC,
 		  (TSTR
@@ -2578,7 +3148,7 @@ static int yaffs_CheckGarbageCollection(
 		if(checkpointBlockAdjust < 0)
 			checkpointBlockAdjust = 0;
 
-		if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust)) {
+		if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
 			/* We need a block soon...*/
 			aggressive = 1;
 		} else {
@@ -2906,11 +3476,18 @@ void yaffs_DeleteChunk(yaffs_Device * de
 
 	if (chunkId <= 0)
 		return;
+		
 
 	dev->nDeletions++;
 	block = chunkId / dev->nChunksPerBlock;
 	page = chunkId % dev->nChunksPerBlock;
 
+
+	if(!yaffs_CheckChunkBit(dev,block,page))
+		T(YAFFS_TRACE_VERIFY,
+		 	(TSTR("Deleting invalid chunk %d"TENDSTR),
+		 	 chunkId));
+
 	bi = yaffs_GetBlockInfo(dev, block);
 
 	T(YAFFS_TRACE_DELETION,
@@ -3021,15 +3598,19 @@ int yaffs_UpdateObjectHeader(yaffs_Objec
 
 	int newChunkId;
 	yaffs_ExtendedTags newTags;
+	yaffs_ExtendedTags oldTags;
 
 	__u8 *buffer = NULL;
 	YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
 
 	yaffs_ObjectHeader *oh = NULL;
+	
+	yaffs_strcpy(oldName,"silly old name");
 
 	if (!in->fake || force) {
 
 		yaffs_CheckGarbageCollection(dev);
+		yaffs_CheckObjectDetailsLoaded(in);
 
 		buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
 		oh = (yaffs_ObjectHeader *) buffer;
@@ -3038,7 +3619,10 @@ int yaffs_UpdateObjectHeader(yaffs_Objec
 
 		if (prevChunkId >= 0) {
 			result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
-							buffer, NULL);
+							buffer, &oldTags);
+			
+			yaffs_VerifyObjectHeader(in,oh,&oldTags,0);
+										
 			memcpy(oldName, oh->name, sizeof(oh->name));
 		}
 
@@ -3072,7 +3656,7 @@ int yaffs_UpdateObjectHeader(yaffs_Objec
 		if (name && *name) {
 			memset(oh->name, 0, sizeof(oh->name));
 			yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
-		} else if (prevChunkId) {
+		} else if (prevChunkId>=0) {
 			memcpy(oh->name, oldName, sizeof(oh->name));
 		} else {
 			memset(oh->name, 0, sizeof(oh->name));
@@ -3126,6 +3710,8 @@ int yaffs_UpdateObjectHeader(yaffs_Objec
 		newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
 		newTags.extraObjectType = in->variantType;
 
+		yaffs_VerifyObjectHeader(in,oh,&newTags,1);
+
 		/* Create new chunk in NAND */
 		newChunkId =
 		    yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
@@ -3448,6 +4034,9 @@ static void yaffs_InvalidateWholeChunkCa
 static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev,int head)
 {
 	yaffs_CheckpointValidity cp;
+	
+	memset(&cp,0,sizeof(cp));
+	
 	cp.structType = sizeof(cp);
 	cp.magic = YAFFS_MAGIC;
 	cp.version = YAFFS_CHECKPOINT_VERSION;
@@ -3684,12 +4273,15 @@ static int yaffs_ReadCheckpointTnodes(ya
 	yaffs_Device *dev = obj->myDev;
 	yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
 	yaffs_Tnode *tn;
+	int nread = 0;
 	
 	ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk));
 	
 	while(ok && (~baseChunk)){
+		nread++;
 		/* Read level 0 tnode */
 		
+		
 		/* printf("read  tnode at %d\n",baseChunk); */
 		tn = yaffs_GetTnodeRaw(dev);
 		if(tn)
@@ -3703,6 +4295,7 @@ static int yaffs_ReadCheckpointTnodes(ya
 					       		fileStructPtr,
 					       		baseChunk,
 					       		tn) ? 1 : 0;
+					       		
 		}
 			
 		if(ok)
@@ -3710,6 +4303,10 @@ static int yaffs_ReadCheckpointTnodes(ya
 		
 	}
 
+	T(YAFFS_TRACE_CHECKPOINT,(
+		TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
+		nread,baseChunk,ok));
+
 	return ok ? 1 : 0;	
 }
  
@@ -3770,16 +4367,18 @@ static int yaffs_ReadCheckpointObjects(y
 	while(ok && !done) {
 		ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
 		if(cp.structType != sizeof(cp)) {
-			/* printf("structure parsing failed\n"); */
+			T(YAFFS_TRACE_CHECKPOINT,(TSTR("struct size %d instead of %d ok %d"TENDSTR),
+				cp.structType,sizeof(cp),ok));
 			ok = 0;
 		}
 			
+		T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
+			cp.objectId,cp.parentId,cp.variantType,cp.chunkId));
+			
 		if(ok && cp.objectId == ~0)
 			done = 1;
 		else if(ok){
 			obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType);
-			T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
-				cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj));
 			if(obj) {
 				yaffs_CheckpointObjectToObject(obj,&cp);
 				if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
@@ -3801,22 +4400,76 @@ static int yaffs_ReadCheckpointObjects(y
 	return ok ? 1 : 0;
 }
 
-static int yaffs_WriteCheckpointData(yaffs_Device *dev)
-{
-
+static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
+{
+	__u32 checkpointSum;
+	int ok;
+	
+	yaffs_GetCheckpointSum(dev,&checkpointSum);
+	
+	ok = (yaffs_CheckpointWrite(dev,&checkpointSum,sizeof(checkpointSum)) == sizeof(checkpointSum));
+	
+	if(!ok)
+		return 0;
+	
+	return 1;
+}
+
+static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
+{
+	__u32 checkpointSum0;
+	__u32 checkpointSum1;
 	int ok;
 	
-	ok = yaffs_CheckpointOpen(dev,1);
-	
+	yaffs_GetCheckpointSum(dev,&checkpointSum0);
+	
+	ok = (yaffs_CheckpointRead(dev,&checkpointSum1,sizeof(checkpointSum1)) == sizeof(checkpointSum1));
+	
+	if(!ok)
+		return 0;
+		
+	if(checkpointSum0 != checkpointSum1)
+		return 0;
+	
+	return 1;
+}
+
+
+static int yaffs_WriteCheckpointData(yaffs_Device *dev)
+{
+
+	int ok = 1;
+	
+	if(dev->skipCheckpointWrite || !dev->isYaffs2){
+		T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint write" TENDSTR)));
+		ok = 0;
+	}
+		
 	if(ok)
+		ok = yaffs_CheckpointOpen(dev,1);
+	
+	if(ok){
+		T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR)));
 		ok = yaffs_WriteCheckpointValidityMarker(dev,1);
-	if(ok)
+	}
+	if(ok){
+		T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint device" TENDSTR)));
 		ok = yaffs_WriteCheckpointDevice(dev);
-	if(ok)
+	}
+	if(ok){
+		T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint objects" TENDSTR)));
 		ok = yaffs_WriteCheckpointObjects(dev);
-	if(ok)
+	}
+	if(ok){
+		T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR)));
 		ok = yaffs_WriteCheckpointValidityMarker(dev,0);
-		
+	}
+	
+	if(ok){
+		ok = yaffs_WriteCheckpointSum(dev);
+	}
+	
+	
 	if(!yaffs_CheckpointClose(dev))
 		 ok = 0;
 		 
@@ -3830,20 +4483,37 @@ static int yaffs_WriteCheckpointData(yaf
 
 static int yaffs_ReadCheckpointData(yaffs_Device *dev)
 {
-	int ok;
-	
-	ok = yaffs_CheckpointOpen(dev,0); /* open for read */
+	int ok = 1;
+	
+	if(dev->skipCheckpointRead || !dev->isYaffs2){
+		T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint read" TENDSTR)));
+		ok = 0;
+	}
 	
 	if(ok)
+		ok = yaffs_CheckpointOpen(dev,0); /* open for read */
+	
+	if(ok){
+		T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR)));	
 		ok = yaffs_ReadCheckpointValidityMarker(dev,1);
-	if(ok)
+	}
+	if(ok){
+		T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint device" TENDSTR)));
 		ok = yaffs_ReadCheckpointDevice(dev);
-	if(ok)
+	}
+	if(ok){
+		T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint objects" TENDSTR)));	
 		ok = yaffs_ReadCheckpointObjects(dev);
-	if(ok)
+	}
+	if(ok){
+		T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR)));
 		ok = yaffs_ReadCheckpointValidityMarker(dev,0);
-		
-
+	}
+	
+	if(ok){
+		ok = yaffs_ReadCheckpointSum(dev);
+		T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint checksum %d" TENDSTR),ok));
+	}
 
 	if(!yaffs_CheckpointClose(dev))
 		ok = 0;
@@ -3871,13 +4541,19 @@ static void yaffs_InvalidateCheckpoint(y
 
 int yaffs_CheckpointSave(yaffs_Device *dev)
 {
-	yaffs_ReportOddballBlocks(dev);
+
 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
 
-	if(!dev->isCheckpointed)
+	yaffs_VerifyObjects(dev);
+	yaffs_VerifyBlocks(dev);
+	yaffs_VerifyFreeChunks(dev);
+
+	if(!dev->isCheckpointed) {
+		yaffs_InvalidateCheckpoint(dev);
 		yaffs_WriteCheckpointData(dev);
-	
-	T(YAFFS_TRACE_CHECKPOINT,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
+	}
+	
+	T(YAFFS_TRACE_ALWAYS,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
 
 	return dev->isCheckpointed;
 }
@@ -3886,13 +4562,17 @@ int yaffs_CheckpointRestore(yaffs_Device
 {
 	int retval;
 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
-	
+		
 	retval = yaffs_ReadCheckpointData(dev);
 
+	if(dev->isCheckpointed){
+		yaffs_VerifyObjects(dev);
+		yaffs_VerifyBlocks(dev);
+		yaffs_VerifyFreeChunks(dev);
+	}
+
 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
 	
-	yaffs_ReportOddballBlocks(dev);
-	
 	return retval;
 }
 
@@ -4269,7 +4949,7 @@ int yaffs_ResizeFile(yaffs_Object * in, 
 	int newFullChunks;
 	
 	yaffs_Device *dev = in->myDev;
-	
+
 	yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
 
 	yaffs_FlushFilesChunkCache(in);
@@ -4380,7 +5060,7 @@ static int yaffs_DoGenericObjectDeletion
 
 	if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
 		/* Move to the unlinked directory so we have a record that it was deleted. */
-		yaffs_ChangeObjectName(in, in->myDev->deletedDir, NULL, 0, 0);
+		yaffs_ChangeObjectName(in, in->myDev->deletedDir,"deleted", 0, 0);
 
 	}
 
@@ -4418,7 +5098,7 @@ static int yaffs_UnlinkFile(yaffs_Object
 		if (immediateDeletion) {
 			retVal =
 			    yaffs_ChangeObjectName(in, in->myDev->deletedDir,
-						   NULL, 0, 0);
+						   "deleted", 0, 0);
 			T(YAFFS_TRACE_TRACING,
 			  (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
 			   in->objectId));
@@ -4431,7 +5111,7 @@ static int yaffs_UnlinkFile(yaffs_Object
 		} else {
 			retVal =
 			    yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
-						   NULL, 0, 0);
+						   "unlinked", 0, 0);
 		}
 
 	}
@@ -4692,13 +5372,15 @@ static int yaffs_Scan(yaffs_Device * dev
 	int deleted;
 	yaffs_BlockState state;
 	yaffs_Object *hardList = NULL;
-	yaffs_Object *hl;
 	yaffs_BlockInfo *bi;
 	int sequenceNumber;
 	yaffs_ObjectHeader *oh;
 	yaffs_Object *in;
 	yaffs_Object *parent;
 	int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
+	
+	int alloc_failed = 0;
+	
 
 	__u8 *chunkData;
 
@@ -4722,6 +5404,8 @@ static int yaffs_Scan(yaffs_Device * dev
 
 	if (dev->isYaffs2) {
 		blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
+		if(!blockIndex)
+			return YAFFS_FAIL;
 	}
 
 	/* Scan all the blocks to determine their state */
@@ -4803,7 +5487,7 @@ static int yaffs_Scan(yaffs_Device * dev
 	}
 
 	/* For each block.... */
-	for (blockIterator = startIterator; blockIterator <= endIterator;
+	for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
 	     blockIterator++) {
 
 		if (dev->isYaffs2) {
@@ -4819,7 +5503,7 @@ static int yaffs_Scan(yaffs_Device * dev
 		deleted = 0;
 
 		/* For each chunk in each block that needs scanning....*/
-		for (c = 0; c < dev->nChunksPerBlock &&
+		for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&
 		     state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
 			/* Read the tags and decide what to do */
 			chunk = blk * dev->nChunksPerBlock + c;
@@ -4887,12 +5571,20 @@ static int yaffs_Scan(yaffs_Device * dev
 				/* PutChunkIntoFile checks for a clash (two data chunks with
 				 * the same chunkId).
 				 */
-				yaffs_PutChunkIntoFile(in, tags.chunkId, chunk,
-						       1);
+				 
+				if(!in)
+					alloc_failed = 1;
+
+				if(in){
+					if(!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk,1))
+						alloc_failed = 1;
+				}
+				
 				endpos =
 				    (tags.chunkId - 1) * dev->nDataBytesPerChunk +
 				    tags.byteCount;
-				if (in->variantType == YAFFS_OBJECT_TYPE_FILE
+				if (in && 
+				    in->variantType == YAFFS_OBJECT_TYPE_FILE
 				    && in->variant.fileVariant.scannedFileSize <
 				    endpos) {
 					in->variant.fileVariant.
@@ -4937,14 +5629,17 @@ static int yaffs_Scan(yaffs_Device * dev
 								      objectId,
 								      oh->type);
 
-				if (oh->shadowsObject > 0) {
+				if(!in)
+					alloc_failed = 1;
+					
+				if (in && oh->shadowsObject > 0) {
 					yaffs_HandleShadowedObject(dev,
 								   oh->
 								   shadowsObject,
 								   0);
 				}
 
-				if (in->valid) {
+				if (in && in->valid) {
 					/* We have already filled this one. We have a duplicate and need to resolve it. */
 
 					unsigned existingSerial = in->serial;
@@ -4965,7 +5660,7 @@ static int yaffs_Scan(yaffs_Device * dev
 					}
 				}
 
-				if (!in->valid &&
+				if (in && !in->valid &&
 				    (tags.objectId == YAFFS_OBJECTID_ROOT ||
 				     tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
 					/* We only load some info, don't fiddle with directory structure */
@@ -4990,7 +5685,7 @@ static int yaffs_Scan(yaffs_Device * dev
 #endif
 					in->chunkId = chunk;
 
-				} else if (!in->valid) {
+				} else if (in && !in->valid) {
 					/* we need to load this info */
 
 					in->valid = 1;
@@ -5099,9 +5794,10 @@ static int yaffs_Scan(yaffs_Device * dev
 						/* Do nothing */
 						break;
 					case YAFFS_OBJECT_TYPE_SYMLINK:	
-						in->variant.symLinkVariant.
-						    alias =
+						in->variant.symLinkVariant.alias =
 						    yaffs_CloneString(oh->alias);
+						if(!in->variant.symLinkVariant.alias)
+							alloc_failed = 1;
 						break;
 					}
 
@@ -5163,7 +5859,12 @@ static int yaffs_Scan(yaffs_Device * dev
 
 	yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
 
+	if(alloc_failed){
+		return YAFFS_FAIL;
+	}
+	
 	T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
+	
 
 	return YAFFS_OK;
 }
@@ -5175,13 +5876,17 @@ static void yaffs_CheckObjectDetailsLoad
 	yaffs_Device *dev = in->myDev;
 	yaffs_ExtendedTags tags;
 	int result;
-	
+	int alloc_failed = 0;
+
+	if(!in)
+		return;
+		
 #if 0
 	T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR),
 		in->objectId,
 		in->lazyLoaded ? "not yet" : "already"));
 #endif
-		
+
 	if(in->lazyLoaded){
 		in->lazyLoaded = 0;
 		chunkData = yaffs_GetTempBuffer(dev, __LINE__);
@@ -5208,9 +5913,12 @@ static void yaffs_CheckObjectDetailsLoad
 #endif
 		yaffs_SetObjectName(in, oh->name);
 		
-		if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
+		if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK){
 			 in->variant.symLinkVariant.alias =
 						    yaffs_CloneString(oh->alias);
+			if(!in->variant.symLinkVariant.alias)
+				alloc_failed = 1; /* Not returned to caller */
+		}
 						    
 		yaffs_ReleaseTempBuffer(dev,chunkData, __LINE__);
 	}
@@ -5244,6 +5952,7 @@ static int yaffs_ScanBackwards(yaffs_Dev
 	int isShrink;
 	int foundChunksInBlock;
 	int equivalentObjectId;
+	int alloc_failed = 0;
 	
 
 	yaffs_BlockIndex *blockIndex = NULL;
@@ -5276,6 +5985,8 @@ static int yaffs_ScanBackwards(yaffs_Dev
 		return YAFFS_FAIL;
 	}
 	
+	dev->blocksInCheckpoint = 0;
+	
 	chunkData = yaffs_GetTempBuffer(dev, __LINE__);
 
 	/* Scan all the blocks to determine their state */
@@ -5299,7 +6010,7 @@ static int yaffs_ScanBackwards(yaffs_Dev
 
 		
 		if(state == YAFFS_BLOCK_STATE_CHECKPOINT){
-			/* todo .. fix free space ? */
+			dev->blocksInCheckpoint++;
 			
 		} else if (state == YAFFS_BLOCK_STATE_DEAD) {
 			T(YAFFS_TRACE_BAD_BLOCKS,
@@ -5377,7 +6088,7 @@ static int yaffs_ScanBackwards(yaffs_Dev
 	  (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
 
 	/* For each block.... backwards */
-	for (blockIterator = endIterator; blockIterator >= startIterator;
+	for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
 	     blockIterator--) {
 	        /* Cooperative multitasking! This loop can run for so
 		   long that watchdog timers expire. */
@@ -5387,18 +6098,22 @@ static int yaffs_ScanBackwards(yaffs_Dev
 		blk = blockIndex[blockIterator].block;
 
 		bi = yaffs_GetBlockInfo(dev, blk);
+		
+		
 		state = bi->blockState;
 
 		deleted = 0;
 
 		/* For each chunk in each block that needs scanning.... */
 		foundChunksInBlock = 0;
-		for (c = dev->nChunksPerBlock - 1; c >= 0 &&
+		for (c = dev->nChunksPerBlock - 1; 
+		     !alloc_failed && c >= 0 &&
 		     (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
 		      state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
 			/* Scan backwards... 
 			 * Read the tags and decide what to do
 			 */
+			
 			chunk = blk * dev->nChunksPerBlock + c;
 
 			result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
@@ -5476,12 +6191,20 @@ static int yaffs_ScanBackwards(yaffs_Dev
 								      tags.
 								      objectId,
 								      YAFFS_OBJECT_TYPE_FILE);
-				if (in->variantType == YAFFS_OBJECT_TYPE_FILE
+				if(!in){
+					/* Out of memory */
+					alloc_failed = 1;
+				}
+				
+				if (in &&
+				    in->variantType == YAFFS_OBJECT_TYPE_FILE
 				    && chunkBase <
 				    in->variant.fileVariant.shrinkSize) {
 					/* This has not been invalidated by a resize */
-					yaffs_PutChunkIntoFile(in, tags.chunkId,
-							       chunk, -1);
+					if(!yaffs_PutChunkIntoFile(in, tags.chunkId,
+							       chunk, -1)){
+						alloc_failed = 1;
+					}
 
 					/* File size is calculated by looking at the data chunks if we have not 
 					 * seen an object header yet. Stop this practice once we find an object header.
@@ -5502,7 +6225,7 @@ static int yaffs_ScanBackwards(yaffs_Dev
 						    scannedFileSize;
 					}
 
-				} else {
+				} else if(in) {
 					/* This chunk has been invalidated by a resize, so delete */
 					yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
 
@@ -5790,16 +6513,21 @@ static int yaffs_ScanBackwards(yaffs_Dev
 						/* Do nothing */
 						break;
 					case YAFFS_OBJECT_TYPE_SYMLINK:
-						if(oh)
+						if(oh){
 						   in->variant.symLinkVariant.alias =
 						    yaffs_CloneString(oh->
 								      alias);
+						   if(!in->variant.symLinkVariant.alias)
+						   	alloc_failed = 1;
+						}
 						break;
 					}
 
 				}
+				
 			}
-		}
+
+		} /* End of scanning for each chunk */
 
 		if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
 			/* If we got this far while scanning, then the block is fully allocated. */
@@ -5862,6 +6590,10 @@ static int yaffs_ScanBackwards(yaffs_Dev
 	}
 
 	yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
+	
+	if(alloc_failed){
+		return YAFFS_FAIL;
+	}
 
 	T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
 
@@ -5969,7 +6701,7 @@ yaffs_Object *yaffs_FindObjectByName(yaf
 				 */
 				yaffs_GetObjectName(l, buffer,
 						    YAFFS_MAX_NAME_LENGTH);
-				if (yaffs_strcmp(name, buffer) == 0) {
+				if (yaffs_strncmp(name, buffer,YAFFS_MAX_NAME_LENGTH) == 0) {
 					return l;
 				}
 
@@ -6025,6 +6757,7 @@ yaffs_Object *yaffs_GetEquivalentObject(
 	if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
 		/* We want the object id of the equivalent object, not this one */
 		obj = obj->variant.hardLinkVariant.equivalentObject;
+		yaffs_CheckObjectDetailsLoaded(obj);
 	}
 	return obj;
 
@@ -6262,7 +6995,7 @@ static int yaffs_CheckDevFunctions(const
 }
 
 
-static void yaffs_CreateInitialDirectories(yaffs_Device *dev)
+static int yaffs_CreateInitialDirectories(yaffs_Device *dev)
 {
 	/* Initialise the unlinked, deleted, root and lost and found directories */
 	
@@ -6271,6 +7004,7 @@ static void yaffs_CreateInitialDirectori
 
 	dev->unlinkedDir =
 	    yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
+	
 	dev->deletedDir =
 	    yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
 
@@ -6280,11 +7014,18 @@ static void yaffs_CreateInitialDirectori
 	dev->lostNFoundDir =
 	    yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND,
 				      YAFFS_LOSTNFOUND_MODE | S_IFDIR);
-	yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir);
+	
+	if(dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir){
+		yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir);
+		return YAFFS_OK;
+	}
+	
+	return YAFFS_FAIL;
 }
 
 int yaffs_GutsInitialise(yaffs_Device * dev)
 {
+	int init_failed = 0;
 	unsigned x;
 	int bits;
 
@@ -6456,71 +7197,111 @@ int yaffs_GutsInitialise(yaffs_Device * 
 	dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */
 
 	/* Initialise temporary buffers and caches. */
-	{
+	if(!yaffs_InitialiseTempBuffers(dev))
+		init_failed = 1;
+	
+	dev->srCache = NULL;
+	dev->gcCleanupList = NULL;
+	
+	
+	if (!init_failed &&
+	    dev->nShortOpCaches > 0) {
 		int i;
-		for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
-			dev->tempBuffer[i].line = 0;	/* not in use */
-			dev->tempBuffer[i].buffer =
-			    YMALLOC_DMA(dev->nDataBytesPerChunk);
-		}
-	}
-	
-	if (dev->nShortOpCaches > 0) {
-		int i;
+		__u8 *buf;
+		int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);
 
 		if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) {
 			dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
 		}
 
-		dev->srCache =
-		    YMALLOC(dev->nShortOpCaches * sizeof(yaffs_ChunkCache));
-
-		for (i = 0; i < dev->nShortOpCaches; i++) {
+		buf = dev->srCache =  YMALLOC(srCacheBytes);
+		    
+		if(dev->srCache)
+			memset(dev->srCache,0,srCacheBytes);
+		   
+		for (i = 0; i < dev->nShortOpCaches && buf; i++) {
 			dev->srCache[i].object = NULL;
 			dev->srCache[i].lastUse = 0;
 			dev->srCache[i].dirty = 0;
-			dev->srCache[i].data = YMALLOC_DMA(dev->nDataBytesPerChunk);
+			dev->srCache[i].data = buf = YMALLOC_DMA(dev->nDataBytesPerChunk);
 		}
+		if(!buf)
+			init_failed = 1;
+			
 		dev->srLastUse = 0;
 	}
 
 	dev->cacheHits = 0;
 	
-	dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
+	if(!init_failed){
+		dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
+		if(!dev->gcCleanupList)
+			init_failed = 1;
+	}
 
 	if (dev->isYaffs2) {
 		dev->useHeaderFileSize = 1;
 	}
-
-	yaffs_InitialiseBlocks(dev);
+	if(!init_failed && !yaffs_InitialiseBlocks(dev))
+		init_failed = 1;
+		
 	yaffs_InitialiseTnodes(dev);
 	yaffs_InitialiseObjects(dev);
 
-	yaffs_CreateInitialDirectories(dev);
-
-
-	/* Now scan the flash. */
-	if (dev->isYaffs2) {
-		if(yaffs_CheckpointRestore(dev)) {
-			T(YAFFS_TRACE_ALWAYS,
-			  (TSTR("yaffs: restored from checkpoint" TENDSTR)));
-		} else {
-
-			/* Clean up the mess caused by an aborted checkpoint load 
-			 * and scan backwards. 
-			 */
-			yaffs_DeinitialiseBlocks(dev);
-			yaffs_DeinitialiseTnodes(dev);
-			yaffs_DeinitialiseObjects(dev);
-			yaffs_InitialiseBlocks(dev);
-			yaffs_InitialiseTnodes(dev);
-			yaffs_InitialiseObjects(dev);
-			yaffs_CreateInitialDirectories(dev);
-
-			yaffs_ScanBackwards(dev);
-		}
-	}else
-		yaffs_Scan(dev);
+	if(!init_failed && !yaffs_CreateInitialDirectories(dev))
+		init_failed = 1;
+
+
+	if(!init_failed){
+		/* Now scan the flash. */
+		if (dev->isYaffs2) {
+			if(yaffs_CheckpointRestore(dev)) {
+				T(YAFFS_TRACE_ALWAYS,
+				  (TSTR("yaffs: restored from checkpoint" TENDSTR)));
+			} else {
+
+				/* Clean up the mess caused by an aborted checkpoint load 
+				 * and scan backwards. 
+				 */
+				yaffs_DeinitialiseBlocks(dev);
+				yaffs_DeinitialiseTnodes(dev);
+				yaffs_DeinitialiseObjects(dev);
+				
+			
+				dev->nErasedBlocks = 0;
+				dev->nFreeChunks = 0;
+				dev->allocationBlock = -1;
+				dev->allocationPage = -1;
+				dev->nDeletedFiles = 0;
+				dev->nUnlinkedFiles = 0;
+				dev->nBackgroundDeletions = 0;
+				dev->oldestDirtySequence = 0;
+
+				if(!init_failed && !yaffs_InitialiseBlocks(dev))
+					init_failed = 1;
+					
+				yaffs_InitialiseTnodes(dev);
+				yaffs_InitialiseObjects(dev);
+
+				if(!init_failed && !yaffs_CreateInitialDirectories(dev))
+					init_failed = 1;
+
+				if(!init_failed && !yaffs_ScanBackwards(dev))
+					init_failed = 1;
+			}
+		}else
+			if(!yaffs_Scan(dev))
+				init_failed = 1;
+	}
+		
+	if(init_failed){
+		/* Clean up the mess */
+		T(YAFFS_TRACE_TRACING,
+		  (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR)));
+
+		yaffs_Deinitialise(dev);
+		return YAFFS_FAIL;
+	}
 
 	/* Zero out stats */
 	dev->nPageReads = 0;
@@ -6532,6 +7313,8 @@ int yaffs_GutsInitialise(yaffs_Device * 
 	dev->nRetiredBlocks = 0;
 
 	yaffs_VerifyFreeChunks(dev);
+	yaffs_VerifyBlocks(dev);
+	
 
 	T(YAFFS_TRACE_TRACING,
 	  (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
@@ -6547,13 +7330,17 @@ void yaffs_Deinitialise(yaffs_Device * d
 		yaffs_DeinitialiseBlocks(dev);
 		yaffs_DeinitialiseTnodes(dev);
 		yaffs_DeinitialiseObjects(dev);
-		if (dev->nShortOpCaches > 0) {
+		if (dev->nShortOpCaches > 0 &&
+		    dev->srCache) {
 
 			for (i = 0; i < dev->nShortOpCaches; i++) {
-				YFREE(dev->srCache[i].data);
+				if(dev->srCache[i].data)
+					YFREE(dev->srCache[i].data);
+				dev->srCache[i].data = NULL;
 			}
 
 			YFREE(dev->srCache);
+			dev->srCache = NULL;
 		}
 
 		YFREE(dev->gcCleanupList);
@@ -6644,9 +7431,15 @@ static int yaffs_freeVerificationFailure
 
 static void yaffs_VerifyFreeChunks(yaffs_Device * dev)
 {
-	int counted = yaffs_CountFreeChunks(dev);
-
-	int difference = dev->nFreeChunks - counted;
+	int counted;
+	int difference;
+	
+	if(yaffs_SkipVerification(dev))
+		return;
+	
+	counted = yaffs_CountFreeChunks(dev);
+
+	difference = dev->nFreeChunks - counted;
 
 	if (difference) {
 		T(YAFFS_TRACE_ALWAYS,
--- a/yaffs_guts.h
+++ b/yaffs_guts.h
@@ -63,9 +63,7 @@
 
 #define YAFFS_OBJECT_SPACE		0x40000
 
-#define YAFFS_NCHECKPOINT_OBJECTS	5000
-
-#define YAFFS_CHECKPOINT_VERSION 	2
+#define YAFFS_CHECKPOINT_VERSION 	3
 
 #ifdef CONFIG_YAFFS_UNICODE
 #define YAFFS_MAX_NAME_LENGTH		127
@@ -162,6 +160,8 @@ typedef enum {
 	YAFFS_OBJECT_TYPE_SPECIAL
 } yaffs_ObjectType;
 
+#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
+
 typedef struct {
 
 	unsigned validMarker0;
@@ -264,6 +264,9 @@ typedef enum {
 	/* This block has failed and is not in use */
 } yaffs_BlockState;
 
+#define	YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
+
+
 typedef struct {
 
 	int softDeletions:10;	/* number of soft deleted pages */
@@ -272,7 +275,7 @@ typedef struct {
 	__u32 needsRetiring:1;	/* Data has failed on this block, need to get valid data off */
                         	/* and retire the block. */
 	__u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */
-	__u32 gcPrioritise: 1; 	/* An ECC check or bank check has failed on this block. 
+	__u32 gcPrioritise: 1; 	/* An ECC check or blank check has failed on this block. 
 				   It should be prioritised for GC */
         __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
 
@@ -531,9 +534,6 @@ struct yaffs_DeviceStruct {
 	int nReservedBlocks;	/* We want this tuneable so that we can reduce */
 				/* reserved blocks on NOR and RAM. */
 	
-	/* Stuff used by the partitioned checkpointing mechanism */
-	int checkpointStartBlock;
-	int checkpointEndBlock;
 	
 	/* Stuff used by the shared space checkpointing mechanism */
 	/* If this value is zero, then this mechanism is disabled */
@@ -595,6 +595,10 @@ struct yaffs_DeviceStruct {
 	
 
 	/* End of stuff that must be set before initialisation. */
+	
+	/* Checkpoint control. Can be set before or after initialisation */
+	__u8 skipCheckpointRead;
+	__u8 skipCheckpointWrite;
 
 	/* Runtime parameters. Set up by YAFFS. */
 
@@ -650,6 +654,8 @@ struct yaffs_DeviceStruct {
 	int checkpointNextBlock;
 	int *checkpointBlockList;
 	int checkpointMaxBlocks;
+	__u32 checkpointSum;
+	__u32 checkpointXor;
 	
 	/* Block Info */
 	yaffs_BlockInfo *blockInfo;
--- a/yportenv.h
+++ b/yportenv.h
@@ -41,6 +41,7 @@
 #define _Y(x)     x
 #define yaffs_strcpy(a,b)    strcpy(a,b)
 #define yaffs_strncpy(a,b,c) strncpy(a,b,c)
+#define yaffs_strncmp(a,b,c) strncmp(a,b,c)
 #define yaffs_strlen(s)	     strlen(s)
 #define yaffs_sprintf	     sprintf
 #define yaffs_toupper(a)     toupper(a)
@@ -60,7 +61,7 @@
 // KR - added for use in scan so processes aren't blocked indefinitely.
 #define YYIELD() schedule()
 
-#define YAFFS_ROOT_MODE				0666
+#define YAFFS_ROOT_MODE			0666
 #define YAFFS_LOSTNFOUND_MODE		0666
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
@@ -134,7 +135,11 @@
 
 extern unsigned yaffs_traceMask;
 
-#define YAFFS_TRACE_ERROR		0x00000001
+/*
+ * Tracing flags.
+ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
+ */
+ 
 #define YAFFS_TRACE_OS			0x00000002
 #define YAFFS_TRACE_ALLOCATE		0x00000004
 #define YAFFS_TRACE_SCAN		0x00000008
@@ -150,10 +155,19 @@ extern unsigned yaffs_traceMask;
 #define YAFFS_TRACE_SCAN_DEBUG		0x00002000
 #define YAFFS_TRACE_MTD			0x00004000
 #define YAFFS_TRACE_CHECKPOINT		0x00008000
-#define YAFFS_TRACE_ALWAYS		0x40000000
+
+#define YAFFS_TRACE_VERIFY		0x00010000
+#define YAFFS_TRACE_VERIFY_NAND		0x00020000
+#define YAFFS_TRACE_VERIFY_FULL		0x00040000
+#define YAFFS_TRACE_VERIFY_ALL		0x000F0000
+
+
+#define YAFFS_TRACE_ERROR		0x40000000
 #define YAFFS_TRACE_BUG			0x80000000
+#define YAFFS_TRACE_ALWAYS		0xF0000000
 
-#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ERROR)) TOUT(p);} while(0)
+
+#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
 
 #ifndef CONFIG_YAFFS_WINCE
 #define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))