linux/generic: sync to todays yaffs tree
authorAlexandros C. Couloumbis <alex@ozo.com>
Wed, 20 Oct 2010 11:27:31 +0000 (11:27 +0000)
committerAlexandros C. Couloumbis <alex@ozo.com>
Wed, 20 Oct 2010 11:27:31 +0000 (11:27 +0000)
SVN-Revision: 23544

target/linux/generic/patches-2.6.36/511-yaffs-git-2010-10-01.patch [deleted file]
target/linux/generic/patches-2.6.36/511-yaffs-git-2010-10-20.patch [new file with mode: 0644]

diff --git a/target/linux/generic/patches-2.6.36/511-yaffs-git-2010-10-01.patch b/target/linux/generic/patches-2.6.36/511-yaffs-git-2010-10-01.patch
deleted file mode 100644 (file)
index 1ba5b1f..0000000
+++ /dev/null
@@ -1,23872 +0,0 @@
---- a/fs/yaffs2/devextras.h
-+++ b/fs/yaffs2/devextras.h
-@@ -1,7 +1,7 @@
- /*
-  * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
-  *
-- * Copyright (C) 2002-2007 Aleph One Ltd.
-+ * Copyright (C) 2002-2010 Aleph One Ltd.
-  *   for Toby Churchill Ltd and Brightstar Engineering
-  *
-  * Created by Charles Manning <charles@aleph1.co.uk>
-@@ -24,6 +24,8 @@
- #define __EXTRAS_H__
-+#include "yportenv.h"
-+
- #if !(defined __KERNEL__)
- /* Definition of types */
-@@ -33,103 +35,6 @@ typedef unsigned __u32;
- #endif
--/*
-- * 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 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);\
--      (p)->prev = (p); \
--} 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;
--      newEntry->next = listNext;
--      listNext->prev = newEntry;
--
--}
--
--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;
--
--}
--
--static __inline__ void ylist_del_init(struct ylist_head *entry)
--{
--      ylist_del(entry);
--      entry->next = entry->prev = entry;
--}
--
--
--/* Test if the list is empty */
--static __inline__ int ylist_empty(struct ylist_head *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.
-- */
--
--
--#define ylist_entry(entry, type, 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)
--
--#define ylist_for_each_safe(itervar, saveVar, list) \
--      for (itervar = (list)->next, saveVar = (list)->next->next; \
--              itervar != (list); itervar = saveVar, saveVar = saveVar->next)
--
- #if !(defined __KERNEL__)
---- a/fs/yaffs2/Kconfig
-+++ b/fs/yaffs2/Kconfig
-@@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2
-         If unsure, say Y.
--config YAFFS_DISABLE_LAZY_LOAD
--      bool "Disable lazy loading"
--      depends on YAFFS_YAFFS2
-+config YAFFS_DISABLE_TAGS_ECC
-+      bool "Disable YAFFS from doing ECC on tags by default"
-+      depends on YAFFS_FS && YAFFS_YAFFS2
-       default n
-       help
--        "Lazy loading" defers loading file details until they are
--        required. This saves mount time, but makes the first look-up
--        a bit longer.
--
--        Lazy loading will only happen if enabled by this option being 'n'
--        and if the appropriate tags are available, else yaffs2 will
--        automatically fall back to immediate loading and do the right
--        thing.
--
--        Lazy laoding will be required by checkpointing.
--
--        Setting this to 'y' will disable lazy loading.
-+        This defaults Yaffs to using its own ECC calculations on tags instead of
-+        just relying on the MTD.
-+        This behavior can also be overridden with tags_ecc_on and
-+        tags_ecc_off mount options.
-         If unsure, say N.
-@@ -154,3 +146,45 @@ config YAFFS_SHORT_NAMES_IN_RAM
-         but makes look-ups faster.
-         If unsure, say Y.
-+
-+config YAFFS_EMPTY_LOST_AND_FOUND
-+      bool "Empty lost and found on boot"
-+      depends on YAFFS_FS
-+      default n
-+      help
-+        If this is enabled then the contents of lost and found is
-+        automatically dumped at mount.
-+
-+        If unsure, say N.
-+
-+config YAFFS_DISABLE_BLOCK_REFRESHING
-+      bool "Disable yaffs2 block refreshing"
-+      depends on YAFFS_FS
-+      default n
-+      help
-+       If this is set, then block refreshing is disabled.
-+       Block refreshing infrequently refreshes the oldest block in
-+       a yaffs2 file system. This mechanism helps to refresh flash to
-+       mitigate against data loss. This is particularly useful for MLC.
-+
-+        If unsure, say N.
-+
-+config YAFFS_DISABLE_BACKGROUND
-+      bool "Disable yaffs2 background processing"
-+      depends on YAFFS_FS
-+      default n
-+      help
-+       If this is set, then background processing is disabled.
-+       Background processing makes many foreground activities faster.
-+
-+        If unsure, say N.
-+
-+config YAFFS_XATTR
-+      bool "Enable yaffs2 xattr support"
-+      depends on YAFFS_FS
-+      default y
-+      help
-+       If this is set then yaffs2 will provide xattr support.
-+       If unsure, say Y.
-+
-+
---- a/fs/yaffs2/Makefile
-+++ b/fs/yaffs2/Makefile
-@@ -4,7 +4,14 @@
- obj-$(CONFIG_YAFFS_FS) += yaffs.o
--yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
--yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
-+yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o
-+yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
- yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
- yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
-+yaffs-y += yaffs_nameval.o
-+yaffs-y += yaffs_allocator.o
-+yaffs-y += yaffs_yaffs1.o
-+yaffs-y += yaffs_yaffs2.o
-+yaffs-y += yaffs_bitmap.o
-+yaffs-y += yaffs_verify.o
-+
---- a/fs/yaffs2/moduleconfig.h
-+++ b/fs/yaffs2/moduleconfig.h
-@@ -1,7 +1,7 @@
- /*
-  * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
-  *
-- * Copyright (C) 2002-2007 Aleph One Ltd.
-+ * Copyright (C) 2002-2010 Aleph One Ltd.
-  *   for Toby Churchill Ltd and Brightstar Engineering
-  *
-  * Created by Martin Fouts <Martin.Fouts@palmsource.com>
-@@ -29,22 +29,43 @@
- /* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
- /* #define CONFIG_YAFFS_DOES_ECC */
-+/* Default: Selected */
-+/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */
-+#define CONFIG_YAFFS_DOES_TAGS_ECC
-+
- /* Default: Not selected */
- /* Meaning: ECC byte order is 'wrong'.  Only meaningful if */
- /*          CONFIG_YAFFS_DOES_ECC is set */
- /* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
--/* Default: Selected */
--/* Meaning: Disables testing whether chunks are erased before writing to them*/
--#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
-+/* Default: Not selected */
-+/* Meaning: Always test whether chunks are erased before writing to them.
-+          Use during mtd debugging and init. */
-+/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */
-+
-+/* Default: Not Selected */
-+/* Meaning: At mount automatically empty all files from lost and found. */
-+/* This is done to fix an old problem where rmdir was not checking for an */
-+/* empty directory. This can also be achieved with a mount option. */
-+#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
- /* Default: Selected */
- /* Meaning: Cache short names, taking more RAM, but faster look-ups */
- #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
--/* Default: 10 */
--/* Meaning: set the count of blocks to reserve for checkpointing */
--#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
-+/* Default: Unselected */
-+/* Meaning: Select to disable block refreshing. */
-+/* Block Refreshing periodically rewrites the oldest block. */
-+/* #define CONFIG_DISABLE_BLOCK_REFRESHING */
-+
-+/* Default: Unselected */
-+/* Meaning: Select to disable background processing */
-+/* #define CONFIG_DISABLE_BACKGROUND */
-+
-+
-+/* Default: Selected */
-+/* Meaning: Enable XATTR support */
-+#define CONFIG_YAFFS_XATTR
- /*
- Older-style on-NAND data format has a "pageStatus" byte to record
---- /dev/null
-+++ b/fs/yaffs2/yaffs_allocator.c
-@@ -0,0 +1,409 @@
-+/*
-+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
-+ *
-+ * Copyright (C) 2002-2010 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 Lesser General Public License version 2.1 as
-+ * published by the Free Software Foundation.
-+ *
-+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
-+ */
-+
-+
-+#include "yaffs_allocator.h"
-+#include "yaffs_guts.h"
-+#include "yaffs_trace.h"
-+#include "yportenv.h"
-+
-+#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
-+
-+void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
-+{
-+      dev = dev;
-+}
-+
-+void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
-+{
-+      dev = dev;
-+}
-+
-+yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
-+{
-+      return (yaffs_Tnode *)YMALLOC(dev->tnodeSize);
-+}
-+
-+void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
-+{
-+      dev = dev;
-+      YFREE(tn);
-+}
-+
-+void yaffs_InitialiseRawObjects(yaffs_Device *dev)
-+{
-+      dev = dev;
-+}
-+
-+void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
-+{
-+      dev = dev;
-+}
-+
-+yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
-+{
-+      dev = dev;
-+      return (yaffs_Object *) YMALLOC(sizeof(yaffs_Object));
-+}
-+
-+
-+void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
-+{
-+
-+      dev = dev;
-+      YFREE(obj);
-+}
-+
-+#else
-+
-+struct yaffs_TnodeList_struct {
-+      struct yaffs_TnodeList_struct *next;
-+      yaffs_Tnode *tnodes;
-+};
-+
-+typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
-+
-+struct yaffs_ObjectList_struct {
-+      yaffs_Object *objects;
-+      struct yaffs_ObjectList_struct *next;
-+};
-+
-+typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
-+
-+
-+struct yaffs_AllocatorStruct {
-+      int nTnodesCreated;
-+      yaffs_Tnode *freeTnodes;
-+      int nFreeTnodes;
-+      yaffs_TnodeList *allocatedTnodeList;
-+
-+      int nObjectsCreated;
-+      yaffs_Object *freeObjects;
-+      int nFreeObjects;
-+
-+      yaffs_ObjectList *allocatedObjectList;
-+};
-+
-+typedef struct yaffs_AllocatorStruct yaffs_Allocator;
-+
-+
-+static void yaffs_DeinitialiseRawTnodes(yaffs_Device *dev)
-+{
-+
-+      yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
-+
-+      yaffs_TnodeList *tmp;
-+
-+      if(!allocator){
-+              YBUG();
-+              return;
-+      }
-+
-+      while (allocator->allocatedTnodeList) {
-+              tmp = allocator->allocatedTnodeList->next;
-+
-+              YFREE(allocator->allocatedTnodeList->tnodes);
-+              YFREE(allocator->allocatedTnodeList);
-+              allocator->allocatedTnodeList = tmp;
-+
-+      }
-+
-+      allocator->freeTnodes = NULL;
-+      allocator->nFreeTnodes = 0;
-+      allocator->nTnodesCreated = 0;
-+}
-+
-+static void yaffs_InitialiseRawTnodes(yaffs_Device *dev)
-+{
-+      yaffs_Allocator *allocator = dev->allocator;
-+
-+      if(allocator){
-+              allocator->allocatedTnodeList = NULL;
-+              allocator->freeTnodes = NULL;
-+              allocator->nFreeTnodes = 0;
-+              allocator->nTnodesCreated = 0;
-+      } else
-+              YBUG();
-+}
-+
-+static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
-+{
-+      yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
-+      int i;
-+      yaffs_Tnode *newTnodes;
-+      __u8 *mem;
-+      yaffs_Tnode *curr;
-+      yaffs_Tnode *next;
-+      yaffs_TnodeList *tnl;
-+
-+      if(!allocator){
-+              YBUG();
-+              return YAFFS_FAIL;
-+      }
-+
-+      if (nTnodes < 1)
-+              return YAFFS_OK;
-+
-+
-+      /* make these things */
-+
-+      newTnodes = YMALLOC(nTnodes * dev->tnodeSize);
-+      mem = (__u8 *)newTnodes;
-+
-+      if (!newTnodes) {
-+              T(YAFFS_TRACE_ERROR,
-+                      (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
-+              return YAFFS_FAIL;
-+      }
-+
-+      /* New hookup for wide tnodes */
-+      for (i = 0; i < nTnodes - 1; i++) {
-+              curr = (yaffs_Tnode *) &mem[i * dev->tnodeSize];
-+              next = (yaffs_Tnode *) &mem[(i+1) * dev->tnodeSize];
-+              curr->internal[0] = next;
-+      }
-+
-+      curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * dev->tnodeSize];
-+      curr->internal[0] = allocator->freeTnodes;
-+      allocator->freeTnodes = (yaffs_Tnode *)mem;
-+
-+      allocator->nFreeTnodes += nTnodes;
-+      allocator->nTnodesCreated += nTnodes;
-+
-+      /* Now add this bunch of tnodes to a list for freeing up.
-+       * NB If we can't add this to the management list it isn't fatal
-+       * but it just means we can't free this bunch of tnodes later.
-+       */
-+
-+      tnl = YMALLOC(sizeof(yaffs_TnodeList));
-+      if (!tnl) {
-+              T(YAFFS_TRACE_ERROR,
-+                (TSTR
-+                 ("yaffs: Could not add tnodes to management list" TENDSTR)));
-+                 return YAFFS_FAIL;
-+      } else {
-+              tnl->tnodes = newTnodes;
-+              tnl->next = allocator->allocatedTnodeList;
-+              allocator->allocatedTnodeList = tnl;
-+      }
-+
-+      T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
-+
-+      return YAFFS_OK;
-+}
-+
-+
-+yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
-+{
-+      yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
-+      yaffs_Tnode *tn = NULL;
-+
-+      if(!allocator){
-+              YBUG();
-+              return NULL;
-+      }
-+
-+      /* If there are none left make more */
-+      if (!allocator->freeTnodes)
-+              yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
-+
-+      if (allocator->freeTnodes) {
-+              tn = allocator->freeTnodes;
-+              allocator->freeTnodes = allocator->freeTnodes->internal[0];
-+              allocator->nFreeTnodes--;
-+      }
-+
-+      return tn;
-+}
-+
-+/* FreeTnode frees up a tnode and puts it back on the free list */
-+void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
-+{
-+      yaffs_Allocator *allocator = dev->allocator;
-+
-+      if(!allocator){
-+              YBUG();
-+              return;
-+      }
-+
-+      if (tn) {
-+              tn->internal[0] = allocator->freeTnodes;
-+              allocator->freeTnodes = tn;
-+              allocator->nFreeTnodes++;
-+      }
-+      dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
-+}
-+
-+
-+
-+static void yaffs_InitialiseRawObjects(yaffs_Device *dev)
-+{
-+      yaffs_Allocator *allocator = dev->allocator;
-+
-+      if(allocator) {
-+              allocator->allocatedObjectList = NULL;
-+              allocator->freeObjects = NULL;
-+              allocator->nFreeObjects = 0;
-+      } else
-+              YBUG();
-+}
-+
-+static void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
-+{
-+      yaffs_Allocator *allocator = dev->allocator;
-+      yaffs_ObjectList *tmp;
-+
-+      if(!allocator){
-+              YBUG();
-+              return;
-+      }
-+
-+      while (allocator->allocatedObjectList) {
-+              tmp = allocator->allocatedObjectList->next;
-+              YFREE(allocator->allocatedObjectList->objects);
-+              YFREE(allocator->allocatedObjectList);
-+
-+              allocator->allocatedObjectList = tmp;
-+      }
-+
-+      allocator->freeObjects = NULL;
-+      allocator->nFreeObjects = 0;
-+      allocator->nObjectsCreated = 0;
-+}
-+
-+
-+static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
-+{
-+      yaffs_Allocator *allocator = dev->allocator;
-+
-+      int i;
-+      yaffs_Object *newObjects;
-+      yaffs_ObjectList *list;
-+
-+      if(!allocator){
-+              YBUG();
-+              return YAFFS_FAIL;
-+      }
-+
-+      if (nObjects < 1)
-+              return YAFFS_OK;
-+
-+      /* make these things */
-+      newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
-+      list = YMALLOC(sizeof(yaffs_ObjectList));
-+
-+      if (!newObjects || !list) {
-+              if (newObjects){
-+                      YFREE(newObjects);
-+                      newObjects = NULL;
-+              }
-+              if (list){
-+                      YFREE(list);
-+                      list = NULL;
-+              }
-+              T(YAFFS_TRACE_ALLOCATE,
-+                (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
-+              return YAFFS_FAIL;
-+      }
-+
-+      /* Hook them into the free list */
-+      for (i = 0; i < nObjects - 1; i++) {
-+              newObjects[i].siblings.next =
-+                              (struct ylist_head *)(&newObjects[i + 1]);
-+      }
-+
-+      newObjects[nObjects - 1].siblings.next = (void *)allocator->freeObjects;
-+      allocator->freeObjects = newObjects;
-+      allocator->nFreeObjects += nObjects;
-+      allocator->nObjectsCreated += nObjects;
-+
-+      /* Now add this bunch of Objects to a list for freeing up. */
-+
-+      list->objects = newObjects;
-+      list->next = allocator->allocatedObjectList;
-+      allocator->allocatedObjectList = list;
-+
-+      return YAFFS_OK;
-+}
-+
-+yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
-+{
-+      yaffs_Object *obj = NULL;
-+      yaffs_Allocator *allocator = dev->allocator;
-+
-+      if(!allocator) {
-+              YBUG();
-+              return obj;
-+      }
-+
-+      /* If there are none left make more */
-+      if (!allocator->freeObjects)
-+              yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
-+
-+      if (allocator->freeObjects) {
-+              obj = allocator->freeObjects;
-+              allocator->freeObjects =
-+                      (yaffs_Object *) (allocator->freeObjects->siblings.next);
-+              allocator->nFreeObjects--;
-+      }
-+
-+      return obj;
-+}
-+
-+
-+void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
-+{
-+
-+      yaffs_Allocator *allocator = dev->allocator;
-+
-+      if(!allocator)
-+              YBUG();
-+      else {
-+              /* Link into the free list. */
-+              obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
-+              allocator->freeObjects = obj;
-+              allocator->nFreeObjects++;
-+      }
-+}
-+
-+void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
-+{
-+      if(dev->allocator){
-+              yaffs_DeinitialiseRawTnodes(dev);
-+              yaffs_DeinitialiseRawObjects(dev);
-+
-+              YFREE(dev->allocator);
-+              dev->allocator=NULL;
-+      } else
-+              YBUG();
-+}
-+
-+void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
-+{
-+      yaffs_Allocator *allocator;
-+
-+      if(!dev->allocator){
-+              allocator = YMALLOC(sizeof(yaffs_Allocator));
-+              if(allocator){
-+                      dev->allocator = allocator;
-+                      yaffs_InitialiseRawTnodes(dev);
-+                      yaffs_InitialiseRawObjects(dev);
-+              }
-+      } else
-+              YBUG();
-+}
-+
-+
-+#endif
---- /dev/null
-+++ b/fs/yaffs2/yaffs_allocator.h
-@@ -0,0 +1,30 @@
-+/*
-+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
-+ *
-+ * Copyright (C) 2002-2010 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 Lesser General Public License version 2.1 as
-+ * published by the Free Software Foundation.
-+ *
-+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
-+ */
-+
-+#ifndef __YAFFS_ALLOCATOR_H__
-+#define __YAFFS_ALLOCATOR_H__
-+
-+#include "yaffs_guts.h"
-+
-+void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev);
-+void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev);
-+
-+yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev);
-+void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn);
-+
-+yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev);
-+void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj);
-+
-+#endif
---- /dev/null
-+++ b/fs/yaffs2/yaffs_bitmap.c
-@@ -0,0 +1,105 @@
-+/*
-+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
-+ *
-+ * Copyright (C) 2002-2010 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 "yaffs_bitmap.h"
-+#include "yaffs_trace.h"
-+/*
-+ * Chunk bitmap manipulations
-+ */
-+
-+static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
-+{
-+      if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
-+              T(YAFFS_TRACE_ERROR,
-+                      (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
-+                      blk));
-+              YBUG();
-+      }
-+      return dev->chunkBits +
-+              (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
-+}
-+
-+void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
-+{
-+      if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
-+                      chunk < 0 || chunk >= dev->param.nChunksPerBlock) {
-+              T(YAFFS_TRACE_ERROR,
-+              (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
-+                      blk, chunk));
-+              YBUG();
-+      }
-+}
-+
-+void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
-+{
-+      __u8 *blkBits = yaffs_BlockBits(dev, blk);
-+
-+      memset(blkBits, 0, dev->chunkBitmapStride);
-+}
-+
-+void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
-+{
-+      __u8 *blkBits = yaffs_BlockBits(dev, blk);
-+
-+      yaffs_VerifyChunkBitId(dev, blk, chunk);
-+
-+      blkBits[chunk / 8] &= ~(1 << (chunk & 7));
-+}
-+
-+void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
-+{
-+      __u8 *blkBits = yaffs_BlockBits(dev, blk);
-+
-+      yaffs_VerifyChunkBitId(dev, blk, chunk);
-+
-+      blkBits[chunk / 8] |= (1 << (chunk & 7));
-+}
-+
-+int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
-+{
-+      __u8 *blkBits = yaffs_BlockBits(dev, blk);
-+      yaffs_VerifyChunkBitId(dev, blk, chunk);
-+
-+      return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
-+}
-+
-+int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
-+{
-+      __u8 *blkBits = yaffs_BlockBits(dev, blk);
-+      int i;
-+      for (i = 0; i < dev->chunkBitmapStride; i++) {
-+              if (*blkBits)
-+                      return 1;
-+              blkBits++;
-+      }
-+      return 0;
-+}
-+
-+int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
-+{
-+      __u8 *blkBits = yaffs_BlockBits(dev, blk);
-+      int i;
-+      int n = 0;
-+      for (i = 0; i < dev->chunkBitmapStride; i++) {
-+              __u8 x = *blkBits;
-+              while (x) {
-+                      if (x & 1)
-+                              n++;
-+                      x >>= 1;
-+              }
-+
-+              blkBits++;
-+      }
-+      return n;
-+}
-+
---- /dev/null
-+++ b/fs/yaffs2/yaffs_bitmap.h
-@@ -0,0 +1,31 @@
-+/*
-+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
-+ *
-+ * Copyright (C) 2002-2010 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.
-+ */
-+
-+/*
-+ * Chunk bitmap manipulations
-+ */
-+
-+#ifndef __YAFFS_BITMAP_H__
-+#define __YAFFS_BITMAP_H__
-+
-+#include "yaffs_guts.h"
-+
-+void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk);
-+void yaffs_ClearChunkBits(yaffs_Device *dev, int blk);
-+void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk);
-+void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk);
-+int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk);
-+int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk);
-+int yaffs_CountChunkBits(yaffs_Device *dev, int blk);
-+
-+#endif
---- a/fs/yaffs2/yaffs_checkptrw.c
-+++ b/fs/yaffs2/yaffs_checkptrw.c
-@@ -1,7 +1,7 @@
- /*
-  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
-  *
-- * Copyright (C) 2002-2007 Aleph One Ltd.
-+ * Copyright (C) 2002-2010 Aleph One Ltd.
-  *   for Toby Churchill Ltd and Brightstar Engineering
-  *
-  * Created by Charles Manning <charles@aleph1.co.uk>
-@@ -11,16 +11,12 @@
-  * published by the Free Software Foundation.
-  */
--const char *yaffs_checkptrw_c_version =
--      "$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $";
--
--
- #include "yaffs_checkptrw.h"
- #include "yaffs_getblockinfo.h"
--static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
-+static int yaffs2_CheckpointSpaceOk(yaffs_Device *dev)
- {
--      int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
-+      int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks;
-       T(YAFFS_TRACE_CHECKPOINT,
-               (TSTR("checkpt blocks available = %d" TENDSTR),
-@@ -30,11 +26,11 @@ static int yaffs_CheckpointSpaceOk(yaffs
- }
--static int yaffs_CheckpointErase(yaffs_Device *dev)
-+static int yaffs2_CheckpointErase(yaffs_Device *dev)
- {
-       int i;
--      if (!dev->eraseBlockInNAND)
-+      if (!dev->param.eraseBlockInNAND)
-               return 0;
-       T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
-               dev->internalStartBlock, dev->internalEndBlock));
-@@ -43,12 +39,15 @@ static int yaffs_CheckpointErase(yaffs_D
-               yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
-               if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
-                       T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
--                      if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
-+
-+                      dev->nBlockErasures++;
-+
-+                      if (dev->param.eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
-                               bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
-                               dev->nErasedBlocks++;
--                              dev->nFreeChunks += dev->nChunksPerBlock;
-+                              dev->nFreeChunks += dev->param.nChunksPerBlock;
-                       } else {
--                              dev->markNANDBlockBad(dev, i);
-+                              dev->param.markNANDBlockBad(dev, i);
-                               bi->blockState = YAFFS_BLOCK_STATE_DEAD;
-                       }
-               }
-@@ -60,13 +59,13 @@ static int yaffs_CheckpointErase(yaffs_D
- }
--static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
-+static void yaffs2_CheckpointFindNextErasedBlock(yaffs_Device *dev)
- {
-       int  i;
--      int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
-+      int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks;
-       T(YAFFS_TRACE_CHECKPOINT,
-               (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
--              dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
-+              dev->nErasedBlocks, dev->param.nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
-       if (dev->checkpointNextBlock >= 0 &&
-                       dev->checkpointNextBlock <= dev->internalEndBlock &&
-@@ -88,7 +87,7 @@ static void yaffs_CheckpointFindNextEras
-       dev->checkpointCurrentBlock = -1;
- }
--static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
-+static void yaffs2_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
- {
-       int  i;
-       yaffs_ExtendedTags tags;
-@@ -98,10 +97,10 @@ static void yaffs_CheckpointFindNextChec
-       if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
-               for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
--                      int chunk = i * dev->nChunksPerBlock;
-+                      int chunk = i * dev->param.nChunksPerBlock;
-                       int realignedChunk = chunk - dev->chunkOffset;
--                      dev->readChunkWithTagsFromNAND(dev, realignedChunk,
-+                      dev->param.readChunkWithTagsFromNAND(dev, realignedChunk,
-                                       NULL, &tags);
-                       T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
-                               i, tags.objectId, tags.sequenceNumber, tags.eccResult));
-@@ -124,29 +123,29 @@ static void yaffs_CheckpointFindNextChec
- }
--int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
-+int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting)
- {
-+
-+      dev->checkpointOpenForWrite = forWriting;
-+
-       /* Got the functions we need? */
--      if (!dev->writeChunkWithTagsToNAND ||
--                      !dev->readChunkWithTagsFromNAND ||
--                      !dev->eraseBlockInNAND ||
--                      !dev->markNANDBlockBad)
-+      if (!dev->param.writeChunkWithTagsToNAND ||
-+              !dev->param.readChunkWithTagsFromNAND ||
-+              !dev->param.eraseBlockInNAND ||
-+              !dev->param.markNANDBlockBad)
-               return 0;
--      if (forWriting && !yaffs_CheckpointSpaceOk(dev))
-+      if (forWriting && !yaffs2_CheckpointSpaceOk(dev))
-               return 0;
-       if (!dev->checkpointBuffer)
--              dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
-+              dev->checkpointBuffer = YMALLOC_DMA(dev->param.totalBytesPerChunk);
-       if (!dev->checkpointBuffer)
-               return 0;
-       dev->checkpointPageSequence = 0;
--
--      dev->checkpointOpenForWrite = forWriting;
--
-       dev->checkpointByteCount = 0;
-       dev->checkpointSum = 0;
-       dev->checkpointXor = 0;
-@@ -158,7 +157,7 @@ int yaffs_CheckpointOpen(yaffs_Device *d
-       if (forWriting) {
-               memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
-               dev->checkpointByteOffset = 0;
--              return yaffs_CheckpointErase(dev);
-+              return yaffs2_CheckpointErase(dev);
-       } else {
-               int i;
-               /* Set to a value that will kick off a read */
-@@ -168,6 +167,9 @@ int yaffs_CheckpointOpen(yaffs_Device *d
-               dev->blocksInCheckpoint = 0;
-               dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
-               dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
-+              if(!dev->checkpointBlockList)
-+                      return 0;
-+
-               for (i = 0; i < dev->checkpointMaxBlocks; i++)
-                       dev->checkpointBlockList[i] = -1;
-       }
-@@ -175,7 +177,7 @@ int yaffs_CheckpointOpen(yaffs_Device *d
-       return 1;
- }
--int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
-+int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
- {
-       __u32 compositeSum;
-       compositeSum =  (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
-@@ -183,7 +185,7 @@ int yaffs_GetCheckpointSum(yaffs_Device
-       return 1;
- }
--static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
-+static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev)
- {
-       int chunk;
-       int realignedChunk;
-@@ -191,7 +193,7 @@ static int yaffs_CheckpointFlushBuffer(y
-       yaffs_ExtendedTags tags;
-       if (dev->checkpointCurrentBlock < 0) {
--              yaffs_CheckpointFindNextErasedBlock(dev);
-+              yaffs2_CheckpointFindNextErasedBlock(dev);
-               dev->checkpointCurrentChunk = 0;
-       }
-@@ -211,7 +213,7 @@ static int yaffs_CheckpointFlushBuffer(y
-               dev->blocksInCheckpoint++;
-       }
--      chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
-+      chunk = dev->checkpointCurrentBlock * dev->param.nChunksPerBlock + dev->checkpointCurrentChunk;
-       T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
-@@ -219,12 +221,14 @@ static int yaffs_CheckpointFlushBuffer(y
-       realignedChunk = chunk - dev->chunkOffset;
--      dev->writeChunkWithTagsToNAND(dev, realignedChunk,
-+      dev->nPageWrites++;
-+
-+      dev->param.writeChunkWithTagsToNAND(dev, realignedChunk,
-                       dev->checkpointBuffer, &tags);
-       dev->checkpointByteOffset = 0;
-       dev->checkpointPageSequence++;
-       dev->checkpointCurrentChunk++;
--      if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {
-+      if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock) {
-               dev->checkpointCurrentChunk = 0;
-               dev->checkpointCurrentBlock = -1;
-       }
-@@ -234,7 +238,7 @@ static int yaffs_CheckpointFlushBuffer(y
- }
--int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
-+int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
- {
-       int i = 0;
-       int ok = 1;
-@@ -263,13 +267,13 @@ int yaffs_CheckpointWrite(yaffs_Device *
-               if (dev->checkpointByteOffset < 0 ||
-                  dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
--                      ok = yaffs_CheckpointFlushBuffer(dev);
-+                      ok = yaffs2_CheckpointFlushBuffer(dev);
-       }
-       return i;
- }
--int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
-+int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
- {
-       int i = 0;
-       int ok = 1;
-@@ -294,7 +298,7 @@ int yaffs_CheckpointRead(yaffs_Device *d
-                       dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
-                       if (dev->checkpointCurrentBlock < 0) {
--                              yaffs_CheckpointFindNextCheckpointBlock(dev);
-+                              yaffs2_CheckpointFindNextCheckpointBlock(dev);
-                               dev->checkpointCurrentChunk = 0;
-                       }
-@@ -302,14 +306,16 @@ int yaffs_CheckpointRead(yaffs_Device *d
-                               ok = 0;
-                       else {
-                               chunk = dev->checkpointCurrentBlock *
--                                      dev->nChunksPerBlock +
-+                                      dev->param.nChunksPerBlock +
-                                       dev->checkpointCurrentChunk;
-                               realignedChunk = chunk - dev->chunkOffset;
-+                              
-+                              dev->nPageReads++;
-                               /* read in the next chunk */
-                               /* printf("read checkpoint page %d\n",dev->checkpointPage); */
--                              dev->readChunkWithTagsFromNAND(dev,
-+                              dev->param.readChunkWithTagsFromNAND(dev,
-                                               realignedChunk,
-                                               dev->checkpointBuffer,
-                                               &tags);
-@@ -323,7 +329,7 @@ int yaffs_CheckpointRead(yaffs_Device *d
-                               dev->checkpointPageSequence++;
-                               dev->checkpointCurrentChunk++;
--                              if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
-+                              if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock)
-                                       dev->checkpointCurrentBlock = -1;
-                       }
-               }
-@@ -342,17 +348,20 @@ int yaffs_CheckpointRead(yaffs_Device *d
-       return  i;
- }
--int yaffs_CheckpointClose(yaffs_Device *dev)
-+int yaffs2_CheckpointClose(yaffs_Device *dev)
- {
-       if (dev->checkpointOpenForWrite) {
-               if (dev->checkpointByteOffset != 0)
--                      yaffs_CheckpointFlushBuffer(dev);
--      } else {
-+                      yaffs2_CheckpointFlushBuffer(dev);
-+      } else if(dev->checkpointBlockList){
-               int i;
-               for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
--                      yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
--                      if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
-+                      int blk = dev->checkpointBlockList[i];
-+                      yaffs_BlockInfo *bi = NULL;
-+                      if( dev->internalStartBlock <= blk && blk <= dev->internalEndBlock)
-+                              bi = yaffs_GetBlockInfo(dev, blk);
-+                      if (bi && bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
-                               bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
-                       else {
-                               /* Todo this looks odd... */
-@@ -362,7 +371,7 @@ int yaffs_CheckpointClose(yaffs_Device *
-               dev->checkpointBlockList = NULL;
-       }
--      dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
-+      dev->nFreeChunks -= dev->blocksInCheckpoint * dev->param.nChunksPerBlock;
-       dev->nErasedBlocks -= dev->blocksInCheckpoint;
-@@ -378,16 +387,14 @@ int yaffs_CheckpointClose(yaffs_Device *
-               return 0;
- }
--int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
-+int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev)
- {
--      /* Erase the first checksum block */
--
--      T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));
-+      /* Erase the checkpoint data */
--      if (!yaffs_CheckpointSpaceOk(dev))
--              return 0;
-+      T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
-+              dev->blocksInCheckpoint));
--      return yaffs_CheckpointErase(dev);
-+      return yaffs2_CheckpointErase(dev);
- }
---- a/fs/yaffs2/yaffs_checkptrw.h
-+++ b/fs/yaffs2/yaffs_checkptrw.h
-@@ -1,7 +1,7 @@
- /*
-  * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
-  *
-- * Copyright (C) 2002-2007 Aleph One Ltd.
-+ * Copyright (C) 2002-2010 Aleph One Ltd.
-  *   for Toby Churchill Ltd and Brightstar Engineering
-  *
-  * Created by Charles Manning <charles@aleph1.co.uk>
-@@ -18,18 +18,17 @@
- #include "yaffs_guts.h"
--int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
-+int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting);
--int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
-+int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
--int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
-+int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
--int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
-+int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
--int yaffs_CheckpointClose(yaffs_Device *dev);
-+int yaffs2_CheckpointClose(yaffs_Device *dev);
--int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
-+int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev);
- #endif
--
---- a/fs/yaffs2/yaffs_ecc.c
-+++ b/fs/yaffs2/yaffs_ecc.c
-@@ -1,7 +1,7 @@
- /*
-  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
-  *
-- * Copyright (C) 2002-2007 Aleph One Ltd.
-+ * Copyright (C) 2002-2010 Aleph One Ltd.
-  *   for Toby Churchill Ltd and Brightstar Engineering
-  *
-  * Created by Charles Manning <charles@aleph1.co.uk>
-@@ -28,9 +28,6 @@
-  * this bytes influence on the line parity.
-  */
--const char *yaffs_ecc_c_version =
--      "$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $";
--
- #include "yportenv.h"
- #include "yaffs_ecc.h"
---- a/fs/yaffs2/yaffs_ecc.h
-+++ b/fs/yaffs2/yaffs_ecc.h
-@@ -1,7 +1,7 @@
- /*
-  * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
-  *
-- * Copyright (C) 2002-2007 Aleph One Ltd.
-+ * Copyright (C) 2002-2010 Aleph One Ltd.
-  *   for Toby Churchill Ltd and Brightstar Engineering
-  *
-  * Created by Charles Manning <charles@aleph1.co.uk>
---- a/fs/yaffs2/yaffs_fs.c
-+++ /dev/null
-@@ -1,2529 +0,0 @@
--/*
-- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
-- *
-- * Copyright (C) 2002-2009 Aleph One Ltd.
-- *   for Toby Churchill Ltd and Brightstar Engineering
-- *
-- * Created by Charles Manning <charles@aleph1.co.uk>
-- * Acknowledgements:
-- * Luc van OostenRyck for numerous patches.
-- * Nick Bane for numerous patches.
-- * Nick Bane for 2.5/2.6 integration.
-- * Andras Toth for mknod rdev issue.
-- * Michael Fischer for finding the problem with inode inconsistency.
-- * Some code bodily lifted from JFFS
-- *
-- * 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.
-- */
--
--/*
-- *
-- * This is the file system front-end to YAFFS that hooks it up to
-- * the VFS.
-- *
-- * Special notes:
-- * >> 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.
-- */
--
--const char *yaffs_fs_c_version =
--    "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $";
--extern const char *yaffs_guts_c_version;
--
--#include <linux/version.h>
--#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
--#include <linux/config.h>
--#endif
--#include <linux/kernel.h>
--#include <linux/module.h>
--#include <linux/slab.h>
--#include <linux/init.h>
--#include <linux/fs.h>
--#include <linux/proc_fs.h>
--#include <linux/smp_lock.h>
--#include <linux/pagemap.h>
--#include <linux/mtd/mtd.h>
--#include <linux/interrupt.h>
--#include <linux/string.h>
--#include <linux/ctype.h>
--
--#include "asm/div64.h"
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--
--#include <linux/statfs.h>     /* Added NCB 15-8-2003 */
--#include <linux/statfs.h>
--#define UnlockPage(p) unlock_page(p)
--#define Page_Uptodate(page)   test_bit(PG_uptodate, &(page)->flags)
--
--/* FIXME: use sb->s_id instead ? */
--#define yaffs_devname(sb, buf)        bdevname(sb->s_bdev, buf)
--
--#else
--
--#include <linux/locks.h>
--#define       BDEVNAME_SIZE           0
--#define       yaffs_devname(sb, buf)  kdevname(sb->s_dev)
--
--#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
--/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
--#define __user
--#endif
--
--#endif
--
--#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
--#define YPROC_ROOT  (&proc_root)
--#else
--#define YPROC_ROOT  NULL
--#endif
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--#define WRITE_SIZE_STR "writesize"
--#define WRITE_SIZE(mtd) ((mtd)->writesize)
--#else
--#define WRITE_SIZE_STR "oobblock"
--#define WRITE_SIZE(mtd) ((mtd)->oobblock)
--#endif
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
--#define YAFFS_USE_WRITE_BEGIN_END 1
--#else
--#define YAFFS_USE_WRITE_BEGIN_END 0
--#endif
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
--static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
--{
--      uint64_t result = partition_size;
--      do_div(result, block_size);
--      return (uint32_t)result;
--}
--#else
--#define YCALCBLOCKS(s, b) ((s)/(b))
--#endif
--
--#include <linux/uaccess.h>
--
--#include "yportenv.h"
--#include "yaffs_guts.h"
--
--#include <linux/mtd/mtd.h>
--#include "yaffs_mtdif.h"
--#include "yaffs_mtdif1.h"
--#include "yaffs_mtdif2.h"
--
--unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
--unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
--unsigned int yaffs_auto_checkpoint = 1;
--
--/* Module Parameters */
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--module_param(yaffs_traceMask, uint, 0644);
--module_param(yaffs_wr_attempts, uint, 0644);
--module_param(yaffs_auto_checkpoint, uint, 0644);
--#else
--MODULE_PARM(yaffs_traceMask, "i");
--MODULE_PARM(yaffs_wr_attempts, "i");
--MODULE_PARM(yaffs_auto_checkpoint, "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))
--#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
--#else
--#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
--#endif
--
--#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
--#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--#define yaffs_SuperToDevice(sb)       ((yaffs_Device *)sb->s_fs_info)
--#else
--#define yaffs_SuperToDevice(sb)       ((yaffs_Device *)sb->u.generic_sbp)
--#endif
--
--static void yaffs_put_super(struct super_block *sb);
--
--static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
--                              loff_t *pos);
--static ssize_t yaffs_hold_space(struct file *f);
--static void yaffs_release_space(struct file *f);
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--static int yaffs_file_flush(struct file *file, fl_owner_t id);
--#else
--static int yaffs_file_flush(struct file *file);
--#endif
--
--static int yaffs_sync_object(struct file *file, struct dentry *dentry,
--                              int datasync);
--
--static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
--                      struct nameidata *n);
--static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
--                                      struct nameidata *n);
--#else
--static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
--static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
--#endif
--static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
--                      struct dentry *dentry);
--static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
--static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
--                      const char *symname);
--static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
--                      dev_t dev);
--#else
--static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
--                      int dev);
--#endif
--static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
--                      struct inode *new_dir, struct dentry *new_dentry);
--static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--static int yaffs_sync_fs(struct super_block *sb, int wait);
--static void yaffs_write_super(struct super_block *sb);
--#else
--static int yaffs_sync_fs(struct super_block *sb);
--static int yaffs_write_super(struct super_block *sb);
--#endif
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
--#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
--#else
--static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
--#endif
--
--#ifdef YAFFS_HAS_PUT_INODE
--static void yaffs_put_inode(struct inode *inode);
--#endif
--
--static void yaffs_delete_inode(struct inode *);
--static void yaffs_clear_inode(struct inode *);
--
--static int yaffs_readpage(struct file *file, struct page *page);
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
--#else
--static int yaffs_writepage(struct page *page);
--#endif
--
--
--#if (YAFFS_USE_WRITE_BEGIN_END != 0)
--static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
--                              loff_t pos, unsigned len, unsigned flags,
--                              struct page **pagep, void **fsdata);
--static int yaffs_write_end(struct file *filp, struct address_space *mapping,
--                              loff_t pos, unsigned len, unsigned copied,
--                              struct page *pg, void *fsdadata);
--#else
--static int yaffs_prepare_write(struct file *f, struct page *pg,
--                              unsigned offset, unsigned to);
--static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
--                              unsigned to);
--
--#endif
--
--static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
--                              int buflen);
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
--static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
--#else
--static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
--#endif
--
--static struct address_space_operations yaffs_file_address_operations = {
--      .readpage = yaffs_readpage,
--      .writepage = yaffs_writepage,
--#if (YAFFS_USE_WRITE_BEGIN_END > 0)
--      .write_begin = yaffs_write_begin,
--      .write_end = yaffs_write_end,
--#else
--      .prepare_write = yaffs_prepare_write,
--      .commit_write = yaffs_commit_write,
--#endif
--};
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
--static const struct file_operations yaffs_file_operations = {
--      .read = do_sync_read,
--      .write = do_sync_write,
--      .aio_read = generic_file_aio_read,
--      .aio_write = generic_file_aio_write,
--      .mmap = generic_file_mmap,
--      .flush = yaffs_file_flush,
--      .fsync = yaffs_sync_object,
--      .splice_read = generic_file_splice_read,
--      .splice_write = generic_file_splice_write,
--      .llseek = generic_file_llseek,
--};
--
--#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
--
--static const struct file_operations yaffs_file_operations = {
--      .read = do_sync_read,
--      .write = do_sync_write,
--      .aio_read = generic_file_aio_read,
--      .aio_write = generic_file_aio_write,
--      .mmap = generic_file_mmap,
--      .flush = yaffs_file_flush,
--      .fsync = yaffs_sync_object,
--      .sendfile = generic_file_sendfile,
--};
--
--#else
--
--static const struct file_operations yaffs_file_operations = {
--      .read = generic_file_read,
--      .write = generic_file_write,
--      .mmap = generic_file_mmap,
--      .flush = yaffs_file_flush,
--      .fsync = yaffs_sync_object,
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--      .sendfile = generic_file_sendfile,
--#endif
--};
--#endif
--
--static const struct inode_operations yaffs_file_inode_operations = {
--      .setattr = yaffs_setattr,
--};
--
--static const struct inode_operations yaffs_symlink_inode_operations = {
--      .readlink = yaffs_readlink,
--      .follow_link = yaffs_follow_link,
--      .setattr = yaffs_setattr,
--};
--
--static const struct inode_operations yaffs_dir_inode_operations = {
--      .create = yaffs_create,
--      .lookup = yaffs_lookup,
--      .link = yaffs_link,
--      .unlink = yaffs_unlink,
--      .symlink = yaffs_symlink,
--      .mkdir = yaffs_mkdir,
--      .rmdir = yaffs_unlink,
--      .mknod = yaffs_mknod,
--      .rename = yaffs_rename,
--      .setattr = yaffs_setattr,
--};
--
--static const struct file_operations yaffs_dir_operations = {
--      .read = generic_read_dir,
--      .readdir = yaffs_readdir,
--      .fsync = yaffs_sync_object,
--};
--
--static const struct super_operations yaffs_super_ops = {
--      .statfs = yaffs_statfs,
--
--#ifndef YAFFS_USE_OWN_IGET
--      .read_inode = yaffs_read_inode,
--#endif
--#ifdef YAFFS_HAS_PUT_INODE
--      .put_inode = yaffs_put_inode,
--#endif
--      .put_super = yaffs_put_super,
--      .delete_inode = yaffs_delete_inode,
--      .clear_inode = yaffs_clear_inode,
--      .sync_fs = yaffs_sync_fs,
--      .write_super = yaffs_write_super,
--};
--
--static void yaffs_GrossLock(yaffs_Device *dev)
--{
--      T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current));
--      down(&dev->grossLock);
--      T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current));
--}
--
--static void yaffs_GrossUnlock(yaffs_Device *dev)
--{
--      T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current));
--      up(&dev->grossLock);
--}
--
--static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
--                      int buflen)
--{
--      unsigned char *alias;
--      int ret;
--
--      yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
--
--      yaffs_GrossLock(dev);
--
--      alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
--
--      yaffs_GrossUnlock(dev);
--
--      if (!alias)
--              return -ENOMEM;
--
--      ret = vfs_readlink(dentry, buffer, buflen, alias);
--      kfree(alias);
--      return ret;
--}
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
--static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
--#else
--static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
--#endif
--{
--      unsigned char *alias;
--      int ret;
--      yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
--
--      yaffs_GrossLock(dev);
--
--      alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
--
--      yaffs_GrossUnlock(dev);
--
--      if (!alias) {
--              ret = -ENOMEM;
--              goto out;
--      }
--
--      ret = vfs_follow_link(nd, alias);
--      kfree(alias);
--out:
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
--      return ERR_PTR(ret);
--#else
--      return ret;
--#endif
--}
--
--struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
--                              yaffs_Object *obj);
--
--/*
-- * Lookup is used to find objects in the fs
-- */
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--
--static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
--                              struct nameidata *n)
--#else
--static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
--#endif
--{
--      yaffs_Object *obj;
--      struct inode *inode = NULL;     /* NCB 2.5/2.6 needs NULL here */
--
--      yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
--
--      yaffs_GrossLock(dev);
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_lookup for %d:%s\n",
--              yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
--
--      obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
--                                      dentry->d_name.name);
--
--      obj = yaffs_GetEquivalentObject(obj);   /* in case it was a hardlink */
--
--      /* Can't hold gross lock when calling yaffs_get_inode() */
--      yaffs_GrossUnlock(dev);
--
--      if (obj) {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_lookup found %d\n", obj->objectId));
--
--              inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
--
--              if (inode) {
--                      T(YAFFS_TRACE_OS,
--                              ("yaffs_loookup dentry \n"));
--/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
-- * d_add even if NULL inode */
--#if 0
--                      /*dget(dentry); // try to solve directory bug */
--                      d_add(dentry, inode);
--
--                      /* return dentry; */
--                      return NULL;
--#endif
--              }
--
--      } else {
--              T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n"));
--
--      }
--
--/* added NCB for 2.5/6 compatability - forces add even if inode is
-- * NULL which creates dentry hash */
--      d_add(dentry, inode);
--
--      return NULL;
--}
--
--
--#ifdef YAFFS_HAS_PUT_INODE
--
--/* For now put inode is just for debugging
-- * Put inode is called when the inode **structure** is put.
-- */
--static void yaffs_put_inode(struct inode *inode)
--{
--      T(YAFFS_TRACE_OS,
--              ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
--              atomic_read(&inode->i_count)));
--
--}
--#endif
--
--/* clear is called to tell the fs to release any per-inode data it holds */
--static void yaffs_clear_inode(struct inode *inode)
--{
--      yaffs_Object *obj;
--      yaffs_Device *dev;
--
--      obj = yaffs_InodeToObject(inode);
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
--              atomic_read(&inode->i_count),
--              obj ? "object exists" : "null object"));
--
--      if (obj) {
--              dev = obj->myDev;
--              yaffs_GrossLock(dev);
--
--              /* Clear the association between the inode and
--               * the yaffs_Object.
--               */
--              obj->myInode = NULL;
--              yaffs_InodeToObjectLV(inode) = NULL;
--
--              /* If the object freeing was deferred, then the real
--               * free happens now.
--               * This should fix the inode inconsistency problem.
--               */
--
--              yaffs_HandleDeferedFree(obj);
--
--              yaffs_GrossUnlock(dev);
--      }
--
--}
--
--/* delete is called when the link count is zero and the inode
-- * is put (ie. nobody wants to know about it anymore, time to
-- * delete the file).
-- * NB Must call clear_inode()
-- */
--static void yaffs_delete_inode(struct inode *inode)
--{
--      yaffs_Object *obj = yaffs_InodeToObject(inode);
--      yaffs_Device *dev;
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
--              atomic_read(&inode->i_count),
--              obj ? "object exists" : "null object"));
--
--      if (obj) {
--              dev = obj->myDev;
--              yaffs_GrossLock(dev);
--              yaffs_DeleteObject(obj);
--              yaffs_GrossUnlock(dev);
--      }
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
--      truncate_inode_pages(&inode->i_data, 0);
--#endif
--      clear_inode(inode);
--}
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--static int yaffs_file_flush(struct file *file, fl_owner_t id)
--#else
--static int yaffs_file_flush(struct file *file)
--#endif
--{
--      yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
--
--      yaffs_Device *dev = obj->myDev;
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_file_flush object %d (%s)\n", obj->objectId,
--              obj->dirty ? "dirty" : "clean"));
--
--      yaffs_GrossLock(dev);
--
--      yaffs_FlushFile(obj, 1);
--
--      yaffs_GrossUnlock(dev);
--
--      return 0;
--}
--
--static int yaffs_readpage_nolock(struct file *f, struct page *pg)
--{
--      /* Lifted from jffs2 */
--
--      yaffs_Object *obj;
--      unsigned char *pg_buf;
--      int ret;
--
--      yaffs_Device *dev;
--
--      T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n",
--                      (unsigned)(pg->index << PAGE_CACHE_SHIFT),
--                      (unsigned)PAGE_CACHE_SIZE));
--
--      obj = yaffs_DentryToObject(f->f_dentry);
--
--      dev = obj->myDev;
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--      BUG_ON(!PageLocked(pg));
--#else
--      if (!PageLocked(pg))
--              PAGE_BUG(pg);
--#endif
--
--      pg_buf = kmap(pg);
--      /* FIXME: Can kmap fail? */
--
--      yaffs_GrossLock(dev);
--
--      ret = yaffs_ReadDataFromFile(obj, pg_buf,
--                              pg->index << PAGE_CACHE_SHIFT,
--                              PAGE_CACHE_SIZE);
--
--      yaffs_GrossUnlock(dev);
--
--      if (ret >= 0)
--              ret = 0;
--
--      if (ret) {
--              ClearPageUptodate(pg);
--              SetPageError(pg);
--      } else {
--              SetPageUptodate(pg);
--              ClearPageError(pg);
--      }
--
--      flush_dcache_page(pg);
--      kunmap(pg);
--
--      T(YAFFS_TRACE_OS, ("yaffs_readpage done\n"));
--      return ret;
--}
--
--static int yaffs_readpage_unlock(struct file *f, struct page *pg)
--{
--      int ret = yaffs_readpage_nolock(f, pg);
--      UnlockPage(pg);
--      return ret;
--}
--
--static int yaffs_readpage(struct file *f, struct page *pg)
--{
--      return yaffs_readpage_unlock(f, pg);
--}
--
--/* writepage inspired by/stolen from smbfs */
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
--#else
--static int yaffs_writepage(struct page *page)
--#endif
--{
--      struct address_space *mapping = page->mapping;
--      loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
--      struct inode *inode;
--      unsigned long end_index;
--      char *buffer;
--      yaffs_Object *obj;
--      int nWritten = 0;
--      unsigned nBytes;
--
--      if (!mapping)
--              BUG();
--      inode = mapping->host;
--      if (!inode)
--              BUG();
--
--      if (offset > inode->i_size) {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_writepage at %08x, inode size = %08x!!!\n",
--                      (unsigned)(page->index << PAGE_CACHE_SHIFT),
--                      (unsigned)inode->i_size));
--              T(YAFFS_TRACE_OS,
--                      ("                -> don't care!!\n"));
--              unlock_page(page);
--              return 0;
--      }
--
--      end_index = inode->i_size >> PAGE_CACHE_SHIFT;
--
--      /* easy case */
--      if (page->index < end_index)
--              nBytes = PAGE_CACHE_SIZE;
--      else
--              nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
--
--      get_page(page);
--
--      buffer = kmap(page);
--
--      obj = yaffs_InodeToObject(inode);
--      yaffs_GrossLock(obj->myDev);
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_writepage at %08x, size %08x\n",
--              (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
--      T(YAFFS_TRACE_OS,
--              ("writepag0: obj = %05x, ino = %05x\n",
--              (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
--
--      nWritten = yaffs_WriteDataToFile(obj, buffer,
--                      page->index << PAGE_CACHE_SHIFT, nBytes, 0);
--
--      T(YAFFS_TRACE_OS,
--              ("writepag1: obj = %05x, ino = %05x\n",
--              (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
--
--      yaffs_GrossUnlock(obj->myDev);
--
--      kunmap(page);
--      SetPageUptodate(page);
--      UnlockPage(page);
--      put_page(page);
--
--      return (nWritten == nBytes) ? 0 : -ENOSPC;
--}
--
--
--#if (YAFFS_USE_WRITE_BEGIN_END > 0)
--static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
--                              loff_t pos, unsigned len, unsigned flags,
--                              struct page **pagep, void **fsdata)
--{
--      struct page *pg = NULL;
--      pgoff_t index = pos >> PAGE_CACHE_SHIFT;
--      uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);
--      uint32_t to = offset + len;
--
--      int ret = 0;
--      int space_held = 0;
--
--      T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n"));
--      /* Get a page */
--#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)
--      pg = grab_cache_page_write_begin(mapping, index, flags);
--#else
--      pg = __grab_cache_page(mapping, index);
--#endif
--
--      *pagep = pg;
--      if (!pg) {
--              ret =  -ENOMEM;
--              goto out;
--      }
--      /* Get fs space */
--      space_held = yaffs_hold_space(filp);
--
--      if (!space_held) {
--              ret = -ENOSPC;
--              goto out;
--      }
--
--      /* Update page if required */
--
--      if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
--              ret = yaffs_readpage_nolock(filp, pg);
--
--      if (ret)
--              goto out;
--
--      /* Happy path return */
--      T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n"));
--
--      return 0;
--
--out:
--      T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));
--      if (space_held)
--              yaffs_release_space(filp);
--      if (pg) {
--              unlock_page(pg);
--              page_cache_release(pg);
--      }
--      return ret;
--}
--
--#else
--
--static int yaffs_prepare_write(struct file *f, struct page *pg,
--                              unsigned offset, unsigned to)
--{
--      T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n"));
--
--      if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
--              return yaffs_readpage_nolock(f, pg);
--      return 0;
--}
--#endif
--
--#if (YAFFS_USE_WRITE_BEGIN_END > 0)
--static int yaffs_write_end(struct file *filp, struct address_space *mapping,
--                              loff_t pos, unsigned len, unsigned copied,
--                              struct page *pg, void *fsdadata)
--{
--      int ret = 0;
--      void *addr, *kva;
--      uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
--
--      kva = kmap(pg);
--      addr = kva + offset_into_page;
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_write_end addr %x pos %x nBytes %d\n",
--              (unsigned) addr,
--              (int)pos, copied));
--
--      ret = yaffs_file_write(filp, addr, copied, &pos);
--
--      if (ret != copied) {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_write_end not same size ret %d  copied %d\n",
--                      ret, copied));
--              SetPageError(pg);
--              ClearPageUptodate(pg);
--      } else {
--              SetPageUptodate(pg);
--      }
--
--      kunmap(pg);
--
--      yaffs_release_space(filp);
--      unlock_page(pg);
--      page_cache_release(pg);
--      return ret;
--}
--#else
--
--static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
--                              unsigned to)
--{
--      void *addr, *kva;
--
--      loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
--      int nBytes = to - offset;
--      int nWritten;
--
--      unsigned spos = pos;
--      unsigned saddr;
--
--      kva = kmap(pg);
--      addr = kva + offset;
--
--      saddr = (unsigned) addr;
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_commit_write addr %x pos %x nBytes %d\n",
--              saddr, spos, nBytes));
--
--      nWritten = yaffs_file_write(f, addr, nBytes, &pos);
--
--      if (nWritten != nBytes) {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_commit_write not same size nWritten %d  nBytes %d\n",
--                      nWritten, nBytes));
--              SetPageError(pg);
--              ClearPageUptodate(pg);
--      } else {
--              SetPageUptodate(pg);
--      }
--
--      kunmap(pg);
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_commit_write returning %d\n",
--              nWritten == nBytes ? 0 : nWritten));
--
--      return nWritten == nBytes ? 0 : nWritten;
--}
--#endif
--
--
--static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
--{
--      if (inode && obj) {
--
--
--              /* Check mode against the variant type and attempt to repair if broken. */
--              __u32 mode = obj->yst_mode;
--              switch (obj->variantType) {
--              case YAFFS_OBJECT_TYPE_FILE:
--                      if (!S_ISREG(mode)) {
--                              obj->yst_mode &= ~S_IFMT;
--                              obj->yst_mode |= S_IFREG;
--                      }
--
--                      break;
--              case YAFFS_OBJECT_TYPE_SYMLINK:
--                      if (!S_ISLNK(mode)) {
--                              obj->yst_mode &= ~S_IFMT;
--                              obj->yst_mode |= S_IFLNK;
--                      }
--
--                      break;
--              case YAFFS_OBJECT_TYPE_DIRECTORY:
--                      if (!S_ISDIR(mode)) {
--                              obj->yst_mode &= ~S_IFMT;
--                              obj->yst_mode |= S_IFDIR;
--                      }
--
--                      break;
--              case YAFFS_OBJECT_TYPE_UNKNOWN:
--              case YAFFS_OBJECT_TYPE_HARDLINK:
--              case YAFFS_OBJECT_TYPE_SPECIAL:
--              default:
--                      /* TODO? */
--                      break;
--              }
--
--              inode->i_flags |= S_NOATIME;
--
--              inode->i_ino = obj->objectId;
--              inode->i_mode = obj->yst_mode;
--              inode->i_uid = obj->yst_uid;
--              inode->i_gid = obj->yst_gid;
--#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
--              inode->i_blksize = inode->i_sb->s_blocksize;
--#endif
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--
--              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->yst_mtime;
--              inode->i_mtime.tv_nsec = 0;
--              inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
--              inode->i_ctime.tv_nsec = 0;
--#else
--              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;
--
--              inode->i_nlink = yaffs_GetObjectLinkCount(obj);
--
--              T(YAFFS_TRACE_OS,
--                      ("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->yst_mode & S_IFMT) {
--              default:        /* fifo, device or socket */
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--                      init_special_inode(inode, obj->yst_mode,
--                                      old_decode_dev(obj->yst_rdev));
--#else
--                      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;
--                      inode->i_fop = &yaffs_file_operations;
--                      inode->i_mapping->a_ops =
--                              &yaffs_file_address_operations;
--                      break;
--              case S_IFDIR:   /* directory */
--                      inode->i_op = &yaffs_dir_inode_operations;
--                      inode->i_fop = &yaffs_dir_operations;
--                      break;
--              case S_IFLNK:   /* symlink */
--                      inode->i_op = &yaffs_symlink_inode_operations;
--                      break;
--              }
--
--              yaffs_InodeToObjectLV(inode) = obj;
--
--              obj->myInode = inode;
--
--      } else {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_FileInode invalid parameters\n"));
--      }
--
--}
--
--struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
--                              yaffs_Object *obj)
--{
--      struct inode *inode;
--
--      if (!sb) {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_get_inode for NULL super_block!!\n"));
--              return NULL;
--
--      }
--
--      if (!obj) {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_get_inode for NULL object!!\n"));
--              return NULL;
--
--      }
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_get_inode for object %d\n", 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 */
--      /* NB You can't be holding grossLock or deadlock will happen! */
--
--      return inode;
--}
--
--static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
--                              loff_t *pos)
--{
--      yaffs_Object *obj;
--      int nWritten, ipos;
--      struct inode *inode;
--      yaffs_Device *dev;
--
--      obj = yaffs_DentryToObject(f->f_dentry);
--
--      dev = obj->myDev;
--
--      yaffs_GrossLock(dev);
--
--      inode = f->f_dentry->d_inode;
--
--      if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
--              ipos = inode->i_size;
--      else
--              ipos = *pos;
--
--      if (!obj)
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_file_write: hey obj is null!\n"));
--      else
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_file_write about to write writing %zu bytes"
--                      "to object %d at %d\n",
--                      n, obj->objectId, ipos));
--
--      nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_file_write writing %zu bytes, %d written at %d\n",
--              n, nWritten, ipos));
--
--      if (nWritten > 0) {
--              ipos += nWritten;
--              *pos = ipos;
--              if (ipos > inode->i_size) {
--                      inode->i_size = ipos;
--                      inode->i_blocks = (ipos + 511) >> 9;
--
--                      T(YAFFS_TRACE_OS,
--                              ("yaffs_file_write size updated to %d bytes, "
--                              "%d blocks\n",
--                              ipos, (int)(inode->i_blocks)));
--              }
--
--      }
--      yaffs_GrossUnlock(dev);
--      return nWritten == 0 ? -ENOSPC : nWritten;
--}
--
--/* Space holding and freeing is done to ensure we have space available for write_begin/end */
--/* For now we just assume few parallel writes and check against a small number. */
--/* Todo: need to do this with a counter to handle parallel reads better */
--
--static ssize_t yaffs_hold_space(struct file *f)
--{
--      yaffs_Object *obj;
--      yaffs_Device *dev;
--
--      int nFreeChunks;
--
--
--      obj = yaffs_DentryToObject(f->f_dentry);
--
--      dev = obj->myDev;
--
--      yaffs_GrossLock(dev);
--
--      nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
--
--      yaffs_GrossUnlock(dev);
--
--      return (nFreeChunks > 20) ? 1 : 0;
--}
--
--static void yaffs_release_space(struct file *f)
--{
--      yaffs_Object *obj;
--      yaffs_Device *dev;
--
--
--      obj = yaffs_DentryToObject(f->f_dentry);
--
--      dev = obj->myDev;
--
--      yaffs_GrossLock(dev);
--
--
--      yaffs_GrossUnlock(dev);
--}
--
--static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
--{
--      yaffs_Object *obj;
--      yaffs_Device *dev;
--      struct inode *inode = f->f_dentry->d_inode;
--      unsigned long offset, curoffs;
--      struct ylist_head *i;
--      yaffs_Object *l;
--
--      char name[YAFFS_MAX_NAME_LENGTH + 1];
--
--      obj = yaffs_DentryToObject(f->f_dentry);
--      dev = obj->myDev;
--
--      yaffs_GrossLock(dev);
--
--      offset = f->f_pos;
--
--      T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
--
--      if (offset == 0) {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_readdir: entry . ino %d \n",
--                      (int)inode->i_ino));
--              if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
--                      goto out;
--              offset++;
--              f->f_pos++;
--      }
--      if (offset == 1) {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_readdir: entry .. ino %d \n",
--                      (int)f->f_dentry->d_parent->d_inode->i_ino));
--              if (filldir(dirent, "..", 2, offset,
--                      f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
--                      goto out;
--              offset++;
--              f->f_pos++;
--      }
--
--      curoffs = 1;
--
--      /* If the directory has changed since the open or last call to
--         readdir, rewind to after the 2 canned entries. */
--
--      if (f->f_version != inode->i_version) {
--              offset = 2;
--              f->f_pos = offset;
--              f->f_version = inode->i_version;
--      }
--
--      ylist_for_each(i, &obj->variant.directoryVariant.children) {
--              curoffs++;
--              if (curoffs >= offset) {
--                      l = ylist_entry(i, yaffs_Object, siblings);
--
--                      yaffs_GetObjectName(l, name,
--                                          YAFFS_MAX_NAME_LENGTH + 1);
--                      T(YAFFS_TRACE_OS,
--                        ("yaffs_readdir: %s inode %d\n", name,
--                         yaffs_GetObjectInode(l)));
--
--                      if (filldir(dirent,
--                                      name,
--                                      strlen(name),
--                                      offset,
--                                      yaffs_GetObjectInode(l),
--                                      yaffs_GetObjectType(l)) < 0)
--                              goto up_and_out;
--
--                      offset++;
--                      f->f_pos++;
--              }
--      }
--
--up_and_out:
--out:
--      yaffs_GrossUnlock(dev);
--
--      return 0;
--}
--
--/*
-- * File creation. Allocate an inode, and we're done..
-- */
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
--#define YCRED(x) x
--#else
--#define YCRED(x) (x->cred)
--#endif
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
--                      dev_t rdev)
--#else
--static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
--                      int rdev)
--#endif
--{
--      struct inode *inode;
--
--      yaffs_Object *obj = NULL;
--      yaffs_Device *dev;
--
--      yaffs_Object *parent = yaffs_InodeToObject(dir);
--
--      int error = -ENOSPC;
--      uid_t uid = YCRED(current)->fsuid;
--      gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
--
--      if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
--              mode |= S_ISGID;
--
--      if (parent) {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_mknod: parent object %d type %d\n",
--                      parent->objectId, parent->variantType));
--      } else {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_mknod: could not get parent object\n"));
--              return -EPERM;
--      }
--
--      T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
--                      "mode %x dev %x\n",
--                      dentry->d_name.name, mode, rdev));
--
--      dev = parent->myDev;
--
--      yaffs_GrossLock(dev);
--
--      switch (mode & S_IFMT) {
--      default:
--              /* Special (socket, fifo, device...) */
--              T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n"));
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--              obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
--                              gid, old_encode_dev(rdev));
--#else
--              obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
--                              gid, rdev);
--#endif
--              break;
--      case S_IFREG:           /* file          */
--              T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n"));
--              obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
--                              gid);
--              break;
--      case S_IFDIR:           /* directory */
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_mknod: making directory\n"));
--              obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
--                                      uid, gid);
--              break;
--      case S_IFLNK:           /* symlink */
--              T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n"));
--              obj = NULL;     /* Do we ever get here? */
--              break;
--      }
--
--      /* Can not call yaffs_get_inode() with gross lock held */
--      yaffs_GrossUnlock(dev);
--
--      if (obj) {
--              inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
--              d_instantiate(dentry, inode);
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_mknod created object %d count = %d\n",
--                      obj->objectId, atomic_read(&inode->i_count)));
--              error = 0;
--      } else {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_mknod failed making object\n"));
--              error = -ENOMEM;
--      }
--
--      return error;
--}
--
--static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
--{
--      int retVal;
--      T(YAFFS_TRACE_OS, ("yaffs_mkdir\n"));
--      retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
--      return retVal;
--}
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
--                      struct nameidata *n)
--#else
--static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
--#endif
--{
--      T(YAFFS_TRACE_OS, ("yaffs_create\n"));
--      return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
--}
--
--static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
--{
--      int retVal;
--
--      yaffs_Device *dev;
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_unlink %d:%s\n", (int)(dir->i_ino),
--              dentry->d_name.name));
--
--      dev = yaffs_InodeToObject(dir)->myDev;
--
--      yaffs_GrossLock(dev);
--
--      retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
--
--      if (retVal == YAFFS_OK) {
--              dentry->d_inode->i_nlink--;
--              dir->i_version++;
--              yaffs_GrossUnlock(dev);
--              mark_inode_dirty(dentry->d_inode);
--              return 0;
--      }
--      yaffs_GrossUnlock(dev);
--      return -ENOTEMPTY;
--}
--
--/*
-- * Create a link...
-- */
--static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
--                      struct dentry *dentry)
--{
--      struct inode *inode = old_dentry->d_inode;
--      yaffs_Object *obj = NULL;
--      yaffs_Object *link = NULL;
--      yaffs_Device *dev;
--
--      T(YAFFS_TRACE_OS, ("yaffs_link\n"));
--
--      obj = yaffs_InodeToObject(inode);
--      dev = obj->myDev;
--
--      yaffs_GrossLock(dev);
--
--      if (!S_ISDIR(inode->i_mode))            /* Don't link directories */
--              link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
--                      obj);
--
--      if (link) {
--              old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
--              d_instantiate(dentry, old_dentry->d_inode);
--              atomic_inc(&old_dentry->d_inode->i_count);
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_link link count %d i_count %d\n",
--                      old_dentry->d_inode->i_nlink,
--                      atomic_read(&old_dentry->d_inode->i_count)));
--      }
--
--      yaffs_GrossUnlock(dev);
--
--      if (link)
--              return 0;
--
--      return -EPERM;
--}
--
--static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
--                              const char *symname)
--{
--      yaffs_Object *obj;
--      yaffs_Device *dev;
--      uid_t uid = YCRED(current)->fsuid;
--      gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
--
--      T(YAFFS_TRACE_OS, ("yaffs_symlink\n"));
--
--      dev = yaffs_InodeToObject(dir)->myDev;
--      yaffs_GrossLock(dev);
--      obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
--                              S_IFLNK | S_IRWXUGO, uid, gid, symname);
--      yaffs_GrossUnlock(dev);
--
--      if (obj) {
--              struct inode *inode;
--
--              inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
--              d_instantiate(dentry, inode);
--              T(YAFFS_TRACE_OS, ("symlink created OK\n"));
--              return 0;
--      } else {
--              T(YAFFS_TRACE_OS, ("symlink not created\n"));
--      }
--
--      return -ENOMEM;
--}
--
--static int yaffs_sync_object(struct file *file, struct dentry *dentry,
--                              int datasync)
--{
--
--      yaffs_Object *obj;
--      yaffs_Device *dev;
--
--      obj = yaffs_DentryToObject(dentry);
--
--      dev = obj->myDev;
--
--      T(YAFFS_TRACE_OS, ("yaffs_sync_object\n"));
--      yaffs_GrossLock(dev);
--      yaffs_FlushFile(obj, 1);
--      yaffs_GrossUnlock(dev);
--      return 0;
--}
--
--/*
-- * The VFS layer already does all the dentry stuff for rename.
-- *
-- * NB: POSIX says you can rename an object over an old object of the same name
-- */
--static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
--                      struct inode *new_dir, struct dentry *new_dentry)
--{
--      yaffs_Device *dev;
--      int retVal = YAFFS_FAIL;
--      yaffs_Object *target;
--
--      T(YAFFS_TRACE_OS, ("yaffs_rename\n"));
--      dev = yaffs_InodeToObject(old_dir)->myDev;
--
--      yaffs_GrossLock(dev);
--
--      /* Check if the target is an existing directory that is not empty. */
--      target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
--                              new_dentry->d_name.name);
--
--
--
--      if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
--              !ylist_empty(&target->variant.directoryVariant.children)) {
--
--              T(YAFFS_TRACE_OS, ("target is non-empty dir\n"));
--
--              retVal = YAFFS_FAIL;
--      } else {
--              /* Now does unlinking internally using shadowing mechanism */
--              T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n"));
--
--              retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
--                              old_dentry->d_name.name,
--                              yaffs_InodeToObject(new_dir),
--                              new_dentry->d_name.name);
--      }
--      yaffs_GrossUnlock(dev);
--
--      if (retVal == YAFFS_OK) {
--              if (target) {
--                      new_dentry->d_inode->i_nlink--;
--                      mark_inode_dirty(new_dentry->d_inode);
--              }
--
--              return 0;
--      } else {
--              return -ENOTEMPTY;
--      }
--}
--
--static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
--{
--      struct inode *inode = dentry->d_inode;
--      int error;
--      yaffs_Device *dev;
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_setattr of object %d\n",
--              yaffs_InodeToObject(inode)->objectId));
--
--      error = inode_change_ok(inode, attr);
--      if (error == 0) {
--              dev = yaffs_InodeToObject(inode)->myDev;
--              yaffs_GrossLock(dev);
--              if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
--                              YAFFS_OK) {
--                      error = 0;
--              } else {
--                      error = -EPERM;
--              }
--              yaffs_GrossUnlock(dev);
--              if (!error)
--                      error = inode_setattr(inode, attr);
--      }
--      return error;
--}
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
--{
--      yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
--      struct super_block *sb = dentry->d_sb;
--#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
--{
--      yaffs_Device *dev = yaffs_SuperToDevice(sb);
--#else
--static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
--{
--      yaffs_Device *dev = yaffs_SuperToDevice(sb);
--#endif
--
--      T(YAFFS_TRACE_OS, ("yaffs_statfs\n"));
--
--      yaffs_GrossLock(dev);
--
--      buf->f_type = YAFFS_MAGIC;
--      buf->f_bsize = sb->s_blocksize;
--      buf->f_namelen = 255;
--
--      if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
--              /* Do this if chunk size is not a power of 2 */
--
--              uint64_t bytesInDev;
--              uint64_t bytesFree;
--
--              bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) *
--                      ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
--
--              do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
--              buf->f_blocks = bytesInDev;
--
--              bytesFree  = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
--                      ((uint64_t)(dev->nDataBytesPerChunk));
--
--              do_div(bytesFree, sb->s_blocksize);
--
--              buf->f_bfree = bytesFree;
--
--      } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
--
--              buf->f_blocks =
--                      (dev->endBlock - dev->startBlock + 1) *
--                      dev->nChunksPerBlock /
--                      (sb->s_blocksize / dev->nDataBytesPerChunk);
--              buf->f_bfree =
--                      yaffs_GetNumberOfFreeChunks(dev) /
--                      (sb->s_blocksize / dev->nDataBytesPerChunk);
--      } else {
--              buf->f_blocks =
--                      (dev->endBlock - dev->startBlock + 1) *
--                      dev->nChunksPerBlock *
--                      (dev->nDataBytesPerChunk / sb->s_blocksize);
--
--              buf->f_bfree =
--                      yaffs_GetNumberOfFreeChunks(dev) *
--                      (dev->nDataBytesPerChunk / sb->s_blocksize);
--      }
--
--      buf->f_files = 0;
--      buf->f_ffree = 0;
--      buf->f_bavail = buf->f_bfree;
--
--      yaffs_GrossUnlock(dev);
--      return 0;
--}
--
--
--static int yaffs_do_sync_fs(struct super_block *sb)
--{
--
--      yaffs_Device *dev = yaffs_SuperToDevice(sb);
--      T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n"));
--
--      if (sb->s_dirt) {
--              yaffs_GrossLock(dev);
--
--              if (dev) {
--                      yaffs_FlushEntireDeviceCache(dev);
--                      yaffs_CheckpointSave(dev);
--              }
--
--              yaffs_GrossUnlock(dev);
--
--              sb->s_dirt = 0;
--      }
--      return 0;
--}
--
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--static void yaffs_write_super(struct super_block *sb)
--#else
--static int yaffs_write_super(struct super_block *sb)
--#endif
--{
--
--      T(YAFFS_TRACE_OS, ("yaffs_write_super\n"));
--      if (yaffs_auto_checkpoint >= 2)
--              yaffs_do_sync_fs(sb);
--#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
--      return 0;
--#endif
--}
--
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--static int yaffs_sync_fs(struct super_block *sb, int wait)
--#else
--static int yaffs_sync_fs(struct super_block *sb)
--#endif
--{
--      T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n"));
--
--      if (yaffs_auto_checkpoint >= 1)
--              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,
--              ("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)
--{
--      /* 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_Object *obj;
--      yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
--
--      T(YAFFS_TRACE_OS,
--              ("yaffs_read_inode for %d\n", (int)inode->i_ino));
--
--      yaffs_GrossLock(dev);
--
--      obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
--
--      yaffs_FillInodeFromObject(inode, obj);
--
--      yaffs_GrossUnlock(dev);
--}
--
--#endif
--
--static YLIST_HEAD(yaffs_dev_list);
--
--#if 0 /* not used */
--static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
--{
--      yaffs_Device    *dev = yaffs_SuperToDevice(sb);
--
--      if (*flags & MS_RDONLY) {
--              struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
--
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_remount_fs: %s: RO\n", dev->name));
--
--              yaffs_GrossLock(dev);
--
--              yaffs_FlushEntireDeviceCache(dev);
--
--              yaffs_CheckpointSave(dev);
--
--              if (mtd->sync)
--                      mtd->sync(mtd);
--
--              yaffs_GrossUnlock(dev);
--      } else {
--              T(YAFFS_TRACE_OS,
--                      ("yaffs_remount_fs: %s: RW\n", dev->name));
--      }
--
--      return 0;
--}
--#endif
--
--static void yaffs_put_super(struct super_block *sb)
--{
--      yaffs_Device *dev = yaffs_SuperToDevice(sb);
--
--      T(YAFFS_TRACE_OS, ("yaffs_put_super\n"));
--
--      yaffs_GrossLock(dev);
--
--      yaffs_FlushEntireDeviceCache(dev);
--
--      yaffs_CheckpointSave(dev);
--
--      if (dev->putSuperFunc)
--              dev->putSuperFunc(sb);
--
--      yaffs_Deinitialise(dev);
--
--      yaffs_GrossUnlock(dev);
--
--      /* we assume this is protected by lock_kernel() in mount/umount */
--      ylist_del(&dev->devList);
--
--      if (dev->spareBuffer) {
--              YFREE(dev->spareBuffer);
--              dev->spareBuffer = NULL;
--      }
--
--      kfree(dev);
--}
--
--
--static void yaffs_MTDPutSuper(struct super_block *sb)
--{
--      struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
--
--      if (mtd->sync)
--              mtd->sync(mtd);
--
--      put_mtd_device(mtd);
--}
--
--
--static void yaffs_MarkSuperBlockDirty(void *vsb)
--{
--      struct super_block *sb = (struct super_block *)vsb;
--
--      T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb));
--      if (sb)
--              sb->s_dirt = 1;
--}
--
--typedef struct {
--      int inband_tags;
--      int skip_checkpoint_read;
--      int skip_checkpoint_write;
--      int no_cache;
--} yaffs_options;
--
--#define MAX_OPT_LEN 20
--static int yaffs_parse_options(yaffs_options *options, const char *options_str)
--{
--      char cur_opt[MAX_OPT_LEN + 1];
--      int p;
--      int error = 0;
--
--      /* Parse through the options which is a comma seperated list */
--
--      while (options_str && *options_str && !error) {
--              memset(cur_opt, 0, MAX_OPT_LEN + 1);
--              p = 0;
--
--              while (*options_str && *options_str != ',') {
--                      if (p < MAX_OPT_LEN) {
--                              cur_opt[p] = *options_str;
--                              p++;
--                      }
--                      options_str++;
--              }
--
--              if (!strcmp(cur_opt, "inband-tags"))
--                      options->inband_tags = 1;
--              else if (!strcmp(cur_opt, "no-cache"))
--                      options->no_cache = 1;
--              else if (!strcmp(cur_opt, "no-checkpoint-read"))
--                      options->skip_checkpoint_read = 1;
--              else if (!strcmp(cur_opt, "no-checkpoint-write"))
--                      options->skip_checkpoint_write = 1;
--              else if (!strcmp(cur_opt, "no-checkpoint")) {
--                      options->skip_checkpoint_read = 1;
--                      options->skip_checkpoint_write = 1;
--              } else {
--                      printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
--                                      cur_opt);
--                      error = 1;
--              }
--      }
--
--      return error;
--}
--
--static struct super_block *yaffs_internal_read_super(int yaffsVersion,
--                                              struct super_block *sb,
--                                              void *data, int silent)
--{
--      int nBlocks;
--      struct inode *inode = NULL;
--      struct dentry *root;
--      yaffs_Device *dev = 0;
--      char devname_buf[BDEVNAME_SIZE + 1];
--      struct mtd_info *mtd;
--      int err;
--      char *data_str = (char *)data;
--
--      yaffs_options options;
--
--      sb->s_magic = YAFFS_MAGIC;
--      sb->s_op = &yaffs_super_ops;
--      sb->s_flags |= MS_NOATIME;
--
--      if (!sb)
--              printk(KERN_INFO "yaffs: sb is NULL\n");
--      else if (!sb->s_dev)
--              printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
--      else if (!yaffs_devname(sb, devname_buf))
--              printk(KERN_INFO "yaffs: devname is NULL\n");
--      else
--              printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
--                     sb->s_dev,
--                     yaffs_devname(sb, devname_buf));
--
--      if (!data_str)
--              data_str = "";
--
--      printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
--
--      memset(&options, 0, sizeof(options));
--
--      if (yaffs_parse_options(&options, data_str)) {
--              /* Option parsing failed */
--              return NULL;
--      }
--
--
--      sb->s_blocksize = PAGE_CACHE_SIZE;
--      sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
--      T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
--      T(YAFFS_TRACE_OS,
--        ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
--
--#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
--      T(YAFFS_TRACE_OS,
--        ("yaffs: Write verification disabled. All guarantees "
--         "null and void\n"));
--#endif
--
--      T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
--                             "\"%s\"\n",
--                             MAJOR(sb->s_dev), MINOR(sb->s_dev),
--                             yaffs_devname(sb, devname_buf)));
--
--      /* Check it's an mtd device..... */
--      if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
--              return NULL;    /* This isn't an mtd device */
--
--      /* Get the device */
--      mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
--      if (!mtd) {
--              T(YAFFS_TRACE_ALWAYS,
--                ("yaffs: MTD device #%u doesn't appear to exist\n",
--                 MINOR(sb->s_dev)));
--              return NULL;
--      }
--      /* Check it's NAND */
--      if (mtd->type != MTD_NANDFLASH) {
--              T(YAFFS_TRACE_ALWAYS,
--                ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
--              return NULL;
--      }
--
--      T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
--      T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
--      T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
--      T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
--      T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
--      T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
--      T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
--      T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
--      T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
--      T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
--      T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));
--#else
--      T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
--#endif
--
--#ifdef CONFIG_YAFFS_AUTO_YAFFS2
--
--      if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
--              T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
--              yaffsVersion = 2;
--      }
--
--      /* Added NCB 26/5/2006 for completeness */
--      if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
--              T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
--              yaffsVersion = 1;
--      }
--
--#endif
--
--      if (yaffsVersion == 2) {
--              /* Check for version 2 style functions */
--              if (!mtd->erase ||
--                  !mtd->block_isbad ||
--                  !mtd->block_markbad ||
--                  !mtd->read ||
--                  !mtd->write ||
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--                  !mtd->read_oob || !mtd->write_oob) {
--#else
--                  !mtd->write_ecc ||
--                  !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
--#endif
--                      T(YAFFS_TRACE_ALWAYS,
--                        ("yaffs: MTD device does not support required "
--                         "functions\n"));;
--                      return NULL;
--              }
--
--              if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
--                  mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
--                  !options.inband_tags) {
--                      T(YAFFS_TRACE_ALWAYS,
--                        ("yaffs: MTD device does not have the "
--                         "right page sizes\n"));
--                      return NULL;
--              }
--      } else {
--              /* Check for V1 style functions */
--              if (!mtd->erase ||
--                  !mtd->read ||
--                  !mtd->write ||
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--                  !mtd->read_oob || !mtd->write_oob) {
--#else
--                  !mtd->write_ecc ||
--                  !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
--#endif
--                      T(YAFFS_TRACE_ALWAYS,
--                        ("yaffs: MTD device does not support required "
--                         "functions\n"));;
--                      return NULL;
--              }
--
--              if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
--                  mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
--                      T(YAFFS_TRACE_ALWAYS,
--                        ("yaffs: MTD device does not support have the "
--                         "right page sizes\n"));
--                      return NULL;
--              }
--      }
--
--      /* OK, so if we got here, we have an MTD that's NAND and looks
--       * like it has the right capabilities
--       * Set the yaffs_Device up for mtd
--       */
--
--#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 */
--              T(YAFFS_TRACE_ALWAYS,
--                ("yaffs_read_super: Failed trying to allocate "
--                 "yaffs_Device. \n"));
--              return NULL;
--      }
--
--      memset(dev, 0, sizeof(yaffs_Device));
--      dev->genericDevice = mtd;
--      dev->name = mtd->name;
--
--      /* Set up the memory size parameters.... */
--
--      nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
--
--      dev->startBlock = 0;
--      dev->endBlock = nBlocks - 1;
--      dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
--      dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
--      dev->nReservedBlocks = 5;
--      dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
--      dev->inbandTags = options.inband_tags;
--
--      /* ... and the functions. */
--      if (yaffsVersion == 2) {
--              dev->writeChunkWithTagsToNAND =
--                  nandmtd2_WriteChunkWithTagsToNAND;
--              dev->readChunkWithTagsFromNAND =
--                  nandmtd2_ReadChunkWithTagsFromNAND;
--              dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
--              dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
--              dev->spareBuffer = YMALLOC(mtd->oobsize);
--              dev->isYaffs2 = 1;
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--              dev->totalBytesPerChunk = mtd->writesize;
--              dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
--#else
--              dev->totalBytesPerChunk = mtd->oobblock;
--              dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
--#endif
--              nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
--
--              dev->startBlock = 0;
--              dev->endBlock = nBlocks - 1;
--      } else {
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--              /* use the MTD interface in yaffs_mtdif1.c */
--              dev->writeChunkWithTagsToNAND =
--                      nandmtd1_WriteChunkWithTagsToNAND;
--              dev->readChunkWithTagsFromNAND =
--                      nandmtd1_ReadChunkWithTagsFromNAND;
--              dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
--              dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
--#else
--              dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
--              dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
--#endif
--              dev->isYaffs2 = 0;
--      }
--      /* ... and common functions */
--      dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
--      dev->initialiseNAND = nandmtd_InitialiseNAND;
--
--      dev->putSuperFunc = yaffs_MTDPutSuper;
--
--      dev->superBlock = (void *)sb;
--      dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
--
--
--#ifndef CONFIG_YAFFS_DOES_ECC
--      dev->useNANDECC = 1;
--#endif
--
--#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
--      dev->wideTnodesDisabled = 1;
--#endif
--
--      dev->skipCheckpointRead = options.skip_checkpoint_read;
--      dev->skipCheckpointWrite = options.skip_checkpoint_write;
--
--      /* we assume this is protected by lock_kernel() in mount/umount */
--      ylist_add_tail(&dev->devList, &yaffs_dev_list);
--
--      init_MUTEX(&dev->grossLock);
--
--      yaffs_GrossLock(dev);
--
--      err = yaffs_GutsInitialise(dev);
--
--      T(YAFFS_TRACE_OS,
--        ("yaffs_read_super: guts initialised %s\n",
--         (err == YAFFS_OK) ? "OK" : "FAILED"));
--
--      /* Release lock before yaffs_get_inode() */
--      yaffs_GrossUnlock(dev);
--
--      /* Create root inode */
--      if (err == YAFFS_OK)
--              inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
--                                      yaffs_Root(dev));
--
--      if (!inode)
--              return NULL;
--
--      inode->i_op = &yaffs_dir_inode_operations;
--      inode->i_fop = &yaffs_dir_operations;
--
--      T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
--
--      root = d_alloc_root(inode);
--
--      T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
--
--      if (!root) {
--              iput(inode);
--              return NULL;
--      }
--      sb->s_root = root;
--      sb->s_dirt = !dev->isCheckpointed;
--      T(YAFFS_TRACE_ALWAYS,
--        ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));
--
--      T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
--      return sb;
--}
--
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
--                                       int silent)
--{
--      return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
--}
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--static int yaffs_read_super(struct file_system_type *fs,
--                          int flags, const char *dev_name,
--                          void *data, struct vfsmount *mnt)
--{
--
--      return get_sb_bdev(fs, flags, dev_name, data,
--                         yaffs_internal_read_super_mtd, mnt);
--}
--#else
--static struct super_block *yaffs_read_super(struct file_system_type *fs,
--                                          int flags, const char *dev_name,
--                                          void *data)
--{
--
--      return get_sb_bdev(fs, flags, dev_name, data,
--                         yaffs_internal_read_super_mtd);
--}
--#endif
--
--static struct file_system_type yaffs_fs_type = {
--      .owner = THIS_MODULE,
--      .name = "yaffs",
--      .get_sb = yaffs_read_super,
--      .kill_sb = kill_block_super,
--      .fs_flags = FS_REQUIRES_DEV,
--};
--#else
--static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
--                                          int silent)
--{
--      return yaffs_internal_read_super(1, sb, data, silent);
--}
--
--static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
--                    FS_REQUIRES_DEV);
--#endif
--
--
--#ifdef CONFIG_YAFFS_YAFFS2
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
--static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
--                                        int silent)
--{
--      return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
--}
--
--#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
--static int yaffs2_read_super(struct file_system_type *fs,
--                      int flags, const char *dev_name, void *data,
--                      struct vfsmount *mnt)
--{
--      return get_sb_bdev(fs, flags, dev_name, data,
--                      yaffs2_internal_read_super_mtd, mnt);
--}
--#else
--static struct super_block *yaffs2_read_super(struct file_system_type *fs,
--                                           int flags, const char *dev_name,
--                                           void *data)
--{
--
--      return get_sb_bdev(fs, flags, dev_name, data,
--                         yaffs2_internal_read_super_mtd);
--}
--#endif
--
--static struct file_system_type yaffs2_fs_type = {
--      .owner = THIS_MODULE,
--      .name = "yaffs2",
--      .get_sb = yaffs2_read_super,
--      .kill_sb = kill_block_super,
--      .fs_flags = FS_REQUIRES_DEV,
--};
--#else
--static struct super_block *yaffs2_read_super(struct super_block *sb,
--                                           void *data, int silent)
--{
--      return yaffs_internal_read_super(2, sb, data, silent);
--}
--
--static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
--                    FS_REQUIRES_DEV);
--#endif
--
--#endif                                /* CONFIG_YAFFS_YAFFS2 */
--
--static struct proc_dir_entry *my_proc_entry;
--
--static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
--{
--      buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
--      buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
--      buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
--      buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
--      buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
--      buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
--      buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
--      buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
--      buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
--      buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
--      buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
--      buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
--      buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
--      buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
--      buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
--      buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
--      buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
--      buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
--      buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
--      buf += sprintf(buf, "passiveGCs......... %d\n",
--                  dev->passiveGarbageCollections);
--      buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
--      buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
--      buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
--      buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
--      buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
--      buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
--      buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
--      buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
--      buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
--      buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
--      buf +=
--          sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
--      buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
--      buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
--      buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
--
--      return buf;
--}
--
--static int yaffs_proc_read(char *page,
--                         char **start,
--                         off_t offset, int count, int *eof, void *data)
--{
--      struct ylist_head *item;
--      char *buf = page;
--      int step = offset;
--      int n = 0;
--
--      /* Get proc_file_read() to step 'offset' by one on each sucessive call.
--       * We use 'offset' (*ppos) to indicate where we are in devList.
--       * This also assumes the user has posted a read buffer large
--       * enough to hold the complete output; but that's life in /proc.
--       */
--
--      *(int *)start = 1;
--
--      /* Print header first */
--      if (step == 0) {
--              buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
--                             "\n%s\n%s\n", yaffs_fs_c_version,
--                             yaffs_guts_c_version);
--      }
--
--      /* hold lock_kernel while traversing yaffs_dev_list */
--      lock_kernel();
--
--      /* Locate and print the Nth entry.  Order N-squared but N is small. */
--      ylist_for_each(item, &yaffs_dev_list) {
--              yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
--              if (n < step) {
--                      n++;
--                      continue;
--              }
--              buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
--              buf = yaffs_dump_dev(buf, dev);
--              break;
--      }
--      unlock_kernel();
--
--      return buf - page < count ? buf - page : count;
--}
--
--/**
-- * Set the verbosity of the warnings and error messages.
-- *
-- * Note that the names can only be a..z or _ with the current code.
-- */
--
--static struct {
--      char *mask_name;
--      unsigned mask_bitfield;
--} mask_flags[] = {
--      {"allocate", YAFFS_TRACE_ALLOCATE},
--      {"always", YAFFS_TRACE_ALWAYS},
--      {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
--      {"buffers", YAFFS_TRACE_BUFFERS},
--      {"bug", YAFFS_TRACE_BUG},
--      {"checkpt", YAFFS_TRACE_CHECKPOINT},
--      {"deletion", YAFFS_TRACE_DELETION},
--      {"erase", YAFFS_TRACE_ERASE},
--      {"error", YAFFS_TRACE_ERROR},
--      {"gc_detail", YAFFS_TRACE_GC_DETAIL},
--      {"gc", YAFFS_TRACE_GC},
--      {"mtd", YAFFS_TRACE_MTD},
--      {"nandaccess", YAFFS_TRACE_NANDACCESS},
--      {"os", YAFFS_TRACE_OS},
--      {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
--      {"scan", YAFFS_TRACE_SCAN},
--      {"tracing", YAFFS_TRACE_TRACING},
--
--      {"verify", YAFFS_TRACE_VERIFY},
--      {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
--      {"verify_full", YAFFS_TRACE_VERIFY_FULL},
--      {"verify_all", YAFFS_TRACE_VERIFY_ALL},
--
--      {"write", YAFFS_TRACE_WRITE},
--      {"all", 0xffffffff},
--      {"none", 0},
--      {NULL, 0},
--};
--
--#define MAX_MASK_NAME_LENGTH 40
--static int yaffs_proc_write(struct file *file, const char *buf,
--                                       unsigned long count, void *data)
--{
--      unsigned rg = 0, mask_bitfield;
--      char *end;
--      char *mask_name;
--      const char *x;
--      char substring[MAX_MASK_NAME_LENGTH + 1];
--      int i;
--      int done = 0;
--      int add, len = 0;
--      int pos = 0;
--
--      rg = yaffs_traceMask;
--
--      while (!done && (pos < count)) {
--              done = 1;
--              while ((pos < count) && isspace(buf[pos]))
--                      pos++;
--
--              switch (buf[pos]) {
--              case '+':
--              case '-':
--              case '=':
--                      add = buf[pos];
--                      pos++;
--                      break;
--
--              default:
--                      add = ' ';
--                      break;
--              }
--              mask_name = NULL;
--
--              mask_bitfield = simple_strtoul(buf + pos, &end, 0);
--
--              if (end > buf + pos) {
--                      mask_name = "numeral";
--                      len = end - (buf + pos);
--                      pos += len;
--                      done = 0;
--              } else {
--                      for (x = buf + pos, i = 0;
--                          (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
--                          i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
--                              substring[i] = *x;
--                      substring[i] = '\0';
--
--                      for (i = 0; mask_flags[i].mask_name != NULL; i++) {
--                              if (strcmp(substring, mask_flags[i].mask_name) == 0) {
--                                      mask_name = mask_flags[i].mask_name;
--                                      mask_bitfield = mask_flags[i].mask_bitfield;
--                                      done = 0;
--                                      break;
--                              }
--                      }
--              }
--
--              if (mask_name != NULL) {
--                      done = 0;
--                      switch (add) {
--                      case '-':
--                              rg &= ~mask_bitfield;
--                              break;
--                      case '+':
--                              rg |= mask_bitfield;
--                              break;
--                      case '=':
--                              rg = mask_bitfield;
--                              break;
--                      default:
--                              rg |= mask_bitfield;
--                              break;
--                      }
--              }
--      }
--
--      yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
--
--      printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
--
--      if (rg & YAFFS_TRACE_ALWAYS) {
--              for (i = 0; mask_flags[i].mask_name != NULL; i++) {
--                      char flag;
--                      flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
--                      printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
--              }
--      }
--
--      return count;
--}
--
--/* Stuff to handle installation of file systems */
--struct file_system_to_install {
--      struct file_system_type *fst;
--      int installed;
--};
--
--static struct file_system_to_install fs_to_install[] = {
--      {&yaffs_fs_type, 0},
--      {&yaffs2_fs_type, 0},
--      {NULL, 0}
--};
--
--static int __init init_yaffs_fs(void)
--{
--      int error = 0;
--      struct file_system_to_install *fsinst;
--
--      T(YAFFS_TRACE_ALWAYS,
--        ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
--
--      /* Install the proc_fs entry */
--      my_proc_entry = create_proc_entry("yaffs",
--                                             S_IRUGO | S_IFREG,
--                                             YPROC_ROOT);
--
--      if (my_proc_entry) {
--              my_proc_entry->write_proc = yaffs_proc_write;
--              my_proc_entry->read_proc = yaffs_proc_read;
--              my_proc_entry->data = NULL;
--      } else
--              return -ENOMEM;
--
--      /* Now add the file system entries */
--
--      fsinst = fs_to_install;
--
--      while (fsinst->fst && !error) {
--              error = register_filesystem(fsinst->fst);
--              if (!error)
--                      fsinst->installed = 1;
--              fsinst++;
--      }
--
--      /* Any errors? uninstall  */
--      if (error) {
--              fsinst = fs_to_install;
--
--              while (fsinst->fst) {
--                      if (fsinst->installed) {
--                              unregister_filesystem(fsinst->fst);
--                              fsinst->installed = 0;
--                      }
--                      fsinst++;
--              }
--      }
--
--      return error;
--}
--
--static void __exit exit_yaffs_fs(void)
--{
--
--      struct file_system_to_install *fsinst;
--
--      T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
--                             " removing. \n"));
--
--      remove_proc_entry("yaffs", YPROC_ROOT);
--
--      fsinst = fs_to_install;
--
--      while (fsinst->fst) {
--              if (fsinst->installed) {
--                      unregister_filesystem(fsinst->fst);
--                      fsinst->installed = 0;
--              }
--              fsinst++;
--      }
--}
--
--module_init(init_yaffs_fs)
--module_exit(exit_yaffs_fs)
--
--MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
--MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
--MODULE_LICENSE("GPL");
---- a/fs/yaffs2/yaffs_getblockinfo.h
-+++ b/fs/yaffs2/yaffs_getblockinfo.h
-@@ -1,7 +1,7 @@
- /*
-  * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
-  *
-- * Copyright (C) 2002-2007 Aleph One Ltd.
-+ * Copyright (C) 2002-2010 Aleph One Ltd.
-  *   for Toby Churchill Ltd and Brightstar Engineering
-  *
-  * Created by Charles Manning <charles@aleph1.co.uk>
-@@ -17,6 +17,7 @@
- #define __YAFFS_GETBLOCKINFO_H__
- #include "yaffs_guts.h"
-+#include "yaffs_trace.h"
- /* Function to manipulate block info */
- static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
---- a/fs/yaffs2/yaffs_guts.c
-+++ b/fs/yaffs2/yaffs_guts.c
-@@ -1,7 +1,7 @@
- /*
-  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
-  *
-- * Copyright (C) 2002-2007 Aleph One Ltd.
-+ * Copyright (C) 2002-2010 Aleph One Ltd.
-  *   for Toby Churchill Ltd and Brightstar Engineering
-  *
-  * Created by Charles Manning <charles@aleph1.co.uk>
-@@ -10,11 +10,8 @@
-  * it under the terms of the GNU General Public License version 2 as
-  * published by the Free Software Foundation.
-  */
--
--const char *yaffs_guts_c_version =
--    "$Id: yaffs_guts.c,v 1.82 2009-03-09 04:24:17 charles Exp $";
--
- #include "yportenv.h"
-+#include "yaffs_trace.h"
- #include "yaffsinterface.h"
- #include "yaffs_guts.h"
-@@ -22,22 +19,28 @@ const char *yaffs_guts_c_version =
- #include "yaffs_getblockinfo.h"
- #include "yaffs_tagscompat.h"
--#ifndef CONFIG_YAFFS_USE_OWN_SORT
--#include "yaffs_qsort.h"
--#endif
-+
- #include "yaffs_nand.h"
--#include "yaffs_checkptrw.h"
-+#include "yaffs_yaffs1.h"
-+#include "yaffs_yaffs2.h"
-+#include "yaffs_bitmap.h"
-+#include "yaffs_verify.h"
- #include "yaffs_nand.h"
- #include "yaffs_packedtags2.h"
-+#include "yaffs_nameval.h"
-+#include "yaffs_allocator.h"
--#define YAFFS_PASSIVE_GC_CHUNKS 2
-+/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
-+#define YAFFS_GC_GOOD_ENOUGH 2
-+#define YAFFS_GC_PASSIVE_THRESHOLD 4
- #include "yaffs_ecc.h"
-+
- /* Robustification (if it ever comes about...) */
- static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);
- static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
-@@ -49,33 +52,26 @@ static void yaffs_HandleUpdateChunk(yaff
-                               const yaffs_ExtendedTags *tags);
- /* Other local prototypes */
-+static void yaffs_UpdateParent(yaffs_Object *obj);
- static int yaffs_UnlinkObject(yaffs_Object *obj);
- static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
--static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
--
- static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev,
-                                       const __u8 *buffer,
-                                       yaffs_ExtendedTags *tags,
-                                       int useReserve);
--static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
--                              int chunkInNAND, int inScan);
-+
- static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
-                                       yaffs_ObjectType type);
--static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
--                              yaffs_Object *obj);
--static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
--                              int force, int isShrink, int shadows);
-+
-+
-+static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod);
-+
- static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
- static int yaffs_CheckStructures(void);
--static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
--                      int chunkOffset, int *limit);
- static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
--static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
--
--
- static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
-                               int chunkInNAND);
-@@ -87,30 +83,22 @@ static int yaffs_TagsMatch(const yaffs_E
- static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
-                               yaffs_BlockInfo **blockUsedPtr);
--static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
--
- static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
--static void yaffs_VerifyDirectory(yaffs_Object *directory);
--#ifdef YAFFS_PARANOID
--static int yaffs_CheckFileSanity(yaffs_Object *in);
--#else
--#define yaffs_CheckFileSanity(in)
--#endif
--
- static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
- static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
--static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
--
- static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
-                               yaffs_ExtendedTags *tags);
--static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
--              unsigned pos);
--static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
--                                      yaffs_FileStructure *fStruct,
--                                      __u32 chunkId);
-+static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
-+                                      int chunkInNAND,
-+                                      const __u8 *data,
-+                                      yaffs_ExtendedTags *tags);
-+
-+
-+static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize);
-+static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev,YCHAR *ohName, const YCHAR *name);
- /* Function to calculate chunk and offset */
-@@ -172,7 +160,7 @@ static __u32 ShiftsGE(__u32 x)
- static __u32 Shifts(__u32 x)
- {
--      int nShifts;
-+      __u32 nShifts;
-       nShifts =  0;
-@@ -203,7 +191,7 @@ static int yaffs_InitialiseTempBuffers(y
-       for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
-               dev->tempBuffer[i].line = 0;    /* not in use */
-               dev->tempBuffer[i].buffer = buf =
--                  YMALLOC_DMA(dev->totalBytesPerChunk);
-+                  YMALLOC_DMA(dev->param.totalBytesPerChunk);
-       }
-       return buf ? YAFFS_OK : YAFFS_FAIL;
-@@ -286,7 +274,7 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
-                       return 1;
-       }
--      for (i = 0; i < dev->nShortOpCaches; i++) {
-+      for (i = 0; i < dev->param.nShortOpCaches; i++) {
-               if (dev->srCache[i].data == buffer)
-                       return 1;
-       }
-@@ -299,6374 +287,4183 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi
-       return 0;
- }
--
--
- /*
-- * Chunk bitmap manipulations
-+ * Verification code
-  */
--static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
--{
--      if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
--              T(YAFFS_TRACE_ERROR,
--                      (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
--                      blk));
--              YBUG();
--      }
--      return dev->chunkBits +
--              (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
--}
--static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
--{
--      if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
--                      chunk < 0 || chunk >= dev->nChunksPerBlock) {
--              T(YAFFS_TRACE_ERROR,
--              (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
--                      blk, chunk));
--              YBUG();
--      }
--}
--static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
--{
--      __u8 *blkBits = yaffs_BlockBits(dev, blk);
--      memset(blkBits, 0, dev->chunkBitmapStride);
--}
-+/*
-+ *  Simple hash function. Needs to have a reasonable spread
-+ */
--static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
-+static Y_INLINE int yaffs_HashFunction(int n)
- {
--      __u8 *blkBits = yaffs_BlockBits(dev, blk);
--
--      yaffs_VerifyChunkBitId(dev, blk, chunk);
--
--      blkBits[chunk / 8] &= ~(1 << (chunk & 7));
-+      n = abs(n);
-+      return n % YAFFS_NOBJECT_BUCKETS;
- }
--static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
--{
--      __u8 *blkBits = yaffs_BlockBits(dev, blk);
--
--      yaffs_VerifyChunkBitId(dev, blk, chunk);
--
--      blkBits[chunk / 8] |= (1 << (chunk & 7));
--}
-+/*
-+ * Access functions to useful fake objects.
-+ * Note that root might have a presence in NAND if permissions are set.
-+ */
--static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
-+yaffs_Object *yaffs_Root(yaffs_Device *dev)
- {
--      __u8 *blkBits = yaffs_BlockBits(dev, blk);
--      yaffs_VerifyChunkBitId(dev, blk, chunk);
--
--      return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
-+      return dev->rootDir;
- }
--static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
-+yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
- {
--      __u8 *blkBits = yaffs_BlockBits(dev, blk);
--      int i;
--      for (i = 0; i < dev->chunkBitmapStride; i++) {
--              if (*blkBits)
--                      return 1;
--              blkBits++;
--      }
--      return 0;
-+      return dev->lostNFoundDir;
- }
--static int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
--{
--      __u8 *blkBits = yaffs_BlockBits(dev, blk);
--      int i;
--      int n = 0;
--      for (i = 0; i < dev->chunkBitmapStride; i++) {
--              __u8 x = *blkBits;
--              while (x) {
--                      if (x & 1)
--                              n++;
--                      x >>= 1;
--              }
--
--              blkBits++;
--      }
--      return n;
--}
- /*
-- * Verification code
-+ *  Erased NAND checking functions
-  */
--static int yaffs_SkipVerification(yaffs_Device *dev)
--{
--      return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
--}
--
--static int yaffs_SkipFullVerification(yaffs_Device *dev)
--{
--      return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
--}
--
--static int yaffs_SkipNANDVerification(yaffs_Device *dev)
-+int yaffs_CheckFF(__u8 *buffer, int nBytes)
- {
--      return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
-+      /* Horrible, slow implementation */
-+      while (nBytes--) {
-+              if (*buffer != 0xFF)
-+                      return 0;
-+              buffer++;
-+      }
-+      return 1;
- }
--static const char *blockStateName[] = {
--"Unknown",
--"Needs scanning",
--"Scanning",
--"Empty",
--"Allocating",
--"Full",
--"Dirty",
--"Checkpoint",
--"Collecting",
--"Dead"
--};
--
--static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
-+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
-+                              int chunkInNAND)
- {
--      int actuallyUsed;
--      int inUse;
-+      int retval = YAFFS_OK;
-+      __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
-+      yaffs_ExtendedTags tags;
-+      int result;
--      if (yaffs_SkipVerification(dev))
--              return;
-+      result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
--      /* Report illegal runtime states */
--      if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
--              T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
-+      if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
-+              retval = YAFFS_FAIL;
--      switch (bi->blockState) {
--      case YAFFS_BLOCK_STATE_UNKNOWN:
--      case YAFFS_BLOCK_STATE_SCANNING:
--      case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
--              T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
--              n, blockStateName[bi->blockState]));
-+      if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
-+              T(YAFFS_TRACE_NANDACCESS,
-+                (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
-+              retval = YAFFS_FAIL;
-       }
--      /* Check pages in use and soft deletions are legal */
--
--      actuallyUsed = bi->pagesInUse - bi->softDeletions;
--
--      if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||
--         bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||
--         actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)
--              T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
--              n, bi->pagesInUse, bi->softDeletions));
--
-+      yaffs_ReleaseTempBuffer(dev, data, __LINE__);
--      /* Check chunk bitmap legal */
--      inUse = yaffs_CountChunkBits(dev, n);
--      if (inUse != bi->pagesInUse)
--              T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
--                      n, bi->pagesInUse, inUse));
-+      return retval;
--      /* Check that the sequence number is valid.
--       * Ten million is legal, but is very unlikely
--       */
--      if (dev->isYaffs2 &&
--         (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
--         (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
--              T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
--              n, bi->sequenceNumber));
- }
--static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
--              int n)
-+
-+static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
-+                                      int chunkInNAND,
-+                                      const __u8 *data,
-+                                      yaffs_ExtendedTags *tags)
- {
--      yaffs_VerifyBlock(dev, bi, n);
-+      int retval = YAFFS_OK;
-+      yaffs_ExtendedTags tempTags;
-+      __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
-+      int result;
-+      
-+      result = yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,&tempTags);
-+      if(memcmp(buffer,data,dev->nDataBytesPerChunk) ||
-+              tempTags.objectId != tags->objectId ||
-+              tempTags.chunkId  != tags->chunkId ||
-+              tempTags.byteCount != tags->byteCount)
-+              retval = YAFFS_FAIL;
--      /* After collection the block should be in the erased state */
--      /* This will need to change if we do partial gc */
-+      yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
--      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));
--      }
-+      return retval;
- }
--static void yaffs_VerifyBlocks(yaffs_Device *dev)
-+static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
-+                                      const __u8 *data,
-+                                      yaffs_ExtendedTags *tags,
-+                                      int useReserve)
- {
--      int i;
--      int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
--      int nIllegalBlockStates = 0;
--
--      if (yaffs_SkipVerification(dev))
--              return;
--
--      memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
--
--      for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
--              yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
--              yaffs_VerifyBlock(dev, bi, i);
--
--              if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
--                      nBlocksPerState[bi->blockState]++;
--              else
--                      nIllegalBlockStates++;
--      }
-+      int attempts = 0;
-+      int writeOk = 0;
-+      int chunk;
--      T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
--      T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
-+      yaffs2_InvalidateCheckpoint(dev);
--      T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
--      if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
--              T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
-+      do {
-+              yaffs_BlockInfo *bi = 0;
-+              int erasedOk = 0;
--      for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
--              T(YAFFS_TRACE_VERIFY,
--                (TSTR("%s %d blocks"TENDSTR),
--                blockStateName[i], nBlocksPerState[i]));
-+              chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
-+              if (chunk < 0) {
-+                      /* no space */
-+                      break;
-+              }
--      if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
--              T(YAFFS_TRACE_VERIFY,
--               (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
--               dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
-+              /* First check this chunk is erased, if it needs
-+               * checking.  The checking policy (unless forced
-+               * always on) is as follows:
-+               *
-+               * Check the first page we try to write in a block.
-+               * If the check passes then we don't need to check any
-+               * more.        If the check fails, we check again...
-+               * If the block has been erased, we don't need to check.
-+               *
-+               * However, if the block has been prioritised for gc,
-+               * then we think there might be something odd about
-+               * this block and stop using it.
-+               *
-+               * Rationale: We should only ever see chunks that have
-+               * not been erased if there was a partially written
-+               * chunk due to power loss.  This checking policy should
-+               * catch that case with very few checks and thus save a
-+               * lot of checks that are most likely not needed.
-+               *
-+               * Mods to the above
-+               * If an erase check fails or the write fails we skip the 
-+               * rest of the block.
-+               */
--      if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
--              T(YAFFS_TRACE_VERIFY,
--               (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
--               dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
-+              /* let's give it a try */
-+              attempts++;
--      if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
--              T(YAFFS_TRACE_VERIFY,
--               (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
--               nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
-+              if(dev->param.alwaysCheckErased)
-+                      bi->skipErasedCheck = 0;
--      T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
-+              if (!bi->skipErasedCheck) {
-+                      erasedOk = yaffs_CheckChunkErased(dev, chunk);
-+                      if (erasedOk != YAFFS_OK) {
-+                              T(YAFFS_TRACE_ERROR,
-+                              (TSTR("**>> yaffs chunk %d was not erased"
-+                              TENDSTR), chunk));
--}
-+                              /* If not erased, delete this one,
-+                               * skip rest of block and
-+                               * try another chunk */
-+                               yaffs_DeleteChunk(dev,chunk,1,__LINE__);
-+                               yaffs_SkipRestOfBlock(dev);
-+                              continue;
-+                      }
-+              }
--/*
-- * Verify the object header. oh must be valid, but obj and tags may be NULL in which
-- * case those tests will not be performed.
-- */
--static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
--{
--      if (obj && yaffs_SkipVerification(obj->myDev))
--              return;
-+              writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
-+                              data, tags);
--      if (!(tags && obj && oh)) {
--              T(YAFFS_TRACE_VERIFY,
--                              (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),
--                              (__u32)tags, (__u32)obj, (__u32)oh));
--              return;
--      }
-+              if(!bi->skipErasedCheck)
-+                      writeOk = yaffs_VerifyChunkWritten(dev, chunk, data, tags);
--      if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
--                      oh->type > YAFFS_OBJECT_TYPE_MAX)
--              T(YAFFS_TRACE_VERIFY,
--                      (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
--                      tags->objectId, oh->type));
-+              if (writeOk != YAFFS_OK) {
-+                      /* Clean up aborted write, skip to next block and
-+                       * try another chunk */
-+                      yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
-+                      continue;
-+              }
--      if (tags->objectId != obj->objectId)
--              T(YAFFS_TRACE_VERIFY,
--                      (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
--                      tags->objectId, obj->objectId));
-+              bi->skipErasedCheck = 1;
-+              /* Copy the data into the robustification buffer */
-+              yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
--      /*
--       * Check that the object's parent ids match if parentCheck requested.
--       *
--       * Tests do not apply to the root object.
--       */
-+      } while (writeOk != YAFFS_OK &&
-+              (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
--      if (parentCheck && tags->objectId > 1 && !obj->parent)
--              T(YAFFS_TRACE_VERIFY,
--                      (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
--                      tags->objectId, oh->parentObjectId));
-+      if (!writeOk)
-+              chunk = -1;
--      if (parentCheck && obj->parent &&
--                      oh->parentObjectId != obj->parent->objectId &&
--                      (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
--                      obj->parent->objectId != YAFFS_OBJECTID_DELETED))
--              T(YAFFS_TRACE_VERIFY,
--                      (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
--                      tags->objectId, oh->parentObjectId, obj->parent->objectId));
-+      if (attempts > 1) {
-+              T(YAFFS_TRACE_ERROR,
-+                      (TSTR("**>> yaffs write required %d attempts" TENDSTR),
-+                      attempts));
--      if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
--              T(YAFFS_TRACE_VERIFY,
--                      (TSTR("Obj %d header name is NULL"TENDSTR),
--                      obj->objectId));
-+              dev->nRetriedWrites += (attempts - 1);
-+      }
--      if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
--              T(YAFFS_TRACE_VERIFY,
--                      (TSTR("Obj %d header name is 0xFF"TENDSTR),
--                      obj->objectId));
-+      return chunk;
- }
-+ 
-+/*
-+ * Block retiring for handling a broken block.
-+ */
--static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
--                                      __u32 level, int chunkOffset)
-+static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
- {
--      int i;
--      yaffs_Device *dev = obj->myDev;
--      int ok = 1;
-+      yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
--      if (tn) {
--              if (level > 0) {
-+      yaffs2_InvalidateCheckpoint(dev);
-+      
-+      yaffs2_ClearOldestDirtySequence(dev,bi);
--                      for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
--                              if (tn->internal[i]) {
--                                      ok = yaffs_VerifyTnodeWorker(obj,
--                                                      tn->internal[i],
--                                                      level - 1,
--                                                      (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
--                              }
--                      }
--              } else if (level == 0) {
-+      if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
-+              if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
-+                      T(YAFFS_TRACE_ALWAYS, (TSTR(
-+                              "yaffs: Failed to mark bad and erase block %d"
-+                              TENDSTR), blockInNAND));
-+              } else {
-                       yaffs_ExtendedTags tags;
--                      __u32 objectId = obj->objectId;
-+                      int chunkId = blockInNAND * dev->param.nChunksPerBlock;
--                      chunkOffset <<=  YAFFS_TNODES_LEVEL0_BITS;
-+                      __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
--                      for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
--                              __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
-+                      memset(buffer, 0xff, dev->nDataBytesPerChunk);
-+                      yaffs_InitialiseTags(&tags);
-+                      tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
-+                      if (dev->param.writeChunkWithTagsToNAND(dev, chunkId -
-+                              dev->chunkOffset, buffer, &tags) != YAFFS_OK)
-+                              T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
-+                                      TCONT("write bad block marker to block %d")
-+                                      TENDSTR), blockInNAND));
--                              if (theChunk > 0) {
--                                      /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
--                                      yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
--                                      if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
--                                              T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
--                                                      objectId, chunkOffset, theChunk,
--                                                      tags.objectId, tags.chunkId));
--                                      }
--                              }
--                              chunkOffset++;
--                      }
-+                      yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
-               }
-       }
--      return ok;
-+      bi->blockState = YAFFS_BLOCK_STATE_DEAD;
-+      bi->gcPrioritise = 0;
-+      bi->needsRetiring = 0;
-+      dev->nRetiredBlocks++;
- }
-+/*
-+ * Functions for robustisizing TODO
-+ *
-+ */
--static void yaffs_VerifyFile(yaffs_Object *obj)
-+static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
-+                              const __u8 *data,
-+                              const yaffs_ExtendedTags *tags)
- {
--      int requiredTallness;
--      int actualTallness;
--      __u32 lastChunk;
--      __u32 x;
--      __u32 i;
--      yaffs_Device *dev;
--      yaffs_ExtendedTags tags;
--      yaffs_Tnode *tn;
--      __u32 objectId;
-+      dev=dev;
-+      chunkInNAND=chunkInNAND;
-+      data=data;
-+      tags=tags;
-+}
--      if (!obj)
--              return;
-+static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
-+                              const yaffs_ExtendedTags *tags)
-+{
-+      dev=dev;
-+      chunkInNAND=chunkInNAND;
-+      tags=tags;
-+}
--      if (yaffs_SkipVerification(obj->myDev))
--              return;
-+void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
-+{
-+      if (!bi->gcPrioritise) {
-+              bi->gcPrioritise = 1;
-+              dev->hasPendingPrioritisedGCs = 1;
-+              bi->chunkErrorStrikes++;
--      dev = obj->myDev;
--      objectId = obj->objectId;
-+              if (bi->chunkErrorStrikes > 3) {
-+                      bi->needsRetiring = 1; /* Too many stikes, so retire this */
-+                      T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
--      /* Check file size is consistent with tnode depth */
--      lastChunk =  obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
--      x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
--      requiredTallness = 0;
--      while (x > 0) {
--              x >>= YAFFS_TNODES_INTERNAL_BITS;
--              requiredTallness++;
-+              }
-       }
-+}
-+
-+static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
-+              int erasedOk)
-+{
-+      int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
-+      yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
--      actualTallness = obj->variant.fileVariant.topLevel;
-+      yaffs_HandleChunkError(dev, bi);
--      if (requiredTallness > actualTallness)
--              T(YAFFS_TRACE_VERIFY,
--              (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
--               obj->objectId, actualTallness, requiredTallness));
-+      if (erasedOk) {
-+              /* Was an actual write failure, so mark the block for retirement  */
-+              bi->needsRetiring = 1;
-+              T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
-+                (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
-+      }
-+
-+      /* Delete the chunk */
-+      yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
-+      yaffs_SkipRestOfBlock(dev);
-+}
--      /* Check that the chunks in the tnode tree are all correct.
--       * We do this by scanning through the tnode tree and
--       * checking the tags for every chunk match.
--       */
-+/*---------------- Name handling functions ------------*/
--      if (yaffs_SkipNANDVerification(dev))
--              return;
-+static __u16 yaffs_CalcNameSum(const YCHAR *name)
-+{
-+      __u16 sum = 0;
-+      __u16 i = 1;
--      for (i = 1; i <= lastChunk; i++) {
--              tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
-+      const YUCHAR *bname = (const YUCHAR *) name;
-+      if (bname) {
-+              while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
--              if (tn) {
--                      __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
--                      if (theChunk > 0) {
--                              /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
--                              yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
--                              if (tags.objectId != objectId || tags.chunkId != i) {
--                                      T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
--                                              objectId, i, theChunk,
--                                              tags.objectId, tags.chunkId));
--                              }
--                      }
-+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
-+                      sum += yaffs_toupper(*bname) * i;
-+#else
-+                      sum += (*bname) * i;
-+#endif
-+                      i++;
-+                      bname++;
-               }
-       }
-+      return sum;
- }
--
--static void yaffs_VerifyHardLink(yaffs_Object *obj)
-+void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
- {
--      if (obj && yaffs_SkipVerification(obj->myDev))
--              return;
-+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
-+      memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
-+      if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH)
-+              yaffs_strcpy(obj->shortName, name);
-+      else
-+              obj->shortName[0] = _Y('\0');
-+#endif
-+      obj->sum = yaffs_CalcNameSum(name);
-+}
--      /* Verify sane equivalent object */
-+void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh)
-+{
-+#ifdef CONFIG_YAFFS_AUTO_UNICODE
-+      YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1];
-+      memset(tmpName,0,sizeof(tmpName));
-+      yaffs_LoadNameFromObjectHeader(obj->myDev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1);
-+      yaffs_SetObjectName(obj,tmpName);
-+#else
-+      yaffs_SetObjectName(obj,oh->name);
-+#endif
- }
--static void yaffs_VerifySymlink(yaffs_Object *obj)
-+/*-------------------- TNODES -------------------
-+
-+ * List of spare tnodes
-+ * The list is hooked together using the first pointer
-+ * in the tnode.
-+ */
-+
-+
-+yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
- {
--      if (obj && yaffs_SkipVerification(obj->myDev))
--              return;
-+      yaffs_Tnode *tn = yaffs_AllocateRawTnode(dev);
-+      if (tn){
-+              memset(tn, 0, dev->tnodeSize);
-+              dev->nTnodes++;
-+      }
-+
-+      dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
--      /* Verify symlink string */
-+      return tn;
- }
--static void yaffs_VerifySpecial(yaffs_Object *obj)
-+/* FreeTnode frees up a tnode and puts it back on the free list */
-+static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
- {
--      if (obj && yaffs_SkipVerification(obj->myDev))
--              return;
-+      yaffs_FreeRawTnode(dev,tn);
-+      dev->nTnodes--;
-+      dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
- }
--static void yaffs_VerifyObject(yaffs_Object *obj)
-+static void yaffs_DeinitialiseTnodesAndObjects(yaffs_Device *dev)
- {
--      yaffs_Device *dev;
--
--      __u32 chunkMin;
--      __u32 chunkMax;
--
--      __u32 chunkIdOk;
--      __u32 chunkInRange;
--      __u32 chunkShouldNotBeDeleted;
--      __u32 chunkValid;
--
--      if (!obj)
--              return;
-+      yaffs_DeinitialiseRawTnodesAndObjects(dev);
-+      dev->nObjects = 0;
-+      dev->nTnodes = 0;
-+}
--      if (obj->beingCreated)
--              return;
--      dev = obj->myDev;
-+void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
-+              unsigned val)
-+{
-+      __u32 *map = (__u32 *)tn;
-+      __u32 bitInMap;
-+      __u32 bitInWord;
-+      __u32 wordInMap;
-+      __u32 mask;
--      if (yaffs_SkipVerification(dev))
--              return;
-+      pos &= YAFFS_TNODES_LEVEL0_MASK;
-+      val >>= dev->chunkGroupBits;
--      /* Check sane object header chunk */
-+      bitInMap = pos * dev->tnodeWidth;
-+      wordInMap = bitInMap / 32;
-+      bitInWord = bitInMap & (32 - 1);
--      chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
--      chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
-+      mask = dev->tnodeMask << bitInWord;
--      chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
--      chunkIdOk = chunkInRange || obj->hdrChunk == 0;
--      chunkValid = chunkInRange &&
--                      yaffs_CheckChunkBit(dev,
--                                      obj->hdrChunk / dev->nChunksPerBlock,
--                                      obj->hdrChunk % dev->nChunksPerBlock);
--      chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
-+      map[wordInMap] &= ~mask;
-+      map[wordInMap] |= (mask & (val << bitInWord));
--      if (!obj->fake &&
--                      (!chunkIdOk || chunkShouldNotBeDeleted)) {
--              T(YAFFS_TRACE_VERIFY,
--                      (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
--                      obj->objectId, obj->hdrChunk,
--                      chunkIdOk ? "" : ",out of range",
--                      chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
-+      if (dev->tnodeWidth > (32 - bitInWord)) {
-+              bitInWord = (32 - bitInWord);
-+              wordInMap++;;
-+              mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
-+              map[wordInMap] &= ~mask;
-+              map[wordInMap] |= (mask & (val >> bitInWord));
-       }
-+}
--      if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
--              yaffs_ExtendedTags tags;
--              yaffs_ObjectHeader *oh;
--              __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
--
--              oh = (yaffs_ObjectHeader *)buffer;
-+__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
-+              unsigned pos)
-+{
-+      __u32 *map = (__u32 *)tn;
-+      __u32 bitInMap;
-+      __u32 bitInWord;
-+      __u32 wordInMap;
-+      __u32 val;
--              yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
--                              &tags);
-+      pos &= YAFFS_TNODES_LEVEL0_MASK;
--              yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
-+      bitInMap = pos * dev->tnodeWidth;
-+      wordInMap = bitInMap / 32;
-+      bitInWord = bitInMap & (32 - 1);
--              yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
--      }
-+      val = map[wordInMap] >> bitInWord;
--      /* Verify it has a parent */
--      if (obj && !obj->fake &&
--                      (!obj->parent || obj->parent->myDev != dev)) {
--              T(YAFFS_TRACE_VERIFY,
--                      (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
--                      obj->objectId, obj->parent));
-+      if      (dev->tnodeWidth > (32 - bitInWord)) {
-+              bitInWord = (32 - bitInWord);
-+              wordInMap++;;
-+              val |= (map[wordInMap] << bitInWord);
-       }
--      /* Verify parent is a directory */
--      if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
--              T(YAFFS_TRACE_VERIFY,
--                      (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
--                      obj->objectId, obj->parent->variantType));
--      }
-+      val &= dev->tnodeMask;
-+      val <<= dev->chunkGroupBits;
--      switch (obj->variantType) {
--      case YAFFS_OBJECT_TYPE_FILE:
--              yaffs_VerifyFile(obj);
--              break;
--      case YAFFS_OBJECT_TYPE_SYMLINK:
--              yaffs_VerifySymlink(obj);
--              break;
--      case YAFFS_OBJECT_TYPE_DIRECTORY:
--              yaffs_VerifyDirectory(obj);
--              break;
--      case YAFFS_OBJECT_TYPE_HARDLINK:
--              yaffs_VerifyHardLink(obj);
--              break;
--      case YAFFS_OBJECT_TYPE_SPECIAL:
--              yaffs_VerifySpecial(obj);
--              break;
--      case YAFFS_OBJECT_TYPE_UNKNOWN:
--      default:
--              T(YAFFS_TRACE_VERIFY,
--              (TSTR("Obj %d has illegaltype %d"TENDSTR),
--              obj->objectId, obj->variantType));
--              break;
--      }
-+      return val;
- }
--static void yaffs_VerifyObjects(yaffs_Device *dev)
-+/* ------------------- End of individual tnode manipulation -----------------*/
-+
-+/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
-+ * The look up tree is represented by the top tnode and the number of topLevel
-+ * in the tree. 0 means only the level 0 tnode is in the tree.
-+ */
-+
-+/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
-+yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
-+                                      yaffs_FileStructure *fStruct,
-+                                      __u32 chunkId)
- {
--      yaffs_Object *obj;
--      int i;
--      struct ylist_head *lh;
-+      yaffs_Tnode *tn = fStruct->top;
-+      __u32 i;
-+      int requiredTallness;
-+      int level = fStruct->topLevel;
--      if (yaffs_SkipVerification(dev))
--              return;
-+      dev=dev;
--      /* Iterate through the objects in each hash entry */
-+      /* Check sane level and chunk Id */
-+      if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
-+              return NULL;
--      for (i = 0; i <  YAFFS_NOBJECT_BUCKETS; i++) {
--              ylist_for_each(lh, &dev->objectBucket[i].list) {
--                      if (lh) {
--                              obj = ylist_entry(lh, yaffs_Object, hashLink);
--                              yaffs_VerifyObject(obj);
--                      }
--              }
-+      if (chunkId > YAFFS_MAX_CHUNK_ID)
-+              return NULL;
-+
-+      /* First check we're tall enough (ie enough topLevel) */
-+
-+      i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
-+      requiredTallness = 0;
-+      while (i) {
-+              i >>= YAFFS_TNODES_INTERNAL_BITS;
-+              requiredTallness++;
-       }
--}
-+      if (requiredTallness > fStruct->topLevel)
-+              return NULL; /* Not tall enough, so we can't find it */
--/*
-- *  Simple hash function. Needs to have a reasonable spread
-- */
-+      /* Traverse down to level 0 */
-+      while (level > 0 && tn) {
-+              tn = tn->internal[(chunkId >>
-+                      (YAFFS_TNODES_LEVEL0_BITS +
-+                              (level - 1) *
-+                              YAFFS_TNODES_INTERNAL_BITS)) &
-+                      YAFFS_TNODES_INTERNAL_MASK];
-+              level--;
-+      }
--static Y_INLINE int yaffs_HashFunction(int n)
--{
--      n = abs(n);
--      return n % YAFFS_NOBJECT_BUCKETS;
-+      return tn;
- }
--/*
-- * Access functions to useful fake objects.
-- * Note that root might have a presence in NAND if permissions are set.
-+/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
-+ * This happens in two steps:
-+ *  1. If the tree isn't tall enough, then make it taller.
-+ *  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
-+ *
-+ * Used when modifying the tree.
-+ *
-+ *  If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
-+ *  be plugged into the ttree.
-  */
--yaffs_Object *yaffs_Root(yaffs_Device *dev)
-+yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
-+                                      yaffs_FileStructure *fStruct,
-+                                      __u32 chunkId,
-+                                      yaffs_Tnode *passedTn)
- {
--      return dev->rootDir;
--}
-+      int requiredTallness;
-+      int i;
-+      int l;
-+      yaffs_Tnode *tn;
--yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
--{
--      return dev->lostNFoundDir;
--}
-+      __u32 x;
--/*
-- *  Erased NAND checking functions
-- */
-+      /* Check sane level and page Id */
-+      if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
-+              return NULL;
--int yaffs_CheckFF(__u8 *buffer, int nBytes)
--{
--      /* Horrible, slow implementation */
--      while (nBytes--) {
--              if (*buffer != 0xFF)
--                      return 0;
--              buffer++;
--      }
--      return 1;
--}
--
--static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
--                              int chunkInNAND)
--{
--      int retval = YAFFS_OK;
--      __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
--      yaffs_ExtendedTags tags;
--      int result;
--
--      result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
--
--      if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
--              retval = YAFFS_FAIL;
--
--      if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
--              T(YAFFS_TRACE_NANDACCESS,
--                (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
--              retval = YAFFS_FAIL;
--      }
--
--      yaffs_ReleaseTempBuffer(dev, data, __LINE__);
--
--      return retval;
--
--}
--
--static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
--                                      const __u8 *data,
--                                      yaffs_ExtendedTags *tags,
--                                      int useReserve)
--{
--      int attempts = 0;
--      int writeOk = 0;
--      int chunk;
--
--      yaffs_InvalidateCheckpoint(dev);
--
--      do {
--              yaffs_BlockInfo *bi = 0;
--              int erasedOk = 0;
--
--              chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
--              if (chunk < 0) {
--                      /* no space */
--                      break;
--              }
--
--              /* First check this chunk is erased, if it needs
--               * checking.  The checking policy (unless forced
--               * always on) is as follows:
--               *
--               * Check the first page we try to write in a block.
--               * If the check passes then we don't need to check any
--               * more.        If the check fails, we check again...
--               * If the block has been erased, we don't need to check.
--               *
--               * However, if the block has been prioritised for gc,
--               * then we think there might be something odd about
--               * this block and stop using it.
--               *
--               * Rationale: We should only ever see chunks that have
--               * not been erased if there was a partially written
--               * chunk due to power loss.  This checking policy should
--               * catch that case with very few checks and thus save a
--               * lot of checks that are most likely not needed.
--               */
--              if (bi->gcPrioritise) {
--                      yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
--                      /* try another chunk */
--                      continue;
--              }
--
--              /* let's give it a try */
--              attempts++;
--
--#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
--              bi->skipErasedCheck = 0;
--#endif
--              if (!bi->skipErasedCheck) {
--                      erasedOk = yaffs_CheckChunkErased(dev, chunk);
--                      if (erasedOk != YAFFS_OK) {
--                              T(YAFFS_TRACE_ERROR,
--                              (TSTR("**>> yaffs chunk %d was not erased"
--                              TENDSTR), chunk));
--
--                              /* try another chunk */
--                              continue;
--                      }
--                      bi->skipErasedCheck = 1;
--              }
--
--              writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
--                              data, tags);
--              if (writeOk != YAFFS_OK) {
--                      yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
--                      /* try another chunk */
--                      continue;
--              }
--
--              /* Copy the data into the robustification buffer */
--              yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
--
--      } while (writeOk != YAFFS_OK &&
--              (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
--
--      if (!writeOk)
--              chunk = -1;
--
--      if (attempts > 1) {
--              T(YAFFS_TRACE_ERROR,
--                      (TSTR("**>> yaffs write required %d attempts" TENDSTR),
--                      attempts));
--
--              dev->nRetriedWrites += (attempts - 1);
--      }
--
--      return chunk;
--}
--
--/*
-- * Block retiring for handling a broken block.
-- */
--
--static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
--{
--      yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
--
--      yaffs_InvalidateCheckpoint(dev);
--
--      if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
--              if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
--                      T(YAFFS_TRACE_ALWAYS, (TSTR(
--                              "yaffs: Failed to mark bad and erase block %d"
--                              TENDSTR), blockInNAND));
--              } else {
--                      yaffs_ExtendedTags tags;
--                      int chunkId = blockInNAND * dev->nChunksPerBlock;
--
--                      __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
--
--                      memset(buffer, 0xff, dev->nDataBytesPerChunk);
--                      yaffs_InitialiseTags(&tags);
--                      tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
--                      if (dev->writeChunkWithTagsToNAND(dev, chunkId -
--                              dev->chunkOffset, buffer, &tags) != YAFFS_OK)
--                              T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
--                                      TCONT("write bad block marker to block %d")
--                                      TENDSTR), blockInNAND));
--
--                      yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
--              }
--      }
--
--      bi->blockState = YAFFS_BLOCK_STATE_DEAD;
--      bi->gcPrioritise = 0;
--      bi->needsRetiring = 0;
--
--      dev->nRetiredBlocks++;
--}
--
--/*
-- * Functions for robustisizing TODO
-- *
-- */
--
--static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
--                              const __u8 *data,
--                              const yaffs_ExtendedTags *tags)
--{
--}
--
--static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
--                              const yaffs_ExtendedTags *tags)
--{
--}
--
--void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
--{
--      if (!bi->gcPrioritise) {
--              bi->gcPrioritise = 1;
--              dev->hasPendingPrioritisedGCs = 1;
--              bi->chunkErrorStrikes++;
--
--              if (bi->chunkErrorStrikes > 3) {
--                      bi->needsRetiring = 1; /* Too many stikes, so retire this */
--                      T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
--
--              }
--      }
--}
--
--static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
--              int erasedOk)
--{
--      int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
--      yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
--
--      yaffs_HandleChunkError(dev, bi);
--
--      if (erasedOk) {
--              /* Was an actual write failure, so mark the block for retirement  */
--              bi->needsRetiring = 1;
--              T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
--                (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
--      }
--
--      /* Delete the chunk */
--      yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
--}
--
--
--/*---------------- Name handling functions ------------*/
--
--static __u16 yaffs_CalcNameSum(const YCHAR *name)
--{
--      __u16 sum = 0;
--      __u16 i = 1;
--
--      const YUCHAR *bname = (const YUCHAR *) name;
--      if (bname) {
--              while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
--
--#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
--                      sum += yaffs_toupper(*bname) * i;
--#else
--                      sum += (*bname) * i;
--#endif
--                      i++;
--                      bname++;
--              }
--      }
--      return sum;
--}
--
--static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
--{
--#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
--      memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
--      if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
--              yaffs_strcpy(obj->shortName, name);
--      else
--              obj->shortName[0] = _Y('\0');
--#endif
--      obj->sum = yaffs_CalcNameSum(name);
--}
--
--/*-------------------- TNODES -------------------
--
-- * List of spare tnodes
-- * The list is hooked together using the first pointer
-- * in the tnode.
-- */
--
--/* yaffs_CreateTnodes creates a bunch more tnodes and
-- * adds them to the tnode free list.
-- * Don't use this function directly
-- */
--
--static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
--{
--      int i;
--      int tnodeSize;
--      yaffs_Tnode *newTnodes;
--      __u8 *mem;
--      yaffs_Tnode *curr;
--      yaffs_Tnode *next;
--      yaffs_TnodeList *tnl;
--
--      if (nTnodes < 1)
--              return YAFFS_OK;
--
--      /* Calculate the tnode size in bytes for variable width tnode support.
--       * Must be a multiple of 32-bits  */
--      tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
--
--      if (tnodeSize < sizeof(yaffs_Tnode))
--              tnodeSize = sizeof(yaffs_Tnode);
--
--      /* make these things */
--
--      newTnodes = YMALLOC(nTnodes * tnodeSize);
--      mem = (__u8 *)newTnodes;
--
--      if (!newTnodes) {
--              T(YAFFS_TRACE_ERROR,
--                      (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
--              return YAFFS_FAIL;
--      }
--
--      /* Hook them into the free list */
--#if 0
--      for (i = 0; i < nTnodes - 1; i++) {
--              newTnodes[i].internal[0] = &newTnodes[i + 1];
--#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
--              newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
--#endif
--      }
--
--      newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
--#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
--      newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
--#endif
--      dev->freeTnodes = newTnodes;
--#else
--      /* New hookup for wide tnodes */
--      for (i = 0; i < nTnodes - 1; i++) {
--              curr = (yaffs_Tnode *) &mem[i * tnodeSize];
--              next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
--              curr->internal[0] = next;
--      }
--
--      curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
--      curr->internal[0] = dev->freeTnodes;
--      dev->freeTnodes = (yaffs_Tnode *)mem;
--
--#endif
--
--
--      dev->nFreeTnodes += nTnodes;
--      dev->nTnodesCreated += nTnodes;
--
--      /* Now add this bunch of tnodes to a list for freeing up.
--       * NB If we can't add this to the management list it isn't fatal
--       * but it just means we can't free this bunch of tnodes later.
--       */
--
--      tnl = YMALLOC(sizeof(yaffs_TnodeList));
--      if (!tnl) {
--              T(YAFFS_TRACE_ERROR,
--                (TSTR
--                 ("yaffs: Could not add tnodes to management list" TENDSTR)));
--                 return YAFFS_FAIL;
--      } else {
--              tnl->tnodes = newTnodes;
--              tnl->next = dev->allocatedTnodeList;
--              dev->allocatedTnodeList = tnl;
--      }
--
--      T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
--
--      return YAFFS_OK;
--}
--
--/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
--
--static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
--{
--      yaffs_Tnode *tn = NULL;
--
--      /* If there are none left make more */
--      if (!dev->freeTnodes)
--              yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
--
--      if (dev->freeTnodes) {
--              tn = dev->freeTnodes;
--#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
--              if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
--                      /* Hoosterman, this thing looks like it isn't in the list */
--                      T(YAFFS_TRACE_ALWAYS,
--                        (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
--              }
--#endif
--              dev->freeTnodes = dev->freeTnodes->internal[0];
--              dev->nFreeTnodes--;
--      }
--
--      dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
--
--      return tn;
--}
--
--static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
--{
--      yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
--      int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
--
--      if (tnodeSize < sizeof(yaffs_Tnode))
--              tnodeSize = sizeof(yaffs_Tnode);
--
--      if (tn)
--              memset(tn, 0, tnodeSize);
--
--      return tn;
--}
--
--/* FreeTnode frees up a tnode and puts it back on the free list */
--static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
--{
--      if (tn) {
--#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
--              if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
--                      /* Hoosterman, this thing looks like it is already in the list */
--                      T(YAFFS_TRACE_ALWAYS,
--                        (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
--              }
--              tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
--#endif
--              tn->internal[0] = dev->freeTnodes;
--              dev->freeTnodes = tn;
--              dev->nFreeTnodes++;
--      }
--      dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
--}
--
--static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)
--{
--      /* Free the list of allocated tnodes */
--      yaffs_TnodeList *tmp;
--
--      while (dev->allocatedTnodeList) {
--              tmp = dev->allocatedTnodeList->next;
--
--              YFREE(dev->allocatedTnodeList->tnodes);
--              YFREE(dev->allocatedTnodeList);
--              dev->allocatedTnodeList = tmp;
--
--      }
--
--      dev->freeTnodes = NULL;
--      dev->nFreeTnodes = 0;
--}
--
--static void yaffs_InitialiseTnodes(yaffs_Device *dev)
--{
--      dev->allocatedTnodeList = NULL;
--      dev->freeTnodes = NULL;
--      dev->nFreeTnodes = 0;
--      dev->nTnodesCreated = 0;
--}
--
--
--void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
--              unsigned val)
--{
--      __u32 *map = (__u32 *)tn;
--      __u32 bitInMap;
--      __u32 bitInWord;
--      __u32 wordInMap;
--      __u32 mask;
--
--      pos &= YAFFS_TNODES_LEVEL0_MASK;
--      val >>= dev->chunkGroupBits;
--
--      bitInMap = pos * dev->tnodeWidth;
--      wordInMap = bitInMap / 32;
--      bitInWord = bitInMap & (32 - 1);
--
--      mask = dev->tnodeMask << bitInWord;
--
--      map[wordInMap] &= ~mask;
--      map[wordInMap] |= (mask & (val << bitInWord));
--
--      if (dev->tnodeWidth > (32 - bitInWord)) {
--              bitInWord = (32 - bitInWord);
--              wordInMap++;;
--              mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
--              map[wordInMap] &= ~mask;
--              map[wordInMap] |= (mask & (val >> bitInWord));
--      }
--}
--
--static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
--              unsigned pos)
--{
--      __u32 *map = (__u32 *)tn;
--      __u32 bitInMap;
--      __u32 bitInWord;
--      __u32 wordInMap;
--      __u32 val;
--
--      pos &= YAFFS_TNODES_LEVEL0_MASK;
--
--      bitInMap = pos * dev->tnodeWidth;
--      wordInMap = bitInMap / 32;
--      bitInWord = bitInMap & (32 - 1);
--
--      val = map[wordInMap] >> bitInWord;
--
--      if      (dev->tnodeWidth > (32 - bitInWord)) {
--              bitInWord = (32 - bitInWord);
--              wordInMap++;;
--              val |= (map[wordInMap] << bitInWord);
--      }
--
--      val &= dev->tnodeMask;
--      val <<= dev->chunkGroupBits;
--
--      return val;
--}
--
--/* ------------------- End of individual tnode manipulation -----------------*/
--
--/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
-- * The look up tree is represented by the top tnode and the number of topLevel
-- * in the tree. 0 means only the level 0 tnode is in the tree.
-- */
--
--/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
--static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
--                                      yaffs_FileStructure *fStruct,
--                                      __u32 chunkId)
--{
--      yaffs_Tnode *tn = fStruct->top;
--      __u32 i;
--      int requiredTallness;
--      int level = fStruct->topLevel;
--
--      /* Check sane level and chunk Id */
--      if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
--              return NULL;
--
--      if (chunkId > YAFFS_MAX_CHUNK_ID)
--              return NULL;
--
--      /* First check we're tall enough (ie enough topLevel) */
--
--      i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
--      requiredTallness = 0;
--      while (i) {
--              i >>= YAFFS_TNODES_INTERNAL_BITS;
--              requiredTallness++;
--      }
--
--      if (requiredTallness > fStruct->topLevel)
--              return NULL; /* Not tall enough, so we can't find it */
--
--      /* Traverse down to level 0 */
--      while (level > 0 && tn) {
--              tn = tn->internal[(chunkId >>
--                      (YAFFS_TNODES_LEVEL0_BITS +
--                              (level - 1) *
--                              YAFFS_TNODES_INTERNAL_BITS)) &
--                      YAFFS_TNODES_INTERNAL_MASK];
--              level--;
--      }
--
--      return tn;
--}
--
--/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
-- * This happens in two steps:
-- *  1. If the tree isn't tall enough, then make it taller.
-- *  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
-- *
-- * Used when modifying the tree.
-- *
-- *  If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
-- *  be plugged into the ttree.
-- */
--
--static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
--                                      yaffs_FileStructure *fStruct,
--                                      __u32 chunkId,
--                                      yaffs_Tnode *passedTn)
--{
--      int requiredTallness;
--      int i;
--      int l;
--      yaffs_Tnode *tn;
--
--      __u32 x;
--
--
--      /* Check sane level and page Id */
--      if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
--              return NULL;
--
--      if (chunkId > YAFFS_MAX_CHUNK_ID)
--              return NULL;
--
--      /* First check we're tall enough (ie enough topLevel) */
--
--      x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
--      requiredTallness = 0;
--      while (x) {
--              x >>= YAFFS_TNODES_INTERNAL_BITS;
--              requiredTallness++;
--      }
--
--
--      if (requiredTallness > fStruct->topLevel) {
--              /* Not tall enough, gotta make the tree taller */
--              for (i = fStruct->topLevel; i < requiredTallness; i++) {
--
--                      tn = yaffs_GetTnode(dev);
--
--                      if (tn) {
--                              tn->internal[0] = fStruct->top;
--                              fStruct->top = tn;
--                      } else {
--                              T(YAFFS_TRACE_ERROR,
--                                (TSTR("yaffs: no more tnodes" TENDSTR)));
--                      }
--              }
--
--              fStruct->topLevel = requiredTallness;
--      }
--
--      /* Traverse down to level 0, adding anything we need */
--
--      l = fStruct->topLevel;
--      tn = fStruct->top;
--
--      if (l > 0) {
--              while (l > 0 && tn) {
--                      x = (chunkId >>
--                           (YAFFS_TNODES_LEVEL0_BITS +
--                            (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
--                          YAFFS_TNODES_INTERNAL_MASK;
--
--
--                      if ((l > 1) && !tn->internal[x]) {
--                              /* Add missing non-level-zero tnode */
--                              tn->internal[x] = yaffs_GetTnode(dev);
--
--                      } else if (l == 1) {
--                              /* Looking from level 1 at level 0 */
--                              if (passedTn) {
--                                      /* If we already have one, then release it.*/
--                                      if (tn->internal[x])
--                                              yaffs_FreeTnode(dev, tn->internal[x]);
--                                      tn->internal[x] = passedTn;
--
--                              } else if (!tn->internal[x]) {
--                                      /* Don't have one, none passed in */
--                                      tn->internal[x] = yaffs_GetTnode(dev);
--                              }
--                      }
--
--                      tn = tn->internal[x];
--                      l--;
--              }
--      } else {
--              /* top is level 0 */
--              if (passedTn) {
--                      memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
--                      yaffs_FreeTnode(dev, passedTn);
--              }
--      }
--
--      return tn;
--}
--
--static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
--                              yaffs_ExtendedTags *tags, int objectId,
--                              int chunkInInode)
--{
--      int j;
--
--      for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
--              if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
--                              theChunk % dev->nChunksPerBlock)) {
--                      yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
--                                                      tags);
--                      if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
--                              /* found it; */
--                              return theChunk;
--                      }
--              }
--              theChunk++;
--      }
--      return -1;
--}
--
--
--/* DeleteWorker scans backwards through the tnode tree and deletes all the
-- * chunks and tnodes in the file
-- * Returns 1 if the tree was deleted.
-- * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
-- */
--
--static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
--                            int chunkOffset, int *limit)
--{
--      int i;
--      int chunkInInode;
--      int theChunk;
--      yaffs_ExtendedTags tags;
--      int foundChunk;
--      yaffs_Device *dev = in->myDev;
--
--      int allDone = 1;
--
--      if (tn) {
--              if (level > 0) {
--                      for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
--                           i--) {
--                              if (tn->internal[i]) {
--                                      if (limit && (*limit) < 0) {
--                                              allDone = 0;
--                                      } else {
--                                              allDone =
--                                                      yaffs_DeleteWorker(in,
--                                                              tn->
--                                                              internal
--                                                              [i],
--                                                              level -
--                                                              1,
--                                                              (chunkOffset
--                                                                      <<
--                                                                      YAFFS_TNODES_INTERNAL_BITS)
--                                                              + i,
--                                                              limit);
--                                      }
--                                      if (allDone) {
--                                              yaffs_FreeTnode(dev,
--                                                              tn->
--                                                              internal[i]);
--                                              tn->internal[i] = NULL;
--                                      }
--                              }
--                      }
--                      return (allDone) ? 1 : 0;
--              } else if (level == 0) {
--                      int hitLimit = 0;
--
--                      for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
--                                      i--) {
--                              theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
--                              if (theChunk) {
--
--                                      chunkInInode = (chunkOffset <<
--                                              YAFFS_TNODES_LEVEL0_BITS) + i;
--
--                                      foundChunk =
--                                              yaffs_FindChunkInGroup(dev,
--                                                              theChunk,
--                                                              &tags,
--                                                              in->objectId,
--                                                              chunkInInode);
--
--                                      if (foundChunk > 0) {
--                                              yaffs_DeleteChunk(dev,
--                                                                foundChunk, 1,
--                                                                __LINE__);
--                                              in->nDataChunks--;
--                                              if (limit) {
--                                                      *limit = *limit - 1;
--                                                      if (*limit <= 0)
--                                                              hitLimit = 1;
--                                              }
--
--                                      }
--
--                                      yaffs_PutLevel0Tnode(dev, tn, i, 0);
--                              }
--
--                      }
--                      return (i < 0) ? 1 : 0;
--
--              }
--
--      }
--
--      return 1;
--
--}
--
--static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
--{
--      yaffs_BlockInfo *theBlock;
--
--      T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
--
--      theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
--      if (theBlock) {
--              theBlock->softDeletions++;
--              dev->nFreeChunks++;
--      }
--}
--
--/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
-- * All soft deleting does is increment the block's softdelete count and pulls the chunk out
-- * of the tnode.
-- * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
-- */
--
--static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
--                                __u32 level, int chunkOffset)
--{
--      int i;
--      int theChunk;
--      int allDone = 1;
--      yaffs_Device *dev = in->myDev;
--
--      if (tn) {
--              if (level > 0) {
--
--                      for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
--                           i--) {
--                              if (tn->internal[i]) {
--                                      allDone =
--                                          yaffs_SoftDeleteWorker(in,
--                                                                 tn->
--                                                                 internal[i],
--                                                                 level - 1,
--                                                                 (chunkOffset
--                                                                  <<
--                                                                  YAFFS_TNODES_INTERNAL_BITS)
--                                                                 + i);
--                                      if (allDone) {
--                                              yaffs_FreeTnode(dev,
--                                                              tn->
--                                                              internal[i]);
--                                              tn->internal[i] = NULL;
--                                      } else {
--                                              /* Hoosterman... how could this happen? */
--                                      }
--                              }
--                      }
--                      return (allDone) ? 1 : 0;
--              } else if (level == 0) {
--
--                      for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
--                              theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
--                              if (theChunk) {
--                                      /* Note this does not find the real chunk, only the chunk group.
--                                       * We make an assumption that a chunk group is not larger than
--                                       * a block.
--                                       */
--                                      yaffs_SoftDeleteChunk(dev, theChunk);
--                                      yaffs_PutLevel0Tnode(dev, tn, i, 0);
--                              }
--
--                      }
--                      return 1;
--
--              }
--
--      }
--
--      return 1;
--
--}
--
--static void yaffs_SoftDeleteFile(yaffs_Object *obj)
--{
--      if (obj->deleted &&
--          obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
--              if (obj->nDataChunks <= 0) {
--                      /* Empty file with no duplicate object headers, just delete it immediately */
--                      yaffs_FreeTnode(obj->myDev,
--                                      obj->variant.fileVariant.top);
--                      obj->variant.fileVariant.top = NULL;
--                      T(YAFFS_TRACE_TRACING,
--                        (TSTR("yaffs: Deleting empty file %d" TENDSTR),
--                         obj->objectId));
--                      yaffs_DoGenericObjectDeletion(obj);
--              } else {
--                      yaffs_SoftDeleteWorker(obj,
--                                             obj->variant.fileVariant.top,
--                                             obj->variant.fileVariant.
--                                             topLevel, 0);
--                      obj->softDeleted = 1;
--              }
--      }
--}
--
--/* Pruning removes any part of the file structure tree that is beyond the
-- * bounds of the file (ie that does not point to chunks).
-- *
-- * A file should only get pruned when its size is reduced.
-- *
-- * Before pruning, the chunks must be pulled from the tree and the
-- * level 0 tnode entries must be zeroed out.
-- * Could also use this for file deletion, but that's probably better handled
-- * by a special case.
-- */
--
--static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
--                              __u32 level, int del0)
--{
--      int i;
--      int hasData;
--
--      if (tn) {
--              hasData = 0;
--
--              for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
--                      if (tn->internal[i] && level > 0) {
--                              tn->internal[i] =
--                                  yaffs_PruneWorker(dev, tn->internal[i],
--                                                    level - 1,
--                                                    (i == 0) ? del0 : 1);
--                      }
--
--                      if (tn->internal[i])
--                              hasData++;
--              }
--
--              if (hasData == 0 && del0) {
--                      /* Free and return NULL */
--
--                      yaffs_FreeTnode(dev, tn);
--                      tn = NULL;
--              }
--
--      }
--
--      return tn;
--
--}
--
--static int yaffs_PruneFileStructure(yaffs_Device *dev,
--                              yaffs_FileStructure *fStruct)
--{
--      int i;
--      int hasData;
--      int done = 0;
--      yaffs_Tnode *tn;
--
--      if (fStruct->topLevel > 0) {
--              fStruct->top =
--                  yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
--
--              /* Now we have a tree with all the non-zero branches NULL but the height
--               * is the same as it was.
--               * Let's see if we can trim internal tnodes to shorten the tree.
--               * We can do this if only the 0th element in the tnode is in use
--               * (ie all the non-zero are NULL)
--               */
--
--              while (fStruct->topLevel && !done) {
--                      tn = fStruct->top;
--
--                      hasData = 0;
--                      for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
--                              if (tn->internal[i])
--                                      hasData++;
--                      }
--
--                      if (!hasData) {
--                              fStruct->top = tn->internal[0];
--                              fStruct->topLevel--;
--                              yaffs_FreeTnode(dev, tn);
--                      } else {
--                              done = 1;
--                      }
--              }
--      }
--
--      return YAFFS_OK;
--}
--
--/*-------------------- End of File Structure functions.-------------------*/
--
--/* yaffs_CreateFreeObjects creates a bunch more objects and
-- * adds them to the object free list.
-- */
--static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
--{
--      int i;
--      yaffs_Object *newObjects;
--      yaffs_ObjectList *list;
--
--      if (nObjects < 1)
--              return YAFFS_OK;
--
--      /* make these things */
--      newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
--      list = YMALLOC(sizeof(yaffs_ObjectList));
--
--      if (!newObjects || !list) {
--              if (newObjects)
--                      YFREE(newObjects);
--              if (list)
--                      YFREE(list);
--              T(YAFFS_TRACE_ALLOCATE,
--                (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
--              return YAFFS_FAIL;
--      }
--
--      /* Hook them into the free list */
--      for (i = 0; i < nObjects - 1; i++) {
--              newObjects[i].siblings.next =
--                              (struct ylist_head *)(&newObjects[i + 1]);
--      }
--
--      newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
--      dev->freeObjects = newObjects;
--      dev->nFreeObjects += nObjects;
--      dev->nObjectsCreated += nObjects;
--
--      /* Now add this bunch of Objects to a list for freeing up. */
--
--      list->objects = newObjects;
--      list->next = dev->allocatedObjectList;
--      dev->allocatedObjectList = list;
--
--      return YAFFS_OK;
--}
--
--
--/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
--static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
--{
--      yaffs_Object *tn = NULL;
--
--#ifdef VALGRIND_TEST
--      tn = YMALLOC(sizeof(yaffs_Object));
--#else
--      /* If there are none left make more */
--      if (!dev->freeObjects)
--              yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
--
--      if (dev->freeObjects) {
--              tn = dev->freeObjects;
--              dev->freeObjects =
--                      (yaffs_Object *) (dev->freeObjects->siblings.next);
--              dev->nFreeObjects--;
--      }
--#endif
--      if (tn) {
--              /* Now sweeten it up... */
--
--              memset(tn, 0, sizeof(yaffs_Object));
--              tn->beingCreated = 1;
--
--              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);
--
--
--              /* Now make the directory sane */
--              if (dev->rootDir) {
--                      tn->parent = dev->rootDir;
--                      ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children);
--              }
--
--              /* Add it to the lost and found directory.
--               * NB Can't put root or lostNFound in lostNFound so
--               * check if lostNFound exists first
--               */
--              if (dev->lostNFoundDir)
--                      yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
--
--              tn->beingCreated = 0;
--      }
--
--      dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
--
--      return tn;
--}
--
--static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
--                                             __u32 mode)
--{
--
--      yaffs_Object *obj =
--          yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
--      if (obj) {
--              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->hdrChunk = 0;      /* Not a valid chunk. */
--      }
--
--      return obj;
--
--}
--
--static void yaffs_UnhashObject(yaffs_Object *tn)
--{
--      int bucket;
--      yaffs_Device *dev = tn->myDev;
--
--      /* If it is still linked into the bucket list, free from the list */
--      if (!ylist_empty(&tn->hashLink)) {
--              ylist_del_init(&tn->hashLink);
--              bucket = yaffs_HashFunction(tn->objectId);
--              dev->objectBucket[bucket].count--;
--      }
--}
--
--/*  FreeObject frees up a Object and puts it back on the free list */
--static void yaffs_FreeObject(yaffs_Object *tn)
--{
--      yaffs_Device *dev = tn->myDev;
--
--#ifdef __KERNEL__
--      T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
--#endif
--
--      if (tn->parent)
--              YBUG();
--      if (!ylist_empty(&tn->siblings))
--              YBUG();
--
--
--#ifdef __KERNEL__
--      if (tn->myInode) {
--              /* We're still hooked up to a cached inode.
--               * Don't delete now, but mark for later deletion
--               */
--              tn->deferedFree = 1;
--              return;
--      }
--#endif
--
--      yaffs_UnhashObject(tn);
--
--#ifdef VALGRIND_TEST
--      YFREE(tn);
--#else
--      /* Link into the free list. */
--      tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
--      dev->freeObjects = tn;
--      dev->nFreeObjects++;
--#endif
--      dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
--}
--
--#ifdef __KERNEL__
--
--void yaffs_HandleDeferedFree(yaffs_Object *obj)
--{
--      if (obj->deferedFree)
--              yaffs_FreeObject(obj);
--}
--
--#endif
--
--static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
--{
--      /* Free the list of allocated Objects */
--
--      yaffs_ObjectList *tmp;
--
--      while (dev->allocatedObjectList) {
--              tmp = dev->allocatedObjectList->next;
--              YFREE(dev->allocatedObjectList->objects);
--              YFREE(dev->allocatedObjectList);
--
--              dev->allocatedObjectList = tmp;
--      }
--
--      dev->freeObjects = NULL;
--      dev->nFreeObjects = 0;
--}
--
--static void yaffs_InitialiseObjects(yaffs_Device *dev)
--{
--      int i;
--
--      dev->allocatedObjectList = NULL;
--      dev->freeObjects = NULL;
--      dev->nFreeObjects = 0;
--
--      for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
--              YINIT_LIST_HEAD(&dev->objectBucket[i].list);
--              dev->objectBucket[i].count = 0;
--      }
--}
--
--static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
--{
--      static int x;
--      int i;
--      int l = 999;
--      int lowest = 999999;
--
--      /* First let's see if we can find one that's empty. */
--
--      for (i = 0; i < 10 && lowest > 0; i++) {
--              x++;
--              x %= YAFFS_NOBJECT_BUCKETS;
--              if (dev->objectBucket[x].count < lowest) {
--                      lowest = dev->objectBucket[x].count;
--                      l = x;
--              }
--
--      }
--
--      /* If we didn't find an empty list, then try
--       * looking a bit further for a short one
--       */
--
--      for (i = 0; i < 10 && lowest > 3; i++) {
--              x++;
--              x %= YAFFS_NOBJECT_BUCKETS;
--              if (dev->objectBucket[x].count < lowest) {
--                      lowest = dev->objectBucket[x].count;
--                      l = x;
--              }
--
--      }
--
--      return l;
--}
--
--static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
--{
--      int bucket = yaffs_FindNiceObjectBucket(dev);
--
--      /* Now find an object value that has not already been taken
--       * by scanning the list.
--       */
--
--      int found = 0;
--      struct ylist_head *i;
--
--      __u32 n = (__u32) bucket;
--
--      /* yaffs_CheckObjectHashSanity();  */
--
--      while (!found) {
--              found = 1;
--              n += YAFFS_NOBJECT_BUCKETS;
--              if (1 || dev->objectBucket[bucket].count > 0) {
--                      ylist_for_each(i, &dev->objectBucket[bucket].list) {
--                              /* If there is already one in the list */
--                              if (i && ylist_entry(i, yaffs_Object,
--                                              hashLink)->objectId == n) {
--                                      found = 0;
--                              }
--                      }
--              }
--      }
--
--      return n;
--}
--
--static void yaffs_HashObject(yaffs_Object *in)
--{
--      int bucket = yaffs_HashFunction(in->objectId);
--      yaffs_Device *dev = in->myDev;
--
--      ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
--      dev->objectBucket[bucket].count++;
--}
--
--yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
--{
--      int bucket = yaffs_HashFunction(number);
--      struct ylist_head *i;
--      yaffs_Object *in;
--
--      ylist_for_each(i, &dev->objectBucket[bucket].list) {
--              /* Look if it is in the list */
--              if (i) {
--                      in = ylist_entry(i, yaffs_Object, hashLink);
--                      if (in->objectId == number) {
--#ifdef __KERNEL__
--                              /* Don't tell the VFS about this one if it is defered free */
--                              if (in->deferedFree)
--                                      return NULL;
--#endif
--
--                              return in;
--                      }
--              }
--      }
--
--      return NULL;
--}
--
--yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
--                                  yaffs_ObjectType type)
--{
--      yaffs_Object *theObject;
--      yaffs_Tnode *tn = NULL;
--
--      if (number < 0)
--              number = yaffs_CreateNewObjectNumber(dev);
--
--      theObject = yaffs_AllocateEmptyObject(dev);
--      if (!theObject)
--              return NULL;
--
--      if (type == YAFFS_OBJECT_TYPE_FILE) {
--              tn = yaffs_GetTnode(dev);
--              if (!tn) {
--                      yaffs_FreeObject(theObject);
--                      return NULL;
--              }
--      }
--
--      if (theObject) {
--              theObject->fake = 0;
--              theObject->renameAllowed = 1;
--              theObject->unlinkAllowed = 1;
--              theObject->objectId = number;
--              yaffs_HashObject(theObject);
--              theObject->variantType = type;
--#ifdef CONFIG_YAFFS_WINCE
--              yfsd_WinFileTimeNow(theObject->win_atime);
--              theObject->win_ctime[0] = theObject->win_mtime[0] =
--                  theObject->win_atime[0];
--              theObject->win_ctime[1] = theObject->win_mtime[1] =
--                  theObject->win_atime[1];
--
--#else
--
--              theObject->yst_atime = theObject->yst_mtime =
--                  theObject->yst_ctime = Y_CURRENT_TIME;
--#endif
--              switch (type) {
--              case YAFFS_OBJECT_TYPE_FILE:
--                      theObject->variant.fileVariant.fileSize = 0;
--                      theObject->variant.fileVariant.scannedFileSize = 0;
--                      theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
--                      theObject->variant.fileVariant.topLevel = 0;
--                      theObject->variant.fileVariant.top = tn;
--                      break;
--              case YAFFS_OBJECT_TYPE_DIRECTORY:
--                      YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
--                                      children);
--                      break;
--              case YAFFS_OBJECT_TYPE_SYMLINK:
--              case YAFFS_OBJECT_TYPE_HARDLINK:
--              case YAFFS_OBJECT_TYPE_SPECIAL:
--                      /* No action required */
--                      break;
--              case YAFFS_OBJECT_TYPE_UNKNOWN:
--                      /* todo this should not happen */
--                      break;
--              }
--      }
--
--      return theObject;
--}
--
--static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
--                                                    int number,
--                                                    yaffs_ObjectType type)
--{
--      yaffs_Object *theObject = NULL;
--
--      if (number > 0)
--              theObject = yaffs_FindObjectByNumber(dev, number);
--
--      if (!theObject)
--              theObject = yaffs_CreateNewObject(dev, number, type);
--
--      return theObject;
--
--}
--
--
--static YCHAR *yaffs_CloneString(const YCHAR *str)
--{
--      YCHAR *newStr = NULL;
--
--      if (str && *str) {
--              newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
--              if (newStr)
--                      yaffs_strcpy(newStr, str);
--      }
--
--      return newStr;
--
--}
--
--/*
-- * Mknod (create) a new object.
-- * equivalentObject only has meaning for a hard link;
-- * aliasString only has meaning for a sumlink.
-- * rdev only has meaning for devices (a subset of special objects)
-- */
--
--static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
--                                     yaffs_Object *parent,
--                                     const YCHAR *name,
--                                     __u32 mode,
--                                     __u32 uid,
--                                     __u32 gid,
--                                     yaffs_Object *equivalentObject,
--                                     const YCHAR *aliasString, __u32 rdev)
--{
--      yaffs_Object *in;
--      YCHAR *str = NULL;
--
--      yaffs_Device *dev = parent->myDev;
--
--      /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
--      if (yaffs_FindObjectByName(parent, name))
--              return NULL;
--
--      in = yaffs_CreateNewObject(dev, -1, type);
--
--      if (!in)
--              return YAFFS_FAIL;
--
--      if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
--              str = yaffs_CloneString(aliasString);
--              if (!str) {
--                      yaffs_FreeObject(in);
--                      return NULL;
--              }
--      }
--
--
--
--      if (in) {
--              in->hdrChunk = 0;
--              in->valid = 1;
--              in->variantType = type;
--
--              in->yst_mode = mode;
--
--#ifdef CONFIG_YAFFS_WINCE
--              yfsd_WinFileTimeNow(in->win_atime);
--              in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
--              in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
--
--#else
--              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;
--
--              yaffs_SetObjectName(in, name);
--              in->dirty = 1;
--
--              yaffs_AddObjectToDirectory(parent, in);
--
--              in->myDev = parent->myDev;
--
--              switch (type) {
--              case YAFFS_OBJECT_TYPE_SYMLINK:
--                      in->variant.symLinkVariant.alias = str;
--                      break;
--              case YAFFS_OBJECT_TYPE_HARDLINK:
--                      in->variant.hardLinkVariant.equivalentObject =
--                              equivalentObject;
--                      in->variant.hardLinkVariant.equivalentObjectId =
--                              equivalentObject->objectId;
--                      ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
--                      break;
--              case YAFFS_OBJECT_TYPE_FILE:
--              case YAFFS_OBJECT_TYPE_DIRECTORY:
--              case YAFFS_OBJECT_TYPE_SPECIAL:
--              case YAFFS_OBJECT_TYPE_UNKNOWN:
--                      /* do nothing */
--                      break;
--              }
--
--              if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
--                      /* Could not create the object header, fail the creation */
--                      yaffs_DeleteObject(in);
--                      in = NULL;
--              }
--
--      }
--
--      return in;
--}
--
--yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
--                      __u32 mode, __u32 uid, __u32 gid)
--{
--      return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
--                              uid, gid, NULL, NULL, 0);
--}
--
--yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
--                              __u32 mode, __u32 uid, __u32 gid)
--{
--      return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
--                               mode, uid, gid, NULL, NULL, 0);
--}
--
--yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
--                              __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
--{
--      return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
--                               uid, gid, NULL, NULL, rdev);
--}
--
--yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
--                              __u32 mode, __u32 uid, __u32 gid,
--                              const YCHAR *alias)
--{
--      return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
--                              uid, gid, NULL, alias, 0);
--}
--
--/* yaffs_Link returns the object id of the equivalent object.*/
--yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
--                      yaffs_Object *equivalentObject)
--{
--      /* Get the real object in case we were fed a hard link as an equivalent object */
--      equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
--
--      if (yaffs_MknodObject
--          (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
--           equivalentObject, NULL, 0)) {
--              return equivalentObject;
--      } else {
--              return NULL;
--      }
--
--}
--
--static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
--                              const YCHAR *newName, int force, int shadows)
--{
--      int unlinkOp;
--      int deleteOp;
--
--      yaffs_Object *existingTarget;
--
--      if (newDir == NULL)
--              newDir = obj->parent;   /* use the old directory */
--
--      if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
--              T(YAFFS_TRACE_ALWAYS,
--                (TSTR
--                 ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
--                  TENDSTR)));
--              YBUG();
--      }
--
--      /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
--      if (obj->myDev->isYaffs2)
--              unlinkOp = (newDir == obj->myDev->unlinkedDir);
--      else
--              unlinkOp = (newDir == obj->myDev->unlinkedDir
--                          && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
--
--      deleteOp = (newDir == obj->myDev->deletedDir);
--
--      existingTarget = yaffs_FindObjectByName(newDir, newName);
--
--      /* If the object is a file going into the unlinked directory,
--       *   then it is OK to just stuff it in since duplicate names are allowed.
--       *   else only proceed if the new name does not exist and if we're putting
--       *   it into a directory.
--       */
--      if ((unlinkOp ||
--           deleteOp ||
--           force ||
--           (shadows > 0) ||
--           !existingTarget) &&
--          newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
--              yaffs_SetObjectName(obj, newName);
--              obj->dirty = 1;
--
--              yaffs_AddObjectToDirectory(newDir, obj);
--
--              if (unlinkOp)
--                      obj->unlinked = 1;
--
--              /* If it is a deletion then we mark it as a shrink for gc purposes. */
--              if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0)
--                      return YAFFS_OK;
--      }
--
--      return YAFFS_FAIL;
--}
--
--int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
--              yaffs_Object *newDir, const YCHAR *newName)
--{
--      yaffs_Object *obj = NULL;
--      yaffs_Object *existingTarget = NULL;
--      int force = 0;
--
--
--      if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
--              YBUG();
--      if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
--              YBUG();
--
--#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
--      /* Special case for case insemsitive systems (eg. WinCE).
--       * While look-up is case insensitive, the name isn't.
--       * Therefore we might want to change x.txt to X.txt
--      */
--      if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
--              force = 1;
--#endif
--
--      else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
--              /* ENAMETOOLONG */
--              return YAFFS_FAIL;
--
--      obj = yaffs_FindObjectByName(oldDir, oldName);
--
--      if (obj && obj->renameAllowed) {
--
--              /* Now do the handling for an existing target, if there is one */
--
--              existingTarget = yaffs_FindObjectByName(newDir, newName);
--              if (existingTarget &&
--                      existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
--                      !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
--                      /* There is a target that is a non-empty directory, so we fail */
--                      return YAFFS_FAIL;      /* EEXIST or ENOTEMPTY */
--              } else if (existingTarget && existingTarget != obj) {
--                      /* Nuke the target first, using shadowing,
--                       * but only if it isn't the same object
--                       */
--                      yaffs_ChangeObjectName(obj, newDir, newName, force,
--                                              existingTarget->objectId);
--                      yaffs_UnlinkObject(existingTarget);
--              }
--
--              return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
--      }
--      return YAFFS_FAIL;
--}
--
--/*------------------------- Block Management and Page Allocation ----------------*/
--
--static int yaffs_InitialiseBlocks(yaffs_Device *dev)
--{
--      int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
--
--      dev->blockInfo = NULL;
--      dev->chunkBits = NULL;
--
--      dev->allocationBlock = -1;      /* force it to get a new one */
--
--      /* If the first allocation strategy fails, thry the alternate one */
--      dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
--      if (!dev->blockInfo) {
--              dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
--              dev->blockInfoAlt = 1;
--      } else
--              dev->blockInfoAlt = 0;
--
--      if (dev->blockInfo) {
--              /* Set up dynamic blockinfo stuff. */
--              dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
--              dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
--              if (!dev->chunkBits) {
--                      dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
--                      dev->chunkBitsAlt = 1;
--              } else
--                      dev->chunkBitsAlt = 0;
--      }
--
--      if (dev->blockInfo && dev->chunkBits) {
--              memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
--              memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
--              return YAFFS_OK;
--      }
--
--      return YAFFS_FAIL;
--}
--
--static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
--{
--      if (dev->blockInfoAlt && dev->blockInfo)
--              YFREE_ALT(dev->blockInfo);
--      else if (dev->blockInfo)
--              YFREE(dev->blockInfo);
--
--      dev->blockInfoAlt = 0;
--
--      dev->blockInfo = NULL;
--
--      if (dev->chunkBitsAlt && dev->chunkBits)
--              YFREE_ALT(dev->chunkBits);
--      else if (dev->chunkBits)
--              YFREE(dev->chunkBits);
--      dev->chunkBitsAlt = 0;
--      dev->chunkBits = NULL;
--}
--
--static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
--                                      yaffs_BlockInfo *bi)
--{
--      int i;
--      __u32 seq;
--      yaffs_BlockInfo *b;
--
--      if (!dev->isYaffs2)
--              return 1;       /* disqualification only applies to yaffs2. */
--
--      if (!bi->hasShrinkHeader)
--              return 1;       /* can gc */
--
--      /* Find the oldest dirty sequence number if we don't know it and save it
--       * so we don't have to keep recomputing it.
--       */
--      if (!dev->oldestDirtySequence) {
--              seq = dev->sequenceNumber;
--
--              for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
--                              i++) {
--                      b = yaffs_GetBlockInfo(dev, i);
--                      if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
--                          (b->pagesInUse - b->softDeletions) <
--                          dev->nChunksPerBlock && b->sequenceNumber < seq) {
--                              seq = b->sequenceNumber;
--                      }
--              }
--              dev->oldestDirtySequence = seq;
--      }
--
--      /* Can't do gc of this block if there are any blocks older than this one that have
--       * discarded pages.
--       */
--      return (bi->sequenceNumber <= dev->oldestDirtySequence);
--}
--
--/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
-- * for garbage collection.
-- */
--
--static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
--                                      int aggressive)
--{
--      int b = dev->currentDirtyChecker;
--
--      int i;
--      int iterations;
--      int dirtiest = -1;
--      int pagesInUse = 0;
--      int prioritised = 0;
--      yaffs_BlockInfo *bi;
--      int pendingPrioritisedExist = 0;
--
--      /* First let's see if we need to grab a prioritised block */
--      if (dev->hasPendingPrioritisedGCs) {
--              for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) {
--
--                      bi = yaffs_GetBlockInfo(dev, i);
--                      /* yaffs_VerifyBlock(dev,bi,i); */
--
--                      if (bi->gcPrioritise) {
--                              pendingPrioritisedExist = 1;
--                              if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
--                                 yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
--                                      pagesInUse = (bi->pagesInUse - bi->softDeletions);
--                                      dirtiest = i;
--                                      prioritised = 1;
--                                      aggressive = 1; /* Fool the non-aggressive skip logiv below */
--                              }
--                      }
--              }
--
--              if (!pendingPrioritisedExist) /* None found, so we can clear this */
--                      dev->hasPendingPrioritisedGCs = 0;
--      }
--
--      /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
--       * search harder.
--       * else (we're doing a leasurely gc), then we only bother to do this if the
--       * block has only a few pages in use.
--       */
--
--      dev->nonAggressiveSkip--;
--
--      if (!aggressive && (dev->nonAggressiveSkip > 0))
--              return -1;
--
--      if (!prioritised)
--              pagesInUse =
--                      (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
--
--      if (aggressive)
--              iterations =
--                  dev->internalEndBlock - dev->internalStartBlock + 1;
--      else {
--              iterations =
--                  dev->internalEndBlock - dev->internalStartBlock + 1;
--              iterations = iterations / 16;
--              if (iterations > 200)
--                      iterations = 200;
--      }
--
--      for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
--              b++;
--              if (b < dev->internalStartBlock || b > dev->internalEndBlock)
--                      b = dev->internalStartBlock;
--
--              if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
--                      T(YAFFS_TRACE_ERROR,
--                        (TSTR("**>> Block %d is not valid" TENDSTR), b));
--                      YBUG();
--              }
--
--              bi = yaffs_GetBlockInfo(dev, b);
--
--              if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
--                      (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
--                              yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
--                      dirtiest = b;
--                      pagesInUse = (bi->pagesInUse - bi->softDeletions);
--              }
--      }
--
--      dev->currentDirtyChecker = b;
--
--      if (dirtiest > 0) {
--              T(YAFFS_TRACE_GC,
--                (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
--                 dev->nChunksPerBlock - pagesInUse, prioritised));
--      }
--
--      dev->oldestDirtySequence = 0;
--
--      if (dirtiest > 0)
--              dev->nonAggressiveSkip = 4;
--
--      return dirtiest;
--}
--
--static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
--{
--      yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
--
--      int erasedOk = 0;
--
--      /* If the block is still healthy erase it and mark as clean.
--       * If the block has had a data failure, then retire it.
--       */
--
--      T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
--              (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
--              blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
--
--      bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
--
--      if (!bi->needsRetiring) {
--              yaffs_InvalidateCheckpoint(dev);
--              erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
--              if (!erasedOk) {
--                      dev->nErasureFailures++;
--                      T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
--                        (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
--              }
--      }
--
--      if (erasedOk &&
--          ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
--              int i;
--              for (i = 0; i < dev->nChunksPerBlock; i++) {
--                      if (!yaffs_CheckChunkErased
--                          (dev, blockNo * dev->nChunksPerBlock + i)) {
--                              T(YAFFS_TRACE_ERROR,
--                                (TSTR
--                                 (">>Block %d erasure supposedly OK, but chunk %d not erased"
--                                  TENDSTR), blockNo, i));
--                      }
--              }
--      }
--
--      if (erasedOk) {
--              /* Clean it up... */
--              bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
--              dev->nErasedBlocks++;
--              bi->pagesInUse = 0;
--              bi->softDeletions = 0;
--              bi->hasShrinkHeader = 0;
--              bi->skipErasedCheck = 1;  /* This is clean, so no need to check */
--              bi->gcPrioritise = 0;
--              yaffs_ClearChunkBits(dev, blockNo);
--
--              T(YAFFS_TRACE_ERASE,
--                (TSTR("Erased block %d" TENDSTR), blockNo));
--      } 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));
--      }
--}
--
--static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
--{
--      int i;
--
--      yaffs_BlockInfo *bi;
--
--      if (dev->nErasedBlocks < 1) {
--              /* Hoosterman we've got a problem.
--               * Can't get space to gc
--               */
--              T(YAFFS_TRACE_ERROR,
--                (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
--
--              return -1;
--      }
--
--      /* Find an empty block. */
--
--      for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
--              dev->allocationBlockFinder++;
--              if (dev->allocationBlockFinder < dev->internalStartBlock
--                  || dev->allocationBlockFinder > dev->internalEndBlock) {
--                      dev->allocationBlockFinder = dev->internalStartBlock;
--              }
--
--              bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
--
--              if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
--                      bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
--                      dev->sequenceNumber++;
--                      bi->sequenceNumber = dev->sequenceNumber;
--                      dev->nErasedBlocks--;
--                      T(YAFFS_TRACE_ALLOCATE,
--                        (TSTR("Allocated block %d, seq  %d, %d left" TENDSTR),
--                         dev->allocationBlockFinder, dev->sequenceNumber,
--                         dev->nErasedBlocks));
--                      return dev->allocationBlockFinder;
--              }
--      }
--
--      T(YAFFS_TRACE_ALWAYS,
--        (TSTR
--         ("yaffs tragedy: no more erased blocks, but there should have been %d"
--          TENDSTR), dev->nErasedBlocks));
--
--      return -1;
--}
--
--
--
--static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
--{
--      if (!dev->nCheckpointBlocksRequired &&
--         dev->isYaffs2) {
--              /* Not a valid value so recalculate */
--              int nBytes = 0;
--              int nBlocks;
--              int devBlocks = (dev->endBlock - dev->startBlock + 1);
--              int tnodeSize;
--
--              tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
--
--              if (tnodeSize < sizeof(yaffs_Tnode))
--                      tnodeSize = sizeof(yaffs_Tnode);
--
--              nBytes += sizeof(yaffs_CheckpointValidity);
--              nBytes += sizeof(yaffs_CheckpointDevice);
--              nBytes += devBlocks * sizeof(yaffs_BlockInfo);
--              nBytes += devBlocks * dev->chunkBitmapStride;
--              nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);
--              nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);
--              nBytes += sizeof(yaffs_CheckpointValidity);
--              nBytes += sizeof(__u32); /* checksum*/
--
--              /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
--
--              nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3;
--
--              dev->nCheckpointBlocksRequired = nBlocks;
--      }
--
--      return dev->nCheckpointBlocksRequired;
--}
--
--/*
-- * Check if there's space to allocate...
-- * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
-- */
--static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
--{
--      int reservedChunks;
--      int reservedBlocks = dev->nReservedBlocks;
--      int checkpointBlocks;
--
--      if (dev->isYaffs2) {
--              checkpointBlocks =  yaffs_CalcCheckpointBlocksRequired(dev) -
--                                  dev->blocksInCheckpoint;
--              if (checkpointBlocks < 0)
--                      checkpointBlocks = 0;
--      } else {
--              checkpointBlocks = 0;
--      }
--
--      reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
--
--      return (dev->nFreeChunks > reservedChunks);
--}
--
--static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
--              yaffs_BlockInfo **blockUsedPtr)
--{
--      int retVal;
--      yaffs_BlockInfo *bi;
--
--      if (dev->allocationBlock < 0) {
--              /* Get next block to allocate off */
--              dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
--              dev->allocationPage = 0;
--      }
--
--      if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
--              /* Not enough space to allocate unless we're allowed to use the reserve. */
--              return -1;
--      }
--
--      if (dev->nErasedBlocks < dev->nReservedBlocks
--                      && dev->allocationPage == 0) {
--              T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
--      }
--
--      /* Next page please.... */
--      if (dev->allocationBlock >= 0) {
--              bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
--
--              retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
--                      dev->allocationPage;
--              bi->pagesInUse++;
--              yaffs_SetChunkBit(dev, dev->allocationBlock,
--                              dev->allocationPage);
--
--              dev->allocationPage++;
--
--              dev->nFreeChunks--;
--
--              /* If the block is full set the state to full */
--              if (dev->allocationPage >= dev->nChunksPerBlock) {
--                      bi->blockState = YAFFS_BLOCK_STATE_FULL;
--                      dev->allocationBlock = -1;
--              }
--
--              if (blockUsedPtr)
--                      *blockUsedPtr = bi;
--
--              return retVal;
--      }
--
--      T(YAFFS_TRACE_ERROR,
--                      (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
--
--      return -1;
--}
--
--static int yaffs_GetErasedChunks(yaffs_Device *dev)
--{
--      int n;
--
--      n = dev->nErasedBlocks * dev->nChunksPerBlock;
--
--      if (dev->allocationBlock > 0)
--              n += (dev->nChunksPerBlock - dev->allocationPage);
--
--      return n;
--
--}
--
--static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
--              int wholeBlock)
--{
--      int oldChunk;
--      int newChunk;
--      int markNAND;
--      int retVal = YAFFS_OK;
--      int cleanups = 0;
--      int i;
--      int isCheckpointBlock;
--      int matchingChunk;
--      int maxCopies;
--
--      int chunksBefore = yaffs_GetErasedChunks(dev);
--      int chunksAfter;
--
--      yaffs_ExtendedTags tags;
--
--      yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
--
--      yaffs_Object *object;
--
--      isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
--
--      bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
--
--      T(YAFFS_TRACE_TRACING,
--                      (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
--                       block,
--                       bi->pagesInUse,
--                       bi->hasShrinkHeader,
--                       wholeBlock));
--
--      /*yaffs_VerifyFreeChunks(dev); */
--
--      bi->hasShrinkHeader = 0;        /* clear the flag so that the block can erase */
--
--      /* Take off the number of soft deleted entries because
--       * they're going to get really deleted during GC.
--       */
--      dev->nFreeChunks -= bi->softDeletions;
--
--      dev->isDoingGC = 1;
--
--      if (isCheckpointBlock ||
--                      !yaffs_StillSomeChunkBits(dev, block)) {
--              T(YAFFS_TRACE_TRACING,
--                              (TSTR
--                               ("Collecting block %d that has no chunks in use" TENDSTR),
--                               block));
--              yaffs_BlockBecameDirty(dev, block);
--      } else {
--
--              __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
--
--              yaffs_VerifyBlock(dev, bi, block);
--
--              maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10;
--              oldChunk = block * dev->nChunksPerBlock + dev->gcChunk;
--
--              for (/* init already done */;
--                   retVal == YAFFS_OK &&
--                   dev->gcChunk < dev->nChunksPerBlock &&
--                   (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
--                   maxCopies > 0;
--                   dev->gcChunk++, oldChunk++) {
--                      if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
--
--                              /* This page is in use and might need to be copied off */
--
--                              maxCopies--;
--
--                              markNAND = 1;
--
--                              yaffs_InitialiseTags(&tags);
--
--                              yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
--                                                              buffer, &tags);
--
--                              object =
--                                  yaffs_FindObjectByNumber(dev,
--                                                           tags.objectId);
--
--                              T(YAFFS_TRACE_GC_DETAIL,
--                                (TSTR
--                                 ("Collecting chunk in block %d, %d %d %d " TENDSTR),
--                                 dev->gcChunk, tags.objectId, tags.chunkId,
--                                 tags.byteCount));
--
--                              if (object && !yaffs_SkipVerification(dev)) {
--                                      if (tags.chunkId == 0)
--                                              matchingChunk = object->hdrChunk;
--                                      else if (object->softDeleted)
--                                              matchingChunk = oldChunk; /* Defeat the test */
--                                      else
--                                              matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
--
--                                      if (oldChunk != matchingChunk)
--                                              T(YAFFS_TRACE_ERROR,
--                                                (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
--                                                oldChunk, matchingChunk, tags.objectId, tags.chunkId));
--
--                              }
--
--                              if (!object) {
--                                      T(YAFFS_TRACE_ERROR,
--                                        (TSTR
--                                         ("page %d in gc has no object: %d %d %d "
--                                          TENDSTR), oldChunk,
--                                          tags.objectId, tags.chunkId, tags.byteCount));
--                              }
--
--                              if (object &&
--                                  object->deleted &&
--                                  object->softDeleted &&
--                                  tags.chunkId != 0) {
--                                      /* Data chunk in a soft deleted file, throw it away
--                                       * It's a soft deleted data chunk,
--                                       * No need to copy this, just forget about it and
--                                       * fix up the object.
--                                       */
--
--                                      object->nDataChunks--;
--
--                                      if (object->nDataChunks <= 0) {
--                                              /* remeber to clean up the object */
--                                              dev->gcCleanupList[cleanups] =
--                                                  tags.objectId;
--                                              cleanups++;
--                                      }
--                                      markNAND = 0;
--                              } else if (0) {
--                                      /* Todo object && object->deleted && object->nDataChunks == 0 */
--                                      /* Deleted object header with no data chunks.
--                                       * Can be discarded and the file deleted.
--                                       */
--                                      object->hdrChunk = 0;
--                                      yaffs_FreeTnode(object->myDev,
--                                                      object->variant.
--                                                      fileVariant.top);
--                                      object->variant.fileVariant.top = NULL;
--                                      yaffs_DoGenericObjectDeletion(object);
--
--                              } else if (object) {
--                                      /* It's either a data chunk in a live file or
--                                       * an ObjectHeader, so we're interested in it.
--                                       * NB Need to keep the ObjectHeaders of deleted files
--                                       * until the whole file has been deleted off
--                                       */
--                                      tags.serialNumber++;
--
--                                      dev->nGCCopies++;
--
--                                      if (tags.chunkId == 0) {
--                                              /* It is an object Id,
--                                               * We need to nuke the shrinkheader flags first
--                                               * We no longer want the shrinkHeader flag since its work is done
--                                               * and if it is left in place it will mess up scanning.
--                                               */
--
--                                              yaffs_ObjectHeader *oh;
--                                              oh = (yaffs_ObjectHeader *)buffer;
--                                              oh->isShrink = 0;
--                                              tags.extraIsShrinkHeader = 0;
--
--                                              yaffs_VerifyObjectHeader(object, oh, &tags, 1);
--                                      }
--
--                                      newChunk =
--                                          yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
--
--                                      if (newChunk < 0) {
--                                              retVal = YAFFS_FAIL;
--                                      } else {
--
--                                              /* Ok, now fix up the Tnodes etc. */
--
--                                              if (tags.chunkId == 0) {
--                                                      /* It's a header */
--                                                      object->hdrChunk =  newChunk;
--                                                      object->serial =   tags.serialNumber;
--                                              } else {
--                                                      /* It's a data chunk */
--                                                      yaffs_PutChunkIntoFile
--                                                          (object,
--                                                           tags.chunkId,
--                                                           newChunk, 0);
--                                              }
--                                      }
--                              }
--
--                              if (retVal == YAFFS_OK)
--                                      yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
--
--                      }
--              }
--
--              yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
--
--
--              /* Do any required cleanups */
--              for (i = 0; i < cleanups; i++) {
--                      /* Time to delete the file too */
--                      object =
--                          yaffs_FindObjectByNumber(dev,
--                                                   dev->gcCleanupList[i]);
--                      if (object) {
--                              yaffs_FreeTnode(dev,
--                                              object->variant.fileVariant.
--                                              top);
--                              object->variant.fileVariant.top = NULL;
--                              T(YAFFS_TRACE_GC,
--                                (TSTR
--                                 ("yaffs: About to finally delete object %d"
--                                  TENDSTR), object->objectId));
--                              yaffs_DoGenericObjectDeletion(object);
--                              object->myDev->nDeletedFiles--;
--                      }
--
--              }
--
--      }
--
--      yaffs_VerifyCollectedBlock(dev, bi, block);
-+      if (chunkId > YAFFS_MAX_CHUNK_ID)
-+              return NULL;
--      chunksAfter = yaffs_GetErasedChunks(dev);
--      if (chunksBefore >= chunksAfter) {
--              T(YAFFS_TRACE_GC,
--                (TSTR
--                 ("gc did not increase free chunks before %d after %d"
--                  TENDSTR), chunksBefore, chunksAfter));
--      }
-+      /* First check we're tall enough (ie enough topLevel) */
--      /* If the gc completed then clear the current gcBlock so that we find another. */
--      if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
--              dev->gcBlock = -1;
--              dev->gcChunk = 0;
-+      x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
-+      requiredTallness = 0;
-+      while (x) {
-+              x >>= YAFFS_TNODES_INTERNAL_BITS;
-+              requiredTallness++;
-       }
--      dev->isDoingGC = 0;
--
--      return retVal;
--}
--/* New garbage collector
-- * If we're very low on erased blocks then we do aggressive garbage collection
-- * otherwise we do "leasurely" garbage collection.
-- * Aggressive gc looks further (whole array) and will accept less dirty blocks.
-- * Passive gc only inspects smaller areas and will only accept more dirty blocks.
-- *
-- * The idea is to help clear out space in a more spread-out manner.
-- * Dunno if it really does anything useful.
-- */
--static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
--{
--      int block;
--      int aggressive;
--      int gcOk = YAFFS_OK;
--      int maxTries = 0;
-+      if (requiredTallness > fStruct->topLevel) {
-+              /* Not tall enough, gotta make the tree taller */
-+              for (i = fStruct->topLevel; i < requiredTallness; i++) {
--      int checkpointBlockAdjust;
-+                      tn = yaffs_GetTnode(dev);
--      if (dev->isDoingGC) {
--              /* Bail out so we don't get recursive gc */
--              return YAFFS_OK;
-+                      if (tn) {
-+                              tn->internal[0] = fStruct->top;
-+                              fStruct->top = tn;
-+                              fStruct->topLevel++;
-+                      } else {
-+                              T(YAFFS_TRACE_ERROR,
-+                                      (TSTR("yaffs: no more tnodes" TENDSTR)));
-+                              return NULL;
-+                      }
-+              }
-       }
--      /* This loop should pass the first time.
--       * We'll only see looping here if the erase of the collected block fails.
--       */
--
--      do {
--              maxTries++;
--
--              checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
--              if (checkpointBlockAdjust < 0)
--                      checkpointBlockAdjust = 0;
-+      /* Traverse down to level 0, adding anything we need */
--              if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
--                      /* We need a block soon...*/
--                      aggressive = 1;
--              } else {
--                      /* We're in no hurry */
--                      aggressive = 0;
--              }
-+      l = fStruct->topLevel;
-+      tn = fStruct->top;
--              if (dev->gcBlock <= 0) {
--                      dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
--                      dev->gcChunk = 0;
--              }
-+      if (l > 0) {
-+              while (l > 0 && tn) {
-+                      x = (chunkId >>
-+                           (YAFFS_TNODES_LEVEL0_BITS +
-+                            (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
-+                          YAFFS_TNODES_INTERNAL_MASK;
--              block = dev->gcBlock;
--              if (block > 0) {
--                      dev->garbageCollections++;
--                      if (!aggressive)
--                              dev->passiveGarbageCollections++;
-+                      if ((l > 1) && !tn->internal[x]) {
-+                              /* Add missing non-level-zero tnode */
-+                              tn->internal[x] = yaffs_GetTnode(dev);
-+                              if(!tn->internal[x])
-+                                      return NULL;
-+                      } else if (l == 1) {
-+                              /* Looking from level 1 at level 0 */
-+                              if (passedTn) {
-+                                      /* If we already have one, then release it.*/
-+                                      if (tn->internal[x])
-+                                              yaffs_FreeTnode(dev, tn->internal[x]);
-+                                      tn->internal[x] = passedTn;
--                      T(YAFFS_TRACE_GC,
--                        (TSTR
--                         ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
--                         dev->nErasedBlocks, aggressive));
-+                              } else if (!tn->internal[x]) {
-+                                      /* Don't have one, none passed in */
-+                                      tn->internal[x] = yaffs_GetTnode(dev);
-+                                      if(!tn->internal[x])
-+                                              return NULL;
-+                              }
-+                      }
--                      gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive);
-+                      tn = tn->internal[x];
-+                      l--;
-               }
--
--              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));
-+      } else {
-+              /* top is level 0 */
-+              if (passedTn) {
-+                      memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
-+                      yaffs_FreeTnode(dev, passedTn);
-               }
--      } while ((dev->nErasedBlocks < dev->nReservedBlocks) &&
--               (block > 0) &&
--               (maxTries < 2));
-+      }
--      return aggressive ? gcOk : YAFFS_OK;
-+      return tn;
- }
--/*-------------------------  TAGS --------------------------------*/
--
--static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
--                         int chunkInObject)
-+static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
-+                              yaffs_ExtendedTags *tags, int objectId,
-+                              int chunkInInode)
- {
--      return (tags->chunkId == chunkInObject &&
--              tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
-+      int j;
-+      for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
-+              if (yaffs_CheckChunkBit(dev, theChunk / dev->param.nChunksPerBlock,
-+                              theChunk % dev->param.nChunksPerBlock)) {
-+                      
-+                      if(dev->chunkGroupSize == 1)
-+                              return theChunk;
-+                      else {
-+                              yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
-+                                                              tags);
-+                              if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
-+                                      /* found it; */
-+                                      return theChunk;
-+                              }
-+                      }
-+              }
-+              theChunk++;
-+      }
-+      return -1;
- }
-+#if 0
-+/* Experimental code not being used yet. Might speed up file deletion */
-+/* DeleteWorker scans backwards through the tnode tree and deletes all the
-+ * chunks and tnodes in the file.
-+ * Returns 1 if the tree was deleted.
-+ * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
-+ */
--/*-------------------- Data file manipulation -----------------*/
--
--static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
--                               yaffs_ExtendedTags *tags)
-+static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
-+                            int chunkOffset, int *limit)
- {
--      /*Get the Tnode, then get the level 0 offset chunk offset */
--      yaffs_Tnode *tn;
--      int theChunk = -1;
--      yaffs_ExtendedTags localTags;
--      int retVal = -1;
--
-+      int i;
-+      int chunkInInode;
-+      int theChunk;
-+      yaffs_ExtendedTags tags;
-+      int foundChunk;
-       yaffs_Device *dev = in->myDev;
--      if (!tags) {
--              /* Passed a NULL, so use our own tags space */
--              tags = &localTags;
--      }
--
--      tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
-+      int allDone = 1;
-       if (tn) {
--              theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
-+              if (level > 0) {
-+                      for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
-+                           i--) {
-+                              if (tn->internal[i]) {
-+                                      if (limit && (*limit) < 0) {
-+                                              allDone = 0;
-+                                      } else {
-+                                              allDone =
-+                                                      yaffs_DeleteWorker(in,
-+                                                              tn->
-+                                                              internal
-+                                                              [i],
-+                                                              level -
-+                                                              1,
-+                                                              (chunkOffset
-+                                                                      <<
-+                                                                      YAFFS_TNODES_INTERNAL_BITS)
-+                                                              + i,
-+                                                              limit);
-+                                      }
-+                                      if (allDone) {
-+                                              yaffs_FreeTnode(dev,
-+                                                              tn->
-+                                                              internal[i]);
-+                                              tn->internal[i] = NULL;
-+                                      }
-+                              }
-+                      }
-+                      return (allDone) ? 1 : 0;
-+              } else if (level == 0) {
-+                      int hitLimit = 0;
--              retVal =
--                  yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
--                                         chunkInInode);
--      }
--      return retVal;
--}
-+                      for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
-+                                      i--) {
-+                              theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
-+                              if (theChunk) {
--static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
--                                        yaffs_ExtendedTags *tags)
--{
--      /* Get the Tnode, then get the level 0 offset chunk offset */
--      yaffs_Tnode *tn;
--      int theChunk = -1;
--      yaffs_ExtendedTags localTags;
-+                                      chunkInInode = (chunkOffset <<
-+                                              YAFFS_TNODES_LEVEL0_BITS) + i;
-+
-+                                      foundChunk =
-+                                              yaffs_FindChunkInGroup(dev,
-+                                                              theChunk,
-+                                                              &tags,
-+                                                              in->objectId,
-+                                                              chunkInInode);
-+
-+                                      if (foundChunk > 0) {
-+                                              yaffs_DeleteChunk(dev,
-+                                                                foundChunk, 1,
-+                                                                __LINE__);
-+                                              in->nDataChunks--;
-+                                              if (limit) {
-+                                                      *limit = *limit - 1;
-+                                                      if (*limit <= 0)
-+                                                              hitLimit = 1;
-+                                              }
--      yaffs_Device *dev = in->myDev;
--      int retVal = -1;
-+                                      }
-+
-+                                      yaffs_LoadLevel0Tnode(dev, tn, i, 0);
-+                              }
-+
-+                      }
-+                      return (i < 0) ? 1 : 0;
-+
-+              }
--      if (!tags) {
--              /* Passed a NULL, so use our own tags space */
--              tags = &localTags;
-       }
--      tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
-+      return 1;
--      if (tn) {
-+}
--              theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
-+#endif
--              retVal =
--                  yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
--                                         chunkInInode);
-+static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
-+{
-+      yaffs_BlockInfo *theBlock;
-+      unsigned blockNo;
--              /* Delete the entry in the filestructure (if found) */
--              if (retVal != -1)
--                      yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);
--      }
-+      T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
--      return retVal;
-+      blockNo =  chunk / dev->param.nChunksPerBlock;
-+      theBlock = yaffs_GetBlockInfo(dev, blockNo);
-+      if (theBlock) {
-+              theBlock->softDeletions++;
-+              dev->nFreeChunks++;
-+              yaffs2_UpdateOldestDirtySequence(dev, blockNo, theBlock);
-+      }
- }
--#ifdef YAFFS_PARANOID
-+/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
-+ * All soft deleting does is increment the block's softdelete count and pulls the chunk out
-+ * of the tnode.
-+ * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
-+ */
--static int yaffs_CheckFileSanity(yaffs_Object *in)
-+static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
-+                                __u32 level, int chunkOffset)
- {
--      int chunk;
--      int nChunks;
--      int fSize;
--      int failed = 0;
--      int objId;
--      yaffs_Tnode *tn;
--      yaffs_Tags localTags;
--      yaffs_Tags *tags = &localTags;
-+      int i;
-       int theChunk;
--      int chunkDeleted;
-+      int allDone = 1;
-+      yaffs_Device *dev = in->myDev;
--      if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
--              return YAFFS_FAIL;
-+      if (tn) {
-+              if (level > 0) {
--      objId = in->objectId;
--      fSize = in->variant.fileVariant.fileSize;
--      nChunks =
--          (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
--
--      for (chunk = 1; chunk <= nChunks; chunk++) {
--              tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
--                                         chunk);
--
--              if (tn) {
--
--                      theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
--
--                      if (yaffs_CheckChunkBits
--                          (dev, theChunk / dev->nChunksPerBlock,
--                           theChunk % dev->nChunksPerBlock)) {
--
--                              yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
--                                                          tags,
--                                                          &chunkDeleted);
--                              if (yaffs_TagsMatch
--                                  (tags, in->objectId, chunk, chunkDeleted)) {
--                                      /* found it; */
-+                      for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
-+                           i--) {
-+                              if (tn->internal[i]) {
-+                                      allDone =
-+                                          yaffs_SoftDeleteWorker(in,
-+                                                                 tn->
-+                                                                 internal[i],
-+                                                                 level - 1,
-+                                                                 (chunkOffset
-+                                                                  <<
-+                                                                  YAFFS_TNODES_INTERNAL_BITS)
-+                                                                 + i);
-+                                      if (allDone) {
-+                                              yaffs_FreeTnode(dev,
-+                                                              tn->
-+                                                              internal[i]);
-+                                              tn->internal[i] = NULL;
-+                                      } else {
-+                                              /* Hoosterman... how could this happen? */
-+                                      }
-+                              }
-+                      }
-+                      return (allDone) ? 1 : 0;
-+              } else if (level == 0) {
-+                      for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
-+                              theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
-+                              if (theChunk) {
-+                                      /* Note this does not find the real chunk, only the chunk group.
-+                                       * We make an assumption that a chunk group is not larger than
-+                                       * a block.
-+                                       */
-+                                      yaffs_SoftDeleteChunk(dev, theChunk);
-+                                      yaffs_LoadLevel0Tnode(dev, tn, i, 0);
-                               }
--                      } else {
--                              failed = 1;
-                       }
-+                      return 1;
--              } else {
--                      /* T(("No level 0 found for %d\n", chunk)); */
-               }
-+
-       }
--      return failed ? YAFFS_FAIL : YAFFS_OK;
-+      return 1;
-+
- }
--#endif
-+static void yaffs_SoftDeleteFile(yaffs_Object *obj)
-+{
-+      if (obj->deleted &&
-+          obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
-+              if (obj->nDataChunks <= 0) {
-+                      /* Empty file with no duplicate object headers, just delete it immediately */
-+                      yaffs_FreeTnode(obj->myDev,
-+                                      obj->variant.fileVariant.top);
-+                      obj->variant.fileVariant.top = NULL;
-+                      T(YAFFS_TRACE_TRACING,
-+                        (TSTR("yaffs: Deleting empty file %d" TENDSTR),
-+                         obj->objectId));
-+                      yaffs_DoGenericObjectDeletion(obj);
-+              } else {
-+                      yaffs_SoftDeleteWorker(obj,
-+                                             obj->variant.fileVariant.top,
-+                                             obj->variant.fileVariant.
-+                                             topLevel, 0);
-+                      obj->softDeleted = 1;
-+              }
-+      }
-+}
--static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
--                                int chunkInNAND, int inScan)
-+/* Pruning removes any part of the file structure tree that is beyond the
-+ * bounds of the file (ie that does not point to chunks).
-+ *
-+ * A file should only get pruned when its size is reduced.
-+ *
-+ * Before pruning, the chunks must be pulled from the tree and the
-+ * level 0 tnode entries must be zeroed out.
-+ * Could also use this for file deletion, but that's probably better handled
-+ * by a special case.
-+ *
-+ * This function is recursive. For levels > 0 the function is called again on
-+ * any sub-tree. For level == 0 we just check if the sub-tree has data.
-+ * If there is no data in a subtree then it is pruned.
-+ */
-+
-+static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
-+                              __u32 level, int del0)
- {
--      /* NB inScan is zero unless scanning.
--       * For forward scanning, inScan is > 0;
--       * for backward scanning inScan is < 0
--       */
-+      int i;
-+      int hasData;
--      yaffs_Tnode *tn;
--      yaffs_Device *dev = in->myDev;
--      int existingChunk;
--      yaffs_ExtendedTags existingTags;
--      yaffs_ExtendedTags newTags;
--      unsigned existingSerial, newSerial;
-+      if (tn) {
-+              hasData = 0;
--      if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
--              /* Just ignore an attempt at putting a chunk into a non-file during scanning
--               * If it is not during Scanning then something went wrong!
--               */
--              if (!inScan) {
--                      T(YAFFS_TRACE_ERROR,
--                        (TSTR
--                         ("yaffs tragedy:attempt to put data chunk into a non-file"
--                          TENDSTR)));
--                      YBUG();
--              }
-+              if(level > 0){
-+                      for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
-+                              if (tn->internal[i]) {
-+                                      tn->internal[i] =
-+                                              yaffs_PruneWorker(dev, tn->internal[i],
-+                                                      level - 1,
-+                                                      (i == 0) ? del0 : 1);
-+                              }
--              yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
--              return YAFFS_OK;
--      }
-+                              if (tn->internal[i])
-+                                      hasData++;
-+                      }
-+              } else {
-+                      int tnodeSize_u32 = dev->tnodeSize/sizeof(__u32);
-+                      __u32 *map = (__u32 *)tn;
--      tn = yaffs_AddOrFindLevel0Tnode(dev,
--                                      &in->variant.fileVariant,
--                                      chunkInInode,
--                                      NULL);
--      if (!tn)
--              return YAFFS_FAIL;
-+                        for(i = 0; !hasData && i < tnodeSize_u32; i++){
-+                                if(map[i])
-+                                        hasData++;
-+                        }
-+                }
--      existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
-+              if (hasData == 0 && del0) {
-+                      /* Free and return NULL */
--      if (inScan != 0) {
--              /* If we're scanning then we need to test for duplicates
--               * NB This does not need to be efficient since it should only ever
--               * happen when the power fails during a write, then only one
--               * chunk should ever be affected.
--               *
--               * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
--               * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
--               */
-+                      yaffs_FreeTnode(dev, tn);
-+                      tn = NULL;
-+              }
--              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.
--                       *
--                       * We have a duplicate now we need to decide which one to use:
--                       *
--                       * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
--                       * Forward scanning YAFFS2: The new one is what we use, dump the old one.
--                       * YAFFS1: Get both sets of tags and compare serial numbers.
--                       */
-+      }
--                      if (inScan > 0) {
--                              /* Only do this for forward scanning */
--                              yaffs_ReadChunkWithTagsFromNAND(dev,
--                                                              chunkInNAND,
--                                                              NULL, &newTags);
-+      return tn;
--                              /* Do a proper find */
--                              existingChunk =
--                                  yaffs_FindChunkInFile(in, chunkInInode,
--                                                        &existingTags);
--                      }
-+}
--                      if (existingChunk <= 0) {
--                              /*Hoosterman - how did this happen? */
-+static int yaffs_PruneFileStructure(yaffs_Device *dev,
-+                              yaffs_FileStructure *fStruct)
-+{
-+      int i;
-+      int hasData;
-+      int done = 0;
-+      yaffs_Tnode *tn;
--                              T(YAFFS_TRACE_ERROR,
--                                (TSTR
--                                 ("yaffs tragedy: existing chunk < 0 in scan"
--                                  TENDSTR)));
-+      if (fStruct->topLevel > 0) {
-+              fStruct->top =
-+                  yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
--                      }
-+              /* Now we have a tree with all the non-zero branches NULL but the height
-+               * is the same as it was.
-+               * Let's see if we can trim internal tnodes to shorten the tree.
-+               * We can do this if only the 0th element in the tnode is in use
-+               * (ie all the non-zero are NULL)
-+               */
--                      /* NB The deleted flags should be false, otherwise the chunks will
--                       * not be loaded during a scan
--                       */
-+              while (fStruct->topLevel && !done) {
-+                      tn = fStruct->top;
--                      if (inScan > 0) {
--                              newSerial = newTags.serialNumber;
--                              existingSerial = existingTags.serialNumber;
-+                      hasData = 0;
-+                      for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
-+                              if (tn->internal[i])
-+                                      hasData++;
-                       }
--
--                      if ((inScan > 0) &&
--                          (in->myDev->isYaffs2 ||
--                           existingChunk <= 0 ||
--                           ((existingSerial + 1) & 3) == newSerial)) {
--                              /* Forward scanning.
--                               * Use new
--                               * Delete the old one and drop through to update the tnode
--                               */
--                              yaffs_DeleteChunk(dev, existingChunk, 1,
--                                                __LINE__);
--                      } else {
--                              /* Backward scanning or we want to use the existing one
--                               * Use existing.
--                               * Delete the new one and return early so that the tnode isn't changed
--                               */
--                              yaffs_DeleteChunk(dev, chunkInNAND, 1,
--                                                __LINE__);
--                              return YAFFS_OK;
-+
-+                      if (!hasData) {
-+                              fStruct->top = tn->internal[0];
-+                              fStruct->topLevel--;
-+                              yaffs_FreeTnode(dev, tn);
-+                      } else {
-+                              done = 1;
-                       }
-               }
--
-       }
--      if (existingChunk == 0)
--              in->nDataChunks++;
--
--      yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
--
-       return YAFFS_OK;
- }
--static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
--                                      __u8 *buffer)
--{
--      int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
--
--      if (chunkInNAND >= 0)
--              return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
--                                              buffer, NULL);
--      else {
--              T(YAFFS_TRACE_NANDACCESS,
--                (TSTR("Chunk %d not found zero instead" TENDSTR),
--                 chunkInNAND));
--              /* get sane (zero) data if you read a hole */
--              memset(buffer, 0, in->myDev->nDataBytesPerChunk);
--              return 0;
--      }
-+/*-------------------- End of File Structure functions.-------------------*/
--}
--void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
-+/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
-+static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
- {
--      int block;
--      int page;
--      yaffs_ExtendedTags tags;
--      yaffs_BlockInfo *bi;
-+      yaffs_Object *obj = yaffs_AllocateRawObject(dev);
--      if (chunkId <= 0)
--              return;
-+      if (obj) {
-+              dev->nObjects++;
--      dev->nDeletions++;
--      block = chunkId / dev->nChunksPerBlock;
--      page = chunkId % dev->nChunksPerBlock;
-+              /* Now sweeten it up... */
-+              memset(obj, 0, sizeof(yaffs_Object));
-+              obj->beingCreated = 1;
--      if (!yaffs_CheckChunkBit(dev, block, page))
--              T(YAFFS_TRACE_VERIFY,
--                      (TSTR("Deleting invalid chunk %d"TENDSTR),
--                       chunkId));
-+              obj->myDev = dev;
-+              obj->hdrChunk = 0;
-+              obj->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
-+              YINIT_LIST_HEAD(&(obj->hardLinks));
-+              YINIT_LIST_HEAD(&(obj->hashLink));
-+              YINIT_LIST_HEAD(&obj->siblings);
--      bi = yaffs_GetBlockInfo(dev, block);
--      T(YAFFS_TRACE_DELETION,
--        (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
-+              /* Now make the directory sane */
-+              if (dev->rootDir) {
-+                      obj->parent = dev->rootDir;
-+                      ylist_add(&(obj->siblings), &dev->rootDir->variant.directoryVariant.children);
-+              }
--      if (markNAND &&
--          bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
-+              /* Add it to the lost and found directory.
-+               * NB Can't put root or lostNFound in lostNFound so
-+               * check if lostNFound exists first
-+               */
-+              if (dev->lostNFoundDir)
-+                      yaffs_AddObjectToDirectory(dev->lostNFoundDir, obj);
--              yaffs_InitialiseTags(&tags);
-+              obj->beingCreated = 0;
-+      }
--              tags.chunkDeleted = 1;
-+      dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
--              yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
--              yaffs_HandleUpdateChunk(dev, chunkId, &tags);
--      } else {
--              dev->nUnmarkedDeletions++;
--      }
-+      return obj;
-+}
--      /* Pull out of the management area.
--       * If the whole block became dirty, this will kick off an erasure.
--       */
--      if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
--          bi->blockState == YAFFS_BLOCK_STATE_FULL ||
--          bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
--          bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
--              dev->nFreeChunks++;
-+static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
-+                                             __u32 mode)
-+{
--              yaffs_ClearChunkBit(dev, block, page);
-+      yaffs_Object *obj =
-+          yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
-+      if (obj) {
-+              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->hdrChunk = 0;      /* Not a valid chunk. */
-+      }
--              bi->pagesInUse--;
-+      return obj;
--              if (bi->pagesInUse == 0 &&
--                  !bi->hasShrinkHeader &&
--                  bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
--                  bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
--                      yaffs_BlockBecameDirty(dev, block);
--              }
-+}
--      }
-+static void yaffs_UnhashObject(yaffs_Object *obj)
-+{
-+      int bucket;
-+      yaffs_Device *dev = obj->myDev;
-+      /* If it is still linked into the bucket list, free from the list */
-+      if (!ylist_empty(&obj->hashLink)) {
-+              ylist_del_init(&obj->hashLink);
-+              bucket = yaffs_HashFunction(obj->objectId);
-+              dev->objectBucket[bucket].count--;
-+      }
- }
--static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
--                                      const __u8 *buffer, int nBytes,
--                                      int useReserve)
-+/*  FreeObject frees up a Object and puts it back on the free list */
-+static void yaffs_FreeObject(yaffs_Object *obj)
- {
--      /* Find old chunk Need to do this to get serial number
--       * Write new one and patch into tree.
--       * Invalidate old tags.
--       */
-+      yaffs_Device *dev = obj->myDev;
--      int prevChunkId;
--      yaffs_ExtendedTags prevTags;
-+      T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->myInode));
--      int newChunkId;
--      yaffs_ExtendedTags newTags;
-+      if (!obj)
-+              YBUG();
-+      if (obj->parent)
-+              YBUG();
-+      if (!ylist_empty(&obj->siblings))
-+              YBUG();
--      yaffs_Device *dev = in->myDev;
--      yaffs_CheckGarbageCollection(dev);
-+      if (obj->myInode) {
-+              /* We're still hooked up to a cached inode.
-+               * Don't delete now, but mark for later deletion
-+               */
-+              obj->deferedFree = 1;
-+              return;
-+      }
-+
-+      yaffs_UnhashObject(obj);
--      /* Get the previous chunk at this location in the file if it exists */
--      prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
-+      yaffs_FreeRawObject(dev,obj);
-+      dev->nObjects--;
-+      dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
-+}
--      /* Set up new tags */
--      yaffs_InitialiseTags(&newTags);
--      newTags.chunkId = chunkInInode;
--      newTags.objectId = in->objectId;
--      newTags.serialNumber =
--          (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
--      newTags.byteCount = nBytes;
-+void yaffs_HandleDeferedFree(yaffs_Object *obj)
-+{
-+      if (obj->deferedFree)
-+              yaffs_FreeObject(obj);
-+}
--      if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
--              T(YAFFS_TRACE_ERROR,
--              (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
--              YBUG();
-+static void yaffs_InitialiseTnodesAndObjects(yaffs_Device *dev)
-+{
-+      int i;
-+
-+      dev->nObjects = 0;
-+      dev->nTnodes = 0;
-+
-+      yaffs_InitialiseRawTnodesAndObjects(dev);
-+
-+      for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
-+              YINIT_LIST_HEAD(&dev->objectBucket[i].list);
-+              dev->objectBucket[i].count = 0;
-       }
-+}
--      newChunkId =
--          yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
--                                            useReserve);
-+static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
-+{
-+      int i;
-+      int l = 999;
-+      int lowest = 999999;
--      if (newChunkId >= 0) {
--              yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
--              if (prevChunkId >= 0)
--                      yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
-+      /* Search for the shortest list or one that
-+       * isn't too long.
-+       */
-+
-+      for (i = 0; i < 10 && lowest > 4; i++) {
-+              dev->bucketFinder++;
-+              dev->bucketFinder %= YAFFS_NOBJECT_BUCKETS;
-+              if (dev->objectBucket[dev->bucketFinder].count < lowest) {
-+                      lowest = dev->objectBucket[dev->bucketFinder].count;
-+                      l = dev->bucketFinder;
-+              }
--              yaffs_CheckFileSanity(in);
-       }
--      return newChunkId;
-+      return l;
- }
--/* UpdateObjectHeader updates the header on NAND for an object.
-- * If name is not NULL, then that new name is used.
-- */
--int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
--                           int isShrink, int shadows)
-+static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
- {
-+      int bucket = yaffs_FindNiceObjectBucket(dev);
--      yaffs_BlockInfo *bi;
-+      /* Now find an object value that has not already been taken
-+       * by scanning the list.
-+       */
--      yaffs_Device *dev = in->myDev;
-+      int found = 0;
-+      struct ylist_head *i;
--      int prevChunkId;
--      int retVal = 0;
--      int result = 0;
-+      __u32 n = (__u32) bucket;
--      int newChunkId;
--      yaffs_ExtendedTags newTags;
--      yaffs_ExtendedTags oldTags;
-+      /* yaffs_CheckObjectHashSanity();  */
--      __u8 *buffer = NULL;
--      YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
-+      while (!found) {
-+              found = 1;
-+              n += YAFFS_NOBJECT_BUCKETS;
-+              if (1 || dev->objectBucket[bucket].count > 0) {
-+                      ylist_for_each(i, &dev->objectBucket[bucket].list) {
-+                              /* If there is already one in the list */
-+                              if (i && ylist_entry(i, yaffs_Object,
-+                                              hashLink)->objectId == n) {
-+                                      found = 0;
-+                              }
-+                      }
-+              }
-+      }
--      yaffs_ObjectHeader *oh = NULL;
-+      return n;
-+}
--      yaffs_strcpy(oldName, _Y("silly old name"));
-+static void yaffs_HashObject(yaffs_Object *in)
-+{
-+      int bucket = yaffs_HashFunction(in->objectId);
-+      yaffs_Device *dev = in->myDev;
-+      ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
-+      dev->objectBucket[bucket].count++;
-+}
--      if (!in->fake ||
--              in == dev->rootDir || /* The rootDir should also be saved */
--              force) {
-+yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
-+{
-+      int bucket = yaffs_HashFunction(number);
-+      struct ylist_head *i;
-+      yaffs_Object *in;
--              yaffs_CheckGarbageCollection(dev);
--              yaffs_CheckObjectDetailsLoaded(in);
-+      ylist_for_each(i, &dev->objectBucket[bucket].list) {
-+              /* Look if it is in the list */
-+              if (i) {
-+                      in = ylist_entry(i, yaffs_Object, hashLink);
-+                      if (in->objectId == number) {
--              buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
--              oh = (yaffs_ObjectHeader *) buffer;
-+                              /* Don't tell the VFS about this one if it is defered free */
-+                              if (in->deferedFree)
-+                                      return NULL;
--              prevChunkId = in->hdrChunk;
-+                              return in;
-+                      }
-+              }
-+      }
--              if (prevChunkId > 0) {
--                      result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
--                                                      buffer, &oldTags);
-+      return NULL;
-+}
--                      yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
-+yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
-+                                  yaffs_ObjectType type)
-+{
-+      yaffs_Object *theObject=NULL;
-+      yaffs_Tnode *tn = NULL;
-+
-+      if (number < 0)
-+              number = yaffs_CreateNewObjectNumber(dev);
--                      memcpy(oldName, oh->name, sizeof(oh->name));
--              }
-+      if (type == YAFFS_OBJECT_TYPE_FILE) {
-+              tn = yaffs_GetTnode(dev);
-+              if (!tn)
-+                      return NULL;
-+      }
--              memset(buffer, 0xFF, dev->nDataBytesPerChunk);
-+      theObject = yaffs_AllocateEmptyObject(dev);
-+      if (!theObject){
-+              if(tn)
-+                      yaffs_FreeTnode(dev,tn);
-+              return NULL;
-+      }
--              oh->type = in->variantType;
--              oh->yst_mode = in->yst_mode;
--              oh->shadowsObject = oh->inbandShadowsObject = shadows;
-+      if (theObject) {
-+              theObject->fake = 0;
-+              theObject->renameAllowed = 1;
-+              theObject->unlinkAllowed = 1;
-+              theObject->objectId = number;
-+              yaffs_HashObject(theObject);
-+              theObject->variantType = type;
- #ifdef CONFIG_YAFFS_WINCE
--              oh->win_atime[0] = in->win_atime[0];
--              oh->win_ctime[0] = in->win_ctime[0];
--              oh->win_mtime[0] = in->win_mtime[0];
--              oh->win_atime[1] = in->win_atime[1];
--              oh->win_ctime[1] = in->win_ctime[1];
--              oh->win_mtime[1] = in->win_mtime[1];
--#else
--              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)
--                      oh->parentObjectId = in->parent->objectId;
--              else
--                      oh->parentObjectId = 0;
--
--              if (name && *name) {
--                      memset(oh->name, 0, sizeof(oh->name));
--                      yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
--              } else if (prevChunkId >= 0)
--                      memcpy(oh->name, oldName, sizeof(oh->name));
--              else
--                      memset(oh->name, 0, sizeof(oh->name));
-+              yfsd_WinFileTimeNow(theObject->win_atime);
-+              theObject->win_ctime[0] = theObject->win_mtime[0] =
-+                  theObject->win_atime[0];
-+              theObject->win_ctime[1] = theObject->win_mtime[1] =
-+                  theObject->win_atime[1];
--              oh->isShrink = isShrink;
-+#else
--              switch (in->variantType) {
--              case YAFFS_OBJECT_TYPE_UNKNOWN:
--                      /* Should not happen */
--                      break;
-+              theObject->yst_atime = theObject->yst_mtime =
-+                  theObject->yst_ctime = Y_CURRENT_TIME;
-+#endif
-+              switch (type) {
-               case YAFFS_OBJECT_TYPE_FILE:
--                      oh->fileSize =
--                          (oh->parentObjectId == YAFFS_OBJECTID_DELETED
--                           || oh->parentObjectId ==
--                           YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
--                          fileVariant.fileSize;
--                      break;
--              case YAFFS_OBJECT_TYPE_HARDLINK:
--                      oh->equivalentObjectId =
--                          in->variant.hardLinkVariant.equivalentObjectId;
--                      break;
--              case YAFFS_OBJECT_TYPE_SPECIAL:
--                      /* Do nothing */
-+                      theObject->variant.fileVariant.fileSize = 0;
-+                      theObject->variant.fileVariant.scannedFileSize = 0;
-+                      theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
-+                      theObject->variant.fileVariant.topLevel = 0;
-+                      theObject->variant.fileVariant.top = tn;
-                       break;
-               case YAFFS_OBJECT_TYPE_DIRECTORY:
--                      /* Do nothing */
-+                      YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
-+                                      children);
-+                      YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
-+                                      dirty);
-                       break;
-               case YAFFS_OBJECT_TYPE_SYMLINK:
--                      yaffs_strncpy(oh->alias,
--                                    in->variant.symLinkVariant.alias,
--                                    YAFFS_MAX_ALIAS_LENGTH);
--                      oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
-+              case YAFFS_OBJECT_TYPE_HARDLINK:
-+              case YAFFS_OBJECT_TYPE_SPECIAL:
-+                      /* No action required */
-+                      break;
-+              case YAFFS_OBJECT_TYPE_UNKNOWN:
-+                      /* todo this should not happen */
-                       break;
-               }
-+      }
--              /* Tags */
--              yaffs_InitialiseTags(&newTags);
--              in->serial++;
--              newTags.chunkId = 0;
--              newTags.objectId = in->objectId;
--              newTags.serialNumber = in->serial;
--
--              /* Add extra info for file header */
--
--              newTags.extraHeaderInfoAvailable = 1;
--              newTags.extraParentObjectId = oh->parentObjectId;
--              newTags.extraFileLength = oh->fileSize;
--              newTags.extraIsShrinkHeader = oh->isShrink;
--              newTags.extraEquivalentObjectId = oh->equivalentObjectId;
--              newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
--              newTags.extraObjectType = in->variantType;
--
--              yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
-+      return theObject;
-+}
--              /* Create new chunk in NAND */
--              newChunkId =
--                  yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
--                                                    (prevChunkId >= 0) ? 1 : 0);
-+yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
-+                                              int number,
-+                                              yaffs_ObjectType type)
-+{
-+      yaffs_Object *theObject = NULL;
--              if (newChunkId >= 0) {
-+      if (number > 0)
-+              theObject = yaffs_FindObjectByNumber(dev, number);
--                      in->hdrChunk = newChunkId;
-+      if (!theObject)
-+              theObject = yaffs_CreateNewObject(dev, number, type);
--                      if (prevChunkId >= 0) {
--                              yaffs_DeleteChunk(dev, prevChunkId, 1,
--                                                __LINE__);
--                      }
-+      return theObject;
--                      if (!yaffs_ObjectHasCachedWriteData(in))
--                              in->dirty = 0;
-+}
--                      /* If this was a shrink, then mark the block that the chunk lives on */
--                      if (isShrink) {
--                              bi = yaffs_GetBlockInfo(in->myDev,
--                                      newChunkId / in->myDev->nChunksPerBlock);
--                              bi->hasShrinkHeader = 1;
--                      }
--              }
-+YCHAR *yaffs_CloneString(const YCHAR *str)
-+{
-+      YCHAR *newStr = NULL;
-+      int len;
--              retVal = newChunkId;
-+      if (!str)
-+              str = _Y("");
-+      len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH);
-+      newStr = YMALLOC((len + 1) * sizeof(YCHAR));
-+      if (newStr){
-+              yaffs_strncpy(newStr, str,len);
-+              newStr[len] = 0;
-       }
-+      return newStr;
--      if (buffer)
--              yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
--
--      return retVal;
- }
--/*------------------------ Short Operations Cache ----------------------------------------
-- *   In many situations where there is no high level buffering (eg WinCE) a lot of
-- *   reads might be short sequential reads, and a lot of writes may be short
-- *   sequential writes. eg. scanning/writing a jpeg file.
-- *   In these cases, a short read/write cache can provide a huge perfomance benefit
-- *   with dumb-as-a-rock code.
-- *   In Linux, the page cache provides read buffering aand the short op cache provides write
-- *   buffering.
-- *
-- *   There are a limited number (~10) of cache chunks per device so that we don't
-- *   need a very intelligent search.
-+/*
-+ * Mknod (create) a new object.
-+ * equivalentObject only has meaning for a hard link;
-+ * aliasString only has meaning for a symlink.
-+ * rdev only has meaning for devices (a subset of special objects)
-  */
--static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
-+static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
-+                                     yaffs_Object *parent,
-+