changeset 248:a8738fee77c1

Restructure tests
author charles
date Sun, 04 Jan 2009 21:44:24 +0000
parents a759c32d15f1
children 2e6d0dd55c20
files direct/Makefile direct/dtest.c direct/nor_stress.c direct/nor_stress.h direct/run_fw_update_test.sh direct/tests/Makefile direct/tests/README direct/tests/init_fw_update_test.sh direct/tests/nor_stress.c direct/tests/nor_stress.h direct/tests/run_fw_update_test.sh direct/tests/yaffs_fsx.c direct/tests/yaffs_fsx.h direct/tests/yaffs_test.c direct/yaffs_test.c direct/yaffscfg2k.c direct/ynorsim.c yaffs_guts.c
diffstat 18 files changed, 1555 insertions(+), 454 deletions(-) [+]
line wrap: on
line diff
--- a/direct/Makefile
+++ b/direct/Makefile
@@ -33,11 +33,10 @@ COMMONTESTOBJS = yaffscfg2k.o yaffs_ecc.
 		 yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \
 		 yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \
 		 yaffs_checkptrw.o  yaffs_qsort.o\
-		 yaffs_norif1.o  ynorsim.o nor_stress.o
+		 yaffs_norif1.o  ynorsim.o
 #		 yaffs_checkptrwtest.o\
 
 DIRECTTESTOBJS = $(COMMONTESTOBJS) dtest.o
-YAFFSTESTOBJS  = $(COMMONTESTOBJS) yaffs_test.o
 
 BOOTTESTOBJS = bootldtst.o yboot.o yaffs_fileem.o nand_ecc.o
 
@@ -53,7 +52,7 @@ SYMLINKS = devextras.h yaffs_ecc.c yaffs
 
 #all: directtest2k boottest
 
-all: directtest2k yaffs_test
+all: directtest2k
 
 $(ALLOBJS): %.o: %.c
 	gcc -c $(CFLAGS) -o $@ $<
--- a/direct/dtest.c
+++ b/direct/dtest.c
@@ -2318,7 +2318,7 @@ int main(int argc, char *argv[])
 
 	//rename_over_test("//////////////////flash///////////////////yaffs1///////////");
 	
-	rmdir_test("M18-1");
+	rmdir_test("/M18-1");
 	
 	 //scan_pattern_test("/flash",10000,10);
 	//short_scan_test("/flash/flash",40000,200);
deleted file mode 100644
--- a/direct/nor_stress.c
+++ /dev/null
@@ -1,360 +0,0 @@
-#include "nor_stress.h"
-
-
-#include "yaffsfs.h"
-
-#include <stdio.h>
-
-
-
-static unsigned powerUps;
-static unsigned cycleStarts;
-static unsigned cycleEnds;
-
-
-char fullPathName[100];
-char fullPowerUpName[100];
-char fullStartName[100];
-char fullEndName[100];
-char fullMainName[100];
-char fullTempMainName[100];
-char fullTempCounterName[100];
-
-
-void MakeName(char *fullName,const char *prefix, const char *name)
-{
-  strcpy(fullName,prefix);
-  strcat(fullName,"/");
-  strcat(fullName,name);
-}
-
-
-void MakeFullNames(const char *prefix)
-{
-  MakeName(fullPathName,prefix,"");
-  MakeName(fullPowerUpName,prefix,"powerUps");
-  MakeName(fullStartName,prefix,"starts");
-  MakeName(fullEndName,prefix,"ends");
-  MakeName(fullMainName,prefix,"main");
-  MakeName(fullTempCounterName,prefix,"tmp-counter");
-  MakeName(fullTempMainName,prefix,"tmp-main");
-}
-
-static void FatalError(void)
-{
-  printf("Integrity error\n");
-  while(1){}
-}
-
-static void UpdateCounter(const char *name, unsigned *val,  int initialise)
-{
-  int inh=-1;
-  int outh=-1;
-  unsigned x[2];
-  int nread = 0;
-  int nwritten = 0;
-  
-  x[0] = x[1] = 0;
-  
-  if(initialise){
-    x[0] = 0; 
-    x[1] = 1;
-  } else {
-    inh = yaffs_open(name,O_RDONLY, S_IREAD | S_IWRITE);
-    if(inh >= 0){
-      nread = yaffs_read(inh,x,sizeof(x));
-      yaffs_close(inh);
-    }
-
-    if(nread != sizeof(x) ||
-       x[0] + 1 != x[1]){
-      printf("Error reading counter %s handle %d, x[0] %u x[1] %u last error %d\n",
-              name, inh, x[0], x[1],yaffsfs_GetLastError());
-      FatalError();
-              
-    }
-    x[0]++;
-    x[1]++;
-  }
-  
-  outh = yaffs_open(fullTempCounterName, O_RDWR | O_TRUNC | O_CREAT, S_IREAD | S_IWRITE);
-  if(outh >= 0){
-    nwritten = yaffs_write(outh,x,sizeof(x));
-    yaffs_close(outh);
-    yaffs_rename(fullTempCounterName,name);
-  }
-  
-  if(nwritten != sizeof(x)){
-      printf("Error writing counter %s handle %d, x[0] %u x[1] %u\n",
-              name, inh, x[0], x[1]);
-      FatalError();
-  }
-  
-  *val = x[0];
-  
-  printf("##\n"
-         "## Set counter %s to %u\n"
-         "##\n", name,x[0]);
-}
-
-
-static void dump_directory_tree_worker(const char *dname,int recursive)
-{
-	yaffs_DIR *d;
-	yaffs_dirent *de;
-	struct yaffs_stat s;
-	char str[1000];
-			
-	d = yaffs_opendir(dname);
-	
-	if(!d)
-	{
-		printf("opendir failed\n");
-	}
-	else
-	{
-		while((de = yaffs_readdir(d)) != NULL)
-		{
-			strcpy(str,dname);
-			strcat(str,"/");
-			strcat(str,de->d_name);
-			
-			yaffs_lstat(str,&s);
-			
-			printf("%s inode %d obj %x length %d mode %X ",str,s.st_ino,de->d_dont_use,(int)s.st_size,s.st_mode);
-			switch(s.st_mode & S_IFMT)
-			{
-				case S_IFREG: printf("data file"); break;
-				case S_IFDIR: printf("directory"); break;
-				case S_IFLNK: printf("symlink -->");
-							  if(yaffs_readlink(str,str,100) < 0)
-								printf("no alias");
-							  else
-								printf("\"%s\"",str);    
-							  break;
-				default: printf("unknown"); break;
-			}
-			
-			printf("\n");
-
-			if((s.st_mode & S_IFMT) == S_IFDIR && recursive)
-				dump_directory_tree_worker(str,1);
-				
-                        if(s.st_ino > 10000)
-                          FatalError();
-							
-		}
-		
-		yaffs_closedir(d);
-	}
-
-}
-
-static void dump_directory_tree(const char *dname)
-{
-	dump_directory_tree_worker(dname,1);
-	printf("\n");
-	printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname));
-}
-
-
-
-
-#define XX_SIZE 500
-
-static unsigned xx[XX_SIZE];
-
-static int yWriteFile(const char *fname, unsigned sz32)
-{
-	int h;
-	int r;
-	int i;
-	unsigned checksum = 0;
-	
-	printf("Writing file %s\n",fname);
-
-	h = yaffs_open(fname,O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
-
-	if(h < 0){
-		printf("could not open file %s\n",fname);
-		return h;
-	}
-
-        xx[0] = sz32;
-        checksum ^= xx[0];
-
-	if((r = yaffs_write(h,xx,sizeof(unsigned))) != sizeof(unsigned)){
-		goto WRITE_ERROR;
-	}
-		
-	while(sz32> 0){
-        	for(i = 0; i < XX_SIZE; i++){
-        	  xx[i] = sz32 + i;
-        	  checksum ^= xx[i];
-                }
-
-		if((r = yaffs_write(h,xx,sizeof(xx))) != sizeof(xx)){
-			goto WRITE_ERROR;
-		}
-		sz32--;
-	}
-
-	xx[0] = checksum;
-
-	if((r = yaffs_write(h,xx,sizeof(unsigned))) != sizeof(unsigned)){
-		goto WRITE_ERROR;
-	}
-	
-	
-	yaffs_close(h);
-	return 0;
-
-WRITE_ERROR:
-	printf("ywrite error at position %d\n",(int)yaffs_lseek(h,0,SEEK_END));
-	yaffs_close(h);
-	return -1;
-	
-}
-
-static int yVerifyFile(const char *fName)
-{
-	unsigned checksum = 0;
-	unsigned totalSize;
-	unsigned sz32;
-	unsigned recordedSize = 0;
-	int r;
-	int h;
-	int i;
-	int retval = 0;
-
-
-        printf("Verifying file %s\n",fName);
-        	
-	h = yaffs_open(fName, O_RDONLY,S_IREAD | S_IWRITE);
-
-	if(h < 0){
-		printf("could not open file %s\n",fName);
-		return -1;
-	}
-
-	totalSize = yaffs_lseek(h,0,SEEK_END);
-	yaffs_lseek(h,0,SEEK_SET);
-
-	r = yaffs_read(h,&sz32,sizeof(sz32));
-
-	if(r != sizeof(sz32)){
-		printf("reading size failed ... returned %d\n",r);
-		yaffs_close(h);
-		return -1;
-	}
-	
-	recordedSize = sz32 * sizeof(xx) + 8;
-
-	printf("verify %s: file size is %d, recorded size is %d\n", fName, totalSize, recordedSize);
-	if(totalSize != recordedSize){
-		printf("!!!!!!!!!!!!!!!!!!!!!!!!file size is wrong, should be %d, is %d\n", recordedSize,totalSize);
-		yaffs_close(h);
-		return -1;
-	}
-
-	checksum ^= sz32;
-
-
-	while(sz32 > 0){
-		r = yaffs_read(h,xx,sizeof(xx));
-		if(r != sizeof(xx)){
-			printf("!!!!!!!!!!!!!!!!!!!!!!!!!!reading data failed ... returned %d\n",r);
-			yaffs_close(h);
-			return -1;
-		}
-		for(i = 0; i < XX_SIZE; i++)
-		  checksum ^= xx[i];
-		sz32--;
-	}
-	r = yaffs_read(h,xx,sizeof(xx[0]));
-	if(r != sizeof(xx[0])){
-		printf("!!!!!!!!!!!!!!!!!!!!!!!!!!reading data failed ... returned %d\n",r);
-		yaffs_close(h);
-		return -1;
-	}
-	
-	checksum ^= xx[0];
-
-	if(checksum != 0){
-		printf("!!!!!!!!!!!!!!!!!!!!! checksum failed\n");
-		retval = -1;
-        } else
-		printf("verified ok\n");
-	yaffs_close(h);
-
-	return retval;
-}
-
-extern int random_seed;
-
-int myrand(void) {
-  random_seed = random_seed * 1103515245 + 12345;
-  return((unsigned)(random_seed/65536) % 32768);
-}
-
-static void DoUpdateMainFile(void)
-{
-        int result;
-        int sz32;
-        sz32 = (myrand() % 1000)   + 20;
-        
-	result = yWriteFile(fullTempMainName,sz32);
-	if(result)
-	    FatalError();
-	yaffs_rename(fullTempMainName,fullMainName);
-}
-
-static void DoVerifyMainFile(void)
-{
-        int result;
-	result = yVerifyFile(fullMainName);
-	if(result)
-	    FatalError();
-
-}
-
-
-void NorStressTestInitialise(const char *prefix)
-{
-  MakeFullNames(prefix);
-  
-  yaffs_StartUp();
-  yaffs_mount(fullPathName);
-  UpdateCounter(fullPowerUpName,&powerUps,1);
-  UpdateCounter(fullStartName,&cycleStarts,1);
-  UpdateCounter(fullEndName,&cycleEnds,1);
-  UpdateCounter(fullPowerUpName,&powerUps,1);
-  DoUpdateMainFile();
-  DoVerifyMainFile();
-  yaffs_unmount(fullPathName);
-}
-
-
-void NorStressTestRun(const char *prefix)
-{
-  MakeFullNames(prefix);
-
-  yaffs_StartUp();
-  yaffs_mount(fullPathName);
-  
-  dump_directory_tree(fullPathName);
-  
-  UpdateCounter(fullPowerUpName,&powerUps,0);
-  dump_directory_tree(fullPathName);
-  
-  while(1){
-    UpdateCounter(fullStartName, &cycleStarts,0);
-    dump_directory_tree(fullPathName);
-    DoVerifyMainFile();
-    DoUpdateMainFile();
-    dump_directory_tree(fullPathName);
-  
-    UpdateCounter(fullEndName,&cycleEnds,0);
-    dump_directory_tree(fullPathName);
-  }
-}
deleted file mode 100644
--- a/direct/nor_stress.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __NOR_STRESS_H__
-#define __NOR_STRESS_H__
-
-void NorStressTestInitialise(const char *path);
-void NorStressTestRun(const char *path);
-
-#endif
-
deleted file mode 100755
--- a/direct/run_fw_update_test.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-
-for ((i=0; i < 100000; i++))  
-do
-
-   seed=$RANDOM   
-   j=$(( $i % 10 ))
-   rm seed*$j
-   echo $seed>seed$i
-   rm data*$j
-   cp ynorsimdata data$i
-   echo "######### Run $i with seed $seed"
-   ./yaffs_test /M18-1 fw_update $seed
-done
new file mode 100644
--- /dev/null
+++ b/direct/tests/Makefile
@@ -0,0 +1,81 @@
+# Makefile for YAFFS direct stress tests
+#
+#
+# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
+#
+# Copyright (C) 2003 Aleph One Ltd.
+#
+#
+# Created by Charles Manning <charles@aleph1.co.uk>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# NB Warning this Makefile does not include header dependencies.
+#
+# $Id$
+
+#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
+
+CFLAGS =      -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2  
+CFLAGS +=     -DCONFIG_YAFFS_PROVIDE_DEFS -DCONFIG_YAFFSFS_PROVIDE_VALUES -DNO_Y_INLINE
+CFLAGS +=    -Wall -g $(EXTRA_COMPILE_FLAGS) -Wstrict-aliasing 
+#CFLAGS +=    -fno-strict-aliasing
+CFLAGS +=    -O0
+#CFLAGS +=    -DVALGRIND_TEST
+
+#CFLAGS+=   -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations
+#CFLAGS+=   -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline
+
+
+COMMONTESTOBJS = yaffscfg2k.o yaffs_ecc.o yaffs_fileem.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \
+		 yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \
+		 yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \
+		 yaffs_checkptrw.o  yaffs_qsort.o\
+		 yaffs_norif1.o  ynorsim.o nor_stress.o yaffs_fsx.o
+#		 yaffs_checkptrwtest.o\
+
+YAFFSTESTOBJS  = $(COMMONTESTOBJS) yaffs_test.o
+
+
+#ALLOBJS =  dtest.o nand_ecc.o yaffscfg.o yaffs_fileem.o yaffsfs.o yaffs_ramdisk.o bootldtst.o yboot.o yaffs_ramem2k.o
+
+ALLOBJS = $(sort $(YAFFSTESTOBJS))
+
+YAFFSSYMLINKS = devextras.h yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h yaffsinterface.h yportenv.h yaffs_tagscompat.c yaffs_tagscompat.h \
+          yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h  yaffs_nandemul2k.h \
+          yaffs_nand.c yaffs_nand.h yaffs_getblockinfo.h \
+          yaffs_tagsvalidity.c yaffs_tagsvalidity.h yaffs_checkptrw.h yaffs_checkptrw.c \
+          yaffs_qsort.c yaffs_qsort.h
+
+YAFFSDIRECTSYMLINKS =  yaffscfg2k.c yaffs_fileem2k.c yaffsfs.c yaffs_flashif.h yaffs_flashif2.h\
+		       yaffs_fileem2k.h yaffsfs.h yaffs_malloc.h yaffs_ramdisk.h ydirectenv.h \
+		       yaffscfg.h yaffs_fileem.c yaffs_flashif.c yaffs_ramdisk.c yaffs_ramem2k.c\
+		       yaffs_norif1.c yaffs_norif1.h ynorsim.c ynorsim.h
+
+
+SYMLINKS = $(YAFFSSYMLINKS) $(YAFFSDIRECTSYMLINKS)
+#all: directtest2k boottest
+
+all: yaffs_test
+
+$(ALLOBJS): %.o: %.c
+	gcc -c $(CFLAGS) -o $@ $<
+
+
+$(YAFFSSYMLINKS):
+	ln -s ../../$@ $@
+
+$(YAFFSDIRECTSYMLINKS):
+	ln -s ../$@ $@
+
+
+yaffs_test: $(SYMLINKS) $(YAFFSTESTOBJS)
+	gcc -o $@ $(YAFFSTESTOBJS)
+
+
+
+
+clean:
+	rm -f $(ALLOBJS) core
new file mode 100644
--- /dev/null
+++ b/direct/tests/README
@@ -0,0 +1,7 @@
+NB THis directory uses a hacked version of fsx.c which is released under
+Apple Public Source License.
+
+From what I have been able to determine, it is legally OK to release a hacked
+version for the purposes of testing.
+
+If anyone knows otherwise, please contact me: manningc2@actrix.gen.nz
new file mode 100755
--- /dev/null
+++ b/direct/tests/init_fw_update_test.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+# Run this to initialise the file system for the test runs.
+   ./yaffs_test  -u -i M18-1
new file mode 100644
--- /dev/null
+++ b/direct/tests/nor_stress.c
@@ -0,0 +1,391 @@
+#include "nor_stress.h"
+
+
+#include "yaffsfs.h"
+#include "yaffs_fsx.h"
+
+#include <stdio.h>
+
+
+
+#if 1
+#define FSX_INIT(mount_pt) do{ if(interleave_fsx) yaffs_fsx_init(mount_pt); } while(0)
+#define FSX_COMPLETE() do { if(interleave_fsx) yaffs_fsx_complete(); } while (0)
+
+#define FSX() \
+do { \
+  if((myrand() & 0x1) == 0){\
+     if(interleave_fsx) \
+        yaffs_fsx_do_op(); \
+  } \
+} while(0)
+
+#else
+#define FSX_INIT(mount_point) do { } while(0)
+#define FSX_COMPLETE() do { } while(0)
+#define FSX() do { } while(0)
+#endif
+
+
+static unsigned powerUps;
+static unsigned cycleStarts;
+static unsigned cycleEnds;
+
+static int interleave_fsx;
+
+char fullPathName[100];
+char fullPowerUpName[100];
+char fullStartName[100];
+char fullEndName[100];
+char fullMainName[100];
+char fullTempMainName[100];
+char fullTempCounterName[100];
+
+
+extern int random_seed;
+
+int myrand(void) {
+  random_seed = random_seed * 1103515245 + 12345;
+  return((unsigned)(random_seed/65536) % 32768);
+}
+
+void MakeName(char *fullName,const char *prefix, const char *name)
+{
+  strcpy(fullName,prefix);
+  strcat(fullName,"/");
+  strcat(fullName,name);
+}
+
+
+void MakeFullNames(const char *prefix)
+{
+  MakeName(fullPathName,prefix,"");
+  MakeName(fullPowerUpName,prefix,"powerUps");
+  MakeName(fullStartName,prefix,"starts");
+  MakeName(fullEndName,prefix,"ends");
+  MakeName(fullMainName,prefix,"main");
+  MakeName(fullTempCounterName,prefix,"tmp-counter");
+  MakeName(fullTempMainName,prefix,"tmp-main");
+}
+
+static void FatalError(void)
+{
+  printf("Integrity error\n");
+  while(1){}
+}
+
+static void UpdateCounter(const char *name, unsigned *val,  int initialise)
+{
+  int inh=-1;
+  int outh=-1;
+  unsigned x[2];
+  int nread = 0;
+  int nwritten = 0;
+  
+  x[0] = x[1] = 0;
+  
+  if(initialise){
+    x[0] = 0; 
+    x[1] = 1;
+  } else {
+    inh = yaffs_open(name,O_RDONLY, S_IREAD | S_IWRITE);
+    if(inh >= 0){
+      nread = yaffs_read(inh,x,sizeof(x));
+      yaffs_close(inh);
+    }
+
+    if(nread != sizeof(x) ||
+       x[0] + 1 != x[1]){
+      printf("Error reading counter %s handle %d, x[0] %u x[1] %u last error %d\n",
+              name, inh, x[0], x[1],yaffsfs_GetLastError());
+      FatalError();
+              
+    }
+    x[0]++;
+    x[1]++;
+  }
+  
+  FSX();
+  outh = yaffs_open(fullTempCounterName, O_RDWR | O_TRUNC | O_CREAT, S_IREAD | S_IWRITE);
+  if(outh >= 0){
+   FSX(); 
+    nwritten = yaffs_write(outh,x,sizeof(x));
+    FSX();
+    yaffs_close(outh);
+    FSX();
+    yaffs_rename(fullTempCounterName,name);
+    FSX();
+  }
+  
+  if(nwritten != sizeof(x)){
+      printf("Error writing counter %s handle %d, x[0] %u x[1] %u\n",
+              name, inh, x[0], x[1]);
+      FatalError();
+  }
+  
+  *val = x[0];
+  
+  printf("##\n"
+         "## Set counter %s to %u\n"
+         "##\n", name,x[0]);
+}
+
+
+static void dump_directory_tree_worker(const char *dname,int recursive)
+{
+	yaffs_DIR *d;
+	yaffs_dirent *de;
+	struct yaffs_stat s;
+	char str[1000];
+			
+	d = yaffs_opendir(dname);
+	
+	if(!d)
+	{
+		printf("opendir failed\n");
+	}
+	else
+	{
+		while((de = yaffs_readdir(d)) != NULL)
+		{
+			strcpy(str,dname);
+			strcat(str,"/");
+			strcat(str,de->d_name);
+			
+			yaffs_lstat(str,&s);
+			
+			printf("%s inode %d obj %x length %d mode %X ",str,s.st_ino,de->d_dont_use,(int)s.st_size,s.st_mode);
+			switch(s.st_mode & S_IFMT)
+			{
+				case S_IFREG: printf("data file"); break;
+				case S_IFDIR: printf("directory"); break;
+				case S_IFLNK: printf("symlink -->");
+							  if(yaffs_readlink(str,str,100) < 0)
+								printf("no alias");
+							  else
+								printf("\"%s\"",str);    
+							  break;
+				default: printf("unknown"); break;
+			}
+			
+			printf("\n");
+
+			if((s.st_mode & S_IFMT) == S_IFDIR && recursive)
+				dump_directory_tree_worker(str,1);
+				
+                        if(s.st_ino > 10000)
+                          FatalError();
+							
+		}
+		
+		yaffs_closedir(d);
+	}
+
+}
+
+static void dump_directory_tree(const char *dname)
+{
+	dump_directory_tree_worker(dname,1);
+	printf("\n");
+	printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname));
+}
+
+
+
+
+#define XX_SIZE 500
+
+static unsigned xx[XX_SIZE];
+
+static int yWriteFile(const char *fname, unsigned sz32)
+{
+	int h;
+	int r;
+	int i;
+	unsigned checksum = 0;
+	
+	printf("Writing file %s\n",fname);
+
+	FSX();
+	h = yaffs_open(fname,O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
+	FSX();
+
+	if(h < 0){
+		printf("could not open file %s\n",fname);
+		return h;
+	}
+
+        xx[0] = sz32;
+        checksum ^= xx[0];
+
+	if((r = yaffs_write(h,xx,sizeof(unsigned))) != sizeof(unsigned)){
+		goto WRITE_ERROR;
+	}
+        FSX();
+	while(sz32> 0){
+        	for(i = 0; i < XX_SIZE; i++){
+        	  xx[i] = sz32 + i;
+        	  checksum ^= xx[i];
+                }
+                
+                FSX();
+		if((r = yaffs_write(h,xx,sizeof(xx))) != sizeof(xx)){
+			goto WRITE_ERROR;
+		}
+		sz32--;
+	}
+
+	xx[0] = checksum;
+	FSX();
+	if((r = yaffs_write(h,xx,sizeof(unsigned))) != sizeof(unsigned)){
+		goto WRITE_ERROR;
+	}
+	
+	FSX();
+	yaffs_close(h);
+	return 0;
+
+WRITE_ERROR:
+	printf("ywrite error at position %d\n",(int)yaffs_lseek(h,0,SEEK_END));
+	yaffs_close(h);
+	return -1;
+	
+}
+
+static int yVerifyFile(const char *fName)
+{
+	unsigned checksum = 0;
+	unsigned totalSize;
+	unsigned sz32;
+	unsigned recordedSize = 0;
+	int r;
+	int h;
+	int i;
+	int retval = 0;
+
+
+        printf("Verifying file %s\n",fName);
+        	
+	h = yaffs_open(fName, O_RDONLY,S_IREAD | S_IWRITE);
+
+	if(h < 0){
+		printf("could not open file %s\n",fName);
+		return -1;
+	}
+
+	totalSize = yaffs_lseek(h,0,SEEK_END);
+	yaffs_lseek(h,0,SEEK_SET);
+
+	r = yaffs_read(h,&sz32,sizeof(sz32));
+
+	if(r != sizeof(sz32)){
+		printf("reading size failed ... returned %d\n",r);
+		yaffs_close(h);
+		return -1;
+	}
+	
+	recordedSize = sz32 * sizeof(xx) + 8;
+
+	printf("verify %s: file size is %d, recorded size is %d\n", fName, totalSize, recordedSize);
+	if(totalSize != recordedSize){
+		printf("!!!!!!!!!!!!!!!!!!!!!!!!file size is wrong, should be %d, is %d\n", recordedSize,totalSize);
+		yaffs_close(h);
+		return -1;
+	}
+
+	checksum ^= sz32;
+
+
+	while(sz32 > 0){
+		r = yaffs_read(h,xx,sizeof(xx));
+		if(r != sizeof(xx)){
+			printf("!!!!!!!!!!!!!!!!!!!!!!!!!!reading data failed ... returned %d\n",r);
+			yaffs_close(h);
+			return -1;
+		}
+		for(i = 0; i < XX_SIZE; i++)
+		  checksum ^= xx[i];
+		sz32--;
+	}
+	r = yaffs_read(h,xx,sizeof(xx[0]));
+	if(r != sizeof(xx[0])){
+		printf("!!!!!!!!!!!!!!!!!!!!!!!!!!reading data failed ... returned %d\n",r);
+		yaffs_close(h);
+		return -1;
+	}
+	
+	checksum ^= xx[0];
+
+	if(checksum != 0){
+		printf("!!!!!!!!!!!!!!!!!!!!! checksum failed\n");
+		retval = -1;
+        } else
+		printf("verified ok\n");
+	yaffs_close(h);
+
+	return retval;
+}
+
+
+static void DoUpdateMainFile(void)
+{
+        int result;
+        int sz32;
+        sz32 = (myrand() % 1000)   + 20;
+        
+	result = yWriteFile(fullTempMainName,sz32);
+	FSX();
+	if(result)
+	    FatalError();
+	yaffs_rename(fullTempMainName,fullMainName);
+	FSX();
+}
+
+static void DoVerifyMainFile(void)
+{
+        int result;
+	result = yVerifyFile(fullMainName);
+	if(result)
+	    FatalError();
+
+}
+
+
+void NorStressTestInitialise(const char *prefix)
+{
+  MakeFullNames(prefix);
+  
+  UpdateCounter(fullPowerUpName,&powerUps,1);
+  UpdateCounter(fullStartName,&cycleStarts,1);
+  UpdateCounter(fullEndName,&cycleEnds,1);
+  UpdateCounter(fullPowerUpName,&powerUps,1);
+  DoUpdateMainFile();
+  DoVerifyMainFile();
+}
+
+
+void NorStressTestRun(const char *prefix, int n_cycles, int do_fsx)
+{
+  interleave_fsx = do_fsx;
+  MakeFullNames(prefix);
+  FSX_INIT(prefix);
+    
+  dump_directory_tree(fullPathName);
+  
+  UpdateCounter(fullPowerUpName,&powerUps,0);
+  dump_directory_tree(fullPathName);
+  
+  while(n_cycles < 0 || n_cycles > 0){
+    if(n_cycles > 0)
+      n_cycles--;
+    UpdateCounter(fullStartName, &cycleStarts,0);
+    dump_directory_tree(fullPathName);
+    DoVerifyMainFile();
+    DoUpdateMainFile();
+    dump_directory_tree(fullPathName);
+  
+    UpdateCounter(fullEndName,&cycleEnds,0);
+    dump_directory_tree(fullPathName);
+  }
+  FSX_COMPLETE();
+}
new file mode 100644
--- /dev/null
+++ b/direct/tests/nor_stress.h
@@ -0,0 +1,8 @@
+#ifndef __NOR_STRESS_H__
+#define __NOR_STRESS_H__
+
+void NorStressTestInitialise(const char *path);
+void NorStressTestRun(const char *path, int n_cycles, int do_fsx);
+
+#endif
+
new file mode 100755
--- /dev/null
+++ b/direct/tests/run_fw_update_test.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+
+for ((i=0; i < 100000; i++))  
+do
+
+   seed=$RANDOM   
+   j=$(( $i % 10 ))
+   rm seed*$j
+   echo $seed>seed$i
+   rm data*$j
+   cp ynorsimdata data$i
+   echo "######### Run $i with seed $seed"
+   ./yaffs_test -f -u -p -s$seed M18-1
+done
new file mode 100644
--- /dev/null
+++ b/direct/tests/yaffs_fsx.c
@@ -0,0 +1,914 @@
+/*
+ * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.2 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ *	WARNING--WARNING--WARNING
+ *	This is not the original fsx.c. It has been modified to run with
+ *      yaffs direct. Seek out the original fsx.c if you want to do anything
+ *	else.
+ *
+ *	
+ *
+ *	File:	fsx.c
+ *	Author:	Avadis Tevanian, Jr.
+ *
+ *	File system exerciser. 
+ *
+ *	Rewrite and enhancements 1998-2001 Conrad Minshall -- conrad@mac.com
+ *
+ *	Various features from Joe Sokol, Pat Dirks, and Clark Warner.
+ *
+ *	Small changes to work under Linux -- davej@suse.de
+ *
+ *	Sundry porting patches from Guy Harris 12/2001
+ *
+ *	Checks for mmap last-page zero fill.
+ *
+ *	Modified heavily by Charles Manning to exercise via the
+ *	yaffs direct interface.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _UWIN
+# include <sys/param.h>
+# include <limits.h>
+# include <time.h>
+# include <strings.h>
+#endif
+#include <fcntl.h>
+#include <sys/mman.h>
+#ifndef MAP_FILE
+# define MAP_FILE 0
+#endif
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <time.h>
+
+#include "yaffsfs.h"
+
+#define NUMPRINTCOLUMNS 32	/* # columns of data to print on each line */
+
+/*
+ *	A log entry is an operation and a bunch of arguments.
+ */
+
+struct log_entry {
+	int	operation;
+	int	args[3];
+};
+
+#define	LOGSIZE	1000
+
+struct log_entry	oplog[LOGSIZE];	/* the log */
+int			logptr = 0;	/* current position in log */
+int			logcount = 0;	/* total ops */
+
+/*
+ *	Define operations
+ */
+
+#define	OP_READ		1
+#define OP_WRITE	2
+#define OP_TRUNCATE	3
+#define OP_CLOSEOPEN	4
+#define OP_MAPREAD	5
+#define OP_MAPWRITE	6
+#define OP_SKIPPED	7
+
+int page_size;
+int page_mask;
+
+char	*original_buf;			/* a pointer to the original data */
+char	*good_buf;			/* a pointer to the correct data */
+char	*temp_buf;			/* a pointer to the current data */
+
+char	fname[200];				/* name of our test file */
+char	mount_name[200];
+
+int	fd;				/* fd for our test file */
+
+off_t		file_size = 0;
+off_t		biggest = 0;
+char		state[256];
+unsigned long	testcalls = 0;		/* calls to function "test" */
+
+unsigned long	simulatedopcount = 0;	/* -b flag */
+int	closeprob = 0;			/* -c flag */
+int	debug = 0;			/* -d flag */
+unsigned long	debugstart = 0;		/* -D flag */
+unsigned long	maxfilelen = 256 * 1024;	/* -l flag */
+int	sizechecks = 1;			/* -n flag disables them */
+int	maxoplen = 64 * 1024;		/* -o flag */
+int	quiet = 0;			/* -q flag */
+unsigned long progressinterval = 0;	/* -p flag */
+int	readbdy = 1;			/* -r flag */
+int	style = 0;			/* -s flag */
+int	truncbdy = 1;			/* -t flag */
+int	writebdy = 1;			/* -w flag */
+long	monitorstart = -1;		/* -m flag */
+long	monitorend = -1;		/* -m flag */
+int	lite = 0;			/* -L flag */
+long	numops = /*-1 */ 10000000;			/* -N flag */
+int	randomoplen = 1;		/* -O flag disables it */
+int	seed = 1;			/* -S flag */
+
+int     mapped_writes = 0;	      /* yaffs direct does not support mmapped files */
+int 	mapped_reads = 0;
+
+int	fsxgoodfd = 0;
+FILE *	fsxlogf = NULL;
+int badoff = -1;
+int closeopen = 0;
+
+
+
+void EXIT(int x)
+{
+	printf("fsx wanted to exit with %d\n",x);
+	while(1){}
+}
+
+char goodfile[1024];
+char logfile[1024];
+
+
+void
+vwarnc(code, fmt, ap)
+	int code;
+	const char *fmt;
+	va_list ap;
+{
+	fprintf(stderr, "fsx: ");
+	if (fmt != NULL) {
+		vfprintf(stderr, fmt, ap);
+		fprintf(stderr, ": ");
+	}
+	fprintf(stderr, "%s\n", strerror(code));
+}
+
+
+void
+warn(const char * fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	vwarnc(errno, fmt, ap);
+	va_end(ap);
+}
+
+
+void
+prt(char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	vfprintf(stdout, fmt, args);
+	if (fsxlogf)
+		vfprintf(fsxlogf, fmt, args);
+	va_end(args);
+}
+
+void
+prterr(char *prefix)
+{
+	prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno));
+}
+
+
+void
+log4(int operation, int arg0, int arg1, int arg2)
+{
+	struct log_entry *le;
+
+	le = &oplog[logptr];
+	le->operation = operation;
+	if (closeopen)
+		le->operation = ~ le->operation;
+	le->args[0] = arg0;
+	le->args[1] = arg1;
+	le->args[2] = arg2;
+	logptr++;
+	logcount++;
+	if (logptr >= LOGSIZE)
+		logptr = 0;
+}
+
+
+void
+logdump(void)
+{
+	int	i, count, down;
+	struct log_entry	*lp;
+
+	prt("LOG DUMP (%d total operations):\n", logcount);
+	if (logcount < LOGSIZE) {
+		i = 0;
+		count = logcount;
+	} else {
+		i = logptr;
+		count = LOGSIZE;
+	}
+	for ( ; count > 0; count--) {
+		int opnum;
+
+		opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
+		prt("%d(%d mod 256): ", opnum, opnum%256);
+		lp = &oplog[i];
+		if ((closeopen = lp->operation < 0))
+			lp->operation = ~ lp->operation;
+			
+		switch (lp->operation) {
+		case OP_MAPREAD:
+			prt("MAPREAD\t0x%x thru 0x%x\t(0x%x bytes)",
+			    lp->args[0], lp->args[0] + lp->args[1] - 1,
+			    lp->args[1]);
+			if (badoff >= lp->args[0] && badoff <
+						     lp->args[0] + lp->args[1])
+				prt("\t***RRRR***");
+			break;
+		case OP_MAPWRITE:
+			prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)",
+			    lp->args[0], lp->args[0] + lp->args[1] - 1,
+			    lp->args[1]);
+			if (badoff >= lp->args[0] && badoff <
+						     lp->args[0] + lp->args[1])
+				prt("\t******WWWW");
+			break;
+		case OP_READ:
+			prt("READ\t0x%x thru 0x%x\t(0x%x bytes)",
+			    lp->args[0], lp->args[0] + lp->args[1] - 1,
+			    lp->args[1]);
+			if (badoff >= lp->args[0] &&
+			    badoff < lp->args[0] + lp->args[1])
+				prt("\t***RRRR***");
+			break;
+		case OP_WRITE:
+			prt("WRITE\t0x%x thru 0x%x\t(0x%x bytes)",
+			    lp->args[0], lp->args[0] + lp->args[1] - 1,
+			    lp->args[1]);
+			if (lp->args[0] > lp->args[2])
+				prt(" HOLE");
+			else if (lp->args[0] + lp->args[1] > lp->args[2])
+				prt(" EXTEND");
+			if ((badoff >= lp->args[0] || badoff >=lp->args[2]) &&
+			    badoff < lp->args[0] + lp->args[1])
+				prt("\t***WWWW");
+			break;
+		case OP_TRUNCATE:
+			down = lp->args[0] < lp->args[1];
+			prt("TRUNCATE %s\tfrom 0x%x to 0x%x",
+			    down ? "DOWN" : "UP", lp->args[1], lp->args[0]);
+			if (badoff >= lp->args[!down] &&
+			    badoff < lp->args[!!down])
+				prt("\t******WWWW");
+			break;
+		case OP_SKIPPED:
+			prt("SKIPPED (no operation)");
+			break;
+		default:
+			prt("BOGUS LOG ENTRY (operation code = %d)!",
+			    lp->operation);
+		}
+		if (closeopen)
+			prt("\n\t\tCLOSE/OPEN");
+		prt("\n");
+		i++;
+		if (i == LOGSIZE)
+			i = 0;
+	}
+}
+
+
+void
+save_buffer(char *buffer, off_t bufferlength, int fd)
+{
+	off_t ret;
+	ssize_t byteswritten;
+
+	if (fd <= 0 || bufferlength == 0)
+		return;
+
+	if (bufferlength > SSIZE_MAX) {
+		prt("fsx flaw: overflow in save_buffer\n");
+		EXIT(67);
+	}
+	if (lite) {
+		off_t size_by_seek = yaffs_lseek(fd, (off_t)0, SEEK_END);
+		if (size_by_seek == (off_t)-1)
+			prterr("save_buffer: lseek eof");
+		else if (bufferlength > size_by_seek) {
+			warn("save_buffer: .fsxgood file too short... will save 0x%llx bytes instead of 0x%llx\n", (unsigned long long)size_by_seek,
+			     (unsigned long long)bufferlength);
+			bufferlength = size_by_seek;
+		}
+	}
+
+	ret = yaffs_lseek(fd, (off_t)0, SEEK_SET);
+	if (ret == (off_t)-1)
+		prterr("save_buffer: lseek 0");
+	
+	byteswritten = yaffs_write(fd, buffer, (size_t)bufferlength);
+	if (byteswritten != bufferlength) {
+		if (byteswritten == -1)
+			prterr("save_buffer write");
+		else
+			warn("save_buffer: short write, 0x%x bytes instead of 0x%llx\n",
+			     (unsigned)byteswritten,
+			     (unsigned long long)bufferlength);
+	}
+}
+
+
+void
+report_failure(int status)
+{
+	logdump();
+	
+	if (fsxgoodfd) {
+		if (good_buf) {
+			save_buffer(good_buf, file_size, fsxgoodfd);
+			prt("Correct content saved for comparison\n");
+			prt("(maybe hexdump \"%s\" vs \"%s.fsxgood\")\n",
+			    fname, fname);
+		}
+		close(fsxgoodfd);
+	}
+	prt("Exiting with %d\n",status);
+	EXIT(status);
+}
+
+
+#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \
+					*(((unsigned char *)(cp)) + 1)))
+
+void
+check_buffers(unsigned offset, unsigned size)
+{
+	unsigned char c, t;
+	unsigned i = 0;
+	unsigned n = 0;
+	unsigned op = 0;
+	unsigned bad = 0;
+
+	if (memcmp(good_buf + offset, temp_buf, size) != 0) {
+		prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n",
+		    offset, size);
+		prt("OFFSET\tGOOD\tBAD\tRANGE\n");
+		while (size > 0) {
+			c = good_buf[offset];
+			t = temp_buf[i];
+			if (c != t) {
+				if (n == 0) {
+					bad = short_at(&temp_buf[i]);
+					prt("0x%5x\t0x%04x\t0x%04x", offset,
+					    short_at(&good_buf[offset]), bad);
+					op = temp_buf[offset & 1 ? i+1 : i];
+				}
+				n++;
+				badoff = offset;
+			}
+			offset++;
+			i++;
+			size--;
+		}
+		if (n) {
+			prt("\t0x%5x\n", n);
+			if (bad)
+				prt("operation# (mod 256) for the bad data may be %u\n", ((unsigned)op & 0xff));
+			else
+				prt("operation# (mod 256) for the bad data unknown, check HOLE and EXTEND ops\n");
+		} else
+			prt("????????????????\n");
+		report_failure(110);
+	}
+}
+
+
+void
+check_size(void)
+{
+	struct yaffs_stat	statbuf;
+	off_t	size_by_seek;
+
+	if (yaffs_fstat(fd, &statbuf)) {
+		prterr("check_size: fstat");
+		statbuf.st_size = -1;
+	}
+	size_by_seek = yaffs_lseek(fd, (off_t)0, SEEK_END);
+	if (file_size != statbuf.st_size || file_size != size_by_seek) {
+		prt("Size error: expected 0x%llx stat 0x%llx seek 0x%llx\n",
+		    (unsigned long long)file_size,
+		    (unsigned long long)statbuf.st_size,
+		    (unsigned long long)size_by_seek);
+		report_failure(120);
+	}
+}
+
+
+void
+check_trunc_hack(void)
+{
+	struct yaffs_stat statbuf;
+
+	yaffs_ftruncate(fd, (off_t)0);
+	yaffs_ftruncate(fd, (off_t)100000);
+	yaffs_fstat(fd, &statbuf);
+	if (statbuf.st_size != (off_t)100000) {
+		prt("no extend on truncate! not posix!\n");
+		EXIT(130);
+	}
+	yaffs_ftruncate(fd, (off_t)0);
+}
+
+
+void
+doread(unsigned offset, unsigned size)
+{
+	off_t ret;
+	unsigned iret;
+
+	offset -= offset % readbdy;
+	if (size == 0) {
+		if (!quiet && testcalls > simulatedopcount)
+			prt("skipping zero size read\n");
+		log4(OP_SKIPPED, OP_READ, offset, size);
+		return;
+	}
+	if (size + offset > file_size) {
+		if (!quiet && testcalls > simulatedopcount)
+			prt("skipping seek/read past end of file\n");
+		log4(OP_SKIPPED, OP_READ, offset, size);
+		return;
+	}
+
+	log4(OP_READ, offset, size, 0);
+
+	if (testcalls <= simulatedopcount)
+		return;
+
+	if (!quiet && ((progressinterval &&
+			testcalls % progressinterval == 0) ||
+		       (debug &&
+			(monitorstart == -1 ||
+			 (offset + size > monitorstart &&
+			  (monitorend == -1 || offset <= monitorend))))))
+		prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+		    offset, offset + size - 1, size);
+	ret = yaffs_lseek(fd, (off_t)offset, SEEK_SET);
+	if (ret == (off_t)-1) {
+		prterr("doread: lseek");
+		report_failure(140);
+	}
+	iret = yaffs_read(fd, temp_buf, size);
+	if (iret != size) {
+		if (iret == -1)
+			prterr("doread: read");
+		else
+			prt("short read: 0x%x bytes instead of 0x%x\n",
+			    iret, size);
+		report_failure(141);
+	}
+	check_buffers(offset, size);
+}
+
+
+
+
+
+void
+gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size)
+{
+	while (size--) {
+		good_buf[offset] = testcalls % 256; 
+		if (offset % 2)
+			good_buf[offset] += original_buf[offset];
+		offset++;
+	}
+}
+
+
+void
+dowrite(unsigned offset, unsigned size)
+{
+	off_t ret;
+	unsigned iret;
+
+	offset -= offset % writebdy;
+	if (size == 0) {
+		if (!quiet && testcalls > simulatedopcount)
+			prt("skipping zero size write\n");
+		log4(OP_SKIPPED, OP_WRITE, offset, size);
+		return;
+	}
+
+	log4(OP_WRITE, offset, size, file_size);
+
+	gendata(original_buf, good_buf, offset, size);
+	if (file_size < offset + size) {
+		if (file_size < offset)
+			memset(good_buf + file_size, '\0', offset - file_size);
+		file_size = offset + size;
+		if (lite) {
+			warn("Lite file size bug in fsx!");
+			report_failure(149);
+		}
+	}
+
+	if (testcalls <= simulatedopcount)
+		return;
+
+	if (!quiet && ((progressinterval &&
+			testcalls % progressinterval == 0) ||
+		       (debug &&
+			(monitorstart == -1 ||
+			 (offset + size > monitorstart &&
+			  (monitorend == -1 || offset <= monitorend))))))
+		prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+		    offset, offset + size - 1, size);
+	ret = yaffs_lseek(fd, (off_t)offset, SEEK_SET);
+	if (ret == (off_t)-1) {
+		prterr("dowrite: lseek");
+		report_failure(150);
+	}
+	iret = yaffs_write(fd, good_buf + offset, size);
+	if (iret != size) {
+		if (iret == -1)
+			prterr("dowrite: write");
+		else
+			prt("short write: 0x%x bytes instead of 0x%x\n",
+			    iret, size);
+		report_failure(151);
+	}
+}
+
+
+
+void
+dotruncate(unsigned size)
+{
+	int oldsize = file_size;
+
+	size -= size % truncbdy;
+	if (size > biggest) {
+		biggest = size;
+		if (!quiet && testcalls > simulatedopcount)
+			prt("truncating to largest ever: 0x%x\n", size);
+	}
+
+	log4(OP_TRUNCATE, size, (unsigned)file_size, 0);
+
+	if (size > file_size)
+		memset(good_buf + file_size, '\0', size - file_size);
+	file_size = size;
+
+	if (testcalls <= simulatedopcount)
+		return;
+	
+	if ((progressinterval && testcalls % progressinterval == 0) ||
+	    (debug && (monitorstart == -1 || monitorend == -1 ||
+		       size <= monitorend)))
+		prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size);
+	if (yaffs_ftruncate(fd, (off_t)size) == -1) {
+		prt("ftruncate1: %x\n", size);
+		prterr("dotruncate: ftruncate");
+		report_failure(160);
+	}
+}
+
+
+void
+writefileimage()
+{
+	ssize_t iret;
+
+	if (yaffs_lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
+		prterr("writefileimage: lseek");
+		report_failure(171);
+	}
+	iret = yaffs_write(fd, good_buf, file_size);
+	if ((off_t)iret != file_size) {
+		if (iret == -1)
+			prterr("writefileimage: write");
+		else
+			prt("short write: 0x%x bytes instead of 0x%llx\n",
+			    iret, (unsigned long long)file_size);
+		report_failure(172);
+	}
+	if (lite ? 0 : yaffs_ftruncate(fd, file_size) == -1) {
+		prt("ftruncate2: %llx\n", (unsigned long long)file_size);
+		prterr("writefileimage: ftruncate");
+		report_failure(173);
+	}
+}
+
+
+void
+docloseopen(void)
+{ 
+	if (testcalls <= simulatedopcount)
+		return;
+
+	if (debug)
+		prt("%lu close/open\n", testcalls);
+	if (yaffs_close(fd)) {
+		prterr("docloseopen: close");
+		report_failure(180);
+	}
+	fd = yaffs_open(fname, O_RDWR, 0);
+	if (fd < 0) {
+		prterr("docloseopen: open");
+		report_failure(181);
+	}
+}
+
+
+void
+yaffs_fsx_do_op(void)
+{
+	unsigned long	offset;
+	unsigned long	size = maxoplen;
+	unsigned long	rv = random();
+	unsigned long	op = rv % (3 + !lite + mapped_writes);
+
+	/* turn off the map read if necessary */
+
+	if (op == 2 && !mapped_reads)
+	    op = 0;
+
+	if (simulatedopcount > 0 && testcalls == simulatedopcount)
+		writefileimage();
+
+	testcalls++;
+
+	if (closeprob)
+		closeopen = (rv >> 3) < (1 << 28) / closeprob;
+
+	if (debugstart > 0 && testcalls >= debugstart)
+		debug = 1;
+
+	if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0)
+		prt("%lu...\n", testcalls);
+
+	/*
+	 * READ:	op = 0
+	 * WRITE:	op = 1
+	 * MAPREAD:     op = 2
+	 * TRUNCATE:	op = 3
+	 * MAPWRITE:    op = 3 or 4
+	 */
+	if (lite ? 0 : op == 3 && (style & 1) == 0) /* vanilla truncate? */
+		dotruncate(random() % maxfilelen);
+	else {
+		if (randomoplen)
+			size = random() % (maxoplen+1);
+		if (lite ? 0 : op == 3)
+			dotruncate(size);
+		else {
+			offset = random();
+			if (op == 1 || op == (lite ? 3 : 4)) {
+				offset %= maxfilelen;
+				if (offset + size > maxfilelen)
+					size = maxfilelen - offset;
+				dowrite(offset, size);
+			} else {
+				if (file_size)
+					offset %= file_size;
+				else
+					offset = 0;
+				if (offset + size > file_size)
+					size = file_size - offset;
+				doread(offset, size);
+			}
+		}
+	}
+	if (sizechecks && testcalls > simulatedopcount)
+		check_size();
+	if (closeopen)
+		docloseopen();
+}
+
+
+void
+cleanup(sig)
+	int	sig;
+{
+	if (sig)
+		prt("signal %d\n", sig);
+	prt("testcalls = %lu\n", testcalls);
+	EXIT(sig);
+}
+
+
+void
+usage(void)
+{
+	fprintf(stdout, "usage: %s",
+		"fsx [-dnqLOW] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] fname\n\
+	-b opnum: beginning operation number (default 1)\n\
+	-c P: 1 in P chance of file close+open at each op (default infinity)\n\
+	-d: debug output for all operations\n\
+	-l flen: the upper bound on file size (default 262144)\n\
+	-m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\
+	-n: no verifications of file size\n\
+	-o oplen: the upper bound on operation size (default 65536)\n\
+	-p progressinterval: debug output at specified operation interval\n\
+	-q: quieter operation\n\
+	-r readbdy: 4096 would make reads page aligned (default 1)\n\
+	-s style: 1 gives smaller truncates (default 0)\n\
+	-t truncbdy: 4096 would make truncates page aligned (default 1)\n\
+	-w writebdy: 4096 would make writes page aligned (default 1)\n\
+	-D startingop: debug output starting at specified operation\n\
+	-L: fsxLite - no file creations & no file size changes\n\
+	-N numops: total # operations to do (default infinity)\n\
+	-O: use oplen (see -o flag) for every op (default random)\n\
+	-P dirpath: save .fsxlog and .fsxgood files in dirpath (default ./)\n\
+	-S seed: for random # generator (default 1) 0 gets timestamp\n\
+	fname: this filename is REQUIRED (no default)\n");
+	EXIT(90);
+}
+
+
+int
+getnum(char *s, char **e)
+{
+	int ret = -1;
+
+	*e = (char *) 0;
+	ret = strtol(s, e, 0);
+	if (*e)
+		switch (**e) {
+		case 'b':
+		case 'B':
+			ret *= 512;
+			*e = *e + 1;
+			break;
+		case 'k':
+		case 'K':
+			ret *= 1024;
+			*e = *e + 1;
+			break;
+		case 'm':
+		case 'M':
+			ret *= 1024*1024;
+			*e = *e + 1;
+			break;
+		case 'w':
+		case 'W':
+			ret *= 4;
+			*e = *e + 1;
+			break;
+		}
+	return (ret);
+}
+
+
+
+extern int random_seed;
+extern int simulate_power_failure;
+
+
+int mounted_by_fsx = 0;
+
+int
+yaffs_fsx_init(const char *mount_pt)
+{
+	int	i, style, ch;
+	char	*endp;
+
+	goodfile[0] = 0;
+	logfile[0] = 0;
+
+	page_size = getpagesize();
+	page_mask = page_size - 1;
+
+	setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
+
+	strcpy(mount_name,mount_pt);
+	strcpy(fname,mount_name);
+	strcat(fname,"/fsxdata");
+	
+#if 0
+	signal(SIGHUP,	cleanup);
+	signal(SIGINT,	cleanup);
+	signal(SIGPIPE,	cleanup);
+	signal(SIGALRM,	cleanup);
+	signal(SIGTERM,	cleanup);
+	signal(SIGXCPU,	cleanup);
+	signal(SIGXFSZ,	cleanup);
+	signal(SIGVTALRM,	cleanup);
+	signal(SIGUSR1,	cleanup);
+	signal(SIGUSR2,	cleanup);
+#endif
+
+	initstate(seed, state, 256);
+	setstate(state);
+	fd = yaffs_open(fname, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC), 0666);
+	if (fd < 0) {
+		prterr(fname);
+		EXIT(91);
+	}
+	strncat(goodfile, fname, 256);
+	strcat (goodfile, ".fsxgood");
+	fsxgoodfd = yaffs_open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666);
+	if (fsxgoodfd < 0) {
+		prterr(goodfile);
+		EXIT(92);
+	}
+	strncat(logfile, "fsx", 256);
+	strcat (logfile, ".fsxlog");
+	fsxlogf = fopen(logfile, "w");
+	if (fsxlogf == NULL) {
+		prterr(logfile);
+		EXIT(93);
+	}
+	if (lite) {
+		off_t ret;
+		file_size = maxfilelen = yaffs_lseek(fd, (off_t)0, SEEK_END);
+		if (file_size == (off_t)-1) {
+			prterr(fname);
+			warn("main: lseek eof");
+			EXIT(94);
+		}
+		ret = yaffs_lseek(fd, (off_t)0, SEEK_SET);
+		if (ret == (off_t)-1) {
+			prterr(fname);
+			warn("main: lseek 0");
+			EXIT(95);
+		}
+	}
+	original_buf = (char *) malloc(maxfilelen);
+	for (i = 0; i < maxfilelen; i++)
+		original_buf[i] = random() % 256;
+	good_buf = (char *) malloc(maxfilelen);
+	memset(good_buf, '\0', maxfilelen);
+	temp_buf = (char *) malloc(maxoplen);
+	memset(temp_buf, '\0', maxoplen);
+	if (lite) {	/* zero entire existing file */
+		ssize_t written;
+
+		written = yaffs_write(fd, good_buf, (size_t)maxfilelen);
+		if (written != maxfilelen) {
+			if (written == -1) {
+				prterr(fname);
+				warn("main: error on write");
+			} else
+				warn("main: short write, 0x%x bytes instead of 0x%x\n",
+				     (unsigned)written, maxfilelen);
+			EXIT(98);
+		}
+	} else 
+		check_trunc_hack();
+		
+	return 0;
+}
+
+
+int yaffs_fsx_complete(void)
+{
+	if (yaffs_close(fd)) {
+		prterr("close");
+		report_failure(99);
+	}
+	
+	yaffs_close(fsxgoodfd);
+	
+	prt("All operations completed A-OK!\n");
+
+	EXIT(0);
+	return 0;
+}
+
+int
+yaffs_fsx_main(const char *mount_pt)
+{
+	yaffs_fsx_init(mount_pt);
+	while (numops == -1 || numops--)
+		yaffs_fsx_do_op();
+	yaffs_fsx_complete();
+}
new file mode 100644
--- /dev/null
+++ b/direct/tests/yaffs_fsx.h
@@ -0,0 +1,9 @@
+#ifndef __YAFFS_FSX_H__
+#define __YAFFS_FSX_H__
+
+int yaffs_fsx_init(const char *mountpt);
+int yaffs_fsx_complete(void);
+int yaffs_fsx_do_op(void);
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/direct/tests/yaffs_test.c
@@ -0,0 +1,116 @@
+/*
+ * YAFFS: Yet another FFS. A NAND-flash specific file system. 
+ *
+ * Copyright (C) 2002 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "yaffsfs.h"
+
+#include "nor_stress.h"
+#include "yaffs_fsx.h"
+
+
+
+
+int random_seed;
+int simulate_power_failure = 0;
+
+
+int do_fsx;
+int init_test;
+int do_upgrade;
+int n_cycles = -1;
+
+char mount_point[200];
+
+void BadUsage(void)
+{
+	exit(2);
+}
+
+int main(int argc, char **argv)
+{
+	int ch;
+	
+
+	while ((ch = getopt(argc,argv, "fin:ps:u"))
+	       != EOF)
+		switch (ch) {
+		case 's':
+			random_seed = atoi(optarg);
+			break;
+		case 'p':
+			simulate_power_failure =1;
+			break;
+		case 'i':
+			init_test = 1;
+			break;
+		case 'f':
+			do_fsx = 1;
+			break;
+		case 'u':
+			do_upgrade = 1;
+			break;
+		case 'n':
+			n_cycles = atoi(optarg);
+			break;
+		default:
+			BadUsage();
+			/* NOTREACHED */
+		}
+	argc -= optind;
+	argv += optind;
+	
+	if(argc == 1) {
+		strcpy(mount_point,argv[0]);
+		
+		if(simulate_power_failure)
+			n_cycles = -1;
+		printf("Running test %s %s %s %s seed %d cycles %d\n",
+			do_upgrade ? "fw_upgrade" : "",
+			init_test ? "initialise":"",
+			do_fsx ? "fsx" :"",
+			simulate_power_failure ? "power_fail" : "",
+			random_seed, n_cycles);
+
+		yaffs_StartUp();
+		yaffs_mount(mount_point);
+			
+		if(do_upgrade && init_test){
+			simulate_power_failure = 0;
+			NorStressTestInitialise(mount_point);
+		} else if(do_upgrade){
+			printf("Running stress on %s with seed %d\n",argv[1],random_seed);
+			NorStressTestRun(mount_point,n_cycles,do_fsx);
+		} else if(do_fsx){
+			yaffs_fsx_main(mount_point);
+		}else {
+			printf("No test to run!\n");
+			BadUsage();
+		}
+		yaffs_unmount(mount_point);
+		
+		printf("Test run completed!\n");
+	}
+	else
+		BadUsage();
+	return 0;
+}
+
+
deleted file mode 100644
--- a/direct/yaffs_test.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * YAFFS: Yet another FFS. A NAND-flash specific file system. 
- *
- * Copyright (C) 2002 Aleph One Ltd.
- *   for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-
-
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "yaffsfs.h"
-
-#include "nor_stress.h"
-
-
-
-int random_seed;
-int simulate_power_failure = 0;
-
-void BadUsage(void)
-{
-	printf("usage root_dir test_id seed \n");
-	printf(" test_id: fw_update fw_update_init\n");
-	exit(2);
-}
-int main(int argc, const char *argv[])
-{
-	yaffs_StartUp();
-	if(argc == 4) {
-		random_seed = atoi(argv[3]);
-		if(random_seed <= 0)
-			BadUsage();
-			
-		if(!strcmp(argv[2],"fw_update_init")){
-			NorStressTestInitialise(argv[1]);
-		}
-		else if(!strcmp(argv[2],"fw_update")){
-			printf("Running stress on %s with seed %d\n",argv[1],random_seed);
-			simulate_power_failure = 1;
-			NorStressTestRun(argv[1]);
-		}
-		else 
-			BadUsage();
-	}
-	else
-		BadUsage();
-	return 0;
-}
--- a/direct/yaffscfg2k.c
+++ b/direct/yaffscfg2k.c
@@ -37,7 +37,7 @@ unsigned yaffs_traceMask =
 	YAFFS_TRACE_CHECKPOINT |
 	YAFFS_TRACE_BAD_BLOCKS |
 
-/*	YAFFS_TRACE_VERIFY |  */
+	YAFFS_TRACE_VERIFY | 
 	
 	0;
         
--- a/direct/ynorsim.c
+++ b/direct/ynorsim.c
@@ -19,7 +19,7 @@
  */
    
 //#define YNORSIM_BIT_CHANGES 15
-#define YNORSIM_BIT_CHANGES 1
+#define YNORSIM_BIT_CHANGES 2
 
 #if 0
 /* Simulate 32MB of flash in 256k byte blocks.
@@ -94,7 +94,7 @@ static void ynorsim_Ready(void)
     return;
   srand(random_seed);
   remaining_ops = 1000000000;
-  remaining_ops = (rand() % 10000) * 300 * YNORSIM_BIT_CHANGES;
+  remaining_ops = (rand() % 10000) * 4000 * YNORSIM_BIT_CHANGES;
   ynorsim_RestoreImage();
 }
 
--- a/yaffs_guts.c
+++ b/yaffs_guts.c
@@ -482,9 +482,10 @@ static void yaffs_VerifyCollectedBlock(y
 	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){
+	/* This will need to change if we do partial gc */
+	
+	if(bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
+	   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));
 	}
@@ -6768,7 +6769,7 @@ static void yaffs_VerifyDirectory(yaffs_
 		if (lh) {
                         listObj = ylist_entry(lh, yaffs_Object, siblings);
 			if(listObj->parent != directory){
-				T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent" TENDSTR),listObj->parent));
+				T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR),listObj->parent));
 				YBUG();
 			}
 			yaffs_VerifyObjectInDirectory(listObj);