changeset 217:6dbe40ae9e54

Some cleanups, Linux 2.6.25 handling, fix handing of root permissions
author charles
date Thu, 03 Jul 2008 21:06:05 +0100
parents 15f3cbc2541b
children a3531aef506e
files devextras.h direct/dtest.c direct/yaffsfs.c direct/yaffsfs.h mtdemul/Makefile mtdemul/nandemul2k.c yaffs_fs.c yaffs_guts.c yaffs_guts.h
diffstat 9 files changed, 342 insertions(+), 218 deletions(-) [+]
line wrap: on
line diff
--- a/devextras.h
+++ b/devextras.h
@@ -11,107 +11,125 @@
  * published by the Free Software Foundation.
  *
  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
- */
-
-/*
+ */
+
+/*
  * This file is just holds extra declarations of macros that would normally
  * be providesd in the Linux kernel. These macros have been written from
  * scratch but are functionally equivalent to the Linux ones.
- *
- */
-
-#ifndef __EXTRAS_H__
-#define __EXTRAS_H__
-
-
-#if !(defined __KERNEL__) 
-
+ *
+ */
+
+#ifndef __EXTRAS_H__
+#define __EXTRAS_H__
+
+
+#if !(defined __KERNEL__) 
+
 /* Definition of types */
-typedef unsigned char __u8;
-typedef unsigned short __u16;
-typedef unsigned __u32;
-
+typedef unsigned char __u8;
+typedef unsigned short __u16;
+typedef unsigned __u32;
+
 #endif
-
-/*
- * This is a simple doubly linked list implementation that matches the 
- * way the Linux kernel doubly linked list implementation works.
- */
-
+
+/*
+ * This is a simple doubly linked list implementation that matches the 
+ * way the Linux kernel doubly linked list implementation works.
+ */
+
 struct ylist_head {
-        struct ylist_head *next; /* next in chain */
-        struct ylist_head *prev; /* previous in chain */
-};
-
-
-/* Initialise a list head to an empty list */
+	struct ylist_head *next; /* next in chain */
+	struct ylist_head *prev; /* previous in chain */
+};
+
+
+/* Initialise a static list */
+#define YLIST_HEAD(name) \
+struct ylist_head name = { &(name),&(name)}
+
+
+
+/* Initialise a list head to an empty list */
 #define YINIT_LIST_HEAD(p) \
-do { \
- (p)->next = (p);\
+do { \
+ (p)->next = (p);\
  (p)->prev = (p); \
-} while(0)
-
-
-/* Add an element to a list */
+} while(0)
+
+
+/* Add an element to a list */
 static __inline__ void ylist_add(struct ylist_head *newEntry, 
                                  struct ylist_head *list)
-{
+{
         struct ylist_head *listNext = list->next;
-        
-        list->next = newEntry;
-        newEntry->prev = list;
+        
+        list->next = newEntry;
+        newEntry->prev = list;
 	newEntry->next = listNext;
 	listNext->prev = newEntry;
 	
 }
 
-
-/* Take an element out of its current list, with or without
- * reinitialising the links.of the entry*/
+static __inline__ void ylist_add_tail(struct ylist_head *newEntry, 
+				 struct ylist_head *list)
+{
+	struct ylist_head *listPrev = list->prev;
+	
+	list->prev = newEntry;
+	newEntry->next = list;
+	newEntry->prev = listPrev;
+	listPrev->next = newEntry;
+	
+}
+
+
+/* Take an element out of its current list, with or without
+ * reinitialising the links.of the entry*/
 static __inline__ void ylist_del(struct ylist_head *entry)
-{
+{
         struct ylist_head *listNext = entry->next;
         struct ylist_head *listPrev = entry->prev;
-        
-        listNext->prev = listPrev;
-        listPrev->next = listNext;
-        
-}
-
+        
+        listNext->prev = listPrev;
+        listPrev->next = listNext;
+        
+}
+
 static __inline__ void ylist_del_init(struct ylist_head *entry)
-{
+{
         ylist_del(entry);
-        entry->next = entry->prev = entry;
-}
-
-
-/* Test if the list is empty */
+        entry->next = entry->prev = entry;
+}
+
+
+/* Test if the list is empty */
 static __inline__ int ylist_empty(struct ylist_head *entry)
-{
-        return (entry->next == entry);
-}
-
-
+{
+        return (entry->next == entry);
+}
+
+
 /* ylist_entry takes a pointer to a list entry and offsets it to that
- * we can find a pointer to the object it is embedded in.
- */
- 
- 
+ * we can find a pointer to the object it is embedded in.
+ */
+ 
+ 
 #define ylist_entry(entry, type, member) \
-        ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
-
-
+        ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
+
+
 /* ylist_for_each and list_for_each_safe  iterate over lists.
  * ylist_for_each_safe uses temporary storage to make the list delete safe
- */
-
+ */
+
 #define ylist_for_each(itervar, list) \
-        for (itervar = (list)->next; itervar != (list); itervar = itervar->next )
-
+        for (itervar = (list)->next; itervar != (list); itervar = itervar->next )
+
 #define ylist_for_each_safe(itervar,saveVar, list) \
-        for (itervar = (list)->next, saveVar = (list)->next->next; itervar != (list); \
-         itervar = saveVar, saveVar = saveVar->next)
-
+        for (itervar = (list)->next, saveVar = (list)->next->next; itervar != (list); \
+         itervar = saveVar, saveVar = saveVar->next)
+
 
 #if !(defined __KERNEL__)
 
@@ -122,30 +140,30 @@ static __inline__ int ylist_empty(struct
 
 
 #ifdef CONFIG_YAFFS_PROVIDE_DEFS
-/* File types */
-
+/* File types */
+
 
-#define DT_UNKNOWN      0
-#define DT_FIFO         1
-#define DT_CHR          2
+#define DT_UNKNOWN      0
+#define DT_FIFO         1
+#define DT_CHR          2
 #define DT_DIR		4
 #define DT_BLK		6
-#define DT_REG          8
-#define DT_LNK          10
-#define DT_SOCK         12
+#define DT_REG          8
+#define DT_LNK          10
+#define DT_SOCK         12
 #define DT_WHT          14
-
-
-#ifndef WIN32
-#include <sys/stat.h>
-#endif
-
-/*
- * Attribute flags.  These should be or-ed together to figure out what
- * has been changed!
- */
-#define ATTR_MODE       1
-#define ATTR_UID        2
+
+
+#ifndef WIN32
+#include <sys/stat.h>
+#endif
+
+/*
+ * Attribute flags.  These should be or-ed together to figure out what
+ * has been changed!
+ */
+#define ATTR_MODE       1
+#define ATTR_UID        2
 #define ATTR_GID	4
 #define ATTR_SIZE	8
 #define ATTR_ATIME	16
@@ -161,21 +179,21 @@ struct iattr {
 	unsigned ia_atime;
 	unsigned ia_mtime;
 	unsigned ia_ctime;
-        unsigned int ia_attr_flags;
-};
-
+        unsigned int ia_attr_flags;
+};
+
 #endif
 
 
-#define KERN_DEBUG
-
-#else
-
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/stat.h>
-
-#endif
-
-
-#endif
+#define KERN_DEBUG
+
+#else
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+
+#endif
+
+
+#endif
--- a/direct/dtest.c
+++ b/direct/dtest.c
@@ -966,6 +966,7 @@ void rename_over_test(const char *mountp
 	
 }
 
+
 int resize_stress_test(const char *path)
 {
    int a,b,i,j;
@@ -1029,6 +1030,28 @@ int resize_stress_test(const char *path)
    
 }
 
+int root_perm_remount(const char *path)
+{
+   struct yaffs_stat s;
+   
+   yaffs_StartUp();
+   
+   yaffs_mount(path);
+   
+   yaffs_stat(path,&s);
+   printf("root perms after mount %x\n",s.st_mode);
+   
+   yaffs_chmod(path, 0777);
+
+   yaffs_stat(path,&s);
+   printf("root perms after setting to 0777 is  %x\n",s.st_mode);
+   
+   yaffs_unmount(path);
+      
+   return 0;
+   
+}
+
 
 int resize_stress_test_no_grow_complex(const char *path,int iters)
 {
@@ -2259,7 +2282,8 @@ int main(int argc, char *argv[])
 	
 	//return cache_read_test();
 	
-	//resize_stress_test_no_grow("/flash/flash",20);
+	// resize_stress_test_no_grow("/flash/flash",20);
+	//root_perm_remount("/flash/flash");
 	
 	//huge_directory_test_on_path("/ram2k");
 	
--- a/direct/yaffsfs.c
+++ b/direct/yaffsfs.c
@@ -1602,6 +1602,28 @@ loff_t yaffs_totalspace(const YCHAR *pat
 	return retVal;
 }
 
+int yaffs_inodecount(const YCHAR *path)
+{
+	loff_t retVal= -1;
+	yaffs_Device *dev=NULL;
+	YCHAR *dummy;
+
+	yaffsfs_Lock();
+	dev = yaffsfs_FindDevice(path,&dummy);
+	if(dev  && dev->isMounted) {
+	   int nObjects = dev->nObjectsCreated - dev->nFreeObjects;
+	   if(nObjects > dev->nHardLinks)
+		retVal = nObjects - dev->nHardLinks;
+	}
+	
+	if(retVal < 0){
+		yaffsfs_SetError(-EINVAL);
+	}
+	
+	yaffsfs_Unlock();
+	return retVal;	
+}
+
 
 
 void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList)
--- a/direct/yaffsfs.h
+++ b/direct/yaffsfs.h
@@ -272,6 +272,9 @@ int yaffs_mknod(const YCHAR *pathname, m
 loff_t yaffs_freespace(const YCHAR *path);
 loff_t yaffs_totalspace(const YCHAR *path);
 
+int yaffs_inodecount(const YCHAR *path);
+
+
 void yaffs_initialise(yaffsfs_DeviceConfiguration *configList);
 
 int yaffs_StartUp(void);
--- a/mtdemul/Makefile
+++ b/mtdemul/Makefile
@@ -15,8 +15,9 @@
 ## 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 = /opt/linux-source-2.6.24
 
+#CFLAGS = -D__KERNEL__ -DMODULE   -I$(KERNELDIR)/include -O2 -Wall -g
 CFLAGS = -D__KERNEL__ -DMODULE   -I$(KERNELDIR)/include -O2 -Wall -g
 
 
--- a/mtdemul/nandemul2k.c
+++ b/mtdemul/nandemul2k.c
@@ -15,7 +15,7 @@
  *  This version hacked for emulating 2kpage NAND for YAFFS2 testing.
  */
 
-#include <linux/config.h>
+//#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/version.h>
@@ -280,15 +280,10 @@ static int nandemul2k_ReadStatus(__u8 *s
  */
 static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
 			size_t *retlen, u_char *buf);
-static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *dummy);
 static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
 				size_t *retlen, u_char *buf);
 static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
 			size_t *retlen, const u_char *buf);
-static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf,
-				u_char *oob_buf, struct nand_oobinfo *dummy);
 static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
 				size_t *retlen, const u_char *buf);
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7))
@@ -343,17 +338,17 @@ static int nand_read_ecc (struct mtd_inf
 
 		/* Get raw starting column */
 
-		start = from & (mtd->oobblock-1);
+		start = from & (PAGE_DATA_SIZE - 1);
 
 		// OK now check for the curveball where the start and end are in
 		// the same page
-		if((start + n) < mtd->oobblock)
+		if((start + n) < PAGE_DATA_SIZE)
 		{
 			nToCopy = n;
 		}
 		else
 		{
-			nToCopy =  mtd->oobblock - start;
+			nToCopy =  PAGE_DATA_SIZE - start;
 		}
 
 		nandemul2k_Read(buf, page, start, nToCopy);
@@ -386,7 +381,7 @@ static int nand_read_oob (struct mtd_inf
 	page = ((int) from) >> NAND_SHIFT;
 
 	/* Mask to get column */
-	col = from & 0x0f;
+	col = from & (PAGE_SPARE_SIZE-1)
 
 	/* Initialize return length value */
 	*retlen = 0;
@@ -447,17 +442,17 @@ static int nand_write_ecc (struct mtd_in
 
 		/* Get raw starting column */
 
-		start = to & (mtd->oobblock - 1);
+		start = to & (PAGE_DATA_SIZE - 1);
 
 		// OK now check for the curveball where the start and end are in
 		// the same page
-		if((start + n) < mtd->oobblock)
+		if((start + n) < PAGE_DATA_SIZE)
 		{
 			nToCopy = n;
 		}
 		else
 		{
-			nToCopy =  mtd->oobblock - start;
+			nToCopy =  PAGE_DATA_SIZE - start;
 		}
 
 		nandemul2k_Program(buf, page, start, nToCopy);
@@ -492,7 +487,7 @@ static int nand_write_oob (struct mtd_in
 	page = ((int) to) >> NAND_SHIFT;
 
 	/* Mask to get column */
-	col = to & 0x0f;
+	col = to & PAGE_SPARE_SIZE;
 
 	/* Initialize return length value */
 	*retlen = 0;
@@ -567,10 +562,9 @@ static int nand_erase (struct mtd_info *
 		nandemul2k_DoErase(block);
 		block++;
 	}
-
-	instr->state = MTD_ERASE_DONE;  * change state to ERASE_DONE */
-
-	instr->callback(instr);  * wake up */
+	
+	instr->state = MTD_ERASE_DONE; /* Changed state to done */
+	instr->callback(instr);	       /* ... and wake up */
 
 	return 0;
 
@@ -603,8 +597,9 @@ static void nand_sync (struct mtd_info *
  */
 static int nandemul2k_scan (struct mtd_info *mtd,int nchips)
 {
-	mtd->oobblock = PAGE_DATA_SIZE;
-	mtd->oobsize =  PAGE_SPARE_SIZE;
+	mtd->writesize = PAGE_DATA_SIZE;
+	mtd->oobsize   = PAGE_SPARE_SIZE;
+	mtd->oobavail  = PAGE_SPARE_SIZE/2; /* Simulate using up some for other uses */
 	mtd->erasesize = PAGE_DATA_SIZE * PAGES_PER_BLOCK;
 	mtd->size = sizeInMB * 1024*1024;
 
@@ -614,14 +609,13 @@ static int nandemul2k_scan (struct mtd_i
 	mtd->type = MTD_NANDFLASH;
 	mtd->flags = MTD_CAP_NANDFLASH;
 	mtd->owner = THIS_MODULE;
-	mtd->ecctype = MTD_ECC_NONE;
 	mtd->erase = nand_erase;
 	mtd->point = NULL;
 	mtd->unpoint = NULL;
 	mtd->read = nand_read;
 	mtd->write = nand_write;
-	mtd->read_ecc = nand_read_ecc;
-	mtd->write_ecc = nand_write_ecc;
+	mtd->read_oob = nand_read_oob;
+	mtd->write_oob = nand_write_oob;
 	mtd->read_oob = nand_read_oob;
 	mtd->write_oob = nand_write_oob;
 	mtd->block_isbad = nand_block_isbad;
--- a/yaffs_fs.c
+++ b/yaffs_fs.c
@@ -43,7 +43,6 @@ extern const char *yaffs_guts_c_version;
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/list.h>
 #include <linux/fs.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
@@ -108,6 +107,19 @@ MODULE_PARM(yaffs_traceMask,"i");
 MODULE_PARM(yaffs_wr_attempts,"i");
 #endif
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
+/* use iget and read_inode */
+#define Y_IGET(sb,inum) iget((sb),(inum))
+static void yaffs_read_inode(struct inode *inode);
+
+#else
+/* Call local equivalent */
+#define YAFFS_USE_OWN_IGET
+#define Y_IGET(sb,inum) yaffs_iget((sb),(inum))
+
+static struct inode * yaffs_iget(struct super_block *sb, unsigned long ino);
+#endif
+
 /*#define T(x) printk x */
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
@@ -183,7 +195,6 @@ static int yaffs_statfs(struct super_blo
 #else
 static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
 #endif
-static void yaffs_read_inode(struct inode *inode);
 
 static void yaffs_put_inode(struct inode *inode);
 static void yaffs_delete_inode(struct inode *);
@@ -286,7 +297,10 @@ static struct file_operations yaffs_dir_
 
 static struct super_operations yaffs_super_ops = {
 	.statfs = yaffs_statfs,
+
+#ifndef YAFFS_USE_OWN_IGET
 	.read_inode = yaffs_read_inode,
+#endif
 	.put_inode = yaffs_put_inode,
 	.put_super = yaffs_put_super,
 	.delete_inode = yaffs_delete_inode,
@@ -848,7 +862,9 @@ struct inode *yaffs_get_inode(struct sup
 	T(YAFFS_TRACE_OS,
 	  (KERN_DEBUG "yaffs_get_inode for object %d\n", obj->objectId));
 
-	inode = iget(sb, obj->objectId);
+	inode = Y_IGET(sb, obj->objectId);
+	if(IS_ERR(inode))
+	  return NULL;
 
 	/* NB Side effect: iget calls back to yaffs_read_inode(). */
 	/* iget also increments the inode's i_count */
@@ -920,7 +936,7 @@ static int yaffs_readdir(struct file *f,
 	yaffs_Device *dev;
 	struct inode *inode = f->f_dentry->d_inode;
 	unsigned long offset, curoffs;
-	struct list_head *i;
+	struct ylist_head *i;
 	yaffs_Object *l;
 
 	char name[YAFFS_MAX_NAME_LENGTH + 1];
@@ -969,10 +985,10 @@ static int yaffs_readdir(struct file *f,
 		f->f_version = inode->i_version;
 	}
 
-	list_for_each(i, &obj->variant.directoryVariant.children) {
+	ylist_for_each(i, &obj->variant.directoryVariant.children) {
 		curoffs++;
 		if (curoffs >= offset) {
-			l = list_entry(i, yaffs_Object, siblings);
+			l = ylist_entry(i, yaffs_Object, siblings);
 
 			yaffs_GetObjectName(l, name,
 					    YAFFS_MAX_NAME_LENGTH + 1);
@@ -1273,7 +1289,7 @@ static int yaffs_rename(struct inode *ol
 
 	if (target &&
 	    target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
-	    !list_empty(&target->variant.directoryVariant.children)) {
+	    !ylist_empty(&target->variant.directoryVariant.children)) {
 
 	        T(YAFFS_TRACE_OS, (KERN_DEBUG "target is non-empty dir\n"));
 
@@ -1404,7 +1420,6 @@ static int yaffs_statfs(struct super_blo
 }
 
 
-/**
 static int yaffs_do_sync_fs(struct super_block *sb)
 {
 
@@ -1414,8 +1429,10 @@ static int yaffs_do_sync_fs(struct super
 	if(sb->s_dirt) {
 		yaffs_GrossLock(dev);
 
-		if(dev)
+		if(dev){
+			yaffs_FlushEntireDeviceCache(dev);
 			yaffs_CheckpointSave(dev);
+		}
 
 		yaffs_GrossUnlock(dev);
 
@@ -1423,7 +1440,7 @@ static int yaffs_do_sync_fs(struct super
 	}
 	return 0;
 }
-**/
+
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
 static void yaffs_write_super(struct super_block *sb)
@@ -1433,8 +1450,9 @@ static int yaffs_write_super(struct supe
 {
 
 	T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_super\n"));
+	yaffs_do_sync_fs(sb);
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
-	return 0; /* yaffs_do_sync_fs(sb);*/
+	return 0; 
 #endif
 }
 
@@ -1448,10 +1466,47 @@ static int yaffs_sync_fs(struct super_bl
 
 	T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n"));
 
-	return 0; /* yaffs_do_sync_fs(sb);*/
+	yaffs_do_sync_fs(sb);
+	
+	return 0; 
 
 }
 
+#ifdef YAFFS_USE_OWN_IGET
+
+static struct inode * yaffs_iget(struct super_block *sb, unsigned long ino)
+{
+	struct inode *inode;
+	yaffs_Object *obj;
+	yaffs_Device *dev = yaffs_SuperToDevice(sb);
+
+	T(YAFFS_TRACE_OS,
+	  (KERN_DEBUG "yaffs_iget for %lu\n", ino));
+
+	inode = iget_locked(sb, ino);
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
+	if (!(inode->i_state & I_NEW))
+		return inode;
+
+       /* NB This is called as a side effect of other functions, but
+	* we had to release the lock to prevent deadlocks, so
+	* need to lock again.
+	*/
+    
+	yaffs_GrossLock(dev);
+
+	obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
+
+	yaffs_FillInodeFromObject(inode, obj);
+
+	yaffs_GrossUnlock(dev);
+	
+	unlock_new_inode(inode);
+	return inode;
+}
+
+#else
 
 static void yaffs_read_inode(struct inode *inode)
 {
@@ -1475,7 +1530,9 @@ static void yaffs_read_inode(struct inod
 	yaffs_GrossUnlock(dev);
 }
 
-static LIST_HEAD(yaffs_dev_list);
+#endif
+
+static YLIST_HEAD(yaffs_dev_list);
 
 #if 0 // not used
 static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
@@ -1529,7 +1586,7 @@ static void yaffs_put_super(struct super
 	yaffs_GrossUnlock(dev);
 
 	/* we assume this is protected by lock_kernel() in mount/umount */
-	list_del(&dev->devList);
+	ylist_del(&dev->devList);
 
 	if(dev->spareBuffer){
 		YFREE(dev->spareBuffer);
@@ -1864,7 +1921,7 @@ static struct super_block *yaffs_interna
 	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);
+	ylist_add_tail(&dev->devList, &yaffs_dev_list);
 
 	init_MUTEX(&dev->grossLock);
 
@@ -2049,7 +2106,7 @@ static int yaffs_proc_read(char *page,
 			   char **start,
 			   off_t offset, int count, int *eof, void *data)
 {
-	struct list_head *item;
+	struct ylist_head *item;
 	char *buf = page;
 	int step = offset;
 	int n = 0;
@@ -2073,8 +2130,8 @@ static int yaffs_proc_read(char *page,
 	lock_kernel();
 
 	/* Locate and print the Nth entry.  Order N-squared but N is small. */
-	list_for_each(item, &yaffs_dev_list) {
-		yaffs_Device *dev = list_entry(item, yaffs_Device, devList);
+	ylist_for_each(item, &yaffs_dev_list) {
+		yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
 		if (n < step) {
 			n++;
 			continue;
--- a/yaffs_guts.c
+++ b/yaffs_guts.c
@@ -767,20 +767,20 @@ static void yaffs_VerifyObject(yaffs_Obj
 		return;
 		
 	/* Check sane object header chunk */
-	
-        chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
-        chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
-        
-        chunkIdOk = (((unsigned)(obj->chunkId)) >= chunkMin && ((unsigned)(obj->chunkId)) <= chunkMax);
-        chunkIsLive = chunkIdOk && 
-                        yaffs_CheckChunkBit(dev, 
-                                            obj->chunkId / dev->nChunksPerBlock,
-					    obj->chunkId % dev->nChunksPerBlock);
-	if(!obj->fake && 
+
+	chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
+	chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
+
+	chunkIdOk = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
+	chunkIsLive = chunkIdOk &&
+			yaffs_CheckChunkBit(dev,
+					    obj->hdrChunk / dev->nChunksPerBlock,
+					    obj->hdrChunk % dev->nChunksPerBlock);
+	if(!obj->fake &&
 	    (!chunkIdOk || !chunkIsLive)) {
 	   T(YAFFS_TRACE_VERIFY,
 	   (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
-	   obj->objectId,obj->chunkId,
+	   obj->objectId,obj->hdrChunk,
 	   chunkIdOk ? "" : ",out of range",
 	   chunkIsLive || !chunkIdOk ? "" : ",marked as deleted"));
 	}
@@ -791,9 +791,9 @@ static void yaffs_VerifyObject(yaffs_Obj
 		__u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
 		
 		oh = (yaffs_ObjectHeader *)buffer;
-		
-		yaffs_ReadChunkWithTagsFromNAND(dev, obj->chunkId,buffer, &tags);
-		
+
+		yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk,buffer, &tags);
+
 		yaffs_VerifyObjectHeader(obj,oh,&tags,1);
 		
 		yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
@@ -875,7 +875,8 @@ static Y_INLINE int yaffs_HashFunction(i
 }
 
 /*
- * Access functions to useful fake objects
+ * Access functions to useful fake objects.
+ * Note that root might have a presence in NAND if permissions are set.
  */
  
 yaffs_Object *yaffs_Root(yaffs_Device * dev)
@@ -1922,12 +1923,12 @@ static yaffs_Object *yaffs_AllocateEmpty
 		/* Now sweeten it up... */
 
 		memset(tn, 0, sizeof(yaffs_Object));
-                tn->myDev = dev;
-                tn->chunkId = -1;
-                tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
-                YINIT_LIST_HEAD(&(tn->hardLinks));
-                YINIT_LIST_HEAD(&(tn->hashLink));
-                YINIT_LIST_HEAD(&tn->siblings);
+		tn->myDev = dev;
+		tn->hdrChunk = 0;
+		tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
+		YINIT_LIST_HEAD(&(tn->hardLinks));
+		YINIT_LIST_HEAD(&(tn->hashLink));
+		YINIT_LIST_HEAD(&tn->siblings);
 
                 /* Add it to the lost and found directory.
                  * NB Can't put root or lostNFound in lostNFound so
@@ -1950,14 +1951,14 @@ static yaffs_Object *yaffs_CreateFakeDir
 	yaffs_Object *obj =
 	    yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
 	if (obj) {
-		obj->fake = 1;		/* it is fake so it has no NAND presence... */
+		obj->fake = 1;		/* it is fake so it might have no NAND presence... */
 		obj->renameAllowed = 0;	/* ... and we're not allowed to rename it... */
 		obj->unlinkAllowed = 0;	/* ... or unlink it */
 		obj->deleted = 0;
 		obj->unlinked = 0;
 		obj->yst_mode = mode;
 		obj->myDev = dev;
-		obj->chunkId = 0;	/* Not a valid chunk. */
+		obj->hdrChunk = 0;	/* Not a valid chunk. */
 	}
 
 	return obj;
@@ -2296,7 +2297,7 @@ static yaffs_Object *yaffs_MknodObject(y
 	
 
 	if (in) {
-		in->chunkId = -1;
+		in->hdrChunk = 0;
 		in->valid = 1;
 		in->variantType = type;
 
@@ -3035,7 +3036,7 @@ static int yaffs_GarbageCollectBlock(yaf
 				   
 				if(object && !yaffs_SkipVerification(dev)){
 					if(tags.chunkId == 0)
-						matchingChunk = object->chunkId;
+						matchingChunk = object->hdrChunk;
 					else if(object->softDeleted)
 						matchingChunk = oldChunk; /* Defeat the test */
 					else
@@ -3079,7 +3080,7 @@ static int yaffs_GarbageCollectBlock(yaf
 					/* Deleted object header with no data chunks.
 					 * Can be discarded and the file deleted.
 					 */
-					object->chunkId = 0;
+					object->hdrChunk = 0;
 					yaffs_FreeTnode(object->myDev,
 							object->variant.
 							fileVariant.top);
@@ -3125,7 +3126,7 @@ static int yaffs_GarbageCollectBlock(yaf
 
 						if (tags.chunkId == 0) {
 							/* It's a header */
-							object->chunkId =  newChunk;
+							object->hdrChunk =  newChunk;
 							object->serial =   tags.serialNumber;
 						} else {
 							/* It's a data chunk */
@@ -3444,7 +3445,7 @@ static int yaffs_PutChunkIntoFile(yaffs_
 		 * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
 		 */
 
-		if (existingChunk != 0) {
+		if (existingChunk > 0) {
 			/* NB Right now existing chunk will not be real chunkId if the device >= 32MB
 			 *    thus we have to do a FindChunkInFile to get the real chunk id.
 			 *
@@ -3675,7 +3676,10 @@ int yaffs_UpdateObjectHeader(yaffs_Objec
         
         yaffs_strcpy(oldName,_Y("silly old name"));
 
-        if (!in->fake || force) {
+
+	if (!in->fake || 
+	    in == dev->rootDir || /* The rootDir should also be saved */
+	    force) {
 
 		yaffs_CheckGarbageCollection(dev);
 		yaffs_CheckObjectDetailsLoaded(in);
@@ -3683,9 +3687,9 @@ int yaffs_UpdateObjectHeader(yaffs_Objec
 		buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
 		oh = (yaffs_ObjectHeader *) buffer;
 
-		prevChunkId = in->chunkId;
-
-		if (prevChunkId >= 0) {
+		prevChunkId = in->hdrChunk;
+
+		if (prevChunkId > 0) {
 			result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
 							buffer, &oldTags);
 			
@@ -3787,7 +3791,7 @@ int yaffs_UpdateObjectHeader(yaffs_Objec
 
 		if (newChunkId >= 0) {
 
-			in->chunkId = newChunkId;
+			in->hdrChunk = newChunkId;
 
 			if (prevChunkId >= 0) {
 				yaffs_DeleteChunk(dev, prevChunkId, 1,
@@ -4227,8 +4231,8 @@ static void yaffs_ObjectToCheckpointObje
 
 	cp->objectId = obj->objectId;
 	cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
-	cp->chunkId = obj->chunkId;
-	cp->variantType = obj->variantType;			
+	cp->hdrChunk = obj->hdrChunk;
+	cp->variantType = obj->variantType;
 	cp->deleted = obj->deleted;
 	cp->softDeleted = obj->softDeleted;
 	cp->unlinked = obj->unlinked;
@@ -4261,9 +4265,9 @@ static void yaffs_CheckpointObjectToObje
 		
 	if(parent)
 		yaffs_AddObjectToDirectory(parent, obj);
-		
-	obj->chunkId = cp->chunkId;
-	obj->variantType = cp->variantType;			
+
+	obj->hdrChunk = cp->hdrChunk;
+	obj->variantType = cp->variantType;
 	obj->deleted = cp->deleted;
 	obj->softDeleted = cp->softDeleted;
 	obj->unlinked = cp->unlinked;
@@ -4277,8 +4281,8 @@ static void yaffs_CheckpointObjectToObje
 		obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
 	else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
 		obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
-		
-	if(obj->objectId >= YAFFS_NOBJECT_BUCKETS)
+
+	if(obj->hdrChunk > 0)
 		obj->lazyLoaded = 1;
 }
 
@@ -4409,8 +4413,8 @@ static int yaffs_WriteCheckpointObjects(
 
 					T(YAFFS_TRACE_CHECKPOINT,(
 						TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
-						cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj));
-						
+						cp.objectId,cp.parentId,cp.variantType,cp.hdrChunk,(unsigned) obj));
+
 					ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
 					
 					if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){
@@ -4448,8 +4452,8 @@ static int yaffs_ReadCheckpointObjects(y
 		}
 			
 		T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
-			cp.objectId,cp.parentId,cp.variantType,cp.chunkId));
-			
+			cp.objectId,cp.parentId,cp.variantType,cp.hdrChunk));
+
 		if(ok && cp.objectId == ~0)
 			done = 1;
 		else if(ok){
@@ -5143,8 +5147,8 @@ static int yaffs_DoGenericObjectDeletion
 	}
 
 	yaffs_RemoveObjectFromDirectory(in);
-	yaffs_DeleteChunk(in->myDev, in->chunkId, 1, __LINE__);
-	in->chunkId = -1;
+	yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
+	in->hdrChunk = 0;
 
 	yaffs_FreeObject(in);
 	return YAFFS_OK;
@@ -5678,7 +5682,7 @@ static int yaffs_Scan(yaffs_Device * dev
 					    newSerial) {
 						/* Use new one - destroy the exisiting one */
 						yaffs_DeleteChunk(dev,
-								  in->chunkId,
+								  in->hdrChunk,
 								  1, __LINE__);
 						in->valid = 0;
 					} else {
@@ -5711,7 +5715,7 @@ static int yaffs_Scan(yaffs_Device * dev
 					in->yst_ctime = oh->yst_ctime;
 					in->yst_rdev = oh->yst_rdev;
 #endif
-					in->chunkId = chunk;
+					in->hdrChunk = chunk;
 
 				} else if (in && !in->valid) {
 					/* we need to load this info */
@@ -5735,7 +5739,7 @@ static int yaffs_Scan(yaffs_Device * dev
 					in->yst_ctime = oh->yst_ctime;
 					in->yst_rdev = oh->yst_rdev;
 #endif
-					in->chunkId = chunk;
+					in->hdrChunk = chunk;
 
 					yaffs_SetObjectName(in, oh->name);
 					in->dirty = 0;
@@ -5934,12 +5938,12 @@ static void yaffs_CheckObjectDetailsLoad
 		in->lazyLoaded ? "not yet" : "already"));
 #endif
 
-	if(in->lazyLoaded){
+	if(in->lazyLoaded && in->hdrChunk > 0){
 		in->lazyLoaded = 0;
 		chunkData = yaffs_GetTempBuffer(dev, __LINE__);
 
-		result = yaffs_ReadChunkWithTagsFromNAND(dev,in->chunkId,chunkData,&tags);
-		oh = (yaffs_ObjectHeader *) chunkData;		
+		result = yaffs_ReadChunkWithTagsFromNAND(dev,in->hdrChunk,chunkData,&tags);
+		oh = (yaffs_ObjectHeader *) chunkData;
 
 		in->yst_mode = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
@@ -6420,15 +6424,15 @@ static int yaffs_ScanBackwards(yaffs_Dev
 						in->variantType = tags.extraObjectType;
 						in->lazyLoaded = 1;
 					}
-						
-					in->chunkId = chunk;
+
+					in->hdrChunk = chunk;
 
 				} else if (!in->valid) {
 					/* we need to load this info */
 
 					in->valid = 1;
-					in->chunkId = chunk;
-					
+					in->hdrChunk = chunk;
+
 					if(oh) {
 						in->variantType = oh->type;
 
@@ -6745,9 +6749,8 @@ yaffs_Object *yaffs_FindObjectByName(yaf
 				if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) {
 					return l;
 				}
-			} else if (yaffs_SumCompare(l->sum, sum) || l->chunkId <= 0)	
-			{
-				/* LostnFound cunk called Objxxx
+			} else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0){
+				/* LostnFound chunk called Objxxx
 				 * Do a real check
 				 */
 				yaffs_GetObjectName(l, buffer,
@@ -6822,7 +6825,7 @@ int yaffs_GetObjectName(yaffs_Object * o
 
 	if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
 		yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
-	} else if (obj->chunkId <= 0) {
+	} else if (obj->hdrChunk <= 0) {
 		YCHAR locName[20];
 		/* make up a name */
 		yaffs_sprintf(locName, _Y("%s%d"), YAFFS_LOSTNFOUND_PREFIX,
@@ -6843,9 +6846,9 @@ int yaffs_GetObjectName(yaffs_Object * o
 
 		memset(buffer, 0, obj->myDev->nDataBytesPerChunk);
 
-		if (obj->chunkId >= 0) {
+		if (obj->hdrChunk > 0) {
 			result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev,
-							obj->chunkId, buffer,
+							obj->hdrChunk, buffer,
 							NULL);
 		}
 		yaffs_strncpy(name, oh->name, buffSize - 1);
@@ -7006,7 +7009,7 @@ int yaffs_DumpObject(yaffs_Object * obj)
 	   ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d"
 	    " chunk %d type %d size %d\n"
 	    TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name,
-	   obj->dirty, obj->valid, obj->serial, obj->sum, obj->chunkId,
+	   obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk,
 	   yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
 
 	return YAFFS_OK;
@@ -7306,6 +7309,7 @@ int yaffs_GutsInitialise(yaffs_Device * 
 		/* Now scan the flash. */
 		if (dev->isYaffs2) {
 			if(yaffs_CheckpointRestore(dev)) {
+				yaffs_CheckObjectDetailsLoaded(dev->rootDir);
 				T(YAFFS_TRACE_ALWAYS,
 				  (TSTR("yaffs: restored from checkpoint" TENDSTR)));
 			} else {
--- a/yaffs_guts.h
+++ b/yaffs_guts.h
@@ -436,8 +436,8 @@ struct yaffs_ObjectStruct {
         struct yaffs_ObjectStruct *parent; 
         struct ylist_head siblings;
 
-        /* Where's my object header in NAND? */
-        int chunkId;            
+	/* Where's my object header in NAND? */
+	int hdrChunk;
 
 	int nDataChunks;	/* Number of data chunks attached to the file. */
 
@@ -501,8 +501,7 @@ typedef struct {
         int structType;
 	__u32 objectId;		
 	__u32 parentId;
-	int chunkId;
-			
+	int hdrChunk;
 	yaffs_ObjectType variantType:3;
 	__u8 deleted:1;		
 	__u8 softDeleted:1;	
@@ -693,6 +692,8 @@ struct yaffs_DeviceStruct {
 	int nObjectsCreated;
 	yaffs_Object *freeObjects;
 	int nFreeObjects;
+	
+	int nHardLinks;
 
 	yaffs_ObjectList *allocatedObjectList;