From: Gabor Juhos Date: Fri, 23 Jan 2009 17:24:20 +0000 (+0000) Subject: generic-2.6/2.6.28: sync yaffs code with the current CVS version X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=d99ccd5b1538c3971efb082ba7e310527769806f;p=openwrt%2Fstaging%2Fluka.git generic-2.6/2.6.28: sync yaffs code with the current CVS version SVN-Revision: 14158 --- diff --git a/target/linux/generic-2.6/patches-2.6.28/511-yaffs-cvs-2009-01-23.patch b/target/linux/generic-2.6/patches-2.6.28/511-yaffs-cvs-2009-01-23.patch new file mode 100644 index 0000000000..6193e89211 --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.28/511-yaffs-cvs-2009-01-23.patch @@ -0,0 +1,8237 @@ +--- a/fs/yaffs2/yaffs_tagscompat.h ++++ b/fs/yaffs2/yaffs_tagscompat.h +@@ -30,8 +30,9 @@ int yaffs_TagsCompatabilityReadChunkWith + int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, + int blockNo); + int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, +- int blockNo, yaffs_BlockState * +- state, int *sequenceNumber); ++ int blockNo, ++ yaffs_BlockState *state, ++ __u32 *sequenceNumber); + + void yaffs_CalcTagsECC(yaffs_Tags * tags); + int yaffs_CheckECCOnTags(yaffs_Tags * tags); +--- a/fs/yaffs2/Kconfig ++++ b/fs/yaffs2/Kconfig +@@ -43,7 +43,8 @@ config YAFFS_9BYTE_TAGS + format that you need to continue to support. New data written + also uses the older-style format. Note: Use of this option + generally requires that MTD's oob layout be adjusted to use the +- older-style format. See notes on tags formats and MTD versions. ++ older-style format. See notes on tags formats and MTD versions ++ in yaffs_mtdif1.c. + + If unsure, say N. + +@@ -109,26 +110,6 @@ config YAFFS_DISABLE_LAZY_LOAD + + If unsure, say N. + +-config YAFFS_CHECKPOINT_RESERVED_BLOCKS +- int "Reserved blocks for checkpointing" +- depends on YAFFS_YAFFS2 +- default 10 +- help +- Give the number of Blocks to reserve for checkpointing. +- Checkpointing saves the state at unmount so that mounting is +- much faster as a scan of all the flash to regenerate this state +- is not needed. These Blocks are reserved per partition, so if +- you have very small partitions the default (10) may be a mess +- for you. You can set this value to 0, but that does not mean +- checkpointing is disabled at all. There only won't be any +- specially reserved blocks for checkpointing, so if there is +- enough free space on the filesystem, it will be used for +- checkpointing. +- +- If unsure, leave at default (10), but don't wonder if there are +- always 2MB used on your large page device partition (10 x 2k +- pagesize). When using small partitions or when being very small +- on space, you probably want to set this to zero. + + config YAFFS_DISABLE_WIDE_TNODES + bool "Turn off wide tnodes" +--- a/fs/yaffs2/yaffs_mtdif.h ++++ b/fs/yaffs2/yaffs_mtdif.h +@@ -18,6 +18,11 @@ + + #include "yaffs_guts.h" + ++#if (MTD_VERSION_CODE < MTD_VERSION(2,6,18)) ++extern struct nand_oobinfo yaffs_oobinfo; ++extern struct nand_oobinfo yaffs_noeccinfo; ++#endif ++ + int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND, + const __u8 * data, const yaffs_Spare * spare); + int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data, +--- a/fs/yaffs2/devextras.h ++++ b/fs/yaffs2/devextras.h +@@ -1,5 +1,5 @@ + /* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering +@@ -14,203 +14,145 @@ + */ + + /* +- * This file is just holds extra declarations used during development. +- * Most of these are from kernel includes placed here so we can use them in +- * applications. ++ * This file is just holds extra declarations of macros that would normally ++ * be providesd in the Linux kernel. These macros have been written from ++ * scratch but are functionally equivalent to the Linux ones. + * + */ + + #ifndef __EXTRAS_H__ + #define __EXTRAS_H__ + +-#if defined WIN32 +-#define __inline__ __inline +-#define new newHack +-#endif +- +-#if !(defined __KERNEL__) || (defined WIN32) + +-/* User space defines */ ++#if !(defined __KERNEL__) + ++/* Definition of types */ + typedef unsigned char __u8; + typedef unsigned short __u16; + typedef unsigned __u32; + ++#endif ++ + /* +- * Simple doubly linked list implementation. +- * +- * Some of the internal functions ("__xxx") are useful when +- * manipulating whole lists rather than single entries, as +- * sometimes we already know the next/prev entries and we can +- * generate better code by using them directly rather than +- * using the generic single-entry routines. ++ * This is a simple doubly linked list implementation that matches the ++ * way the Linux kernel doubly linked list implementation works. + */ + +-#define prefetch(x) 1 +- +-struct list_head { +- struct list_head *next, *prev; ++struct ylist_head { ++ struct ylist_head *next; /* next in chain */ ++ struct ylist_head *prev; /* previous in chain */ + }; + +-#define LIST_HEAD_INIT(name) { &(name), &(name) } + +-#define LIST_HEAD(name) \ +- struct list_head name = LIST_HEAD_INIT(name) ++/* Initialise a static list */ ++#define YLIST_HEAD(name) \ ++struct ylist_head name = { &(name),&(name)} + +-#define INIT_LIST_HEAD(ptr) do { \ +- (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +-} while (0) + +-/* +- * Insert a new entry between two known consecutive entries. +- * +- * This is only for internal list manipulation where we know +- * the prev/next entries already! +- */ +-static __inline__ void __list_add(struct list_head *new, +- struct list_head *prev, +- struct list_head *next) +-{ +- next->prev = new; +- new->next = next; +- new->prev = prev; +- prev->next = new; +-} + +-/** +- * list_add - add a new entry +- * @new: new entry to be added +- * @head: list head to add it after +- * +- * Insert a new entry after the specified head. +- * This is good for implementing stacks. +- */ +-static __inline__ void list_add(struct list_head *new, struct list_head *head) +-{ +- __list_add(new, head, head->next); +-} ++/* Initialise a list head to an empty list */ ++#define YINIT_LIST_HEAD(p) \ ++do { \ ++ (p)->next = (p);\ ++ (p)->prev = (p); \ ++} while(0) + +-/** +- * list_add_tail - add a new entry +- * @new: new entry to be added +- * @head: list head to add it before +- * +- * Insert a new entry before the specified head. +- * This is useful for implementing queues. +- */ +-static __inline__ void list_add_tail(struct list_head *new, +- struct list_head *head) ++ ++/* Add an element to a list */ ++static __inline__ void ylist_add(struct ylist_head *newEntry, ++ struct ylist_head *list) + { +- __list_add(new, head->prev, head); ++ struct ylist_head *listNext = list->next; ++ ++ list->next = newEntry; ++ newEntry->prev = list; ++ newEntry->next = listNext; ++ listNext->prev = newEntry; ++ + } + +-/* +- * Delete a list entry by making the prev/next entries +- * point to each other. +- * +- * This is only for internal list manipulation where we know +- * the prev/next entries already! +- */ +-static __inline__ void __list_del(struct list_head *prev, +- struct list_head *next) ++static __inline__ void ylist_add_tail(struct ylist_head *newEntry, ++ struct ylist_head *list) + { +- next->prev = prev; +- prev->next = next; ++ struct ylist_head *listPrev = list->prev; ++ ++ list->prev = newEntry; ++ newEntry->next = list; ++ newEntry->prev = listPrev; ++ listPrev->next = newEntry; ++ + } + +-/** +- * list_del - deletes entry from list. +- * @entry: the element to delete from the list. +- * Note: list_empty on entry does not return true after this, the entry is +- * in an undefined state. +- */ +-static __inline__ void list_del(struct list_head *entry) ++ ++/* 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) + { +- __list_del(entry->prev, entry->next); ++ struct ylist_head *listNext = entry->next; ++ struct ylist_head *listPrev = entry->prev; ++ ++ listNext->prev = listPrev; ++ listPrev->next = listNext; ++ + } + +-/** +- * list_del_init - deletes entry from list and reinitialize it. +- * @entry: the element to delete from the list. +- */ +-static __inline__ void list_del_init(struct list_head *entry) ++static __inline__ void ylist_del_init(struct ylist_head *entry) + { +- __list_del(entry->prev, entry->next); +- INIT_LIST_HEAD(entry); ++ ylist_del(entry); ++ entry->next = entry->prev = entry; + } + +-/** +- * list_empty - tests whether a list is empty +- * @head: the list to test. +- */ +-static __inline__ int list_empty(struct list_head *head) ++ ++/* Test if the list is empty */ ++static __inline__ int ylist_empty(struct ylist_head *entry) + { +- return head->next == head; ++ return (entry->next == entry); + } + +-/** +- * list_splice - join two lists +- * @list: the new list to add. +- * @head: the place to add it in the first list. ++ ++/* 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. + */ +-static __inline__ void list_splice(struct list_head *list, +- struct list_head *head) +-{ +- struct list_head *first = list->next; ++ ++ ++#define ylist_entry(entry, type, member) \ ++ ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member))) + +- if (first != list) { +- struct list_head *last = list->prev; +- struct list_head *at = head->next; +- +- first->prev = head; +- head->next = first; +- +- last->next = at; +- at->prev = last; +- } +-} + +-/** +- * list_entry - get the struct for this entry +- * @ptr: the &struct list_head pointer. +- * @type: the type of the struct this is embedded in. +- * @member: the name of the list_struct within the struct. ++/* 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 list_entry(ptr, type, member) \ +- ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +-/** +- * list_for_each - iterate over a list +- * @pos: the &struct list_head to use as a loop counter. +- * @head: the head for your list. +- */ +-#define list_for_each(pos, head) \ +- for (pos = (head)->next, prefetch(pos->next); pos != (head); \ +- pos = pos->next, prefetch(pos->next)) +- +-/** +- * list_for_each_safe - iterate over a list safe against removal +- * of list entry +- * @pos: the &struct list_head to use as a loop counter. +- * @n: another &struct list_head to use as temporary storage +- * @head: the head for your list. +- */ +-#define list_for_each_safe(pos, n, head) \ +- for (pos = (head)->next, n = pos->next; pos != (head); \ +- pos = n, n = pos->next) ++#define ylist_for_each(itervar, list) \ ++ for (itervar = (list)->next; itervar != (list); itervar = itervar->next ) + +-/* +- * File types +- */ +-#define DT_UNKNOWN 0 +-#define DT_FIFO 1 +-#define DT_CHR 2 ++#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__) ++ ++ ++#ifndef WIN32 ++#include ++#endif ++ ++ ++#ifdef CONFIG_YAFFS_PROVIDE_DEFS ++/* File types */ ++ ++ ++#define DT_UNKNOWN 0 ++#define DT_FIFO 1 ++#define DT_CHR 2 + #define DT_DIR 4 + #define DT_BLK 6 +-#define DT_REG 8 +-#define DT_LNK 10 +-#define DT_SOCK 12 +-#define DT_WHT 14 ++#define DT_REG 8 ++#define DT_LNK 10 ++#define DT_SOCK 12 ++#define DT_WHT 14 ++ + + #ifndef WIN32 + #include +@@ -220,17 +162,13 @@ static __inline__ void list_splice(struc + * Attribute flags. These should be or-ed together to figure out what + * has been changed! + */ +-#define ATTR_MODE 1 +-#define ATTR_UID 2 ++#define ATTR_MODE 1 ++#define ATTR_UID 2 + #define ATTR_GID 4 + #define ATTR_SIZE 8 + #define ATTR_ATIME 16 + #define ATTR_MTIME 32 + #define ATTR_CTIME 64 +-#define ATTR_ATIME_SET 128 +-#define ATTR_MTIME_SET 256 +-#define ATTR_FORCE 512 /* Not a change, but a change it */ +-#define ATTR_ATTR_FLAG 1024 + + struct iattr { + unsigned int ia_valid; +@@ -241,24 +179,21 @@ struct iattr { + unsigned ia_atime; + unsigned ia_mtime; + unsigned ia_ctime; +- unsigned int ia_attr_flags; ++ unsigned int ia_attr_flags; + }; + ++#endif ++ ++ + #define KERN_DEBUG + + #else + +-#ifndef WIN32 + #include +-#include + #include + #include +-#endif + + #endif + +-#if defined WIN32 +-#undef new +-#endif + + #endif +--- a/fs/yaffs2/yaffs_packedtags2.c ++++ b/fs/yaffs2/yaffs_packedtags2.c +@@ -37,60 +37,70 @@ + #define EXTRA_OBJECT_TYPE_SHIFT (28) + #define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) + +-static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt) ++ ++static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart * ptt) + { + T(YAFFS_TRACE_MTD, + (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), +- pt->t.objectId, pt->t.chunkId, pt->t.byteCount, +- pt->t.sequenceNumber)); ++ ptt->objectId, ptt->chunkId, ptt->byteCount, ++ ptt->sequenceNumber)); ++} ++static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt) ++{ ++ yaffs_DumpPackedTags2TagsPart(&pt->t); + } + + static void yaffs_DumpTags2(const yaffs_ExtendedTags * t) + { + T(YAFFS_TRACE_MTD, + (TSTR +- ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte " +- "%d del %d ser %d seq %d" ++ ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d" + TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId, + t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, + t->sequenceNumber)); + + } + +-void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t) ++void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart * ptt, const yaffs_ExtendedTags * t) + { +- pt->t.chunkId = t->chunkId; +- pt->t.sequenceNumber = t->sequenceNumber; +- pt->t.byteCount = t->byteCount; +- pt->t.objectId = t->objectId; ++ ptt->chunkId = t->chunkId; ++ ptt->sequenceNumber = t->sequenceNumber; ++ ptt->byteCount = t->byteCount; ++ ptt->objectId = t->objectId; + + if (t->chunkId == 0 && t->extraHeaderInfoAvailable) { + /* Store the extra header info instead */ + /* We save the parent object in the chunkId */ +- pt->t.chunkId = EXTRA_HEADER_INFO_FLAG ++ ptt->chunkId = EXTRA_HEADER_INFO_FLAG + | t->extraParentObjectId; + if (t->extraIsShrinkHeader) { +- pt->t.chunkId |= EXTRA_SHRINK_FLAG; ++ ptt->chunkId |= EXTRA_SHRINK_FLAG; + } + if (t->extraShadows) { +- pt->t.chunkId |= EXTRA_SHADOWS_FLAG; ++ ptt->chunkId |= EXTRA_SHADOWS_FLAG; + } + +- pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK; +- pt->t.objectId |= ++ ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK; ++ ptt->objectId |= + (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT); + + if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { +- pt->t.byteCount = t->extraEquivalentObjectId; ++ ptt->byteCount = t->extraEquivalentObjectId; + } else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) { +- pt->t.byteCount = t->extraFileLength; ++ ptt->byteCount = t->extraFileLength; + } else { +- pt->t.byteCount = 0; ++ ptt->byteCount = 0; + } + } + +- yaffs_DumpPackedTags2(pt); ++ yaffs_DumpPackedTags2TagsPart(ptt); + yaffs_DumpTags2(t); ++} ++ ++ ++void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t) ++{ ++ yaffs_PackTags2TagsPart(&pt->t,t); + + #ifndef YAFFS_IGNORE_TAGS_ECC + { +@@ -101,20 +111,63 @@ void yaffs_PackTags2(yaffs_PackedTags2 * + #endif + } + +-void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt) ++ ++void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags * t, yaffs_PackedTags2TagsPart * ptt) + { + + memset(t, 0, sizeof(yaffs_ExtendedTags)); + + yaffs_InitialiseTags(t); + ++ if (ptt->sequenceNumber != 0xFFFFFFFF) { ++ t->blockBad = 0; ++ t->chunkUsed = 1; ++ t->objectId = ptt->objectId; ++ t->chunkId = ptt->chunkId; ++ t->byteCount = ptt->byteCount; ++ t->chunkDeleted = 0; ++ t->serialNumber = 0; ++ t->sequenceNumber = ptt->sequenceNumber; ++ ++ /* Do extra header info stuff */ ++ ++ if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) { ++ t->chunkId = 0; ++ t->byteCount = 0; ++ ++ t->extraHeaderInfoAvailable = 1; ++ t->extraParentObjectId = ++ ptt->chunkId & (~(ALL_EXTRA_FLAGS)); ++ t->extraIsShrinkHeader = ++ (ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0; ++ t->extraShadows = ++ (ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0; ++ t->extraObjectType = ++ ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT; ++ t->objectId &= ~EXTRA_OBJECT_TYPE_MASK; ++ ++ if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { ++ t->extraEquivalentObjectId = ptt->byteCount; ++ } else { ++ t->extraFileLength = ptt->byteCount; ++ } ++ } ++ } ++ ++ yaffs_DumpPackedTags2TagsPart(ptt); ++ yaffs_DumpTags2(t); ++ ++} ++ ++ ++void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt) ++{ ++ ++ yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR; ++ + if (pt->t.sequenceNumber != 0xFFFFFFFF) { + /* Page is in use */ +-#ifdef YAFFS_IGNORE_TAGS_ECC +- { +- t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; +- } +-#else ++#ifndef YAFFS_IGNORE_TAGS_ECC + { + yaffs_ECCOther ecc; + int result; +@@ -129,54 +182,27 @@ void yaffs_UnpackTags2(yaffs_ExtendedTag + &pt->ecc, &ecc); + switch(result){ + case 0: +- t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; ++ eccResult = YAFFS_ECC_RESULT_NO_ERROR; + break; + case 1: +- t->eccResult = YAFFS_ECC_RESULT_FIXED; ++ eccResult = YAFFS_ECC_RESULT_FIXED; + break; + case -1: +- t->eccResult = YAFFS_ECC_RESULT_UNFIXED; ++ eccResult = YAFFS_ECC_RESULT_UNFIXED; + break; + default: +- t->eccResult = YAFFS_ECC_RESULT_UNKNOWN; ++ eccResult = YAFFS_ECC_RESULT_UNKNOWN; + } + } + #endif +- t->blockBad = 0; +- t->chunkUsed = 1; +- t->objectId = pt->t.objectId; +- t->chunkId = pt->t.chunkId; +- t->byteCount = pt->t.byteCount; +- t->chunkDeleted = 0; +- t->serialNumber = 0; +- t->sequenceNumber = pt->t.sequenceNumber; +- +- /* Do extra header info stuff */ +- +- if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) { +- t->chunkId = 0; +- t->byteCount = 0; +- +- t->extraHeaderInfoAvailable = 1; +- t->extraParentObjectId = +- pt->t.chunkId & (~(ALL_EXTRA_FLAGS)); +- t->extraIsShrinkHeader = +- (pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0; +- t->extraShadows = +- (pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0; +- t->extraObjectType = +- pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT; +- t->objectId &= ~EXTRA_OBJECT_TYPE_MASK; +- +- if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { +- t->extraEquivalentObjectId = pt->t.byteCount; +- } else { +- t->extraFileLength = pt->t.byteCount; +- } +- } + } + ++ yaffs_UnpackTags2TagsPart(t,&pt->t); ++ ++ t->eccResult = eccResult; ++ + yaffs_DumpPackedTags2(pt); + yaffs_DumpTags2(t); + + } ++ +--- a/fs/yaffs2/yaffs_ecc.c ++++ b/fs/yaffs2/yaffs_ecc.c +@@ -29,7 +29,7 @@ + */ + + const char *yaffs_ecc_c_version = +- "$Id: yaffs_ecc.c,v 1.9 2007-02-14 01:09:06 wookey Exp $"; ++ "$Id: yaffs_ecc.c,v 1.10 2007-12-13 15:35:17 wookey Exp $"; + + #include "yportenv.h" + +--- a/fs/yaffs2/yaffs_packedtags2.h ++++ b/fs/yaffs2/yaffs_packedtags2.h +@@ -33,6 +33,11 @@ typedef struct { + yaffs_ECCOther ecc; + } yaffs_PackedTags2; + ++/* Full packed tags with ECC, used for oob tags */ + void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t); + void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt); ++ ++/* Only the tags part (no ECC for use with inband tags */ ++void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart * pt, const yaffs_ExtendedTags * t); ++void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags * t, yaffs_PackedTags2TagsPart * pt); + #endif +--- a/fs/yaffs2/yportenv.h ++++ b/fs/yaffs2/yportenv.h +@@ -17,6 +17,14 @@ + #ifndef __YPORTENV_H__ + #define __YPORTENV_H__ + ++/* ++ * Define the MTD version in terms of Linux Kernel versions ++ * This allows yaffs to be used independantly of the kernel ++ * as well as with it. ++ */ ++ ++#define MTD_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) ++ + #if defined CONFIG_YAFFS_WINCE + + #include "ywinceenv.h" +@@ -26,7 +34,10 @@ + #include "moduleconfig.h" + + /* Linux kernel */ ++ + #include ++#define MTD_VERSION_CODE LINUX_VERSION_CODE ++ + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) + #include + #endif +@@ -40,6 +51,7 @@ + #define YCHAR char + #define YUCHAR unsigned char + #define _Y(x) x ++#define yaffs_strcat(a,b) strcat(a,b) + #define yaffs_strcpy(a,b) strcpy(a,b) + #define yaffs_strncpy(a,b,c) strncpy(a,b,c) + #define yaffs_strncmp(a,b,c) strncmp(a,b,c) +@@ -90,6 +102,8 @@ + + #elif defined CONFIG_YAFFS_DIRECT + ++#define MTD_VERSION_CODE MTD_VERSION(2,6,22) ++ + /* Direct interface */ + #include "ydirectenv.h" + +@@ -111,6 +125,7 @@ + #define YCHAR char + #define YUCHAR unsigned char + #define _Y(x) x ++#define yaffs_strcat(a,b) strcat(a,b) + #define yaffs_strcpy(a,b) strcpy(a,b) + #define yaffs_strncpy(a,b,c) strncpy(a,b,c) + #define yaffs_strlen(s) strlen(s) +@@ -180,8 +195,8 @@ extern unsigned int yaffs_wr_attempts; + + #define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0) + +-#ifndef CONFIG_YAFFS_WINCE +-#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__)) ++#ifndef YBUG ++#define YBUG() do {T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__));} while(0) + #endif + + #endif +--- a/fs/yaffs2/Makefile ++++ b/fs/yaffs2/Makefile +@@ -5,7 +5,6 @@ + obj-$(CONFIG_YAFFS_FS) += yaffs.o + + yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o +-yaffs-y += yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o ++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o + yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o +-yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o +-yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o ++yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o +--- a/fs/yaffs2/yaffs_mtdif1-compat.c ++++ /dev/null +@@ -1,434 +0,0 @@ +-From ian@brightstareng.com Fri May 18 15:06:49 2007 +-From ian@brightstareng.com Fri May 18 15:08:21 2007 +-Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com) +- by apollo.linkchoose.co.uk with esmtp (Exim 4.60) +- (envelope-from ) +- id 1Hp380-00011e-T6 +- for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100 +-Received: from localhost (localhost.localdomain [127.0.0.1]) +- by zebra.brightstareng.com (Postfix) with ESMTP +- id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT) +-Received: from zebra.brightstareng.com ([127.0.0.1]) +- by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP +- id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT) +-Received: from pippin (unknown [192.168.1.25]) +- by zebra.brightstareng.com (Postfix) with ESMTP +- id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT) +-From: Ian McDonnell +-To: David Goodenough +-Subject: Re: something tested this time -- yaffs_mtdif1-compat.c +-Date: Fri, 18 May 2007 10:06:49 -0400 +-User-Agent: KMail/1.9.1 +-References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk> +-In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk> +-Cc: Andrea Conti , +- Charles Manning +-MIME-Version: 1.0 +-Content-Type: Multipart/Mixed; +- boundary="Boundary-00=_5LbTGmt62YoutxM" +-Message-Id: <200705181006.49860.ian@brightstareng.com> +-X-Virus-Scanned: by amavisd-new at brightstareng.com +-Status: R +-X-Status: NT +-X-KMail-EncryptionState: +-X-KMail-SignatureState: +-X-KMail-MDN-Sent: +- +---Boundary-00=_5LbTGmt62YoutxM +-Content-Type: text/plain; +- charset="iso-8859-15" +-Content-Transfer-Encoding: 7bit +-Content-Disposition: inline +- +-David, Andrea, +- +-On Friday 18 May 2007 08:34, you wrote: +-> Yea team. With this fix in place (I put it in the wrong place +-> at first) I can now mount and ls the Yaffs partition without +-> an error messages! +- +-Good news! +- +-Attached is a newer yaffs_mtdif1.c with a bandaid to help the +-2.6.18 and 2.6.19 versions of MTD not trip on the oob read. +-See the LINUX_VERSION_CODE conditional in +-nandmtd1_ReadChunkWithTagsFromNAND. +- +--imcd +- +---Boundary-00=_5LbTGmt62YoutxM +-Content-Type: text/x-csrc; +- charset="iso-8859-15"; +- name="yaffs_mtdif1.c" +-Content-Transfer-Encoding: 7bit +-Content-Disposition: attachment; +- filename="yaffs_mtdif1.c" +- +-/* +- * YAFFS: Yet another FFS. A NAND-flash specific file system. +- * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND. +- * +- * Copyright (C) 2002 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * 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 module provides the interface between yaffs_nand.c and the +- * MTD API. This version is used when the MTD interface supports the +- * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17, +- * and we have small-page NAND device. +- * +- * These functions are invoked via function pointers in yaffs_nand.c. +- * This replaces functionality provided by functions in yaffs_mtdif.c +- * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are +- * called in yaffs_mtdif.c when the function pointers are NULL. +- * We assume the MTD layer is performing ECC (useNANDECC is true). +- */ +- +-#include "yportenv.h" +-#include "yaffs_guts.h" +-#include "yaffs_packedtags1.h" +-#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC +- +-#include "linux/kernel.h" +-#include "linux/version.h" +-#include "linux/types.h" +-#include "linux/mtd/mtd.h" +- +-/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +- +-const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1-compat.c 13022 2008-10-22 06:51:06Z nbd $"; +- +-#ifndef CONFIG_YAFFS_9BYTE_TAGS +-# define YTAG1_SIZE 8 +-#else +-# define YTAG1_SIZE 9 +-#endif +- +-#if 0 +-/* Use the following nand_ecclayout with MTD when using +- * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout. +- * If you have existing Yaffs images and the byte order differs from this, +- * adjust 'oobfree' to match your existing Yaffs data. +- * +- * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the +- * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to +- * the 9th byte. +- * +- * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5 +- * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P +- * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus +- * byte and B is the small-page bad-block indicator byte. +- */ +-static struct nand_ecclayout nand_oob_16 = { +- .eccbytes = 6, +- .eccpos = { 8, 9, 10, 13, 14, 15 }, +- .oobavail = 9, +- .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } } +-}; +-#endif +- +-/* Write a chunk (page) of data to NAND. +- * +- * Caller always provides ExtendedTags data which are converted to a more +- * compact (packed) form for storage in NAND. A mini-ECC runs over the +- * contents of the tags meta-data; used to valid the tags when read. +- * +- * - Pack ExtendedTags to PackedTags1 form +- * - Compute mini-ECC for PackedTags1 +- * - Write data and packed tags to NAND. +- * +- * Note: Due to the use of the PackedTags1 meta-data which does not include +- * a full sequence number (as found in the larger PackedTags2 form) it is +- * necessary for Yaffs to re-write a chunk/page (just once) to mark it as +- * discarded and dirty. This is not ideal: newer NAND parts are supposed +- * to be written just once. When Yaffs performs this operation, this +- * function is called with a NULL data pointer -- calling MTD write_oob +- * without data is valid usage (2.6.17). +- * +- * Any underlying MTD error results in YAFFS_FAIL. +- * Returns YAFFS_OK or YAFFS_FAIL. +- */ +-int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, +- int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags) +-{ +- struct mtd_info * mtd = dev->genericDevice; +- int chunkBytes = dev->nDataBytesPerChunk; +- loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; +- struct mtd_oob_ops ops; +- yaffs_PackedTags1 pt1; +- int retval; +- +- /* we assume that PackedTags1 and yaffs_Tags are compatible */ +- compile_time_assertion(sizeof(yaffs_PackedTags1) == 12); +- compile_time_assertion(sizeof(yaffs_Tags) == 8); +- +- yaffs_PackTags1(&pt1, etags); +- yaffs_CalcTagsECC((yaffs_Tags *)&pt1); +- +- /* When deleting a chunk, the upper layer provides only skeletal +- * etags, one with chunkDeleted set. However, we need to update the +- * tags, not erase them completely. So we use the NAND write property +- * that only zeroed-bits stick and set tag bytes to all-ones and +- * zero just the (not) deleted bit. +- */ +-#ifndef CONFIG_YAFFS_9BYTE_TAGS +- if (etags->chunkDeleted) { +- memset(&pt1, 0xff, 8); +- /* clear delete status bit to indicate deleted */ +- pt1.deleted = 0; +- } +-#else +- ((__u8 *)&pt1)[8] = 0xff; +- if (etags->chunkDeleted) { +- memset(&pt1, 0xff, 8); +- /* zero pageStatus byte to indicate deleted */ +- ((__u8 *)&pt1)[8] = 0; +- } +-#endif +- +- memset(&ops, 0, sizeof(ops)); +- ops.mode = MTD_OOB_AUTO; +- ops.len = (data) ? chunkBytes : 0; +- ops.ooblen = YTAG1_SIZE; +- ops.datbuf = (__u8 *)data; +- ops.oobbuf = (__u8 *)&pt1; +- +- retval = mtd->write_oob(mtd, addr, &ops); +- if (retval) { +- yaffs_trace(YAFFS_TRACE_MTD, +- "write_oob failed, chunk %d, mtd error %d\n", +- chunkInNAND, retval); +- } +- return retval ? YAFFS_FAIL : YAFFS_OK; +-} +- +-/* Return with empty ExtendedTags but add eccResult. +- */ +-static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval) +-{ +- if (etags) { +- memset(etags, 0, sizeof(*etags)); +- etags->eccResult = eccResult; +- } +- return retval; +-} +- +-/* Read a chunk (page) from NAND. +- * +- * Caller expects ExtendedTags data to be usable even on error; that is, +- * all members except eccResult and blockBad are zeroed. +- * +- * - Check ECC results for data (if applicable) +- * - Check for blank/erased block (return empty ExtendedTags if blank) +- * - Check the PackedTags1 mini-ECC (correct if necessary/possible) +- * - Convert PackedTags1 to ExtendedTags +- * - Update eccResult and blockBad members to refect state. +- * +- * Returns YAFFS_OK or YAFFS_FAIL. +- */ +-int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, +- int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags) +-{ +- struct mtd_info * mtd = dev->genericDevice; +- int chunkBytes = dev->nDataBytesPerChunk; +- loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; +- int eccres = YAFFS_ECC_RESULT_NO_ERROR; +- struct mtd_oob_ops ops; +- yaffs_PackedTags1 pt1; +- int retval; +- int deleted; +- +- memset(&ops, 0, sizeof(ops)); +- ops.mode = MTD_OOB_AUTO; +- ops.len = (data) ? chunkBytes : 0; +- ops.ooblen = YTAG1_SIZE; +- ops.datbuf = data; +- ops.oobbuf = (__u8 *)&pt1; +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) +- /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; +- * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. +- */ +- ops.len = (ops.datbuf) ? ops.len : ops.ooblen; +-#endif +- /* Read page and oob using MTD. +- * Check status and determine ECC result. +- */ +- retval = mtd->read_oob(mtd, addr, &ops); +- if (retval) { +- yaffs_trace(YAFFS_TRACE_MTD, +- "read_oob failed, chunk %d, mtd error %d\n", +- chunkInNAND, retval); +- } +- +- switch (retval) { +- case 0: +- /* no error */ +- break; +- +- case -EUCLEAN: +- /* MTD's ECC fixed the data */ +- eccres = YAFFS_ECC_RESULT_FIXED; +- dev->eccFixed++; +- break; +- +- case -EBADMSG: +- /* MTD's ECC could not fix the data */ +- dev->eccUnfixed++; +- /* fall into... */ +- default: +- rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0); +- etags->blockBad = (mtd->block_isbad)(mtd, addr); +- return YAFFS_FAIL; +- } +- +- /* Check for a blank/erased chunk. +- */ +- if (yaffs_CheckFF((__u8 *)&pt1, 8)) { +- /* when blank, upper layers want eccResult to be <= NO_ERROR */ +- return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK); +- } +- +-#ifndef CONFIG_YAFFS_9BYTE_TAGS +- /* Read deleted status (bit) then return it to it's non-deleted +- * state before performing tags mini-ECC check. pt1.deleted is +- * inverted. +- */ +- deleted = !pt1.deleted; +- pt1.deleted = 1; +-#else +- (void) deleted; /* not used */ +-#endif +- +- /* Check the packed tags mini-ECC and correct if necessary/possible. +- */ +- retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1); +- switch (retval) { +- case 0: +- /* no tags error, use MTD result */ +- break; +- case 1: +- /* recovered tags-ECC error */ +- dev->tagsEccFixed++; +- eccres = YAFFS_ECC_RESULT_FIXED; +- break; +- default: +- /* unrecovered tags-ECC error */ +- dev->tagsEccUnfixed++; +- return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL); +- } +- +- /* Unpack the tags to extended form and set ECC result. +- * [set shouldBeFF just to keep yaffs_UnpackTags1 happy] +- */ +- pt1.shouldBeFF = 0xFFFFFFFF; +- yaffs_UnpackTags1(etags, &pt1); +- etags->eccResult = eccres; +- +- /* Set deleted state. +- */ +-#ifndef CONFIG_YAFFS_9BYTE_TAGS +- etags->chunkDeleted = deleted; +-#else +- etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7); +-#endif +- return YAFFS_OK; +-} +- +-/* Mark a block bad. +- * +- * This is a persistant state. +- * Use of this function should be rare. +- * +- * Returns YAFFS_OK or YAFFS_FAIL. +- */ +-int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) +-{ +- struct mtd_info * mtd = dev->genericDevice; +- int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; +- int retval; +- +- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo); +- +- retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo); +- return (retval) ? YAFFS_FAIL : YAFFS_OK; +-} +- +-/* Check any MTD prerequists. +- * +- * Returns YAFFS_OK or YAFFS_FAIL. +- */ +-static int nandmtd1_TestPrerequists(struct mtd_info * mtd) +-{ +- /* 2.6.18 has mtd->ecclayout->oobavail */ +- /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */ +- int oobavail = mtd->ecclayout->oobavail; +- +- if (oobavail < YTAG1_SIZE) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "mtd device has only %d bytes for tags, need %d", +- oobavail, YTAG1_SIZE); +- return YAFFS_FAIL; +- } +- return YAFFS_OK; +-} +- +-/* Query for the current state of a specific block. +- * +- * Examine the tags of the first chunk of the block and return the state: +- * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad +- * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use +- * - YAFFS_BLOCK_STATE_EMPTY, the block is clean +- * +- * Always returns YAFFS_OK. +- */ +-int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, +- yaffs_BlockState * pState, int *pSequenceNumber) +-{ +- struct mtd_info * mtd = dev->genericDevice; +- int chunkNo = blockNo * dev->nChunksPerBlock; +- yaffs_ExtendedTags etags; +- int state = YAFFS_BLOCK_STATE_DEAD; +- int seqnum = 0; +- int retval; +- +- /* We don't yet have a good place to test for MTD config prerequists. +- * Do it here as we are called during the initial scan. +- */ +- if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) { +- return YAFFS_FAIL; +- } +- +- retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); +- if (etags.blockBad) { +- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, +- "block %d is marked bad", blockNo); +- state = YAFFS_BLOCK_STATE_DEAD; +- } +- else if (etags.chunkUsed) { +- state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; +- seqnum = etags.sequenceNumber; +- } +- else { +- state = YAFFS_BLOCK_STATE_EMPTY; +- } +- +- *pState = state; +- *pSequenceNumber = seqnum; +- +- /* query always succeeds */ +- return YAFFS_OK; +-} +- +-#endif /*KERNEL_VERSION*/ +- +---Boundary-00=_5LbTGmt62YoutxM-- +- +- +- +--- a/fs/yaffs2/yaffs_fs.c ++++ b/fs/yaffs2/yaffs_fs.c +@@ -32,7 +32,7 @@ + */ + + const char *yaffs_fs_c_version = +- "$Id: yaffs_fs.c,v 1.63 2007-09-19 20:35:40 imcd Exp $"; ++ "$Id: yaffs_fs.c,v 1.71 2009-01-22 00:45:54 charles Exp $"; + extern const char *yaffs_guts_c_version; + + #include +@@ -43,7 +43,6 @@ extern const char *yaffs_guts_c_version; + #include + #include + #include +-#include + #include + #include + #include +@@ -53,6 +52,8 @@ extern const char *yaffs_guts_c_version; + #include + #include + ++#include "asm/div64.h" ++ + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + + #include /* Added NCB 15-8-2003 */ +@@ -76,6 +77,12 @@ extern const char *yaffs_guts_c_version; + + #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 +@@ -84,6 +91,13 @@ extern const char *yaffs_guts_c_version; + #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 ++ ++ + #include + + #include "yportenv.h" +@@ -96,14 +110,30 @@ extern const char *yaffs_guts_c_version; + + 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 */ +@@ -127,6 +157,8 @@ static void yaffs_put_super(struct super + + 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); +@@ -181,9 +213,11 @@ static int yaffs_statfs(struct super_blo + #else + static int yaffs_statfs(struct super_block *sb, struct statfs *buf); + #endif +-static void yaffs_read_inode(struct inode *inode); + ++#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 *); + +@@ -193,10 +227,22 @@ static int yaffs_writepage(struct page * + #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); +@@ -209,8 +255,13 @@ static int yaffs_follow_link(struct dent + 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)) +@@ -224,6 +275,7 @@ static struct file_operations yaffs_file + .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)) +@@ -284,8 +336,13 @@ static struct file_operations yaffs_dir_ + + static struct super_operations yaffs_super_ops = { + .statfs = yaffs_statfs, ++ ++#ifndef YAFFS_USE_OWN_IGET + .read_inode = yaffs_read_inode, ++#endif ++#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, +@@ -429,6 +486,9 @@ static struct dentry *yaffs_lookup(struc + + } + ++ ++#ifdef YAFFS_HAS_PUT_INODE ++ + /* For now put inode is just for debugging + * Put inode is called when the inode **structure** is put. + */ +@@ -439,6 +499,7 @@ static void yaffs_put_inode(struct inode + 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) +@@ -667,6 +728,64 @@ static int yaffs_writepage(struct 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, (KERN_DEBUG "start yaffs_write_begin\n")); ++ /* Get a page */ ++ pg = __grab_cache_page(mapping,index); ++ *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, (KERN_DEBUG "end yaffs_write_begin - ok\n")); ++ ++ return 0; ++ ++out: ++ T(YAFFS_TRACE_OS, (KERN_DEBUG "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) + { +@@ -674,22 +793,69 @@ static int yaffs_prepare_write(struct fi + T(YAFFS_TRACE_OS, (KERN_DEBUG "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; ++ pgoff_t index = pos >> PAGE_CACHE_SHIFT; ++ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE -1); ++ ++ ++ ++ kva=kmap(pg); ++ addr = kva + offset_into_page; ++ ++ T(YAFFS_TRACE_OS, ++ (KERN_DEBUG "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, ++ (KERN_DEBUG ++ "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 = page_address(pg) + offset; ++ 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 = (unsigned)addr; ++ unsigned saddr; ++ ++ kva=kmap(pg); ++ addr = kva + offset; ++ ++ saddr = (unsigned) addr; + + T(YAFFS_TRACE_OS, + (KERN_DEBUG "yaffs_commit_write addr %x pos %x nBytes %d\n", saddr, +@@ -708,6 +874,8 @@ static int yaffs_commit_write(struct fil + SetPageUptodate(pg); + } + ++ kunmap(pg); ++ + T(YAFFS_TRACE_OS, + (KERN_DEBUG "yaffs_commit_write returning %d\n", + nWritten == nBytes ? 0 : nWritten)); +@@ -715,6 +883,8 @@ static int yaffs_commit_write(struct fil + return nWritten == nBytes ? 0 : nWritten; + + } ++#endif ++ + + static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj) + { +@@ -753,6 +923,8 @@ static void yaffs_FillInodeFromObject(st + break; + } + ++ inode->i_flags |= S_NOATIME; ++ + inode->i_ino = obj->objectId; + inode->i_mode = obj->yst_mode; + inode->i_uid = obj->yst_uid; +@@ -844,7 +1016,9 @@ struct inode *yaffs_get_inode(struct sup + T(YAFFS_TRACE_OS, + (KERN_DEBUG "yaffs_get_inode for object %d\n", obj->objectId)); + +- inode = iget(sb, obj->objectId); ++ inode = Y_IGET(sb, obj->objectId); ++ if(IS_ERR(inode)) ++ return NULL; + + /* NB Side effect: iget calls back to yaffs_read_inode(). */ + /* iget also increments the inode's i_count */ +@@ -910,13 +1084,55 @@ static ssize_t yaffs_file_write(struct f + 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 list_head *i; ++ struct ylist_head *i; + yaffs_Object *l; + + char name[YAFFS_MAX_NAME_LENGTH + 1]; +@@ -965,10 +1181,10 @@ static int yaffs_readdir(struct file *f, + f->f_version = inode->i_version; + } + +- list_for_each(i, &obj->variant.directoryVariant.children) { ++ ylist_for_each(i, &obj->variant.directoryVariant.children) { + curoffs++; + if (curoffs >= offset) { +- l = list_entry(i, yaffs_Object, siblings); ++ l = ylist_entry(i, yaffs_Object, siblings); + + yaffs_GetObjectName(l, name, + YAFFS_MAX_NAME_LENGTH + 1); +@@ -1269,7 +1485,7 @@ static int yaffs_rename(struct inode *ol + + if (target && + target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && +- !list_empty(&target->variant.directoryVariant.children)) { ++ !ylist_empty(&target->variant.directoryVariant.children)) { + + T(YAFFS_TRACE_OS, (KERN_DEBUG "target is non-empty dir\n")); + +@@ -1350,25 +1566,47 @@ static int yaffs_statfs(struct super_blo + buf->f_type = YAFFS_MAGIC; + buf->f_bsize = sb->s_blocksize; + buf->f_namelen = 255; +- if (sb->s_blocksize > dev->nDataBytesPerChunk) { +- ++ ++ 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); ++ (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_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; +@@ -1378,7 +1616,6 @@ static int yaffs_statfs(struct super_blo + } + + +-/** + static int yaffs_do_sync_fs(struct super_block *sb) + { + +@@ -1388,8 +1625,10 @@ static int yaffs_do_sync_fs(struct super + if(sb->s_dirt) { + yaffs_GrossLock(dev); + +- if(dev) ++ if(dev){ ++ yaffs_FlushEntireDeviceCache(dev); + yaffs_CheckpointSave(dev); ++ } + + yaffs_GrossUnlock(dev); + +@@ -1397,7 +1636,7 @@ static int yaffs_do_sync_fs(struct super + } + return 0; + } +-**/ ++ + + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + static void yaffs_write_super(struct super_block *sb) +@@ -1407,8 +1646,10 @@ static int yaffs_write_super(struct supe + { + + T(YAFFS_TRACE_OS, (KERN_DEBUG "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; /* yaffs_do_sync_fs(sb);*/ ++ return 0; + #endif + } + +@@ -1422,10 +1663,48 @@ static int yaffs_sync_fs(struct super_bl + + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n")); + +- return 0; /* yaffs_do_sync_fs(sb);*/ ++ 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, ++ (KERN_DEBUG "yaffs_iget for %lu\n", ino)); ++ ++ inode = iget_locked(sb, ino); ++ if (!inode) ++ return ERR_PTR(-ENOMEM); ++ if (!(inode->i_state & I_NEW)) ++ return inode; ++ ++ /* NB This is called as a side effect of other functions, but ++ * we had to release the lock to prevent deadlocks, so ++ * need to lock again. ++ */ ++ ++ yaffs_GrossLock(dev); ++ ++ obj = yaffs_FindObjectByNumber(dev, inode->i_ino); ++ ++ yaffs_FillInodeFromObject(inode, obj); ++ ++ yaffs_GrossUnlock(dev); ++ ++ unlock_new_inode(inode); ++ return inode; ++} ++ ++#else + + static void yaffs_read_inode(struct inode *inode) + { +@@ -1449,7 +1728,9 @@ static void yaffs_read_inode(struct inod + yaffs_GrossUnlock(dev); + } + +-static LIST_HEAD(yaffs_dev_list); ++#endif ++ ++static YLIST_HEAD(yaffs_dev_list); + + #if 0 // not used + static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) +@@ -1503,7 +1784,7 @@ static void yaffs_put_super(struct super + yaffs_GrossUnlock(dev); + + /* we assume this is protected by lock_kernel() in mount/umount */ +- list_del(&dev->devList); ++ ylist_del(&dev->devList); + + if(dev->spareBuffer){ + YFREE(dev->spareBuffer); +@@ -1532,8 +1813,8 @@ static void yaffs_MarkSuperBlockDirty(vo + struct super_block *sb = (struct super_block *)vsb; + + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_MarkSuperBlockDirty() sb = %p\n",sb)); +-// if(sb) +-// sb->s_dirt = 1; ++ if(sb) ++ sb->s_dirt = 1; + } + + typedef struct { +@@ -1602,6 +1883,7 @@ static struct super_block *yaffs_interna + + 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"); +@@ -1678,22 +1960,15 @@ static struct super_block *yaffs_interna + #ifdef CONFIG_YAFFS_AUTO_YAFFS2 + + if (yaffsVersion == 1 && +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +- mtd->writesize >= 2048) { +-#else +- mtd->oobblock >= 2048) { +-#endif ++ 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 && +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +- mtd->writesize == 512) { +-#else +- mtd->oobblock == 512) { +-#endif ++ if (yaffsVersion == 2 && ++ !options.inband_tags && ++ WRITE_SIZE(mtd) == 512){ + T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n")); + yaffsVersion = 1; + } +@@ -1719,12 +1994,9 @@ static struct super_block *yaffs_interna + return NULL; + } + +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +- if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE || +-#else +- if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE || +-#endif +- mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) { ++ 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")); +@@ -1784,9 +2056,10 @@ static struct super_block *yaffs_interna + dev->startBlock = 0; + dev->endBlock = nBlocks - 1; + dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; +- dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK; ++ 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) { +@@ -1799,15 +2072,14 @@ static struct super_block *yaffs_interna + dev->spareBuffer = YMALLOC(mtd->oobsize); + dev->isYaffs2 = 1; + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +- dev->nDataBytesPerChunk = mtd->writesize; ++ dev->totalBytesPerChunk = mtd->writesize; + dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; + #else +- dev->nDataBytesPerChunk = mtd->oobblock; ++ dev->totalBytesPerChunk = mtd->oobblock; + dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; + #endif + nBlocks = mtd->size / mtd->erasesize; + +- dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS; + dev->startBlock = 0; + dev->endBlock = nBlocks - 1; + } else { +@@ -1847,7 +2119,7 @@ static struct super_block *yaffs_interna + dev->skipCheckpointWrite = options.skip_checkpoint_write; + + /* we assume this is protected by lock_kernel() in mount/umount */ +- list_add_tail(&dev->devList, &yaffs_dev_list); ++ ylist_add_tail(&dev->devList, &yaffs_dev_list); + + init_MUTEX(&dev->grossLock); + +@@ -1884,6 +2156,9 @@ static struct super_block *yaffs_interna + 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; +@@ -1990,12 +2265,12 @@ static char *yaffs_dump_dev(char *buf, y + { + buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock); + buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); ++ buf += sprintf(buf, "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, "nCheckptResBlocks.. %d\n", dev->nCheckpointReservedBlocks); + buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint); + buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated); + buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes); +@@ -2006,10 +2281,8 @@ static char *yaffs_dump_dev(char *buf, y + 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", ++ 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); +@@ -2025,6 +2298,7 @@ static char *yaffs_dump_dev(char *buf, y + 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; + } +@@ -2033,7 +2307,7 @@ static int yaffs_proc_read(char *page, + char **start, + off_t offset, int count, int *eof, void *data) + { +- struct list_head *item; ++ struct ylist_head *item; + char *buf = page; + int step = offset; + int n = 0; +@@ -2057,8 +2331,8 @@ static int yaffs_proc_read(char *page, + lock_kernel(); + + /* Locate and print the Nth entry. Order N-squared but N is small. */ +- list_for_each(item, &yaffs_dev_list) { +- yaffs_Device *dev = list_entry(item, yaffs_Device, devList); ++ ylist_for_each(item, &yaffs_dev_list) { ++ yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList); + if (n < step) { + n++; + continue; +@@ -2231,7 +2505,7 @@ static int __init init_yaffs_fs(void) + /* Install the proc_fs entry */ + my_proc_entry = create_proc_entry("yaffs", + S_IRUGO | S_IFREG, +- &proc_root); ++ YPROC_ROOT); + + if (my_proc_entry) { + my_proc_entry->write_proc = yaffs_proc_write; +@@ -2277,7 +2551,7 @@ static void __exit exit_yaffs_fs(void) + T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__ + " removing. \n")); + +- remove_proc_entry("yaffs", &proc_root); ++ remove_proc_entry("yaffs", YPROC_ROOT); + + fsinst = fs_to_install; + +--- /dev/null ++++ b/fs/yaffs2/yaffs_getblockinfo.h +@@ -0,0 +1,34 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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_GETBLOCKINFO_H__ ++#define __YAFFS_GETBLOCKINFO_H__ ++ ++#include "yaffs_guts.h" ++ ++/* Function to manipulate block info */ ++static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk) ++{ ++ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR), ++ blk)); ++ YBUG(); ++ } ++ return &dev->blockInfo[blk - dev->internalStartBlock]; ++} ++ ++#endif +--- a/fs/yaffs2/yaffs_nand.c ++++ b/fs/yaffs2/yaffs_nand.c +@@ -12,12 +12,13 @@ + */ + + const char *yaffs_nand_c_version = +- "$Id: yaffs_nand.c,v 1.7 2007-02-14 01:09:06 wookey Exp $"; ++ "$Id: yaffs_nand.c,v 1.9 2008-05-05 07:58:58 charles Exp $"; + + #include "yaffs_nand.h" + #include "yaffs_tagscompat.h" + #include "yaffs_tagsvalidity.h" + ++#include "yaffs_getblockinfo.h" + + int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, + __u8 * buffer, +@@ -98,7 +99,7 @@ int yaffs_MarkBlockBad(yaffs_Device * de + int yaffs_QueryInitialBlockState(yaffs_Device * dev, + int blockNo, + yaffs_BlockState * state, +- unsigned *sequenceNumber) ++ __u32 *sequenceNumber) + { + blockNo -= dev->blockOffset; + +--- a/fs/yaffs2/yaffs_guts.c ++++ b/fs/yaffs2/yaffs_guts.c +@@ -11,14 +11,16 @@ + * published by the Free Software Foundation. + */ + ++ + const char *yaffs_guts_c_version = +- "$Id: yaffs_guts.c,v 1.49 2007-05-15 20:07:40 charles Exp $"; ++ "$Id: yaffs_guts.c,v 1.76 2009-01-23 06:36:49 charles Exp $"; + + #include "yportenv.h" + + #include "yaffsinterface.h" + #include "yaffs_guts.h" + #include "yaffs_tagsvalidity.h" ++#include "yaffs_getblockinfo.h" + + #include "yaffs_tagscompat.h" + #ifndef CONFIG_YAFFS_USE_OWN_SORT +@@ -32,11 +34,6 @@ const char *yaffs_guts_c_version = + #include "yaffs_packedtags2.h" + + +-#ifdef CONFIG_YAFFS_WINCE +-void yfsd_LockYAFFS(BOOL fsLockOnly); +-void yfsd_UnlockYAFFS(BOOL fsLockOnly); +-#endif +- + #define YAFFS_PASSIVE_GC_CHUNKS 2 + + #include "yaffs_ecc.h" +@@ -78,9 +75,6 @@ static int yaffs_DoGenericObjectDeletion + + static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blockNo); + +-static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo); +-static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, +- int lineNo); + + static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, + int chunkInNAND); +@@ -99,6 +93,7 @@ static void yaffs_VerifyFreeChunks(yaffs + + 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 +@@ -121,95 +116,109 @@ static yaffs_Tnode *yaffs_FindLevel0Tnod + + /* Function to calculate chunk and offset */ + +-static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, __u32 *chunk, __u32 *offset) ++static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut, __u32 *offsetOut) + { +- if(dev->chunkShift){ +- /* Easy-peasy power of 2 case */ +- *chunk = (__u32)(addr >> dev->chunkShift); +- *offset = (__u32)(addr & dev->chunkMask); +- } +- else if(dev->crumbsPerChunk) ++ int chunk; ++ __u32 offset; ++ ++ chunk = (__u32)(addr >> dev->chunkShift); ++ ++ if(dev->chunkDiv == 1) + { +- /* Case where we're using "crumbs" */ +- *offset = (__u32)(addr & dev->crumbMask); +- addr >>= dev->crumbShift; +- *chunk = ((__u32)addr)/dev->crumbsPerChunk; +- *offset += ((addr - (*chunk * dev->crumbsPerChunk)) << dev->crumbShift); ++ /* easy power of 2 case */ ++ offset = (__u32)(addr & dev->chunkMask); + } + else +- YBUG(); ++ { ++ /* Non power-of-2 case */ ++ ++ loff_t chunkBase; ++ ++ chunk /= dev->chunkDiv; ++ ++ chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk; ++ offset = (__u32)(addr - chunkBase); ++ } ++ ++ *chunkOut = chunk; ++ *offsetOut = offset; + } + +-/* Function to return the number of shifts for a power of 2 greater than or equal ++/* Function to return the number of shifts for a power of 2 greater than or equal + * to the given number + * Note we don't try to cater for all possible numbers and this does not have to + * be hellishly efficient. + */ +- ++ + static __u32 ShiftsGE(__u32 x) + { + int extraBits; + int nShifts; +- ++ + nShifts = extraBits = 0; +- ++ + while(x>1){ + if(x & 1) extraBits++; + x>>=1; + nShifts++; + } + +- if(extraBits) ++ if(extraBits) + nShifts++; +- ++ + return nShifts; + } + + /* Function to return the number of shifts to get a 1 in bit 0 + */ +- +-static __u32 ShiftDiv(__u32 x) ++ ++static __u32 Shifts(__u32 x) + { + int nShifts; +- ++ + nShifts = 0; +- ++ + if(!x) return 0; +- ++ + while( !(x&1)){ + x>>=1; + nShifts++; + } +- ++ + return nShifts; + } + + + +-/* ++/* + * Temporary buffer manipulations. + */ + +-static int yaffs_InitialiseTempBuffers(yaffs_Device *dev) ++static int yaffs_InitialiseTempBuffers(yaffs_Device *dev) + { + int i; + __u8 *buf = (__u8 *)1; +- ++ + memset(dev->tempBuffer,0,sizeof(dev->tempBuffer)); +- ++ + for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { + dev->tempBuffer[i].line = 0; /* not in use */ + dev->tempBuffer[i].buffer = buf = +- YMALLOC_DMA(dev->nDataBytesPerChunk); ++ YMALLOC_DMA(dev->totalBytesPerChunk); + } +- ++ + return buf ? YAFFS_OK : YAFFS_FAIL; +- ++ + } + +-static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo) ++__u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo) + { + int i, j; ++ ++ dev->tempInUse++; ++ if(dev->tempInUse > dev->maxTemp) ++ dev->maxTemp = dev->tempInUse; ++ + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { + if (dev->tempBuffer[i].line == 0) { + dev->tempBuffer[i].line = lineNo; +@@ -242,10 +251,13 @@ static __u8 *yaffs_GetTempBuffer(yaffs_D + + } + +-static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, ++void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, + int lineNo) + { + int i; ++ ++ dev->tempInUse--; ++ + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { + if (dev->tempBuffer[i].buffer == buffer) { + dev->tempBuffer[i].line = 0; +@@ -337,7 +349,7 @@ static Y_INLINE void yaffs_ClearChunkBit + 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)); +@@ -375,16 +387,16 @@ static int yaffs_CountChunkBits(yaffs_De + n++; + x >>=1; + } +- ++ + blkBits++; + } + return n; + } + +-/* ++/* + * Verification code + */ +- ++ + static int yaffs_SkipVerification(yaffs_Device *dev) + { + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); +@@ -417,14 +429,14 @@ static void yaffs_VerifyBlock(yaffs_Devi + { + int actuallyUsed; + int inUse; +- ++ + if(yaffs_SkipVerification(dev)) + return; +- ++ + /* Report illegal runtime states */ +- if(bi->blockState <0 || bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) ++ if(bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) + T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has undefined state %d"TENDSTR),n,bi->blockState)); +- ++ + switch(bi->blockState){ + case YAFFS_BLOCK_STATE_UNKNOWN: + case YAFFS_BLOCK_STATE_SCANNING: +@@ -432,43 +444,44 @@ static void yaffs_VerifyBlock(yaffs_Devi + T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has bad run-state %s"TENDSTR), + n,blockStateName[bi->blockState])); + } +- ++ + /* Check pages in use and soft deletions are legal */ +- ++ + actuallyUsed = bi->pagesInUse - bi->softDeletions; +- ++ + if(bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock || + bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock || + actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock) + T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR), + n,bi->pagesInUse,bi->softDeletions)); +- +- ++ ++ + /* Check chunk bitmap legal */ + inUse = yaffs_CountChunkBits(dev,n); + if(inUse != bi->pagesInUse) + T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR), + n,bi->pagesInUse,inUse)); +- ++ + /* Check that the sequence number is valid. +- * Ten million is legal, but is very unlikely ++ * Ten million is legal, but is very unlikely + */ +- if(dev->isYaffs2 && ++ if(dev->isYaffs2 && + (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) && + (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000 )) + T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has suspect sequence number of %d"TENDSTR), + n,bi->sequenceNumber)); +- ++ + } + + static void yaffs_VerifyCollectedBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n) + { + yaffs_VerifyBlock(dev,bi,n); +- ++ + /* After collection the block should be in the erased state */ +- /* TODO: This will need to change if we do partial gc */ +- +- if(bi->blockState != YAFFS_BLOCK_STATE_EMPTY){ ++ /* This will need to change if we do partial gc */ ++ ++ if(bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && ++ bi->blockState != YAFFS_BLOCK_STATE_EMPTY){ + T(YAFFS_TRACE_ERROR,(TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), + n,bi->blockState)); + } +@@ -479,28 +492,28 @@ static void yaffs_VerifyBlocks(yaffs_Dev + int i; + int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; + int nIllegalBlockStates = 0; +- ++ + + if(yaffs_SkipVerification(dev)) + return; + + memset(nBlocksPerState,0,sizeof(nBlocksPerState)); + +- ++ + for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++){ + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); + yaffs_VerifyBlock(dev,bi,i); + +- if(bi->blockState >=0 && bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) ++ if(bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) + nBlocksPerState[bi->blockState]++; + else + nIllegalBlockStates++; +- ++ + } +- ++ + T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR))); + T(YAFFS_TRACE_VERIFY,(TSTR("Block summary"TENDSTR))); +- ++ + T(YAFFS_TRACE_VERIFY,(TSTR("%d blocks have illegal states"TENDSTR),nIllegalBlockStates)); + if(nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) + T(YAFFS_TRACE_VERIFY,(TSTR("Too many allocating blocks"TENDSTR))); +@@ -509,17 +522,17 @@ static void yaffs_VerifyBlocks(yaffs_Dev + T(YAFFS_TRACE_VERIFY, + (TSTR("%s %d blocks"TENDSTR), + blockStateName[i],nBlocksPerState[i])); +- ++ + if(dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) + T(YAFFS_TRACE_VERIFY, + (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), + dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); +- ++ + if(dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) + T(YAFFS_TRACE_VERIFY, + (TSTR("Erased block count wrong dev %d count %d"TENDSTR), + dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); +- ++ + if(nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1) + T(YAFFS_TRACE_VERIFY, + (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR), +@@ -535,16 +548,16 @@ static void yaffs_VerifyBlocks(yaffs_Dev + */ + static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) + { +- if(yaffs_SkipVerification(obj->myDev)) ++ if(obj && yaffs_SkipVerification(obj->myDev)) + return; +- ++ + if(!(tags && obj && oh)){ + T(YAFFS_TRACE_VERIFY, + (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR), + (__u32)tags,(__u32)obj,(__u32)oh)); + return; + } +- ++ + if(oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || + oh->type > YAFFS_OBJECT_TYPE_MAX) + T(YAFFS_TRACE_VERIFY, +@@ -559,25 +572,25 @@ static void yaffs_VerifyObjectHeader(yaf + + /* + * Check that the object's parent ids match if parentCheck requested. +- * ++ * + * Tests do not apply to the root object. + */ +- ++ + if(parentCheck && tags->objectId > 1 && !obj->parent) + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR), + tags->objectId, oh->parentObjectId)); +- +- ++ ++ + if(parentCheck && obj->parent && +- oh->parentObjectId != obj->parent->objectId && ++ oh->parentObjectId != obj->parent->objectId && + (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED || + obj->parent->objectId != YAFFS_OBJECTID_DELETED)) + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR), + tags->objectId, oh->parentObjectId, obj->parent->objectId)); +- +- ++ ++ + if(tags->objectId > 1 && oh->name[0] == 0) /* Null name */ + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d header name is NULL"TENDSTR), +@@ -597,7 +610,6 @@ static int yaffs_VerifyTnodeWorker(yaffs + int i; + yaffs_Device *dev = obj->myDev; + int ok = 1; +- int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + + if (tn) { + if (level > 0) { +@@ -611,15 +623,14 @@ static int yaffs_VerifyTnodeWorker(yaffs + } + } + } else if (level == 0) { +- int i; + yaffs_ExtendedTags tags; + __u32 objectId = obj->objectId; +- ++ + chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS; +- ++ + for(i = 0; i < YAFFS_NTNODES_LEVEL0; i++){ + __u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i); +- ++ + if(theChunk > 0){ + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */ + yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags); +@@ -646,18 +657,20 @@ static void yaffs_VerifyFile(yaffs_Objec + __u32 lastChunk; + __u32 x; + __u32 i; +- int ok; + yaffs_Device *dev; + yaffs_ExtendedTags tags; + yaffs_Tnode *tn; + __u32 objectId; +- +- if(obj && yaffs_SkipVerification(obj->myDev)) ++ ++ if(!obj) + return; + ++ if(yaffs_SkipVerification(obj->myDev)) ++ return; ++ + dev = obj->myDev; + objectId = obj->objectId; +- ++ + /* Check file size is consistent with tnode depth */ + lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1; + x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; +@@ -666,23 +679,23 @@ static void yaffs_VerifyFile(yaffs_Objec + x >>= YAFFS_TNODES_INTERNAL_BITS; + requiredTallness++; + } +- ++ + actualTallness = obj->variant.fileVariant.topLevel; +- ++ + if(requiredTallness > actualTallness ) + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR), + obj->objectId,actualTallness, requiredTallness)); +- +- +- /* Check that the chunks in the tnode tree are all correct. ++ ++ ++ /* Check that the chunks in the tnode tree are all correct. + * We do this by scanning through the tnode tree and + * checking the tags for every chunk match. + */ + + if(yaffs_SkipNANDVerification(dev)) + return; +- ++ + for(i = 1; i <= lastChunk; i++){ + tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant,i); + +@@ -703,18 +716,12 @@ static void yaffs_VerifyFile(yaffs_Objec + + } + +-static void yaffs_VerifyDirectory(yaffs_Object *obj) +-{ +- if(obj && yaffs_SkipVerification(obj->myDev)) +- return; +- +-} + + static void yaffs_VerifyHardLink(yaffs_Object *obj) + { + if(obj && yaffs_SkipVerification(obj->myDev)) + return; +- ++ + /* Verify sane equivalent object */ + } + +@@ -722,7 +729,7 @@ static void yaffs_VerifySymlink(yaffs_Ob + { + if(obj && yaffs_SkipVerification(obj->myDev)) + return; +- ++ + /* Verify symlink string */ + } + +@@ -735,69 +742,77 @@ static void yaffs_VerifySpecial(yaffs_Ob + static void yaffs_VerifyObject(yaffs_Object *obj) + { + yaffs_Device *dev; +- ++ + __u32 chunkMin; + __u32 chunkMax; +- ++ + __u32 chunkIdOk; +- __u32 chunkIsLive; +- ++ __u32 chunkInRange; ++ __u32 chunkShouldNotBeDeleted; ++ __u32 chunkValid; ++ + if(!obj) + return; +- ++ ++ if(obj->beingCreated) ++ return; ++ + dev = obj->myDev; +- ++ + if(yaffs_SkipVerification(dev)) + return; +- ++ + /* Check sane object header chunk */ + + chunkMin = dev->internalStartBlock * dev->nChunksPerBlock; + chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1; + +- chunkIdOk = (obj->chunkId >= chunkMin && obj->chunkId <= chunkMax); +- chunkIsLive = chunkIdOk && ++ chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax); ++ chunkIdOk = chunkInRange || obj->hdrChunk == 0; ++ chunkValid = chunkInRange && + yaffs_CheckChunkBit(dev, +- obj->chunkId / dev->nChunksPerBlock, +- obj->chunkId % dev->nChunksPerBlock); ++ obj->hdrChunk / dev->nChunksPerBlock, ++ obj->hdrChunk % dev->nChunksPerBlock); ++ chunkShouldNotBeDeleted = chunkInRange && !chunkValid; ++ + if(!obj->fake && +- (!chunkIdOk || !chunkIsLive)) { ++ (!chunkIdOk || chunkShouldNotBeDeleted)) { + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), +- obj->objectId,obj->chunkId, ++ obj->objectId,obj->hdrChunk, + chunkIdOk ? "" : ",out of range", +- chunkIsLive || !chunkIdOk ? "" : ",marked as deleted")); ++ chunkShouldNotBeDeleted ? ",marked as deleted" : "")); + } +- +- if(chunkIdOk && chunkIsLive &&!yaffs_SkipNANDVerification(dev)) { ++ ++ if(chunkValid &&!yaffs_SkipNANDVerification(dev)) { + yaffs_ExtendedTags tags; + yaffs_ObjectHeader *oh; + __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__); +- ++ + oh = (yaffs_ObjectHeader *)buffer; + +- yaffs_ReadChunkWithTagsFromNAND(dev, obj->chunkId,buffer, &tags); ++ yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk,buffer, &tags); + + yaffs_VerifyObjectHeader(obj,oh,&tags,1); +- ++ + yaffs_ReleaseTempBuffer(dev,buffer,__LINE__); + } +- ++ + /* Verify it has a parent */ + if(obj && !obj->fake && + (!obj->parent || obj->parent->myDev != dev)){ + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), +- obj->objectId,obj->parent)); ++ obj->objectId,obj->parent)); + } +- ++ + /* Verify parent is a directory */ + if(obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY){ + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), +- obj->objectId,obj->parent->variantType)); ++ obj->objectId,obj->parent->variantType)); + } +- ++ + switch(obj->variantType){ + case YAFFS_OBJECT_TYPE_FILE: + yaffs_VerifyFile(obj); +@@ -818,31 +833,31 @@ static void yaffs_VerifyObject(yaffs_Obj + default: + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d has illegaltype %d"TENDSTR), +- obj->objectId,obj->variantType)); ++ obj->objectId,obj->variantType)); + break; + } +- +- ++ ++ + } + + static void yaffs_VerifyObjects(yaffs_Device *dev) + { +- yaffs_Object *obj; +- int i; +- struct list_head *lh; +- +- if(yaffs_SkipVerification(dev)) +- return; +- +- /* Iterate through the objects in each hash entry */ +- +- for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++){ +- list_for_each(lh, &dev->objectBucket[i].list) { +- if (lh) { +- obj = list_entry(lh, yaffs_Object, hashLink); +- yaffs_VerifyObject(obj); +- } +- } ++ yaffs_Object *obj; ++ int i; ++ struct ylist_head *lh; ++ ++ if(yaffs_SkipVerification(dev)) ++ return; ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ 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); ++ } ++ } + } + + } +@@ -851,7 +866,7 @@ static void yaffs_VerifyObjects(yaffs_De + /* + * Simple hash function. Needs to have a reasonable spread + */ +- ++ + static Y_INLINE int yaffs_HashFunction(int n) + { + n = abs(n); +@@ -859,9 +874,10 @@ static Y_INLINE int yaffs_HashFunction(i + } + + /* +- * Access functions to useful fake objects ++ * Access functions to useful fake objects. ++ * Note that root might have a presence in NAND if permissions are set. + */ +- ++ + yaffs_Object *yaffs_Root(yaffs_Device * dev) + { + return dev->rootDir; +@@ -876,7 +892,7 @@ yaffs_Object *yaffs_LostNFound(yaffs_Dev + /* + * Erased NAND checking functions + */ +- ++ + int yaffs_CheckFF(__u8 * buffer, int nBytes) + { + /* Horrible, slow implementation */ +@@ -898,10 +914,10 @@ static int yaffs_CheckChunkErased(struct + 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, +@@ -915,7 +931,6 @@ static int yaffs_CheckChunkErased(struct + + } + +- + static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, + const __u8 * data, + yaffs_ExtendedTags * tags, +@@ -992,7 +1007,11 @@ static int yaffs_WriteNewChunkWithTagsTo + /* Copy the data into the robustification buffer */ + yaffs_HandleWriteChunkOk(dev, chunk, data, tags); + +- } while (writeOk != YAFFS_OK && attempts < yaffs_wr_attempts); ++ } while (writeOk != YAFFS_OK && ++ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); ++ ++ if(!writeOk) ++ chunk = -1; + + if (attempts > 1) { + T(YAFFS_TRACE_ERROR, +@@ -1008,13 +1027,13 @@ static int yaffs_WriteNewChunkWithTagsTo + /* + * 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); +- ++ + yaffs_MarkBlockBad(dev, blockInNAND); + + bi->blockState = YAFFS_BLOCK_STATE_DEAD; +@@ -1028,7 +1047,7 @@ static void yaffs_RetireBlock(yaffs_Devi + * Functions for robustisizing TODO + * + */ +- ++ + static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, + const __u8 * data, + const yaffs_ExtendedTags * tags) +@@ -1046,13 +1065,13 @@ void yaffs_HandleChunkError(yaffs_Device + 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))); + + } +- ++ + } + } + +@@ -1063,30 +1082,30 @@ static void yaffs_HandleWriteChunkError( + 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 ------------*/ ++/*---------------- Name handling functions ------------*/ + + static __u16 yaffs_CalcNameSum(const YCHAR * name) + { + __u16 sum = 0; + __u16 i = 1; + +- YUCHAR *bname = (YUCHAR *) name; ++ const YUCHAR *bname = (const YUCHAR *) name; + if (bname) { + while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) { + +@@ -1099,12 +1118,14 @@ static __u16 yaffs_CalcNameSum(const YCH + 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 { +@@ -1120,7 +1141,7 @@ static void yaffs_SetObjectName(yaffs_Ob + * 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 +@@ -1138,11 +1159,15 @@ static int yaffs_CreateTnodes(yaffs_Devi + + 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); +@@ -1175,7 +1200,7 @@ static int yaffs_CreateTnodes(yaffs_Devi + 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; +@@ -1190,7 +1215,7 @@ static int yaffs_CreateTnodes(yaffs_Devi + * 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, +@@ -1233,17 +1258,23 @@ static yaffs_Tnode *yaffs_GetTnodeRaw(ya + 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, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); ++ memset(tn, 0, tnodeSize); + +- return tn; ++ return tn; + } + + /* FreeTnode frees up a tnode and puts it back on the free list */ +@@ -1262,6 +1293,8 @@ static void yaffs_FreeTnode(yaffs_Device + dev->freeTnodes = tn; + dev->nFreeTnodes++; + } ++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ ++ + } + + static void yaffs_DeinitialiseTnodes(yaffs_Device * dev) +@@ -1299,19 +1332,19 @@ void yaffs_PutLevel0Tnode(yaffs_Device * + __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++;; +@@ -1328,24 +1361,24 @@ static __u32 yaffs_GetChunkGroupBase(yaf + __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; + } + +@@ -1394,7 +1427,7 @@ static yaffs_Tnode *yaffs_FindLevel0Tnod + while (level > 0 && tn) { + tn = tn-> + internal[(chunkId >> +- ( YAFFS_TNODES_LEVEL0_BITS + ++ ( YAFFS_TNODES_LEVEL0_BITS + + (level - 1) * + YAFFS_TNODES_INTERNAL_BITS) + ) & +@@ -1416,7 +1449,7 @@ static yaffs_Tnode *yaffs_FindLevel0Tnod + * 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, +@@ -1453,7 +1486,7 @@ static yaffs_Tnode *yaffs_AddOrFindLevel + 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) { +@@ -1472,7 +1505,7 @@ static yaffs_Tnode *yaffs_AddOrFindLevel + + l = fStruct->topLevel; + tn = fStruct->top; +- ++ + if(l > 0) { + while (l > 0 && tn) { + x = (chunkId >> +@@ -1492,13 +1525,13 @@ static yaffs_Tnode *yaffs_AddOrFindLevel + 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--; + } +@@ -1539,7 +1572,7 @@ static int yaffs_FindChunkInGroup(yaffs_ + + /* 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 1 if the tree was deleted. + * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete. + */ + +@@ -1653,7 +1686,7 @@ static void yaffs_SoftDeleteChunk(yaffs_ + * 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) + { +@@ -1694,7 +1727,7 @@ static int yaffs_SoftDeleteWorker(yaffs_ + 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 ++ * We make an assumption that a chunk group is not larger than + * a block. + */ + yaffs_SoftDeleteChunk(dev, theChunk); +@@ -1796,7 +1829,7 @@ static int yaffs_PruneFileStructure(yaff + /* 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 ++ * We can do this if only the 0th element in the tnode is in use + * (ie all the non-zero are NULL) + */ + +@@ -1850,14 +1883,14 @@ static int yaffs_CreateFreeObjects(yaffs + (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]); ++ } + +- /* Hook them into the free list */ +- for (i = 0; i < nObjects - 1; i++) { +- newObjects[i].siblings.next = +- (struct list_head *)(&newObjects[i + 1]); +- } +- +- newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects; ++ newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects; + dev->freeObjects = newObjects; + dev->nFreeObjects += nObjects; + dev->nObjectsCreated += nObjects; +@@ -1877,6 +1910,9 @@ static yaffs_Object *yaffs_AllocateEmpty + { + 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); +@@ -1887,25 +1923,40 @@ static yaffs_Object *yaffs_AllocateEmpty + 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->chunkId = -1; ++ tn->hdrChunk = 0; + tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN; +- INIT_LIST_HEAD(&(tn->hardLinks)); +- INIT_LIST_HEAD(&(tn->hashLink)); +- INIT_LIST_HEAD(&tn->siblings); ++ 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 ++ /* 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; + } +@@ -1917,14 +1968,14 @@ static yaffs_Object *yaffs_CreateFakeDir + yaffs_Object *obj = + yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); + if (obj) { +- obj->fake = 1; /* it is fake so it has no NAND presence... */ ++ obj->fake = 1; /* it is fake so it might have no NAND presence... */ + obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */ + obj->unlinkAllowed = 0; /* ... or unlink it */ + obj->deleted = 0; + obj->unlinked = 0; + obj->yst_mode = mode; + obj->myDev = dev; +- obj->chunkId = 0; /* Not a valid chunk. */ ++ obj->hdrChunk = 0; /* Not a valid chunk. */ + } + + return obj; +@@ -1934,14 +1985,14 @@ static yaffs_Object *yaffs_CreateFakeDir + static void yaffs_UnhashObject(yaffs_Object * tn) + { + int bucket; +- yaffs_Device *dev = tn->myDev; ++ yaffs_Device *dev = tn->myDev; + +- /* If it is still linked into the bucket list, free from the list */ +- if (!list_empty(&tn->hashLink)) { +- list_del_init(&tn->hashLink); +- bucket = yaffs_HashFunction(tn->objectId); +- dev->objectBucket[bucket].count--; +- } ++ /* 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--; ++ } + + } + +@@ -1951,6 +2002,13 @@ static void yaffs_FreeObject(yaffs_Objec + + yaffs_Device *dev = tn->myDev; + ++ ++ if(tn->parent) ++ YBUG(); ++ if(!ylist_empty(&tn->siblings)) ++ YBUG(); ++ ++ + #ifdef __KERNEL__ + if (tn->myInode) { + /* We're still hooked up to a cached inode. +@@ -1961,12 +2019,18 @@ static void yaffs_FreeObject(yaffs_Objec + } + #endif + +- yaffs_UnhashObject(tn); ++ 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*/ + +- /* Link into the free list. */ +- tn->siblings.next = (struct list_head *)(dev->freeObjects); +- dev->freeObjects = tn; +- dev->nFreeObjects++; + } + + #ifdef __KERNEL__ +@@ -2004,12 +2068,12 @@ static void yaffs_InitialiseObjects(yaff + + dev->allocatedObjectList = NULL; + dev->freeObjects = NULL; +- dev->nFreeObjects = 0; ++ dev->nFreeObjects = 0; + +- for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { +- INIT_LIST_HEAD(&dev->objectBucket[i].list); +- dev->objectBucket[i].count = 0; +- } ++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { ++ YINIT_LIST_HEAD(&dev->objectBucket[i].list); ++ dev->objectBucket[i].count = 0; ++ } + + } + +@@ -2055,26 +2119,26 @@ static int yaffs_CreateNewObjectNumber(y + + /* Now find an object value that has not already been taken + * by scanning the list. +- */ ++ */ + +- int found = 0; +- struct list_head *i; ++ int found = 0; ++ struct ylist_head *i; + +- __u32 n = (__u32) bucket; ++ __u32 n = (__u32) bucket; + + /* yaffs_CheckObjectHashSanity(); */ + + while (!found) { +- found = 1; +- n += YAFFS_NOBJECT_BUCKETS; +- if (1 || dev->objectBucket[bucket].count > 0) { +- list_for_each(i, &dev->objectBucket[bucket].list) { +- /* If there is already one in the list */ +- if (i +- && list_entry(i, yaffs_Object, +- hashLink)->objectId == n) { +- found = 0; +- } ++ 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; ++ } + } + } + } +@@ -2085,27 +2149,27 @@ static int yaffs_CreateNewObjectNumber(y + + static void yaffs_HashObject(yaffs_Object * in) + { +- int bucket = yaffs_HashFunction(in->objectId); +- yaffs_Device *dev = in->myDev; ++ int bucket = yaffs_HashFunction(in->objectId); ++ yaffs_Device *dev = in->myDev; + +- list_add(&in->hashLink, &dev->objectBucket[bucket].list); +- dev->objectBucket[bucket].count++; ++ 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 list_head *i; +- yaffs_Object *in; +- +- list_for_each(i, &dev->objectBucket[bucket].list) { +- /* Look if it is in the list */ +- if (i) { +- in = list_entry(i, yaffs_Object, hashLink); +- if (in->objectId == 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 */ ++ /* Don't tell the VFS about this one if it is defered free */ + if (in->deferedFree) + return NULL; + #endif +@@ -2123,7 +2187,7 @@ yaffs_Object *yaffs_CreateNewObject(yaff + { + + yaffs_Object *theObject; +- yaffs_Tnode *tn; ++ yaffs_Tnode *tn = NULL; + + if (number < 0) { + number = yaffs_CreateNewObjectNumber(dev); +@@ -2132,7 +2196,7 @@ yaffs_Object *yaffs_CreateNewObject(yaff + theObject = yaffs_AllocateEmptyObject(dev); + if(!theObject) + return NULL; +- ++ + if(type == YAFFS_OBJECT_TYPE_FILE){ + tn = yaffs_GetTnode(dev); + if(!tn){ +@@ -2140,8 +2204,8 @@ yaffs_Object *yaffs_CreateNewObject(yaff + return NULL; + } + } +- +- ++ ++ + + if (theObject) { + theObject->fake = 0; +@@ -2162,19 +2226,25 @@ yaffs_Object *yaffs_CreateNewObject(yaff + theObject->yst_atime = theObject->yst_mtime = + theObject->yst_ctime = Y_CURRENT_TIME; + #endif ++ ++#if 0 ++ theObject->sum_prev = 12345; ++ theObject->sum_trailer = 6789; ++#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: +- INIT_LIST_HEAD(&theObject->variant.directoryVariant. +- children); +- break; +- case YAFFS_OBJECT_TYPE_SYMLINK: ++ 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 */ +@@ -2205,7 +2275,7 @@ static yaffs_Object *yaffs_FindOrCreateO + return theObject; + + } +- ++ + + static YCHAR *yaffs_CloneString(const YCHAR * str) + { +@@ -2227,7 +2297,7 @@ static YCHAR *yaffs_CloneString(const YC + * 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, +@@ -2238,7 +2308,7 @@ static yaffs_Object *yaffs_MknodObject(y + const YCHAR * aliasString, __u32 rdev) + { + yaffs_Object *in; +- YCHAR *str; ++ YCHAR *str = NULL; + + yaffs_Device *dev = parent->myDev; + +@@ -2249,6 +2319,9 @@ static yaffs_Object *yaffs_MknodObject(y + + in = yaffs_CreateNewObject(dev, -1, type); + ++ if(!in) ++ return YAFFS_FAIL; ++ + if(type == YAFFS_OBJECT_TYPE_SYMLINK){ + str = yaffs_CloneString(aliasString); + if(!str){ +@@ -2256,11 +2329,11 @@ static yaffs_Object *yaffs_MknodObject(y + return NULL; + } + } +- +- ++ ++ + + if (in) { +- in->chunkId = -1; ++ in->hdrChunk = 0; + in->valid = 1; + in->variantType = type; + +@@ -2293,13 +2366,13 @@ static yaffs_Object *yaffs_MknodObject(y + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + in->variant.hardLinkVariant.equivalentObject = +- equivalentObject; +- in->variant.hardLinkVariant.equivalentObjectId = +- equivalentObject->objectId; +- list_add(&in->hardLinks, &equivalentObject->hardLinks); +- break; +- case YAFFS_OBJECT_TYPE_FILE: +- case YAFFS_OBJECT_TYPE_DIRECTORY: ++ 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 */ +@@ -2378,11 +2451,11 @@ static int yaffs_ChangeObjectName(yaffs_ + if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { + T(YAFFS_TRACE_ALWAYS, + (TSTR +- ("tragendy: yaffs_ChangeObjectName: newDir is not a directory" ++ ("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); +@@ -2395,9 +2468,9 @@ static int yaffs_ChangeObjectName(yaffs_ + + existingTarget = yaffs_FindObjectByName(newDir, newName); + +- /* If the object is a file going into the unlinked directory, ++ /* 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 ++ * else only proceed if the new name does not exist and if we're putting + * it into a directory. + */ + if ((unlinkOp || +@@ -2425,9 +2498,15 @@ static int yaffs_ChangeObjectName(yaffs_ + int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName, + yaffs_Object * newDir, const YCHAR * newName) + { +- yaffs_Object *obj; +- yaffs_Object *existingTarget; ++ 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). +@@ -2439,29 +2518,24 @@ int yaffs_RenameObject(yaffs_Object * ol + } + #endif + +- obj = yaffs_FindObjectByName(oldDir, oldName); +- /* Check new name to long. */ +- if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK && +- yaffs_strlen(newName) > YAFFS_MAX_ALIAS_LENGTH) +- /* ENAMETOOLONG */ +- return YAFFS_FAIL; +- else if (obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK && +- yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) ++ 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 && +- !list_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, ++ 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, +@@ -2479,10 +2553,10 @@ int yaffs_RenameObject(yaffs_Object * ol + 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 */ +@@ -2493,9 +2567,9 @@ static int yaffs_InitialiseBlocks(yaffs_ + } + 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); +@@ -2506,7 +2580,7 @@ static int yaffs_InitialiseBlocks(yaffs_ + else + dev->chunkBitsAlt = 0; + } +- ++ + if (dev->blockInfo && dev->chunkBits) { + memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo)); + memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks); +@@ -2527,7 +2601,7 @@ static void yaffs_DeinitialiseBlocks(yaf + dev->blockInfoAlt = 0; + + dev->blockInfo = NULL; +- ++ + if(dev->chunkBitsAlt && dev->chunkBits) + YFREE_ALT(dev->chunkBits); + else if(dev->chunkBits) +@@ -2591,14 +2665,14 @@ static int yaffs_FindBlockForGarbageColl + 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 && +@@ -2610,7 +2684,7 @@ static int yaffs_FindBlockForGarbageColl + } + } + } +- ++ + if(!pendingPrioritisedExist) /* None found, so we can clear this */ + dev->hasPendingPrioritisedGCs = 0; + } +@@ -2662,7 +2736,7 @@ static int yaffs_FindBlockForGarbageColl + dirtiest = b; + pagesInUse = 0; + } +- else ++ else + #endif + + if (bi->blockState == YAFFS_BLOCK_STATE_FULL && +@@ -2699,11 +2773,11 @@ static void yaffs_BlockBecameDirty(yaffs + /* 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) { +@@ -2716,7 +2790,7 @@ static void yaffs_BlockBecameDirty(yaffs + } + } + +- if (erasedOk && ++ if (erasedOk && + ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) { + int i; + for (i = 0; i < dev->nChunksPerBlock; i++) { +@@ -2763,11 +2837,11 @@ static int yaffs_FindBlockForAllocation( + * Can't get space to gc + */ + T(YAFFS_TRACE_ERROR, +- (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR))); ++ (TSTR("yaffs tragedy: no more erased blocks" TENDSTR))); + + return -1; + } +- ++ + /* Find an empty block. */ + + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { +@@ -2794,13 +2868,48 @@ static int yaffs_FindBlockForAllocation( + + T(YAFFS_TRACE_ALWAYS, + (TSTR +- ("yaffs tragedy: no more eraased blocks, but there should have been %d" ++ ("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) +@@ -2808,13 +2917,18 @@ static int yaffs_CheckSpaceForAllocation + int reservedChunks; + int reservedBlocks = dev->nReservedBlocks; + int checkpointBlocks; +- +- checkpointBlocks = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; +- if(checkpointBlocks < 0) +- checkpointBlocks = 0; +- ++ ++ 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); + } + +@@ -2861,10 +2975,10 @@ static int yaffs_AllocateChunk(yaffs_Dev + + if(blockUsedPtr) + *blockUsedPtr = bi; +- ++ + return retVal; + } +- ++ + T(YAFFS_TRACE_ERROR, + (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); + +@@ -2885,17 +2999,17 @@ static int yaffs_GetErasedChunks(yaffs_D + + } + +-static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) ++static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block, int wholeBlock) + { + int oldChunk; + int newChunk; +- int chunkInBlock; + int markNAND; + int retVal = YAFFS_OK; + int cleanups = 0; + int i; + int isCheckpointBlock; + int matchingChunk; ++ int maxCopies; + + int chunksBefore = yaffs_GetErasedChunks(dev); + int chunksAfter; +@@ -2907,12 +3021,15 @@ static int yaffs_GarbageCollectBlock(yaf + 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, " TENDSTR), block, +- bi->pagesInUse, bi->hasShrinkHeader)); ++ (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR), ++ block, ++ bi->pagesInUse, ++ bi->hasShrinkHeader, ++ wholeBlock)); + + /*yaffs_VerifyFreeChunks(dev); */ + +@@ -2935,16 +3052,23 @@ static int yaffs_GarbageCollectBlock(yaf + } else { + + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); +- ++ + yaffs_VerifyBlock(dev,bi,block); + +- for (chunkInBlock = 0, oldChunk = block * dev->nChunksPerBlock; +- chunkInBlock < dev->nChunksPerBlock +- && yaffs_StillSomeChunkBits(dev, block); +- chunkInBlock++, oldChunk++) { +- if (yaffs_CheckChunkBit(dev, block, chunkInBlock)) { ++ 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; + +@@ -2959,23 +3083,23 @@ static int yaffs_GarbageCollectBlock(yaf + + T(YAFFS_TRACE_GC_DETAIL, + (TSTR +- ("Collecting page %d, %d %d %d " TENDSTR), +- chunkInBlock, tags.objectId, tags.chunkId, ++ ("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->chunkId; ++ 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) { +@@ -2986,11 +3110,13 @@ static int yaffs_GarbageCollectBlock(yaf + tags.objectId, tags.chunkId, tags.byteCount)); + } + +- if (object && object->deleted +- && tags.chunkId != 0) { +- /* Data chunk in a deleted file, throw it away ++ 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 ++ * No need to copy this, just forget about it and + * fix up the object. + */ + +@@ -3009,7 +3135,7 @@ static int yaffs_GarbageCollectBlock(yaf + /* Deleted object header with no data chunks. + * Can be discarded and the file deleted. + */ +- object->chunkId = 0; ++ object->hdrChunk = 0; + yaffs_FreeTnode(object->myDev, + object->variant. + fileVariant.top); +@@ -3037,10 +3163,9 @@ static int yaffs_GarbageCollectBlock(yaf + yaffs_ObjectHeader *oh; + oh = (yaffs_ObjectHeader *)buffer; + oh->isShrink = 0; +- oh->shadowsObject = -1; + tags.extraShadows = 0; + tags.extraIsShrinkHeader = 0; +- ++ + yaffs_VerifyObjectHeader(object,oh,&tags,1); + } + +@@ -3055,7 +3180,7 @@ static int yaffs_GarbageCollectBlock(yaf + + if (tags.chunkId == 0) { + /* It's a header */ +- object->chunkId = newChunk; ++ object->hdrChunk = newChunk; + object->serial = tags.serialNumber; + } else { + /* It's a data chunk */ +@@ -3067,12 +3192,14 @@ static int yaffs_GarbageCollectBlock(yaf + } + } + +- yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__); ++ if(retVal == YAFFS_OK) ++ yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__); + + } + } + + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); ++ + + + /* Do any required cleanups */ +@@ -3099,7 +3226,7 @@ static int yaffs_GarbageCollectBlock(yaf + } + + yaffs_VerifyCollectedBlock(dev,bi,block); +- ++ + if (chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev))) { + T(YAFFS_TRACE_GC, + (TSTR +@@ -3107,9 +3234,15 @@ static int yaffs_GarbageCollectBlock(yaf + TENDSTR), chunksBefore, chunksAfter)); + } + ++ /* 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; ++ } ++ + dev->isDoingGC = 0; + +- return YAFFS_OK; ++ return retVal; + } + + /* New garbage collector +@@ -3127,22 +3260,22 @@ static int yaffs_CheckGarbageCollection( + int aggressive; + int gcOk = YAFFS_OK; + int maxTries = 0; +- ++ + int checkpointBlockAdjust; + + if (dev->isDoingGC) { + /* Bail out so we don't get recursive gc */ + return YAFFS_OK; + } +- ++ + /* This loop should pass the first time. + * We'll only see looping here if the erase of the collected block fails. + */ + + do { + maxTries++; +- +- checkpointBlockAdjust = (dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint); ++ ++ checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; + if(checkpointBlockAdjust < 0) + checkpointBlockAdjust = 0; + +@@ -3154,7 +3287,12 @@ static int yaffs_CheckGarbageCollection( + aggressive = 0; + } + +- block = yaffs_FindBlockForGarbageCollection(dev, aggressive); ++ if(dev->gcBlock <= 0){ ++ dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive); ++ dev->gcChunk = 0; ++ } ++ ++ block = dev->gcBlock; + + if (block > 0) { + dev->garbageCollections++; +@@ -3167,7 +3305,7 @@ static int yaffs_CheckGarbageCollection( + ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR), + dev->nErasedBlocks, aggressive)); + +- gcOk = yaffs_GarbageCollectBlock(dev, block); ++ gcOk = yaffs_GarbageCollectBlock(dev,block,aggressive); + } + + if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) { +@@ -3176,8 +3314,9 @@ static int yaffs_CheckGarbageCollection( + ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" + TENDSTR), dev->nErasedBlocks, maxTries, block)); + } +- } while ((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0) +- && (maxTries < 2)); ++ } while ((dev->nErasedBlocks < dev->nReservedBlocks) && ++ (block > 0) && ++ (maxTries < 2)); + + return aggressive ? gcOk : YAFFS_OK; + } +@@ -3326,11 +3465,11 @@ static int yaffs_CheckFileSanity(yaffs_O + static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode, + int chunkInNAND, int inScan) + { +- /* NB inScan is zero unless scanning. +- * For forward scanning, inScan is > 0; ++ /* NB inScan is zero unless scanning. ++ * For forward scanning, inScan is > 0; + * for backward scanning inScan is < 0 + */ +- ++ + yaffs_Tnode *tn; + yaffs_Device *dev = in->myDev; + int existingChunk; +@@ -3354,7 +3493,7 @@ static int yaffs_PutChunkIntoFile(yaffs_ + return YAFFS_OK; + } + +- tn = yaffs_AddOrFindLevel0Tnode(dev, ++ tn = yaffs_AddOrFindLevel0Tnode(dev, + &in->variant.fileVariant, + chunkInInode, + NULL); +@@ -3366,7 +3505,7 @@ static int yaffs_PutChunkIntoFile(yaffs_ + + 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 ++ * 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. + * +@@ -3374,7 +3513,7 @@ static int yaffs_PutChunkIntoFile(yaffs_ + * Update: For backward scanning we don't need to re-read tags so this is quite cheap. + */ + +- if (existingChunk != 0) { ++ if (existingChunk > 0) { + /* NB Right now existing chunk will not be real chunkId if the device >= 32MB + * thus we have to do a FindChunkInFile to get the real chunk id. + * +@@ -3407,18 +3546,20 @@ static int yaffs_PutChunkIntoFile(yaffs_ + + } + +- /* NB The deleted flags should be false, otherwise the chunks will ++ /* NB The deleted flags should be false, otherwise the chunks will + * not be loaded during a scan + */ + +- newSerial = newTags.serialNumber; +- existingSerial = existingTags.serialNumber; ++ if(inScan > 0) { ++ newSerial = newTags.serialNumber; ++ existingSerial = existingTags.serialNumber; ++ } + + if ((inScan > 0) && + (in->myDev->isYaffs2 || + existingChunk <= 0 || + ((existingSerial + 1) & 3) == newSerial)) { +- /* Forward scanning. ++ /* Forward scanning. + * Use new + * Delete the old one and drop through to update the tnode + */ +@@ -3459,7 +3600,7 @@ static int yaffs_ReadChunkDataFromObject + (TSTR("Chunk %d not found zero instead" TENDSTR), + chunkInNAND)); + /* get sane (zero) data if you read a hole */ +- memset(buffer, 0, in->myDev->nDataBytesPerChunk); ++ memset(buffer, 0, in->myDev->nDataBytesPerChunk); + return 0; + } + +@@ -3474,7 +3615,7 @@ void yaffs_DeleteChunk(yaffs_Device * de + + if (chunkId <= 0) + return; +- ++ + + dev->nDeletions++; + block = chunkId / dev->nChunksPerBlock; +@@ -3560,6 +3701,14 @@ static int yaffs_WriteChunkDataToObject( + newTags.serialNumber = + (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1; + newTags.byteCount = nBytes; ++ ++ if(nBytes < 1 || nBytes > dev->totalBytesPerChunk){ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes)); ++ while(1){} ++ } ++ ++ + + newChunkId = + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, +@@ -3601,11 +3750,14 @@ int yaffs_UpdateObjectHeader(yaffs_Objec + __u8 *buffer = NULL; + YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1]; + +- yaffs_ObjectHeader *oh = NULL; ++ yaffs_ObjectHeader *oh = NULL; ++ ++ yaffs_strcpy(oldName,_Y("silly old name")); + +- yaffs_strcpy(oldName,"silly old name"); + +- if (!in->fake || force) { ++ if (!in->fake || ++ in == dev->rootDir || /* The rootDir should also be saved */ ++ force) { + + yaffs_CheckGarbageCollection(dev); + yaffs_CheckObjectDetailsLoaded(in); +@@ -3613,14 +3765,14 @@ int yaffs_UpdateObjectHeader(yaffs_Objec + buffer = yaffs_GetTempBuffer(in->myDev, __LINE__); + oh = (yaffs_ObjectHeader *) buffer; + +- prevChunkId = in->chunkId; ++ prevChunkId = in->hdrChunk; + +- if (prevChunkId >= 0) { ++ if (prevChunkId > 0) { + result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId, + buffer, &oldTags); +- ++ + yaffs_VerifyObjectHeader(in,oh,&oldTags,0); +- ++ + memcpy(oldName, oh->name, sizeof(oh->name)); + } + +@@ -3628,7 +3780,7 @@ int yaffs_UpdateObjectHeader(yaffs_Objec + + oh->type = in->variantType; + oh->yst_mode = in->yst_mode; +- oh->shadowsObject = shadows; ++ oh->shadowsObject = oh->inbandShadowsObject = shadows; + + #ifdef CONFIG_YAFFS_WINCE + oh->win_atime[0] = in->win_atime[0]; +@@ -3717,7 +3869,7 @@ int yaffs_UpdateObjectHeader(yaffs_Objec + + if (newChunkId >= 0) { + +- in->chunkId = newChunkId; ++ in->hdrChunk = newChunkId; + + if (prevChunkId >= 0) { + yaffs_DeleteChunk(dev, prevChunkId, 1, +@@ -3748,11 +3900,11 @@ int yaffs_UpdateObjectHeader(yaffs_Objec + + /*------------------------ 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 ++ * 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 ++ * 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 ++ * 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 +@@ -3765,14 +3917,14 @@ static int yaffs_ObjectHasCachedWriteDat + int i; + yaffs_ChunkCache *cache; + int nCaches = obj->myDev->nShortOpCaches; +- ++ + for(i = 0; i < nCaches; i++){ + cache = &dev->srCache[i]; + if (cache->object == obj && + cache->dirty) + return 1; + } +- ++ + return 0; + } + +@@ -3838,7 +3990,7 @@ void yaffs_FlushEntireDeviceCache(yaffs_ + yaffs_Object *obj; + int nCaches = dev->nShortOpCaches; + int i; +- ++ + /* Find a dirty object in the cache and flush it... + * until there are no further dirty objects. + */ +@@ -3848,53 +4000,33 @@ void yaffs_FlushEntireDeviceCache(yaffs_ + if (dev->srCache[i].object && + dev->srCache[i].dirty) + obj = dev->srCache[i].object; +- ++ + } + if(obj) + yaffs_FlushFilesChunkCache(obj); +- ++ + } while(obj); +- ++ + } + + + /* Grab us a cache chunk for use. +- * First look for an empty one. ++ * First look for an empty one. + * Then look for the least recently used non-dirty one. + * Then look for the least recently used dirty one...., flush and look again. + */ + static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device * dev) + { + int i; +- int usage; +- int theOne; + + if (dev->nShortOpCaches > 0) { + for (i = 0; i < dev->nShortOpCaches; i++) { +- if (!dev->srCache[i].object) ++ if (!dev->srCache[i].object) + return &dev->srCache[i]; + } +- +- return NULL; +- +- theOne = -1; +- usage = 0; /* just to stop the compiler grizzling */ +- +- for (i = 0; i < dev->nShortOpCaches; i++) { +- if (!dev->srCache[i].dirty && +- ((dev->srCache[i].lastUse < usage && theOne >= 0) || +- theOne < 0)) { +- usage = dev->srCache[i].lastUse; +- theOne = i; +- } +- } +- +- +- return theOne >= 0 ? &dev->srCache[theOne] : NULL; +- } else { +- return NULL; + } + ++ return NULL; + } + + static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device * dev) +@@ -4032,14 +4164,14 @@ static void yaffs_InvalidateWholeChunkCa + static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev,int head) + { + yaffs_CheckpointValidity cp; +- ++ + memset(&cp,0,sizeof(cp)); +- ++ + cp.structType = sizeof(cp); + cp.magic = YAFFS_MAGIC; + cp.version = YAFFS_CHECKPOINT_VERSION; + cp.head = (head) ? 1 : 0; +- ++ + return (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp))? + 1 : 0; + } +@@ -4048,9 +4180,9 @@ static int yaffs_ReadCheckpointValidityM + { + yaffs_CheckpointValidity cp; + int ok; +- ++ + ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); +- ++ + if(ok) + ok = (cp.structType == sizeof(cp)) && + (cp.magic == YAFFS_MAGIC) && +@@ -4059,20 +4191,20 @@ static int yaffs_ReadCheckpointValidityM + return ok ? 1 : 0; + } + +-static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, ++static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, + yaffs_Device *dev) + { + cp->nErasedBlocks = dev->nErasedBlocks; + cp->allocationBlock = dev->allocationBlock; + cp->allocationPage = dev->allocationPage; + cp->nFreeChunks = dev->nFreeChunks; +- ++ + cp->nDeletedFiles = dev->nDeletedFiles; + cp->nUnlinkedFiles = dev->nUnlinkedFiles; + cp->nBackgroundDeletions = dev->nBackgroundDeletions; + cp->sequenceNumber = dev->sequenceNumber; + cp->oldestDirtySequence = dev->oldestDirtySequence; +- ++ + } + + static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev, +@@ -4082,7 +4214,7 @@ static void yaffs_CheckpointDeviceToDevi + dev->allocationBlock = cp->allocationBlock; + dev->allocationPage = cp->allocationPage; + dev->nFreeChunks = cp->nFreeChunks; +- ++ + dev->nDeletedFiles = cp->nDeletedFiles; + dev->nUnlinkedFiles = cp->nUnlinkedFiles; + dev->nBackgroundDeletions = cp->nBackgroundDeletions; +@@ -4098,20 +4230,20 @@ static int yaffs_WriteCheckpointDevice(y + __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); + + int ok; +- ++ + /* Write device runtime values*/ + yaffs_DeviceToCheckpointDevice(&cp,dev); + cp.structType = sizeof(cp); +- ++ + ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); +- ++ + /* Write block info */ + if(ok) { + nBytes = nBlocks * sizeof(yaffs_BlockInfo); + ok = (yaffs_CheckpointWrite(dev,dev->blockInfo,nBytes) == nBytes); + } +- +- /* Write chunk bits */ ++ ++ /* Write chunk bits */ + if(ok) { + nBytes = nBlocks * dev->chunkBitmapStride; + ok = (yaffs_CheckpointWrite(dev,dev->chunkBits,nBytes) == nBytes); +@@ -4126,28 +4258,28 @@ static int yaffs_ReadCheckpointDevice(ya + __u32 nBytes; + __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); + +- int ok; +- ++ int ok; ++ + ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); + if(!ok) + return 0; +- ++ + if(cp.structType != sizeof(cp)) + return 0; +- +- ++ ++ + yaffs_CheckpointDeviceToDevice(dev,&cp); +- ++ + nBytes = nBlocks * sizeof(yaffs_BlockInfo); +- ++ + ok = (yaffs_CheckpointRead(dev,dev->blockInfo,nBytes) == nBytes); +- ++ + if(!ok) + return 0; + nBytes = nBlocks * dev->chunkBitmapStride; +- ++ + ok = (yaffs_CheckpointRead(dev,dev->chunkBits,nBytes) == nBytes); +- ++ + return ok ? 1 : 0; + } + +@@ -4157,7 +4289,7 @@ static void yaffs_ObjectToCheckpointObje + + cp->objectId = obj->objectId; + cp->parentId = (obj->parent) ? obj->parent->objectId : 0; +- cp->chunkId = obj->chunkId; ++ cp->hdrChunk = obj->hdrChunk; + cp->variantType = obj->variantType; + cp->deleted = obj->deleted; + cp->softDeleted = obj->softDeleted; +@@ -4167,7 +4299,7 @@ static void yaffs_ObjectToCheckpointObje + cp->unlinkAllowed = obj->unlinkAllowed; + cp->serial = obj->serial; + cp->nDataChunks = obj->nDataChunks; +- ++ + if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) + cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize; + else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) +@@ -4178,9 +4310,9 @@ static void yaffs_CheckpointObjectToObje + { + + yaffs_Object *parent; +- ++ + obj->objectId = cp->objectId; +- ++ + if(cp->parentId) + parent = yaffs_FindOrCreateObjectByNumber( + obj->myDev, +@@ -4188,11 +4320,11 @@ static void yaffs_CheckpointObjectToObje + YAFFS_OBJECT_TYPE_DIRECTORY); + else + parent = NULL; +- ++ + if(parent) + yaffs_AddObjectToDirectory(parent, obj); + +- obj->chunkId = cp->chunkId; ++ obj->hdrChunk = cp->hdrChunk; + obj->variantType = cp->variantType; + obj->deleted = cp->deleted; + obj->softDeleted = cp->softDeleted; +@@ -4202,13 +4334,13 @@ static void yaffs_CheckpointObjectToObje + obj->unlinkAllowed = cp->unlinkAllowed; + obj->serial = cp->serial; + obj->nDataChunks = cp->nDataChunks; +- ++ + if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) + obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId; + else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) + obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId; + +- if(obj->objectId >= YAFFS_NOBJECT_BUCKETS) ++ if(obj->hdrChunk > 0) + obj->lazyLoaded = 1; + } + +@@ -4220,7 +4352,11 @@ static int yaffs_CheckpointTnodeWorker(y + int i; + yaffs_Device *dev = in->myDev; + int ok = 1; +- int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; ++ int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; ++ ++ if(tnodeSize < sizeof(yaffs_Tnode)) ++ tnodeSize = sizeof(yaffs_Tnode); ++ + + if (tn) { + if (level > 0) { +@@ -4235,10 +4371,9 @@ static int yaffs_CheckpointTnodeWorker(y + } + } else if (level == 0) { + __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS; +- /* printf("write tnode at %d\n",baseOffset); */ + ok = (yaffs_CheckpointWrite(dev,&baseOffset,sizeof(baseOffset)) == sizeof(baseOffset)); + if(ok) +- ok = (yaffs_CheckpointWrite(dev,tn,nTnodeBytes) == nTnodeBytes); ++ ok = (yaffs_CheckpointWrite(dev,tn,tnodeSize) == tnodeSize); + } + } + +@@ -4250,17 +4385,17 @@ static int yaffs_WriteCheckpointTnodes(y + { + __u32 endMarker = ~0; + int ok = 1; +- ++ + if(obj->variantType == YAFFS_OBJECT_TYPE_FILE){ + ok = yaffs_CheckpointTnodeWorker(obj, + obj->variant.fileVariant.top, + obj->variant.fileVariant.topLevel, + 0); + if(ok) +- ok = (yaffs_CheckpointWrite(obj->myDev,&endMarker,sizeof(endMarker)) == ++ ok = (yaffs_CheckpointWrite(obj->myDev,&endMarker,sizeof(endMarker)) == + sizeof(endMarker)); + } +- ++ + return ok ? 1 : 0; + } + +@@ -4272,70 +4407,72 @@ static int yaffs_ReadCheckpointTnodes(ya + yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant; + yaffs_Tnode *tn; + int nread = 0; ++ int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + +- ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk)); ++ if(tnodeSize < sizeof(yaffs_Tnode)) ++ tnodeSize = sizeof(yaffs_Tnode); + ++ ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk)); ++ + while(ok && (~baseChunk)){ + nread++; + /* Read level 0 tnode */ +- +- +- /* printf("read tnode at %d\n",baseChunk); */ ++ ++ + tn = yaffs_GetTnodeRaw(dev); + if(tn) +- ok = (yaffs_CheckpointRead(dev,tn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8) == +- (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); ++ ok = (yaffs_CheckpointRead(dev,tn,tnodeSize) == tnodeSize); + else + ok = 0; +- ++ + if(tn && ok){ + ok = yaffs_AddOrFindLevel0Tnode(dev, + fileStructPtr, + baseChunk, + tn) ? 1 : 0; +- ++ + } +- ++ + if(ok) + ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk)); +- ++ + } + + T(YAFFS_TRACE_CHECKPOINT,( + TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR), + nread,baseChunk,ok)); + +- return ok ? 1 : 0; ++ return ok ? 1 : 0; + } +- ++ + + static int yaffs_WriteCheckpointObjects(yaffs_Device *dev) + { + yaffs_Object *obj; +- yaffs_CheckpointObject cp; +- int i; +- int ok = 1; +- struct list_head *lh; ++ yaffs_CheckpointObject cp; ++ int i; ++ int ok = 1; ++ struct ylist_head *lh; + +- +- /* Iterate through the objects in each hash entry, ++ ++ /* Iterate through the objects in each hash entry, + * dumping them to the checkpointing stream. +- */ +- +- for(i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++){ +- list_for_each(lh, &dev->objectBucket[i].list) { +- if (lh) { +- obj = list_entry(lh, yaffs_Object, hashLink); +- if (!obj->deferedFree) { +- yaffs_ObjectToCheckpointObject(&cp,obj); +- cp.structType = sizeof(cp); ++ */ ++ ++ for(i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++){ ++ ylist_for_each(lh, &dev->objectBucket[i].list) { ++ if (lh) { ++ obj = ylist_entry(lh, yaffs_Object, hashLink); ++ if (!obj->deferedFree) { ++ yaffs_ObjectToCheckpointObject(&cp,obj); ++ cp.structType = sizeof(cp); + + T(YAFFS_TRACE_CHECKPOINT,( + TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR), +- cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj)); ++ cp.objectId,cp.parentId,cp.variantType,cp.hdrChunk,(unsigned) obj)); + + ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); +- ++ + if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){ + ok = yaffs_WriteCheckpointTnodes(obj); + } +@@ -4343,14 +4480,14 @@ static int yaffs_WriteCheckpointObjects( + } + } + } +- ++ + /* Dump end of list */ + memset(&cp,0xFF,sizeof(yaffs_CheckpointObject)); + cp.structType = sizeof(cp); +- ++ + if(ok) + ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); +- ++ + return ok ? 1 : 0; + } + +@@ -4361,7 +4498,7 @@ static int yaffs_ReadCheckpointObjects(y + int ok = 1; + int done = 0; + yaffs_Object *hardList = NULL; +- ++ + while(ok && !done) { + ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); + if(cp.structType != sizeof(cp)) { +@@ -4369,9 +4506,9 @@ static int yaffs_ReadCheckpointObjects(y + cp.structType,sizeof(cp),ok)); + ok = 0; + } +- ++ + T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR), +- cp.objectId,cp.parentId,cp.variantType,cp.chunkId)); ++ cp.objectId,cp.parentId,cp.variantType,cp.hdrChunk)); + + if(ok && cp.objectId == ~0) + done = 1; +@@ -4380,21 +4517,21 @@ static int yaffs_ReadCheckpointObjects(y + if(obj) { + yaffs_CheckpointObjectToObject(obj,&cp); + if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) { +- ok = yaffs_ReadCheckpointTnodes(obj); +- } else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { +- obj->hardLinks.next = +- (struct list_head *) +- hardList; +- hardList = obj; +- } +- ++ ok = yaffs_ReadCheckpointTnodes(obj); ++ } else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { ++ obj->hardLinks.next = ++ (struct ylist_head *) ++ hardList; ++ hardList = obj; ++ } ++ + } + } + } +- ++ + if(ok) + yaffs_HardlinkFixup(dev,hardList); +- ++ + return ok ? 1 : 0; + } + +@@ -4402,14 +4539,14 @@ static int yaffs_WriteCheckpointSum(yaff + { + __u32 checkpointSum; + int ok; +- ++ + yaffs_GetCheckpointSum(dev,&checkpointSum); +- ++ + ok = (yaffs_CheckpointWrite(dev,&checkpointSum,sizeof(checkpointSum)) == sizeof(checkpointSum)); +- ++ + if(!ok) + return 0; +- ++ + return 1; + } + +@@ -4418,17 +4555,17 @@ static int yaffs_ReadCheckpointSum(yaffs + __u32 checkpointSum0; + __u32 checkpointSum1; + int ok; +- ++ + yaffs_GetCheckpointSum(dev,&checkpointSum0); +- ++ + ok = (yaffs_CheckpointRead(dev,&checkpointSum1,sizeof(checkpointSum1)) == sizeof(checkpointSum1)); +- ++ + if(!ok) + return 0; +- ++ + if(checkpointSum0 != checkpointSum1) + return 0; +- ++ + return 1; + } + +@@ -4437,15 +4574,15 @@ static int yaffs_WriteCheckpointData(yaf + { + + int ok = 1; +- ++ + if(dev->skipCheckpointWrite || !dev->isYaffs2){ + T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint write" TENDSTR))); + ok = 0; + } +- ++ + if(ok) + ok = yaffs_CheckpointOpen(dev,1); +- ++ + if(ok){ + T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR))); + ok = yaffs_WriteCheckpointValidityMarker(dev,1); +@@ -4462,18 +4599,18 @@ static int yaffs_WriteCheckpointData(yaf + T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR))); + ok = yaffs_WriteCheckpointValidityMarker(dev,0); + } +- ++ + if(ok){ + ok = yaffs_WriteCheckpointSum(dev); + } +- +- ++ ++ + if(!yaffs_CheckpointClose(dev)) + ok = 0; +- ++ + if(ok) + dev->isCheckpointed = 1; +- else ++ else + dev->isCheckpointed = 0; + + return dev->isCheckpointed; +@@ -4482,17 +4619,17 @@ static int yaffs_WriteCheckpointData(yaf + static int yaffs_ReadCheckpointData(yaffs_Device *dev) + { + int ok = 1; +- ++ + if(dev->skipCheckpointRead || !dev->isYaffs2){ + T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint read" TENDSTR))); + ok = 0; + } +- ++ + if(ok) + ok = yaffs_CheckpointOpen(dev,0); /* open for read */ +- ++ + if(ok){ +- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR))); ++ T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR))); + ok = yaffs_ReadCheckpointValidityMarker(dev,1); + } + if(ok){ +@@ -4500,14 +4637,14 @@ static int yaffs_ReadCheckpointData(yaff + ok = yaffs_ReadCheckpointDevice(dev); + } + if(ok){ +- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint objects" TENDSTR))); ++ T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint objects" TENDSTR))); + ok = yaffs_ReadCheckpointObjects(dev); + } + if(ok){ + T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR))); + ok = yaffs_ReadCheckpointValidityMarker(dev,0); + } +- ++ + if(ok){ + ok = yaffs_ReadCheckpointSum(dev); + T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint checksum %d" TENDSTR),ok)); +@@ -4518,7 +4655,7 @@ static int yaffs_ReadCheckpointData(yaff + + if(ok) + dev->isCheckpointed = 1; +- else ++ else + dev->isCheckpointed = 0; + + return ok ? 1 : 0; +@@ -4527,7 +4664,7 @@ static int yaffs_ReadCheckpointData(yaff + + static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) + { +- if(dev->isCheckpointed || ++ if(dev->isCheckpointed || + dev->blocksInCheckpoint > 0){ + dev->isCheckpointed = 0; + yaffs_CheckpointInvalidateStream(dev); +@@ -4550,7 +4687,7 @@ int yaffs_CheckpointSave(yaffs_Device *d + yaffs_InvalidateCheckpoint(dev); + yaffs_WriteCheckpointData(dev); + } +- ++ + T(YAFFS_TRACE_ALWAYS,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); + + return dev->isCheckpointed; +@@ -4560,7 +4697,7 @@ int yaffs_CheckpointRestore(yaffs_Device + { + int retval; + T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); +- ++ + retval = yaffs_ReadCheckpointData(dev); + + if(dev->isCheckpointed){ +@@ -4570,7 +4707,7 @@ int yaffs_CheckpointRestore(yaffs_Device + } + + T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); +- ++ + return retval; + } + +@@ -4589,7 +4726,7 @@ int yaffs_ReadDataFromFile(yaffs_Object + { + + int chunk; +- int start; ++ __u32 start; + int nToCopy; + int n = nBytes; + int nDone = 0; +@@ -4606,7 +4743,7 @@ int yaffs_ReadDataFromFile(yaffs_Object + chunk++; + + /* OK now check for the curveball where the start and end are in +- * the same chunk. ++ * the same chunk. + */ + if ((start + n) < dev->nDataBytesPerChunk) { + nToCopy = n; +@@ -4617,10 +4754,10 @@ int yaffs_ReadDataFromFile(yaffs_Object + cache = yaffs_FindChunkCache(in, chunk); + + /* If the chunk is already in the cache or it is less than a whole chunk +- * then use the cache (if there is caching) ++ * or we're using inband tags then use the cache (if there is caching) + * else bypass the cache. + */ +- if (cache || nToCopy != dev->nDataBytesPerChunk) { ++ if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) { + if (dev->nShortOpCaches > 0) { + + /* If we can't find the data in the cache, then load it up. */ +@@ -4641,14 +4778,9 @@ int yaffs_ReadDataFromFile(yaffs_Object + + cache->locked = 1; + +-#ifdef CONFIG_YAFFS_WINCE +- yfsd_UnlockYAFFS(TRUE); +-#endif ++ + memcpy(buffer, &cache->data[start], nToCopy); + +-#ifdef CONFIG_YAFFS_WINCE +- yfsd_LockYAFFS(TRUE); +-#endif + cache->locked = 0; + } else { + /* Read into the local buffer then copy..*/ +@@ -4657,41 +4789,19 @@ int yaffs_ReadDataFromFile(yaffs_Object + yaffs_GetTempBuffer(dev, __LINE__); + yaffs_ReadChunkDataFromObject(in, chunk, + localBuffer); +-#ifdef CONFIG_YAFFS_WINCE +- yfsd_UnlockYAFFS(TRUE); +-#endif ++ + memcpy(buffer, &localBuffer[start], nToCopy); + +-#ifdef CONFIG_YAFFS_WINCE +- yfsd_LockYAFFS(TRUE); +-#endif ++ + yaffs_ReleaseTempBuffer(dev, localBuffer, + __LINE__); + } + + } else { +-#ifdef CONFIG_YAFFS_WINCE +- __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); +- +- /* Under WinCE can't do direct transfer. Need to use a local buffer. +- * This is because we otherwise screw up WinCE's memory mapper +- */ +- yaffs_ReadChunkDataFromObject(in, chunk, localBuffer); +- +-#ifdef CONFIG_YAFFS_WINCE +- yfsd_UnlockYAFFS(TRUE); +-#endif +- memcpy(buffer, localBuffer, dev->nDataBytesPerChunk); + +-#ifdef CONFIG_YAFFS_WINCE +- yfsd_LockYAFFS(TRUE); +- yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); +-#endif +- +-#else + /* A full chunk. Read directly into the supplied buffer. */ + yaffs_ReadChunkDataFromObject(in, chunk, buffer); +-#endif ++ + } + + n -= nToCopy; +@@ -4709,14 +4819,15 @@ int yaffs_WriteDataToFile(yaffs_Object * + { + + int chunk; +- int start; ++ __u32 start; + int nToCopy; +- int n = nBytes; +- int nDone = 0; +- int nToWriteBack; +- int startOfWrite = offset; +- int chunkWritten = 0; +- int nBytesRead; ++ int n = nBytes; ++ int nDone = 0; ++ int nToWriteBack; ++ int startOfWrite = offset; ++ int chunkWritten = 0; ++ __u32 nBytesRead; ++ __u32 chunkStart; + + yaffs_Device *dev; + +@@ -4726,6 +4837,12 @@ int yaffs_WriteDataToFile(yaffs_Object * + //chunk = offset / dev->nDataBytesPerChunk + 1; + //start = offset % dev->nDataBytesPerChunk; + yaffs_AddrToChunk(dev,offset,&chunk,&start); ++ ++ if(chunk * dev->nDataBytesPerChunk + start != offset || ++ start >= dev->nDataBytesPerChunk){ ++ T(YAFFS_TRACE_ERROR,(TSTR("AddrToChunk of offset %d gives chunk %d start %d"TENDSTR), ++ (int)offset, chunk,start)); ++ } + chunk++; + + /* OK now check for the curveball where the start and end are in +@@ -4740,9 +4857,12 @@ int yaffs_WriteDataToFile(yaffs_Object * + * we need to write back as much as was there before. + */ + +- nBytesRead = +- in->variant.fileVariant.fileSize - +- ((chunk - 1) * dev->nDataBytesPerChunk); ++ chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk); ++ ++ if(chunkStart > in->variant.fileVariant.fileSize) ++ nBytesRead = 0; /* Past end of file */ ++ else ++ nBytesRead = in->variant.fileVariant.fileSize - chunkStart; + + if (nBytesRead > dev->nDataBytesPerChunk) { + nBytesRead = dev->nDataBytesPerChunk; +@@ -4751,19 +4871,24 @@ int yaffs_WriteDataToFile(yaffs_Object * + nToWriteBack = + (nBytesRead > + (start + n)) ? nBytesRead : (start + n); ++ ++ if(nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk) ++ YBUG(); + + } else { + nToCopy = dev->nDataBytesPerChunk - start; + nToWriteBack = dev->nDataBytesPerChunk; + } + +- if (nToCopy != dev->nDataBytesPerChunk) { +- /* An incomplete start or end chunk (or maybe both start and end chunk) */ ++ if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) { ++ /* An incomplete start or end chunk (or maybe both start and end chunk), ++ * or we're using inband tags, so we want to use the cache buffers. ++ */ + if (dev->nShortOpCaches > 0) { + yaffs_ChunkCache *cache; + /* If we can't find the data in the cache, then load the cache */ + cache = yaffs_FindChunkCache(in, chunk); +- ++ + if (!cache + && yaffs_CheckSpaceForAllocation(in-> + myDev)) { +@@ -4776,28 +4901,24 @@ int yaffs_WriteDataToFile(yaffs_Object * + cache-> + data); + } +- else if(cache && ++ else if(cache && + !cache->dirty && + !yaffs_CheckSpaceForAllocation(in->myDev)){ + /* Drop the cache if it was a read cache item and + * no space check has been made for it. +- */ ++ */ + cache = NULL; + } + + if (cache) { + yaffs_UseChunkCache(dev, cache, 1); + cache->locked = 1; +-#ifdef CONFIG_YAFFS_WINCE +- yfsd_UnlockYAFFS(TRUE); +-#endif ++ + + memcpy(&cache->data[start], buffer, + nToCopy); + +-#ifdef CONFIG_YAFFS_WINCE +- yfsd_LockYAFFS(TRUE); +-#endif ++ + cache->locked = 0; + cache->nBytes = nToWriteBack; + +@@ -4825,15 +4946,10 @@ int yaffs_WriteDataToFile(yaffs_Object * + yaffs_ReadChunkDataFromObject(in, chunk, + localBuffer); + +-#ifdef CONFIG_YAFFS_WINCE +- yfsd_UnlockYAFFS(TRUE); +-#endif ++ + + memcpy(&localBuffer[start], buffer, nToCopy); + +-#ifdef CONFIG_YAFFS_WINCE +- yfsd_LockYAFFS(TRUE); +-#endif + chunkWritten = + yaffs_WriteChunkDataToObject(in, chunk, + localBuffer, +@@ -4846,31 +4962,15 @@ int yaffs_WriteDataToFile(yaffs_Object * + } + + } else { +- +-#ifdef CONFIG_YAFFS_WINCE +- /* Under WinCE can't do direct transfer. Need to use a local buffer. +- * This is because we otherwise screw up WinCE's memory mapper +- */ +- __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); +-#ifdef CONFIG_YAFFS_WINCE +- yfsd_UnlockYAFFS(TRUE); +-#endif +- memcpy(localBuffer, buffer, dev->nDataBytesPerChunk); +-#ifdef CONFIG_YAFFS_WINCE +- yfsd_LockYAFFS(TRUE); +-#endif +- chunkWritten = +- yaffs_WriteChunkDataToObject(in, chunk, localBuffer, +- dev->nDataBytesPerChunk, +- 0); +- yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); +-#else + /* A full chunk. Write directly from the supplied buffer. */ ++ ++ ++ + chunkWritten = + yaffs_WriteChunkDataToObject(in, chunk, buffer, + dev->nDataBytesPerChunk, + 0); +-#endif ++ + /* Since we've overwritten the cached data, we better invalidate it. */ + yaffs_InvalidateChunkCache(in, chunk); + } +@@ -4943,9 +5043,9 @@ int yaffs_ResizeFile(yaffs_Object * in, + { + + int oldFileSize = in->variant.fileVariant.fileSize; +- int newSizeOfPartialChunk; ++ __u32 newSizeOfPartialChunk; + int newFullChunks; +- ++ + yaffs_Device *dev = in->myDev; + + yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk); +@@ -4953,23 +5053,23 @@ int yaffs_ResizeFile(yaffs_Object * in, + yaffs_FlushFilesChunkCache(in); + yaffs_InvalidateWholeChunkCache(in); + +- yaffs_CheckGarbageCollection(dev); ++ yaffs_CheckGarbageCollection(dev); + +- if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { +- return yaffs_GetFileSize(in); +- } ++ if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { ++ return YAFFS_FAIL; ++ } + +- if (newSize == oldFileSize) { +- return oldFileSize; +- } ++ if (newSize == oldFileSize) { ++ return YAFFS_OK; ++ } + +- if (newSize < oldFileSize) { ++ if (newSize < oldFileSize) { + + yaffs_PruneResizedChunks(in, newSize); + + if (newSizeOfPartialChunk != 0) { + int lastChunk = 1 + newFullChunks; +- ++ + __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); + + /* Got to read and rewrite the last chunk with its new size and zero pad */ +@@ -4993,19 +5093,20 @@ int yaffs_ResizeFile(yaffs_Object * in, + in->variant.fileVariant.fileSize = newSize; + } + +- +- ++ ++ + /* Write a new object header. + * show we've shrunk the file, if need be + * Do this only if the file is not in the deleted directories. + */ +- if (in->parent->objectId != YAFFS_OBJECTID_UNLINKED && ++ if (in->parent && ++ in->parent->objectId != YAFFS_OBJECTID_UNLINKED && + in->parent->objectId != YAFFS_OBJECTID_DELETED) { + yaffs_UpdateObjectHeader(in, NULL, 0, + (newSize < oldFileSize) ? 1 : 0, 0); + } + +- return newSize; ++ return YAFFS_OK; + } + + loff_t yaffs_GetFileSize(yaffs_Object * obj) +@@ -5058,13 +5159,13 @@ static int yaffs_DoGenericObjectDeletion + + if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) { + /* Move to the unlinked directory so we have a record that it was deleted. */ +- yaffs_ChangeObjectName(in, in->myDev->deletedDir,"deleted", 0, 0); ++ yaffs_ChangeObjectName(in, in->myDev->deletedDir,_Y("deleted"), 0, 0); + + } + + yaffs_RemoveObjectFromDirectory(in); +- yaffs_DeleteChunk(in->myDev, in->chunkId, 1, __LINE__); +- in->chunkId = -1; ++ yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__); ++ in->hdrChunk = 0; + + yaffs_FreeObject(in); + return YAFFS_OK; +@@ -5075,62 +5176,66 @@ static int yaffs_DoGenericObjectDeletion + * and the inode associated with the file. + * It does not delete the links associated with the file. + */ ++ + static int yaffs_UnlinkFile(yaffs_Object * in) + { + + int retVal; + int immediateDeletion = 0; + +- if (1) { + #ifdef __KERNEL__ +- if (!in->myInode) { +- immediateDeletion = 1; +- +- } ++ if (!in->myInode) { ++ immediateDeletion = 1; ++ } + #else +- if (in->inUse <= 0) { +- immediateDeletion = 1; +- +- } ++ if (in->inUse <= 0) { ++ immediateDeletion = 1; ++ } + #endif +- if (immediateDeletion) { +- retVal = +- yaffs_ChangeObjectName(in, in->myDev->deletedDir, +- "deleted", 0, 0); +- T(YAFFS_TRACE_TRACING, +- (TSTR("yaffs: immediate deletion of file %d" TENDSTR), +- in->objectId)); +- in->deleted = 1; +- in->myDev->nDeletedFiles++; +- if (0 && in->myDev->isYaffs2) { +- yaffs_ResizeFile(in, 0); +- } +- yaffs_SoftDeleteFile(in); +- } else { +- retVal = +- yaffs_ChangeObjectName(in, in->myDev->unlinkedDir, +- "unlinked", 0, 0); +- } + ++ if (immediateDeletion) { ++ retVal = ++ yaffs_ChangeObjectName(in, in->myDev->deletedDir, ++ _Y("deleted"), 0, 0); ++ T(YAFFS_TRACE_TRACING, ++ (TSTR("yaffs: immediate deletion of file %d" TENDSTR), ++ in->objectId)); ++ in->deleted = 1; ++ in->myDev->nDeletedFiles++; ++ if (1 || in->myDev->isYaffs2) { ++ yaffs_ResizeFile(in, 0); ++ } ++ yaffs_SoftDeleteFile(in); ++ } else { ++ retVal = ++ yaffs_ChangeObjectName(in, in->myDev->unlinkedDir, ++ _Y("unlinked"), 0, 0); + } ++ ++ + return retVal; + } + + int yaffs_DeleteFile(yaffs_Object * in) + { + int retVal = YAFFS_OK; ++ int deleted = in->deleted; ++ ++ yaffs_ResizeFile(in,0); + + if (in->nDataChunks > 0) { +- /* Use soft deletion if there is data in the file */ ++ /* Use soft deletion if there is data in the file. ++ * That won't be the case if it has been resized to zero. ++ */ + if (!in->unlinked) { + retVal = yaffs_UnlinkFile(in); + } + if (retVal == YAFFS_OK && in->unlinked && !in->deleted) { +- in->deleted = 1; ++ in->deleted = deleted = 1; + in->myDev->nDeletedFiles++; + yaffs_SoftDeleteFile(in); + } +- return in->deleted ? YAFFS_OK : YAFFS_FAIL; ++ return deleted ? YAFFS_OK : YAFFS_FAIL; + } else { + /* The file has no data chunks so we toss it immediately */ + yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top); +@@ -5143,10 +5248,10 @@ int yaffs_DeleteFile(yaffs_Object * in) + + static int yaffs_DeleteDirectory(yaffs_Object * in) + { +- /* First check that the directory is empty. */ +- if (list_empty(&in->variant.directoryVariant.children)) { +- return yaffs_DoGenericObjectDeletion(in); +- } ++ /* First check that the directory is empty. */ ++ if (ylist_empty(&in->variant.directoryVariant.children)) { ++ return yaffs_DoGenericObjectDeletion(in); ++ } + + return YAFFS_FAIL; + +@@ -5161,11 +5266,11 @@ static int yaffs_DeleteSymLink(yaffs_Obj + + static int yaffs_DeleteHardLink(yaffs_Object * in) + { +- /* remove this hardlink from the list assocaited with the equivalent +- * object +- */ +- list_del(&in->hardLinks); +- return yaffs_DoGenericObjectDeletion(in); ++ /* remove this hardlink from the list assocaited with the equivalent ++ * object ++ */ ++ ylist_del_init(&in->hardLinks); ++ return yaffs_DoGenericObjectDeletion(in); + } + + static void yaffs_DestroyObject(yaffs_Object * obj) +@@ -5194,12 +5299,12 @@ static void yaffs_DestroyObject(yaffs_Ob + static int yaffs_UnlinkWorker(yaffs_Object * obj) + { + +- if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { +- return yaffs_DeleteHardLink(obj); +- } else if (!list_empty(&obj->hardLinks)) { +- /* Curve ball: We're unlinking an object that has a hardlink. +- * +- * This problem arises because we are not strictly following ++ if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { ++ return yaffs_DeleteHardLink(obj); ++ } else if (!ylist_empty(&obj->hardLinks)) { ++ /* Curve ball: We're unlinking an object that has a hardlink. ++ * ++ * This problem arises because we are not strictly following + * The Linux link/inode model. + * + * We can't really delete the object. +@@ -5212,15 +5317,15 @@ static int yaffs_UnlinkWorker(yaffs_Obje + */ + + yaffs_Object *hl; +- int retVal; +- YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; ++ int retVal; ++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; + +- hl = list_entry(obj->hardLinks.next, yaffs_Object, hardLinks); ++ hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks); + +- list_del_init(&hl->hardLinks); +- list_del_init(&hl->siblings); ++ ylist_del_init(&hl->hardLinks); ++ ylist_del_init(&hl->siblings); + +- yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1); ++ yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1); + + retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0); + +@@ -5313,7 +5418,7 @@ static void yaffs_HardlinkFixup(yaffs_De + { + yaffs_Object *hl; + yaffs_Object *in; +- ++ + while (hardList) { + hl = hardList; + hardList = (yaffs_Object *) (hardList->hardLinks.next); +@@ -5322,18 +5427,18 @@ static void yaffs_HardlinkFixup(yaffs_De + hl->variant.hardLinkVariant. + equivalentObjectId); + +- if (in) { +- /* Add the hardlink pointers */ +- hl->variant.hardLinkVariant.equivalentObject = in; +- list_add(&hl->hardLinks, &in->hardLinks); +- } else { +- /* Todo Need to report/handle this better. +- * Got a problem... hardlink to a non-existant object +- */ +- hl->variant.hardLinkVariant.equivalentObject = NULL; +- INIT_LIST_HEAD(&hl->hardLinks); ++ if (in) { ++ /* Add the hardlink pointers */ ++ hl->variant.hardLinkVariant.equivalentObject = in; ++ ylist_add(&hl->hardLinks, &in->hardLinks); ++ } else { ++ /* Todo Need to report/handle this better. ++ * Got a problem... hardlink to a non-existant object ++ */ ++ hl->variant.hardLinkVariant.equivalentObject = NULL; ++ YINIT_LIST_HEAD(&hl->hardLinks); + +- } ++ } + + } + +@@ -5355,6 +5460,42 @@ static int ybicmp(const void *a, const v + + } + ++ ++struct yaffs_ShadowFixerStruct { ++ int objectId; ++ int shadowedId; ++ struct yaffs_ShadowFixerStruct *next; ++}; ++ ++ ++static void yaffs_StripDeletedObjects(yaffs_Device *dev) ++{ ++ /* ++ * Sort out state of unlinked and deleted objects after scanning. ++ */ ++ struct ylist_head *i; ++ struct ylist_head *n; ++ yaffs_Object *l; ++ ++ /* Soft delete all the unlinked files */ ++ ylist_for_each_safe(i, n, ++ &dev->unlinkedDir->variant.directoryVariant.children) { ++ if (i) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ yaffs_DestroyObject(l); ++ } ++ } ++ ++ ylist_for_each_safe(i, n, ++ &dev->deletedDir->variant.directoryVariant.children) { ++ if (i) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ yaffs_DestroyObject(l); ++ } ++ } ++ ++} ++ + static int yaffs_Scan(yaffs_Device * dev) + { + yaffs_ExtendedTags tags; +@@ -5362,7 +5503,6 @@ static int yaffs_Scan(yaffs_Device * dev + int blockIterator; + int startIterator; + int endIterator; +- int nBlocksToScan = 0; + int result; + + int chunk; +@@ -5371,27 +5511,20 @@ static int yaffs_Scan(yaffs_Device * dev + yaffs_BlockState state; + yaffs_Object *hardList = NULL; + yaffs_BlockInfo *bi; +- int sequenceNumber; ++ __u32 sequenceNumber; + yaffs_ObjectHeader *oh; + yaffs_Object *in; + yaffs_Object *parent; +- int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; +- ++ + int alloc_failed = 0; +- ++ ++ struct yaffs_ShadowFixerStruct *shadowFixerList = NULL; ++ + + __u8 *chunkData; + +- yaffs_BlockIndex *blockIndex = NULL; +- +- if (dev->isYaffs2) { +- T(YAFFS_TRACE_SCAN, +- (TSTR("yaffs_Scan is not for YAFFS2!" TENDSTR))); +- return YAFFS_FAIL; +- } +- +- //TODO Throw all the yaffs2 stuuf out of yaffs_Scan since it is only for yaffs1 format. +- ++ ++ + T(YAFFS_TRACE_SCAN, + (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR), + dev->internalStartBlock, dev->internalEndBlock)); +@@ -5400,12 +5533,6 @@ static int yaffs_Scan(yaffs_Device * dev + + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; + +- if (dev->isYaffs2) { +- blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); +- if(!blockIndex) +- return YAFFS_FAIL; +- } +- + /* Scan all the blocks to determine their state */ + for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { + bi = yaffs_GetBlockInfo(dev, blk); +@@ -5430,70 +5557,21 @@ static int yaffs_Scan(yaffs_Device * dev + (TSTR("Block empty " TENDSTR))); + dev->nErasedBlocks++; + dev->nFreeChunks += dev->nChunksPerBlock; +- } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { +- +- /* Determine the highest sequence number */ +- if (dev->isYaffs2 && +- sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && +- sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) { +- +- blockIndex[nBlocksToScan].seq = sequenceNumber; +- blockIndex[nBlocksToScan].block = blk; +- +- nBlocksToScan++; +- +- if (sequenceNumber >= dev->sequenceNumber) { +- dev->sequenceNumber = sequenceNumber; +- } +- } else if (dev->isYaffs2) { +- /* TODO: Nasty sequence number! */ +- T(YAFFS_TRACE_SCAN, +- (TSTR +- ("Block scanning block %d has bad sequence number %d" +- TENDSTR), blk, sequenceNumber)); +- +- } +- } ++ } + } + +- /* Sort the blocks +- * Dungy old bubble sort for now... +- */ +- if (dev->isYaffs2) { +- yaffs_BlockIndex temp; +- int i; +- int j; +- +- for (i = 0; i < nBlocksToScan; i++) +- for (j = i + 1; j < nBlocksToScan; j++) +- if (blockIndex[i].seq > blockIndex[j].seq) { +- temp = blockIndex[j]; +- blockIndex[j] = blockIndex[i]; +- blockIndex[i] = temp; +- } +- } +- +- /* Now scan the blocks looking at the data. */ +- if (dev->isYaffs2) { +- startIterator = 0; +- endIterator = nBlocksToScan - 1; +- T(YAFFS_TRACE_SCAN_DEBUG, +- (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); +- } else { +- startIterator = dev->internalStartBlock; +- endIterator = dev->internalEndBlock; +- } ++ startIterator = dev->internalStartBlock; ++ endIterator = dev->internalEndBlock; + + /* For each block.... */ + for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; + blockIterator++) { ++ ++ YYIELD(); + +- if (dev->isYaffs2) { +- /* get the block to scan in the correct order */ +- blk = blockIndex[blockIterator].block; +- } else { +- blk = blockIterator; +- } ++ YYIELD(); ++ ++ blk = blockIterator; + + bi = yaffs_GetBlockInfo(dev, blk); + state = bi->blockState; +@@ -5511,7 +5589,7 @@ static int yaffs_Scan(yaffs_Device * dev + + /* Let's have a good look at this chunk... */ + +- if (!dev->isYaffs2 && tags.chunkDeleted) { ++ if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) { + /* YAFFS1 only... + * A deleted chunk + */ +@@ -5520,7 +5598,7 @@ static int yaffs_Scan(yaffs_Device * dev + /*T((" %d %d deleted\n",blk,c)); */ + } else if (!tags.chunkUsed) { + /* An unassigned chunk in the block +- * This means that either the block is empty or ++ * This means that either the block is empty or + * this is the one being allocated from + */ + +@@ -5537,21 +5615,9 @@ static int yaffs_Scan(yaffs_Device * dev + state = YAFFS_BLOCK_STATE_ALLOCATING; + dev->allocationBlock = blk; + dev->allocationPage = c; +- dev->allocationBlockFinder = blk; ++ dev->allocationBlockFinder = blk; + /* Set it to here to encourage the allocator to go forth from here. */ +- +- /* Yaffs2 sanity check: +- * This should be the one with the highest sequence number +- */ +- if (dev->isYaffs2 +- && (dev->sequenceNumber != +- bi->sequenceNumber)) { +- T(YAFFS_TRACE_ALWAYS, +- (TSTR +- ("yaffs: Allocation block %d was not highest sequence id:" +- " block seq = %d, dev seq = %d" +- TENDSTR), blk,bi->sequenceNumber,dev->sequenceNumber)); +- } ++ + } + + dev->nFreeChunks += (dev->nChunksPerBlock - c); +@@ -5569,7 +5635,7 @@ static int yaffs_Scan(yaffs_Device * dev + /* PutChunkIntoFile checks for a clash (two data chunks with + * the same chunkId). + */ +- ++ + if(!in) + alloc_failed = 1; + +@@ -5577,11 +5643,11 @@ static int yaffs_Scan(yaffs_Device * dev + if(!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk,1)) + alloc_failed = 1; + } +- ++ + endpos = + (tags.chunkId - 1) * dev->nDataBytesPerChunk + + tags.byteCount; +- if (in && ++ if (in && + in->variantType == YAFFS_OBJECT_TYPE_FILE + && in->variant.fileVariant.scannedFileSize < + endpos) { +@@ -5613,7 +5679,7 @@ static int yaffs_Scan(yaffs_Device * dev + tags.objectId); + if (in && in->variantType != oh->type) { + /* This should not happen, but somehow +- * Wev'e ended up with an objectId that has been reused but not yet ++ * Wev'e ended up with an objectId that has been reused but not yet + * deleted, and worse still it has changed type. Delete the old object. + */ + +@@ -5629,12 +5695,18 @@ static int yaffs_Scan(yaffs_Device * dev + + if(!in) + alloc_failed = 1; +- ++ + if (in && oh->shadowsObject > 0) { +- yaffs_HandleShadowedObject(dev, +- oh-> +- shadowsObject, +- 0); ++ ++ struct yaffs_ShadowFixerStruct *fixer; ++ fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct)); ++ if(fixer){ ++ fixer-> next = shadowFixerList; ++ shadowFixerList = fixer; ++ fixer->objectId = tags.objectId; ++ fixer->shadowedId = oh->shadowsObject; ++ } ++ + } + + if (in && in->valid) { +@@ -5643,12 +5715,10 @@ static int yaffs_Scan(yaffs_Device * dev + unsigned existingSerial = in->serial; + unsigned newSerial = tags.serialNumber; + +- if (dev->isYaffs2 || +- ((existingSerial + 1) & 3) == +- newSerial) { ++ if (((existingSerial + 1) & 3) == newSerial) { + /* Use new one - destroy the exisiting one */ + yaffs_DeleteChunk(dev, +- in->chunkId, ++ in->hdrChunk, + 1, __LINE__); + in->valid = 0; + } else { +@@ -5681,7 +5751,8 @@ static int yaffs_Scan(yaffs_Device * dev + in->yst_ctime = oh->yst_ctime; + in->yst_rdev = oh->yst_rdev; + #endif +- in->chunkId = chunk; ++ in->hdrChunk = chunk; ++ in->serial = tags.serialNumber; + + } else if (in && !in->valid) { + /* we need to load this info */ +@@ -5705,7 +5776,8 @@ static int yaffs_Scan(yaffs_Device * dev + in->yst_ctime = oh->yst_ctime; + in->yst_rdev = oh->yst_rdev; + #endif +- in->chunkId = chunk; ++ in->hdrChunk = chunk; ++ in->serial = tags.serialNumber; + + yaffs_SetObjectName(in, oh->name); + in->dirty = 0; +@@ -5720,13 +5792,13 @@ static int yaffs_Scan(yaffs_Device * dev + YAFFS_OBJECT_TYPE_DIRECTORY); + if (parent->variantType == + YAFFS_OBJECT_TYPE_UNKNOWN) { +- /* Set up as a directory */ +- parent->variantType = +- YAFFS_OBJECT_TYPE_DIRECTORY; +- INIT_LIST_HEAD(&parent->variant. +- directoryVariant. +- children); +- } else if (parent->variantType != ++ /* Set up as a directory */ ++ parent->variantType = ++ YAFFS_OBJECT_TYPE_DIRECTORY; ++ YINIT_LIST_HEAD(&parent->variant. ++ directoryVariant. ++ children); ++ } else if (parent->variantType != + YAFFS_OBJECT_TYPE_DIRECTORY) + { + /* Hoosterman, another problem.... +@@ -5735,8 +5807,7 @@ static int yaffs_Scan(yaffs_Device * dev + + T(YAFFS_TRACE_ERROR, + (TSTR +- ("yaffs tragedy: attempting to use non-directory as" +- " a directory in scan. Put in lost+found." ++ ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." + TENDSTR))); + parent = dev->lostNFoundDir; + } +@@ -5752,23 +5823,14 @@ static int yaffs_Scan(yaffs_Device * dev + * Since we might scan a hardlink before its equivalent object is scanned + * we put them all in a list. + * After scanning is complete, we should have all the objects, so we run through this +- * list and fix up all the chains. ++ * list and fix up all the chains. + */ + + switch (in->variantType) { +- case YAFFS_OBJECT_TYPE_UNKNOWN: ++ case YAFFS_OBJECT_TYPE_UNKNOWN: + /* Todo got a problem */ + break; + case YAFFS_OBJECT_TYPE_FILE: +- if (dev->isYaffs2 +- && oh->isShrink) { +- /* Prune back the shrunken chunks */ +- yaffs_PruneResizedChunks +- (in, oh->fileSize); +- /* Mark the block as having a shrinkHeader */ +- bi->hasShrinkHeader = 1; +- } +- + if (dev->useHeaderFileSize) + + in->variant.fileVariant. +@@ -5778,20 +5840,20 @@ static int yaffs_Scan(yaffs_Device * dev + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + in->variant.hardLinkVariant. +- equivalentObjectId = +- oh->equivalentObjectId; +- in->hardLinks.next = +- (struct list_head *) +- hardList; +- hardList = in; +- break; ++ equivalentObjectId = ++ oh->equivalentObjectId; ++ in->hardLinks.next = ++ (struct ylist_head *) ++ hardList; ++ hardList = in; ++ break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + /* Do nothing */ + break; +- case YAFFS_OBJECT_TYPE_SYMLINK: ++ case YAFFS_OBJECT_TYPE_SYMLINK: + in->variant.symLinkVariant.alias = + yaffs_CloneString(oh->alias); + if(!in->variant.symLinkVariant.alias) +@@ -5799,10 +5861,12 @@ static int yaffs_Scan(yaffs_Device * dev + break; + } + +- if (parent == dev->deletedDir) { ++/* ++ if (parent == dev->deletedDir) { + yaffs_DestroyObject(in); + bi->hasShrinkHeader = 1; + } ++*/ + } + } + } +@@ -5823,35 +5887,36 @@ static int yaffs_Scan(yaffs_Device * dev + + } + +- if (blockIndex) { +- YFREE(blockIndex); +- } +- +- ++ + /* Ok, we've done all the scanning. + * Fix up the hard link chains. +- * We should now have scanned all the objects, now it's time to add these ++ * We should now have scanned all the objects, now it's time to add these + * hardlinks. + */ + + yaffs_HardlinkFixup(dev,hardList); +- +- /* Handle the unlinked files. Since they were left in an unlinked state we should +- * just delete them. +- */ ++ ++ /* Fix up any shadowed objects */ + { +- struct list_head *i; +- struct list_head *n; +- +- yaffs_Object *l; +- /* Soft delete all the unlinked files */ +- list_for_each_safe(i, n, +- &dev->unlinkedDir->variant.directoryVariant. +- children) { +- if (i) { +- l = list_entry(i, yaffs_Object, siblings); +- yaffs_DestroyObject(l); ++ struct yaffs_ShadowFixerStruct *fixer; ++ yaffs_Object *obj; ++ ++ while(shadowFixerList){ ++ fixer = shadowFixerList; ++ shadowFixerList = fixer->next; ++ /* Complete the rename transaction by deleting the shadowed object ++ * then setting the object header to unshadowed. ++ */ ++ obj = yaffs_FindObjectByNumber(dev,fixer->shadowedId); ++ if(obj) ++ yaffs_DestroyObject(obj); ++ ++ obj = yaffs_FindObjectByNumber(dev,fixer->objectId); ++ if(obj){ ++ yaffs_UpdateObjectHeader(obj,NULL,1,0,0); + } ++ ++ YFREE(fixer); + } + } + +@@ -5860,9 +5925,9 @@ static int yaffs_Scan(yaffs_Device * dev + if(alloc_failed){ + return YAFFS_FAIL; + } +- ++ + T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR))); +- ++ + + return YAFFS_OK; + } +@@ -5871,25 +5936,27 @@ static void yaffs_CheckObjectDetailsLoad + { + __u8 *chunkData; + yaffs_ObjectHeader *oh; +- yaffs_Device *dev = in->myDev; ++ yaffs_Device *dev; + yaffs_ExtendedTags tags; + int result; + int alloc_failed = 0; + + if(!in) + return; +- ++ ++ dev = in->myDev; ++ + #if 0 + T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR), + in->objectId, + in->lazyLoaded ? "not yet" : "already")); + #endif + +- if(in->lazyLoaded){ ++ if(in->lazyLoaded && in->hdrChunk > 0){ + in->lazyLoaded = 0; + chunkData = yaffs_GetTempBuffer(dev, __LINE__); + +- result = yaffs_ReadChunkWithTagsFromNAND(dev,in->chunkId,chunkData,&tags); ++ result = yaffs_ReadChunkWithTagsFromNAND(dev,in->hdrChunk,chunkData,&tags); + oh = (yaffs_ObjectHeader *) chunkData; + + in->yst_mode = oh->yst_mode; +@@ -5907,17 +5974,17 @@ static void yaffs_CheckObjectDetailsLoad + in->yst_mtime = oh->yst_mtime; + in->yst_ctime = oh->yst_ctime; + in->yst_rdev = oh->yst_rdev; +- ++ + #endif + yaffs_SetObjectName(in, oh->name); +- ++ + if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK){ + in->variant.symLinkVariant.alias = + yaffs_CloneString(oh->alias); + if(!in->variant.symLinkVariant.alias) + alloc_failed = 1; /* Not returned to caller */ + } +- ++ + yaffs_ReleaseTempBuffer(dev,chunkData, __LINE__); + } + } +@@ -5938,20 +6005,20 @@ static int yaffs_ScanBackwards(yaffs_Dev + yaffs_BlockState state; + yaffs_Object *hardList = NULL; + yaffs_BlockInfo *bi; +- int sequenceNumber; ++ __u32 sequenceNumber; + yaffs_ObjectHeader *oh; + yaffs_Object *in; + yaffs_Object *parent; + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; + int itsUnlinked; + __u8 *chunkData; +- ++ + int fileSize; + int isShrink; + int foundChunksInBlock; + int equivalentObjectId; + int alloc_failed = 0; +- ++ + + yaffs_BlockIndex *blockIndex = NULL; + int altBlockIndex = 0; +@@ -5971,20 +6038,20 @@ static int yaffs_ScanBackwards(yaffs_Dev + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; + + blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); +- ++ + if(!blockIndex) { + blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex)); + altBlockIndex = 1; + } +- ++ + if(!blockIndex) { + T(YAFFS_TRACE_SCAN, + (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR))); + return YAFFS_FAIL; + } +- ++ + dev->blocksInCheckpoint = 0; +- ++ + chunkData = yaffs_GetTempBuffer(dev, __LINE__); + + /* Scan all the blocks to determine their state */ +@@ -6001,15 +6068,15 @@ static int yaffs_ScanBackwards(yaffs_Dev + + if(bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) + bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT; +- ++ + T(YAFFS_TRACE_SCAN_DEBUG, + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, + state, sequenceNumber)); + +- ++ + if(state == YAFFS_BLOCK_STATE_CHECKPOINT){ + dev->blocksInCheckpoint++; +- ++ + } else if (state == YAFFS_BLOCK_STATE_DEAD) { + T(YAFFS_TRACE_BAD_BLOCKS, + (TSTR("block %d is bad" TENDSTR), blk)); +@@ -6021,8 +6088,7 @@ static int yaffs_ScanBackwards(yaffs_Dev + } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { + + /* Determine the highest sequence number */ +- if (dev->isYaffs2 && +- sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && ++ if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && + sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) { + + blockIndex[nBlocksToScan].seq = sequenceNumber; +@@ -6033,7 +6099,7 @@ static int yaffs_ScanBackwards(yaffs_Dev + if (sequenceNumber >= dev->sequenceNumber) { + dev->sequenceNumber = sequenceNumber; + } +- } else if (dev->isYaffs2) { ++ } else { + /* TODO: Nasty sequence number! */ + T(YAFFS_TRACE_SCAN, + (TSTR +@@ -6053,12 +6119,14 @@ static int yaffs_ScanBackwards(yaffs_Dev + + /* Sort the blocks */ + #ifndef CONFIG_YAFFS_USE_OWN_SORT +- yaffs_qsort(blockIndex, nBlocksToScan, +- sizeof(yaffs_BlockIndex), ybicmp); ++ { ++ /* Use qsort now. */ ++ yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); ++ } + #else + { + /* Dungy old bubble sort... */ +- ++ + yaffs_BlockIndex temp; + int i; + int j; +@@ -6094,22 +6162,22 @@ static int yaffs_ScanBackwards(yaffs_Dev + blk = blockIndex[blockIterator].block; + + bi = yaffs_GetBlockInfo(dev, blk); +- +- ++ ++ + state = bi->blockState; + + deleted = 0; + + /* For each chunk in each block that needs scanning.... */ + foundChunksInBlock = 0; +- for (c = dev->nChunksPerBlock - 1; ++ for (c = dev->nChunksPerBlock - 1; + !alloc_failed && c >= 0 && + (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || + state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { +- /* Scan backwards... ++ /* Scan backwards... + * Read the tags and decide what to do + */ +- ++ + chunk = blk * dev->nChunksPerBlock + c; + + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, +@@ -6123,14 +6191,14 @@ static int yaffs_ScanBackwards(yaffs_Dev + * it is a chunk that was skipped due to failing the erased + * check. Just skip it so that it can be deleted. + * But, more typically, We get here when this is an unallocated +- * chunk and his means that either the block is empty or ++ * chunk and his means that either the block is empty or + * this is the one being allocated from + */ + + if(foundChunksInBlock) + { + /* This is a chunk that was skipped due to failing the erased check */ +- ++ + } else if (c == 0) { + /* We're looking at the first chunk in the block so the block is unused */ + state = YAFFS_BLOCK_STATE_EMPTY; +@@ -6140,7 +6208,7 @@ static int yaffs_ScanBackwards(yaffs_Dev + state == YAFFS_BLOCK_STATE_ALLOCATING) { + if(dev->sequenceNumber == bi->sequenceNumber) { + /* this is the block being allocated from */ +- ++ + T(YAFFS_TRACE_SCAN, + (TSTR + (" Allocating from %d %d" +@@ -6149,34 +6217,41 @@ static int yaffs_ScanBackwards(yaffs_Dev + state = YAFFS_BLOCK_STATE_ALLOCATING; + dev->allocationBlock = blk; + dev->allocationPage = c; +- dev->allocationBlockFinder = blk; ++ dev->allocationBlockFinder = blk; + } + else { + /* This is a partially written block that is not + * the current allocation block. This block must have + * had a write failure, so set up for retirement. + */ +- +- bi->needsRetiring = 1; ++ ++ /* bi->needsRetiring = 1; ??? TODO */ + bi->gcPrioritise = 1; +- ++ + T(YAFFS_TRACE_ALWAYS, +- (TSTR("Partially written block %d being set for retirement" TENDSTR), ++ (TSTR("Partially written block %d detected" TENDSTR), + blk)); + } + + } +- ++ + } + + dev->nFreeChunks++; ++ ++ } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED){ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR), ++ blk, c)); + +- } else if (tags.chunkId > 0) { ++ dev->nFreeChunks++; ++ ++ }else if (tags.chunkId > 0) { + /* chunkId > 0 so it is a data chunk... */ + unsigned int endpos; + __u32 chunkBase = + (tags.chunkId - 1) * dev->nDataBytesPerChunk; +- ++ + foundChunksInBlock = 1; + + +@@ -6191,7 +6266,7 @@ static int yaffs_ScanBackwards(yaffs_Dev + /* Out of memory */ + alloc_failed = 1; + } +- ++ + if (in && + in->variantType == YAFFS_OBJECT_TYPE_FILE + && chunkBase < +@@ -6202,14 +6277,14 @@ static int yaffs_ScanBackwards(yaffs_Dev + alloc_failed = 1; + } + +- /* File size is calculated by looking at the data chunks if we have not ++ /* File size is calculated by looking at the data chunks if we have not + * seen an object header yet. Stop this practice once we find an object header. + */ + endpos = + (tags.chunkId - + 1) * dev->nDataBytesPerChunk + + tags.byteCount; +- ++ + if (!in->valid && /* have not got an object header yet */ + in->variant.fileVariant. + scannedFileSize < endpos) { +@@ -6255,7 +6330,7 @@ static int yaffs_ScanBackwards(yaffs_Dev + ) { + + /* If we don't have valid info then we need to read the chunk +- * TODO In future we can probably defer reading the chunk and ++ * TODO In future we can probably defer reading the chunk and + * living with invalid data until needed. + */ + +@@ -6265,6 +6340,12 @@ static int yaffs_ScanBackwards(yaffs_Dev + NULL); + + oh = (yaffs_ObjectHeader *) chunkData; ++ ++ if(dev->inbandTags){ ++ /* Fix up the header if they got corrupted by inband tags */ ++ oh->shadowsObject = oh->inbandShadowsObject; ++ oh->isShrink = oh->inbandIsShrink; ++ } + + if (!in) + in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type); +@@ -6275,20 +6356,19 @@ static int yaffs_ScanBackwards(yaffs_Dev + /* TODO Hoosterman we have a problem! */ + T(YAFFS_TRACE_ERROR, + (TSTR +- ("yaffs tragedy: Could not make object for object %d " +- "at chunk %d during scan" ++ ("yaffs tragedy: Could not make object for object %d at chunk %d during scan" + TENDSTR), tags.objectId, chunk)); + + } + + if (in->valid) { + /* We have already filled this one. +- * We have a duplicate that will be discarded, but ++ * We have a duplicate that will be discarded, but + * we first have to suck out resize info if it is a file. + */ + +- if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && +- ((oh && ++ if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && ++ ((oh && + oh-> type == YAFFS_OBJECT_TYPE_FILE)|| + (tags.extraHeaderInfoAvailable && + tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE)) +@@ -6300,7 +6380,9 @@ static int yaffs_ScanBackwards(yaffs_Dev + (oh) ? oh-> + parentObjectId : tags. + extraParentObjectId; +- unsigned isShrink = ++ ++ ++ isShrink = + (oh) ? oh->isShrink : tags. + extraIsShrinkHeader; + +@@ -6339,7 +6421,7 @@ static int yaffs_ScanBackwards(yaffs_Dev + YAFFS_OBJECTID_LOSTNFOUND)) { + /* We only load some info, don't fiddle with directory structure */ + in->valid = 1; +- ++ + if(oh) { + in->variantType = oh->type; + +@@ -6358,20 +6440,20 @@ static int yaffs_ScanBackwards(yaffs_Dev + in->yst_mtime = oh->yst_mtime; + in->yst_ctime = oh->yst_ctime; + in->yst_rdev = oh->yst_rdev; +- ++ + #endif + } else { + in->variantType = tags.extraObjectType; + in->lazyLoaded = 1; + } + +- in->chunkId = chunk; ++ in->hdrChunk = chunk; + + } else if (!in->valid) { + /* we need to load this info */ + + in->valid = 1; +- in->chunkId = chunk; ++ in->hdrChunk = chunk; + + if(oh) { + in->variantType = oh->type; +@@ -6393,12 +6475,12 @@ static int yaffs_ScanBackwards(yaffs_Dev + in->yst_rdev = oh->yst_rdev; + #endif + +- if (oh->shadowsObject > 0) ++ if (oh->shadowsObject > 0) + yaffs_HandleShadowedObject(dev, + oh-> + shadowsObject, + 1); +- ++ + + yaffs_SetObjectName(in, oh->name); + parent = +@@ -6431,13 +6513,13 @@ static int yaffs_ScanBackwards(yaffs_Dev + + if (parent->variantType == + YAFFS_OBJECT_TYPE_UNKNOWN) { +- /* Set up as a directory */ +- parent->variantType = +- YAFFS_OBJECT_TYPE_DIRECTORY; +- INIT_LIST_HEAD(&parent->variant. +- directoryVariant. +- children); +- } else if (parent->variantType != ++ /* Set up as a directory */ ++ parent->variantType = ++ YAFFS_OBJECT_TYPE_DIRECTORY; ++ YINIT_LIST_HEAD(&parent->variant. ++ directoryVariant. ++ children); ++ } else if (parent->variantType != + YAFFS_OBJECT_TYPE_DIRECTORY) + { + /* Hoosterman, another problem.... +@@ -6446,8 +6528,7 @@ static int yaffs_ScanBackwards(yaffs_Dev + + T(YAFFS_TRACE_ERROR, + (TSTR +- ("yaffs tragedy: attempting to use non-directory as" +- " a directory in scan. Put in lost+found." ++ ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." + TENDSTR))); + parent = dev->lostNFoundDir; + } +@@ -6466,11 +6547,11 @@ static int yaffs_ScanBackwards(yaffs_Dev + * Since we might scan a hardlink before its equivalent object is scanned + * we put them all in a list. + * After scanning is complete, we should have all the objects, so we run +- * through this list and fix up all the chains. ++ * through this list and fix up all the chains. + */ + + switch (in->variantType) { +- case YAFFS_OBJECT_TYPE_UNKNOWN: ++ case YAFFS_OBJECT_TYPE_UNKNOWN: + /* Todo got a problem */ + break; + case YAFFS_OBJECT_TYPE_FILE: +@@ -6479,7 +6560,7 @@ static int yaffs_ScanBackwards(yaffs_Dev + scannedFileSize < fileSize) { + /* This covers the case where the file size is greater + * than where the data is +- * This will happen if the file is resized to be larger ++ * This will happen if the file is resized to be larger + * than its current data extents. + */ + in->variant.fileVariant.fileSize = fileSize; +@@ -6495,13 +6576,13 @@ static int yaffs_ScanBackwards(yaffs_Dev + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + if(!itsUnlinked) { +- in->variant.hardLinkVariant.equivalentObjectId = +- equivalentObjectId; +- in->hardLinks.next = +- (struct list_head *) hardList; +- hardList = in; +- } +- break; ++ in->variant.hardLinkVariant.equivalentObjectId = ++ equivalentObjectId; ++ in->hardLinks.next = ++ (struct ylist_head *) hardList; ++ hardList = in; ++ } ++ break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + /* Do nothing */ + break; +@@ -6520,7 +6601,7 @@ static int yaffs_ScanBackwards(yaffs_Dev + } + + } +- ++ + } + + } /* End of scanning for each chunk */ +@@ -6541,72 +6622,128 @@ static int yaffs_ScanBackwards(yaffs_Dev + + } + +- if (altBlockIndex) ++ if (altBlockIndex) + YFREE_ALT(blockIndex); + else + YFREE(blockIndex); +- ++ + /* Ok, we've done all the scanning. + * Fix up the hard link chains. +- * We should now have scanned all the objects, now it's time to add these ++ * We should now have scanned all the objects, now it's time to add these + * hardlinks. + */ + yaffs_HardlinkFixup(dev,hardList); ++ + ++ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); ++ ++ if(alloc_failed){ ++ return YAFFS_FAIL; ++ } + +- /* +- * Sort out state of unlinked and deleted objects. +- */ +- { +- struct list_head *i; +- struct list_head *n; ++ T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR))); + +- yaffs_Object *l; ++ return YAFFS_OK; ++} + +- /* Soft delete all the unlinked files */ +- list_for_each_safe(i, n, +- &dev->unlinkedDir->variant.directoryVariant. +- children) { +- if (i) { +- l = list_entry(i, yaffs_Object, siblings); +- yaffs_DestroyObject(l); +- } +- } ++/*------------------------------ Directory Functions ----------------------------- */ + +- /* Soft delete all the deletedDir files */ +- list_for_each_safe(i, n, +- &dev->deletedDir->variant.directoryVariant. +- children) { +- if (i) { +- l = list_entry(i, yaffs_Object, siblings); +- yaffs_DestroyObject(l); ++static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj) ++{ ++ struct ylist_head *lh; ++ yaffs_Object *listObj; ++ ++ int count = 0; + +- } +- } ++ if(!obj){ ++ T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR))); ++ YBUG(); + } + +- yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); ++ if(yaffs_SkipVerification(obj->myDev)) ++ return; + +- if(alloc_failed){ +- return YAFFS_FAIL; ++ if(!obj->parent){ ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR))); ++ YBUG(); ++ } ++ ++ if(obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY){ ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR))); ++ YBUG(); ++ } ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) { ++ if (lh) { ++ listObj = ylist_entry(lh, yaffs_Object, siblings); ++ yaffs_VerifyObject(listObj); ++ if(obj == listObj) ++ count ++; ++ } ++ } ++ ++ if(count != 1){ ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR),count)); ++ YBUG(); + } + +- T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR))); ++} + +- return YAFFS_OK; ++static void yaffs_VerifyDirectory(yaffs_Object *directory) ++{ ++ ++ struct ylist_head *lh; ++ yaffs_Object *listObj; ++ ++ if(!directory) ++ YBUG(); ++ ++ if(yaffs_SkipFullVerification(directory->myDev)) ++ return; ++ ++ ++ if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY){ ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR),directory->variantType)); ++ YBUG(); ++ } ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ ylist_for_each(lh, &directory->variant.directoryVariant.children) { ++ if (lh) { ++ listObj = ylist_entry(lh, yaffs_Object, siblings); ++ if(listObj->parent != directory){ ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR),listObj->parent)); ++ YBUG(); ++ } ++ yaffs_VerifyObjectInDirectory(listObj); ++ } ++ } ++ + } + +-/*------------------------------ Directory Functions ----------------------------- */ + + static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj) + { + yaffs_Device *dev = obj->myDev; ++ yaffs_Object *parent; ++ ++ yaffs_VerifyObjectInDirectory(obj); ++ parent = obj->parent; ++ ++ yaffs_VerifyDirectory(parent); ++ ++ if(dev && dev->removeObjectCallback) ++ dev->removeObjectCallback(obj); ++ ++ ++ ylist_del_init(&obj->siblings); ++ obj->parent = NULL; + +- if(dev && dev->removeObjectCallback) +- dev->removeObjectCallback(obj); ++ yaffs_VerifyDirectory(parent); + +- list_del_init(&obj->siblings); +- obj->parent = NULL; + } + + +@@ -6629,35 +6766,46 @@ static void yaffs_AddObjectToDirectory(y + YBUG(); + } + +- if (obj->siblings.prev == NULL) { +- /* Not initialised */ +- INIT_LIST_HEAD(&obj->siblings); +- +- } else if (!list_empty(&obj->siblings)) { +- /* If it is holed up somewhere else, un hook it */ +- yaffs_RemoveObjectFromDirectory(obj); +- } +- /* Now add it */ +- list_add(&obj->siblings, &directory->variant.directoryVariant.children); +- obj->parent = directory; ++ if (obj->siblings.prev == NULL) { ++ /* Not initialised */ ++ YBUG(); ++ ++ } else if (ylist_empty(&obj->siblings)) { ++ YBUG(); ++ } ++ + +- if (directory == obj->myDev->unlinkedDir ++ yaffs_VerifyDirectory(directory); ++ ++ yaffs_RemoveObjectFromDirectory(obj); ++ ++ ++ /* Now add it */ ++ ylist_add(&obj->siblings, &directory->variant.directoryVariant.children); ++ obj->parent = directory; ++ ++ if (directory == obj->myDev->unlinkedDir + || directory == obj->myDev->deletedDir) { + obj->unlinked = 1; + obj->myDev->nUnlinkedFiles++; + obj->renameAllowed = 0; + } ++ ++ yaffs_VerifyDirectory(directory); ++ yaffs_VerifyObjectInDirectory(obj); ++ ++ + } + + yaffs_Object *yaffs_FindObjectByName(yaffs_Object * directory, + const YCHAR * name) + { +- int sum; ++ int sum; + +- struct list_head *i; +- YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; ++ struct ylist_head *i; ++ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; + +- yaffs_Object *l; ++ yaffs_Object *l; + + if (!name) { + return NULL; +@@ -6677,22 +6825,24 @@ yaffs_Object *yaffs_FindObjectByName(yaf + YBUG(); + } + +- sum = yaffs_CalcNameSum(name); ++ sum = yaffs_CalcNameSum(name); + +- list_for_each(i, &directory->variant.directoryVariant.children) { +- if (i) { +- l = list_entry(i, yaffs_Object, siblings); +- +- yaffs_CheckObjectDetailsLoaded(l); ++ ylist_for_each(i, &directory->variant.directoryVariant.children) { ++ if (i) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ ++ if(l->parent != directory) ++ YBUG(); ++ ++ yaffs_CheckObjectDetailsLoaded(l); + + /* Special case for lost-n-found */ + if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) { + if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) { + return l; + } +- } else if (yaffs_SumCompare(l->sum, sum) || l->chunkId <= 0) +- { +- /* LostnFound cunk called Objxxx ++ } else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0){ ++ /* LostnFound chunk called Objxxx + * Do a real check + */ + yaffs_GetObjectName(l, buffer, +@@ -6711,12 +6861,12 @@ yaffs_Object *yaffs_FindObjectByName(yaf + + #if 0 + int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir, +- int (*fn) (yaffs_Object *)) ++ int (*fn) (yaffs_Object *)) + { +- struct list_head *i; +- yaffs_Object *l; ++ struct ylist_head *i; ++ yaffs_Object *l; + +- if (!theDir) { ++ if (!theDir) { + T(YAFFS_TRACE_ALWAYS, + (TSTR + ("tragedy: yaffs_FindObjectByName: null pointer directory" +@@ -6727,15 +6877,15 @@ int yaffs_ApplyToDirectoryChildren(yaffs + T(YAFFS_TRACE_ALWAYS, + (TSTR + ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR))); +- YBUG(); +- } ++ YBUG(); ++ } + +- list_for_each(i, &theDir->variant.directoryVariant.children) { +- if (i) { +- l = list_entry(i, yaffs_Object, siblings); +- if (l && !fn(l)) { +- return YAFFS_FAIL; +- } ++ ylist_for_each(i, &theDir->variant.directoryVariant.children) { ++ if (i) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ if (l && !fn(l)) { ++ return YAFFS_FAIL; ++ } + } + } + +@@ -6762,16 +6912,25 @@ yaffs_Object *yaffs_GetEquivalentObject( + int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize) + { + memset(name, 0, buffSize * sizeof(YCHAR)); +- ++ + yaffs_CheckObjectDetailsLoaded(obj); + + if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { + yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1); +- } else if (obj->chunkId <= 0) { ++ } else if (obj->hdrChunk <= 0) { + YCHAR locName[20]; ++ YCHAR numString[20]; ++ YCHAR *x = &numString[19]; ++ unsigned v = obj->objectId; ++ numString[19] = 0; ++ while(v>0){ ++ x--; ++ *x = '0' + (v % 10); ++ v /= 10; ++ } + /* make up a name */ +- yaffs_sprintf(locName, _Y("%s%d"), YAFFS_LOSTNFOUND_PREFIX, +- obj->objectId); ++ yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX); ++ yaffs_strcat(locName,x); + yaffs_strncpy(name, locName, buffSize - 1); + + } +@@ -6788,9 +6947,9 @@ int yaffs_GetObjectName(yaffs_Object * o + + memset(buffer, 0, obj->myDev->nDataBytesPerChunk); + +- if (obj->chunkId >= 0) { ++ if (obj->hdrChunk > 0) { + result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev, +- obj->chunkId, buffer, ++ obj->hdrChunk, buffer, + NULL); + } + yaffs_strncpy(name, oh->name, buffSize - 1); +@@ -6820,16 +6979,16 @@ int yaffs_GetObjectFileLength(yaffs_Obje + + int yaffs_GetObjectLinkCount(yaffs_Object * obj) + { +- int count = 0; +- struct list_head *i; ++ int count = 0; ++ struct ylist_head *i; + +- if (!obj->unlinked) { +- count++; /* the object itself */ +- } +- list_for_each(i, &obj->hardLinks) { +- count++; /* add the hard links; */ +- } +- return count; ++ if (!obj->unlinked) { ++ count++; /* the object itself */ ++ } ++ ylist_for_each(i, &obj->hardLinks) { ++ count++; /* add the hard links; */ ++ } ++ return count; + + } + +@@ -6951,7 +7110,7 @@ int yaffs_DumpObject(yaffs_Object * obj) + ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d" + " chunk %d type %d size %d\n" + TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name, +- obj->dirty, obj->valid, obj->serial, obj->sum, obj->chunkId, ++ obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk, + yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj))); + + return YAFFS_OK; +@@ -6994,13 +7153,13 @@ static int yaffs_CheckDevFunctions(const + static int yaffs_CreateInitialDirectories(yaffs_Device *dev) + { + /* Initialise the unlinked, deleted, root and lost and found directories */ +- ++ + dev->lostNFoundDir = dev->rootDir = NULL; + dev->unlinkedDir = dev->deletedDir = NULL; + + dev->unlinkedDir = + yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); +- ++ + dev->deletedDir = + yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); + +@@ -7010,12 +7169,12 @@ static int yaffs_CreateInitialDirectorie + dev->lostNFoundDir = + yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND, + YAFFS_LOSTNFOUND_MODE | S_IFDIR); +- ++ + if(dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir){ + yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir); + return YAFFS_OK; + } +- ++ + return YAFFS_FAIL; + } + +@@ -7039,6 +7198,8 @@ int yaffs_GutsInitialise(yaffs_Device * + dev->blockOffset = 0; + dev->chunkOffset = 0; + dev->nFreeChunks = 0; ++ ++ dev->gcBlock = -1; + + if (dev->startBlock == 0) { + dev->internalStartBlock = dev->startBlock + 1; +@@ -7049,18 +7210,19 @@ int yaffs_GutsInitialise(yaffs_Device * + + /* Check geometry parameters. */ + +- if ((dev->isYaffs2 && dev->nDataBytesPerChunk < 1024) || +- (!dev->isYaffs2 && dev->nDataBytesPerChunk != 512) || +- dev->nChunksPerBlock < 2 || +- dev->nReservedBlocks < 2 || +- dev->internalStartBlock <= 0 || +- dev->internalEndBlock <= 0 || ++ if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) || ++ (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) || ++ (dev->inbandTags && !dev->isYaffs2 ) || ++ dev->nChunksPerBlock < 2 || ++ dev->nReservedBlocks < 2 || ++ dev->internalStartBlock <= 0 || ++ dev->internalEndBlock <= 0 || + dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2) // otherwise it is too small + ) { + T(YAFFS_TRACE_ALWAYS, + (TSTR +- ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " +- TENDSTR), dev->nDataBytesPerChunk, dev->isYaffs2 ? "2" : "")); ++ ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d " ++ TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags)); + return YAFFS_FAIL; + } + +@@ -7069,6 +7231,12 @@ int yaffs_GutsInitialise(yaffs_Device * + (TSTR("yaffs: InitialiseNAND failed" TENDSTR))); + return YAFFS_FAIL; + } ++ ++ /* Sort out space for inband tags, if required */ ++ if(dev->inbandTags) ++ dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart); ++ else ++ dev->nDataBytesPerChunk = dev->totalBytesPerChunk; + + /* Got the right mix of functions? */ + if (!yaffs_CheckDevFunctions(dev)) { +@@ -7097,41 +7265,28 @@ int yaffs_GutsInitialise(yaffs_Device * + + dev->isMounted = 1; + +- +- + /* OK now calculate a few things for the device */ +- ++ + /* +- * Calculate all the chunk size manipulation numbers: ++ * Calculate all the chunk size manipulation numbers: + */ +- /* Start off assuming it is a power of 2 */ +- dev->chunkShift = ShiftDiv(dev->nDataBytesPerChunk); +- dev->chunkMask = (1<chunkShift) - 1; +- +- if(dev->nDataBytesPerChunk == (dev->chunkMask + 1)){ +- /* Yes it is a power of 2, disable crumbs */ +- dev->crumbMask = 0; +- dev->crumbShift = 0; +- dev->crumbsPerChunk = 0; +- } else { +- /* Not a power of 2, use crumbs instead */ +- dev->crumbShift = ShiftDiv(sizeof(yaffs_PackedTags2TagsPart)); +- dev->crumbMask = (1<crumbShift)-1; +- dev->crumbsPerChunk = dev->nDataBytesPerChunk/(1 << dev->crumbShift); +- dev->chunkShift = 0; +- dev->chunkMask = 0; +- } +- +- ++ x = dev->nDataBytesPerChunk; ++ /* We always use dev->chunkShift and dev->chunkDiv */ ++ dev->chunkShift = Shifts(x); ++ x >>= dev->chunkShift; ++ dev->chunkDiv = x; ++ /* We only use chunk mask if chunkDiv is 1 */ ++ dev->chunkMask = (1<chunkShift) - 1; ++ + /* + * Calculate chunkGroupBits. + * We need to find the next power of 2 > than internalEndBlock + */ + + x = dev->nChunksPerBlock * (dev->internalEndBlock + 1); +- ++ + bits = ShiftsGE(x); +- ++ + /* Set up tnode width if wide tnodes are enabled. */ + if(!dev->wideTnodesDisabled){ + /* bits must be even so that we end up with 32-bit words */ +@@ -7144,20 +7299,20 @@ int yaffs_GutsInitialise(yaffs_Device * + } + else + dev->tnodeWidth = 16; +- ++ + dev->tnodeMask = (1<tnodeWidth)-1; +- ++ + /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), + * so if the bitwidth of the + * chunk range we're using is greater than 16 we need + * to figure out chunk shift and chunkGroupSize + */ +- ++ + if (bits <= dev->tnodeWidth) + dev->chunkGroupBits = 0; + else + dev->chunkGroupBits = bits - dev->tnodeWidth; +- ++ + + dev->chunkGroupSize = 1 << dev->chunkGroupBits; + +@@ -7195,40 +7350,42 @@ int yaffs_GutsInitialise(yaffs_Device * + /* Initialise temporary buffers and caches. */ + if(!yaffs_InitialiseTempBuffers(dev)) + init_failed = 1; +- ++ + dev->srCache = NULL; + dev->gcCleanupList = NULL; +- +- ++ ++ + if (!init_failed && + dev->nShortOpCaches > 0) { + int i; +- __u8 *buf; ++ void *buf; + int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache); + + if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) { + dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; + } + +- buf = dev->srCache = YMALLOC(srCacheBytes); +- ++ dev->srCache = YMALLOC(srCacheBytes); ++ ++ buf = (__u8 *) dev->srCache; ++ + if(dev->srCache) + memset(dev->srCache,0,srCacheBytes); +- ++ + for (i = 0; i < dev->nShortOpCaches && buf; i++) { + dev->srCache[i].object = NULL; + dev->srCache[i].lastUse = 0; + dev->srCache[i].dirty = 0; +- dev->srCache[i].data = buf = YMALLOC_DMA(dev->nDataBytesPerChunk); ++ dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk); + } + if(!buf) + init_failed = 1; +- ++ + dev->srLastUse = 0; + } + + dev->cacheHits = 0; +- ++ + if(!init_failed){ + dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); + if(!dev->gcCleanupList) +@@ -7240,7 +7397,7 @@ int yaffs_GutsInitialise(yaffs_Device * + } + if(!init_failed && !yaffs_InitialiseBlocks(dev)) + init_failed = 1; +- ++ + yaffs_InitialiseTnodes(dev); + yaffs_InitialiseObjects(dev); + +@@ -7252,18 +7409,19 @@ int yaffs_GutsInitialise(yaffs_Device * + /* Now scan the flash. */ + if (dev->isYaffs2) { + if(yaffs_CheckpointRestore(dev)) { ++ yaffs_CheckObjectDetailsLoaded(dev->rootDir); + T(YAFFS_TRACE_ALWAYS, + (TSTR("yaffs: restored from checkpoint" TENDSTR))); + } else { + +- /* Clean up the mess caused by an aborted checkpoint load +- * and scan backwards. ++ /* Clean up the mess caused by an aborted checkpoint load ++ * and scan backwards. + */ + yaffs_DeinitialiseBlocks(dev); + yaffs_DeinitialiseTnodes(dev); + yaffs_DeinitialiseObjects(dev); +- +- ++ ++ + dev->nErasedBlocks = 0; + dev->nFreeChunks = 0; + dev->allocationBlock = -1; +@@ -7275,7 +7433,7 @@ int yaffs_GutsInitialise(yaffs_Device * + + if(!init_failed && !yaffs_InitialiseBlocks(dev)) + init_failed = 1; +- ++ + yaffs_InitialiseTnodes(dev); + yaffs_InitialiseObjects(dev); + +@@ -7288,8 +7446,10 @@ int yaffs_GutsInitialise(yaffs_Device * + }else + if(!yaffs_Scan(dev)) + init_failed = 1; +- } + ++ yaffs_StripDeletedObjects(dev); ++ } ++ + if(init_failed){ + /* Clean up the mess */ + T(YAFFS_TRACE_TRACING, +@@ -7310,7 +7470,7 @@ int yaffs_GutsInitialise(yaffs_Device * + + yaffs_VerifyFreeChunks(dev); + yaffs_VerifyBlocks(dev); +- ++ + + T(YAFFS_TRACE_TRACING, + (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); +@@ -7345,7 +7505,11 @@ void yaffs_Deinitialise(yaffs_Device * d + YFREE(dev->tempBuffer[i].buffer); + } + ++ + dev->isMounted = 0; ++ ++ if(dev->deinitialiseNAND) ++ dev->deinitialiseNAND(dev); + } + + } +@@ -7394,7 +7558,7 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De + #endif + + nFree += dev->nDeletedFiles; +- ++ + /* Now count the number of dirty chunks in the cache and subtract those */ + + { +@@ -7408,12 +7572,12 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De + nFree -= nDirtyCacheChunks; + + nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); +- ++ + /* Now we figure out how much to reserve for the checkpoint and report that... */ +- blocksForCheckpoint = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; ++ blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; + if(blocksForCheckpoint < 0) + blocksForCheckpoint = 0; +- ++ + nFree -= (blocksForCheckpoint * dev->nChunksPerBlock); + + if (nFree < 0) +@@ -7429,10 +7593,10 @@ static void yaffs_VerifyFreeChunks(yaffs + { + int counted; + int difference; +- ++ + if(yaffs_SkipVerification(dev)) + return; +- ++ + counted = yaffs_CountFreeChunks(dev); + + difference = dev->nFreeChunks - counted; +@@ -7448,22 +7612,25 @@ static void yaffs_VerifyFreeChunks(yaffs + /*---------------------------------------- YAFFS test code ----------------------*/ + + #define yaffs_CheckStruct(structure,syze, name) \ ++ do { \ + if(sizeof(structure) != syze) \ + { \ + T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),\ + name,syze,sizeof(structure))); \ + return YAFFS_FAIL; \ +- } ++ } \ ++ } while(0) + + static int yaffs_CheckStructures(void) + { +-/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags") */ +-/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion") */ +-/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare") */ ++/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */ ++/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */ ++/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */ + #ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG +- yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode") ++ yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); ++#endif ++#ifndef CONFIG_YAFFS_WINCE ++ yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader"); + #endif +- yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader") +- + return YAFFS_OK; + } +--- a/fs/yaffs2/yaffs_mtdif1.c ++++ b/fs/yaffs2/yaffs_mtdif1.c +@@ -34,9 +34,9 @@ + #include "linux/mtd/mtd.h" + + /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) ++#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) + +-const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $"; ++const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.8 2008-07-23 03:35:12 charles Exp $"; + + #ifndef CONFIG_YAFFS_9BYTE_TAGS + # define YTAG1_SIZE 8 +@@ -189,7 +189,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y + ops.datbuf = data; + ops.oobbuf = (__u8 *)&pt1; + +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) ++#if (MTD_VERSION_CODE < MTD_VERSION(2,6,20)) + /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; + * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. + */ +@@ -288,7 +288,7 @@ int nandmtd1_MarkNANDBlockBad(struct yaf + int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; + int retval; + +- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo); ++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo); + + retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo); + return (retval) ? YAFFS_FAIL : YAFFS_OK; +@@ -323,10 +323,11 @@ static int nandmtd1_TestPrerequists(stru + * Always returns YAFFS_OK. + */ + int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, +- yaffs_BlockState * pState, int *pSequenceNumber) ++ yaffs_BlockState * pState, __u32 *pSequenceNumber) + { + struct mtd_info * mtd = dev->genericDevice; + int chunkNo = blockNo * dev->nChunksPerBlock; ++ loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk; + yaffs_ExtendedTags etags; + int state = YAFFS_BLOCK_STATE_DEAD; + int seqnum = 0; +@@ -340,11 +341,16 @@ int nandmtd1_QueryNANDBlock(struct yaffs + } + + retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); ++ etags.blockBad = (mtd->block_isbad)(mtd, addr); + if (etags.blockBad) { + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, +- "block %d is marked bad", blockNo); ++ "block %d is marked bad\n", blockNo); + state = YAFFS_BLOCK_STATE_DEAD; + } ++ else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) { ++ /* bad tags, need to look more closely */ ++ state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; ++ } + else if (etags.chunkUsed) { + state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; + seqnum = etags.sequenceNumber; +@@ -360,4 +366,4 @@ int nandmtd1_QueryNANDBlock(struct yaffs + return YAFFS_OK; + } + +-#endif /*KERNEL_VERSION*/ ++#endif /*MTD_VERSION*/ +--- a/fs/yaffs2/yaffs_mtdif2.c ++++ b/fs/yaffs2/yaffs_mtdif2.c +@@ -14,7 +14,7 @@ + /* mtd interface for YAFFS2 */ + + const char *yaffs_mtdif2_c_version = +- "$Id: yaffs_mtdif2.c,v 1.17 2007-02-14 01:09:06 wookey Exp $"; ++ "$Id: yaffs_mtdif2.c,v 1.22 2008-11-02 22:47:13 charles Exp $"; + + #include "yportenv.h" + +@@ -27,19 +27,23 @@ const char *yaffs_mtdif2_c_version = + + #include "yaffs_packedtags2.h" + ++/* NB For use with inband tags.... ++ * We assume that the data buffer is of size totalBytersPerChunk so that we can also ++ * use it to load the tags. ++ */ + int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, + const __u8 * data, + const yaffs_ExtendedTags * tags) + { + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) ++#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) + struct mtd_oob_ops ops; + #else + size_t dummy; + #endif + int retval = 0; + +- loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; ++ loff_t addr; + + yaffs_PackedTags2 pt; + +@@ -47,47 +51,42 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya + (TSTR + ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" + TENDSTR), chunkInNAND, data, tags)); ++ + +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +- if (tags) +- yaffs_PackTags2(&pt, tags); ++ addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; ++ ++ /* For yaffs2 writing there must be both data and tags. ++ * If we're using inband tags, then the tags are stuffed into ++ * the end of the data buffer. ++ */ ++ if(!data || !tags) ++ BUG(); ++ else if(dev->inbandTags){ ++ yaffs_PackedTags2TagsPart *pt2tp; ++ pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); ++ yaffs_PackTags2TagsPart(pt2tp,tags); ++ } + else +- BUG(); /* both tags and data should always be present */ +- +- if (data) { +- ops.mode = MTD_OOB_AUTO; +- ops.ooblen = sizeof(pt); +- ops.len = dev->nDataBytesPerChunk; +- ops.ooboffs = 0; +- ops.datbuf = (__u8 *)data; +- ops.oobbuf = (void *)&pt; +- retval = mtd->write_oob(mtd, addr, &ops); +- } else +- BUG(); /* both tags and data should always be present */ +-#else +- if (tags) { + yaffs_PackTags2(&pt, tags); +- } ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) ++ ops.mode = MTD_OOB_AUTO; ++ ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt); ++ ops.len = dev->totalBytesPerChunk; ++ ops.ooboffs = 0; ++ ops.datbuf = (__u8 *)data; ++ ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt; ++ retval = mtd->write_oob(mtd, addr, &ops); + +- if (data && tags) { +- if (dev->useNANDECC) +- retval = +- mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, +- &dummy, data, (__u8 *) & pt, NULL); +- else +- retval = +- mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, +- &dummy, data, (__u8 *) & pt, NULL); ++#else ++ if (!dev->inbandTags) { ++ retval = ++ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, (__u8 *) & pt, NULL); + } else { +- if (data) +- retval = +- mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, +- data); +- if (tags) +- retval = +- mtd->write_oob(mtd, addr, mtd->oobsize, &dummy, +- (__u8 *) & pt); +- ++ retval = ++ mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy, ++ data); + } + #endif + +@@ -101,13 +100,14 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y + __u8 * data, yaffs_ExtendedTags * tags) + { + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) ++#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) + struct mtd_oob_ops ops; + #endif + size_t dummy; + int retval = 0; ++ int localData = 0; + +- loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; ++ loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; + + yaffs_PackedTags2 pt; + +@@ -115,10 +115,21 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y + (TSTR + ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p" + TENDSTR), chunkInNAND, data, tags)); ++ ++ if(dev->inbandTags){ ++ ++ if(!data) { ++ localData = 1; ++ data = yaffs_GetTempBuffer(dev,__LINE__); ++ } ++ ++ ++ } ++ + + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +- if (data && !tags) +- retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, ++ if (dev->inbandTags || (data && !tags)) ++ retval = mtd->read(mtd, addr, dev->totalBytesPerChunk, + &dummy, data); + else if (tags) { + ops.mode = MTD_OOB_AUTO; +@@ -130,38 +141,43 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y + retval = mtd->read_oob(mtd, addr, &ops); + } + #else +- if (data && tags) { +- if (dev->useNANDECC) { +- retval = +- mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, +- &dummy, data, dev->spareBuffer, +- NULL); +- } else { +- retval = +- mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ if (!dev->inbandTags && data && tags) { ++ ++ retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, + &dummy, data, dev->spareBuffer, + NULL); +- } + } else { + if (data) + retval = + mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, + data); +- if (tags) ++ if (!dev->inbandTags && tags) + retval = + mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, + dev->spareBuffer); + } + #endif + +- memcpy(&pt, dev->spareBuffer, sizeof(pt)); + +- if (tags) +- yaffs_UnpackTags2(tags, &pt); ++ if(dev->inbandTags){ ++ if(tags){ ++ yaffs_PackedTags2TagsPart * pt2tp; ++ pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; ++ yaffs_UnpackTags2TagsPart(tags,pt2tp); ++ } ++ } ++ else { ++ if (tags){ ++ memcpy(&pt, dev->spareBuffer, sizeof(pt)); ++ yaffs_UnpackTags2(tags, &pt); ++ } ++ } + ++ if(localData) ++ yaffs_ReleaseTempBuffer(dev,data,__LINE__); ++ + if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) +- tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; +- ++ tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; + if (retval == 0) + return YAFFS_OK; + else +@@ -178,7 +194,7 @@ int nandmtd2_MarkNANDBlockBad(struct yaf + retval = + mtd->block_markbad(mtd, + blockNo * dev->nChunksPerBlock * +- dev->nDataBytesPerChunk); ++ dev->totalBytesPerChunk); + + if (retval == 0) + return YAFFS_OK; +@@ -188,7 +204,7 @@ int nandmtd2_MarkNANDBlockBad(struct yaf + } + + int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, +- yaffs_BlockState * state, int *sequenceNumber) ++ yaffs_BlockState * state, __u32 *sequenceNumber) + { + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); + int retval; +@@ -198,7 +214,7 @@ int nandmtd2_QueryNANDBlock(struct yaffs + retval = + mtd->block_isbad(mtd, + blockNo * dev->nChunksPerBlock * +- dev->nDataBytesPerChunk); ++ dev->totalBytesPerChunk); + + if (retval) { + T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR))); +--- a/fs/yaffs2/yaffs_guts.h ++++ b/fs/yaffs2/yaffs_guts.h +@@ -1,5 +1,5 @@ + /* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering +@@ -22,11 +22,11 @@ + #define YAFFS_OK 1 + #define YAFFS_FAIL 0 + +-/* Give us a Y=0x59, +- * Give us an A=0x41, +- * Give us an FF=0xFF ++/* Give us a Y=0x59, ++ * Give us an A=0x41, ++ * Give us an FF=0xFF + * Give us an S=0x53 +- * And what have we got... ++ * And what have we got... + */ + #define YAFFS_MAGIC 0x5941FF53 + +@@ -90,7 +90,7 @@ + + #define YAFFS_MAX_SHORT_OP_CACHES 20 + +-#define YAFFS_N_TEMP_BUFFERS 4 ++#define YAFFS_N_TEMP_BUFFERS 6 + + /* We limit the number attempts at sucessfully saving a chunk of data. + * Small-page devices have 32 pages per block; large-page devices have 64. +@@ -102,7 +102,7 @@ + * The range is limited slightly to help distinguish bad numbers from good. + * This also allows us to perhaps in the future use special numbers for + * special purposes. +- * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years, ++ * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years, + * and is a larger number than the lifetime of a 2GB device. + */ + #define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 +@@ -132,12 +132,12 @@ typedef struct { + + #ifndef CONFIG_YAFFS_NO_YAFFS1 + typedef struct { +- unsigned chunkId:20; +- unsigned serialNumber:2; +- unsigned byteCount:10; +- unsigned objectId:18; +- unsigned ecc:12; +- unsigned unusedStuff:2; ++ unsigned chunkId:20; ++ unsigned serialNumber:2; ++ unsigned byteCountLSB:10; ++ unsigned objectId:18; ++ unsigned ecc:12; ++ unsigned byteCountMSB:2; + + } yaffs_Tags; + +@@ -178,7 +178,7 @@ typedef struct { + + /* The following stuff only has meaning when we read */ + yaffs_ECCResult eccResult; +- unsigned blockBad; ++ unsigned blockBad; + + /* YAFFS 1 stuff */ + unsigned chunkDeleted; /* The chunk is marked deleted */ +@@ -244,29 +244,29 @@ typedef enum { + /* This block is empty */ + + YAFFS_BLOCK_STATE_ALLOCATING, +- /* This block is partially allocated. ++ /* This block is partially allocated. + * At least one page holds valid data. + * This is the one currently being used for page + * allocation. Should never be more than one of these + */ + +- YAFFS_BLOCK_STATE_FULL, ++ YAFFS_BLOCK_STATE_FULL, + /* All the pages in this block have been allocated. + */ + + YAFFS_BLOCK_STATE_DIRTY, +- /* All pages have been allocated and deleted. ++ /* All pages have been allocated and deleted. + * Erase me, reuse me. + */ + +- YAFFS_BLOCK_STATE_CHECKPOINT, ++ YAFFS_BLOCK_STATE_CHECKPOINT, + /* This block is assigned to holding checkpoint data. + */ + +- YAFFS_BLOCK_STATE_COLLECTING, ++ YAFFS_BLOCK_STATE_COLLECTING, + /* This block is being garbage collected */ + +- YAFFS_BLOCK_STATE_DEAD ++ YAFFS_BLOCK_STATE_DEAD + /* This block has failed and is not in use */ + } yaffs_BlockState; + +@@ -277,11 +277,11 @@ typedef struct { + + int softDeletions:10; /* number of soft deleted pages */ + int pagesInUse:10; /* number of pages in use */ +- yaffs_BlockState blockState:4; /* One of the above block states */ ++ unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */ + __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */ + /* and retire the block. */ + __u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */ +- __u32 gcPrioritise: 1; /* An ECC check or blank check has failed on this block. ++ __u32 gcPrioritise: 1; /* An ECC check or blank check has failed on this block. + It should be prioritised for GC */ + __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */ + +@@ -300,11 +300,11 @@ typedef struct { + + /* Apply to everything */ + int parentObjectId; +- __u16 sum__NoLongerUsed; /* checksum of name. No longer used */ +- YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; ++ __u16 sum__NoLongerUsed; /* checksum of name. No longer used */ ++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; + +- /* Thes following apply to directories, files, symlinks - not hard links */ +- __u32 yst_mode; /* protection */ ++ /* The following apply to directories, files, symlinks - not hard links */ ++ __u32 yst_mode; /* protection */ + + #ifdef CONFIG_YAFFS_WINCE + __u32 notForWinCE[5]; +@@ -331,11 +331,14 @@ typedef struct { + __u32 win_ctime[2]; + __u32 win_atime[2]; + __u32 win_mtime[2]; +- __u32 roomToGrow[4]; + #else +- __u32 roomToGrow[10]; ++ __u32 roomToGrow[6]; ++ + #endif ++ __u32 inbandShadowsObject; ++ __u32 inbandIsShrink; + ++ __u32 reservedSpace[2]; + int shadowsObject; /* This object header shadows the specified object if > 0 */ + + /* isShrink applies to object headers written when we shrink the file (ie resize) */ +@@ -381,7 +384,7 @@ typedef struct { + } yaffs_FileStructure; + + typedef struct { +- struct list_head children; /* list of child links */ ++ struct ylist_head children; /* list of child links */ + } yaffs_DirectoryStructure; + + typedef struct { +@@ -408,7 +411,7 @@ struct yaffs_ObjectStruct { + __u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */ + __u8 unlinkAllowed:1; + __u8 dirty:1; /* the object needs to be written to flash */ +- __u8 valid:1; /* When the file system is being loaded up, this ++ __u8 valid:1; /* When the file system is being loaded up, this + * object might be created before the data + * is available (ie. file data records appear before the header). + */ +@@ -417,33 +420,36 @@ struct yaffs_ObjectStruct { + __u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is + * still in the inode cache. Free of object is defered. + * until the inode is released. +- */ ++ */ ++ __u8 beingCreated:1; /* This object is still being created so skip some checks. */ + +- __u8 serial; /* serial number of chunk in NAND. Cached here */ +- __u16 sum; /* sum of the name to speed searching */ ++ __u8 serial; /* serial number of chunk in NAND. Cached here */ ++/* __u16 sum_prev; */ ++ __u16 sum; /* sum of the name to speed searching */ ++/* __u16 sum_trailer; */ + +- struct yaffs_DeviceStruct *myDev; /* The device I'm on */ ++ struct yaffs_DeviceStruct *myDev; /* The device I'm on */ + +- struct list_head hashLink; /* list of objects in this hash bucket */ ++ struct ylist_head hashLink; /* list of objects in this hash bucket */ + +- struct list_head hardLinks; /* all the equivalent hard linked objects */ ++ struct ylist_head hardLinks; /* all the equivalent hard linked objects */ + +- /* directory structure stuff */ +- /* also used for linking up the free list */ +- struct yaffs_ObjectStruct *parent; +- struct list_head siblings; ++ /* directory structure stuff */ ++ /* also used for linking up the free list */ ++ struct yaffs_ObjectStruct *parent; ++ struct ylist_head siblings; + + /* Where's my object header in NAND? */ +- int chunkId; ++ int hdrChunk; + + int nDataChunks; /* Number of data chunks attached to the file. */ + + __u32 objectId; /* the object id value */ + +- __u32 yst_mode; ++ __u32 yst_mode; + + #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM +- YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1]; ++ YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1]; + #endif + + #ifndef __KERNEL__ +@@ -485,31 +491,30 @@ struct yaffs_ObjectList_struct { + typedef struct yaffs_ObjectList_struct yaffs_ObjectList; + + typedef struct { +- struct list_head list; +- int count; ++ struct ylist_head list; ++ int count; + } yaffs_ObjectBucket; + + +-/* yaffs_CheckpointObject holds the definition of an object as dumped ++/* yaffs_CheckpointObject holds the definition of an object as dumped + * by checkpointing. + */ + + typedef struct { + int structType; +- __u32 objectId; ++ __u32 objectId; + __u32 parentId; +- int chunkId; +- ++ int hdrChunk; + yaffs_ObjectType variantType:3; +- __u8 deleted:1; +- __u8 softDeleted:1; +- __u8 unlinked:1; +- __u8 fake:1; ++ __u8 deleted:1; ++ __u8 softDeleted:1; ++ __u8 unlinked:1; ++ __u8 fake:1; + __u8 renameAllowed:1; + __u8 unlinkAllowed:1; +- __u8 serial; +- +- int nDataChunks; ++ __u8 serial; ++ ++ int nDataChunks; + __u32 fileSizeOrEquivalentObjectId; + + }yaffs_CheckpointObject; +@@ -528,25 +533,25 @@ typedef struct { + /*----------------- Device ---------------------------------*/ + + struct yaffs_DeviceStruct { +- struct list_head devList; +- const char *name; ++ struct ylist_head devList; ++ const char *name; + +- /* Entry parameters set up way early. Yaffs sets up the rest.*/ +- int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */ +- int nChunksPerBlock; /* does not need to be a power of 2 */ +- int nBytesPerSpare; /* spare area size */ +- int startBlock; /* Start block we're allowed to use */ +- int endBlock; /* End block we're allowed to use */ +- int nReservedBlocks; /* We want this tuneable so that we can reduce */ ++ /* Entry parameters set up way early. Yaffs sets up the rest.*/ ++ int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */ ++ int nChunksPerBlock; /* does not need to be a power of 2 */ ++ int spareBytesPerChunk;/* spare area size */ ++ int startBlock; /* Start block we're allowed to use */ ++ int endBlock; /* End block we're allowed to use */ ++ int nReservedBlocks; /* We want this tuneable so that we can reduce */ + /* reserved blocks on NOR and RAM. */ +- +- ++ ++ + /* Stuff used by the shared space checkpointing mechanism */ + /* If this value is zero, then this mechanism is disabled */ ++ ++// int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */ + +- int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */ +- +- ++ + + + int nShortOpCaches; /* If <= 0, then short op caching is disabled, else +@@ -561,7 +566,7 @@ struct yaffs_DeviceStruct { + * On an mtd this holds the mtd pointer. + */ + void *superBlock; +- ++ + /* NAND access functions (Must be set before calling YAFFS)*/ + + int (*writeChunkToNAND) (struct yaffs_DeviceStruct * dev, +@@ -570,12 +575,13 @@ struct yaffs_DeviceStruct { + int (*readChunkFromNAND) (struct yaffs_DeviceStruct * dev, + int chunkInNAND, __u8 * data, + yaffs_Spare * spare); +- int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev, +- int blockInNAND); +- int (*initialiseNAND) (struct yaffs_DeviceStruct * dev); ++ int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev, ++ int blockInNAND); ++ int (*initialiseNAND) (struct yaffs_DeviceStruct * dev); ++ int (*deinitialiseNAND) (struct yaffs_DeviceStruct * dev); + + #ifdef CONFIG_YAFFS_YAFFS2 +- int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev, ++ int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev, + int chunkInNAND, const __u8 * data, + const yaffs_ExtendedTags * tags); + int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev, +@@ -583,25 +589,27 @@ struct yaffs_DeviceStruct { + yaffs_ExtendedTags * tags); + int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo); + int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo, +- yaffs_BlockState * state, int *sequenceNumber); ++ yaffs_BlockState * state, __u32 *sequenceNumber); + #endif + + int isYaffs2; +- +- /* The removeObjectCallback function must be supplied by OS flavours that ++ ++ /* The removeObjectCallback function must be supplied by OS flavours that + * need it. The Linux kernel does not use this, but yaffs direct does use + * it to implement the faster readdir + */ + void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj); +- ++ + /* Callback to mark the superblock dirsty */ + void (*markSuperBlockDirty)(void * superblock); +- ++ + int wideTnodesDisabled; /* Set to disable wide tnodes */ +- ++ ++ YCHAR *pathDividers; /* String of legal path dividers */ ++ + + /* End of stuff that must be set before initialisation. */ +- ++ + /* Checkpoint control. Can be set before or after initialisation */ + __u8 skipCheckpointRead; + __u8 skipCheckpointWrite; +@@ -610,34 +618,32 @@ struct yaffs_DeviceStruct { + + __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */ + __u16 chunkGroupSize; /* == 2^^chunkGroupBits */ +- ++ + /* Stuff to support wide tnodes */ + __u32 tnodeWidth; + __u32 tnodeMask; +- +- /* Stuff to support various file offses to chunk/offset translations */ +- /* "Crumbs" for nDataBytesPerChunk not being a power of 2 */ +- __u32 crumbMask; +- __u32 crumbShift; +- __u32 crumbsPerChunk; +- +- /* Straight shifting for nDataBytesPerChunk being a power of 2 */ +- __u32 chunkShift; +- __u32 chunkMask; +- ++ ++ /* Stuff for figuring out file offset to chunk conversions */ ++ __u32 chunkShift; /* Shift value */ ++ __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */ ++ __u32 chunkMask; /* Mask to use for power-of-2 case */ ++ ++ /* Stuff to handle inband tags */ ++ int inbandTags; ++ __u32 totalBytesPerChunk; + + #ifdef __KERNEL__ + + struct semaphore sem; /* Semaphore for waiting on erasure.*/ + struct semaphore grossLock; /* Gross locking semaphore */ +- __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer ++ __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer + * at compile time so we have to allocate it. + */ + void (*putSuperFunc) (struct super_block * sb); + #endif + + int isMounted; +- ++ + int isCheckpointed; + + +@@ -646,7 +652,7 @@ struct yaffs_DeviceStruct { + int internalEndBlock; + int blockOffset; + int chunkOffset; +- ++ + + /* Runtime checkpointing stuff */ + int checkpointPageSequence; /* running sequence number of checkpoint pages */ +@@ -662,13 +668,15 @@ struct yaffs_DeviceStruct { + int checkpointMaxBlocks; + __u32 checkpointSum; + __u32 checkpointXor; +- ++ ++ int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */ ++ + /* Block Info */ + yaffs_BlockInfo *blockInfo; + __u8 *chunkBits; /* bitmap of chunks in use */ + unsigned blockInfoAlt:1; /* was allocated using alternative strategy */ + unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */ +- int chunkBitmapStride; /* Number of bytes of chunkBits per block. ++ int chunkBitmapStride; /* Number of bytes of chunkBits per block. + * Must be consistent with nChunksPerBlock. + */ + +@@ -684,10 +692,14 @@ struct yaffs_DeviceStruct { + yaffs_TnodeList *allocatedTnodeList; + + int isDoingGC; ++ int gcBlock; ++ int gcChunk; + + int nObjectsCreated; + yaffs_Object *freeObjects; + int nFreeObjects; ++ ++ int nHardLinks; + + yaffs_ObjectList *allocatedObjectList; + +@@ -716,7 +728,7 @@ struct yaffs_DeviceStruct { + int tagsEccUnfixed; + int nDeletions; + int nUnmarkedDeletions; +- ++ + int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ + + /* Special directories */ +@@ -727,7 +739,7 @@ struct yaffs_DeviceStruct { + * __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK]; + * yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK]; + */ +- ++ + int bufferedBlock; /* Which block is buffered here? */ + int doingBufferedBlockRewrite; + +@@ -744,9 +756,11 @@ struct yaffs_DeviceStruct { + int nUnlinkedFiles; /* Count of unlinked files. */ + int nBackgroundDeletions; /* Count of background deletions. */ + +- ++ ++ /* Temporary buffer management */ + yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS]; + int maxTemp; ++ int tempInUse; + int unmanagedTempAllocations; + int unmanagedTempDeallocations; + +@@ -758,17 +772,17 @@ struct yaffs_DeviceStruct { + + typedef struct yaffs_DeviceStruct yaffs_Device; + +-/* The static layout of bllock usage etc is stored in the super block header */ ++/* The static layout of block usage etc is stored in the super block header */ + typedef struct { + int StructType; +- int version; ++ int version; + int checkpointStartBlock; + int checkpointEndBlock; + int startBlock; + int endBlock; + int rfu[100]; + } yaffs_SuperBlockHeader; +- ++ + /* The CheckpointDevice structure holds the device information that changes at runtime and + * must be preserved over unmount/mount cycles. + */ +@@ -797,18 +811,6 @@ typedef struct { + __u32 head; + } yaffs_CheckpointValidity; + +-/* Function to manipulate block info */ +-static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk) +-{ +- if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { +- T(YAFFS_TRACE_ERROR, +- (TSTR +- ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR), +- blk)); +- YBUG(); +- } +- return &dev->blockInfo[blk - dev->internalStartBlock]; +-} + + /*----------------------- YAFFS Functions -----------------------*/ + +@@ -834,13 +836,13 @@ int yaffs_GetAttributes(yaffs_Object * o + + /* File operations */ + int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, loff_t offset, +- int nBytes); ++ int nBytes); + int yaffs_WriteDataToFile(yaffs_Object * obj, const __u8 * buffer, loff_t offset, +- int nBytes, int writeThrough); ++ int nBytes, int writeThrough); + int yaffs_ResizeFile(yaffs_Object * obj, loff_t newSize); + + yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name, +- __u32 mode, __u32 uid, __u32 gid); ++ __u32 mode, __u32 uid, __u32 gid); + int yaffs_FlushFile(yaffs_Object * obj, int updateTime); + + /* Flushing and checkpointing */ +@@ -899,4 +901,7 @@ void yaffs_DeleteChunk(yaffs_Device * de + int yaffs_CheckFF(__u8 * buffer, int nBytes); + void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi); + ++__u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo); ++void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, int lineNo); ++ + #endif +--- a/fs/yaffs2/moduleconfig.h ++++ b/fs/yaffs2/moduleconfig.h +@@ -54,11 +54,11 @@ that you need to continue to support. N + older-style format. + Note: Use of this option generally requires that MTD's oob layout be + adjusted to use the older-style format. See notes on tags formats and +-MTD versions. ++MTD versions in yaffs_mtdif1.c. + */ + /* Default: Not selected */ + /* Meaning: Use older-style on-NAND data format with pageStatus byte */ +-#define CONFIG_YAFFS_9BYTE_TAGS ++//#define CONFIG_YAFFS_9BYTE_TAGS + + #endif /* YAFFS_OUT_OF_TREE */ + +--- a/fs/yaffs2/yaffs_mtdif1.h ++++ b/fs/yaffs2/yaffs_mtdif1.h +@@ -23,6 +23,6 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y + int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); + + int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, +- yaffs_BlockState * state, int *sequenceNumber); ++ yaffs_BlockState * state, __u32 *sequenceNumber); + + #endif +--- a/fs/yaffs2/yaffs_mtdif2.h ++++ b/fs/yaffs2/yaffs_mtdif2.h +@@ -24,6 +24,6 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y + __u8 * data, yaffs_ExtendedTags * tags); + int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); + int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, +- yaffs_BlockState * state, int *sequenceNumber); ++ yaffs_BlockState * state, __u32 *sequenceNumber); + + #endif +--- a/fs/yaffs2/yaffs_checkptrw.c ++++ b/fs/yaffs2/yaffs_checkptrw.c +@@ -12,11 +12,11 @@ + */ + + const char *yaffs_checkptrw_c_version = +- "$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $"; ++ "$Id: yaffs_checkptrw.c,v 1.17 2008-08-12 22:51:57 charles Exp $"; + + + #include "yaffs_checkptrw.h" +- ++#include "yaffs_getblockinfo.h" + + static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) + { +@@ -142,7 +142,7 @@ int yaffs_CheckpointOpen(yaffs_Device *d + return 0; + + if(!dev->checkpointBuffer) +- dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk); ++ dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk); + if(!dev->checkpointBuffer) + return 0; + +@@ -324,6 +324,7 @@ int yaffs_CheckpointRead(yaffs_Device *d + &tags); + + if(tags.chunkId != (dev->checkpointPageSequence + 1) || ++ tags.eccResult > YAFFS_ECC_RESULT_FIXED || + tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA) + ok = 0; + +--- a/fs/yaffs2/yaffs_tagscompat.c ++++ b/fs/yaffs2/yaffs_tagscompat.c +@@ -14,6 +14,7 @@ + #include "yaffs_guts.h" + #include "yaffs_tagscompat.h" + #include "yaffs_ecc.h" ++#include "yaffs_getblockinfo.h" + + static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND); + #ifdef NOTYET +@@ -252,6 +253,9 @@ static int yaffs_ReadChunkFromNAND(struc + /* Must allocate enough memory for spare+2*sizeof(int) */ + /* for ecc results from device. */ + struct yaffs_NANDSpare nspare; ++ ++ memset(&nspare,0,sizeof(nspare)); ++ + retVal = + dev->readChunkFromNAND(dev, chunkInNAND, data, + (yaffs_Spare *) & nspare); +@@ -336,7 +340,7 @@ static void yaffs_HandleReadDataError(ya + int blockInNAND = chunkInNAND / dev->nChunksPerBlock; + + /* Mark the block for retirement */ +- yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; ++ yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1; + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND)); + +@@ -414,7 +418,16 @@ int yaffs_TagsCompatabilityWriteChunkWit + } else { + tags.objectId = eTags->objectId; + tags.chunkId = eTags->chunkId; +- tags.byteCount = eTags->byteCount; ++ ++ tags.byteCountLSB = eTags->byteCount & 0x3ff; ++ ++ if(dev->nDataBytesPerChunk >= 1024){ ++ tags.byteCountMSB = (eTags->byteCount >> 10) & 3; ++ } else { ++ tags.byteCountMSB = 3; ++ } ++ ++ + tags.serialNumber = eTags->serialNumber; + + if (!dev->useNANDECC && data) { +@@ -435,10 +448,10 @@ int yaffs_TagsCompatabilityReadChunkWith + + yaffs_Spare spare; + yaffs_Tags tags; +- yaffs_ECCResult eccResult; ++ yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN; + + static yaffs_Spare spareFF; +- static int init; ++ static int init = 0; + + if (!init) { + memset(&spareFF, 0xFF, sizeof(spareFF)); +@@ -466,7 +479,11 @@ int yaffs_TagsCompatabilityReadChunkWith + + eTags->objectId = tags.objectId; + eTags->chunkId = tags.chunkId; +- eTags->byteCount = tags.byteCount; ++ eTags->byteCount = tags.byteCountLSB; ++ ++ if(dev->nDataBytesPerChunk >= 1024) ++ eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10); ++ + eTags->serialNumber = tags.serialNumber; + } + } +@@ -497,9 +514,9 @@ int yaffs_TagsCompatabilityMarkNANDBlock + } + + int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, +- int blockNo, yaffs_BlockState * +- state, +- int *sequenceNumber) ++ int blockNo, ++ yaffs_BlockState *state, ++ __u32 *sequenceNumber) + { + + yaffs_Spare spare0, spare1; +--- a/fs/yaffs2/yaffs_mtdif.c ++++ b/fs/yaffs2/yaffs_mtdif.c +@@ -12,7 +12,7 @@ + */ + + const char *yaffs_mtdif_c_version = +- "$Id: yaffs_mtdif.c,v 1.19 2007-02-14 01:09:06 wookey Exp $"; ++ "$Id: yaffs_mtdif.c,v 1.21 2007-12-13 15:35:18 wookey Exp $"; + + #include "yportenv.h" + +@@ -24,7 +24,7 @@ const char *yaffs_mtdif_c_version = + #include "linux/time.h" + #include "linux/mtd/nand.h" + +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) ++#if (MTD_VERSION_CODE < MTD_VERSION(2,6,18)) + static struct nand_oobinfo yaffs_oobinfo = { + .useecc = 1, + .eccbytes = 6, +@@ -36,7 +36,7 @@ static struct nand_oobinfo yaffs_noeccin + }; + #endif + +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) ++#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) + static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob) + { + oob[0] = spare->tagByte0; +@@ -75,14 +75,14 @@ int nandmtd_WriteChunkToNAND(yaffs_Devic + const __u8 * data, const yaffs_Spare * spare) + { + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) ++#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) + struct mtd_oob_ops ops; + #endif + size_t dummy; + int retval = 0; + + loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) ++#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) + __u8 spareAsBytes[8]; /* OOB */ + + if (data && !spare) +@@ -139,14 +139,14 @@ int nandmtd_ReadChunkFromNAND(yaffs_Devi + yaffs_Spare * spare) + { + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) ++#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) + struct mtd_oob_ops ops; + #endif + size_t dummy; + int retval = 0; + + loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) ++#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) + __u8 spareAsBytes[8]; /* OOB */ + + if (data && !spare) +--- a/fs/yaffs2/yaffs_nandemul2k.h ++++ b/fs/yaffs2/yaffs_nandemul2k.h +@@ -22,13 +22,13 @@ + + int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, + int chunkInNAND, const __u8 * data, +- yaffs_ExtendedTags * tags); ++ const yaffs_ExtendedTags * tags); + int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev, + int chunkInNAND, __u8 * data, + yaffs_ExtendedTags * tags); + int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); + int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, +- yaffs_BlockState * state, int *sequenceNumber); ++ yaffs_BlockState * state, __u32 *sequenceNumber); + int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, + int blockInNAND); + int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev); diff --git a/target/linux/generic-2.6/patches-2.6.28/512-yaffs_2.6.25_fix.patch b/target/linux/generic-2.6/patches-2.6.28/512-yaffs_2.6.25_fix.patch deleted file mode 100644 index c127336346..0000000000 --- a/target/linux/generic-2.6/patches-2.6.28/512-yaffs_2.6.25_fix.patch +++ /dev/null @@ -1,92 +0,0 @@ ---- a/fs/yaffs2/yaffs_fs.c -+++ b/fs/yaffs2/yaffs_fs.c -@@ -181,7 +181,13 @@ static int yaffs_statfs(struct super_blo - #else - static int yaffs_statfs(struct super_block *sb, struct statfs *buf); - #endif -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)) -+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino); -+#else - static void yaffs_read_inode(struct inode *inode); -+#endif -+ - - static void yaffs_put_inode(struct inode *inode); - static void yaffs_delete_inode(struct inode *); -@@ -284,7 +290,9 @@ static struct file_operations yaffs_dir_ - - static struct super_operations yaffs_super_ops = { - .statfs = yaffs_statfs, -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)) - .read_inode = yaffs_read_inode, -+#endif - .put_inode = yaffs_put_inode, - .put_super = yaffs_put_super, - .delete_inode = yaffs_delete_inode, -@@ -844,11 +852,17 @@ struct inode *yaffs_get_inode(struct sup - T(YAFFS_TRACE_OS, - (KERN_DEBUG "yaffs_get_inode for object %d\n", obj->objectId)); - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)) -+ inode = yaffs_iget(sb, obj->objectId); -+ if (IS_ERR(inode)) -+ return NULL; -+#else - inode = iget(sb, obj->objectId); - - /* 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! */ -+#endif - - return inode; - } -@@ -1427,6 +1441,39 @@ static int yaffs_sync_fs(struct super_bl - } - - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)) -+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) -+{ -+ yaffs_Object *obj; -+ yaffs_Device *dev = yaffs_SuperToDevice(sb); -+ struct inode *inode; -+ -+ T(YAFFS_TRACE_OS, -+ (KERN_DEBUG "yaffs_iget for %lu\n", ino)); -+ -+ inode = iget_locked(sb, ino); -+ if (!inode) -+ return ERR_PTR(-ENOMEM); -+ if (!(inode->i_state & I_NEW)) -+ return inode; -+ -+ /* NB This is called as a side effect of other functions, but -+ * we had to release the lock to prevent deadlocks, so -+ * need to lock again. -+ */ -+ -+ yaffs_GrossLock(dev); -+ -+ obj = yaffs_FindObjectByNumber(dev, inode->i_ino); -+ -+ yaffs_FillInodeFromObject(inode, obj); -+ -+ yaffs_GrossUnlock(dev); -+ -+ unlock_new_inode(inode); -+ return inode; -+} -+#else - static void yaffs_read_inode(struct inode *inode) - { - /* NB This is called as a side effect of other functions, but -@@ -1448,6 +1495,7 @@ static void yaffs_read_inode(struct inod - - yaffs_GrossUnlock(dev); - } -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)) */ - - static LIST_HEAD(yaffs_dev_list); - diff --git a/target/linux/generic-2.6/patches-2.6.28/513-yaffs_2.6.26_fix.patch b/target/linux/generic-2.6/patches-2.6.28/513-yaffs_2.6.26_fix.patch deleted file mode 100644 index 11594547d1..0000000000 --- a/target/linux/generic-2.6/patches-2.6.28/513-yaffs_2.6.26_fix.patch +++ /dev/null @@ -1,69 +0,0 @@ ---- a/fs/yaffs2/yaffs_fs.c -+++ b/fs/yaffs2/yaffs_fs.c -@@ -76,6 +76,12 @@ extern const char *yaffs_guts_c_version; - - #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 -@@ -189,7 +195,9 @@ static void yaffs_read_inode(struct inod - #endif - - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) - static void yaffs_put_inode(struct inode *inode); -+#endif - static void yaffs_delete_inode(struct inode *); - static void yaffs_clear_inode(struct inode *); - -@@ -293,7 +301,9 @@ static struct super_operations yaffs_sup - #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)) - .read_inode = yaffs_read_inode, - #endif -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) - .put_inode = yaffs_put_inode, -+#endif - .put_super = yaffs_put_super, - .delete_inode = yaffs_delete_inode, - .clear_inode = yaffs_clear_inode, -@@ -437,6 +447,7 @@ static struct dentry *yaffs_lookup(struc - - } - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) - /* For now put inode is just for debugging - * Put inode is called when the inode **structure** is put. - */ -@@ -447,6 +458,7 @@ static void yaffs_put_inode(struct inode - 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) -@@ -2279,7 +2291,7 @@ static int __init init_yaffs_fs(void) - /* Install the proc_fs entry */ - my_proc_entry = create_proc_entry("yaffs", - S_IRUGO | S_IFREG, -- &proc_root); -+ YPROC_ROOT); - - if (my_proc_entry) { - my_proc_entry->write_proc = yaffs_proc_write; -@@ -2325,7 +2337,7 @@ static void __exit exit_yaffs_fs(void) - T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__ - " removing. \n")); - -- remove_proc_entry("yaffs", &proc_root); -+ remove_proc_entry("yaffs", YPROC_ROOT); - - fsinst = fs_to_install; - diff --git a/target/linux/generic-2.6/patches-2.6.28/514-yaffs_2.6.28_fixes.patch b/target/linux/generic-2.6/patches-2.6.28/514-yaffs_2.6.28_fixes.patch deleted file mode 100644 index 012ba04f07..0000000000 --- a/target/linux/generic-2.6/patches-2.6.28/514-yaffs_2.6.28_fixes.patch +++ /dev/null @@ -1,120 +0,0 @@ ---- a/fs/yaffs2/yaffs_fs.c -+++ b/fs/yaffs2/yaffs_fs.c -@@ -207,10 +207,20 @@ static int yaffs_writepage(struct page * - #else - static int yaffs_writepage(struct page *page); - #endif -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) -+static int yaffs_write_begin(struct file *f, struct address_space *mapping, -+ loff_t pos, unsigned len, unsigned flags, -+ struct page **pagep, void **fsdata); -+static int yaffs_write_end(struct file *f, struct address_space *mapping, -+ loff_t pos, unsigned len, unsigned copied, -+ struct page *pg, void *fsdata); -+#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); -@@ -223,8 +233,13 @@ static int yaffs_follow_link(struct dent - static struct address_space_operations yaffs_file_address_operations = { - .readpage = yaffs_readpage, - .writepage = yaffs_writepage, -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) -+ .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)) -@@ -687,6 +702,74 @@ static int yaffs_writepage(struct page * - return (nWritten == nBytes) ? 0 : -ENOSPC; - } - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) -+static int yaffs_write_begin(struct file *f, struct address_space *mapping, -+ loff_t pos, unsigned len, unsigned flags, -+ struct page **pagep, void **fsdata) -+{ -+ struct page *pg; -+ pgoff_t index = pos >> PAGE_CACHE_SHIFT; -+ int ret = 0; -+ -+ pg = __grab_cache_page(mapping, index); -+ if (!pg) -+ return -ENOMEM; -+ -+ *pagep = pg; -+ -+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_begin\n")); -+ if (!Page_Uptodate(pg)) { -+ ret = yaffs_readpage_nolock(f, pg); -+ if (ret) -+ goto err_unlock; -+ } -+ -+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_begin\n")); -+ return 0; -+ -+ err_unlock: -+ unlock_page(pg); -+ page_cache_release(pg); -+ return ret; -+} -+ -+static int yaffs_write_end(struct file *f, struct address_space *mapping, -+ loff_t pos, unsigned len, unsigned copied, -+ struct page *pg, void *fsdata) -+{ -+ void *addr = page_address(pg) + (pos & (PAGE_CACHE_SIZE - 1)); -+ loff_t pos2; -+ int nBytes = copied; -+ int nWritten; -+ -+ T(YAFFS_TRACE_OS, -+ (KERN_DEBUG "yaffs_write_end addr %x pos %x nBytes %d\n", (unsigned)addr, -+ (unsigned)pos, nBytes)); -+ -+ pos2 = pos; -+ nWritten = yaffs_file_write(f, addr, nBytes, &pos2); -+ -+ if (nWritten != nBytes) { -+ T(YAFFS_TRACE_OS, -+ (KERN_DEBUG -+ "yaffs_write_end not same size nWritten %d nBytes %d\n", -+ nWritten, nBytes)); -+ SetPageError(pg); -+ ClearPageUptodate(pg); -+ } else { -+ SetPageUptodate(pg); -+ } -+ -+ T(YAFFS_TRACE_OS, -+ (KERN_DEBUG "yaffs_write_end returning %d\n", -+ nWritten == nBytes ? nWritten : 0)); -+ -+ unlock_page(pg); -+ page_cache_release(pg); -+ -+ return (nWritten == nBytes) ? nWritten : 0; -+} -+#else - static int yaffs_prepare_write(struct file *f, struct page *pg, - unsigned offset, unsigned to) - { -@@ -735,6 +818,7 @@ static int yaffs_commit_write(struct fil - return nWritten == nBytes ? 0 : nWritten; - - } -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) */ - - static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj) - {