changeset 22:0b57027b96fe

Some improvements to garbage collection and st_xxx to yst_xxx changes
author charles <charles>
date Mon, 18 Jul 2005 23:16:04 +0000
parents 68dffdfc2095
children 7942535c12c6
files Makefile yaffs_fs.c yaffs_guts.c yaffs_guts.h yaffs_packedtags2.c
diffstat 5 files changed, 216 insertions(+), 171 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile
+++ b/Makefile
@@ -12,13 +12,13 @@
 # it under the terms of the GNU General Public License version 2 as
 # published by the Free Software Foundation.
 #
-# $Id: Makefile,v 1.2 2005-04-29 18:11:30 charles Exp $
+# $Id: Makefile,v 1.3 2005-07-18 23:16:04 charles Exp $
 #
 
 ## Change or override  KERNELDIR to your kernel
 ## comment out USE_xxxx if you don't want these features.
 
-KERNELDIR = /usr/src/kernel-headers-2.4.27
+KERNELDIR = /usr/src/kernels/2.6.11-1.1369_FC4-i686
 
 ## Change if you are using a cross-compiler
 MAKETOOLS = 
@@ -108,7 +108,10 @@ ENABLE_SHORT_NAMES_IN_RAM = -DCONFIG_SHO
 
 # End of configuration options.
 
-YAFFS_CONFIGS = $(USE_RAM_FOR_TEST) $(USE_MTD) $(USE_RAM_FOR_TEST_2) $(USE_MTD_2)\
+WIERD_COMPILE_CONFIGS = -DNR_IRQS=1 -DNR_IRQ_VECTORS=1
+
+YAFFS_CONFIGS = $(WIERD_COMPILE_CONFIGS) \
+                $(USE_RAM_FOR_TEST) $(USE_MTD) $(USE_RAM_FOR_TEST_2) $(USE_MTD_2)\
                 $(USE_HEADER_FILE_SIZE) $(IGNORE_CHUNK_ERASED) $(IGNORE_WRITE_VERIFY) \
                 $(ENABLE_SHORT_NAMES_IN_RAM) $(USE_NANDECC) $(USE_OLD_MTD) $(USE_WRONGECC)
 
--- a/yaffs_fs.c
+++ b/yaffs_fs.c
@@ -15,7 +15,8 @@
  * the VFS.
  *
  * Special notes: 
- * >> sb->u.generic_sbp points to the yaffs_Device associated with this superblock
+ * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with this superblock
+ * >> 2.6: sb->s_fs_info  points to the yaffs_Device associated with this superblock
  * >> inode->u.generic_ip points to the associated yaffs_Object.
  *
  *
@@ -29,7 +30,7 @@
  */
 
 
-const char *yaffs_fs_c_version = "$Id: yaffs_fs.c,v 1.7 2005-07-05 23:54:59 charles Exp $";
+const char *yaffs_fs_c_version = "$Id: yaffs_fs.c,v 1.8 2005-07-18 23:16:04 charles Exp $";
 extern const char *yaffs_guts_c_version;
 
 
@@ -329,7 +330,7 @@ static struct dentry * yaffs_lookup(stru
 	{
 		T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_lookup found %d\n",obj->objectId));
 		
-		inode = yaffs_get_inode(dir->i_sb, obj->st_mode,0,obj);
+		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode,0,obj);
 		
 		if(inode)
 		{
@@ -612,25 +613,25 @@ static void yaffs_FillInodeFromObject(st
 	if (inode && obj) 
 	{
 		inode->i_ino = obj->objectId;
-		inode->i_mode = obj->st_mode;
-		inode->i_uid = obj->st_uid;
-		inode->i_gid = obj->st_gid;
+		inode->i_mode = obj->yst_mode;
+		inode->i_uid = obj->yst_uid;
+		inode->i_gid = obj->yst_gid;
 		inode->i_blksize = inode->i_sb->s_blocksize;
 //#if defined(CONFIG_KERNEL_2_5)
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
 
-		inode->i_rdev = old_decode_dev(obj->st_rdev);
-		inode->i_atime.tv_sec = (time_t)(obj->st_atime);
+		inode->i_rdev = old_decode_dev(obj->yst_rdev);
+		inode->i_atime.tv_sec = (time_t)(obj->yst_atime);
 		inode->i_atime.tv_nsec = 0;
-		inode->i_mtime.tv_sec = (time_t)obj->st_mtime;
+		inode->i_mtime.tv_sec = (time_t)obj->yst_mtime;
 		inode->i_mtime.tv_nsec =0;
-		inode->i_ctime.tv_sec = (time_t)obj->st_ctime;
+		inode->i_ctime.tv_sec = (time_t)obj->yst_ctime;
 		inode->i_ctime.tv_nsec = 0;
 #else
-		inode->i_rdev = obj->st_rdev;
-		inode->i_atime = obj->st_atime;
-		inode->i_mtime = obj->st_mtime;
-		inode->i_ctime = obj->st_ctime;
+		inode->i_rdev = obj->yst_rdev;
+		inode->i_atime = obj->yst_atime;
+		inode->i_mtime = obj->yst_mtime;
+		inode->i_ctime = obj->yst_ctime;
 #endif
 		inode->i_size = yaffs_GetObjectFileLength(obj);
 		inode->i_blocks = (inode->i_size + 511) >> 9;
@@ -640,13 +641,13 @@ static void yaffs_FillInodeFromObject(st
 		T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
 				inode->i_mode, inode->i_uid, inode->i_gid, (int)inode->i_size, atomic_read(&inode->i_count)));
 		
-		switch (obj->st_mode & S_IFMT) 
+		switch (obj->yst_mode & S_IFMT) 
 		{
 			default: // fifo, device or socket
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-                               init_special_inode(inode, obj->st_mode,old_decode_dev(obj->st_rdev));
+                               init_special_inode(inode, obj->yst_mode,old_decode_dev(obj->yst_rdev));
 #else
-                                 init_special_inode(inode, obj->st_mode,(dev_t)(obj->st_rdev));
+                                 init_special_inode(inode, obj->yst_mode,(dev_t)(obj->yst_rdev));
 #endif				break;
 			case S_IFREG:	// file		
 				inode->i_op = &yaffs_file_inode_operations;
@@ -1091,7 +1092,7 @@ static int yaffs_symlink(struct inode * 
 
 		struct inode* inode;
 	
-		inode = yaffs_get_inode(dir->i_sb, obj->st_mode, 0, obj);
+		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
 		d_instantiate(dentry, inode);
 		T(YAFFS_TRACE_OS,(KERN_DEBUG"symlink created OK\n"));
 		return 0;
@@ -1200,7 +1201,7 @@ static int yaffs_setattr(struct dentry *
 			error = -EPERM;
 		}
 		yaffs_GrossUnlock(dev);
-		inode_setattr(inode,attr);
+		error = inode_setattr(inode,attr);
 	}
 	return error;
 }
@@ -1353,7 +1354,13 @@ static struct super_block *yaffs_interna
 #ifdef CONFIG_YAFFS_RAM_ENABLED
 		// Set the yaffs_Device up for ram emulation
 
+		
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+		sb->s_fs_info =	dev = kmalloc(sizeof(yaffs_Device),GFP_KERNEL);
+#else
 		sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device),GFP_KERNEL);
+#endif
+
 		if(!dev)
 		{
 			// Deep shit could not allocate device structure
@@ -1696,7 +1703,7 @@ static struct file_system_type yaffs_ram
 	.get_sb		= yaffs_ram_read_super,
 	.kill_sb	= kill_block_super,
 //	.kill_sb	= kill_litter_super,
-	.fs_flags	= FS_SINGLE,
+	.fs_flags	= 0 ,
 };
 #else
 static struct super_block *yaffs_ram_read_super(struct super_block * sb, void * data, int silent)
@@ -1725,7 +1732,7 @@ static struct file_system_type yaffs2_ra
 	.get_sb		= yaffs2_ram_read_super,
 	.kill_sb	= kill_block_super,
 //	.kill_sb	= kill_litter_super,
-	.fs_flags	= FS_SINGLE,
+	.fs_flags	= 0 ,
 };
 #else
 static struct super_block *yaffs2_ram_read_super(struct super_block * sb, void * data, int silent)
--- a/yaffs_guts.c
+++ b/yaffs_guts.c
@@ -14,7 +14,7 @@
  */
  //yaffs_guts.c
 
-const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.8 2005-07-05 23:54:59 charles Exp $";
+const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.9 2005-07-18 23:16:04 charles Exp $";
 
 #include "yportenv.h"
 
@@ -141,6 +141,8 @@ loff_t yaffs_GetFileSize(yaffs_Object *o
 
 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
 
+static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
+
 #ifdef YAFFS_PARANOID
 static int yaffs_CheckFileSanity(yaffs_Object *in);
 #else
@@ -1090,6 +1092,7 @@ static void yaffs_SoftDeleteChunk(yaffs_
 	if(theBlock)
 	{
 		theBlock->softDeletions++;
+		dev->nFreeChunks++;
 	}
 }
 
@@ -1386,7 +1389,7 @@ static yaffs_Object *yaffs_CreateFakeDir
 		obj->unlinkAllowed= 0;	// ... or unlink it
 		obj->deleted = 0;
 		obj->unlinked = 0;
-		obj->st_mode = mode;
+		obj->yst_mode = mode;
 		obj->myDev = dev;
 		obj->chunkId = 0; // Not a valid chunk.
 	}
@@ -1642,7 +1645,7 @@ yaffs_Object *yaffs_CreateNewObject(yaff
 
 #else
 
-		theObject->st_atime = theObject->st_mtime = theObject->st_ctime = Y_CURRENT_TIME;		
+		theObject->yst_atime = theObject->yst_mtime = theObject->yst_ctime = Y_CURRENT_TIME;		
 #endif
 		switch(type)
 		{
@@ -1739,7 +1742,7 @@ yaffs_Object *yaffs_MknodObject( yaffs_O
 		in->valid = 1;
 		in->variantType = type;
 
-		in->st_mode  = mode;
+		in->yst_mode  = mode;
 		
 #ifdef CONFIG_YAFFS_WINCE
 		yfsd_WinFileTimeNow(in->win_atime);
@@ -1747,11 +1750,11 @@ yaffs_Object *yaffs_MknodObject( yaffs_O
 		in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
 		
 #else
-		in->st_atime = in->st_mtime = in->st_ctime = Y_CURRENT_TIME;
-
-		in->st_rdev  = rdev;
-		in->st_uid   = uid;
-		in->st_gid   = gid;
+		in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
+
+		in->yst_rdev  = rdev;
+		in->yst_uid   = uid;
+		in->yst_gid   = gid;
 #endif		
 		in->nDataChunks = 0;
 
@@ -2103,6 +2106,7 @@ static int yaffs_FindBlockForGarbageColl
 	}
 
 	pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
+
 	if(aggressive)
 	{
 		iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
@@ -2206,6 +2210,8 @@ static void yaffs_BlockBecameDirty(yaffs
 	}
 	else
 	{
+		dev->nFreeChunks -= dev->nChunksPerBlock; // We lost a block of free space
+		
 		yaffs_RetireBlock(dev,blockNo);
 		T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));
 	}
@@ -2298,6 +2304,15 @@ static int yaffs_FindBlockForAllocation(
 }
 
 
+// To determine if we have enough space we just look at the 
+// number of erased blocks.
+
+static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
+{
+	int reservedChunks = (dev->nReservedBlocks * dev->nChunksPerBlock);
+	return (dev->nFreeChunks > reservedChunks);
+}
+
 
 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
 {
@@ -2311,7 +2326,7 @@ static int yaffs_AllocateChunk(yaffs_Dev
 		dev->allocationPage = 0;
 	}
 	
-	if(!useReserve &&  dev->nErasedBlocks </*=*/ dev->nReservedBlocks)
+	if(!useReserve &&  !yaffs_CheckSpaceForAllocation(dev))
 	{
 		// Not enough space to allocate unless we're allowed to use the reserve.
 		return -1;
@@ -2354,14 +2369,6 @@ static int yaffs_AllocateChunk(yaffs_Dev
 }
 
 
-// To determine if we have enough space we just look at the 
-// number of erased blocks.
-// The cache is allowed to use reserved blocks.
-
-static int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev)
-{
-	return (dev->nErasedBlocks >= dev->nReservedBlocks);
-}
 
 
 static int yaffs_GetErasedChunks(yaffs_Device *dev)
@@ -2402,8 +2409,13 @@ int  yaffs_GarbageCollectBlock(yaffs_Dev
 
 	T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR),block,bi->pagesInUse,bi->hasShrinkHeader));
 	//T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));	
+	
+	//yaffs_VerifyFreeChunks(dev);
 
 	bi->hasShrinkHeader = 0; // clear the flag so that the block can erase
+	
+	dev->nFreeChunks -= bi->softDeletions;  // Take off the number of soft deleted entries because
+						// they're going to get really deleted during GC.
 
 
 	if(!yaffs_StillSomeChunkBits(dev,block))
@@ -2414,7 +2426,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Dev
 	else
 	{
 
-			__u8  *buffer = yaffs_GetTempBuffer(dev,__LINE__);
+	__u8  *buffer = yaffs_GetTempBuffer(dev,__LINE__);
 
 	for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock; 
 	    chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
@@ -2445,7 +2457,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Dev
 			if(object && object->deleted && tags.chunkId != 0)
 			{
 				// Data chunk in a deleted file, throw it away
-				// It's a deleted data chunk,
+				// It's a soft deleted data chunk,
 				// No need to copy this, just forget about it and fix up the
 				// object.
 				
@@ -2512,6 +2524,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Dev
 
 	yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
 
+	//yaffs_VerifyFreeChunks(dev);
 
 	// Do any required cleanups
 	for(i = 0; i < cleanups; i++)
@@ -2534,6 +2547,9 @@ int  yaffs_GarbageCollectBlock(yaffs_Dev
 	{
 			T(YAFFS_TRACE_GC,(TSTR("gc did not increase free chunks before %d after %d" TENDSTR),chunksBefore,chunksAfter));
 	}
+	
+	
+	//yaffs_VerifyFreeChunks(dev);
 			
 	return YAFFS_OK;
 }
@@ -2619,13 +2635,15 @@ int yaffs_CheckGarbageCollection(yaffs_D
 	int maxTries = 0;
 	
 	//yaffs_DoUnlinkedFileDeletion(dev);
+	
+	//yaffs_VerifyFreeChunks(dev);
 
 	// This loop should pass the first time.
 	// We'll only see looping here if the erase of the collected block fails.
 	
 	do{
 		maxTries++;
-		if(dev->nErasedBlocks <= (dev->nReservedBlocks + 2))
+		if(dev->nErasedBlocks < dev->nReservedBlocks)
 		{
 			// We need a block soon...
 			aggressive = 1;
@@ -2651,11 +2669,11 @@ int yaffs_CheckGarbageCollection(yaffs_D
 			gcOk =  yaffs_GarbageCollectBlock(dev,block);
 		}
 
-		if(dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) 
+		if(dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) 
 		{
 			T(YAFFS_TRACE_GC,(TSTR("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" TENDSTR),dev->nErasedBlocks,maxTries,block));
 		}
-	} while((dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) && (block > 0) && (maxTries < 5));
+	} while((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0) && (maxTries < 2));
 
 	return aggressive ? gcOk: YAFFS_OK;
 }
@@ -3138,9 +3156,10 @@ void yaffs_DeleteChunk(yaffs_Device *dev
 	    bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
 	    bi->blockState == YAFFS_BLOCK_STATE_COLLECTING)
 	{
-		dev->nFreeChunks++;
+	        dev->nFreeChunks++;
 
 		yaffs_ClearChunkBit(dev,block,page);
+		
 		bi->pagesInUse--;
 		
 		if(bi->pagesInUse == 0 &&
@@ -3261,7 +3280,7 @@ int yaffs_UpdateObjectHeader(yaffs_Objec
 		// Header data
 		oh->type = in->variantType;
 		
-		oh->st_mode = in->st_mode;
+		oh->yst_mode = in->yst_mode;
 
 #ifdef CONFIG_YAFFS_WINCE
 		oh->win_atime[0] = in->win_atime[0];
@@ -3271,12 +3290,12 @@ int yaffs_UpdateObjectHeader(yaffs_Objec
 		oh->win_ctime[1] = in->win_ctime[1];
 		oh->win_mtime[1] = in->win_mtime[1];
 #else
-		oh->st_uid = in->st_uid;
-		oh->st_gid = in->st_gid;
-		oh->st_atime = in->st_atime;
-		oh->st_mtime = in->st_mtime;
-		oh->st_ctime = in->st_ctime;
-		oh->st_rdev = in->st_rdev;
+		oh->yst_uid = in->yst_uid;
+		oh->yst_gid = in->yst_gid;
+		oh->yst_atime = in->yst_atime;
+		oh->yst_mtime = in->yst_mtime;
+		oh->yst_ctime = in->yst_ctime;
+		oh->yst_rdev = in->yst_rdev;
 #endif	
 		if(in->parent)
 		{
@@ -3856,7 +3875,7 @@ int yaffs_WriteDataToFile(yaffs_Object *
 				yaffs_ChunkCache *cache;
 				// If we can't find the data in the cache, then load it up.
 				cache = yaffs_FindChunkCache(in,chunk);
-				if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev))
+				if(!cache && yaffs_CheckSpaceForAllocation(in->myDev))
 				{
 					cache = yaffs_GrabChunkCache(in->myDev);
 					cache->object = in;
@@ -4108,7 +4127,7 @@ int yaffs_FlushFile(yaffs_Object *in, in
 			yfsd_WinFileTimeNow(in->win_mtime);
 #else
 
-			in->st_mtime = Y_CURRENT_TIME;
+			in->yst_mtime = Y_CURRENT_TIME;
 
 #endif
 		}
@@ -4706,7 +4725,7 @@ static int yaffs_Scan(yaffs_Device *dev)
 					in->valid = 1;
 					in->variantType = oh->type;
 	
-					in->st_mode  = oh->st_mode;
+					in->yst_mode  = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
 					in->win_atime[0] = oh->win_atime[0];
 					in->win_ctime[0] = oh->win_ctime[0];
@@ -4715,12 +4734,12 @@ static int yaffs_Scan(yaffs_Device *dev)
 					in->win_ctime[1] = oh->win_ctime[1];
 					in->win_mtime[1] = oh->win_mtime[1];
 #else
-					in->st_uid   = oh->st_uid;
-					in->st_gid   = oh->st_gid;
-					in->st_atime = oh->st_atime;
-					in->st_mtime = oh->st_mtime;
-					in->st_ctime = oh->st_ctime;
-					in->st_rdev = oh->st_rdev;
+					in->yst_uid   = oh->yst_uid;
+					in->yst_gid   = oh->yst_gid;
+					in->yst_atime = oh->yst_atime;
+					in->yst_mtime = oh->yst_mtime;
+					in->yst_ctime = oh->yst_ctime;
+					in->yst_rdev = oh->yst_rdev;
 #endif
 					in->chunkId  = chunk;
 
@@ -4732,7 +4751,7 @@ static int yaffs_Scan(yaffs_Device *dev)
 					in->valid = 1;
 					in->variantType = oh->type;
 	
-					in->st_mode  = oh->st_mode;
+					in->yst_mode  = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
 					in->win_atime[0] = oh->win_atime[0];
 					in->win_ctime[0] = oh->win_ctime[0];
@@ -4741,12 +4760,12 @@ static int yaffs_Scan(yaffs_Device *dev)
 					in->win_ctime[1] = oh->win_ctime[1];
 					in->win_mtime[1] = oh->win_mtime[1];
 #else
-					in->st_uid   = oh->st_uid;
-					in->st_gid   = oh->st_gid;
-					in->st_atime = oh->st_atime;
-					in->st_mtime = oh->st_mtime;
-					in->st_ctime = oh->st_ctime;
-					in->st_rdev = oh->st_rdev;
+					in->yst_uid   = oh->yst_uid;
+					in->yst_gid   = oh->yst_gid;
+					in->yst_atime = oh->yst_atime;
+					in->yst_mtime = oh->yst_mtime;
+					in->yst_ctime = oh->yst_ctime;
+					in->yst_rdev = oh->yst_rdev;
 #endif
 					in->chunkId  = chunk;
 
@@ -5242,7 +5261,7 @@ static int yaffs_ScanBackwards(yaffs_Dev
 					in->valid = 1;
 					in->variantType = oh->type;
 	
-					in->st_mode  = oh->st_mode;
+					in->yst_mode  = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
 					in->win_atime[0] = oh->win_atime[0];
 					in->win_ctime[0] = oh->win_ctime[0];
@@ -5251,12 +5270,12 @@ static int yaffs_ScanBackwards(yaffs_Dev
 					in->win_ctime[1] = oh->win_ctime[1];
 					in->win_mtime[1] = oh->win_mtime[1];
 #else
-					in->st_uid   = oh->st_uid;
-					in->st_gid   = oh->st_gid;
-					in->st_atime = oh->st_atime;
-					in->st_mtime = oh->st_mtime;
-					in->st_ctime = oh->st_ctime;
-					in->st_rdev = oh->st_rdev;
+					in->yst_uid   = oh->yst_uid;
+					in->yst_gid   = oh->yst_gid;
+					in->yst_atime = oh->yst_atime;
+					in->yst_mtime = oh->yst_mtime;
+					in->yst_ctime = oh->yst_ctime;
+					in->yst_rdev = oh->yst_rdev;
 #endif
 					in->chunkId  = chunk;
 
@@ -5268,7 +5287,7 @@ static int yaffs_ScanBackwards(yaffs_Dev
 					in->valid = 1;
 					in->variantType = oh->type;
 	
-					in->st_mode  = oh->st_mode;
+					in->yst_mode  = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
 					in->win_atime[0] = oh->win_atime[0];
 					in->win_ctime[0] = oh->win_ctime[0];
@@ -5277,12 +5296,12 @@ static int yaffs_ScanBackwards(yaffs_Dev
 					in->win_ctime[1] = oh->win_ctime[1];
 					in->win_mtime[1] = oh->win_mtime[1];
 #else
-					in->st_uid   = oh->st_uid;
-					in->st_gid   = oh->st_gid;
-					in->st_atime = oh->st_atime;
-					in->st_mtime = oh->st_mtime;
-					in->st_ctime = oh->st_ctime;
-					in->st_rdev = oh->st_rdev;
+					in->yst_uid   = oh->yst_uid;
+					in->yst_gid   = oh->yst_gid;
+					in->yst_atime = oh->yst_atime;
+					in->yst_mtime = oh->yst_mtime;
+					in->yst_ctime = oh->yst_ctime;
+					in->yst_rdev = oh->yst_rdev;
 #endif
 					in->chunkId  = chunk;
 
@@ -5714,10 +5733,10 @@ unsigned yaffs_GetObjectType(yaffs_Objec
 		case YAFFS_OBJECT_TYPE_SYMLINK:		return DT_LNK; break;
 		case YAFFS_OBJECT_TYPE_HARDLINK:	return DT_REG; break;
 		case YAFFS_OBJECT_TYPE_SPECIAL:		
-			if(S_ISFIFO(obj->st_mode)) return DT_FIFO;
-			if(S_ISCHR(obj->st_mode)) return DT_CHR;
-			if(S_ISBLK(obj->st_mode)) return DT_BLK;
-			if(S_ISSOCK(obj->st_mode)) return DT_SOCK;
+			if(S_ISFIFO(obj->yst_mode)) return DT_FIFO;
+			if(S_ISCHR(obj->yst_mode)) return DT_CHR;
+			if(S_ISBLK(obj->yst_mode)) return DT_BLK;
+			if(S_ISSOCK(obj->yst_mode)) return DT_SOCK;
 		default: return DT_REG; break;
 	}
 }
@@ -5741,13 +5760,13 @@ int yaffs_SetAttributes(yaffs_Object *ob
 {
 	unsigned int valid = attr->ia_valid;
 	
-	if(valid & ATTR_MODE) obj->st_mode = attr->ia_mode;
-	if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
-	if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
-	
-	if(valid & ATTR_ATIME) obj->st_atime = Y_TIME_CONVERT(attr->ia_atime);
-	if(valid & ATTR_CTIME) obj->st_ctime = Y_TIME_CONVERT(attr->ia_ctime);
-	if(valid & ATTR_MTIME) obj->st_mtime = Y_TIME_CONVERT(attr->ia_mtime);
+	if(valid & ATTR_MODE) obj->yst_mode = attr->ia_mode;
+	if(valid & ATTR_UID) obj->yst_uid = attr->ia_uid;
+	if(valid & ATTR_GID) obj->yst_gid = attr->ia_gid;
+	
+	if(valid & ATTR_ATIME) obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
+	if(valid & ATTR_CTIME) obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
+	if(valid & ATTR_MTIME) obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
 	
 	if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
 	
@@ -5760,13 +5779,13 @@ int yaffs_GetAttributes(yaffs_Object *ob
 {
 	unsigned int valid = 0;
 	
-	attr->ia_mode = obj->st_mode;	valid |= ATTR_MODE;
-	attr->ia_uid = obj->st_uid;		valid |= ATTR_UID;
-	attr->ia_gid = obj->st_gid;		valid |= ATTR_GID;
-	
-	Y_TIME_CONVERT(attr->ia_atime)= obj->st_atime;	valid |= ATTR_ATIME;
-	Y_TIME_CONVERT(attr->ia_ctime) = obj->st_ctime;	valid |= ATTR_CTIME;
-	Y_TIME_CONVERT(attr->ia_mtime) = obj->st_mtime;	valid |= ATTR_MTIME;
+	attr->ia_mode = obj->yst_mode;	valid |= ATTR_MODE;
+	attr->ia_uid = obj->yst_uid;		valid |= ATTR_UID;
+	attr->ia_gid = obj->yst_gid;		valid |= ATTR_GID;
+	
+	Y_TIME_CONVERT(attr->ia_atime)= obj->yst_atime;	valid |= ATTR_ATIME;
+	Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;	valid |= ATTR_CTIME;
+	Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;	valid |= ATTR_MTIME;
 
 	attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
 	
@@ -5874,6 +5893,7 @@ int yaffs_GutsInitialise(yaffs_Device *d
 	dev->internalEndBlock =  dev->endBlock;
 	dev->blockOffset = 0;
 	dev->chunkOffset = 0;
+	dev->nFreeChunks = 0;
 	
 	if(dev->startBlock == 0)
 	{
@@ -6067,12 +6087,14 @@ int yaffs_GutsInitialise(yaffs_Device *d
 	
 	// Zero out stats
 	dev->nPageReads = 0;
-    dev->nPageWrites =  0;
+   	dev->nPageWrites =  0;
 	dev->nBlockErasures = 0;
 	dev->nGCCopies = 0;
 	dev->nRetriedWrites = 0;
 
 	dev->nRetiredBlocks = 0;
+	
+	yaffs_VerifyFreeChunks(dev);
 
 	T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
 	return YAFFS_OK;
@@ -6143,17 +6165,13 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_D
 
 #endif
 
-int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
+static int  yaffs_CountFreeChunks(yaffs_Device *dev)
 {
 	int nFree;
-	int pending;
 	int b;
-	int nDirtyCacheChunks=0;
-	
-	yaffs_BlockInfo *blk;
-	
-	struct list_head *i;	
-	yaffs_Object *l;
+
+	yaffs_BlockInfo *blk;	
+
 	
 	for(nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; b++)
 	{
@@ -6163,44 +6181,36 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_D
 		{
 			case YAFFS_BLOCK_STATE_EMPTY:
 			case YAFFS_BLOCK_STATE_ALLOCATING: 
-			case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse); break;
+			case YAFFS_BLOCK_STATE_COLLECTING:
+			case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse + blk->softDeletions); break;
 			default: break;
 		}
-	}
-	
-	
-	pending = 0;
-	
-	// To the free chunks add the chunks that are in the deleted unlinked files.
-	list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
-	{
-		if(i)
-		{
-			l = list_entry(i, yaffs_Object,siblings);
-			if(l->deleted)
-			{
-				pending++;
-				pending += l->nDataChunks;
-			}
-		}
-	}
-	
-	
-	
-	//printf("___________ really free is %d, pending %d, nFree is %d\n",nFree,pending, nFree+pending);
-	
-	if(nFree != dev->nFreeChunks) 
-	{
-	//	printf("___________Different! really free is %d, nFreeChunks %d\n",nFree dev->nFreeChunks);
-	}
-
-	nFree += pending;
+
+	}
+	
+	return nFree;
+}	
+	
+
+
+int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
+{
+	// This is what we report to the outside world
+
+	int nFree;
+	int nDirtyCacheChunks;
+		
+#if 1	
+	nFree = dev->nFreeChunks;
+#else
+	nFree = yaffs_CountFreeChunks(dev);
+#endif
 	
 	// Now count the number of dirty chunks in the cache and subtract those
 	
 	{
 		int i;
-		for(i = 0; i < dev->nShortOpCaches; i++)
+		for( nDirtyCacheChunks = 0,i = 0; i < dev->nShortOpCaches; i++)
 		{
 			if(dev->srCache[i].dirty) nDirtyCacheChunks++;
 		}
@@ -6216,7 +6226,20 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_D
 	
 }
 
-
+static int  yaffs_freeVerificationFailures;
+
+static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
+{
+	int counted = yaffs_CountFreeChunks(dev);
+	
+	int difference = dev->nFreeChunks - counted;
+	
+	if(difference)
+	{
+		T(YAFFS_TRACE_ALWAYS,(TSTR("Freechunks verification failure %d %d %d" TENDSTR),dev->nFreeChunks,counted,difference)); 
+		yaffs_freeVerificationFailures++;	
+	}
+}
 
 /////////////////// YAFFS test code //////////////////////////////////
 
--- a/yaffs_guts.h
+++ b/yaffs_guts.h
@@ -14,7 +14,7 @@
  *
  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
  *
- * $Id: yaffs_guts.h,v 1.7 2005-07-06 00:36:32 charles Exp $
+ * $Id: yaffs_guts.h,v 1.8 2005-07-18 23:16:04 charles Exp $
  */
 
 #ifndef __YAFFS_GUTS_H__
@@ -179,16 +179,17 @@ typedef struct
 	unsigned sequenceNumber; 	// The sequence number of this block
 
 	// Extra info if this is an object header (YAFFS2 only)
-	unsigned extraHeaderInfoAvailable; 
-	unsigned extraParentObjectId;
-	unsigned extraIsShrinkHeader;
+	
+	unsigned extraHeaderInfoAvailable; // There is extra info available if this is not zero
+	unsigned extraParentObjectId;	   // The parent object
+	unsigned extraIsShrinkHeader;	   // Is it a shrink header?
 	
-	yaffs_ObjectType extraObjectType;
+	yaffs_ObjectType extraObjectType;  // What object type?
 
-	unsigned extraFileLength;
-	unsigned extraEquivalentObjectId;
+	unsigned extraFileLength;	   // Length if it is a file
+	unsigned extraEquivalentObjectId;  // Equivalent object Id if it is a hard link
 
-	unsigned validMarker1;
+	unsigned validMarker1;	
 	
 } yaffs_ExtendedTags;
 
@@ -282,16 +283,16 @@ typedef struct
 	YCHAR  name[YAFFS_MAX_NAME_LENGTH + 1];
 
 	// Thes following apply to directories, files, symlinks - not hard links
-	__u32 st_mode;  // protection
+	__u32 yst_mode;  // protection
 
 #ifdef CONFIG_YAFFS_WINCE
 	__u32 notForWinCE[5];
 #else
-	__u32 st_uid;   // user ID of owner
-	__u32 st_gid;    // group ID of owner 
-	__u32 st_atime; // time of last access
-	__u32 st_mtime; // time of last modification
-	__u32 st_ctime; // time of last change
+	__u32 yst_uid;   // user ID of owner
+	__u32 yst_gid;    // group ID of owner 
+	__u32 yst_atime; // time of last access
+	__u32 yst_mtime; // time of last modification
+	__u32 yst_ctime; // time of last change
 #endif
 
 	// File size  applies to files only
@@ -303,7 +304,7 @@ typedef struct
 	// Alias is for symlinks only.
 	YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
 	
-	__u32 st_rdev;  // device stuff for block and char devices (maj/min)
+	__u32 yst_rdev;  // device stuff for block and char devices (maj/min)
 	
 #ifdef CONFIG_YAFFS_WINCE
 	__u32 win_ctime[2];
@@ -432,7 +433,7 @@ struct  yaffs_ObjectStruct
 	__u32 objectId;		// the object id value
 	
 	
-	__u32 st_mode;  	// protection
+	__u32 yst_mode;  	// protection
 
 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
 	YCHAR shortName[YAFFS_SHORT_NAME_LENGTH+1];
@@ -447,14 +448,14 @@ struct  yaffs_ObjectStruct
 	__u32 win_mtime[2];
 	__u32 win_atime[2];
 #else
-	__u32 st_uid;   	// user ID of owner
-	__u32 st_gid;    	// group ID of owner 
-	__u32 st_atime; 	// time of last access
-	__u32 st_mtime; 	// time of last modification
-	__u32 st_ctime; 	// time of last change
+	__u32 yst_uid;   	// user ID of owner
+	__u32 yst_gid;    	// group ID of owner 
+	__u32 yst_atime; 	// time of last access
+	__u32 yst_mtime; 	// time of last modification
+	__u32 yst_ctime; 	// time of last change
 #endif
 
-	__u32 st_rdev; 	    // device stuff for block and char devices
+	__u32 yst_rdev; 	    // device stuff for block and char devices
 
 
 
--- a/yaffs_packedtags2.c
+++ b/yaffs_packedtags2.c
@@ -89,8 +89,11 @@ void yaffs_PackTags2(yaffs_PackedTags2 *
 	yaffs_DumpPackedTags2(pt);
 	yaffs_DumpTags2(t);
 	
-	yaffs_ECCCalculateOther((unsigned char *)&pt->t,sizeof(yaffs_PackedTags2TagsPart),&pt->ecc);
-	
+#ifndef YAFFS_IGNORE_TAGS_ECC
+	{ 
+	  yaffs_ECCCalculateOther((unsigned char *)&pt->t,sizeof(yaffs_PackedTags2TagsPart),&pt->ecc);
+	}
+#endif
 }
 
 void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)
@@ -104,9 +107,17 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag
 	if(pt->t.sequenceNumber != 0xFFFFFFFF)
 	{
 		// Page is in use
-		yaffs_ECCOther ecc;
-		yaffs_ECCCalculateOther((unsigned char *)&pt->t,sizeof(yaffs_PackedTags2TagsPart),&ecc);
-		t->eccResult = yaffs_ECCCorrectOther((unsigned char *)&pt->t,sizeof(yaffs_PackedTags2TagsPart),&pt->ecc,&ecc);
+#ifdef YAFFS_IGNORE_TAGS_ECC
+		{
+			t->eccResult = 0;
+		}
+#else
+		{
+			yaffs_ECCOther ecc;
+			yaffs_ECCCalculateOther((unsigned char *)&pt->t,sizeof(yaffs_PackedTags2TagsPart),&ecc);
+			t->eccResult = yaffs_ECCCorrectOther((unsigned char *)&pt->t,sizeof(yaffs_PackedTags2TagsPart),&pt->ecc,&ecc);
+		}
+#endif
 		t->blockBad = 0;
 		t->chunkUsed = 1;
 		t->objectId = pt->t.objectId;