From e97d7c88a7566b17912d82e115f02e6fab11699e Mon Sep 17 00:00:00 2001 From: rajkosto Date: Wed, 3 Nov 2010 22:24:52 +0100 Subject: [PATCH 1/2] go back to using google's version of yaffs for higher stability --- arch/arm/configs/htcleo_defconfig | 7 +- fs/yaffs2/Kconfig | 58 +- fs/yaffs2/Makefile | 11 +- fs/yaffs2/devextras.h | 101 +- fs/yaffs2/moduleconfig.h | 35 +- fs/yaffs2/yaffs_allocator.c | 409 -- fs/yaffs2/yaffs_allocator.h | 30 - fs/yaffs2/yaffs_bitmap.c | 105 - fs/yaffs2/yaffs_bitmap.h | 31 - fs/yaffs2/yaffs_checkptrw.c | 87 +- fs/yaffs2/yaffs_checkptrw.h | 15 +- fs/yaffs2/yaffs_ecc.c | 5 +- fs/yaffs2/yaffs_ecc.h | 2 +- fs/yaffs2/{yaffs_vfs_glue.c => yaffs_fs.c} | 1678 ++------ fs/yaffs2/yaffs_getblockinfo.h | 3 +- fs/yaffs2/yaffs_guts.c | 4492 +++++++++++++++----- fs/yaffs2/yaffs_guts.h | 325 +- fs/yaffs2/yaffs_linux.h | 43 - fs/yaffs2/yaffs_linux_allocator.c | 200 - fs/yaffs2/yaffs_list.h | 127 - fs/yaffs2/yaffs_mtdif.c | 199 +- fs/yaffs2/yaffs_mtdif.h | 7 +- fs/yaffs2/yaffs_mtdif1.c | 42 +- fs/yaffs2/yaffs_mtdif1.h | 2 +- fs/yaffs2/yaffs_mtdif2.c | 82 +- fs/yaffs2/yaffs_mtdif2.h | 2 +- fs/yaffs2/yaffs_nameval.c | 197 - fs/yaffs2/yaffs_nameval.h | 25 - fs/yaffs2/yaffs_nand.c | 30 +- fs/yaffs2/yaffs_nand.h | 2 +- fs/yaffs2/yaffs_nandemul2k.h | 2 +- fs/yaffs2/yaffs_packedtags1.c | 2 +- fs/yaffs2/yaffs_packedtags1.h | 2 +- fs/yaffs2/yaffs_packedtags2.c | 47 +- fs/yaffs2/yaffs_packedtags2.h | 6 +- fs/yaffs2/yaffs_qsort.h | 13 +- fs/yaffs2/yaffs_tagscompat.c | 31 +- fs/yaffs2/yaffs_tagscompat.h | 2 +- fs/yaffs2/yaffs_tagsvalidity.c | 2 +- fs/yaffs2/yaffs_tagsvalidity.h | 2 +- fs/yaffs2/yaffs_trace.h | 60 - fs/yaffs2/yaffs_verify.c | 626 --- fs/yaffs2/yaffs_verify.h | 39 - fs/yaffs2/yaffs_yaffs1.c | 465 -- fs/yaffs2/yaffs_yaffs1.h | 22 - fs/yaffs2/yaffs_yaffs2.c | 1540 ------- fs/yaffs2/yaffs_yaffs2.h | 36 - fs/yaffs2/yaffsinterface.h | 2 +- fs/yaffs2/yportenv.h | 226 +- 49 files changed, 4477 insertions(+), 7000 deletions(-) delete mode 100644 fs/yaffs2/yaffs_allocator.c delete mode 100644 fs/yaffs2/yaffs_allocator.h delete mode 100644 fs/yaffs2/yaffs_bitmap.c delete mode 100644 fs/yaffs2/yaffs_bitmap.h rename fs/yaffs2/{yaffs_vfs_glue.c => yaffs_fs.c} (59%) delete mode 100644 fs/yaffs2/yaffs_linux.h delete mode 100644 fs/yaffs2/yaffs_linux_allocator.c delete mode 100644 fs/yaffs2/yaffs_list.h delete mode 100644 fs/yaffs2/yaffs_nameval.c delete mode 100644 fs/yaffs2/yaffs_nameval.h delete mode 100644 fs/yaffs2/yaffs_trace.h delete mode 100644 fs/yaffs2/yaffs_verify.c delete mode 100644 fs/yaffs2/yaffs_verify.h delete mode 100644 fs/yaffs2/yaffs_yaffs1.c delete mode 100644 fs/yaffs2/yaffs_yaffs1.h delete mode 100644 fs/yaffs2/yaffs_yaffs2.c delete mode 100644 fs/yaffs2/yaffs_yaffs2.h diff --git a/arch/arm/configs/htcleo_defconfig b/arch/arm/configs/htcleo_defconfig index 85503ae6..6bf3ed03 100644 --- a/arch/arm/configs/htcleo_defconfig +++ b/arch/arm/configs/htcleo_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.32.15 -# Fri Oct 29 13:59:28 2010 +# Wed Nov 3 19:18:32 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -1688,14 +1688,11 @@ CONFIG_YAFFS_YAFFS1=y # CONFIG_YAFFS_DOES_ECC is not set CONFIG_YAFFS_YAFFS2=y CONFIG_YAFFS_AUTO_YAFFS2=y -CONFIG_YAFFS_DISABLE_TAGS_ECC=y +# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set # CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set # CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y # CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set -CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING=y -# CONFIG_YAFFS_DISABLE_BACKGROUND is not set -CONFIG_YAFFS_XATTR=y # CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set CONFIG_SQUASHFS=y diff --git a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig index 7b3988c3..85844504 100644 --- a/fs/yaffs2/Kconfig +++ b/fs/yaffs2/Kconfig @@ -90,15 +90,23 @@ config YAFFS_AUTO_YAFFS2 If unsure, say Y. -config YAFFS_DISABLE_TAGS_ECC - bool "Disable YAFFS from doing ECC on tags by default" - depends on YAFFS_FS && YAFFS_YAFFS2 +config YAFFS_DISABLE_LAZY_LOAD + bool "Disable lazy loading" + depends on YAFFS_YAFFS2 default n help - This defaults Yaffs to using its own ECC calculations on tags instead of - just relying on the MTD. - This behavior can also be overridden with tags_ecc_on and - tags_ecc_off mount options. + "Lazy loading" defers loading file details until they are + required. This saves mount time, but makes the first look-up + a bit longer. + + Lazy loading will only happen if enabled by this option being 'n' + and if the appropriate tags are available, else yaffs2 will + automatically fall back to immediate loading and do the right + thing. + + Lazy laoding will be required by checkpointing. + + Setting this to 'y' will disable lazy loading. If unsure, say N. @@ -148,43 +156,9 @@ config YAFFS_SHORT_NAMES_IN_RAM If unsure, say Y. config YAFFS_EMPTY_LOST_AND_FOUND - bool "Empty lost and found on boot" + bool "Empty lost and found on mount" depends on YAFFS_FS default n help If this is enabled then the contents of lost and found is automatically dumped at mount. - - If unsure, say N. - -config YAFFS_DISABLE_BLOCK_REFRESHING - bool "Disable yaffs2 block refreshing" - depends on YAFFS_FS - default n - help - If this is set, then block refreshing is disabled. - Block refreshing infrequently refreshes the oldest block in - a yaffs2 file system. This mechanism helps to refresh flash to - mitigate against data loss. This is particularly useful for MLC. - - If unsure, say N. - -config YAFFS_DISABLE_BACKGROUND - bool "Disable yaffs2 background processing" - depends on YAFFS_FS - default n - help - If this is set, then background processing is disabled. - Background processing makes many foreground activities faster. - - If unsure, say N. - -config YAFFS_XATTR - bool "Enable yaffs2 xattr support" - depends on YAFFS_FS - default y - help - If this is set then yaffs2 will provide xattr support. - If unsure, say Y. - - diff --git a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile index fbdbd4a0..382ee614 100644 --- a/fs/yaffs2/Makefile +++ b/fs/yaffs2/Makefile @@ -4,14 +4,7 @@ obj-$(CONFIG_YAFFS_FS) += yaffs.o -yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o -yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o +yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o -yaffs-y += yaffs_nameval.o -yaffs-y += yaffs_allocator.o -yaffs-y += yaffs_yaffs1.o -yaffs-y += yaffs_yaffs2.o -yaffs-y += yaffs_bitmap.o -yaffs-y += yaffs_verify.o - diff --git a/fs/yaffs2/devextras.h b/fs/yaffs2/devextras.h index ce30c820..7df46dc2 100644 --- a/fs/yaffs2/devextras.h +++ b/fs/yaffs2/devextras.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -24,8 +24,6 @@ #define __EXTRAS_H__ -#include "yportenv.h" - #if !(defined __KERNEL__) /* Definition of types */ @@ -35,6 +33,103 @@ typedef unsigned __u32; #endif +/* + * This is a simple doubly linked list implementation that matches the + * way the Linux kernel doubly linked list implementation works. + */ + +struct ylist_head { + struct ylist_head *next; /* next in chain */ + struct ylist_head *prev; /* previous in chain */ +}; + + +/* Initialise a static list */ +#define YLIST_HEAD(name) \ +struct ylist_head name = { &(name), &(name)} + + + +/* Initialise a list head to an empty list */ +#define YINIT_LIST_HEAD(p) \ +do { \ + (p)->next = (p);\ + (p)->prev = (p); \ +} while (0) + + +/* Add an element to a list */ +static __inline__ void ylist_add(struct ylist_head *newEntry, + struct ylist_head *list) +{ + struct ylist_head *listNext = list->next; + + list->next = newEntry; + newEntry->prev = list; + newEntry->next = listNext; + listNext->prev = newEntry; + +} + +static __inline__ void ylist_add_tail(struct ylist_head *newEntry, + struct ylist_head *list) +{ + struct ylist_head *listPrev = list->prev; + + list->prev = newEntry; + newEntry->next = list; + newEntry->prev = listPrev; + listPrev->next = newEntry; + +} + + +/* Take an element out of its current list, with or without + * reinitialising the links.of the entry*/ +static __inline__ void ylist_del(struct ylist_head *entry) +{ + struct ylist_head *listNext = entry->next; + struct ylist_head *listPrev = entry->prev; + + listNext->prev = listPrev; + listPrev->next = listNext; + +} + +static __inline__ void ylist_del_init(struct ylist_head *entry) +{ + ylist_del(entry); + entry->next = entry->prev = entry; +} + + +/* Test if the list is empty */ +static __inline__ int ylist_empty(struct ylist_head *entry) +{ + return (entry->next == entry); +} + + +/* ylist_entry takes a pointer to a list entry and offsets it to that + * we can find a pointer to the object it is embedded in. + */ + + +#define ylist_entry(entry, type, member) \ + ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member))) + + +/* ylist_for_each and list_for_each_safe iterate over lists. + * ylist_for_each_safe uses temporary storage to make the list delete safe + */ + +#define ylist_for_each(itervar, list) \ + for (itervar = (list)->next; itervar != (list); itervar = itervar->next) + +#define ylist_for_each_safe(itervar, saveVar, list) \ + for (itervar = (list)->next, saveVar = (list)->next->next; \ + itervar != (list); itervar = saveVar, saveVar = saveVar->next) + #if !(defined __KERNEL__) diff --git a/fs/yaffs2/moduleconfig.h b/fs/yaffs2/moduleconfig.h index 43f11447..a344baf3 100644 --- a/fs/yaffs2/moduleconfig.h +++ b/fs/yaffs2/moduleconfig.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Martin Fouts @@ -29,43 +29,22 @@ /* Meaning: Yaffs does its own ECC, rather than using MTD ECC */ /* #define CONFIG_YAFFS_DOES_ECC */ -/* Default: Selected */ -/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */ -#define CONFIG_YAFFS_DOES_TAGS_ECC - /* Default: Not selected */ /* Meaning: ECC byte order is 'wrong'. Only meaningful if */ /* CONFIG_YAFFS_DOES_ECC is set */ /* #define CONFIG_YAFFS_ECC_WRONG_ORDER */ -/* Default: Not selected */ -/* Meaning: Always test whether chunks are erased before writing to them. - Use during mtd debugging and init. */ -/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */ - -/* Default: Not Selected */ -/* Meaning: At mount automatically empty all files from lost and found. */ -/* This is done to fix an old problem where rmdir was not checking for an */ -/* empty directory. This can also be achieved with a mount option. */ -#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND +/* Default: Selected */ +/* Meaning: Disables testing whether chunks are erased before writing to them*/ +#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK /* Default: Selected */ /* Meaning: Cache short names, taking more RAM, but faster look-ups */ #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM -/* Default: Unselected */ -/* Meaning: Select to disable block refreshing. */ -/* Block Refreshing periodically rewrites the oldest block. */ -/* #define CONFIG_DISABLE_BLOCK_REFRESHING */ - -/* Default: Unselected */ -/* Meaning: Select to disable background processing */ -/* #define CONFIG_DISABLE_BACKGROUND */ - - -/* Default: Selected */ -/* Meaning: Enable XATTR support */ -#define CONFIG_YAFFS_XATTR +/* Default: 10 */ +/* Meaning: set the count of blocks to reserve for checkpointing */ +#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 /* Older-style on-NAND data format has a "pageStatus" byte to record diff --git a/fs/yaffs2/yaffs_allocator.c b/fs/yaffs2/yaffs_allocator.c deleted file mode 100644 index ab44bc7d..00000000 --- a/fs/yaffs2/yaffs_allocator.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2.1 as - * published by the Free Software Foundation. - * - * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. - */ - - -#include "yaffs_allocator.h" -#include "yaffs_guts.h" -#include "yaffs_trace.h" -#include "yportenv.h" - -#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR - -void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev) -{ - dev = dev; -} - -void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev) -{ - dev = dev; -} - -yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev) -{ - return (yaffs_Tnode *)YMALLOC(dev->tnodeSize); -} - -void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn) -{ - dev = dev; - YFREE(tn); -} - -void yaffs_InitialiseRawObjects(yaffs_Device *dev) -{ - dev = dev; -} - -void yaffs_DeinitialiseRawObjects(yaffs_Device *dev) -{ - dev = dev; -} - -yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev) -{ - dev = dev; - return (yaffs_Object *) YMALLOC(sizeof(yaffs_Object)); -} - - -void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj) -{ - - dev = dev; - YFREE(obj); -} - -#else - -struct yaffs_TnodeList_struct { - struct yaffs_TnodeList_struct *next; - yaffs_Tnode *tnodes; -}; - -typedef struct yaffs_TnodeList_struct yaffs_TnodeList; - -struct yaffs_ObjectList_struct { - yaffs_Object *objects; - struct yaffs_ObjectList_struct *next; -}; - -typedef struct yaffs_ObjectList_struct yaffs_ObjectList; - - -struct yaffs_AllocatorStruct { - int nTnodesCreated; - yaffs_Tnode *freeTnodes; - int nFreeTnodes; - yaffs_TnodeList *allocatedTnodeList; - - int nObjectsCreated; - yaffs_Object *freeObjects; - int nFreeObjects; - - yaffs_ObjectList *allocatedObjectList; -}; - -typedef struct yaffs_AllocatorStruct yaffs_Allocator; - - -static void yaffs_DeinitialiseRawTnodes(yaffs_Device *dev) -{ - - yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; - - yaffs_TnodeList *tmp; - - if(!allocator){ - YBUG(); - return; - } - - while (allocator->allocatedTnodeList) { - tmp = allocator->allocatedTnodeList->next; - - YFREE(allocator->allocatedTnodeList->tnodes); - YFREE(allocator->allocatedTnodeList); - allocator->allocatedTnodeList = tmp; - - } - - allocator->freeTnodes = NULL; - allocator->nFreeTnodes = 0; - allocator->nTnodesCreated = 0; -} - -static void yaffs_InitialiseRawTnodes(yaffs_Device *dev) -{ - yaffs_Allocator *allocator = dev->allocator; - - if(allocator){ - allocator->allocatedTnodeList = NULL; - allocator->freeTnodes = NULL; - allocator->nFreeTnodes = 0; - allocator->nTnodesCreated = 0; - } else - YBUG(); -} - -static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes) -{ - yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; - int i; - yaffs_Tnode *newTnodes; - __u8 *mem; - yaffs_Tnode *curr; - yaffs_Tnode *next; - yaffs_TnodeList *tnl; - - if(!allocator){ - YBUG(); - return YAFFS_FAIL; - } - - if (nTnodes < 1) - return YAFFS_OK; - - - /* make these things */ - - newTnodes = YMALLOC(nTnodes * dev->tnodeSize); - mem = (__u8 *)newTnodes; - - if (!newTnodes) { - T(YAFFS_TRACE_ERROR, - (TSTR("yaffs: Could not allocate Tnodes" TENDSTR))); - return YAFFS_FAIL; - } - - /* New hookup for wide tnodes */ - for (i = 0; i < nTnodes - 1; i++) { - curr = (yaffs_Tnode *) &mem[i * dev->tnodeSize]; - next = (yaffs_Tnode *) &mem[(i+1) * dev->tnodeSize]; - curr->internal[0] = next; - } - - curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * dev->tnodeSize]; - curr->internal[0] = allocator->freeTnodes; - allocator->freeTnodes = (yaffs_Tnode *)mem; - - allocator->nFreeTnodes += nTnodes; - allocator->nTnodesCreated += nTnodes; - - /* Now add this bunch of tnodes to a list for freeing up. - * NB If we can't add this to the management list it isn't fatal - * but it just means we can't free this bunch of tnodes later. - */ - - tnl = YMALLOC(sizeof(yaffs_TnodeList)); - if (!tnl) { - T(YAFFS_TRACE_ERROR, - (TSTR - ("yaffs: Could not add tnodes to management list" TENDSTR))); - return YAFFS_FAIL; - } else { - tnl->tnodes = newTnodes; - tnl->next = allocator->allocatedTnodeList; - allocator->allocatedTnodeList = tnl; - } - - T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR))); - - return YAFFS_OK; -} - - -yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev) -{ - yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; - yaffs_Tnode *tn = NULL; - - if(!allocator){ - YBUG(); - return NULL; - } - - /* If there are none left make more */ - if (!allocator->freeTnodes) - yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES); - - if (allocator->freeTnodes) { - tn = allocator->freeTnodes; - allocator->freeTnodes = allocator->freeTnodes->internal[0]; - allocator->nFreeTnodes--; - } - - return tn; -} - -/* FreeTnode frees up a tnode and puts it back on the free list */ -void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn) -{ - yaffs_Allocator *allocator = dev->allocator; - - if(!allocator){ - YBUG(); - return; - } - - if (tn) { - tn->internal[0] = allocator->freeTnodes; - allocator->freeTnodes = tn; - allocator->nFreeTnodes++; - } - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ -} - - - -static void yaffs_InitialiseRawObjects(yaffs_Device *dev) -{ - yaffs_Allocator *allocator = dev->allocator; - - if(allocator) { - allocator->allocatedObjectList = NULL; - allocator->freeObjects = NULL; - allocator->nFreeObjects = 0; - } else - YBUG(); -} - -static void yaffs_DeinitialiseRawObjects(yaffs_Device *dev) -{ - yaffs_Allocator *allocator = dev->allocator; - yaffs_ObjectList *tmp; - - if(!allocator){ - YBUG(); - return; - } - - while (allocator->allocatedObjectList) { - tmp = allocator->allocatedObjectList->next; - YFREE(allocator->allocatedObjectList->objects); - YFREE(allocator->allocatedObjectList); - - allocator->allocatedObjectList = tmp; - } - - allocator->freeObjects = NULL; - allocator->nFreeObjects = 0; - allocator->nObjectsCreated = 0; -} - - -static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects) -{ - yaffs_Allocator *allocator = dev->allocator; - - int i; - yaffs_Object *newObjects; - yaffs_ObjectList *list; - - if(!allocator){ - YBUG(); - return YAFFS_FAIL; - } - - if (nObjects < 1) - return YAFFS_OK; - - /* make these things */ - newObjects = YMALLOC(nObjects * sizeof(yaffs_Object)); - list = YMALLOC(sizeof(yaffs_ObjectList)); - - if (!newObjects || !list) { - if (newObjects){ - YFREE(newObjects); - newObjects = NULL; - } - if (list){ - YFREE(list); - list = NULL; - } - T(YAFFS_TRACE_ALLOCATE, - (TSTR("yaffs: Could not allocate more objects" TENDSTR))); - return YAFFS_FAIL; - } - - /* Hook them into the free list */ - for (i = 0; i < nObjects - 1; i++) { - newObjects[i].siblings.next = - (struct ylist_head *)(&newObjects[i + 1]); - } - - newObjects[nObjects - 1].siblings.next = (void *)allocator->freeObjects; - allocator->freeObjects = newObjects; - allocator->nFreeObjects += nObjects; - allocator->nObjectsCreated += nObjects; - - /* Now add this bunch of Objects to a list for freeing up. */ - - list->objects = newObjects; - list->next = allocator->allocatedObjectList; - allocator->allocatedObjectList = list; - - return YAFFS_OK; -} - -yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev) -{ - yaffs_Object *obj = NULL; - yaffs_Allocator *allocator = dev->allocator; - - if(!allocator) { - YBUG(); - return obj; - } - - /* If there are none left make more */ - if (!allocator->freeObjects) - yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS); - - if (allocator->freeObjects) { - obj = allocator->freeObjects; - allocator->freeObjects = - (yaffs_Object *) (allocator->freeObjects->siblings.next); - allocator->nFreeObjects--; - } - - return obj; -} - - -void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj) -{ - - yaffs_Allocator *allocator = dev->allocator; - - if(!allocator) - YBUG(); - else { - /* Link into the free list. */ - obj->siblings.next = (struct ylist_head *)(allocator->freeObjects); - allocator->freeObjects = obj; - allocator->nFreeObjects++; - } -} - -void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev) -{ - if(dev->allocator){ - yaffs_DeinitialiseRawTnodes(dev); - yaffs_DeinitialiseRawObjects(dev); - - YFREE(dev->allocator); - dev->allocator=NULL; - } else - YBUG(); -} - -void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev) -{ - yaffs_Allocator *allocator; - - if(!dev->allocator){ - allocator = YMALLOC(sizeof(yaffs_Allocator)); - if(allocator){ - dev->allocator = allocator; - yaffs_InitialiseRawTnodes(dev); - yaffs_InitialiseRawObjects(dev); - } - } else - YBUG(); -} - - -#endif diff --git a/fs/yaffs2/yaffs_allocator.h b/fs/yaffs2/yaffs_allocator.h deleted file mode 100644 index b0a5d11b..00000000 --- a/fs/yaffs2/yaffs_allocator.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2.1 as - * published by the Free Software Foundation. - * - * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. - */ - -#ifndef __YAFFS_ALLOCATOR_H__ -#define __YAFFS_ALLOCATOR_H__ - -#include "yaffs_guts.h" - -void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev); -void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev); - -yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev); -void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn); - -yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev); -void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj); - -#endif diff --git a/fs/yaffs2/yaffs_bitmap.c b/fs/yaffs2/yaffs_bitmap.c deleted file mode 100644 index c7e9e8c4..00000000 --- a/fs/yaffs2/yaffs_bitmap.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include "yaffs_bitmap.h" -#include "yaffs_trace.h" -/* - * Chunk bitmap manipulations - */ - -static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk) -{ - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { - T(YAFFS_TRACE_ERROR, - (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR), - blk)); - YBUG(); - } - return dev->chunkBits + - (dev->chunkBitmapStride * (blk - dev->internalStartBlock)); -} - -void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk) -{ - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock || - chunk < 0 || chunk >= dev->param.nChunksPerBlock) { - T(YAFFS_TRACE_ERROR, - (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR), - blk, chunk)); - YBUG(); - } -} - -void yaffs_ClearChunkBits(yaffs_Device *dev, int blk) -{ - __u8 *blkBits = yaffs_BlockBits(dev, blk); - - memset(blkBits, 0, dev->chunkBitmapStride); -} - -void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk) -{ - __u8 *blkBits = yaffs_BlockBits(dev, blk); - - yaffs_VerifyChunkBitId(dev, blk, chunk); - - blkBits[chunk / 8] &= ~(1 << (chunk & 7)); -} - -void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk) -{ - __u8 *blkBits = yaffs_BlockBits(dev, blk); - - yaffs_VerifyChunkBitId(dev, blk, chunk); - - blkBits[chunk / 8] |= (1 << (chunk & 7)); -} - -int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk) -{ - __u8 *blkBits = yaffs_BlockBits(dev, blk); - yaffs_VerifyChunkBitId(dev, blk, chunk); - - return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; -} - -int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk) -{ - __u8 *blkBits = yaffs_BlockBits(dev, blk); - int i; - for (i = 0; i < dev->chunkBitmapStride; i++) { - if (*blkBits) - return 1; - blkBits++; - } - return 0; -} - -int yaffs_CountChunkBits(yaffs_Device *dev, int blk) -{ - __u8 *blkBits = yaffs_BlockBits(dev, blk); - int i; - int n = 0; - for (i = 0; i < dev->chunkBitmapStride; i++) { - __u8 x = *blkBits; - while (x) { - if (x & 1) - n++; - x >>= 1; - } - - blkBits++; - } - return n; -} - diff --git a/fs/yaffs2/yaffs_bitmap.h b/fs/yaffs2/yaffs_bitmap.h deleted file mode 100644 index a0ad1308..00000000 --- a/fs/yaffs2/yaffs_bitmap.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * Chunk bitmap manipulations - */ - -#ifndef __YAFFS_BITMAP_H__ -#define __YAFFS_BITMAP_H__ - -#include "yaffs_guts.h" - -void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk); -void yaffs_ClearChunkBits(yaffs_Device *dev, int blk); -void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk); -void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk); -int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk); -int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk); -int yaffs_CountChunkBits(yaffs_Device *dev, int blk); - -#endif diff --git a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c index 16c9f849..7b69a640 100644 --- a/fs/yaffs2/yaffs_checkptrw.c +++ b/fs/yaffs2/yaffs_checkptrw.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -11,12 +11,16 @@ * published by the Free Software Foundation. */ +const char *yaffs_checkptrw_c_version = + "$Id$"; + + #include "yaffs_checkptrw.h" #include "yaffs_getblockinfo.h" -static int yaffs2_CheckpointSpaceOk(yaffs_Device *dev) +static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) { - int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks; + int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpt blocks available = %d" TENDSTR), @@ -26,11 +30,11 @@ static int yaffs2_CheckpointSpaceOk(yaffs_Device *dev) } -static int yaffs2_CheckpointErase(yaffs_Device *dev) +static int yaffs_CheckpointErase(yaffs_Device *dev) { int i; - if (!dev->param.eraseBlockInNAND) + if (!dev->eraseBlockInNAND) return 0; T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR), dev->internalStartBlock, dev->internalEndBlock)); @@ -42,12 +46,12 @@ static int yaffs2_CheckpointErase(yaffs_Device *dev) dev->nBlockErasures++; - if (dev->param.eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) { + if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) { bi->blockState = YAFFS_BLOCK_STATE_EMPTY; dev->nErasedBlocks++; - dev->nFreeChunks += dev->param.nChunksPerBlock; + dev->nFreeChunks += dev->nChunksPerBlock; } else { - dev->param.markNANDBlockBad(dev, i); + dev->markNANDBlockBad(dev, i); bi->blockState = YAFFS_BLOCK_STATE_DEAD; } } @@ -59,13 +63,13 @@ static int yaffs2_CheckpointErase(yaffs_Device *dev) } -static void yaffs2_CheckpointFindNextErasedBlock(yaffs_Device *dev) +static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev) { int i; - int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks; + int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), - dev->nErasedBlocks, dev->param.nReservedBlocks, blocksAvailable, dev->checkpointNextBlock)); + dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock)); if (dev->checkpointNextBlock >= 0 && dev->checkpointNextBlock <= dev->internalEndBlock && @@ -87,7 +91,7 @@ static void yaffs2_CheckpointFindNextErasedBlock(yaffs_Device *dev) dev->checkpointCurrentBlock = -1; } -static void yaffs2_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) +static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) { int i; yaffs_ExtendedTags tags; @@ -97,10 +101,10 @@ static void yaffs2_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks) for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) { - int chunk = i * dev->param.nChunksPerBlock; + int chunk = i * dev->nChunksPerBlock; int realignedChunk = chunk - dev->chunkOffset; - dev->param.readChunkWithTagsFromNAND(dev, realignedChunk, + dev->readChunkWithTagsFromNAND(dev, realignedChunk, NULL, &tags); T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR), i, tags.objectId, tags.sequenceNumber, tags.eccResult)); @@ -123,24 +127,24 @@ static void yaffs2_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) } -int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting) +int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) { dev->checkpointOpenForWrite = forWriting; /* Got the functions we need? */ - if (!dev->param.writeChunkWithTagsToNAND || - !dev->param.readChunkWithTagsFromNAND || - !dev->param.eraseBlockInNAND || - !dev->param.markNANDBlockBad) + if (!dev->writeChunkWithTagsToNAND || + !dev->readChunkWithTagsFromNAND || + !dev->eraseBlockInNAND || + !dev->markNANDBlockBad) return 0; - if (forWriting && !yaffs2_CheckpointSpaceOk(dev)) + if (forWriting && !yaffs_CheckpointSpaceOk(dev)) return 0; if (!dev->checkpointBuffer) - dev->checkpointBuffer = YMALLOC_DMA(dev->param.totalBytesPerChunk); + dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk); if (!dev->checkpointBuffer) return 0; @@ -157,7 +161,7 @@ int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting) if (forWriting) { memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk); dev->checkpointByteOffset = 0; - return yaffs2_CheckpointErase(dev); + return yaffs_CheckpointErase(dev); } else { int i; /* Set to a value that will kick off a read */ @@ -177,7 +181,7 @@ int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting) return 1; } -int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) +int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) { __u32 compositeSum; compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF); @@ -185,7 +189,7 @@ int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) return 1; } -static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev) +static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) { int chunk; int realignedChunk; @@ -193,7 +197,7 @@ static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev) yaffs_ExtendedTags tags; if (dev->checkpointCurrentBlock < 0) { - yaffs2_CheckpointFindNextErasedBlock(dev); + yaffs_CheckpointFindNextErasedBlock(dev); dev->checkpointCurrentChunk = 0; } @@ -213,7 +217,7 @@ static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev) dev->blocksInCheckpoint++; } - chunk = dev->checkpointCurrentBlock * dev->param.nChunksPerBlock + dev->checkpointCurrentChunk; + chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), @@ -223,12 +227,12 @@ static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev) dev->nPageWrites++; - dev->param.writeChunkWithTagsToNAND(dev, realignedChunk, + dev->writeChunkWithTagsToNAND(dev, realignedChunk, dev->checkpointBuffer, &tags); dev->checkpointByteOffset = 0; dev->checkpointPageSequence++; dev->checkpointCurrentChunk++; - if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock) { + if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) { dev->checkpointCurrentChunk = 0; dev->checkpointCurrentBlock = -1; } @@ -238,7 +242,7 @@ static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev) } -int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes) +int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes) { int i = 0; int ok = 1; @@ -267,13 +271,13 @@ int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes) if (dev->checkpointByteOffset < 0 || dev->checkpointByteOffset >= dev->nDataBytesPerChunk) - ok = yaffs2_CheckpointFlushBuffer(dev); + ok = yaffs_CheckpointFlushBuffer(dev); } return i; } -int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) +int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) { int i = 0; int ok = 1; @@ -298,7 +302,7 @@ int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) dev->checkpointByteOffset >= dev->nDataBytesPerChunk) { if (dev->checkpointCurrentBlock < 0) { - yaffs2_CheckpointFindNextCheckpointBlock(dev); + yaffs_CheckpointFindNextCheckpointBlock(dev); dev->checkpointCurrentChunk = 0; } @@ -306,7 +310,7 @@ int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) ok = 0; else { chunk = dev->checkpointCurrentBlock * - dev->param.nChunksPerBlock + + dev->nChunksPerBlock + dev->checkpointCurrentChunk; realignedChunk = chunk - dev->chunkOffset; @@ -315,7 +319,7 @@ int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) /* read in the next chunk */ /* printf("read checkpoint page %d\n",dev->checkpointPage); */ - dev->param.readChunkWithTagsFromNAND(dev, + dev->readChunkWithTagsFromNAND(dev, realignedChunk, dev->checkpointBuffer, &tags); @@ -329,7 +333,7 @@ int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) dev->checkpointPageSequence++; dev->checkpointCurrentChunk++; - if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock) + if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) dev->checkpointCurrentBlock = -1; } } @@ -348,12 +352,12 @@ int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) return i; } -int yaffs2_CheckpointClose(yaffs_Device *dev) +int yaffs_CheckpointClose(yaffs_Device *dev) { if (dev->checkpointOpenForWrite) { if (dev->checkpointByteOffset != 0) - yaffs2_CheckpointFlushBuffer(dev); + yaffs_CheckpointFlushBuffer(dev); } else if(dev->checkpointBlockList){ int i; for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) { @@ -371,7 +375,7 @@ int yaffs2_CheckpointClose(yaffs_Device *dev) dev->checkpointBlockList = NULL; } - dev->nFreeChunks -= dev->blocksInCheckpoint * dev->param.nChunksPerBlock; + dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock; dev->nErasedBlocks -= dev->blocksInCheckpoint; @@ -387,15 +391,12 @@ int yaffs2_CheckpointClose(yaffs_Device *dev) return 0; } -int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev) +int yaffs_CheckpointInvalidateStream(yaffs_Device *dev) { /* Erase the checkpoint data */ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR), dev->blocksInCheckpoint)); - return yaffs2_CheckpointErase(dev); + return yaffs_CheckpointErase(dev); } - - - diff --git a/fs/yaffs2/yaffs_checkptrw.h b/fs/yaffs2/yaffs_checkptrw.h index ea4f0276..5d426ea8 100644 --- a/fs/yaffs2/yaffs_checkptrw.h +++ b/fs/yaffs2/yaffs_checkptrw.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -18,17 +18,18 @@ #include "yaffs_guts.h" -int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting); +int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting); -int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes); +int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes); -int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes); +int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes); -int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); +int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); -int yaffs2_CheckpointClose(yaffs_Device *dev); +int yaffs_CheckpointClose(yaffs_Device *dev); -int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev); +int yaffs_CheckpointInvalidateStream(yaffs_Device *dev); #endif + diff --git a/fs/yaffs2/yaffs_ecc.c b/fs/yaffs2/yaffs_ecc.c index da6145aa..4676346c 100644 --- a/fs/yaffs2/yaffs_ecc.c +++ b/fs/yaffs2/yaffs_ecc.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -28,6 +28,9 @@ * this bytes influence on the line parity. */ +const char *yaffs_ecc_c_version = + "$Id$"; + #include "yportenv.h" #include "yaffs_ecc.h" diff --git a/fs/yaffs2/yaffs_ecc.h b/fs/yaffs2/yaffs_ecc.h index a1ee69ac..60765176 100644 --- a/fs/yaffs2/yaffs_ecc.h +++ b/fs/yaffs2/yaffs_ecc.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning diff --git a/fs/yaffs2/yaffs_vfs_glue.c b/fs/yaffs2/yaffs_fs.c similarity index 59% rename from fs/yaffs2/yaffs_vfs_glue.c rename to fs/yaffs2/yaffs_fs.c index c61da67d..2c89d16b 100644 --- a/fs/yaffs2/yaffs_vfs_glue.c +++ b/fs/yaffs2/yaffs_fs.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2009 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -31,41 +31,14 @@ * >> inode->u.generic_ip points to the associated yaffs_Object. */ -/* - * There are two variants of the VFS glue code. This variant should compile - * for any version of Linux. - */ +const char *yaffs_fs_c_version = + "$Id$"; +extern const char *yaffs_guts_c_version; + #include - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)) -#define YAFFS_COMPILE_BACKGROUND -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6, 23)) -#define YAFFS_COMPILE_FREEZER -#endif -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) -#define YAFFS_COMPILE_EXPORTFS -#endif - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)) -#define YAFFS_USE_SETATTR_COPY -#define YAFFS_USE_TRUNCATE_SETSIZE -#endif -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)) -#define YAFFS_HAS_EVICT_INODE -#endif - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)) -#define YAFFS_NEW_FOLLOW_LINK 1 -#else -#define YAFFS_NEW_FOLLOW_LINK 0 -#endif - #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) #include #endif - #include #include #include @@ -79,28 +52,12 @@ #include #include -#if (YAFFS_NEW_FOLLOW_LINK == 1) -#include -#endif - -#ifdef YAFFS_COMPILE_EXPORTFS -#include -#endif - -#ifdef YAFFS_COMPILE_BACKGROUND -#include -#include -#endif -#ifdef YAFFS_COMPILE_FREEZER -#include -#endif - -#include +#include "asm/div64.h" #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +#include /* Added NCB 15-8-2003 */ #include - #define UnlockPage(p) unlock_page(p) #define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) @@ -126,12 +83,6 @@ #define YPROC_ROOT NULL #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) -#define Y_INIT_TIMER(a) init_timer(a) -#else -#define Y_INIT_TIMER(a) init_timer_on_stack(a) -#endif - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) #define WRITE_SIZE_STR "writesize" #define WRITE_SIZE(mtd) ((mtd)->writesize) @@ -158,36 +109,28 @@ static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) #endif #include -#include #include "yportenv.h" -#include "yaffs_trace.h" #include "yaffs_guts.h" -#include "yaffs_linux.h" - +#include #include "yaffs_mtdif.h" #include "yaffs_mtdif1.h" #include "yaffs_mtdif2.h" -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS; +unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS; unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; unsigned int yaffs_auto_checkpoint = 1; -unsigned int yaffs_gc_control = 1; -unsigned int yaffs_bg_enable = 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); -module_param(yaffs_gc_control, uint, 0644); -module_param(yaffs_bg_enable, uint, 0644); #else MODULE_PARM(yaffs_traceMask, "i"); MODULE_PARM(yaffs_wr_attempts, "i"); MODULE_PARM(yaffs_auto_checkpoint, "i"); -MODULE_PARM(yaffs_gc_control, "i"); #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) @@ -203,6 +146,8 @@ static void yaffs_read_inode(struct inode *inode); static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino); #endif +/*#define T(x) printk x */ + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) #define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private) #else @@ -236,12 +181,8 @@ static int yaffs_file_flush(struct file *file, fl_owner_t id); static int yaffs_file_flush(struct file *file); #endif -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) -static int yaffs_sync_object(struct file *file, int datasync); -#else static int yaffs_sync_object(struct file *file, struct dentry *dentry, int datasync); -#endif static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir); @@ -292,12 +233,8 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf); static void yaffs_put_inode(struct inode *inode); #endif -#ifdef YAFFS_HAS_EVICT_INODE -static void yaffs_evict_inode(struct inode *); -#else static void yaffs_delete_inode(struct inode *); static void yaffs_clear_inode(struct inode *); -#endif static int yaffs_readpage(struct file *file, struct page *page); #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) @@ -306,15 +243,6 @@ static int yaffs_writepage(struct page *page, struct writeback_control *wbc); static int yaffs_writepage(struct page *page); #endif -#ifdef CONFIG_YAFFS_XATTR -int yaffs_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags); -ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff, - size_t size); -int yaffs_removexattr(struct dentry *dentry, const char *name); -ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size); -#endif - #if (YAFFS_USE_WRITE_BEGIN_END != 0) static int yaffs_write_begin(struct file *filp, struct address_space *mapping, @@ -333,20 +261,12 @@ static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, static int yaffs_readlink(struct dentry *dentry, char __user *buffer, int buflen); -#if (YAFFS_NEW_FOLLOW_LINK == 1) -void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); #else static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); #endif -static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev); - -static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin); - -static int yaffs_vfs_setattr(struct inode *, struct iattr *); - - static struct address_space_operations yaffs_file_address_operations = { .readpage = yaffs_readpage, .writepage = yaffs_writepage, @@ -359,7 +279,6 @@ static struct address_space_operations yaffs_file_address_operations = { #endif }; - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) static const struct file_operations yaffs_file_operations = { .read = do_sync_read, @@ -401,40 +320,14 @@ static const struct file_operations yaffs_file_operations = { }; #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)) -static void zero_user_segment(struct page *page, unsigned start, unsigned end) -{ - void * kaddr = kmap_atomic(page, KM_USER0); - memset(kaddr + start, 0, end - start); - kunmap_atomic(kaddr, KM_USER0); - flush_dcache_page(page); -} -#endif - - static const struct inode_operations yaffs_file_inode_operations = { .setattr = yaffs_setattr, -#ifdef CONFIG_YAFFS_XATTR - .setxattr = yaffs_setxattr, - .getxattr = yaffs_getxattr, - .listxattr = yaffs_listxattr, - .removexattr = yaffs_removexattr, -#endif }; static const struct inode_operations yaffs_symlink_inode_operations = { .readlink = yaffs_readlink, .follow_link = yaffs_follow_link, -#if (YAFFS_NEW_FOLLOW_LINK == 1) - .put_link = yaffs_put_link, -#endif .setattr = yaffs_setattr, -#ifdef CONFIG_YAFFS_XATTR - .setxattr = yaffs_setxattr, - .getxattr = yaffs_getxattr, - .listxattr = yaffs_listxattr, - .removexattr = yaffs_removexattr, -#endif }; static const struct inode_operations yaffs_dir_inode_operations = { @@ -448,19 +341,12 @@ static const struct inode_operations yaffs_dir_inode_operations = { .mknod = yaffs_mknod, .rename = yaffs_rename, .setattr = yaffs_setattr, -#ifdef CONFIG_YAFFS_XATTR - .setxattr = yaffs_setxattr, - .getxattr = yaffs_getxattr, - .listxattr = yaffs_listxattr, - .removexattr = yaffs_removexattr, -#endif }; static const struct file_operations yaffs_dir_operations = { .read = generic_read_dir, .readdir = yaffs_readdir, .fsync = yaffs_sync_object, - .llseek = yaffs_dir_llseek, }; static const struct super_operations yaffs_super_ops = { @@ -473,123 +359,25 @@ static const struct super_operations yaffs_super_ops = { .put_inode = yaffs_put_inode, #endif .put_super = yaffs_put_super, -#ifdef YAFFS_HAS_EVICT_INODE - .evict_inode = yaffs_evict_inode, -#else .delete_inode = yaffs_delete_inode, .clear_inode = yaffs_clear_inode, -#endif .sync_fs = yaffs_sync_fs, .write_super = yaffs_write_super, }; - -static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr) -{ -#ifdef YAFFS_USE_SETATTR_COPY - setattr_copy(inode,attr); - return 0; -#else - return inode_setattr(inode, attr); -#endif - -} - -static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize) -{ -#ifdef YAFFS_USE_TRUNCATE_SETSIZE - truncate_setsize(inode,newsize); - return 0; -#else - truncate_inode_pages(&inode->i_data,newsize); - return 0; -#endif - -} - -static unsigned yaffs_gc_control_callback(yaffs_Device *dev) -{ - return yaffs_gc_control; -} - static void yaffs_GrossLock(yaffs_Device *dev) { - T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current)); - down(&(yaffs_DeviceToLC(dev)->grossLock)); - T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current)); + T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current)); + down(&dev->grossLock); + T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current)); } static void yaffs_GrossUnlock(yaffs_Device *dev) { - T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current)); - up(&(yaffs_DeviceToLC(dev)->grossLock)); + T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current)); + up(&dev->grossLock); } -#ifdef YAFFS_COMPILE_EXPORTFS - -static struct inode * -yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation) -{ - return Y_IGET(sb, ino); -} - -static struct dentry * -yaffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) -{ - return generic_fh_to_dentry(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode) ; -} - -static struct dentry * - yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) -{ - return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode); -} - -struct dentry *yaffs2_get_parent(struct dentry *dentry) -{ - - struct super_block *sb = dentry->d_inode->i_sb; - struct dentry *parent = ERR_PTR(-ENOENT); - struct inode *inode; - unsigned long parent_ino; - yaffs_Object *d_obj; - yaffs_Object *parent_obj; - - d_obj = yaffs_InodeToObject(dentry->d_inode); - - if (d_obj) { - parent_obj = d_obj->parent; - if (parent_obj) { - parent_ino = yaffs_GetObjectInode(parent_obj); - inode = Y_IGET(sb, parent_ino); - - if (IS_ERR(inode)) { - parent = ERR_CAST(inode); - } else { - parent = d_obtain_alias(inode); - if (!IS_ERR(parent)) { - parent = ERR_PTR(-ENOMEM); - iput(inode); - } - } - } - } - - return parent; -} - -/* Just declare a zero structure as a NULL value implies - * using the default functions of exportfs. - */ - -static struct export_operations yaffs_export_ops = -{ - .fh_to_dentry = yaffs2_fh_to_dentry, - .fh_to_parent = yaffs2_fh_to_parent, - .get_parent = yaffs2_get_parent, -} ; - -#endif /*-----------------------------------------------------------------*/ /* Directory search context allows us to unlock access to yaffs during @@ -637,7 +425,7 @@ static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_Object *dir) dir->variant.directoryVariant.children.next, yaffs_Object,siblings); YINIT_LIST_HEAD(&sc->others); - ylist_add(&sc->others,&(yaffs_DeviceToLC(dev)->searchContexts)); + ylist_add(&sc->others,&dev->searchContexts); } return sc; } @@ -686,7 +474,7 @@ static void yaffs_RemoveObjectCallback(yaffs_Object *obj) struct ylist_head *i; struct yaffs_SearchContext *sc; - struct ylist_head *search_contexts = &(yaffs_DeviceToLC(obj->myDev)->searchContexts); + struct ylist_head *search_contexts = &obj->myDev->searchContexts; /* Iterate through the directory search contexts. @@ -728,7 +516,7 @@ static int yaffs_readlink(struct dentry *dentry, char __user *buffer, return ret; } -#if (YAFFS_NEW_FOLLOW_LINK == 1) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) #else static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) @@ -741,6 +529,7 @@ static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) yaffs_GrossLock(dev); alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); + yaffs_GrossUnlock(dev); if (!alias) { @@ -748,25 +537,16 @@ static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) goto out; } -#if (YAFFS_NEW_FOLLOW_LINK == 1) - nd_set_link(nd, alias); - ret = (int)alias; -out: - return ERR_PTR(ret); -#else ret = vfs_follow_link(nd, alias); kfree(alias); out: +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) + return ERR_PTR(ret); +#else return ret; #endif } -#if (YAFFS_NEW_FOLLOW_LINK == 1) -void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) { - kfree(alias); -} -#endif - struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, yaffs_Object *obj); @@ -786,11 +566,10 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev; - if(current != yaffs_DeviceToLC(dev)->readdirProcess) - yaffs_GrossLock(dev); + yaffs_GrossLock(dev); T(YAFFS_TRACE_OS, - (TSTR("yaffs_lookup for %d:%s\n"), + ("yaffs_lookup for %d:%s\n", yaffs_InodeToObject(dir)->objectId, dentry->d_name.name)); obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir), @@ -799,18 +578,17 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */ /* Can't hold gross lock when calling yaffs_get_inode() */ - if(current != yaffs_DeviceToLC(dev)->readdirProcess) - yaffs_GrossUnlock(dev); + yaffs_GrossUnlock(dev); if (obj) { T(YAFFS_TRACE_OS, - (TSTR("yaffs_lookup found %d\n"), obj->objectId)); + ("yaffs_lookup found %d\n", obj->objectId)); inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); if (inode) { T(YAFFS_TRACE_OS, - (TSTR("yaffs_loookup dentry \n"))); + ("yaffs_loookup dentry \n")); /* #if 0 asserted by NCB for 2.5/6 compatability - falls through to * d_add even if NULL inode */ #if 0 @@ -823,7 +601,7 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) } } else { - T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n"))); + T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n")); } @@ -843,75 +621,13 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) static void yaffs_put_inode(struct inode *inode) { T(YAFFS_TRACE_OS, - (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino, + ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino, atomic_read(&inode->i_count))); } #endif - -static void yaffs_UnstitchObject(struct inode *inode, yaffs_Object *obj) -{ - /* Clear the association between the inode and - * the yaffs_Object. - */ - obj->myInode = NULL; - yaffs_InodeToObjectLV(inode) = NULL; - - /* If the object freeing was deferred, then the real - * free happens now. - * This should fix the inode inconsistency problem. - */ - yaffs_HandleDeferedFree(obj); -} - -#ifdef YAFFS_HAS_EVICT_INODE -/* yaffs_evict_inode combines into one operation what was previously done in - * yaffs_clear_inode() and yaffs_delete_inode() - * - */ -static void yaffs_evict_inode( struct inode *inode) -{ - yaffs_Object *obj; - yaffs_Device *dev; - int deleteme = 0; - - obj = yaffs_InodeToObject(inode); - - T(YAFFS_TRACE_OS, - (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino, - atomic_read(&inode->i_count), - obj ? "object exists" : "null object")); - - if (!inode->i_nlink && !is_bad_inode(inode)) - deleteme = 1; - truncate_inode_pages(&inode->i_data,0); - end_writeback(inode); - - if(deleteme && obj){ - dev = obj->myDev; - yaffs_GrossLock(dev); - yaffs_DeleteObject(obj); - yaffs_GrossUnlock(dev); - } - if (obj) { - dev = obj->myDev; - yaffs_GrossLock(dev); - yaffs_UnstitchObject(inode,obj); - yaffs_GrossUnlock(dev); - } - - -} -#else - -/* clear is called to tell the fs to release any per-inode data it holds. - * The object might still exist on disk and is just being thrown out of the cache - * or else the object has actually been deleted and we're being called via - * the chain - * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode() - */ - +/* clear is called to tell the fs to release any per-inode data it holds */ static void yaffs_clear_inode(struct inode *inode) { yaffs_Object *obj; @@ -920,14 +636,27 @@ static void yaffs_clear_inode(struct inode *inode) obj = yaffs_InodeToObject(inode); T(YAFFS_TRACE_OS, - (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino, + ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino, atomic_read(&inode->i_count), obj ? "object exists" : "null object")); if (obj) { dev = obj->myDev; yaffs_GrossLock(dev); - yaffs_UnstitchObject(inode,obj); + + /* Clear the association between the inode and + * the yaffs_Object. + */ + obj->myInode = NULL; + yaffs_InodeToObjectLV(inode) = NULL; + + /* If the object freeing was deferred, then the real + * free happens now. + * This should fix the inode inconsistency problem. + */ + + yaffs_HandleDeferedFree(obj); + yaffs_GrossUnlock(dev); } @@ -944,7 +673,7 @@ static void yaffs_delete_inode(struct inode *inode) yaffs_Device *dev; T(YAFFS_TRACE_OS, - (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino, + ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino, atomic_read(&inode->i_count), obj ? "object exists" : "null object")); @@ -959,8 +688,6 @@ static void yaffs_delete_inode(struct inode *inode) #endif clear_inode(inode); } -#endif - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) static int yaffs_file_flush(struct file *file, fl_owner_t id) @@ -973,18 +700,19 @@ static int yaffs_file_flush(struct file *file) yaffs_Device *dev = obj->myDev; T(YAFFS_TRACE_OS, - (TSTR("yaffs_file_flush object %d (%s)\n"), obj->objectId, + ("yaffs_file_flush object %d (%s)\n", obj->objectId, obj->dirty ? "dirty" : "clean")); yaffs_GrossLock(dev); - yaffs_FlushFile(obj, 1, 0); + yaffs_FlushFile(obj, 1); yaffs_GrossUnlock(dev); return 0; } +#define buffsize 100 static int yaffs_readpage_nolock(struct file *f, struct page *pg) { /* Lifted from jffs2 */ @@ -993,12 +721,26 @@ static int yaffs_readpage_nolock(struct file *f, struct page *pg) unsigned char *pg_buf; int ret; + static char buf_src[buffsize], buf_dest[buffsize]; + static int no = 1; + yaffs_Device *dev; - T(YAFFS_TRACE_OS, - (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"), - (unsigned)(pg->index << PAGE_CACHE_SHIFT), - (unsigned)PAGE_CACHE_SIZE)); + T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n", + (unsigned)(pg->index << PAGE_CACHE_SHIFT), + (unsigned)PAGE_CACHE_SIZE)); + + if (yaffs_traceMask & YAFFS_TRACE_HTC_DEBUG) { + snprintf(buf_src, buffsize, "%d, %s, %s\n", \ + (unsigned)(current->pid), current->comm, f->f_dentry->d_name.name); + if (!memcmp(buf_src, buf_dest, sizeof(buf_src) > buffsize?sizeof(buf_src):buffsize)) { + no++; + } else { + pr_info("[YAFFS] %d, %s", no, buf_dest); + memcpy(buf_dest, buf_src, sizeof(buf_src) > buffsize?sizeof(buf_src):buffsize); + no = 1; + } + } obj = yaffs_DentryToObject(f->f_dentry); @@ -1036,7 +778,7 @@ static int yaffs_readpage_nolock(struct file *f, struct page *pg) flush_dcache_page(pg); kunmap(pg); - T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n"))); + T(YAFFS_TRACE_OS, ("yaffs_readpage done\n")); return ret; } @@ -1049,12 +791,7 @@ static int yaffs_readpage_unlock(struct file *f, struct page *pg) static int yaffs_readpage(struct file *f, struct page *pg) { - int ret; - - T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n"))); - ret=yaffs_readpage_unlock(f, pg); - T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n"))); - return ret; + return yaffs_readpage_unlock(f, pg); } /* writepage inspired by/stolen from smbfs */ @@ -1065,79 +802,66 @@ static int yaffs_writepage(struct page *page, struct writeback_control *wbc) static int yaffs_writepage(struct page *page) #endif { - yaffs_Device *dev; struct address_space *mapping = page->mapping; + loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT; struct inode *inode; unsigned long end_index; char *buffer; yaffs_Object *obj; int nWritten = 0; unsigned nBytes; - loff_t i_size; if (!mapping) BUG(); inode = mapping->host; if (!inode) BUG(); - i_size = i_size_read(inode); - end_index = i_size >> PAGE_CACHE_SHIFT; - - if(page->index < end_index) - nBytes = PAGE_CACHE_SIZE; - else { - nBytes = i_size & (PAGE_CACHE_SIZE -1); - - if (page->index > end_index || !nBytes) { - T(YAFFS_TRACE_OS, - (TSTR("yaffs_writepage at %08x, inode size = %08x!!!\n"), - (unsigned)(page->index << PAGE_CACHE_SHIFT), - (unsigned)inode->i_size)); - T(YAFFS_TRACE_OS, - (TSTR(" -> don't care!!\n"))); - - zero_user_segment(page,0,PAGE_CACHE_SIZE); - set_page_writeback(page); - unlock_page(page); - end_page_writeback(page); - return 0; - } + if (offset > inode->i_size) { + T(YAFFS_TRACE_OS, + ("yaffs_writepage at %08x, inode size = %08x!!!\n", + (unsigned)(page->index << PAGE_CACHE_SHIFT), + (unsigned)inode->i_size)); + T(YAFFS_TRACE_OS, + (" -> don't care!!\n")); + unlock_page(page); + return 0; } - if(nBytes != PAGE_CACHE_SIZE) - zero_user_segment(page,nBytes,PAGE_CACHE_SIZE); + end_index = inode->i_size >> PAGE_CACHE_SHIFT; + + /* easy case */ + if (page->index < end_index) + nBytes = PAGE_CACHE_SIZE; + else + nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1); get_page(page); buffer = kmap(page); obj = yaffs_InodeToObject(inode); - dev = obj->myDev; - yaffs_GrossLock(dev); + yaffs_GrossLock(obj->myDev); T(YAFFS_TRACE_OS, - (TSTR("yaffs_writepage at %08x, size %08x\n"), + ("yaffs_writepage at %08x, size %08x\n", (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes)); T(YAFFS_TRACE_OS, - (TSTR("writepag0: obj = %05x, ino = %05x\n"), + ("writepag0: obj = %05x, ino = %05x\n", (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); nWritten = yaffs_WriteDataToFile(obj, buffer, page->index << PAGE_CACHE_SHIFT, nBytes, 0); - yaffs_MarkSuperBlockDirty(dev); - T(YAFFS_TRACE_OS, - (TSTR("writepag1: obj = %05x, ino = %05x\n"), + ("writepag1: obj = %05x, ino = %05x\n", (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); - yaffs_GrossUnlock(dev); + yaffs_GrossUnlock(obj->myDev); kunmap(page); - set_page_writeback(page); - unlock_page(page); - end_page_writeback(page); + SetPageUptodate(page); + UnlockPage(page); put_page(page); return (nWritten == nBytes) ? 0 : -ENOSPC; @@ -1151,12 +875,15 @@ static int yaffs_write_begin(struct file *filp, struct address_space *mapping, { struct page *pg = NULL; pgoff_t index = pos >> PAGE_CACHE_SHIFT; + uint32_t offset = pos & (PAGE_CACHE_SIZE - 1); + uint32_t to = offset + len; int ret = 0; int space_held = 0; + T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n")); /* Get a page */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28) pg = grab_cache_page_write_begin(mapping, index, flags); #else pg = __grab_cache_page(mapping, index); @@ -1167,10 +894,6 @@ static int yaffs_write_begin(struct file *filp, struct address_space *mapping, ret = -ENOMEM; goto out; } - T(YAFFS_TRACE_OS, - (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"), - (int)index,(int)index,Page_Uptodate(pg) ? 1 : 0)); - /* Get fs space */ space_held = yaffs_hold_space(filp); @@ -1181,20 +904,19 @@ static int yaffs_write_begin(struct file *filp, struct address_space *mapping, /* Update page if required */ - if (!Page_Uptodate(pg)) + 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, (TSTR("end yaffs_write_begin - ok\n"))); + T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n")); return 0; out: - T(YAFFS_TRACE_OS, - (TSTR("end yaffs_write_begin fail returning %d\n"), ret)); + T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret)); if (space_held) yaffs_release_space(filp); if (pg) { @@ -1209,9 +931,9 @@ out: static int yaffs_prepare_write(struct file *f, struct page *pg, unsigned offset, unsigned to) { - T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n"))); + T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n")); - if (!Page_Uptodate(pg)) + if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) return yaffs_readpage_nolock(f, pg); return 0; } @@ -1230,18 +952,20 @@ static int yaffs_write_end(struct file *filp, struct address_space *mapping, addr = kva + offset_into_page; T(YAFFS_TRACE_OS, - ("yaffs_write_end addr %p pos %x nBytes %d\n", - addr,(unsigned)pos, copied)); + ("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, - (TSTR("yaffs_write_end not same size ret %d copied %d\n"), + ("yaffs_write_end not same size ret %d copied %d\n", ret, copied)); SetPageError(pg); + ClearPageUptodate(pg); } else { - /* Nothing */ + SetPageUptodate(pg); } kunmap(pg); @@ -1271,24 +995,25 @@ static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, saddr = (unsigned) addr; T(YAFFS_TRACE_OS, - (TSTR("yaffs_commit_write addr %x pos %x nBytes %d\n"), + ("yaffs_commit_write addr %x pos %x nBytes %d\n", saddr, spos, nBytes)); nWritten = yaffs_file_write(f, addr, nBytes, &pos); if (nWritten != nBytes) { T(YAFFS_TRACE_OS, - (TSTR("yaffs_commit_write not same size nWritten %d nBytes %d\n"), + ("yaffs_commit_write not same size nWritten %d nBytes %d\n", nWritten, nBytes)); SetPageError(pg); + ClearPageUptodate(pg); } else { - /* Nothing */ + SetPageUptodate(pg); } kunmap(pg); T(YAFFS_TRACE_OS, - (TSTR("yaffs_commit_write returning %d\n"), + ("yaffs_commit_write returning %d\n", nWritten == nBytes ? 0 : nWritten)); return nWritten == nBytes ? 0 : nWritten; @@ -1363,7 +1088,7 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj) inode->i_nlink = yaffs_GetObjectLinkCount(obj); T(YAFFS_TRACE_OS, - (TSTR("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n"), + ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n", inode->i_mode, inode->i_uid, inode->i_gid, (int)inode->i_size, atomic_read(&inode->i_count))); @@ -1398,7 +1123,7 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj) } else { T(YAFFS_TRACE_OS, - (TSTR("yaffs_FileInode invalid parameters\n"))); + ("yaffs_FileInode invalid parameters\n")); } } @@ -1410,20 +1135,20 @@ struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, if (!sb) { T(YAFFS_TRACE_OS, - (TSTR("yaffs_get_inode for NULL super_block!!\n"))); + ("yaffs_get_inode for NULL super_block!!\n")); return NULL; } if (!obj) { T(YAFFS_TRACE_OS, - (TSTR("yaffs_get_inode for NULL object!!\n"))); + ("yaffs_get_inode for NULL object!!\n")); return NULL; } T(YAFFS_TRACE_OS, - (TSTR("yaffs_get_inode for object %d\n"), obj->objectId)); + ("yaffs_get_inode for object %d\n", obj->objectId)); inode = Y_IGET(sb, obj->objectId); if (IS_ERR(inode)) @@ -1459,20 +1184,18 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, if (!obj) T(YAFFS_TRACE_OS, - (TSTR("yaffs_file_write: hey obj is null!\n"))); + ("yaffs_file_write: hey obj is null!\n")); else T(YAFFS_TRACE_OS, - (TSTR("yaffs_file_write about to write writing %u(%x) bytes" - "to object %d at %d(%x)\n"), - (unsigned) n, (unsigned) n, obj->objectId, ipos,ipos)); + ("yaffs_file_write about to write writing %zu bytes" + "to object %d at %d\n", + n, obj->objectId, ipos)); nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0); - yaffs_MarkSuperBlockDirty(dev); - T(YAFFS_TRACE_OS, - (TSTR("yaffs_file_write: %d(%x) bytes written\n"), - (unsigned )n,(unsigned)n)); + ("yaffs_file_write writing %zu bytes, %d written at %d\n", + n, nWritten, ipos)); if (nWritten > 0) { ipos += nWritten; @@ -1482,8 +1205,8 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, inode->i_blocks = (ipos + 511) >> 9; T(YAFFS_TRACE_OS, - (TSTR("yaffs_file_write size updated to %d bytes, " - "%d blocks\n"), + ("yaffs_file_write size updated to %d bytes, " + "%d blocks\n", ipos, (int)(inode->i_blocks))); } @@ -1533,33 +1256,6 @@ static void yaffs_release_space(struct file *f) yaffs_GrossUnlock(dev); } - -static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin) -{ - long long retval; - - lock_kernel(); - - switch (origin){ - case 2: - offset += i_size_read(file->f_path.dentry->d_inode); - break; - case 1: - offset += file->f_pos; - } - retval = -EINVAL; - - if (offset >= 0){ - if (offset != file->f_pos) - file->f_pos = offset; - - retval = offset; - } - unlock_kernel(); - return retval; -} - - static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) { yaffs_Object *obj; @@ -1577,41 +1273,35 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) yaffs_GrossLock(dev); - yaffs_DeviceToLC(dev)->readdirProcess = current; - offset = f->f_pos; sc = yaffs_NewSearch(obj); if(!sc){ retVal = -ENOMEM; - goto out; + goto unlock_out; } - T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset)); + T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset)); if (offset == 0) { T(YAFFS_TRACE_OS, - (TSTR("yaffs_readdir: entry . ino %d \n"), + ("yaffs_readdir: entry . ino %d \n", (int)inode->i_ino)); yaffs_GrossUnlock(dev); - if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){ - yaffs_GrossLock(dev); + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) goto out; - } yaffs_GrossLock(dev); offset++; f->f_pos++; } if (offset == 1) { T(YAFFS_TRACE_OS, - (TSTR("yaffs_readdir: entry .. ino %d \n"), + ("yaffs_readdir: entry .. ino %d \n", (int)f->f_dentry->d_parent->d_inode->i_ino)); yaffs_GrossUnlock(dev); if (filldir(dirent, "..", 2, offset, - f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){ - yaffs_GrossLock(dev); + f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) goto out; - } yaffs_GrossLock(dev); offset++; f->f_pos++; @@ -1621,6 +1311,7 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) /* If the directory has changed since the open or last call to readdir, rewind to after the 2 canned entries. */ + if (f->f_version != inode->i_version) { offset = 2; f->f_pos = offset; @@ -1637,8 +1328,8 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) yaffs_GetObjectName(l, name, YAFFS_MAX_NAME_LENGTH + 1); T(YAFFS_TRACE_OS, - (TSTR("yaffs_readdir: %s inode %d\n"), - name, yaffs_GetObjectInode(l))); + ("yaffs_readdir: %s inode %d\n", name, + yaffs_GetObjectInode(l))); yaffs_GrossUnlock(dev); @@ -1647,10 +1338,8 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) strlen(name), offset, this_inode, - this_type) < 0){ - yaffs_GrossLock(dev); + this_type) < 0) goto out; - } yaffs_GrossLock(dev); @@ -1660,16 +1349,14 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) yaffs_SearchAdvance(sc); } -out: - yaffs_EndSearch(sc); - yaffs_DeviceToLC(dev)->readdirProcess = NULL; +unlock_out: yaffs_GrossUnlock(dev); +out: + yaffs_EndSearch(sc); return retVal; } - - /* * File creation. Allocate an inode, and we're done.. */ @@ -1704,16 +1391,16 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, if (parent) { T(YAFFS_TRACE_OS, - (TSTR("yaffs_mknod: parent object %d type %d\n"), + ("yaffs_mknod: parent object %d type %d\n", parent->objectId, parent->variantType)); } else { T(YAFFS_TRACE_OS, - (TSTR("yaffs_mknod: could not get parent object\n"))); + ("yaffs_mknod: could not get parent object\n")); return -EPERM; } - T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, " - "mode %x dev %x\n"), + T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, " + "mode %x dev %x\n", dentry->d_name.name, mode, rdev)); dev = parent->myDev; @@ -1723,7 +1410,7 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, switch (mode & S_IFMT) { default: /* Special (socket, fifo, device...) */ - T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n"))); + T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n")); #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid, gid, old_encode_dev(rdev)); @@ -1733,18 +1420,18 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, #endif break; case S_IFREG: /* file */ - T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n"))); + T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n")); obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid, gid); break; case S_IFDIR: /* directory */ T(YAFFS_TRACE_OS, - (TSTR("yaffs_mknod: making directory\n"))); + ("yaffs_mknod: making directory\n")); obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode, uid, gid); break; case S_IFLNK: /* symlink */ - T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n"))); + T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n")); obj = NULL; /* Do we ever get here? */ break; } @@ -1757,13 +1444,12 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, d_instantiate(dentry, inode); update_dir_time(dir); T(YAFFS_TRACE_OS, - (TSTR("yaffs_mknod created object %d count = %d\n"), + ("yaffs_mknod created object %d count = %d\n", obj->objectId, atomic_read(&inode->i_count))); error = 0; - yaffs_FillInodeFromObject(dir,parent); } else { T(YAFFS_TRACE_OS, - (TSTR("yaffs_mknod failed making object\n"))); + ("yaffs_mknod failed making object\n")); error = -ENOMEM; } @@ -1773,7 +1459,7 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { int retVal; - T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n"))); + T(YAFFS_TRACE_OS, ("yaffs_mkdir\n")); retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); return retVal; } @@ -1785,7 +1471,7 @@ static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode) #endif { - T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n"))); + T(YAFFS_TRACE_OS, ("yaffs_create\n")); return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); } @@ -1794,18 +1480,16 @@ static int yaffs_unlink(struct inode *dir, struct dentry *dentry) int retVal; yaffs_Device *dev; - yaffs_Object *obj; T(YAFFS_TRACE_OS, - (TSTR("yaffs_unlink %d:%s\n"), - (int)(dir->i_ino), + ("yaffs_unlink %d:%s\n", (int)(dir->i_ino), dentry->d_name.name)); - obj = yaffs_InodeToObject(dir); - dev = obj->myDev; + + dev = yaffs_InodeToObject(dir)->myDev; yaffs_GrossLock(dev); - retVal = yaffs_Unlink(obj, dentry->d_name.name); + retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name); if (retVal == YAFFS_OK) { dentry->d_inode->i_nlink--; @@ -1830,7 +1514,7 @@ static int yaffs_link(struct dentry *old_dentry, struct inode *dir, yaffs_Object *link = NULL; yaffs_Device *dev; - T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n"))); + T(YAFFS_TRACE_OS, ("yaffs_link\n")); obj = yaffs_InodeToObject(inode); dev = obj->myDev; @@ -1846,7 +1530,7 @@ static int yaffs_link(struct dentry *old_dentry, struct inode *dir, d_instantiate(dentry, old_dentry->d_inode); atomic_inc(&old_dentry->d_inode->i_count); T(YAFFS_TRACE_OS, - (TSTR("yaffs_link link count %d i_count %d\n"), + ("yaffs_link link count %d i_count %d\n", old_dentry->d_inode->i_nlink, atomic_read(&old_dentry->d_inode->i_count))); } @@ -1869,7 +1553,7 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry, uid_t uid = YCRED(current)->fsuid; gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; - T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n"))); + T(YAFFS_TRACE_OS, ("yaffs_symlink\n")); dev = yaffs_InodeToObject(dir)->myDev; yaffs_GrossLock(dev); @@ -1883,37 +1567,29 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry, inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); d_instantiate(dentry, inode); update_dir_time(dir); - T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n"))); + T(YAFFS_TRACE_OS, ("symlink created OK\n")); return 0; } else { - T(YAFFS_TRACE_OS, (TSTR("symlink not created\n"))); + T(YAFFS_TRACE_OS, ("symlink not created\n")); } return -ENOMEM; } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) -static int yaffs_sync_object(struct file *file, int datasync) -#else static int yaffs_sync_object(struct file *file, struct dentry *dentry, int datasync) -#endif { yaffs_Object *obj; yaffs_Device *dev; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) - struct dentry *dentry = file->f_path.dentry; -#endif obj = yaffs_DentryToObject(dentry); dev = obj->myDev; - T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, - (TSTR("yaffs_sync_object\n"))); + T(YAFFS_TRACE_OS, ("yaffs_sync_object\n")); yaffs_GrossLock(dev); - yaffs_FlushFile(obj, 1, datasync); + yaffs_FlushFile(obj, 1); yaffs_GrossUnlock(dev); return 0; } @@ -1930,7 +1606,7 @@ static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, int retVal = YAFFS_FAIL; yaffs_Object *target; - T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n"))); + T(YAFFS_TRACE_OS, ("yaffs_rename\n")); dev = yaffs_InodeToObject(old_dir)->myDev; yaffs_GrossLock(dev); @@ -1944,12 +1620,12 @@ static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && !ylist_empty(&target->variant.directoryVariant.children)) { - T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n"))); + T(YAFFS_TRACE_OS, ("target is non-empty dir\n")); retVal = YAFFS_FAIL; } else { /* Now does unlinking internally using shadowing mechanism */ - T(YAFFS_TRACE_OS, (TSTR("calling yaffs_RenameObject\n"))); + T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n")); retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir), old_dentry->d_name.name, @@ -1976,168 +1652,30 @@ static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; - int error = 0; + int error; yaffs_Device *dev; T(YAFFS_TRACE_OS, - (TSTR("yaffs_setattr of object %d\n"), + ("yaffs_setattr of object %d\n", yaffs_InodeToObject(inode)->objectId)); - /* Fail if a requested resize >= 2GB */ - if (attr->ia_valid & ATTR_SIZE && - (attr->ia_size >> 31)) - error = -EINVAL; - - if (error == 0) - error = inode_change_ok(inode, attr); + error = inode_change_ok(inode, attr); if (error == 0) { - int result; - if (!error){ - error = yaffs_vfs_setattr(inode, attr); - T(YAFFS_TRACE_OS,(TSTR("inode_setattr called\n"))); - if (attr->ia_valid & ATTR_SIZE){ - yaffs_vfs_setsize(inode,attr->ia_size); - inode->i_blocks = (inode->i_size + 511) >> 9; - } - } dev = yaffs_InodeToObject(inode)->myDev; - if (attr->ia_valid & ATTR_SIZE){ - T(YAFFS_TRACE_OS,(TSTR("resize to %d(%x)\n"), - (int)(attr->ia_size),(int)(attr->ia_size))); - } yaffs_GrossLock(dev); - result = yaffs_SetAttributes(yaffs_InodeToObject(inode), attr); - if(result == YAFFS_OK) { + if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) == + YAFFS_OK) { error = 0; } else { error = -EPERM; } yaffs_GrossUnlock(dev); - + if (!error) + error = inode_setattr(inode, attr); } - - T(YAFFS_TRACE_OS, - (TSTR("yaffs_setattr done returning %d\n"),error)); - return error; } -#ifdef CONFIG_YAFFS_XATTR -int yaffs_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) -{ - struct inode *inode = dentry->d_inode; - int error = 0; - yaffs_Device *dev; - yaffs_Object *obj = yaffs_InodeToObject(inode); - - T(YAFFS_TRACE_OS, - (TSTR("yaffs_setxattr of object %d\n"), - obj->objectId)); - - - if (error == 0) { - int result; - dev = obj->myDev; - yaffs_GrossLock(dev); - result = yaffs_SetXAttribute(obj, name, value, size, flags); - if(result == YAFFS_OK) - error = 0; - else if(result < 0) - error = result; - yaffs_GrossUnlock(dev); - - } - T(YAFFS_TRACE_OS, - (TSTR("yaffs_setxattr done returning %d\n"),error)); - - return error; -} - - -ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff, - size_t size) -{ - struct inode *inode = dentry->d_inode; - int error = 0; - yaffs_Device *dev; - yaffs_Object *obj = yaffs_InodeToObject(inode); - - T(YAFFS_TRACE_OS, - (TSTR("yaffs_getxattr \"%s\" from object %d\n"), - name, obj->objectId)); - - if (error == 0) { - dev = obj->myDev; - yaffs_GrossLock(dev); - error = yaffs_GetXAttribute(obj, name, buff, size); - yaffs_GrossUnlock(dev); - - } - T(YAFFS_TRACE_OS, - (TSTR("yaffs_getxattr done returning %d\n"),error)); - - return error; -} - -int yaffs_removexattr(struct dentry *dentry, const char *name) -{ - struct inode *inode = dentry->d_inode; - int error = 0; - yaffs_Device *dev; - yaffs_Object *obj = yaffs_InodeToObject(inode); - - T(YAFFS_TRACE_OS, - (TSTR("yaffs_removexattr of object %d\n"), - obj->objectId)); - - - if (error == 0) { - int result; - dev = obj->myDev; - yaffs_GrossLock(dev); - result = yaffs_RemoveXAttribute(obj, name); - if(result == YAFFS_OK) - error = 0; - else if(result < 0) - error = result; - yaffs_GrossUnlock(dev); - - } - T(YAFFS_TRACE_OS, - (TSTR("yaffs_removexattr done returning %d\n"),error)); - - return error; -} - -ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size) -{ - struct inode *inode = dentry->d_inode; - int error = 0; - yaffs_Device *dev; - yaffs_Object *obj = yaffs_InodeToObject(inode); - - T(YAFFS_TRACE_OS, - (TSTR("yaffs_listxattr of object %d\n"), - obj->objectId)); - - - if (error == 0) { - dev = obj->myDev; - yaffs_GrossLock(dev); - error = yaffs_ListXAttributes(obj, buff, size); - yaffs_GrossUnlock(dev); - - } - T(YAFFS_TRACE_OS, - (TSTR("yaffs_listxattr done returning %d\n"),error)); - - return error; -} - -#endif - - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) { @@ -2153,7 +1691,7 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) yaffs_Device *dev = yaffs_SuperToDevice(sb); #endif - T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n"))); + T(YAFFS_TRACE_OS, ("yaffs_statfs\n")); yaffs_GrossLock(dev); @@ -2167,8 +1705,8 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) uint64_t bytesInDev; uint64_t bytesFree; - bytesInDev = ((uint64_t)((dev->param.endBlock - dev->param.startBlock + 1))) * - ((uint64_t)(dev->param.nChunksPerBlock * dev->nDataBytesPerChunk)); + 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; @@ -2183,16 +1721,16 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) } else if (sb->s_blocksize > dev->nDataBytesPerChunk) { buf->f_blocks = - (dev->param.endBlock - dev->param.startBlock + 1) * - dev->param.nChunksPerBlock / + (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->param.endBlock - dev->param.startBlock + 1) * - dev->param.nChunksPerBlock * + (dev->endBlock - dev->startBlock + 1) * + dev->nChunksPerBlock * (dev->nDataBytesPerChunk / sb->s_blocksize); buf->f_bfree = @@ -2209,238 +1747,27 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) } - -static void yaffs_FlushInodes(struct super_block *sb) -{ - struct inode *iptr; - yaffs_Object *obj; - - list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){ - obj = yaffs_InodeToObject(iptr); - if(obj){ - T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"), - obj->objectId)); - yaffs_FlushFile(obj,1,0); - } - } -} - - -static void yaffs_FlushSuperBlock(struct super_block *sb, int do_checkpoint) -{ - yaffs_Device *dev = yaffs_SuperToDevice(sb); - if(!dev) - return; - - yaffs_FlushInodes(sb); - yaffs_UpdateDirtyDirectories(dev); - yaffs_FlushEntireDeviceCache(dev); - if(do_checkpoint) - yaffs_CheckpointSave(dev); -} - - -static unsigned yaffs_bg_gc_urgency(yaffs_Device *dev) -{ - unsigned erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock; - struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev); - unsigned scatteredFree = 0; /* Free chunks not in an erased block */ - - if(erasedChunks < dev->nFreeChunks) - scatteredFree = (dev->nFreeChunks - erasedChunks); - - if(!context->bgRunning) - return 0; - else if(scatteredFree < (dev->param.nChunksPerBlock * 2)) - return 0; - else if(erasedChunks > dev->nFreeChunks/2) - return 0; - else if(erasedChunks > dev->nFreeChunks/4) - return 1; - else - return 2; -} - -static int yaffs_do_sync_fs(struct super_block *sb, - int request_checkpoint) +static int yaffs_do_sync_fs(struct super_block *sb) { yaffs_Device *dev = yaffs_SuperToDevice(sb); - unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4); - unsigned gc_urgent = yaffs_bg_gc_urgency(dev); - int do_checkpoint; + T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n")); - T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, - (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"), - gc_urgent, - sb->s_dirt ? "dirty" : "clean", - request_checkpoint ? "checkpoint requested" : "no checkpoint", - oneshot_checkpoint ? " one-shot" : "" )); - - yaffs_GrossLock(dev); - do_checkpoint = ((request_checkpoint && !gc_urgent) || - oneshot_checkpoint) && - !dev->isCheckpointed; - - if (sb->s_dirt || do_checkpoint) { - yaffs_FlushSuperBlock(sb, !dev->isCheckpointed && do_checkpoint); - sb->s_dirt = 0; - if(oneshot_checkpoint) - yaffs_auto_checkpoint &= ~4; - } - yaffs_GrossUnlock(dev); - - return 0; -} - -/* - * yaffs background thread functions . - * yaffs_BackgroundThread() the thread function - * yaffs_BackgroundStart() launches the background thread. - * yaffs_BackgroundStop() cleans up the background thread. - * - * NB: - * The thread should only run after the yaffs is initialised - * The thread should be stopped before yaffs is unmounted. - * The thread should not do any writing while the fs is in read only. - */ - -#ifdef YAFFS_COMPILE_BACKGROUND - -void yaffs_background_waker(unsigned long data) -{ - wake_up_process((struct task_struct *)data); -} - -static int yaffs_BackgroundThread(void *data) -{ - yaffs_Device *dev = (yaffs_Device *)data; - struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev); - unsigned long now = jiffies; - unsigned long next_dir_update = now; - unsigned long next_gc = now; - unsigned long expires; - unsigned int urgency; - - int gcResult; - struct timer_list timer; - - T(YAFFS_TRACE_BACKGROUND, - (TSTR("yaffs_background starting for dev %p\n"), - (void *)dev)); - -#ifdef YAFFS_COMPILE_FREEZER - set_freezable(); -#endif - while(context->bgRunning){ - T(YAFFS_TRACE_BACKGROUND, - (TSTR("yaffs_background\n"))); - - if(kthread_should_stop()) - break; - -#ifdef YAFFS_COMPILE_FREEZER - if(try_to_freeze()) - continue; -#endif + if (sb->s_dirt) { yaffs_GrossLock(dev); - now = jiffies; - - if(time_after(now, next_dir_update) && yaffs_bg_enable){ - yaffs_UpdateDirtyDirectories(dev); - next_dir_update = now + HZ; + if (dev) { + yaffs_FlushEntireDeviceCache(dev); + yaffs_CheckpointSave(dev); } - if(time_after(now,next_gc) && yaffs_bg_enable){ - if(!dev->isCheckpointed){ - urgency = yaffs_bg_gc_urgency(dev); - gcResult = yaffs_BackgroundGarbageCollect(dev, urgency); - if(urgency > 1) - next_gc = now + HZ/20+1; - else if(urgency > 0) - next_gc = now + HZ/10+1; - else - next_gc = now + HZ * 2; - } else /* - * gc not running so set to next_dir_update - * to cut down on wake ups - */ - next_gc = next_dir_update; - } yaffs_GrossUnlock(dev); -#if 1 - expires = next_dir_update; - if (time_before(next_gc,expires)) - expires = next_gc; - if(time_before(expires,now)) - expires = now + HZ; - Y_INIT_TIMER(&timer); - timer.expires = expires+1; - timer.data = (unsigned long) current; - timer.function = yaffs_background_waker; - - set_current_state(TASK_INTERRUPTIBLE); - add_timer(&timer); - schedule(); - del_timer_sync(&timer); -#else - msleep(10); -#endif + sb->s_dirt = 0; } - return 0; } -static int yaffs_BackgroundStart(yaffs_Device *dev) -{ - int retval = 0; - struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev); - - if(dev->readOnly) - return -1; - - context->bgRunning = 1; - - context->bgThread = kthread_run(yaffs_BackgroundThread, - (void *)dev,"yaffs-bg-%d",context->mount_id); - - if(IS_ERR(context->bgThread)){ - retval = PTR_ERR(context->bgThread); - context->bgThread = NULL; - context->bgRunning = 0; - } - return retval; -} - -static void yaffs_BackgroundStop(yaffs_Device *dev) -{ - struct yaffs_LinuxContext *ctxt = yaffs_DeviceToLC(dev); - - ctxt->bgRunning = 0; - - if( ctxt->bgThread){ - kthread_stop(ctxt->bgThread); - ctxt->bgThread = NULL; - } -} -#else -static int yaffs_BackgroundThread(void *data) -{ - return 0; -} - -static int yaffs_BackgroundStart(yaffs_Device *dev) -{ - return 0; -} - -static void yaffs_BackgroundStop(yaffs_Device *dev) -{ -} -#endif - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) static void yaffs_write_super(struct super_block *sb) @@ -2448,14 +1775,10 @@ static void yaffs_write_super(struct super_block *sb) static int yaffs_write_super(struct super_block *sb) #endif { - unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2); - - T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, - (TSTR("yaffs_write_super%s\n"), - request_checkpoint ? " checkpt" : "")); - - yaffs_do_sync_fs(sb, request_checkpoint); + T(YAFFS_TRACE_OS, ("yaffs_write_super\n")); + if (yaffs_auto_checkpoint >= 2) + yaffs_do_sync_fs(sb); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) return 0; #endif @@ -2468,13 +1791,10 @@ static int yaffs_sync_fs(struct super_block *sb, int wait) static int yaffs_sync_fs(struct super_block *sb) #endif { - unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1); + T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n")); - T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, - (TSTR("yaffs_sync_fs%s\n"), - request_checkpoint ? " checkpt" : "")); - - yaffs_do_sync_fs(sb, request_checkpoint); + if (yaffs_auto_checkpoint >= 1) + yaffs_do_sync_fs(sb); return 0; } @@ -2488,7 +1808,7 @@ static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) yaffs_Device *dev = yaffs_SuperToDevice(sb); T(YAFFS_TRACE_OS, - (TSTR("yaffs_iget for %lu\n"), ino)); + ("yaffs_iget for %lu\n", ino)); inode = iget_locked(sb, ino); if (!inode) @@ -2526,55 +1846,76 @@ static void yaffs_read_inode(struct inode *inode) yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb); T(YAFFS_TRACE_OS, - (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino)); + ("yaffs_read_inode for %d\n", (int)inode->i_ino)); - if(current != yaffs_DeviceToLC(dev)->readdirProcess) - yaffs_GrossLock(dev); + yaffs_GrossLock(dev); obj = yaffs_FindObjectByNumber(dev, inode->i_ino); yaffs_FillInodeFromObject(inode, obj); - if(current != yaffs_DeviceToLC(dev)->readdirProcess) - yaffs_GrossUnlock(dev); + yaffs_GrossUnlock(dev); } #endif -static YLIST_HEAD(yaffs_context_list); -struct semaphore yaffs_context_lock; +static YLIST_HEAD(yaffs_dev_list); + +#if 0 /* not used */ +static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) +{ + yaffs_Device *dev = yaffs_SuperToDevice(sb); + + if (*flags & MS_RDONLY) { + struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; + + T(YAFFS_TRACE_OS, + ("yaffs_remount_fs: %s: RO\n", dev->name)); + + yaffs_GrossLock(dev); + + yaffs_FlushEntireDeviceCache(dev); + + yaffs_CheckpointSave(dev); + + if (mtd->sync) + mtd->sync(mtd); + + yaffs_GrossUnlock(dev); + } else { + T(YAFFS_TRACE_OS, + ("yaffs_remount_fs: %s: RW\n", dev->name)); + } + + return 0; +} +#endif static void yaffs_put_super(struct super_block *sb) { yaffs_Device *dev = yaffs_SuperToDevice(sb); - T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n"))); - - T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, - (TSTR("Shutting down yaffs background thread\n"))); - yaffs_BackgroundStop(dev); - T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, - (TSTR("yaffs background thread shut down\n"))); + T(YAFFS_TRACE_OS, ("yaffs_put_super\n")); yaffs_GrossLock(dev); - yaffs_FlushSuperBlock(sb,1); + yaffs_FlushEntireDeviceCache(dev); - if (yaffs_DeviceToLC(dev)->putSuperFunc) - yaffs_DeviceToLC(dev)->putSuperFunc(sb); + yaffs_CheckpointSave(dev); + if (dev->putSuperFunc) + dev->putSuperFunc(sb); yaffs_Deinitialise(dev); yaffs_GrossUnlock(dev); - down(&yaffs_context_lock); - ylist_del_init(&(yaffs_DeviceToLC(dev)->contextList)); - up(&yaffs_context_lock); + /* we assume this is protected by lock_kernel() in mount/umount */ + ylist_del(&dev->devList); - if (yaffs_DeviceToLC(dev)->spareBuffer) { - YFREE(yaffs_DeviceToLC(dev)->spareBuffer); - yaffs_DeviceToLC(dev)->spareBuffer = NULL; + if (dev->spareBuffer) { + YFREE(dev->spareBuffer); + dev->spareBuffer = NULL; } kfree(dev); @@ -2583,7 +1924,7 @@ static void yaffs_put_super(struct super_block *sb) static void yaffs_MTDPutSuper(struct super_block *sb) { - struct mtd_info *mtd = yaffs_DeviceToMtd(yaffs_SuperToDevice(sb)); + struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; if (mtd->sync) mtd->sync(mtd); @@ -2592,11 +1933,11 @@ static void yaffs_MTDPutSuper(struct super_block *sb) } -static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev) +static void yaffs_MarkSuperBlockDirty(void *vsb) { - struct super_block *sb = yaffs_DeviceToLC(dev)->superBlock; + struct super_block *sb = (struct super_block *)vsb; - T(YAFFS_TRACE_OS, (TSTR("yaffs_MarkSuperBlockDirty() sb = %p\n"), sb)); + T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb)); if (sb) sb->s_dirt = 1; } @@ -2606,15 +1947,11 @@ typedef struct { int skip_checkpoint_read; int skip_checkpoint_write; int no_cache; - int tags_ecc_on; - int tags_ecc_overridden; - int lazy_loading_enabled; - int lazy_loading_overridden; - int empty_lost_and_found; int empty_lost_and_found_overridden; + int empty_lost_and_found; } yaffs_options; -#define MAX_OPT_LEN 30 +#define MAX_OPT_LEN 20 static int yaffs_parse_options(yaffs_options *options, const char *options_str) { char cur_opt[MAX_OPT_LEN + 1]; @@ -2627,7 +1964,7 @@ static int yaffs_parse_options(yaffs_options *options, const char *options_str) memset(cur_opt, 0, MAX_OPT_LEN + 1); p = 0; - while(*options_str == ',') + while (*options_str == ',') options_str++; while (*options_str && *options_str != ',') { @@ -2640,25 +1977,7 @@ static int yaffs_parse_options(yaffs_options *options, const char *options_str) if (!strcmp(cur_opt, "inband-tags")) options->inband_tags = 1; - else if (!strcmp(cur_opt, "tags-ecc-off")){ - options->tags_ecc_on = 0; - options->tags_ecc_overridden=1; - } else if (!strcmp(cur_opt, "tags-ecc-on")){ - options->tags_ecc_on = 1; - options->tags_ecc_overridden = 1; - } else if (!strcmp(cur_opt, "lazy-loading-off")){ - options->lazy_loading_enabled = 0; - options->lazy_loading_overridden=1; - } else if (!strcmp(cur_opt, "lazy-loading-on")){ - options->lazy_loading_enabled = 1; - options->lazy_loading_overridden = 1; - } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){ - options->empty_lost_and_found = 0; - options->empty_lost_and_found_overridden=1; - } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){ - options->empty_lost_and_found = 1; - options->empty_lost_and_found_overridden=1; - } else if (!strcmp(cur_opt, "no-cache")) + else if (!strcmp(cur_opt, "no-cache")) options->no_cache = 1; else if (!strcmp(cur_opt, "no-checkpoint-read")) options->skip_checkpoint_read = 1; @@ -2667,6 +1986,12 @@ static int yaffs_parse_options(yaffs_options *options, const char *options_str) else if (!strcmp(cur_opt, "no-checkpoint")) { options->skip_checkpoint_read = 1; options->skip_checkpoint_write = 1; + } else if (!strcmp(cur_opt, "empty-lost-and-found-disable")) { + options->empty_lost_and_found = 0; + options->empty_lost_and_found_overridden = 1; + } else if (!strcmp(cur_opt, "empty-lost-and-found-enable")) { + options->empty_lost_and_found = 1; + options->empty_lost_and_found_overridden = 1; } else { printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n", cur_opt); @@ -2689,29 +2014,13 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, struct mtd_info *mtd; int err; char *data_str = (char *)data; - struct yaffs_LinuxContext *context = NULL; - yaffs_DeviceParam *param; - - int readOnly = 0; yaffs_options options; - unsigned mount_id; - int found; - struct yaffs_LinuxContext *context_iterator; - struct ylist_head *l; - sb->s_magic = YAFFS_MAGIC; sb->s_op = &yaffs_super_ops; sb->s_flags |= MS_NOATIME; - readOnly =((sb->s_flags & MS_RDONLY) != 0); - - -#ifdef YAFFS_COMPILE_EXPORTFS - sb->s_export_op = &yaffs_export_ops; -#endif - if (!sb) printk(KERN_INFO "yaffs: sb is NULL\n"); else if (!sb->s_dev) @@ -2719,10 +2028,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, else if (!yaffs_devname(sb, devname_buf)) printk(KERN_INFO "yaffs: devname is NULL\n"); else - printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n", + printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n", sb->s_dev, - yaffs_devname(sb, devname_buf), - readOnly ? "ro" : "rw"); + yaffs_devname(sb, devname_buf)); if (!data_str) data_str = ""; @@ -2739,17 +2047,20 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - + T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion)); T(YAFFS_TRACE_OS, - (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffsVersion)); - T(YAFFS_TRACE_OS, - (TSTR("yaffs_read_super: block size %d\n"), - (int)(sb->s_blocksize))); + ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize))); - T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"), - MAJOR(sb->s_dev), MINOR(sb->s_dev), - yaffs_devname(sb, devname_buf))); +#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY + T(YAFFS_TRACE_OS, + ("yaffs: Write verification disabled. All guarantees " + "null and void\n")); +#endif + + T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, " + "\"%s\"\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev), + yaffs_devname(sb, devname_buf))); /* Check it's an mtd device..... */ if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) @@ -2759,46 +2070,50 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); if (!mtd) { T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"), - MINOR(sb->s_dev))); + ("yaffs: MTD device #%u doesn't appear to exist\n", + MINOR(sb->s_dev))); return NULL; } /* Check it's NAND */ if (mtd->type != MTD_NANDFLASH) { T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs: MTD device is not NAND it's type %d\n"), - mtd->type)); + ("yaffs: MTD device is not NAND it's type %d\n", mtd->type)); return NULL; } - T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase)); - T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read)); - T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write)); - T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob)); - T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob)); - T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad)); - T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad)); - T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd))); - T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize)); - T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize)); + T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase)); + T(YAFFS_TRACE_OS, (" read %p\n", mtd->read)); + T(YAFFS_TRACE_OS, (" write %p\n", mtd->write)); + T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob)); + T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob)); + T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad)); + T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad)); + T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd))); + T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize)); + T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize)); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) - T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size)); + T(YAFFS_TRACE_OS, (" size %u\n", mtd->size)); #else - T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size)); + T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size)); #endif + +#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND + dev->emptyLostAndFound = 1; +#endif + if(options.empty_lost_and_found_overridden) + dev->emptyLostAndFound = options.empty_lost_and_found; + #ifdef CONFIG_YAFFS_AUTO_YAFFS2 if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) { - T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs: auto selecting yaffs2\n"))); + T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n")); yaffsVersion = 2; } /* Added NCB 26/5/2006 for completeness */ if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) { - T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs: auto selecting yaffs1\n"))); + T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n")); yaffsVersion = 1; } @@ -2818,8 +2133,8 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { #endif T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs: MTD device does not support required " - "functions\n"))); + ("yaffs: MTD device does not support required " + "functions\n"));; return NULL; } @@ -2827,8 +2142,8 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && !options.inband_tags) { T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs: MTD device does not have the " - "right page sizes\n"))); + ("yaffs: MTD device does not have the " + "right page sizes\n")); return NULL; } } else { @@ -2843,16 +2158,16 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { #endif T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs: MTD device does not support required " - "functions\n"))); + ("yaffs: MTD device does not support required " + "functions\n"));; return NULL; } if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || mtd->oobsize != YAFFS_BYTES_PER_SPARE) { T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs: MTD device does not support have the " - "right page sizes\n"))); + ("yaffs: MTD device does not support have the " + "right page sizes\n")); return NULL; } } @@ -2862,196 +2177,108 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, * Set the yaffs_Device up for mtd */ - if (!readOnly && !(mtd->flags & MTD_WRITEABLE)){ - readOnly = 1; - printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only"); - sb->s_flags |= MS_RDONLY; - } - - dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); - context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL); - - if(!dev || !context ){ - if(dev) - kfree(dev); - if(context) - kfree(context); - dev = NULL; - context = NULL; - } - +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) + sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); +#else + sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); +#endif if (!dev) { /* Deep shit could not allocate device structure */ T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs_read_super: Failed trying to allocate " - "yaffs_Device. \n"))); + ("yaffs_read_super: Failed trying to allocate " + "yaffs_Device. \n")); return NULL; } + memset(dev, 0, sizeof(yaffs_Device)); - param = &(dev->param); - - memset(context,0,sizeof(struct yaffs_LinuxContext)); - dev->osContext = context; - YINIT_LIST_HEAD(&(context->contextList)); - context->dev = dev; - context->superBlock = sb; - - dev->readOnly = readOnly; - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) - sb->s_fs_info = dev; -#else - sb->u.generic_sbp = dev; -#endif - - dev->driverContext = mtd; - param->name = mtd->name; + dev->genericDevice = mtd; + dev->name = mtd->name; /* Set up the memory size parameters.... */ nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK)); - param->startBlock = 0; - param->endBlock = nBlocks - 1; - param->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; - param->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK; - param->nReservedBlocks = 5; - param->nShortOpCaches = (options.no_cache) ? 0 : 10; - param->inbandTags = options.inband_tags; - -#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD - param->disableLazyLoad = 1; -#endif -#ifdef CONFIG_YAFFS_XATTR - param->enableXattr = 1; -#endif - if(options.lazy_loading_overridden) - param->disableLazyLoad = !options.lazy_loading_enabled; - -#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC - param->noTagsECC = 1; -#endif - -#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND -#else - param->deferDirectoryUpdate = 1; -#endif - - if(options.tags_ecc_overridden) - param->noTagsECC = !options.tags_ecc_on; - -#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND - param->emptyLostAndFound = 1; -#endif - -#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING - param->refreshPeriod = 0; -#else - param->refreshPeriod = 500; -#endif - -#ifdef CONFIG_YAFFS__ALWAYS_CHECK_CHUNK_ERASED - param->alwaysCheckErased = 1; -#endif - - if(options.empty_lost_and_found_overridden) - param->emptyLostAndFound = options.empty_lost_and_found; + dev->startBlock = 0; + dev->endBlock = nBlocks - 1; + dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; + dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK; + dev->nReservedBlocks = 5; + dev->nShortOpCaches = (options.no_cache) ? 0 : 10; + dev->inbandTags = options.inband_tags; /* ... and the functions. */ if (yaffsVersion == 2) { - param->writeChunkWithTagsToNAND = + dev->writeChunkWithTagsToNAND = nandmtd2_WriteChunkWithTagsToNAND; - param->readChunkWithTagsFromNAND = + dev->readChunkWithTagsFromNAND = nandmtd2_ReadChunkWithTagsFromNAND; - param->markNANDBlockBad = nandmtd2_MarkNANDBlockBad; - param->queryNANDBlock = nandmtd2_QueryNANDBlock; - yaffs_DeviceToLC(dev)->spareBuffer = YMALLOC(mtd->oobsize); - param->isYaffs2 = 1; + dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad; + dev->queryNANDBlock = nandmtd2_QueryNANDBlock; + dev->spareBuffer = YMALLOC(mtd->oobsize); + dev->isYaffs2 = 1; #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) - param->totalBytesPerChunk = mtd->writesize; - param->nChunksPerBlock = mtd->erasesize / mtd->writesize; + dev->totalBytesPerChunk = mtd->writesize; + dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; #else - param->totalBytesPerChunk = mtd->oobblock; - param->nChunksPerBlock = mtd->erasesize / mtd->oobblock; + dev->totalBytesPerChunk = mtd->oobblock; + dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; #endif nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize); - param->startBlock = 0; - param->endBlock = nBlocks - 1; + dev->startBlock = 0; + dev->endBlock = nBlocks - 1; } else { #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) /* use the MTD interface in yaffs_mtdif1.c */ - param->writeChunkWithTagsToNAND = + dev->writeChunkWithTagsToNAND = nandmtd1_WriteChunkWithTagsToNAND; - param->readChunkWithTagsFromNAND = + dev->readChunkWithTagsFromNAND = nandmtd1_ReadChunkWithTagsFromNAND; - param->markNANDBlockBad = nandmtd1_MarkNANDBlockBad; - param->queryNANDBlock = nandmtd1_QueryNANDBlock; + dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad; + dev->queryNANDBlock = nandmtd1_QueryNANDBlock; #else - param->writeChunkToNAND = nandmtd_WriteChunkToNAND; - param->readChunkFromNAND = nandmtd_ReadChunkFromNAND; + dev->writeChunkToNAND = nandmtd_WriteChunkToNAND; + dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND; #endif - param->isYaffs2 = 0; + dev->isYaffs2 = 0; } /* ... and common functions */ - param->eraseBlockInNAND = nandmtd_EraseBlockInNAND; - param->initialiseNAND = nandmtd_InitialiseNAND; + dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND; + dev->initialiseNAND = nandmtd_InitialiseNAND; - yaffs_DeviceToLC(dev)->putSuperFunc = yaffs_MTDPutSuper; + dev->putSuperFunc = yaffs_MTDPutSuper; - param->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; - param->gcControl = yaffs_gc_control_callback; + dev->superBlock = (void *)sb; + dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; - yaffs_DeviceToLC(dev)->superBlock= sb; - #ifndef CONFIG_YAFFS_DOES_ECC - param->useNANDECC = 1; + dev->useNANDECC = 1; #endif #ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES - param->wideTnodesDisabled = 1; + dev->wideTnodesDisabled = 1; #endif - param->skipCheckpointRead = options.skip_checkpoint_read; - param->skipCheckpointWrite = options.skip_checkpoint_write; + dev->skipCheckpointRead = options.skip_checkpoint_read; + dev->skipCheckpointWrite = options.skip_checkpoint_write; - down(&yaffs_context_lock); - /* Get a mount id */ - found = 0; - for(mount_id=0; ! found; mount_id++){ - found = 1; - ylist_for_each(l,&yaffs_context_list){ - context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList); - if(context_iterator->mount_id == mount_id) - found = 0; - } - } - context->mount_id = mount_id; - - ylist_add_tail(&(yaffs_DeviceToLC(dev)->contextList), &yaffs_context_list); - up(&yaffs_context_lock); + /* we assume this is protected by lock_kernel() in mount/umount */ + ylist_add_tail(&dev->devList, &yaffs_dev_list); /* Directory search handling...*/ - YINIT_LIST_HEAD(&(yaffs_DeviceToLC(dev)->searchContexts)); - param->removeObjectCallback = yaffs_RemoveObjectCallback; + YINIT_LIST_HEAD(&dev->searchContexts); + dev->removeObjectCallback = yaffs_RemoveObjectCallback; - init_MUTEX(&(yaffs_DeviceToLC(dev)->grossLock)); + init_MUTEX(&dev->grossLock); yaffs_GrossLock(dev); err = yaffs_GutsInitialise(dev); T(YAFFS_TRACE_OS, - (TSTR("yaffs_read_super: guts initialised %s\n"), + ("yaffs_read_super: guts initialised %s\n", (err == YAFFS_OK) ? "OK" : "FAILED")); - - if(err == YAFFS_OK) - yaffs_BackgroundStart(dev); - - if(!context->bgThread) - param->deferDirectoryUpdate = 0; - /* Release lock before yaffs_get_inode() */ yaffs_GrossUnlock(dev); @@ -3067,11 +2294,11 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, inode->i_op = &yaffs_dir_inode_operations; inode->i_fop = &yaffs_dir_operations; - T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n"))); + T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n")); root = d_alloc_root(inode); - T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n"))); + T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n")); if (!root) { iput(inode); @@ -3080,10 +2307,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, sb->s_root = root; sb->s_dirt = !dev->isCheckpointed; T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs_read_super: isCheckpointed %d\n"), - dev->isCheckpointed)); + ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed)); - T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n"))); + T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n")); return sb; } @@ -3183,63 +2409,45 @@ static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, #endif /* CONFIG_YAFFS_YAFFS2 */ static struct proc_dir_entry *my_proc_entry; -static struct proc_dir_entry *debug_proc_entry; -static char *yaffs_dump_dev_part0(char *buf, yaffs_Device * dev) -{ - buf += sprintf(buf, "startBlock......... %d\n", dev->param.startBlock); - buf += sprintf(buf, "endBlock........... %d\n", dev->param.endBlock); - buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->param.totalBytesPerChunk); - buf += sprintf(buf, "useNANDECC......... %d\n", dev->param.useNANDECC); - buf += sprintf(buf, "noTagsECC.......... %d\n", dev->param.noTagsECC); - buf += sprintf(buf, "isYaffs2........... %d\n", dev->param.isYaffs2); - buf += sprintf(buf, "inbandTags......... %d\n", dev->param.inbandTags); - buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->param.emptyLostAndFound); - buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->param.disableLazyLoad); - buf += sprintf(buf, "refreshPeriod...... %d\n", dev->param.refreshPeriod); - buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->param.nShortOpCaches); - buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->param.nReservedBlocks); - buf += sprintf(buf, "alwaysCheckErased.. %d\n", dev->param.alwaysCheckErased); - - buf += sprintf(buf, "\n"); - - return buf; -} - - -static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev) +static char *yaffs_dump_dev(char *buf, yaffs_Device * dev) { + buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock); + buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); + buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk); buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk); buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits); buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize); buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks); + buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks); buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint); - buf += sprintf(buf, "\n"); - buf += sprintf(buf, "nTnodes............ %d\n", dev->nTnodes); - buf += sprintf(buf, "nObjects........... %d\n", dev->nObjects); + buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated); + buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes); + buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated); + buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects); buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks); - buf += sprintf(buf, "\n"); - buf += sprintf(buf, "nPageWrites........ %u\n", dev->nPageWrites); - buf += sprintf(buf, "nPageReads......... %u\n", dev->nPageReads); - buf += sprintf(buf, "nBlockErasures..... %u\n", dev->nBlockErasures); - buf += sprintf(buf, "nGCCopies.......... %u\n", dev->nGCCopies); - buf += sprintf(buf, "allGCs............. %u\n", dev->allGCs); - buf += sprintf(buf, "passiveGCs......... %u\n", dev->passiveGCs); - buf += sprintf(buf, "oldestDirtyGCs..... %u\n", dev->oldestDirtyGCs); - buf += sprintf(buf, "nGCBlocks.......... %u\n", dev->nGCBlocks); - buf += sprintf(buf, "backgroundGCs...... %u\n", dev->backgroundGCs); - buf += sprintf(buf, "nRetriedWrites..... %u\n", dev->nRetriedWrites); - buf += sprintf(buf, "nRetireBlocks...... %u\n", dev->nRetiredBlocks); - buf += sprintf(buf, "eccFixed........... %u\n", dev->eccFixed); - buf += sprintf(buf, "eccUnfixed......... %u\n", dev->eccUnfixed); - buf += sprintf(buf, "tagsEccFixed....... %u\n", dev->tagsEccFixed); - buf += sprintf(buf, "tagsEccUnfixed..... %u\n", dev->tagsEccUnfixed); - buf += sprintf(buf, "cacheHits.......... %u\n", dev->cacheHits); - buf += sprintf(buf, "nDeletedFiles...... %u\n", dev->nDeletedFiles); - buf += sprintf(buf, "nUnlinkedFiles..... %u\n", dev->nUnlinkedFiles); - buf += sprintf(buf, "refreshCount....... %u\n", dev->refreshCount); + buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites); + buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads); + buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures); + buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies); + buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections); + buf += sprintf(buf, "passiveGCs......... %d\n", + dev->passiveGarbageCollections); + buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites); + buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches); + buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks); + buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed); + buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed); + buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed); + buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed); + buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits); + buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles); + buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles); buf += - sprintf(buf, "nBackgroudDeletions %u\n", dev->nBackgroundDeletions); + 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; } @@ -3262,64 +2470,27 @@ static int yaffs_proc_read(char *page, *(int *)start = 1; /* Print header first */ - if (step == 0) - buf += sprintf(buf, "Multi-version YAFFS built:" __DATE__ " " __TIME__"\n"); - else if (step == 1) - buf += sprintf(buf,"\n"); - else { - step-=2; - - down(&yaffs_context_lock); - - /* Locate and print the Nth entry. Order N-squared but N is small. */ - ylist_for_each(item, &yaffs_context_list) { - struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList); - yaffs_Device *dev = dc->dev; - - if (n < (step & ~1)) { - n+=2; - continue; - } - if((step & 1)==0){ - buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->param.name); - buf = yaffs_dump_dev_part0(buf, dev); - } else - buf = yaffs_dump_dev_part1(buf, dev); - - break; - } - up(&yaffs_context_lock); + if (step == 0) { + buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__ + "\n%s\n%s\n", yaffs_fs_c_version, + yaffs_guts_c_version); } - return buf - page < count ? buf - page : count; -} - -static int yaffs_stats_proc_read(char *page, - char **start, - off_t offset, int count, int *eof, void *data) -{ - struct ylist_head *item; - char *buf = page; - int n = 0; - - down(&yaffs_context_lock); + /* hold lock_kernel while traversing yaffs_dev_list */ + lock_kernel(); /* Locate and print the Nth entry. Order N-squared but N is small. */ - ylist_for_each(item, &yaffs_context_list) { - struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList); - yaffs_Device *dev = dc->dev; - - int erasedChunks; - - erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock; - - buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n", - n, dev->nFreeChunks, erasedChunks, - dev->backgroundGCs, dev->oldestDirtyGCs, - dev->nObjects, dev->nTnodes); + ylist_for_each(item, &yaffs_dev_list) { + yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList); + if (n < step) { + n++; + continue; + } + buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name); + buf = yaffs_dump_dev(buf, dev); + break; } - up(&yaffs_context_lock); - + unlock_kernel(); return buf - page < count ? buf - page : count; } @@ -3336,7 +2507,6 @@ static struct { } mask_flags[] = { {"allocate", YAFFS_TRACE_ALLOCATE}, {"always", YAFFS_TRACE_ALWAYS}, - {"background", YAFFS_TRACE_BACKGROUND}, {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, {"buffers", YAFFS_TRACE_BUFFERS}, {"bug", YAFFS_TRACE_BUG}, @@ -3346,28 +2516,26 @@ static struct { {"error", YAFFS_TRACE_ERROR}, {"gc_detail", YAFFS_TRACE_GC_DETAIL}, {"gc", YAFFS_TRACE_GC}, - {"lock", YAFFS_TRACE_LOCK}, {"mtd", YAFFS_TRACE_MTD}, {"nandaccess", YAFFS_TRACE_NANDACCESS}, {"os", YAFFS_TRACE_OS}, {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, {"scan", YAFFS_TRACE_SCAN}, {"tracing", YAFFS_TRACE_TRACING}, - {"sync", YAFFS_TRACE_SYNC}, - {"write", YAFFS_TRACE_WRITE}, {"verify", YAFFS_TRACE_VERIFY}, {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, {"verify_full", YAFFS_TRACE_VERIFY_FULL}, {"verify_all", YAFFS_TRACE_VERIFY_ALL}, + {"write", YAFFS_TRACE_WRITE}, {"all", 0xffffffff}, {"none", 0}, {NULL, 0}, }; #define MAX_MASK_NAME_LENGTH 40 -static int yaffs_proc_write_trace_options(struct file *file, const char *buf, +static int yaffs_proc_write(struct file *file, const char *buf, unsigned long count, void *data) { unsigned rg = 0, mask_bitfield; @@ -3451,8 +2619,7 @@ static int yaffs_proc_write_trace_options(struct file *file, const char *buf, if (rg & YAFFS_TRACE_ALWAYS) { for (i = 0; mask_flags[i].mask_name != NULL; i++) { char flag; - flag = ((rg & mask_flags[i].mask_bitfield) == - mask_flags[i].mask_bitfield) ? '+' : '-'; + flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-'; printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name); } } @@ -3460,13 +2627,6 @@ static int yaffs_proc_write_trace_options(struct file *file, const char *buf, return count; } - -static int yaffs_proc_write(struct file *file, const char *buf, - unsigned long count, void *data) -{ - return yaffs_proc_write_trace_options(file, buf, count, data); -} - /* Stuff to handle installation of file systems */ struct file_system_to_install { struct file_system_type *fst; @@ -3485,19 +2645,9 @@ static int __init init_yaffs_fs(void) struct file_system_to_install *fsinst; T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n"))); + ("yaffs " __DATE__ " " __TIME__ " Installing. \n")); -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED - T(YAFFS_TRACE_ALWAYS, - (TSTR(" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n"))); -#endif - - - - - init_MUTEX(&yaffs_context_lock); - - /* Install the proc_fs entries */ + /* Install the proc_fs entry */ my_proc_entry = create_proc_entry("yaffs", S_IRUGO | S_IFREG, YPROC_ROOT); @@ -3509,17 +2659,6 @@ static int __init init_yaffs_fs(void) } else return -ENOMEM; - debug_proc_entry = create_proc_entry("yaffs_stats", - S_IRUGO | S_IFREG, - YPROC_ROOT); - - if (debug_proc_entry) { - debug_proc_entry->write_proc = NULL; - debug_proc_entry->read_proc = yaffs_stats_proc_read; - debug_proc_entry->data = NULL; - } else - return -ENOMEM; - /* Now add the file system entries */ fsinst = fs_to_install; @@ -3552,11 +2691,10 @@ static void __exit exit_yaffs_fs(void) struct file_system_to_install *fsinst; - T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n"))); + T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__ + " removing. \n")); remove_proc_entry("yaffs", YPROC_ROOT); - remove_proc_entry("yaffs_stats", YPROC_ROOT); fsinst = fs_to_install; @@ -3573,5 +2711,5 @@ module_init(init_yaffs_fs) module_exit(exit_yaffs_fs) MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); -MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010"); +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006"); MODULE_LICENSE("GPL"); diff --git a/fs/yaffs2/yaffs_getblockinfo.h b/fs/yaffs2/yaffs_getblockinfo.h index 71fe1dee..5b0a1ac2 100644 --- a/fs/yaffs2/yaffs_getblockinfo.h +++ b/fs/yaffs2/yaffs_getblockinfo.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -17,7 +17,6 @@ #define __YAFFS_GETBLOCKINFO_H__ #include "yaffs_guts.h" -#include "yaffs_trace.h" /* Function to manipulate block info */ static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk) diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c index 7e97a5f0..5003e52f 100644 --- a/fs/yaffs2/yaffs_guts.c +++ b/fs/yaffs2/yaffs_guts.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -10,8 +10,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +const char *yaffs_guts_c_version = + "$Id$"; + #include "yportenv.h" -#include "yaffs_trace.h" #include "yaffsinterface.h" #include "yaffs_guts.h" @@ -19,28 +22,22 @@ #include "yaffs_getblockinfo.h" #include "yaffs_tagscompat.h" - +#ifndef CONFIG_YAFFS_USE_OWN_SORT +#include "yaffs_qsort.h" +#endif #include "yaffs_nand.h" -#include "yaffs_yaffs1.h" -#include "yaffs_yaffs2.h" -#include "yaffs_bitmap.h" -#include "yaffs_verify.h" +#include "yaffs_checkptrw.h" #include "yaffs_nand.h" #include "yaffs_packedtags2.h" -#include "yaffs_nameval.h" -#include "yaffs_allocator.h" -/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ -#define YAFFS_GC_GOOD_ENOUGH 2 -#define YAFFS_GC_PASSIVE_THRESHOLD 4 +#define YAFFS_PASSIVE_GC_CHUNKS 2 #include "yaffs_ecc.h" - /* Robustification (if it ever comes about...) */ static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND); static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, @@ -56,22 +53,30 @@ static void yaffs_UpdateParent(yaffs_Object *obj); static int yaffs_UnlinkObject(yaffs_Object *obj); static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj); +static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList); + static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve); - +static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, + int chunkInNAND, int inScan); static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, yaffs_ObjectType type); - - -static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod); - +static void yaffs_AddObjectToDirectory(yaffs_Object *directory, + yaffs_Object *obj); +static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, + int force, int isShrink, int shadows); static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj); static int yaffs_CheckStructures(void); +/*static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, + int chunkOffset, int *limit);*/ /*Mark the unused function to remove warning message*/ static int yaffs_DoGenericObjectDeletion(yaffs_Object *in); +static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo); + + static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, int chunkInNAND); @@ -83,23 +88,30 @@ static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, yaffs_BlockInfo **blockUsedPtr); +static void yaffs_VerifyFreeChunks(yaffs_Device *dev); + static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in); +static void yaffs_VerifyDirectory(yaffs_Object *directory); +#ifdef YAFFS_PARANOID +static int yaffs_CheckFileSanity(yaffs_Object *in); +#else +#define yaffs_CheckFileSanity(in) +#endif + static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in); static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId); +static void yaffs_InvalidateCheckpoint(yaffs_Device *dev); + static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode, yaffs_ExtendedTags *tags); -static int yaffs_VerifyChunkWritten(yaffs_Device *dev, - int chunkInNAND, - const __u8 *data, - yaffs_ExtendedTags *tags); - - -static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize); -static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev,YCHAR *ohName, const YCHAR *name); - +static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, + unsigned pos); +static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, + yaffs_FileStructure *fStruct, + __u32 chunkId); /* Function to calculate chunk and offset */ @@ -160,7 +172,7 @@ static __u32 ShiftsGE(__u32 x) static __u32 Shifts(__u32 x) { - __u32 nShifts; + int nShifts; nShifts = 0; @@ -191,7 +203,7 @@ static int yaffs_InitialiseTempBuffers(yaffs_Device *dev) 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->param.totalBytesPerChunk); + YMALLOC_DMA(dev->totalBytesPerChunk); } return buf ? YAFFS_OK : YAFFS_FAIL; @@ -274,7 +286,7 @@ int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer) return 1; } - for (i = 0; i < dev->param.nShortOpCaches; i++) { + for (i = 0; i < dev->nShortOpCaches; i++) { if (dev->srCache[i].data == buffer) return 1; } @@ -287,11 +299,557 @@ int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer) return 0; } + + +/* + * Chunk bitmap manipulations + */ + +static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk) +{ + if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { + T(YAFFS_TRACE_ERROR, + (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR), + blk)); + YBUG(); + } + return dev->chunkBits + + (dev->chunkBitmapStride * (blk - dev->internalStartBlock)); +} + +static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk) +{ + if (blk < dev->internalStartBlock || blk > dev->internalEndBlock || + chunk < 0 || chunk >= dev->nChunksPerBlock) { + T(YAFFS_TRACE_ERROR, + (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR), + blk, chunk)); + YBUG(); + } +} + +static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk) +{ + __u8 *blkBits = yaffs_BlockBits(dev, blk); + + memset(blkBits, 0, dev->chunkBitmapStride); +} + +static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk) +{ + __u8 *blkBits = yaffs_BlockBits(dev, blk); + + yaffs_VerifyChunkBitId(dev, blk, chunk); + + blkBits[chunk / 8] &= ~(1 << (chunk & 7)); +} + +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)); +} + +static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk) +{ + __u8 *blkBits = yaffs_BlockBits(dev, blk); + yaffs_VerifyChunkBitId(dev, blk, chunk); + + return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; +} + +static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk) +{ + __u8 *blkBits = yaffs_BlockBits(dev, blk); + int i; + for (i = 0; i < dev->chunkBitmapStride; i++) { + if (*blkBits) + return 1; + blkBits++; + } + return 0; +} + +static int yaffs_CountChunkBits(yaffs_Device *dev, int blk) +{ + __u8 *blkBits = yaffs_BlockBits(dev, blk); + int i; + int n = 0; + for (i = 0; i < dev->chunkBitmapStride; i++) { + __u8 x = *blkBits; + while (x) { + if (x & 1) + n++; + x >>= 1; + } + + blkBits++; + } + return n; +} + /* * Verification code */ +static int yaffs_SkipVerification(yaffs_Device *dev) +{ + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); +} +static int yaffs_SkipFullVerification(yaffs_Device *dev) +{ + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); +} + +static int yaffs_SkipNANDVerification(yaffs_Device *dev) +{ + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); +} + +static const char *blockStateName[] = { +"Unknown", +"Needs scanning", +"Scanning", +"Empty", +"Allocating", +"Full", +"Dirty", +"Checkpoint", +"Collecting", +"Dead" +}; + +static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n) +{ + int actuallyUsed; + int inUse; + + if (yaffs_SkipVerification(dev)) + return; + + /* Report illegal runtime states */ + if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState)); + + switch (bi->blockState) { + case YAFFS_BLOCK_STATE_UNKNOWN: + case YAFFS_BLOCK_STATE_SCANNING: + case YAFFS_BLOCK_STATE_NEEDS_SCANNING: + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR), + n, blockStateName[bi->blockState])); + } + + /* 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 + */ + 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 */ + /* 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)); + } +} + +static void yaffs_VerifyBlocks(yaffs_Device *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 < 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))); + + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) + 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), + nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); + + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); + +} + +/* + * Verify the object header. oh must be valid, but obj and tags may be NULL in which + * case those tests will not be performed. + */ +static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) +{ + if (obj && yaffs_SkipVerification(obj->myDev)) + return; + + 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, + (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), + tags->objectId, oh->type)); + + if (tags->objectId != obj->objectId) + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d header mismatch objectId %d"TENDSTR), + tags->objectId, obj->objectId)); + + + /* + * 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 != 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), + obj->objectId)); + + if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d header name is 0xFF"TENDSTR), + obj->objectId)); +} + + +#if 0 /*Mark the unused function to remove warning message*/ +static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn, + __u32 level, int chunkOffset) +{ + int i; + yaffs_Device *dev = obj->myDev; + int ok = 1; + + if (tn) { + if (level > 0) { + + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { + if (tn->internal[i]) { + ok = yaffs_VerifyTnodeWorker(obj, + tn->internal[i], + level - 1, + (chunkOffset<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); + if (tags.objectId != objectId || tags.chunkId != chunkOffset) { + T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), + objectId, chunkOffset, theChunk, + tags.objectId, tags.chunkId)); + } + } + chunkOffset++; + } + } + } + + return ok; + +} +#endif + +static void yaffs_VerifyFile(yaffs_Object *obj) +{ + int requiredTallness; + int actualTallness; + __u32 lastChunk; + __u32 x; + __u32 i; + yaffs_Device *dev; + yaffs_ExtendedTags tags; + yaffs_Tnode *tn; + __u32 objectId; + + 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; + requiredTallness = 0; + while (x > 0) { + 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. + * 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); + + if (tn) { + __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i); + if (theChunk > 0) { + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */ + yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags); + if (tags.objectId != objectId || tags.chunkId != i) { + T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), + objectId, i, theChunk, + tags.objectId, tags.chunkId)); + } + } + } + } +} + + +static void yaffs_VerifyHardLink(yaffs_Object *obj) +{ + if (obj && yaffs_SkipVerification(obj->myDev)) + return; + + /* Verify sane equivalent object */ +} + +static void yaffs_VerifySymlink(yaffs_Object *obj) +{ + if (obj && yaffs_SkipVerification(obj->myDev)) + return; + + /* Verify symlink string */ +} + +static void yaffs_VerifySpecial(yaffs_Object *obj) +{ + if (obj && yaffs_SkipVerification(obj->myDev)) + return; +} + +static void yaffs_VerifyObject(yaffs_Object *obj) +{ + yaffs_Device *dev; + + __u32 chunkMin; + __u32 chunkMax; + + __u32 chunkIdOk; + __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; + + chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax); + chunkIdOk = chunkInRange || (obj->hdrChunk == 0); + chunkValid = chunkInRange && + yaffs_CheckChunkBit(dev, + obj->hdrChunk / dev->nChunksPerBlock, + obj->hdrChunk % dev->nChunksPerBlock); + chunkShouldNotBeDeleted = chunkInRange && !chunkValid; + + if (!obj->fake && + (!chunkIdOk || chunkShouldNotBeDeleted)) { + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), + obj->objectId, obj->hdrChunk, + chunkIdOk ? "" : ",out of range", + chunkShouldNotBeDeleted ? ",marked as deleted" : "")); + } + + if (chunkValid && !yaffs_SkipNANDVerification(dev)) { + yaffs_ExtendedTags tags; + yaffs_ObjectHeader *oh; + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); + + oh = (yaffs_ObjectHeader *)buffer; + + 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)); + } + + /* 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)); + } + + switch (obj->variantType) { + case YAFFS_OBJECT_TYPE_FILE: + yaffs_VerifyFile(obj); + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + yaffs_VerifySymlink(obj); + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + yaffs_VerifyDirectory(obj); + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + yaffs_VerifyHardLink(obj); + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + yaffs_VerifySpecial(obj); + break; + case YAFFS_OBJECT_TYPE_UNKNOWN: + default: + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d has illegaltype %d"TENDSTR), + obj->objectId, obj->variantType)); + break; + } +} + +static void yaffs_VerifyObjects(yaffs_Device *dev) +{ + 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); + } + } + } +} /* @@ -360,29 +918,6 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, } - -static int yaffs_VerifyChunkWritten(yaffs_Device *dev, - int chunkInNAND, - const __u8 *data, - yaffs_ExtendedTags *tags) -{ - int retval = YAFFS_OK; - yaffs_ExtendedTags tempTags; - __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__); - int result; - - result = yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,&tempTags); - if(memcmp(buffer,data,dev->nDataBytesPerChunk) || - tempTags.objectId != tags->objectId || - tempTags.chunkId != tags->chunkId || - tempTags.byteCount != tags->byteCount) - retval = YAFFS_FAIL; - - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); - - return retval; -} - static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_ExtendedTags *tags, @@ -392,7 +927,7 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, int writeOk = 0; int chunk; - yaffs2_InvalidateCheckpoint(dev); + yaffs_InvalidateCheckpoint(dev); do { yaffs_BlockInfo *bi = 0; @@ -422,18 +957,19 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, * chunk due to power loss. This checking policy should * catch that case with very few checks and thus save a * lot of checks that are most likely not needed. - * - * Mods to the above - * If an erase check fails or the write fails we skip the - * rest of the block. */ + if (bi->gcPrioritise) { + yaffs_DeleteChunk(dev, chunk, 1, __LINE__); + /* try another chunk */ + continue; + } /* let's give it a try */ attempts++; - if(dev->param.alwaysCheckErased) - bi->skipErasedCheck = 0; - +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED + bi->skipErasedCheck = 0; +#endif if (!bi->skipErasedCheck) { erasedOk = yaffs_CheckChunkErased(dev, chunk); if (erasedOk != YAFFS_OK) { @@ -441,30 +977,20 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, (TSTR("**>> yaffs chunk %d was not erased" TENDSTR), chunk)); - /* If not erased, delete this one, - * skip rest of block and - * try another chunk */ - yaffs_DeleteChunk(dev,chunk,1,__LINE__); - yaffs_SkipRestOfBlock(dev); + /* try another chunk */ continue; } + bi->skipErasedCheck = 1; } writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, data, tags); - - if(!bi->skipErasedCheck) - writeOk = yaffs_VerifyChunkWritten(dev, chunk, data, tags); - if (writeOk != YAFFS_OK) { - /* Clean up aborted write, skip to next block and - * try another chunk */ yaffs_HandleWriteChunkError(dev, chunk, erasedOk); + /* try another chunk */ continue; } - bi->skipErasedCheck = 1; - /* Copy the data into the robustification buffer */ yaffs_HandleWriteChunkOk(dev, chunk, data, tags); @@ -485,8 +1011,80 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, return chunk; } +/* + * Oldest Dirty Sequence Number handling. + */ + +/* yaffs_CalcOldestDirtySequence() + * yaffs_FindOldestDirtySequence() + * Calculate the oldest dirty sequence number if we don't know it. + */ +static int yaffs_CalcOldestDirtySequence(yaffs_Device *dev) +{ + int i; + __u32 seq; + yaffs_BlockInfo *b = 0; + + if (!dev->isYaffs2) + return 0; + + /* Find the oldest dirty sequence number. */ + seq = dev->sequenceNumber; + for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { + b = yaffs_GetBlockInfo(dev, i); + if (b->blockState == YAFFS_BLOCK_STATE_FULL && + (b->pagesInUse - b->softDeletions) < dev->nChunksPerBlock && + b->sequenceNumber < seq) + seq = b->sequenceNumber; + } + return seq; +} + + +static void yaffs_FindOldestDirtySequence(yaffs_Device *dev) +{ + if (dev->isYaffs2 && !dev->oldestDirtySequence) + dev->oldestDirtySequence = + yaffs_CalcOldestDirtySequence(dev); + +#if 0 + if (!yaffs_SkipVerification(dev) && + dev->oldestDirtySequence != yaffs_CalcOldestDirtySequence(dev)) + YBUG(); + +#endif +} + +/* + * yaffs_ClearOldestDirtySequence() + * Called when a block is erased or marked bad. (ie. when its sequenceNumber + * becomes invalid). If the value matches the oldest then we clear + * dev->oldestDirtySequence to force its recomputation. + */ +static void yaffs_ClearOldestDirtySequence(yaffs_Device *dev, + yaffs_BlockInfo *bi) +{ + if (!dev->isYaffs2) + return; + + if (!bi || bi->sequenceNumber == dev->oldestDirtySequence) + dev->oldestDirtySequence = 0; +} + +/* + * yaffs_UpdateOldestDirtySequence() + * Update the oldest dirty sequence number whenever we dirty a block. + * Only do this if the oldestDirtySequence is actually being tracked. + */ +static void yaffs_UpdateOldestDirtySequence(yaffs_Device *dev, + yaffs_BlockInfo *bi) +{ + if (dev->isYaffs2 && dev->oldestDirtySequence) { + if (dev->oldestDirtySequence > bi->sequenceNumber) + dev->oldestDirtySequence = bi->sequenceNumber; + } +} - /* * Block retiring for handling a broken block. */ @@ -495,9 +1093,9 @@ static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND) { yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); - yaffs2_InvalidateCheckpoint(dev); - - yaffs2_ClearOldestDirtySequence(dev,bi); + yaffs_InvalidateCheckpoint(dev); + + yaffs_ClearOldestDirtySequence(dev, bi); if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) { if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) { @@ -506,14 +1104,14 @@ static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND) TENDSTR), blockInNAND)); } else { yaffs_ExtendedTags tags; - int chunkId = blockInNAND * dev->param.nChunksPerBlock; + int chunkId = blockInNAND * dev->nChunksPerBlock; __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); memset(buffer, 0xff, dev->nDataBytesPerChunk); yaffs_InitialiseTags(&tags); tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK; - if (dev->param.writeChunkWithTagsToNAND(dev, chunkId - + if (dev->writeChunkWithTagsToNAND(dev, chunkId - dev->chunkOffset, buffer, &tags) != YAFFS_OK) T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to " TCONT("write bad block marker to block %d") @@ -539,18 +1137,11 @@ static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *tags) { - dev=dev; - chunkInNAND=chunkInNAND; - data=data; - tags=tags; } static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, const yaffs_ExtendedTags *tags) { - dev=dev; - chunkInNAND=chunkInNAND; - tags=tags; } void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi) @@ -571,7 +1162,7 @@ void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi) static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, int erasedOk) { - int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock; + int blockInNAND = chunkInNAND / dev->nChunksPerBlock; yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); yaffs_HandleChunkError(dev, bi); @@ -585,7 +1176,6 @@ static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, /* Delete the chunk */ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); - yaffs_SkipRestOfBlock(dev); } @@ -612,11 +1202,11 @@ static __u16 yaffs_CalcNameSum(const YCHAR *name) return sum; } -void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name) +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_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH) + if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) yaffs_strcpy(obj->shortName, name); else obj->shortName[0] = _Y('\0'); @@ -624,18 +1214,6 @@ void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name) obj->sum = yaffs_CalcNameSum(name); } -void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh) -{ -#ifdef CONFIG_YAFFS_AUTO_UNICODE - YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1]; - memset(tmpName,0,sizeof(tmpName)); - yaffs_LoadNameFromObjectHeader(obj->myDev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1); - yaffs_SetObjectName(obj,tmpName); -#else - yaffs_SetObjectName(obj,oh->name); -#endif -} - /*-------------------- TNODES ------------------- * List of spare tnodes @@ -643,13 +1221,117 @@ void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh) * in the tnode. */ +/* yaffs_CreateTnodes creates a bunch more tnodes and + * adds them to the tnode free list. + * Don't use this function directly + */ -yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev) +static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes) { - yaffs_Tnode *tn = yaffs_AllocateRawTnode(dev); - if (tn){ - memset(tn, 0, dev->tnodeSize); - dev->nTnodes++; + int i; + int tnodeSize; + yaffs_Tnode *newTnodes; + __u8 *mem; + yaffs_Tnode *curr; + yaffs_Tnode *next; + yaffs_TnodeList *tnl; + + if (nTnodes < 1) + return YAFFS_OK; + + /* Calculate the tnode size in bytes for variable width tnode support. + * Must be a multiple of 32-bits */ + tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + + if (tnodeSize < sizeof(yaffs_Tnode)) + tnodeSize = sizeof(yaffs_Tnode); + + /* make these things */ + + newTnodes = YMALLOC(nTnodes * tnodeSize); + mem = (__u8 *)newTnodes; + + if (!newTnodes) { + T(YAFFS_TRACE_ERROR, + (TSTR("yaffs: Could not allocate Tnodes" TENDSTR))); + return YAFFS_FAIL; + } + + /* Hook them into the free list */ +#if 0 + for (i = 0; i < nTnodes - 1; i++) { + newTnodes[i].internal[0] = &newTnodes[i + 1]; +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG + newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; +#endif + } + + newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes; +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG + newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; +#endif + dev->freeTnodes = newTnodes; +#else + /* New hookup for wide tnodes */ + for (i = 0; i < nTnodes - 1; i++) { + curr = (yaffs_Tnode *) &mem[i * tnodeSize]; + next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize]; + curr->internal[0] = next; + } + + curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize]; + curr->internal[0] = dev->freeTnodes; + dev->freeTnodes = (yaffs_Tnode *)mem; + +#endif + + + dev->nFreeTnodes += nTnodes; + dev->nTnodesCreated += nTnodes; + + /* Now add this bunch of tnodes to a list for freeing up. + * NB If we can't add this to the management list it isn't fatal + * but it just means we can't free this bunch of tnodes later. + */ + + tnl = YMALLOC(sizeof(yaffs_TnodeList)); + if (!tnl) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("yaffs: Could not add tnodes to management list" TENDSTR))); + return YAFFS_FAIL; + } else { + tnl->tnodes = newTnodes; + tnl->next = dev->allocatedTnodeList; + dev->allocatedTnodeList = tnl; + } + + T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR))); + + return YAFFS_OK; +} + +/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */ + +static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev) +{ + yaffs_Tnode *tn = NULL; + + /* If there are none left make more */ + if (!dev->freeTnodes) + yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES); + + if (dev->freeTnodes) { + tn = dev->freeTnodes; +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG + if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) { + /* Hoosterman, this thing looks like it isn't in the list */ + T(YAFFS_TRACE_ALWAYS, + (TSTR("yaffs: Tnode list bug 1" TENDSTR))); + } +#endif + dev->freeTnodes = dev->freeTnodes->internal[0]; + dev->nFreeTnodes--; } dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ @@ -657,23 +1339,67 @@ yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev) return tn; } +static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev) +{ + yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev); + int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + + if (tnodeSize < sizeof(yaffs_Tnode)) + tnodeSize = sizeof(yaffs_Tnode); + + if (tn) + memset(tn, 0, tnodeSize); + + return tn; +} + /* FreeTnode frees up a tnode and puts it back on the free list */ static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn) { - yaffs_FreeRawTnode(dev,tn); - dev->nTnodes--; + if (tn) { +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG + if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) { + /* Hoosterman, this thing looks like it is already in the list */ + T(YAFFS_TRACE_ALWAYS, + (TSTR("yaffs: Tnode list bug 2" TENDSTR))); + } + tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1; +#endif + tn->internal[0] = dev->freeTnodes; + dev->freeTnodes = tn; + dev->nFreeTnodes++; + } dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ } -static void yaffs_DeinitialiseTnodesAndObjects(yaffs_Device *dev) +static void yaffs_DeinitialiseTnodes(yaffs_Device *dev) { - yaffs_DeinitialiseRawTnodesAndObjects(dev); - dev->nObjects = 0; - dev->nTnodes = 0; + /* Free the list of allocated tnodes */ + yaffs_TnodeList *tmp; + + while (dev->allocatedTnodeList) { + tmp = dev->allocatedTnodeList->next; + + YFREE(dev->allocatedTnodeList->tnodes); + YFREE(dev->allocatedTnodeList); + dev->allocatedTnodeList = tmp; + + } + + dev->freeTnodes = NULL; + dev->nFreeTnodes = 0; +} + +static void yaffs_InitialiseTnodes(yaffs_Device *dev) +{ + dev->allocatedTnodeList = NULL; + dev->freeTnodes = NULL; + dev->nFreeTnodes = 0; + dev->nTnodesCreated = 0; } -void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, +void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, unsigned val) { __u32 *map = (__u32 *)tn; @@ -703,7 +1429,7 @@ void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, } } -__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, +static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos) { __u32 *map = (__u32 *)tn; @@ -740,7 +1466,7 @@ __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, */ /* FindLevel0Tnode finds the level 0 tnode, if one exists. */ -yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, +static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId) { @@ -749,8 +1475,6 @@ yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, int requiredTallness; int level = fStruct->topLevel; - dev=dev; - /* Check sane level and chunk Id */ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) return NULL; @@ -794,7 +1518,7 @@ yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, * be plugged into the ttree. */ -yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, +static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId, yaffs_Tnode *passedTn) @@ -833,13 +1557,13 @@ yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, if (tn) { tn->internal[0] = fStruct->top; fStruct->top = tn; - fStruct->topLevel++; } else { T(YAFFS_TRACE_ERROR, - (TSTR("yaffs: no more tnodes" TENDSTR))); - return NULL; + (TSTR("yaffs: no more tnodes" TENDSTR))); } } + + fStruct->topLevel = requiredTallness; } /* Traverse down to level 0, adding anything we need */ @@ -858,8 +1582,7 @@ yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, if ((l > 1) && !tn->internal[x]) { /* Add missing non-level-zero tnode */ tn->internal[x] = yaffs_GetTnode(dev); - if(!tn->internal[x]) - return NULL; + } else if (l == 1) { /* Looking from level 1 at level 0 */ if (passedTn) { @@ -871,8 +1594,6 @@ yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, } else if (!tn->internal[x]) { /* Don't have one, none passed in */ tn->internal[x] = yaffs_GetTnode(dev); - if(!tn->internal[x]) - return NULL; } } @@ -897,8 +1618,8 @@ static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, int j; for (j = 0; theChunk && j < dev->chunkGroupSize; j++) { - if (yaffs_CheckChunkBit(dev, theChunk / dev->param.nChunksPerBlock, - theChunk % dev->param.nChunksPerBlock)) { + if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock, + theChunk % dev->nChunksPerBlock)) { if(dev->chunkGroupSize == 1) return theChunk; @@ -916,14 +1637,13 @@ static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, return -1; } -#if 0 -/* Experimental code not being used yet. Might speed up file deletion */ + /* DeleteWorker scans backwards through the tnode tree and deletes all the - * chunks and tnodes in the file. + * chunks and tnodes in the file * Returns 1 if the tree was deleted. * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete. */ - +#if 0 /*Mark the unused function to remove warning message*/ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset, int *limit) { @@ -997,7 +1717,7 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, } - yaffs_LoadLevel0Tnode(dev, tn, i, 0); + yaffs_PutLevel0Tnode(dev, tn, i, 0); } } @@ -1010,22 +1730,18 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, return 1; } - #endif - static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk) { yaffs_BlockInfo *theBlock; - unsigned blockNo; T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk)); - blockNo = chunk / dev->param.nChunksPerBlock; - theBlock = yaffs_GetBlockInfo(dev, blockNo); + theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock); if (theBlock) { theBlock->softDeletions++; dev->nFreeChunks++; - yaffs2_UpdateOldestDirtySequence(dev, blockNo, theBlock); + yaffs_UpdateOldestDirtySequence(dev, theBlock); } } @@ -1079,7 +1795,7 @@ static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, * a block. */ yaffs_SoftDeleteChunk(dev, theChunk); - yaffs_LoadLevel0Tnode(dev, tn, i, 0); + yaffs_PutLevel0Tnode(dev, tn, i, 0); } } @@ -1125,10 +1841,6 @@ static void yaffs_SoftDeleteFile(yaffs_Object *obj) * level 0 tnode entries must be zeroed out. * Could also use this for file deletion, but that's probably better handled * by a special case. - * - * This function is recursive. For levels > 0 the function is called again on - * any sub-tree. For level == 0 we just check if the sub-tree has data. - * If there is no data in a subtree then it is pruned. */ static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, @@ -1140,27 +1852,17 @@ static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, if (tn) { hasData = 0; - if(level > 0){ - for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { - if (tn->internal[i]) { - tn->internal[i] = - yaffs_PruneWorker(dev, tn->internal[i], - level - 1, - (i == 0) ? del0 : 1); - } - - if (tn->internal[i]) - hasData++; + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { + if (tn->internal[i] && level > 0) { + tn->internal[i] = + yaffs_PruneWorker(dev, tn->internal[i], + level - 1, + (i == 0) ? del0 : 1); } - } else { - int tnodeSize_u32 = dev->tnodeSize/sizeof(__u32); - __u32 *map = (__u32 *)tn; - for(i = 0; !hasData && i < tnodeSize_u32; i++){ - if(map[i]) - hasData++; - } - } + if (tn->internal[i]) + hasData++; + } if (hasData == 0 && del0) { /* Free and return NULL */ @@ -1218,32 +1920,90 @@ static int yaffs_PruneFileStructure(yaffs_Device *dev, /*-------------------- End of File Structure functions.-------------------*/ +/* yaffs_CreateFreeObjects creates a bunch more objects and + * adds them to the object free list. + */ +static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects) +{ + int i; + yaffs_Object *newObjects; + yaffs_ObjectList *list; + + if (nObjects < 1) + return YAFFS_OK; + + /* make these things */ + newObjects = YMALLOC(nObjects * sizeof(yaffs_Object)); + list = YMALLOC(sizeof(yaffs_ObjectList)); + + if (!newObjects || !list) { + if (newObjects) + YFREE(newObjects); + if (list) + YFREE(list); + T(YAFFS_TRACE_ALLOCATE, + (TSTR("yaffs: Could not allocate more objects" TENDSTR))); + return YAFFS_FAIL; + } + + /* Hook them into the free list */ + for (i = 0; i < nObjects - 1; i++) { + newObjects[i].siblings.next = + (struct ylist_head *)(&newObjects[i + 1]); + } + + newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects; + dev->freeObjects = newObjects; + dev->nFreeObjects += nObjects; + dev->nObjectsCreated += nObjects; + + /* Now add this bunch of Objects to a list for freeing up. */ + + list->objects = newObjects; + list->next = dev->allocatedObjectList; + dev->allocatedObjectList = list; + + return YAFFS_OK; +} + /* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */ static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev) { - yaffs_Object *obj = yaffs_AllocateRawObject(dev); + yaffs_Object *tn = NULL; - if (obj) { - dev->nObjects++; +#ifdef VALGRIND_TEST + tn = YMALLOC(sizeof(yaffs_Object)); +#else + /* If there are none left make more */ + if (!dev->freeObjects) + yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS); + if (dev->freeObjects) { + tn = dev->freeObjects; + dev->freeObjects = + (yaffs_Object *) (dev->freeObjects->siblings.next); + dev->nFreeObjects--; + } +#endif + if (tn) { /* Now sweeten it up... */ - memset(obj, 0, sizeof(yaffs_Object)); - obj->beingCreated = 1; + memset(tn, 0, sizeof(yaffs_Object)); + tn->beingCreated = 1; - obj->myDev = dev; - obj->hdrChunk = 0; - obj->variantType = YAFFS_OBJECT_TYPE_UNKNOWN; - YINIT_LIST_HEAD(&(obj->hardLinks)); - YINIT_LIST_HEAD(&(obj->hashLink)); - YINIT_LIST_HEAD(&obj->siblings); + tn->myDev = dev; + tn->hdrChunk = 0; + tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN; + YINIT_LIST_HEAD(&(tn->hardLinks)); + YINIT_LIST_HEAD(&(tn->hashLink)); + YINIT_LIST_HEAD(&tn->siblings); /* Now make the directory sane */ if (dev->rootDir) { - obj->parent = dev->rootDir; - ylist_add(&(obj->siblings), &dev->rootDir->variant.directoryVariant.children); + tn->parent = dev->rootDir; + ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children); } /* Add it to the lost and found directory. @@ -1251,14 +2011,14 @@ static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev) * check if lostNFound exists first */ if (dev->lostNFoundDir) - yaffs_AddObjectToDirectory(dev->lostNFoundDir, obj); + yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn); - obj->beingCreated = 0; + tn->beingCreated = 0; } dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ - return obj; + return tn; } static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number, @@ -1282,49 +2042,58 @@ static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number, } -static void yaffs_UnhashObject(yaffs_Object *obj) +static void yaffs_UnhashObject(yaffs_Object *tn) { int bucket; - yaffs_Device *dev = obj->myDev; + yaffs_Device *dev = tn->myDev; /* If it is still linked into the bucket list, free from the list */ - if (!ylist_empty(&obj->hashLink)) { - ylist_del_init(&obj->hashLink); - bucket = yaffs_HashFunction(obj->objectId); + if (!ylist_empty(&tn->hashLink)) { + ylist_del_init(&tn->hashLink); + bucket = yaffs_HashFunction(tn->objectId); dev->objectBucket[bucket].count--; } } /* FreeObject frees up a Object and puts it back on the free list */ -static void yaffs_FreeObject(yaffs_Object *obj) +static void yaffs_FreeObject(yaffs_Object *tn) { - yaffs_Device *dev = obj->myDev; + yaffs_Device *dev = tn->myDev; - T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->myInode)); +#ifdef __KERNEL__ + T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode)); +#endif - if (!obj) + if (tn->parent) YBUG(); - if (obj->parent) - YBUG(); - if (!ylist_empty(&obj->siblings)) + if (!ylist_empty(&tn->siblings)) YBUG(); - if (obj->myInode) { +#ifdef __KERNEL__ + if (tn->myInode) { /* We're still hooked up to a cached inode. * Don't delete now, but mark for later deletion */ - obj->deferedFree = 1; + tn->deferedFree = 1; return; } +#endif - yaffs_UnhashObject(obj); + yaffs_UnhashObject(tn); - yaffs_FreeRawObject(dev,obj); - dev->nObjects--; +#ifdef VALGRIND_TEST + YFREE(tn); +#else + /* Link into the free list. */ + tn->siblings.next = (struct ylist_head *)(dev->freeObjects); + dev->freeObjects = tn; + dev->nFreeObjects++; +#endif dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ } +#ifdef __KERNEL__ void yaffs_HandleDeferedFree(yaffs_Object *obj) { @@ -1332,14 +2101,33 @@ void yaffs_HandleDeferedFree(yaffs_Object *obj) yaffs_FreeObject(obj); } -static void yaffs_InitialiseTnodesAndObjects(yaffs_Device *dev) +#endif + +static void yaffs_DeinitialiseObjects(yaffs_Device *dev) +{ + /* Free the list of allocated Objects */ + + yaffs_ObjectList *tmp; + + while (dev->allocatedObjectList) { + tmp = dev->allocatedObjectList->next; + YFREE(dev->allocatedObjectList->objects); + YFREE(dev->allocatedObjectList); + + dev->allocatedObjectList = tmp; + } + + dev->freeObjects = NULL; + dev->nFreeObjects = 0; +} + +static void yaffs_InitialiseObjects(yaffs_Device *dev) { int i; - dev->nObjects = 0; - dev->nTnodes = 0; - - yaffs_InitialiseRawTnodesAndObjects(dev); + dev->allocatedObjectList = NULL; + dev->freeObjects = NULL; + dev->nFreeObjects = 0; for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { YINIT_LIST_HEAD(&dev->objectBucket[i].list); @@ -1349,21 +2137,33 @@ static void yaffs_InitialiseTnodesAndObjects(yaffs_Device *dev) static int yaffs_FindNiceObjectBucket(yaffs_Device *dev) { + static int x; int i; int l = 999; int lowest = 999999; + /* First let's see if we can find one that's empty. */ - /* Search for the shortest list or one that - * isn't too long. + for (i = 0; i < 10 && lowest > 0; i++) { + x++; + x %= YAFFS_NOBJECT_BUCKETS; + if (dev->objectBucket[x].count < lowest) { + lowest = dev->objectBucket[x].count; + l = x; + } + + } + + /* If we didn't find an empty list, then try + * looking a bit further for a short one */ - for (i = 0; i < 10 && lowest > 4; i++) { - dev->bucketFinder++; - dev->bucketFinder %= YAFFS_NOBJECT_BUCKETS; - if (dev->objectBucket[dev->bucketFinder].count < lowest) { - lowest = dev->objectBucket[dev->bucketFinder].count; - l = dev->bucketFinder; + for (i = 0; i < 10 && lowest > 3; i++) { + x++; + x %= YAFFS_NOBJECT_BUCKETS; + if (dev->objectBucket[x].count < lowest) { + lowest = dev->objectBucket[x].count; + l = x; } } @@ -1423,10 +2223,11 @@ yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number) if (i) { in = ylist_entry(i, yaffs_Object, hashLink); if (in->objectId == number) { - +#ifdef __KERNEL__ /* Don't tell the VFS about this one if it is defered free */ if (in->deferedFree) return NULL; +#endif return in; } @@ -1439,26 +2240,24 @@ yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number) yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, yaffs_ObjectType type) { - yaffs_Object *theObject=NULL; + yaffs_Object *theObject; yaffs_Tnode *tn = NULL; if (number < 0) number = yaffs_CreateNewObjectNumber(dev); + theObject = yaffs_AllocateEmptyObject(dev); + if (!theObject) + return NULL; + if (type == YAFFS_OBJECT_TYPE_FILE) { tn = yaffs_GetTnode(dev); - if (!tn) + if (!tn) { + yaffs_FreeObject(theObject); return NULL; + } } - theObject = yaffs_AllocateEmptyObject(dev); - if (!theObject){ - if(tn) - yaffs_FreeTnode(dev,tn); - return NULL; - } - - if (theObject) { theObject->fake = 0; theObject->renameAllowed = 1; @@ -1489,8 +2288,6 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, case YAFFS_OBJECT_TYPE_DIRECTORY: YINIT_LIST_HEAD(&theObject->variant.directoryVariant. children); - YINIT_LIST_HEAD(&theObject->variant.directoryVariant. - dirty); break; case YAFFS_OBJECT_TYPE_SYMLINK: case YAFFS_OBJECT_TYPE_HARDLINK: @@ -1506,9 +2303,9 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, return theObject; } -yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, - int number, - yaffs_ObjectType type) +static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, + int number, + yaffs_ObjectType type) { yaffs_Object *theObject = NULL; @@ -1523,20 +2320,16 @@ yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, } -YCHAR *yaffs_CloneString(const YCHAR *str) +static YCHAR *yaffs_CloneString(const YCHAR *str) { YCHAR *newStr = NULL; - int len; - if (!str) - str = _Y(""); - - len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH); - newStr = YMALLOC((len + 1) * sizeof(YCHAR)); - if (newStr){ - yaffs_strncpy(newStr, str,len); - newStr[len] = 0; + if (str && *str) { + newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); + if (newStr) + yaffs_strcpy(newStr, str); } + return newStr; } @@ -1544,7 +2337,7 @@ YCHAR *yaffs_CloneString(const YCHAR *str) /* * Mknod (create) a new object. * equivalentObject only has meaning for a hard link; - * aliasString only has meaning for a symlink. + * aliasString only has meaning for a sumlink. * rdev only has meaning for devices (a subset of special objects) */ @@ -1566,24 +2359,21 @@ static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, if (yaffs_FindObjectByName(parent, name)) return NULL; - if (type == YAFFS_OBJECT_TYPE_SYMLINK) { - str = yaffs_CloneString(aliasString); - if (!str) - return NULL; - } - in = yaffs_CreateNewObject(dev, -1, type); - if (!in){ - if(str) - YFREE(str); - return NULL; + if (!in) + return YAFFS_FAIL; + + if (type == YAFFS_OBJECT_TYPE_SYMLINK) { + str = yaffs_CloneString(aliasString); + if (!str) { + yaffs_FreeObject(in); + return NULL; + } } - - if (in) { in->hdrChunk = 0; in->valid = 1; @@ -1631,7 +2421,7 @@ static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, break; } - if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0, NULL) < 0) { + if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) { /* Could not create the object header, fail the creation */ yaffs_DeleteObject(in); in = NULL; @@ -1709,7 +2499,7 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, } /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ - if (obj->myDev->param.isYaffs2) + if (obj->myDev->isYaffs2) unlinkOp = (newDir == obj->myDev->unlinkedDir); else unlinkOp = (newDir == obj->myDev->unlinkedDir @@ -1739,7 +2529,7 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, obj->unlinked = 1; /* If it is a deletion then we mark it as a shrink for gc purposes. */ - if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows, NULL) >= 0) + if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0) return YAFFS_OK; } @@ -1772,7 +2562,7 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, force = 1; #endif - if(yaffs_strnlen(newName,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH) + if(yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) /* ENAMETOOLONG */ return YAFFS_FAIL; @@ -1795,12 +2585,12 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, * Note we must disable gc otherwise it can mess up the shadowing. * */ - dev->gcDisable=1; + dev->isDoingGC=1; yaffs_ChangeObjectName(obj, newDir, newName, force, existingTarget->objectId); existingTarget->isShadowed = 1; yaffs_UnlinkObject(existingTarget); - dev->gcDisable=0; + dev->isDoingGC=0; } result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0); @@ -1808,7 +2598,7 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_UpdateParent(oldDir); if(newDir != oldDir) yaffs_UpdateParent(newDir); - + return result; } return YAFFS_FAIL; @@ -1835,7 +2625,7 @@ static int yaffs_InitialiseBlocks(yaffs_Device *dev) if (dev->blockInfo) { /* Set up dynamic blockinfo stuff. */ - dev->chunkBitmapStride = (dev->param.nChunksPerBlock + 7) / 8; /* round up bytes */ + dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); if (!dev->chunkBits) { dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); @@ -1872,7 +2662,122 @@ static void yaffs_DeinitialiseBlocks(yaffs_Device *dev) dev->chunkBits = NULL; } -void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) +static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, + yaffs_BlockInfo *bi) +{ + if (!dev->isYaffs2) + return 1; /* disqualification only applies to yaffs2. */ + + yaffs_FindOldestDirtySequence(dev); + + /* Can't do gc of this block if there are any blocks older than this one that have + * discarded pages. + */ + return (bi->sequenceNumber <= dev->oldestDirtySequence); +} + +/* FindDiretiestBlock is used to select the dirtiest block (or close enough) + * for garbage collection. + */ + +static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, + int aggressive) +{ + int b = dev->currentDirtyChecker; + + int i; + int iterations; + int dirtiest = -1; + int pagesInUse = 0; + int prioritised = 0; + yaffs_BlockInfo *bi; + int pendingPrioritisedExist = 0; + + /* First let's see if we need to grab a prioritised block */ + if (dev->hasPendingPrioritisedGCs) { + for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) { + + bi = yaffs_GetBlockInfo(dev, i); + /* yaffs_VerifyBlock(dev,bi,i); */ + + if (bi->gcPrioritise) { + pendingPrioritisedExist = 1; + if (bi->blockState == YAFFS_BLOCK_STATE_FULL && + yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { + pagesInUse = (bi->pagesInUse - bi->softDeletions); + dirtiest = i; + prioritised = 1; + aggressive = 1; /* Fool the non-aggressive skip logiv below */ + } + } + } + + if (!pendingPrioritisedExist) /* None found, so we can clear this */ + dev->hasPendingPrioritisedGCs = 0; + } + + /* If we're doing aggressive GC then we are happy to take a less-dirty block, and + * search harder. + * else (we're doing a leasurely gc), then we only bother to do this if the + * block has only a few pages in use. + */ + + dev->nonAggressiveSkip--; + + if (!aggressive && (dev->nonAggressiveSkip > 0)) + return -1; + + if (!prioritised) + pagesInUse = + (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1; + + if (aggressive) + iterations = + dev->internalEndBlock - dev->internalStartBlock + 1; + else { + iterations = + dev->internalEndBlock - dev->internalStartBlock + 1; + iterations = iterations / 16; + if (iterations > 200) + iterations = 200; + } + + for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) { + b++; + if (b < dev->internalStartBlock || b > dev->internalEndBlock) + b = dev->internalStartBlock; + + if (b < dev->internalStartBlock || b > dev->internalEndBlock) { + T(YAFFS_TRACE_ERROR, + (TSTR("**>> Block %d is not valid" TENDSTR), b)); + YBUG(); + } + + bi = yaffs_GetBlockInfo(dev, b); + + if (bi->blockState == YAFFS_BLOCK_STATE_FULL && + (bi->pagesInUse - bi->softDeletions) < pagesInUse && + yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { + dirtiest = b; + pagesInUse = (bi->pagesInUse - bi->softDeletions); + } + } + + dev->currentDirtyChecker = b; + + if (dirtiest > 0) { + T(YAFFS_TRACE_GC, + (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest, + dev->nChunksPerBlock - pagesInUse, prioritised)); + } + + if (dirtiest > 0) + dev->nonAggressiveSkip = 2; + + return dirtiest; +} + +static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) { yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo); @@ -1886,22 +2791,12 @@ void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR), blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : "")); - yaffs2_ClearOldestDirtySequence(dev,bi); + yaffs_ClearOldestDirtySequence(dev, bi); bi->blockState = YAFFS_BLOCK_STATE_DIRTY; - /* If this is the block being garbage collected then stop gc'ing this block */ - if(blockNo == dev->gcBlock) - dev->gcBlock = 0; - - /* If this block is currently the best candidate for gc then drop as a candidate */ - if(blockNo == dev->gcDirtiest){ - dev->gcDirtiest = 0; - dev->gcPagesInUse = 0; - } - if (!bi->needsRetiring) { - yaffs2_InvalidateCheckpoint(dev); + yaffs_InvalidateCheckpoint(dev); erasedOk = yaffs_EraseBlockInNAND(dev, blockNo); if (!erasedOk) { dev->nErasureFailures++; @@ -1913,9 +2808,9 @@ void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) if (erasedOk && ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) { int i; - for (i = 0; i < dev->param.nChunksPerBlock; i++) { + for (i = 0; i < dev->nChunksPerBlock; i++) { if (!yaffs_CheckChunkErased - (dev, blockNo * dev->param.nChunksPerBlock + i)) { + (dev, blockNo * dev->nChunksPerBlock + i)) { T(YAFFS_TRACE_ERROR, (TSTR (">>Block %d erasure supposedly OK, but chunk %d not erased" @@ -1927,7 +2822,6 @@ void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) if (erasedOk) { /* Clean it up... */ bi->blockState = YAFFS_BLOCK_STATE_EMPTY; - bi->sequenceNumber = 0; dev->nErasedBlocks++; bi->pagesInUse = 0; bi->softDeletions = 0; @@ -1939,7 +2833,7 @@ void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) T(YAFFS_TRACE_ERASE, (TSTR("Erased block %d" TENDSTR), blockNo)); } else { - dev->nFreeChunks -= dev->param.nChunksPerBlock; /* We lost a block of free space */ + dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */ yaffs_RetireBlock(dev, blockNo); T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, @@ -1996,21 +2890,63 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev) } + +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()? */ -int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks) +static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev) { int reservedChunks; - int reservedBlocks = dev->param.nReservedBlocks; + int reservedBlocks = dev->nReservedBlocks; int checkpointBlocks; - checkpointBlocks = yaffs2_CalcCheckpointBlocksRequired(dev); + if (dev->isYaffs2) { + checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - + dev->blocksInCheckpoint; + if (checkpointBlocks < 0) + checkpointBlocks = 0; + } else { + checkpointBlocks = 0; + } - reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.nChunksPerBlock); + reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); - return (dev->nFreeChunks > (reservedChunks + nChunks)); + return (dev->nFreeChunks > reservedChunks); } static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, @@ -2025,12 +2961,12 @@ static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, dev->allocationPage = 0; } - if (!useReserve && !yaffs_CheckSpaceForAllocation(dev, 1)) { + if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) { /* Not enough space to allocate unless we're allowed to use the reserve. */ return -1; } - if (dev->nErasedBlocks < dev->param.nReservedBlocks + if (dev->nErasedBlocks < dev->nReservedBlocks && dev->allocationPage == 0) { T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR))); } @@ -2039,7 +2975,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, if (dev->allocationBlock >= 0) { bi = yaffs_GetBlockInfo(dev, dev->allocationBlock); - retVal = (dev->allocationBlock * dev->param.nChunksPerBlock) + + retVal = (dev->allocationBlock * dev->nChunksPerBlock) + dev->allocationPage; bi->pagesInUse++; yaffs_SetChunkBit(dev, dev->allocationBlock, @@ -2050,7 +2986,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, dev->nFreeChunks--; /* If the block is full set the state to full */ - if (dev->allocationPage >= dev->param.nChunksPerBlock) { + if (dev->allocationPage >= dev->nChunksPerBlock) { bi->blockState = YAFFS_BLOCK_STATE_FULL; dev->allocationBlock = -1; } @@ -2071,31 +3007,15 @@ static int yaffs_GetErasedChunks(yaffs_Device *dev) { int n; - n = dev->nErasedBlocks * dev->param.nChunksPerBlock; + n = dev->nErasedBlocks * dev->nChunksPerBlock; if (dev->allocationBlock > 0) - n += (dev->param.nChunksPerBlock - dev->allocationPage); + n += (dev->nChunksPerBlock - dev->allocationPage); return n; } -/* - * yaffs_SkipRestOfBlock() skips over the rest of the allocation block - * if we don't want to write to it. - */ -void yaffs_SkipRestOfBlock(yaffs_Device *dev) -{ - if(dev->allocationBlock > 0){ - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->allocationBlock); - if(bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING){ - bi->blockState = YAFFS_BLOCK_STATE_FULL; - dev->allocationBlock = -1; - } - } -} - - static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, int wholeBlock) { @@ -2103,6 +3023,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, int newChunk; int markNAND; int retVal = YAFFS_OK; + int cleanups = 0; int i; int isCheckpointBlock; int matchingChunk; @@ -2134,7 +3055,13 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */ - dev->gcDisable = 1; + /* Take off the number of soft deleted entries because + * they're going to get really deleted during GC. + */ + if(dev->gcChunk == 0) /* first time through for this block */ + dev->nFreeChunks -= bi->softDeletions; + + dev->isDoingGC = 1; if (isCheckpointBlock || !yaffs_StillSomeChunkBits(dev, block)) { @@ -2149,12 +3076,12 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, yaffs_VerifyBlock(dev, bi, block); - maxCopies = (wholeBlock) ? dev->param.nChunksPerBlock : 5; - oldChunk = block * dev->param.nChunksPerBlock + dev->gcChunk; + maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10; + oldChunk = block * dev->nChunksPerBlock + dev->gcChunk; for (/* init already done */; retVal == YAFFS_OK && - dev->gcChunk < dev->param.nChunksPerBlock && + dev->gcChunk < dev->nChunksPerBlock && (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) && maxCopies > 0; dev->gcChunk++, oldChunk++) { @@ -2213,22 +3140,14 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, * No need to copy this, just forget about it and * fix up the object. */ - - /* Free chunks already includes softdeleted chunks. - * How ever this chunk is going to soon be really deleted - * which will increment free chunks. - * We have to decrement free chunks so this works out properly. - */ - dev->nFreeChunks--; - bi->softDeletions--; object->nDataChunks--; if (object->nDataChunks <= 0) { /* remeber to clean up the object */ - dev->gcCleanupList[dev->nCleanups] = + dev->gcCleanupList[cleanups] = tags.objectId; - dev->nCleanups++; + cleanups++; } markNAND = 0; } else if (0) { @@ -2263,26 +3182,17 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, yaffs_ObjectHeader *oh; oh = (yaffs_ObjectHeader *)buffer; - oh->isShrink = 0; tags.extraIsShrinkHeader = 0; - oh->shadowsObject = 0; oh->inbandShadowsObject = 0; tags.extraShadows = 0; - /* Update file size */ - if(object->variantType == YAFFS_OBJECT_TYPE_FILE){ - oh->fileSize = object->variant.fileVariant.fileSize; - tags.extraFileLength = oh->fileSize; - } - yaffs_VerifyObjectHeader(object, oh, &tags, 1); - newChunk = - yaffs_WriteNewChunkWithTagsToNAND(dev,(__u8 *) oh, &tags, 1); - } else - newChunk = - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1); + } + + newChunk = + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1); if (newChunk < 0) { retVal = YAFFS_FAIL; @@ -2296,8 +3206,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, object->serial = tags.serialNumber; } else { /* It's a data chunk */ - int ok; - ok = yaffs_PutChunkIntoFile + yaffs_PutChunkIntoFile (object, tags.chunkId, newChunk, 0); @@ -2314,23 +3223,8 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); - - } - - yaffs_VerifyCollectedBlock(dev, bi, block); - - - - if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) { - /* - * The gc did not complete. Set block state back to FULL - * because checkpointing does not restore gc. - */ - bi->blockState = YAFFS_BLOCK_STATE_FULL; - } else { - /* The gc completed. */ /* Do any required cleanups */ - for (i = 0; i < dev->nCleanups; i++) { + for (i = 0; i < cleanups; i++) { /* Time to delete the file too */ object = yaffs_FindObjectByNumber(dev, @@ -2350,185 +3244,29 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, } - - chunksAfter = yaffs_GetErasedChunks(dev); - if (chunksBefore >= chunksAfter) { - T(YAFFS_TRACE_GC, - (TSTR - ("gc did not increase free chunks before %d after %d" - TENDSTR), chunksBefore, chunksAfter)); - } - dev->gcBlock = 0; - dev->gcChunk = 0; - dev->nCleanups = 0; } - dev->gcDisable = 0; + yaffs_VerifyCollectedBlock(dev, bi, block); + + chunksAfter = yaffs_GetErasedChunks(dev); + if (chunksBefore >= chunksAfter) { + T(YAFFS_TRACE_GC, + (TSTR + ("gc did not increase free chunks before %d after %d" + TENDSTR), chunksBefore, chunksAfter)); + } + + /* 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 retVal; } -/* - * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough) - * for garbage collection. - */ - -static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, - int aggressive, - int background) -{ - int i; - int iterations; - unsigned selected = 0; - int prioritised = 0; - int prioritisedExists = 0; - yaffs_BlockInfo *bi; - int threshold; - - /* First let's see if we need to grab a prioritised block */ - if (dev->hasPendingPrioritisedGCs && !aggressive) { - dev->gcDirtiest = 0; - bi = dev->blockInfo; - for (i = dev->internalStartBlock; - i <= dev->internalEndBlock && !selected; - i++) { - - if (bi->gcPrioritise) { - prioritisedExists = 1; - if (bi->blockState == YAFFS_BLOCK_STATE_FULL && - yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) { - selected = i; - prioritised = 1; - } - } - bi++; - } - - /* - * If there is a prioritised block and none was selected then - * this happened because there is at least one old dirty block gumming - * up the works. Let's gc the oldest dirty block. - */ - - if(prioritisedExists && - !selected && - dev->oldestDirtyBlock > 0) - selected = dev->oldestDirtyBlock; - - if (!prioritisedExists) /* None found, so we can clear this */ - dev->hasPendingPrioritisedGCs = 0; - } - - /* If we're doing aggressive GC then we are happy to take a less-dirty block, and - * search harder. - * else (we're doing a leasurely gc), then we only bother to do this if the - * block has only a few pages in use. - */ - - if (!selected){ - int pagesUsed; - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; - if (aggressive){ - threshold = dev->param.nChunksPerBlock; - iterations = nBlocks; - } else { - int maxThreshold; - - if(background) - maxThreshold = dev->param.nChunksPerBlock/2; - else - maxThreshold = dev->param.nChunksPerBlock/8; - - if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD) - maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD; - - threshold = background ? - (dev->gcNotDone + 2) * 2 : 0; - if(threshold maxThreshold) - threshold = maxThreshold; - - iterations = nBlocks / 16 + 1; - if (iterations > 100) - iterations = 100; - } - - for (i = 0; - i < iterations && - (dev->gcDirtiest < 1 || - dev->gcPagesInUse > YAFFS_GC_GOOD_ENOUGH); - i++) { - dev->gcBlockFinder++; - if (dev->gcBlockFinder < dev->internalStartBlock || - dev->gcBlockFinder > dev->internalEndBlock) - dev->gcBlockFinder = dev->internalStartBlock; - - bi = yaffs_GetBlockInfo(dev, dev->gcBlockFinder); - - pagesUsed = bi->pagesInUse - bi->softDeletions; - - if (bi->blockState == YAFFS_BLOCK_STATE_FULL && - pagesUsed < dev->param.nChunksPerBlock && - (dev->gcDirtiest < 1 || pagesUsed < dev->gcPagesInUse) && - yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) { - dev->gcDirtiest = dev->gcBlockFinder; - dev->gcPagesInUse = pagesUsed; - } - } - - if(dev->gcDirtiest > 0 && dev->gcPagesInUse <= threshold) - selected = dev->gcDirtiest; - } - - /* - * If nothing has been selected for a while, try selecting the oldest dirty - * because that's gumming up the works. - */ - - if(!selected && dev->param.isYaffs2 && - dev->gcNotDone >= ( background ? 10 : 20)){ - yaffs2_FindOldestDirtySequence(dev); - if(dev->oldestDirtyBlock > 0) { - selected = dev->oldestDirtyBlock; - dev->gcDirtiest = selected; - dev->oldestDirtyGCs++; - bi = yaffs_GetBlockInfo(dev, selected); - dev->gcPagesInUse = bi->pagesInUse - bi->softDeletions; - } else - dev->gcNotDone = 0; - } - - if(selected){ - T(YAFFS_TRACE_GC, - (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), - selected, - dev->param.nChunksPerBlock - dev->gcPagesInUse, - prioritised)); - - dev->nGCBlocks++; - if(background) - dev->backgroundGCs++; - - dev->gcDirtiest = 0; - dev->gcPagesInUse = 0; - dev->gcNotDone = 0; - if(dev->refreshSkip > 0) - dev->refreshSkip--; - } else{ - dev->gcNotDone++; - T(YAFFS_TRACE_GC, - (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR), - dev->gcBlockFinder, dev->gcNotDone, - threshold, - dev->gcDirtiest, dev->gcPagesInUse, - dev->oldestDirtyBlock, - background ? " bg" : "")); - } - - return selected; -} - /* New garbage collector * If we're very low on erased blocks then we do aggressive garbage collection * otherwise we do "leasurely" garbage collection. @@ -2538,111 +3276,72 @@ static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, * The idea is to help clear out space in a more spread-out manner. * Dunno if it really does anything useful. */ -static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background) +static int yaffs_CheckGarbageCollection(yaffs_Device *dev) { - int aggressive = 0; + int block; + int aggressive; int gcOk = YAFFS_OK; int maxTries = 0; - int minErased; - int erasedChunks; + int checkpointBlockAdjust; - if(dev->param.gcControl && - (dev->param.gcControl(dev) & 1) == 0) - return YAFFS_OK; - - if (dev->gcDisable) { + 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 collection does not increase space. + * We'll only see looping here if the erase of the collected block fails. */ do { maxTries++; - checkpointBlockAdjust = yaffs2_CalcCheckpointBlocksRequired(dev); + checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; + if (checkpointBlockAdjust < 0) + checkpointBlockAdjust = 0; - minErased = dev->param.nReservedBlocks + checkpointBlockAdjust + 1; - erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock; - - /* If we need a block soon then do aggressive gc.*/ - if (dev->nErasedBlocks < minErased) + if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) { + /* We need a block soon...*/ aggressive = 1; - else { - if(!background && erasedChunks > (dev->nFreeChunks / 4)) - break; - - if(dev->gcSkip > 20) - dev->gcSkip = 20; - if(erasedChunks < dev->nFreeChunks/2 || - dev->gcSkip < 1 || - background) - aggressive = 0; - else { - dev->gcSkip--; - break; - } + } else { + /* We're in no hurry */ + aggressive = 0; } - dev->gcSkip = 5; - - /* If we don't already have a block being gc'd then see if we should start another */ - - if (dev->gcBlock < 1 && !aggressive) { - dev->gcBlock = yaffs2_FindRefreshBlock(dev); + if (dev->gcBlock <= 0) { + dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive); dev->gcChunk = 0; - dev->nCleanups=0; - } - if (dev->gcBlock < 1) { - dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background); - dev->gcChunk = 0; - dev->nCleanups=0; } - if (dev->gcBlock > 0) { - dev->allGCs++; + block = dev->gcBlock; + + if (block > 0) { + dev->garbageCollections++; if (!aggressive) - dev->passiveGCs++; + dev->passiveGarbageCollections++; T(YAFFS_TRACE_GC, (TSTR ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR), dev->nErasedBlocks, aggressive)); - gcOk = yaffs_GarbageCollectBlock(dev, dev->gcBlock, aggressive); + gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive); } - if (dev->nErasedBlocks < (dev->param.nReservedBlocks) && dev->gcBlock > 0) { + if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) { T(YAFFS_TRACE_GC, (TSTR ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" - TENDSTR), dev->nErasedBlocks, maxTries, dev->gcBlock)); + TENDSTR), dev->nErasedBlocks, maxTries, block)); } - } while ((dev->nErasedBlocks < dev->param.nReservedBlocks) && - (dev->gcBlock > 0) && + } while ((dev->nErasedBlocks < dev->nReservedBlocks) && + (block > 0) && (maxTries < 2)); return aggressive ? gcOk : YAFFS_OK; } -/* - * yaffs_BackgroundGarbageCollect() - * Garbage collects. Intended to be called from a background thread. - * Returns non-zero if at least half the free chunks are erased. - */ -int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency) -{ - int erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock; - - T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency)); - - yaffs_CheckGarbageCollection(dev, 1); - return erasedChunks > dev->nFreeChunks/2; -} - /*------------------------- TAGS --------------------------------*/ static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, @@ -2712,21 +3411,76 @@ static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode, /* Delete the entry in the filestructure (if found) */ if (retVal != -1) - yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, 0); + yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0); } return retVal; } +#ifdef YAFFS_PARANOID -int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, - int chunkInNAND, int inScan) +static int yaffs_CheckFileSanity(yaffs_Object *in) +{ + int chunk; + int nChunks; + int fSize; + int failed = 0; + int objId; + yaffs_Tnode *tn; + yaffs_Tags localTags; + yaffs_Tags *tags = &localTags; + int theChunk; + int chunkDeleted; + + if (in->variantType != YAFFS_OBJECT_TYPE_FILE) + return YAFFS_FAIL; + + objId = in->objectId; + fSize = in->variant.fileVariant.fileSize; + nChunks = + (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk; + + for (chunk = 1; chunk <= nChunks; chunk++) { + tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant, + chunk); + + if (tn) { + + theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk); + + if (yaffs_CheckChunkBits + (dev, theChunk / dev->nChunksPerBlock, + theChunk % dev->nChunksPerBlock)) { + + yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk, + tags, + &chunkDeleted); + if (yaffs_TagsMatch + (tags, in->objectId, chunk, chunkDeleted)) { + /* found it; */ + + } + } else { + + failed = 1; + } + + } else { + /* T(("No level 0 found for %d\n", chunk)); */ + } + } + + return failed ? YAFFS_FAIL : YAFFS_OK; +} + +#endif + +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; * for backward scanning inScan is < 0 - * - * chunkInNAND = 0 is a dummy insert to make sure the tnodes are there. */ yaffs_Tnode *tn; @@ -2758,10 +3512,6 @@ int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, NULL); if (!tn) return YAFFS_FAIL; - - if(!chunkInNAND) - /* Dummy insert, bail now */ - return YAFFS_OK; existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode); @@ -2776,7 +3526,7 @@ int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, */ if (existingChunk > 0) { - /* NB Right now existing chunk will not be real chunkId if the chunk group size > 1 + /* NB Right now existing chunk will not be real chunkId if the device >= 32MB * thus we have to do a FindChunkInFile to get the real chunk id. * * We have a duplicate now we need to decide which one to use: @@ -2818,7 +3568,8 @@ int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, } if ((inScan > 0) && - (existingChunk <= 0 || + (in->myDev->isYaffs2 || + existingChunk <= 0 || ((existingSerial + 1) & 3) == newSerial)) { /* Forward scanning. * Use new @@ -2842,7 +3593,7 @@ int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, if (existingChunk == 0) in->nDataChunks++; - yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, chunkInNAND); + yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND); return YAFFS_OK; } @@ -2877,8 +3628,8 @@ void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn) return; dev->nDeletions++; - block = chunkId / dev->param.nChunksPerBlock; - page = chunkId % dev->param.nChunksPerBlock; + block = chunkId / dev->nChunksPerBlock; + page = chunkId % dev->nChunksPerBlock; if (!yaffs_CheckChunkBit(dev, block, page)) @@ -2887,14 +3638,14 @@ void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn) chunkId)); bi = yaffs_GetBlockInfo(dev, block); - - yaffs2_UpdateOldestDirtySequence(dev, block, bi); + + yaffs_UpdateOldestDirtySequence(dev, bi); T(YAFFS_TRACE_DELETION, (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId)); - if (!dev->param.isYaffs2 && markNAND && - bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) { + if (markNAND && + bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) { yaffs_InitialiseTags(&tags); @@ -2947,16 +3698,10 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, yaffs_Device *dev = in->myDev; - yaffs_CheckGarbageCollection(dev,0); + yaffs_CheckGarbageCollection(dev); - /* Get the previous chunk at this location in the file if it exists. - * If it does not exist then put a zero into the tree. This creates - * the tnode now, rather than later when it is harder to clean up. - */ + /* Get the previous chunk at this location in the file if it exists */ prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags); - if(prevChunkId < 1 && - !yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0)) - return 0; /* Set up new tags */ yaffs_InitialiseTags(&newTags); @@ -2967,24 +3712,23 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, (prevChunkId > 0) ? prevTags.serialNumber + 1 : 1; newTags.byteCount = nBytes; - if (nBytes < 1 || nBytes > dev->param.totalBytesPerChunk) { + if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) { T(YAFFS_TRACE_ERROR, (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes)); YBUG(); } - - + newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, useReserve); - if (newChunkId > 0) { + if (newChunkId >= 0) { yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0); if (prevChunkId > 0) yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__); - yaffs_VerifyFileSanity(in); + yaffs_CheckFileSanity(in); } return newChunkId; @@ -2994,7 +3738,7 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, * If name is not NULL, then that new name is used. */ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, - int isShrink, int shadows, yaffs_XAttrMod *xmod) + int isShrink, int shadows) { yaffs_BlockInfo *bi; @@ -3008,7 +3752,6 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, int newChunkId; yaffs_ExtendedTags newTags; yaffs_ExtendedTags oldTags; - const YCHAR *alias = NULL; __u8 *buffer = NULL; YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1]; @@ -3020,9 +3763,9 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, if (!in->fake || in == dev->rootDir || /* The rootDir should also be saved */ - force || xmod) { + force) { - yaffs_CheckGarbageCollection(dev,0); + yaffs_CheckGarbageCollection(dev); yaffs_CheckObjectDetailsLoaded(in); buffer = yaffs_GetTempBuffer(in->myDev, __LINE__); @@ -3037,9 +3780,9 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, yaffs_VerifyObjectHeader(in, oh, &oldTags, 0); memcpy(oldName, oh->name, sizeof(oh->name)); - memset(buffer, 0xFF, sizeof(yaffs_ObjectHeader)); - } else - memset(buffer, 0xFF, dev->nDataBytesPerChunk); + } + + memset(buffer, 0xFF, dev->nDataBytesPerChunk); oh->type = in->variantType; oh->yst_mode = in->yst_mode; @@ -3067,7 +3810,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, if (name && *name) { memset(oh->name, 0, sizeof(oh->name)); - yaffs_LoadObjectHeaderFromName(dev,oh->name,name); + yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH); } else if (prevChunkId > 0) memcpy(oh->name, oldName, sizeof(oh->name)); else @@ -3097,21 +3840,13 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, /* Do nothing */ break; case YAFFS_OBJECT_TYPE_SYMLINK: - alias = in->variant.symLinkVariant.alias; - if(!alias) - alias = _Y("no alias"); yaffs_strncpy(oh->alias, - alias, + in->variant.symLinkVariant.alias, YAFFS_MAX_ALIAS_LENGTH); oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; break; } - /* process any xattrib modifications */ - if(xmod) - yaffs_ApplyXMod(in, (char *)buffer, xmod); - - /* Tags */ yaffs_InitialiseTags(&newTags); in->serial++; @@ -3151,7 +3886,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, /* If this was a shrink, then mark the block that the chunk lives on */ if (isShrink) { bi = yaffs_GetBlockInfo(in->myDev, - newChunkId / in->myDev->param.nChunksPerBlock); + newChunkId / in->myDev->nChunksPerBlock); bi->hasShrinkHeader = 1; } @@ -3185,7 +3920,7 @@ static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj) yaffs_Device *dev = obj->myDev; int i; yaffs_ChunkCache *cache; - int nCaches = obj->myDev->param.nShortOpCaches; + int nCaches = obj->myDev->nShortOpCaches; for (i = 0; i < nCaches; i++) { cache = &dev->srCache[i]; @@ -3205,7 +3940,7 @@ static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) int i; yaffs_ChunkCache *cache; int chunkWritten = 0; - int nCaches = obj->myDev->param.nShortOpCaches; + int nCaches = obj->myDev->nShortOpCaches; if (nCaches > 0) { do { @@ -3257,7 +3992,7 @@ static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) void yaffs_FlushEntireDeviceCache(yaffs_Device *dev) { yaffs_Object *obj; - int nCaches = dev->param.nShortOpCaches; + int nCaches = dev->nShortOpCaches; int i; /* Find a dirty object in the cache and flush it... @@ -3288,8 +4023,8 @@ static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev) { int i; - if (dev->param.nShortOpCaches > 0) { - for (i = 0; i < dev->param.nShortOpCaches; i++) { + if (dev->nShortOpCaches > 0) { + for (i = 0; i < dev->nShortOpCaches; i++) { if (!dev->srCache[i].object) return &dev->srCache[i]; } @@ -3306,7 +4041,7 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) int i; int pushout; - if (dev->param.nShortOpCaches > 0) { + if (dev->nShortOpCaches > 0) { /* Try find a non-dirty one... */ cache = yaffs_GrabChunkCacheWorker(dev); @@ -3325,7 +4060,7 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) cache = NULL; pushout = -1; - for (i = 0; i < dev->param.nShortOpCaches; i++) { + for (i = 0; i < dev->nShortOpCaches; i++) { if (dev->srCache[i].object && !dev->srCache[i].locked && (dev->srCache[i].lastUse < usage || !cache)) { @@ -3355,8 +4090,8 @@ static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, { yaffs_Device *dev = obj->myDev; int i; - if (dev->param.nShortOpCaches > 0) { - for (i = 0; i < dev->param.nShortOpCaches; i++) { + if (dev->nShortOpCaches > 0) { + for (i = 0; i < dev->nShortOpCaches; i++) { if (dev->srCache[i].object == obj && dev->srCache[i].chunkId == chunkId) { dev->cacheHits++; @@ -3373,11 +4108,11 @@ static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int isAWrite) { - if (dev->param.nShortOpCaches > 0) { + if (dev->nShortOpCaches > 0) { if (dev->srLastUse < 0 || dev->srLastUse > 100000000) { /* Reset the cache usages */ int i; - for (i = 1; i < dev->param.nShortOpCaches; i++) + for (i = 1; i < dev->nShortOpCaches; i++) dev->srCache[i].lastUse = 0; dev->srLastUse = 0; @@ -3398,7 +4133,7 @@ static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, */ static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId) { - if (object->myDev->param.nShortOpCaches > 0) { + if (object->myDev->nShortOpCaches > 0) { yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId); if (cache) @@ -3414,15 +4149,577 @@ static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in) int i; yaffs_Device *dev = in->myDev; - if (dev->param.nShortOpCaches > 0) { + if (dev->nShortOpCaches > 0) { /* Invalidate it. */ - for (i = 0; i < dev->param.nShortOpCaches; i++) { + for (i = 0; i < dev->nShortOpCaches; i++) { if (dev->srCache[i].object == in) dev->srCache[i].object = NULL; } } } +/*--------------------- Checkpointing --------------------*/ + + +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; +} + +static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head) +{ + 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) && + (cp.version == YAFFS_CHECKPOINT_VERSION) && + (cp.head == ((head) ? 1 : 0)); + return ok ? 1 : 0; +} + +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; +} + +static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev, + yaffs_CheckpointDevice *cp) +{ + dev->nErasedBlocks = cp->nErasedBlocks; + dev->allocationBlock = cp->allocationBlock; + dev->allocationPage = cp->allocationPage; + dev->nFreeChunks = cp->nFreeChunks; + + dev->nDeletedFiles = cp->nDeletedFiles; + dev->nUnlinkedFiles = cp->nUnlinkedFiles; + dev->nBackgroundDeletions = cp->nBackgroundDeletions; + dev->sequenceNumber = cp->sequenceNumber; +} + + +static int yaffs_WriteCheckpointDevice(yaffs_Device *dev) +{ + yaffs_CheckpointDevice cp; + __u32 nBytes; + __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 */ + if (ok) { + nBytes = nBlocks * dev->chunkBitmapStride; + ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes); + } + return ok ? 1 : 0; + +} + +static int yaffs_ReadCheckpointDevice(yaffs_Device *dev) +{ + yaffs_CheckpointDevice cp; + __u32 nBytes; + __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); + + 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; +} + +static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp, + yaffs_Object *obj) +{ + + cp->objectId = obj->objectId; + cp->parentId = (obj->parent) ? obj->parent->objectId : 0; + cp->hdrChunk = obj->hdrChunk; + cp->variantType = obj->variantType; + cp->deleted = obj->deleted; + cp->softDeleted = obj->softDeleted; + cp->unlinked = obj->unlinked; + cp->fake = obj->fake; + cp->renameAllowed = obj->renameAllowed; + 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) + cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId; +} + +static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp) +{ + + yaffs_Object *parent; + + if (obj->variantType != cp->variantType) { + T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d " + TCONT("chunk %d does not match existing object type %d") + TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk, + obj->variantType)); + return 0; + } + + obj->objectId = cp->objectId; + + if (cp->parentId) + parent = yaffs_FindOrCreateObjectByNumber( + obj->myDev, + cp->parentId, + YAFFS_OBJECT_TYPE_DIRECTORY); + else + parent = NULL; + + if (parent) { + if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { + T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d" + TCONT(" chunk %d Parent type, %d, not directory") + TENDSTR), + cp->objectId, cp->parentId, cp->variantType, + cp->hdrChunk, parent->variantType)); + return 0; + } + yaffs_AddObjectToDirectory(parent, obj); + } + + obj->hdrChunk = cp->hdrChunk; + obj->variantType = cp->variantType; + obj->deleted = cp->deleted; + obj->softDeleted = cp->softDeleted; + obj->unlinked = cp->unlinked; + obj->fake = cp->fake; + obj->renameAllowed = cp->renameAllowed; + 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->hdrChunk > 0) + obj->lazyLoaded = 1; + return 1; +} + + + +static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn, + __u32 level, int chunkOffset) +{ + int i; + yaffs_Device *dev = in->myDev; + int ok = 1; + int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + + if (tnodeSize < sizeof(yaffs_Tnode)) + tnodeSize = sizeof(yaffs_Tnode); + + + if (tn) { + if (level > 0) { + + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { + if (tn->internal[i]) { + ok = yaffs_CheckpointTnodeWorker(in, + tn->internal[i], + level - 1, + (chunkOffset<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)) == + sizeof(endMarker)); + } + + return ok ? 1 : 0; +} + +static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj) +{ + __u32 baseChunk; + int ok = 1; + yaffs_Device *dev = obj->myDev; + yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant; + yaffs_Tnode *tn; + int nread = 0; + int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + + 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 */ + + + tn = yaffs_GetTnodeRaw(dev); + if (tn) + 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; +} + + +static int yaffs_WriteCheckpointObjects(yaffs_Device *dev) +{ + yaffs_Object *obj; + yaffs_CheckpointObject cp; + int i; + int ok = 1; + struct ylist_head *lh; + + + /* Iterate through the objects in each hash entry, + * dumping them to the checkpointing stream. + */ + + 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.hdrChunk, (unsigned) obj)); + + ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); + + if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE) + ok = yaffs_WriteCheckpointTnodes(obj); + } + } + } + } + + /* 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; +} + +static int yaffs_ReadCheckpointObjects(yaffs_Device *dev) +{ + yaffs_Object *obj; + yaffs_CheckpointObject cp; + 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)) { + T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR), + 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.hdrChunk)); + + if (ok && cp.objectId == ~0) + done = 1; + else if (ok) { + obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType); + if (obj) { + ok = yaffs_CheckpointObjectToObject(obj, &cp); + if (!ok) + break; + if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) { + ok = yaffs_ReadCheckpointTnodes(obj); + } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { + obj->hardLinks.next = + (struct ylist_head *) hardList; + hardList = obj; + } + } else + ok = 0; + } + } + + if (ok) + yaffs_HardlinkFixup(dev, hardList); + + return ok ? 1 : 0; +} + +static int yaffs_WriteCheckpointSum(yaffs_Device *dev) +{ + __u32 checkpointSum; + int ok; + + yaffs_GetCheckpointSum(dev, &checkpointSum); + + ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum)); + + if (!ok) + return 0; + + return 1; +} + +static int yaffs_ReadCheckpointSum(yaffs_Device *dev) +{ + __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; +} + + +static int yaffs_WriteCheckpointData(yaffs_Device *dev) +{ + 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); + } + if (ok) { + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR))); + ok = yaffs_WriteCheckpointDevice(dev); + } + if (ok) { + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR))); + ok = yaffs_WriteCheckpointObjects(dev); + } + if (ok) { + 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 + dev->isCheckpointed = 0; + + return dev->isCheckpointed; +} + +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))); + ok = yaffs_ReadCheckpointValidityMarker(dev, 1); + } + if (ok) { + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR))); + ok = yaffs_ReadCheckpointDevice(dev); + } + if (ok) { + 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)); + } + + if (!yaffs_CheckpointClose(dev)) + ok = 0; + + if (ok) + dev->isCheckpointed = 1; + else + dev->isCheckpointed = 0; + + return ok ? 1 : 0; + +} + +static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) +{ + if (dev->isCheckpointed || + dev->blocksInCheckpoint > 0) { + dev->isCheckpointed = 0; + yaffs_CheckpointInvalidateStream(dev); + if (dev->superBlock && dev->markSuperBlockDirty) + dev->markSuperBlockDirty(dev->superBlock); + } +} + + +int yaffs_CheckpointSave(yaffs_Device *dev) +{ + + T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); + + yaffs_VerifyObjects(dev); + yaffs_VerifyBlocks(dev); + yaffs_VerifyFreeChunks(dev); + + if (!dev->isCheckpointed) { + yaffs_InvalidateCheckpoint(dev); + yaffs_WriteCheckpointData(dev); + } + + T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); + + return dev->isCheckpointed; +} + +int yaffs_CheckpointRestore(yaffs_Device *dev) +{ + int retval; + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); + + retval = yaffs_ReadCheckpointData(dev); + + if (dev->isCheckpointed) { + yaffs_VerifyObjects(dev); + yaffs_VerifyBlocks(dev); + yaffs_VerifyFreeChunks(dev); + } + + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); + + return retval; +} /*--------------------- File read/write ------------------------ * Read and write have very similar structures. @@ -3469,8 +4766,8 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset, * or we're using inband tags then use the cache (if there is caching) * else bypass the cache. */ - if (cache || nToCopy != dev->nDataBytesPerChunk || dev->param.inbandTags) { - if (dev->param.nShortOpCaches > 0) { + 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. */ @@ -3526,7 +4823,7 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset, return nDone; } -int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, +int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, int nBytes, int writeThrough) { @@ -3546,6 +4843,8 @@ int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, dev = in->myDev; while (n > 0 && chunkWritten >= 0) { + /* chunk = offset / dev->nDataBytesPerChunk + 1; */ + /* start = offset % dev->nDataBytesPerChunk; */ yaffs_AddrToChunk(dev, offset, &chunk, &start); if (chunk * dev->nDataBytesPerChunk + start != offset || @@ -3555,7 +4854,7 @@ int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, TENDSTR), (int)offset, chunk, start)); } - chunk++; /* File pos to chunk in file offset */ + chunk++; /* OK now check for the curveball where the start and end are in * the same chunk. @@ -3591,27 +4890,29 @@ int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, nToWriteBack = dev->nDataBytesPerChunk; } - if (nToCopy != dev->nDataBytesPerChunk || dev->param.inbandTags) { + 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->param.nShortOpCaches > 0) { + 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(dev, 1)) { - cache = yaffs_GrabChunkCache(dev); + && yaffs_CheckSpaceForAllocation(in-> + myDev)) { + cache = yaffs_GrabChunkCache(in->myDev); cache->object = in; cache->chunkId = chunk; cache->dirty = 0; cache->locked = 0; yaffs_ReadChunkDataFromObject(in, chunk, - cache->data); + cache-> + data); } else if (cache && !cache->dirty && - !yaffs_CheckSpaceForAllocation(dev, 1)) { + !yaffs_CheckSpaceForAllocation(in->myDev)) { /* Drop the cache if it was a read cache item and * no space check has been made for it. */ @@ -3702,14 +5003,6 @@ int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, return nDone; } -int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, - int nBytes, int writeThrough) -{ - yaffs2_HandleHole(in,offset); - return yaffs_DoWriteDataToFile(in,buffer,offset,nBytes,writeThrough); -} - - /* ---------------------- File resizing stuff ------------------ */ @@ -3738,10 +5031,10 @@ static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize) chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL); if (chunkId > 0) { if (chunkId < - (dev->internalStartBlock * dev->param.nChunksPerBlock) + (dev->internalStartBlock * dev->nChunksPerBlock) || chunkId >= ((dev->internalEndBlock + - 1) * dev->param.nChunksPerBlock)) { + 1) * dev->nChunksPerBlock)) { T(YAFFS_TRACE_ALWAYS, (TSTR("Found daft chunkId %d for %d" TENDSTR), chunkId, i)); @@ -3754,61 +5047,58 @@ static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize) } - -void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize) -{ - int newFullChunks; - __u32 newSizeOfPartialChunk; - yaffs_Device *dev = obj->myDev; - - yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk); - - yaffs_PruneResizedChunks(obj, 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 */ - yaffs_ReadChunkDataFromObject(obj, lastChunk, localBuffer); - memset(localBuffer + newSizeOfPartialChunk, 0, - dev->nDataBytesPerChunk - newSizeOfPartialChunk); - - yaffs_WriteChunkDataToObject(obj, lastChunk, localBuffer, - newSizeOfPartialChunk, 1); - - yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); - } - - obj->variant.fileVariant.fileSize = newSize; - - yaffs_PruneFileStructure(dev, &obj->variant.fileVariant); -} - - int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize) { - yaffs_Device *dev = in->myDev; + int oldFileSize = in->variant.fileVariant.fileSize; + __u32 newSizeOfPartialChunk; + int newFullChunks; + + yaffs_Device *dev = in->myDev; + + yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk); yaffs_FlushFilesChunkCache(in); yaffs_InvalidateWholeChunkCache(in); - yaffs_CheckGarbageCollection(dev,0); + yaffs_CheckGarbageCollection(dev); if (in->variantType != YAFFS_OBJECT_TYPE_FILE) return YAFFS_FAIL; if (newSize == oldFileSize) return YAFFS_OK; - - if(newSize > oldFileSize){ - yaffs2_HandleHole(in,newSize); + + 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 */ + yaffs_ReadChunkDataFromObject(in, lastChunk, + localBuffer); + + memset(localBuffer + newSizeOfPartialChunk, 0, + dev->nDataBytesPerChunk - newSizeOfPartialChunk); + + yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer, + newSizeOfPartialChunk, 1); + + yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); + } + in->variant.fileVariant.fileSize = newSize; + + yaffs_PruneFileStructure(dev, &in->variant.fileVariant); } else { - /* newSize < oldFileSize */ - yaffs_ResizeDown(in, newSize); - } + /* newsSize > oldFileSize */ + in->variant.fileVariant.fileSize = newSize; + } + /* Write a new object header to reflect the resize. * show we've shrunk the file, if need be @@ -3819,25 +5109,21 @@ int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize) !in->isShadowed && in->parent->objectId != YAFFS_OBJECTID_UNLINKED && in->parent->objectId != YAFFS_OBJECTID_DELETED) - yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL); - + yaffs_UpdateObjectHeader(in, NULL, 0, + (newSize < oldFileSize) ? 1 : 0, 0); return YAFFS_OK; } loff_t yaffs_GetFileSize(yaffs_Object *obj) { - YCHAR *alias = NULL; obj = yaffs_GetEquivalentObject(obj); switch (obj->variantType) { case YAFFS_OBJECT_TYPE_FILE: return obj->variant.fileVariant.fileSize; case YAFFS_OBJECT_TYPE_SYMLINK: - alias = obj->variant.symLinkVariant.alias; - if(!alias) - return 0; - return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH); + return yaffs_strlen(obj->variant.symLinkVariant.alias); default: return 0; } @@ -3845,27 +5131,23 @@ loff_t yaffs_GetFileSize(yaffs_Object *obj) -int yaffs_FlushFile(yaffs_Object *in, int updateTime, int dataSync) +int yaffs_FlushFile(yaffs_Object *in, int updateTime) { int retVal; if (in->dirty) { yaffs_FlushFilesChunkCache(in); - if(dataSync) /* Only sync data */ - retVal=YAFFS_OK; - else { - if (updateTime) { + if (updateTime) { #ifdef CONFIG_YAFFS_WINCE - yfsd_WinFileTimeNow(in->win_mtime); + yfsd_WinFileTimeNow(in->win_mtime); #else - in->yst_mtime = Y_CURRENT_TIME; + in->yst_mtime = Y_CURRENT_TIME; #endif - } - - retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL) >= - 0) ? YAFFS_OK : YAFFS_FAIL; } + + retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >= + 0) ? YAFFS_OK : YAFFS_FAIL; } else { retVal = YAFFS_OK; } @@ -3880,7 +5162,7 @@ static int yaffs_DoGenericObjectDeletion(yaffs_Object *in) /* First off, invalidate the file's data in the cache, without flushing. */ yaffs_InvalidateWholeChunkCache(in); - if (in->myDev->param.isYaffs2 && (in->parent != in->myDev->deletedDir)) { + 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, _Y("deleted"), 0, 0); @@ -3904,10 +5186,14 @@ static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in) int retVal; int immediateDeletion = 0; - yaffs_Device *dev = in->myDev; +#ifdef __KERNEL__ if (!in->myInode) immediateDeletion = 1; +#else + if (in->inUse <= 0) + immediateDeletion = 1; +#endif if (immediateDeletion) { retVal = @@ -3918,7 +5204,7 @@ static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in) in->objectId)); in->deleted = 1; in->myDev->nDeletedFiles++; - if (dev->param.disableSoftDelete || dev->param.isYaffs2) + if (1 || in->myDev->isYaffs2) yaffs_ResizeFile(in, 0); yaffs_SoftDeleteFile(in); } else { @@ -3934,11 +5220,9 @@ static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in) int yaffs_DeleteFile(yaffs_Object *in) { int retVal = YAFFS_OK; - int deleted; /* Need to cache value on stack if in is freed */ - yaffs_Device *dev = in->myDev; + int deleted = in->deleted; - if (dev->param.disableSoftDelete || dev->param.isYaffs2) - yaffs_ResizeFile(in, 0); + yaffs_ResizeFile(in, 0); if (in->nDataChunks > 0) { /* Use soft deletion if there is data in the file. @@ -3947,8 +5231,6 @@ int yaffs_DeleteFile(yaffs_Object *in) if (!in->unlinked) retVal = yaffs_UnlinkFileIfNeeded(in); - deleted = in->deleted; - if (retVal == YAFFS_OK && in->unlinked && !in->deleted) { in->deleted = 1; deleted = 1; @@ -3983,9 +5265,7 @@ static int yaffs_DeleteDirectory(yaffs_Object *obj) static int yaffs_DeleteSymLink(yaffs_Object *in) { - if(in->variant.symLinkVariant.alias) - YFREE(in->variant.symLinkVariant.alias); - in->variant.symLinkVariant.alias=NULL; + YFREE(in->variant.symLinkVariant.alias); return yaffs_DoGenericObjectDeletion(in); } @@ -4007,10 +5287,6 @@ int retVal = -1; retVal = yaffs_DeleteFile(obj); break; case YAFFS_OBJECT_TYPE_DIRECTORY: - if(!ylist_empty(&obj->variant.directoryVariant.dirty)){ - T(YAFFS_TRACE_BACKGROUND, (TSTR("Remove object %d from dirty directories" TENDSTR),obj->objectId)); - ylist_del_init(&obj->variant.directoryVariant.dirty); - } return yaffs_DeleteDirectory(obj); break; case YAFFS_OBJECT_TYPE_SYMLINK: @@ -4035,8 +5311,13 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj) int immediateDeletion = 0; +#ifdef __KERNEL__ if (!obj->myInode) immediateDeletion = 1; +#else + if (obj->inUse <= 0) + immediateDeletion = 1; +#endif if(obj) yaffs_UpdateParent(obj->parent); @@ -4053,26 +5334,23 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj) * Instead, we do the following: * - Select a hardlink. * - Unhook it from the hard links - * - Move it from its parent directory (so that the rename can work) + * - Unhook it from its parent directory (so that the rename can work) * - Rename the object to the hardlink's name. * - Delete the hardlink */ yaffs_Object *hl; - yaffs_Object *parent; int retVal; YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks); - yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1); - parent = hl->parent; - ylist_del_init(&hl->hardLinks); + ylist_del_init(&hl->siblings); - yaffs_AddObjectToDirectory(obj->myDev->unlinkedDir, hl); + yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1); - retVal = yaffs_ChangeObjectName(obj,parent, name, 0, 0); + retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0); if (retVal == YAFFS_OK) retVal = yaffs_DoGenericObjectDeletion(hl); @@ -4085,7 +5363,6 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj) return yaffs_DeleteFile(obj); break; case YAFFS_OBJECT_TYPE_DIRECTORY: - ylist_del_init(&obj->variant.directoryVariant.dirty); return yaffs_DeleteDirectory(obj); break; case YAFFS_OBJECT_TYPE_SYMLINK: @@ -4126,7 +5403,7 @@ int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name) /*----------------------- Initialisation Scanning ---------------------- */ -void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, +static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, int backwardScanning) { yaffs_Object *obj; @@ -4160,8 +5437,13 @@ void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, } +typedef struct { + int seq; + int block; +} yaffs_BlockIndex; -void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList) + +static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList) { yaffs_Object *hl; yaffs_Object *in; @@ -4190,6 +5472,29 @@ void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList) } + + + +static int ybicmp(const void *a, const void *b) +{ + register int aseq = ((yaffs_BlockIndex *)a)->seq; + register int bseq = ((yaffs_BlockIndex *)b)->seq; + register int ablock = ((yaffs_BlockIndex *)a)->block; + register int bblock = ((yaffs_BlockIndex *)b)->block; + if (aseq == bseq) + return ablock - bblock; + else + return aseq - bseq; +} + + +struct yaffs_ShadowFixerStruct { + int objectId; + int shadowedId; + struct yaffs_ShadowFixerStruct *next; +}; + + static void yaffs_StripDeletedObjects(yaffs_Device *dev) { /* @@ -4199,9 +5504,6 @@ static void yaffs_StripDeletedObjects(yaffs_Device *dev) struct ylist_head *n; yaffs_Object *l; - if (dev->readOnly) - return; - /* Soft delete all the unlinked files */ ylist_for_each_safe(i, n, &dev->unlinkedDir->variant.directoryVariant.children) { @@ -4237,7 +5539,7 @@ static void yaffs_StripDeletedObjects(yaffs_Device *dev) * This fixes the problem where directories might have inadvertently been deleted * leaving the object "hanging" without being rooted in the directory tree. */ - + static int yaffs_HasNULLParent(yaffs_Device *dev, yaffs_Object *obj) { return (obj == dev->deletedDir || @@ -4255,8 +5557,6 @@ static void yaffs_FixHangingObjects(yaffs_Device *dev) int depthLimit; int hanging; - if (dev->readOnly) - return; /* Iterate through the objects in each hash entry, * looking at each object. @@ -4268,7 +5568,7 @@ static void yaffs_FixHangingObjects(yaffs_Device *dev) if (lh) { obj = ylist_entry(lh, yaffs_Object, hashLink); parent= obj->parent; - + if(yaffs_HasNULLParent(dev,obj)){ /* These directories are not hanging */ hanging = 0; @@ -4296,8 +5596,8 @@ static void yaffs_FixHangingObjects(yaffs_Device *dev) } if(hanging){ T(YAFFS_TRACE_SCAN, - (TSTR("Hanging object %d moved to lost and found" TENDSTR), - obj->objectId)); + (TSTR("Hanging object %d moved to lost and found" TENDSTR), + obj->objectId)); yaffs_AddObjectToDirectory(dev->lostNFoundDir,obj); } } @@ -4317,7 +5617,7 @@ static void yaffs_DeleteDirectoryContents(yaffs_Object *dir) if(dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) YBUG(); - + ylist_for_each_safe(lh, n, &dir->variant.directoryVariant.children) { if (lh) { obj = ylist_entry(lh, yaffs_Object, siblings); @@ -4331,10 +5631,10 @@ static void yaffs_DeleteDirectoryContents(yaffs_Object *dir) /* Need to use UnlinkObject since Delete would not handle * hardlinked objects correctly. */ - yaffs_UnlinkObject(obj); + yaffs_UnlinkObject(obj); } } - + } static void yaffs_EmptyLostAndFound(yaffs_Device *dev) @@ -4342,6 +5642,445 @@ static void yaffs_EmptyLostAndFound(yaffs_Device *dev) yaffs_DeleteDirectoryContents(dev->lostNFoundDir); } +static int yaffs_Scan(yaffs_Device *dev) +{ + yaffs_ExtendedTags tags; + int blk; + int blockIterator; + int startIterator; + int endIterator; + int result; + + int chunk; + int c; + int deleted; + yaffs_BlockState state; + yaffs_Object *hardList = NULL; + yaffs_BlockInfo *bi; + __u32 sequenceNumber; + yaffs_ObjectHeader *oh; + yaffs_Object *in; + yaffs_Object *parent; + + int alloc_failed = 0; + + struct yaffs_ShadowFixerStruct *shadowFixerList = NULL; + + + __u8 *chunkData; + + + + T(YAFFS_TRACE_SCAN, + (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR), + dev->internalStartBlock, dev->internalEndBlock)); + + chunkData = yaffs_GetTempBuffer(dev, __LINE__); + + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; + + /* Scan all the blocks to determine their state */ + for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { + bi = yaffs_GetBlockInfo(dev, blk); + yaffs_ClearChunkBits(dev, blk); + bi->pagesInUse = 0; + bi->softDeletions = 0; + + yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); + + bi->blockState = state; + bi->sequenceNumber = sequenceNumber; + + if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK) + bi->blockState = state = YAFFS_BLOCK_STATE_DEAD; + + T(YAFFS_TRACE_SCAN_DEBUG, + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, + state, sequenceNumber)); + + if (state == YAFFS_BLOCK_STATE_DEAD) { + T(YAFFS_TRACE_BAD_BLOCKS, + (TSTR("block %d is bad" TENDSTR), blk)); + } else if (state == YAFFS_BLOCK_STATE_EMPTY) { + T(YAFFS_TRACE_SCAN_DEBUG, + (TSTR("Block empty " TENDSTR))); + dev->nErasedBlocks++; + dev->nFreeChunks += dev->nChunksPerBlock; + } + } + + startIterator = dev->internalStartBlock; + endIterator = dev->internalEndBlock; + + /* For each block.... */ + for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; + blockIterator++) { + + YYIELD(); + + YYIELD(); + + blk = blockIterator; + + bi = yaffs_GetBlockInfo(dev, blk); + state = bi->blockState; + + deleted = 0; + + /* For each chunk in each block that needs scanning....*/ + for (c = 0; !alloc_failed && c < dev->nChunksPerBlock && + state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { + /* Read the tags and decide what to do */ + chunk = blk * dev->nChunksPerBlock + c; + + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, + &tags); + + /* Let's have a good look at this chunk... */ + + if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) { + /* YAFFS1 only... + * A deleted chunk + */ + deleted++; + dev->nFreeChunks++; + /*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 is the one being allocated from + */ + + if (c == 0) { + /* We're looking at the first chunk in the block so the block is unused */ + state = YAFFS_BLOCK_STATE_EMPTY; + dev->nErasedBlocks++; + } else { + /* this is the block being allocated from */ + T(YAFFS_TRACE_SCAN, + (TSTR + (" Allocating from %d %d" TENDSTR), + blk, c)); + state = YAFFS_BLOCK_STATE_ALLOCATING; + dev->allocationBlock = blk; + dev->allocationPage = c; + dev->allocationBlockFinder = blk; + /* Set it to here to encourage the allocator to go forth from here. */ + + } + + dev->nFreeChunks += (dev->nChunksPerBlock - c); + } else if (tags.chunkId > 0) { + /* chunkId > 0 so it is a data chunk... */ + unsigned int endpos; + + yaffs_SetChunkBit(dev, blk, c); + bi->pagesInUse++; + + in = yaffs_FindOrCreateObjectByNumber(dev, + tags. + objectId, + YAFFS_OBJECT_TYPE_FILE); + /* PutChunkIntoFile checks for a clash (two data chunks with + * the same chunkId). + */ + + if (!in) + alloc_failed = 1; + + if (in) { + if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1)) + alloc_failed = 1; + } + + endpos = + (tags.chunkId - 1) * dev->nDataBytesPerChunk + + tags.byteCount; + if (in && + in->variantType == YAFFS_OBJECT_TYPE_FILE + && in->variant.fileVariant.scannedFileSize < + endpos) { + in->variant.fileVariant. + scannedFileSize = endpos; + if (!dev->useHeaderFileSize) { + in->variant.fileVariant. + fileSize = + in->variant.fileVariant. + scannedFileSize; + } + + } + /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */ + } else { + /* chunkId == 0, so it is an ObjectHeader. + * Thus, we read in the object header and make the object + */ + yaffs_SetChunkBit(dev, blk, c); + bi->pagesInUse++; + + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, + chunkData, + NULL); + + oh = (yaffs_ObjectHeader *) chunkData; + + in = yaffs_FindObjectByNumber(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 + * deleted, and worse still it has changed type. Delete the old object. + */ + + yaffs_DeleteObject(in); + + in = 0; + } + + in = yaffs_FindOrCreateObjectByNumber(dev, + tags. + objectId, + oh->type); + + if (!in) + alloc_failed = 1; + + if (in && 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) { + /* We have already filled this one. We have a duplicate and need to resolve it. */ + + unsigned existingSerial = in->serial; + unsigned newSerial = tags.serialNumber; + + if (((existingSerial + 1) & 3) == newSerial) { + /* Use new one - destroy the exisiting one */ + yaffs_DeleteChunk(dev, + in->hdrChunk, + 1, __LINE__); + in->valid = 0; + } else { + /* Use existing - destroy this one. */ + yaffs_DeleteChunk(dev, chunk, 1, + __LINE__); + } + } + + if (in && !in->valid && + (tags.objectId == YAFFS_OBJECTID_ROOT || + tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) { + /* We only load some info, don't fiddle with directory structure */ + in->valid = 1; + in->variantType = oh->type; + + in->yst_mode = oh->yst_mode; +#ifdef CONFIG_YAFFS_WINCE + in->win_atime[0] = oh->win_atime[0]; + in->win_ctime[0] = oh->win_ctime[0]; + in->win_mtime[0] = oh->win_mtime[0]; + in->win_atime[1] = oh->win_atime[1]; + in->win_ctime[1] = oh->win_ctime[1]; + in->win_mtime[1] = oh->win_mtime[1]; +#else + in->yst_uid = oh->yst_uid; + in->yst_gid = oh->yst_gid; + in->yst_atime = oh->yst_atime; + in->yst_mtime = oh->yst_mtime; + in->yst_ctime = oh->yst_ctime; + in->yst_rdev = oh->yst_rdev; +#endif + in->hdrChunk = chunk; + in->serial = tags.serialNumber; + + } else if (in && !in->valid) { + /* we need to load this info */ + + in->valid = 1; + in->variantType = oh->type; + + in->yst_mode = oh->yst_mode; +#ifdef CONFIG_YAFFS_WINCE + in->win_atime[0] = oh->win_atime[0]; + in->win_ctime[0] = oh->win_ctime[0]; + in->win_mtime[0] = oh->win_mtime[0]; + in->win_atime[1] = oh->win_atime[1]; + in->win_ctime[1] = oh->win_ctime[1]; + in->win_mtime[1] = oh->win_mtime[1]; +#else + in->yst_uid = oh->yst_uid; + in->yst_gid = oh->yst_gid; + in->yst_atime = oh->yst_atime; + in->yst_mtime = oh->yst_mtime; + in->yst_ctime = oh->yst_ctime; + in->yst_rdev = oh->yst_rdev; +#endif + in->hdrChunk = chunk; + in->serial = tags.serialNumber; + + yaffs_SetObjectName(in, oh->name); + in->dirty = 0; + + /* directory stuff... + * hook up to parent + */ + + parent = + yaffs_FindOrCreateObjectByNumber + (dev, oh->parentObjectId, + YAFFS_OBJECT_TYPE_DIRECTORY); + if (!parent) + alloc_failed = 1; + if (parent && parent->variantType == + YAFFS_OBJECT_TYPE_UNKNOWN) { + /* Set up as a directory */ + parent->variantType = + YAFFS_OBJECT_TYPE_DIRECTORY; + YINIT_LIST_HEAD(&parent->variant. + directoryVariant. + children); + } else if (!parent || parent->variantType != + YAFFS_OBJECT_TYPE_DIRECTORY) { + /* Hoosterman, another problem.... + * We're trying to use a non-directory as a directory + */ + + T(YAFFS_TRACE_ERROR, + (TSTR + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." + TENDSTR))); + parent = dev->lostNFoundDir; + } + + yaffs_AddObjectToDirectory(parent, in); + + if (0 && (parent == dev->deletedDir || + parent == dev->unlinkedDir)) { + in->deleted = 1; /* If it is unlinked at start up then it wants deleting */ + dev->nDeletedFiles++; + } + /* Note re hardlinks. + * 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. + */ + + switch (in->variantType) { + case YAFFS_OBJECT_TYPE_UNKNOWN: + /* Todo got a problem */ + break; + case YAFFS_OBJECT_TYPE_FILE: + if (dev->useHeaderFileSize) + + in->variant.fileVariant. + fileSize = + oh->fileSize; + + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + in->variant.hardLinkVariant. + 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: + in->variant.symLinkVariant.alias = + yaffs_CloneString(oh->alias); + if (!in->variant.symLinkVariant.alias) + alloc_failed = 1; + break; + } + +/* + if (parent == dev->deletedDir) { + yaffs_DestroyObject(in); + bi->hasShrinkHeader = 1; + } +*/ + } + } + } + + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { + /* If we got this far while scanning, then the block is fully allocated.*/ + state = YAFFS_BLOCK_STATE_FULL; + } + + bi->blockState = state; + + /* Now let's see if it was dirty */ + if (bi->pagesInUse == 0 && + !bi->hasShrinkHeader && + bi->blockState == YAFFS_BLOCK_STATE_FULL) { + yaffs_BlockBecameDirty(dev, blk); + } + + } + + + /* 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 + * hardlinks. + */ + + yaffs_HardlinkFixup(dev, hardList); + + /* Fix up any shadowed objects */ + { + 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_DeleteObject(obj); + + obj = yaffs_FindObjectByNumber(dev, fixer->objectId); + + if (obj) + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0); + + YFREE(fixer); + } + } + + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); + + if (alloc_failed) + return YAFFS_FAIL; + + T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR))); + + + return YAFFS_OK; +} + static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) { __u8 *chunkData; @@ -4386,7 +6125,7 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) in->yst_rdev = oh->yst_rdev; #endif - yaffs_SetObjectNameFromOH(in, oh); + yaffs_SetObjectName(in, oh->name); if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { in->variant.symLinkVariant.alias = @@ -4399,8 +6138,749 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) } } +static int yaffs_ScanBackwards(yaffs_Device *dev) +{ + yaffs_ExtendedTags tags; + int blk; + int blockIterator; + int startIterator; + int endIterator; + int nBlocksToScan = 0; + + int chunk; + int result; + int c; + int deleted; + yaffs_BlockState state; + yaffs_Object *hardList = NULL; + yaffs_BlockInfo *bi; + __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; + + if (!dev->isYaffs2) { + T(YAFFS_TRACE_SCAN, + (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR))); + return YAFFS_FAIL; + } + + T(YAFFS_TRACE_SCAN, + (TSTR + ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..." + TENDSTR), dev->internalStartBlock, dev->internalEndBlock)); + + + 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 */ + for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { + bi = yaffs_GetBlockInfo(dev, blk); + yaffs_ClearChunkBits(dev, blk); + bi->pagesInUse = 0; + bi->softDeletions = 0; + + yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); + + bi->blockState = state; + bi->sequenceNumber = sequenceNumber; + + if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) + bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT; + if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK) + bi->blockState = state = YAFFS_BLOCK_STATE_DEAD; + + 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)); + } else if (state == YAFFS_BLOCK_STATE_EMPTY) { + T(YAFFS_TRACE_SCAN_DEBUG, + (TSTR("Block empty " TENDSTR))); + dev->nErasedBlocks++; + dev->nFreeChunks += dev->nChunksPerBlock; + } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { + + /* Determine the highest sequence number */ + if (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 { + /* TODO: Nasty sequence number! */ + T(YAFFS_TRACE_SCAN, + (TSTR + ("Block scanning block %d has bad sequence number %d" + TENDSTR), blk, sequenceNumber)); + + } + } + } + + T(YAFFS_TRACE_SCAN, + (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan)); + + + + YYIELD(); + + /* Sort the blocks */ +#ifndef CONFIG_YAFFS_USE_OWN_SORT + { + /* Use qsort now. */ + yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); + } +#else + { + /* Dungy old bubble sort... */ + + 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; + } + } +#endif + + YYIELD(); + + T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR))); + + /* Now scan the blocks looking at the data. */ + startIterator = 0; + endIterator = nBlocksToScan - 1; + T(YAFFS_TRACE_SCAN_DEBUG, + (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); + + /* For each block.... backwards */ + for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator; + blockIterator--) { + /* Cooperative multitasking! This loop can run for so + long that watchdog timers expire. */ + YYIELD(); + + /* get the block to scan in the correct order */ + 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; + !alloc_failed && c >= 0 && + (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || + state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { + /* Scan backwards... + * Read the tags and decide what to do + */ + + chunk = blk * dev->nChunksPerBlock + c; + + result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, + &tags); + + /* Let's have a good look at this chunk... */ + + if (!tags.chunkUsed) { + /* An unassigned chunk in the block. + * If there are used chunks after this one, then + * 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 + * 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; + dev->nErasedBlocks++; + } else { + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || + 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" + TENDSTR), blk, c)); + + state = YAFFS_BLOCK_STATE_ALLOCATING; + dev->allocationBlock = blk; + dev->allocationPage = c; + 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; ??? TODO */ + bi->gcPrioritise = 1; + + T(YAFFS_TRACE_ALWAYS, + (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)); + + 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; + + + yaffs_SetChunkBit(dev, blk, c); + bi->pagesInUse++; + + in = yaffs_FindOrCreateObjectByNumber(dev, + tags. + objectId, + YAFFS_OBJECT_TYPE_FILE); + if (!in) { + /* Out of memory */ + alloc_failed = 1; + } + + if (in && + in->variantType == YAFFS_OBJECT_TYPE_FILE + && chunkBase < + in->variant.fileVariant.shrinkSize) { + /* This has not been invalidated by a resize */ + if (!yaffs_PutChunkIntoFile(in, tags.chunkId, + chunk, -1)) { + alloc_failed = 1; + } + + /* 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) { + in->variant.fileVariant. + scannedFileSize = endpos; + in->variant.fileVariant. + fileSize = + in->variant.fileVariant. + scannedFileSize; + } + + } else if (in) { + /* This chunk has been invalidated by a resize, so delete */ + yaffs_DeleteChunk(dev, chunk, 1, __LINE__); + + } + } else { + /* chunkId == 0, so it is an ObjectHeader. + * Thus, we read in the object header and make the object + */ + foundChunksInBlock = 1; + + yaffs_SetChunkBit(dev, blk, c); + bi->pagesInUse++; + + oh = NULL; + in = NULL; + + if (tags.extraHeaderInfoAvailable) { + in = yaffs_FindOrCreateObjectByNumber + (dev, tags.objectId, + tags.extraObjectType); + if (!in) + alloc_failed = 1; + } + + if (!in || +#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD + !in->valid || +#endif + tags.extraShadows || + (!in->valid && + (tags.objectId == YAFFS_OBJECTID_ROOT || + tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) { + + /* 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 + * living with invalid data until needed. + */ + + result = yaffs_ReadChunkWithTagsFromNAND(dev, + chunk, + chunkData, + 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); + if (!in) + alloc_failed = 1; + } + + } + + if (!in) { + /* 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" + TENDSTR), tags.objectId, chunk)); + continue; + } + + if (in->valid) { + /* We have already filled this one. + * 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 && + oh->type == YAFFS_OBJECT_TYPE_FILE) || + (tags.extraHeaderInfoAvailable && + tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) { + __u32 thisSize = + (oh) ? oh->fileSize : tags. + extraFileLength; + __u32 parentObjectId = + (oh) ? oh-> + parentObjectId : tags. + extraParentObjectId; + + + isShrink = + (oh) ? oh->isShrink : tags. + extraIsShrinkHeader; + + /* If it is deleted (unlinked at start also means deleted) + * we treat the file size as being zeroed at this point. + */ + if (parentObjectId == + YAFFS_OBJECTID_DELETED + || parentObjectId == + YAFFS_OBJECTID_UNLINKED) { + thisSize = 0; + isShrink = 1; + } + + if (isShrink && + in->variant.fileVariant. + shrinkSize > thisSize) { + in->variant.fileVariant. + shrinkSize = + thisSize; + } + + if (isShrink) + bi->hasShrinkHeader = 1; + + } + /* Use existing - destroy this one. */ + yaffs_DeleteChunk(dev, chunk, 1, __LINE__); + + } + + if (!in->valid && in->variantType != + (oh ? oh->type : tags.extraObjectType)) + T(YAFFS_TRACE_ERROR, ( + TSTR("yaffs tragedy: Bad object type, " + TCONT("%d != %d, for object %d at chunk ") + TCONT("%d during scan") + TENDSTR), oh ? + oh->type : tags.extraObjectType, + in->variantType, tags.objectId, + chunk)); + + if (!in->valid && + (tags.objectId == YAFFS_OBJECTID_ROOT || + tags.objectId == + YAFFS_OBJECTID_LOSTNFOUND)) { + /* We only load some info, don't fiddle with directory structure */ + in->valid = 1; + + if (oh) { + in->variantType = oh->type; + + in->yst_mode = oh->yst_mode; +#ifdef CONFIG_YAFFS_WINCE + in->win_atime[0] = oh->win_atime[0]; + in->win_ctime[0] = oh->win_ctime[0]; + in->win_mtime[0] = oh->win_mtime[0]; + in->win_atime[1] = oh->win_atime[1]; + in->win_ctime[1] = oh->win_ctime[1]; + in->win_mtime[1] = oh->win_mtime[1]; +#else + in->yst_uid = oh->yst_uid; + in->yst_gid = oh->yst_gid; + in->yst_atime = oh->yst_atime; + in->yst_mtime = oh->yst_mtime; + in->yst_ctime = oh->yst_ctime; + in->yst_rdev = oh->yst_rdev; + +#endif + } else { + in->variantType = tags.extraObjectType; + in->lazyLoaded = 1; + } + + in->hdrChunk = chunk; + + } else if (!in->valid) { + /* we need to load this info */ + + in->valid = 1; + in->hdrChunk = chunk; + + if (oh) { + in->variantType = oh->type; + + in->yst_mode = oh->yst_mode; +#ifdef CONFIG_YAFFS_WINCE + in->win_atime[0] = oh->win_atime[0]; + in->win_ctime[0] = oh->win_ctime[0]; + in->win_mtime[0] = oh->win_mtime[0]; + in->win_atime[1] = oh->win_atime[1]; + in->win_ctime[1] = oh->win_ctime[1]; + in->win_mtime[1] = oh->win_mtime[1]; +#else + in->yst_uid = oh->yst_uid; + in->yst_gid = oh->yst_gid; + in->yst_atime = oh->yst_atime; + in->yst_mtime = oh->yst_mtime; + in->yst_ctime = oh->yst_ctime; + in->yst_rdev = oh->yst_rdev; +#endif + + if (oh->shadowsObject > 0) + yaffs_HandleShadowedObject(dev, + oh-> + shadowsObject, + 1); + + + yaffs_SetObjectName(in, oh->name); + parent = + yaffs_FindOrCreateObjectByNumber + (dev, oh->parentObjectId, + YAFFS_OBJECT_TYPE_DIRECTORY); + + fileSize = oh->fileSize; + isShrink = oh->isShrink; + equivalentObjectId = oh->equivalentObjectId; + + } else { + in->variantType = tags.extraObjectType; + parent = + yaffs_FindOrCreateObjectByNumber + (dev, tags.extraParentObjectId, + YAFFS_OBJECT_TYPE_DIRECTORY); + fileSize = tags.extraFileLength; + isShrink = tags.extraIsShrinkHeader; + equivalentObjectId = tags.extraEquivalentObjectId; + in->lazyLoaded = 1; + + } + in->dirty = 0; + + if (!parent) + alloc_failed = 1; + + /* directory stuff... + * hook up to parent + */ + + if (parent && parent->variantType == + YAFFS_OBJECT_TYPE_UNKNOWN) { + /* Set up as a directory */ + parent->variantType = + YAFFS_OBJECT_TYPE_DIRECTORY; + YINIT_LIST_HEAD(&parent->variant. + directoryVariant. + children); + } else if (!parent || parent->variantType != + YAFFS_OBJECT_TYPE_DIRECTORY) { + /* Hoosterman, another problem.... + * We're trying to use a non-directory as a directory + */ + + T(YAFFS_TRACE_ERROR, + (TSTR + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." + TENDSTR))); + parent = dev->lostNFoundDir; + } + + yaffs_AddObjectToDirectory(parent, in); + + itsUnlinked = (parent == dev->deletedDir) || + (parent == dev->unlinkedDir); + + if (isShrink) { + /* Mark the block as having a shrinkHeader */ + bi->hasShrinkHeader = 1; + } + + /* Note re hardlinks. + * 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. + */ + + switch (in->variantType) { + case YAFFS_OBJECT_TYPE_UNKNOWN: + /* Todo got a problem */ + break; + case YAFFS_OBJECT_TYPE_FILE: + + if (in->variant.fileVariant. + 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 + * than its current data extents. + */ + in->variant.fileVariant.fileSize = fileSize; + in->variant.fileVariant.scannedFileSize = + in->variant.fileVariant.fileSize; + } + + if (isShrink && + in->variant.fileVariant.shrinkSize > fileSize) { + in->variant.fileVariant.shrinkSize = fileSize; + } + + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + if (!itsUnlinked) { + in->variant.hardLinkVariant.equivalentObjectId = + 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: + if (oh) { + in->variant.symLinkVariant.alias = + yaffs_CloneString(oh->alias); + if (!in->variant.symLinkVariant.alias) + alloc_failed = 1; + } + break; + } + + } + + } + + } /* End of scanning for each chunk */ + + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { + /* If we got this far while scanning, then the block is fully allocated. */ + state = YAFFS_BLOCK_STATE_FULL; + } + + bi->blockState = state; + + /* Now let's see if it was dirty */ + if (bi->pagesInUse == 0 && + !bi->hasShrinkHeader && + bi->blockState == YAFFS_BLOCK_STATE_FULL) { + yaffs_BlockBecameDirty(dev, blk); + } + + } + + 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 + * hardlinks. + */ + yaffs_HardlinkFixup(dev, hardList); + + + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); + + if (alloc_failed) + return YAFFS_FAIL; + + T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR))); + + return YAFFS_OK; +} + /*------------------------------ Directory Functions ----------------------------- */ +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(); + return; + } + + if (yaffs_SkipVerification(obj->myDev)) + return; + + if (!obj->parent) { + T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR))); + YBUG(); + return; + } + + 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(); + } +} + +static void yaffs_VerifyDirectory(yaffs_Object *directory) +{ + struct ylist_head *lh; + yaffs_Object *listObj; + + if (!directory) { + YBUG(); + return; + } + + 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); + } + } +} + /* *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new * link (ie. name) is created or deleted in the directory. @@ -4409,61 +6889,21 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) * create dir/a : update dir's mtime/ctime * rm dir/a: update dir's mtime/ctime * modify dir/a: don't update dir's mtimme/ctime - * - * This can be handled immediately or defered. Defering helps reduce the number - * of updates when many files in a directory are changed within a brief period. - * - * If the directory updating is defered then yaffs_UpdateDirtyDirecories must be - * called periodically. */ static void yaffs_UpdateParent(yaffs_Object *obj) { - yaffs_Device *dev; if(!obj) return; -#ifndef CONFIG_YAFFS_WINCE - dev = obj->myDev; obj->dirty = 1; obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME; - if(dev->param.deferDirectoryUpdate){ - struct ylist_head *link = &obj->variant.directoryVariant.dirty; - - if(ylist_empty(link)){ - ylist_add(link,&dev->dirtyDirectories); - T(YAFFS_TRACE_BACKGROUND, (TSTR("Added object %d to dirty directories" TENDSTR),obj->objectId)); - } - } else - yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL); +#if 0 + yaffs_UpdateObjectHeader(obj,NULL,0,0,0); #endif } -void yaffs_UpdateDirtyDirectories(yaffs_Device *dev) -{ - struct ylist_head *link; - yaffs_Object *obj; - yaffs_DirectoryStructure *dS; - yaffs_ObjectVariant *oV; - - T(YAFFS_TRACE_BACKGROUND, (TSTR("Update dirty directories" TENDSTR))); - - while(!ylist_empty(&dev->dirtyDirectories)){ - link = dev->dirtyDirectories.next; - ylist_del_init(link); - - dS=ylist_entry(link,yaffs_DirectoryStructure,dirty); - oV = ylist_entry(dS,yaffs_ObjectVariant,directoryVariant); - obj = ylist_entry(oV,yaffs_Object,variant); - - T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->objectId)); - - if(obj->dirty) - yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL); - } -} - static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj) { yaffs_Device *dev = obj->myDev; @@ -4474,8 +6914,8 @@ static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj) yaffs_VerifyDirectory(parent); - if (dev && dev->param.removeObjectCallback) - dev->param.removeObjectCallback(obj); + if (dev && dev->removeObjectCallback) + dev->removeObjectCallback(obj); ylist_del_init(&obj->siblings); @@ -4484,7 +6924,7 @@ static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj) yaffs_VerifyDirectory(parent); } -void yaffs_AddObjectToDirectory(yaffs_Object *directory, +static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj) { if (!directory) { @@ -4638,124 +7078,36 @@ yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj) return obj; } -/* - * A note or two on object names. - * * If the object name is missing, we then make one up in the form objnnn - * - * * ASCII names are stored in the object header's name field from byte zero - * * Unicode names are historically stored starting from byte zero. - * - * Then there are automatic Unicode names... - * The purpose of these is to save names in a way that can be read as - * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII - * system to share files. - * - * These automatic unicode are stored slightly differently... - * - If the name can fit in the ASCII character space then they are saved as - * ascii names as per above. - * - If the name needs Unicode then the name is saved in Unicode - * starting at oh->name[1]. - - */ -static void yaffs_FixNullName(yaffs_Object * obj,YCHAR * name, int buffSize) +int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize) { - /* Create an object name if we could not find one. */ - if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){ + 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->hdrChunk <= 0) { YCHAR locName[20]; YCHAR numString[20]; YCHAR *x = &numString[19]; unsigned v = obj->objectId; numString[19] = 0; - while(v>0){ + while (v > 0) { x--; *x = '0' + (v % 10); v /= 10; } /* make up a name */ yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX); - yaffs_strcat(locName,x); + yaffs_strcat(locName, x); yaffs_strncpy(name, locName, buffSize - 1); + } -} - -static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize) -{ -#ifdef CONFIG_YAFFS_AUTO_UNICODE - if(dev->param.autoUnicode){ - if(*ohName){ - /* It is an ASCII name, so do an ASCII to unicode conversion */ - const char *asciiOhName = (const char *)ohName; - int n = bufferSize - 1; - while(n > 0 && *asciiOhName){ - *name = *asciiOhName; - name++; - asciiOhName++; - n--; - } - } else - yaffs_strncpy(name,ohName+1, bufferSize -1); - } else -#endif - yaffs_strncpy(name, ohName, bufferSize - 1); -} - - -static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev, YCHAR *ohName, const YCHAR *name) -{ -#ifdef CONFIG_YAFFS_AUTO_UNICODE - - int isAscii; - YCHAR *w; - - if(dev->param.autoUnicode){ - - isAscii = 1; - w = name; - - /* Figure out if the name will fit in ascii character set */ - while(isAscii && *w){ - if((*w) & 0xff00) - isAscii = 0; - w++; - } - - if(isAscii){ - /* It is an ASCII name, so do a unicode to ascii conversion */ - char *asciiOhName = (char *)ohName; - int n = YAFFS_MAX_NAME_LENGTH - 1; - while(n > 0 && *name){ - *asciiOhName= *name; - name++; - asciiOhName++; - n--; - } - } else{ - /* It is a unicode name, so save starting at the second YCHAR */ - *ohName = 0; - yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2); - } - } - else -#endif - yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1); - -} - -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); - } #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM - else if (obj->shortName[0]) { + else if (obj->shortName[0]) yaffs_strcpy(name, obj->shortName); - } #endif - else if(obj->hdrChunk > 0) { + else { int result; __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__); @@ -4768,17 +7120,14 @@ int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize) obj->hdrChunk, buffer, NULL); } - yaffs_LoadNameFromObjectHeader(obj->myDev,name,oh->name,buffSize); + yaffs_strncpy(name, oh->name, buffSize - 1); yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__); } - yaffs_FixNullName(obj,name,buffSize); - - return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH); + return yaffs_strlen(name); } - int yaffs_GetObjectFileLength(yaffs_Object *obj) { /* Dereference any hard linking */ @@ -4786,11 +7135,9 @@ int yaffs_GetObjectFileLength(yaffs_Object *obj) if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) return obj->variant.fileVariant.fileSize; - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK){ - if(!obj->variant.symLinkVariant.alias) - return 0; - return yaffs_strnlen(obj->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH); - } else { + if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) + return yaffs_strlen(obj->variant.symLinkVariant.alias); + else { /* Only a directory should drop through to here */ return obj->myDev->nDataBytesPerChunk; } @@ -4881,7 +7228,7 @@ int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr) if (valid & ATTR_SIZE) yaffs_ResizeFile(obj, attr->ia_size); - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL); + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0); return YAFFS_OK; @@ -4914,123 +7261,6 @@ int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr) #endif - -static int yaffs_DoXMod(yaffs_Object *obj, int set, const YCHAR *name, const void *value, int size, int flags) -{ - yaffs_XAttrMod xmod; - - int result; - - xmod.set = set; - xmod.name = name; - xmod.data = value; - xmod.size = size; - xmod.flags = flags; - xmod.result = -ENOSPC; - - result = yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, &xmod); - - if(result > 0) - return xmod.result; - else - return -ENOSPC; -} - -static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod) -{ - int retval = 0; - int x_offs = sizeof(yaffs_ObjectHeader); - yaffs_Device *dev = obj->myDev; - int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader); - - char * x_buffer = buffer + x_offs; - - if(xmod->set) - retval = nval_set(x_buffer, x_size, xmod->name, xmod->data, xmod->size, xmod->flags); - else - retval = nval_del(x_buffer, x_size, xmod->name); - - obj->hasXattr = nval_hasvalues(x_buffer, x_size); - obj->xattrKnown = 1; - - xmod->result = retval; - - return retval; -} - -static int yaffs_DoXFetch(yaffs_Object *obj, const YCHAR *name, void *value, int size) -{ - char *buffer = NULL; - int result; - yaffs_ExtendedTags tags; - yaffs_Device *dev = obj->myDev; - int x_offs = sizeof(yaffs_ObjectHeader); - int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader); - - char * x_buffer; - - int retval = 0; - - if(obj->hdrChunk < 1) - return -ENODATA; - - /* If we know that the object has no xattribs then don't do all the - * reading and parsing. - */ - if(obj->xattrKnown && !obj->hasXattr){ - if(name) - return -ENODATA; - else - return 0; - } - - buffer = (char *) yaffs_GetTempBuffer(dev, __LINE__); - if(!buffer) - return -ENOMEM; - - result = yaffs_ReadChunkWithTagsFromNAND(dev,obj->hdrChunk, (__u8 *)buffer, &tags); - - if(result != YAFFS_OK) - retval = -ENOENT; - else{ - x_buffer = buffer + x_offs; - - if (!obj->xattrKnown){ - obj->hasXattr = nval_hasvalues(x_buffer, x_size); - obj->xattrKnown = 1; - } - - if(name) - retval = nval_get(x_buffer, x_size, name, value, size); - else - retval = nval_list(x_buffer, x_size, value,size); - } - yaffs_ReleaseTempBuffer(dev,(__u8 *)buffer,__LINE__); - return retval; -} - -int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags) -{ - return yaffs_DoXMod(obj, 1, name, value, size, flags); -} - -int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name) -{ - return yaffs_DoXMod(obj, 0, name, NULL, 0, 0); -} - -int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size) -{ - return yaffs_DoXFetch(obj, name, value, size); -} - -int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size) -{ - return yaffs_DoXFetch(obj, NULL, buffer,size); -} - - - #if 0 int yaffs_DumpObject(yaffs_Object *obj) { @@ -5056,32 +7286,30 @@ static int yaffs_CheckDevFunctions(const yaffs_Device *dev) { /* Common functions, gotta have */ - if (!dev->param.eraseBlockInNAND || !dev->param.initialiseNAND) + if (!dev->eraseBlockInNAND || !dev->initialiseNAND) return 0; #ifdef CONFIG_YAFFS_YAFFS2 /* Can use the "with tags" style interface for yaffs1 or yaffs2 */ - if (dev->param.writeChunkWithTagsToNAND && - dev->param.readChunkWithTagsFromNAND && - !dev->param.writeChunkToNAND && - !dev->param.readChunkFromNAND && - dev->param.markNANDBlockBad && - dev->param.queryNANDBlock) + if (dev->writeChunkWithTagsToNAND && + dev->readChunkWithTagsFromNAND && + !dev->writeChunkToNAND && + !dev->readChunkFromNAND && + dev->markNANDBlockBad && dev->queryNANDBlock) return 1; #endif /* Can use the "spare" style interface for yaffs1 */ - if (!dev->param.isYaffs2 && - !dev->param.writeChunkWithTagsToNAND && - !dev->param.readChunkWithTagsFromNAND && - dev->param.writeChunkToNAND && - dev->param.readChunkFromNAND && - !dev->param.markNANDBlockBad && - !dev->param.queryNANDBlock) + if (!dev->isYaffs2 && + !dev->writeChunkWithTagsToNAND && + !dev->readChunkWithTagsFromNAND && + dev->writeChunkToNAND && + dev->readChunkFromNAND && + !dev->markNANDBlockBad && !dev->queryNANDBlock) return 1; - return 0; /* bad */ + return 0; /* bad */ } @@ -5128,35 +7356,35 @@ int yaffs_GutsInitialise(yaffs_Device *dev) return YAFFS_FAIL; } - dev->internalStartBlock = dev->param.startBlock; - dev->internalEndBlock = dev->param.endBlock; + dev->internalStartBlock = dev->startBlock; + dev->internalEndBlock = dev->endBlock; dev->blockOffset = 0; dev->chunkOffset = 0; dev->nFreeChunks = 0; - dev->gcBlock = 0; + dev->gcBlock = -1; - if (dev->param.startBlock == 0) { - dev->internalStartBlock = dev->param.startBlock + 1; - dev->internalEndBlock = dev->param.endBlock + 1; + if (dev->startBlock == 0) { + dev->internalStartBlock = dev->startBlock + 1; + dev->internalEndBlock = dev->endBlock + 1; dev->blockOffset = 1; - dev->chunkOffset = dev->param.nChunksPerBlock; + dev->chunkOffset = dev->nChunksPerBlock; } /* Check geometry parameters. */ - if ((!dev->param.inbandTags && dev->param.isYaffs2 && dev->param.totalBytesPerChunk < 1024) || - (!dev->param.isYaffs2 && dev->param.totalBytesPerChunk < 512) || - (dev->param.inbandTags && !dev->param.isYaffs2) || - dev->param.nChunksPerBlock < 2 || - dev->param.nReservedBlocks < 2 || + 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->param.nReservedBlocks + 2)) { /* otherwise it is too small */ + 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, inbandTags %d " - TENDSTR), dev->param.totalBytesPerChunk, dev->param.isYaffs2 ? "2" : "", dev->param.inbandTags)); + TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags)); return YAFFS_FAIL; } @@ -5167,10 +7395,10 @@ int yaffs_GutsInitialise(yaffs_Device *dev) } /* Sort out space for inband tags, if required */ - if (dev->param.inbandTags) - dev->nDataBytesPerChunk = dev->param.totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart); + if (dev->inbandTags) + dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart); else - dev->nDataBytesPerChunk = dev->param.totalBytesPerChunk; + dev->nDataBytesPerChunk = dev->totalBytesPerChunk; /* Got the right mix of functions? */ if (!yaffs_CheckDevFunctions(dev)) { @@ -5217,12 +7445,12 @@ int yaffs_GutsInitialise(yaffs_Device *dev) * We need to find the next power of 2 > than internalEndBlock */ - x = dev->param.nChunksPerBlock * (dev->internalEndBlock + 1); + x = dev->nChunksPerBlock * (dev->internalEndBlock + 1); bits = ShiftsGE(x); /* Set up tnode width if wide tnodes are enabled. */ - if (!dev->param.wideTnodesDisabled) { + if (!dev->wideTnodesDisabled) { /* bits must be even so that we end up with 32-bit words */ if (bits & 1) bits++; @@ -5246,13 +7474,10 @@ int yaffs_GutsInitialise(yaffs_Device *dev) else dev->chunkGroupBits = bits - dev->tnodeWidth; - dev->tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; - if(dev->tnodeSize < sizeof(yaffs_Tnode)) - dev->tnodeSize = sizeof(yaffs_Tnode); dev->chunkGroupSize = 1 << dev->chunkGroupBits; - if (dev->param.nChunksPerBlock < dev->chunkGroupSize) { + if (dev->nChunksPerBlock < dev->chunkGroupSize) { /* We have a problem because the soft delete won't work if * the chunk group size > chunks per block. * This can be remedied by using larger "virtual blocks". @@ -5266,11 +7491,9 @@ int yaffs_GutsInitialise(yaffs_Device *dev) /* OK, we've finished verifying the device, lets continue with initialisation */ /* More device initialisation */ - dev->allGCs = 0; - dev->passiveGCs = 0; - dev->oldestDirtyGCs = 0; - dev->backgroundGCs = 0; - dev->gcBlockFinder = 0; + dev->garbageCollections = 0; + dev->passiveGarbageCollections = 0; + dev->currentDirtyChecker = 0; dev->bufferedBlock = -1; dev->doingBufferedBlockRewrite = 0; dev->nDeletedFiles = 0; @@ -5282,11 +7505,9 @@ int yaffs_GutsInitialise(yaffs_Device *dev) dev->tagsEccUnfixed = 0; dev->nErasureFailures = 0; dev->nErasedBlocks = 0; - dev->gcDisable= 0; + dev->isDoingGC = 0; dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */ - YINIT_LIST_HEAD(&dev->dirtyDirectories); dev->oldestDirtySequence = 0; - dev->oldestDirtyBlock = 0; /* Initialise temporary buffers and caches. */ if (!yaffs_InitialiseTempBuffers(dev)) @@ -5297,13 +7518,13 @@ int yaffs_GutsInitialise(yaffs_Device *dev) if (!init_failed && - dev->param.nShortOpCaches > 0) { + dev->nShortOpCaches > 0) { int i; void *buf; - int srCacheBytes = dev->param.nShortOpCaches * sizeof(yaffs_ChunkCache); + int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache); - if (dev->param.nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) - dev->param.nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; + if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) + dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; dev->srCache = YMALLOC(srCacheBytes); @@ -5312,11 +7533,11 @@ int yaffs_GutsInitialise(yaffs_Device *dev) if (dev->srCache) memset(dev->srCache, 0, srCacheBytes); - for (i = 0; i < dev->param.nShortOpCaches && buf; i++) { + 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->param.totalBytesPerChunk); + dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk); } if (!buf) init_failed = 1; @@ -5327,18 +7548,19 @@ int yaffs_GutsInitialise(yaffs_Device *dev) dev->cacheHits = 0; if (!init_failed) { - dev->gcCleanupList = YMALLOC(dev->param.nChunksPerBlock * sizeof(__u32)); + dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); if (!dev->gcCleanupList) init_failed = 1; } - if (dev->param.isYaffs2) - dev->param.useHeaderFileSize = 1; + if (dev->isYaffs2) + dev->useHeaderFileSize = 1; if (!init_failed && !yaffs_InitialiseBlocks(dev)) init_failed = 1; - yaffs_InitialiseTnodesAndObjects(dev); + yaffs_InitialiseTnodes(dev); + yaffs_InitialiseObjects(dev); if (!init_failed && !yaffs_CreateInitialDirectories(dev)) init_failed = 1; @@ -5346,8 +7568,8 @@ int yaffs_GutsInitialise(yaffs_Device *dev) if (!init_failed) { /* Now scan the flash. */ - if (dev->param.isYaffs2) { - if (yaffs2_CheckpointRestore(dev)) { + if (dev->isYaffs2) { + if (yaffs_CheckpointRestore(dev)) { yaffs_CheckObjectDetailsLoaded(dev->rootDir); T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: restored from checkpoint" TENDSTR))); @@ -5357,8 +7579,9 @@ int yaffs_GutsInitialise(yaffs_Device *dev) * and scan backwards. */ yaffs_DeinitialiseBlocks(dev); + yaffs_DeinitialiseTnodes(dev); + yaffs_DeinitialiseObjects(dev); - yaffs_DeinitialiseTnodesAndObjects(dev); dev->nErasedBlocks = 0; dev->nFreeChunks = 0; @@ -5371,20 +7594,21 @@ int yaffs_GutsInitialise(yaffs_Device *dev) if (!init_failed && !yaffs_InitialiseBlocks(dev)) init_failed = 1; - yaffs_InitialiseTnodesAndObjects(dev); + yaffs_InitialiseTnodes(dev); + yaffs_InitialiseObjects(dev); if (!init_failed && !yaffs_CreateInitialDirectories(dev)) init_failed = 1; - if (!init_failed && !yaffs2_ScanBackwards(dev)) + if (!init_failed && !yaffs_ScanBackwards(dev)) init_failed = 1; } - } else if (!yaffs1_Scan(dev)) + } else if (!yaffs_Scan(dev)) init_failed = 1; yaffs_StripDeletedObjects(dev); yaffs_FixHangingObjects(dev); - if(dev->param.emptyLostAndFound) + if(dev->emptyLostAndFound) yaffs_EmptyLostAndFound(dev); } @@ -5410,8 +7634,8 @@ int yaffs_GutsInitialise(yaffs_Device *dev) yaffs_VerifyBlocks(dev); /* Clean up any aborted checkpoint data */ - if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0) - yaffs2_InvalidateCheckpoint(dev); + if (!dev->isCheckpointed && dev->blocksInCheckpoint > 0) + yaffs_InvalidateCheckpoint(dev); T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); @@ -5425,11 +7649,12 @@ void yaffs_Deinitialise(yaffs_Device *dev) int i; yaffs_DeinitialiseBlocks(dev); - yaffs_DeinitialiseTnodesAndObjects(dev); - if (dev->param.nShortOpCaches > 0 && + yaffs_DeinitialiseTnodes(dev); + yaffs_DeinitialiseObjects(dev); + if (dev->nShortOpCaches > 0 && dev->srCache) { - for (i = 0; i < dev->param.nShortOpCaches; i++) { + for (i = 0; i < dev->nShortOpCaches; i++) { if (dev->srCache[i].data) YFREE(dev->srCache[i].data); dev->srCache[i].data = NULL; @@ -5446,33 +7671,34 @@ void yaffs_Deinitialise(yaffs_Device *dev) dev->isMounted = 0; - if (dev->param.deinitialiseNAND) - dev->param.deinitialiseNAND(dev); + if (dev->deinitialiseNAND) + dev->deinitialiseNAND(dev); } } -int yaffs_CountFreeChunks(yaffs_Device *dev) +static int yaffs_CountFreeChunks(yaffs_Device *dev) { - int nFree=0; + int nFree; int b; yaffs_BlockInfo *blk; - blk = dev->blockInfo; - for (b = dev->internalStartBlock; b <= dev->internalEndBlock; b++) { + for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; + b++) { + blk = yaffs_GetBlockInfo(dev, b); + switch (blk->blockState) { case YAFFS_BLOCK_STATE_EMPTY: case YAFFS_BLOCK_STATE_ALLOCATING: case YAFFS_BLOCK_STATE_COLLECTING: case YAFFS_BLOCK_STATE_FULL: nFree += - (dev->param.nChunksPerBlock - blk->pagesInUse + + (dev->nChunksPerBlock - blk->pagesInUse + blk->softDeletions); break; default: break; } - blk++; } return nFree; @@ -5497,19 +7723,21 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) /* Now count the number of dirty chunks in the cache and subtract those */ - for (nDirtyCacheChunks = 0, i = 0; i < dev->param.nShortOpCaches; i++) { + for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) { if (dev->srCache[i].dirty) nDirtyCacheChunks++; } nFree -= nDirtyCacheChunks; - nFree -= ((dev->param.nReservedBlocks + 1) * dev->param.nChunksPerBlock); + nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); /* Now we figure out how much to reserve for the checkpoint and report that... */ - blocksForCheckpoint = yaffs2_CalcCheckpointBlocksRequired(dev); + blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; + if (blocksForCheckpoint < 0) + blocksForCheckpoint = 0; - nFree -= (blocksForCheckpoint * dev->param.nChunksPerBlock); + nFree -= (blocksForCheckpoint * dev->nChunksPerBlock); if (nFree < 0) nFree = 0; @@ -5518,6 +7746,27 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) } +static int yaffs_freeVerificationFailures; + +static void yaffs_VerifyFreeChunks(yaffs_Device *dev) +{ + int counted; + int difference; + + if (yaffs_SkipVerification(dev)) + return; + + counted = yaffs_CountFreeChunks(dev); + + difference = dev->nFreeChunks - counted; + + if (difference) { + T(YAFFS_TRACE_ALWAYS, + (TSTR("Freechunks verification failure %d %d %d" TENDSTR), + dev->nFreeChunks, counted, difference)); + yaffs_freeVerificationFailures++; + } +} /*---------------------------------------- YAFFS test code ----------------------*/ @@ -5525,7 +7774,7 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) do { \ if (sizeof(structure) != syze) { \ T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\ - name, syze, (int) sizeof(structure))); \ + name, syze, sizeof(structure))); \ return YAFFS_FAIL; \ } \ } while (0) @@ -5535,8 +7784,9 @@ 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_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); */ - +#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG + yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); +#endif #ifndef CONFIG_YAFFS_WINCE yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader"); #endif diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h index 4dc70a2a..1305909e 100644 --- a/fs/yaffs2/yaffs_guts.h +++ b/fs/yaffs2/yaffs_guts.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -16,9 +16,8 @@ #ifndef __YAFFS_GUTS_H__ #define __YAFFS_GUTS_H__ -#include "yportenv.h" #include "devextras.h" -#include "yaffs_list.h" +#include "yportenv.h" #define YAFFS_OK 1 #define YAFFS_FAIL 0 @@ -53,6 +52,7 @@ #define YAFFS_MAX_CHUNK_ID 0x000FFFFF +#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF #define YAFFS_ALLOCATION_NOBJECTS 100 #define YAFFS_ALLOCATION_NTNODES 100 @@ -62,9 +62,8 @@ #define YAFFS_OBJECT_SPACE 0x40000 -#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1) -#define YAFFS_CHECKPOINT_VERSION 4 +#define YAFFS_CHECKPOINT_VERSION 3 #ifdef CONFIG_YAFFS_UNICODE #define YAFFS_MAX_NAME_LENGTH 127 @@ -82,11 +81,12 @@ #define YAFFS_OBJECTID_UNLINKED 3 #define YAFFS_OBJECTID_DELETED 4 -/* Pseudo object ids for checkpointing */ +/* Sseudo object ids for checkpointing */ #define YAFFS_OBJECTID_SB_HEADER 0x10 #define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 #define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 +/* */ #define YAFFS_MAX_SHORT_OP_CACHES 20 @@ -119,7 +119,11 @@ typedef struct { int dirty; int nBytes; /* Only valid if the cache is dirty */ int locked; /* Can't push out or flush while locked. */ +#ifdef CONFIG_YAFFS_YAFFS2 __u8 *data; +#else + __u8 data[YAFFS_BYTES_PER_CHUNK]; +#endif } yaffs_ChunkCache; @@ -230,8 +234,6 @@ typedef enum { YAFFS_BLOCK_STATE_UNKNOWN = 0, YAFFS_BLOCK_STATE_SCANNING, - /* Being scanned */ - YAFFS_BLOCK_STATE_NEEDS_SCANNING, /* The block might have something on it (ie it is allocating or full, perhaps empty) * but it needs to be scanned to determine its true state. @@ -247,23 +249,21 @@ typedef enum { /* 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. - * If a block is only partially allocated at mount it is treated as full. + * allocation. Should never be more than one of these */ YAFFS_BLOCK_STATE_FULL, /* All the pages in this block have been allocated. - * If a block was only partially allocated when mounted we treat - * it as fully allocated. */ YAFFS_BLOCK_STATE_DIRTY, - /* The block was full and now all chunks have been deleted. + /* All pages have been allocated and deleted. * Erase me, reuse me. */ YAFFS_BLOCK_STATE_CHECKPOINT, - /* This block is assigned to holding checkpoint data. */ + /* This block is assigned to holding checkpoint data. + */ YAFFS_BLOCK_STATE_COLLECTING, /* This block is being garbage collected */ @@ -351,12 +351,23 @@ typedef struct { /*--------------------------- Tnode -------------------------- */ union yaffs_Tnode_union { +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG + union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1]; +#else union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL]; +#endif +/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */ }; typedef union yaffs_Tnode_union yaffs_Tnode; +struct yaffs_TnodeList_struct { + struct yaffs_TnodeList_struct *next; + yaffs_Tnode *tnodes; +}; + +typedef struct yaffs_TnodeList_struct yaffs_TnodeList; /*------------------------ Object -----------------------------*/ /* An object can be one of: @@ -376,7 +387,6 @@ typedef struct { typedef struct { struct ylist_head children; /* list of child links */ - struct ylist_head dirty; /* Entry for list of dirty directories */ } yaffs_DirectoryStructure; typedef struct { @@ -395,8 +405,6 @@ typedef union { yaffs_HardLinkStructure hardLinkVariant; } yaffs_ObjectVariant; - - struct yaffs_ObjectStruct { __u8 deleted:1; /* This should only apply to unlinked files. */ __u8 softDeleted:1; /* it has also been soft deleted */ @@ -416,10 +424,7 @@ struct yaffs_ObjectStruct { * until the inode is released. */ __u8 beingCreated:1; /* This object is still being created so skip some checks. */ - __u8 isShadowed:1; /* This object is shadowed on the way to being renamed. */ - - __u8 xattrKnown:1; /* We know if this has object has xattribs or not. */ - __u8 hasXattr:1; /* This object has xattribs. Valid if xattrKnown. */ + __u8 isShadowed:1; /* This object is shadowed on the way to being renamed. */ __u8 serial; /* serial number of chunk in NAND. Cached here */ __u16 sum; /* sum of the name to speed searching */ @@ -448,6 +453,10 @@ struct yaffs_ObjectStruct { YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1]; #endif +#ifndef __KERNEL__ + __u32 inUse; +#endif + #ifdef CONFIG_YAFFS_WINCE __u32 win_ctime[2]; __u32 win_mtime[2]; @@ -462,7 +471,10 @@ struct yaffs_ObjectStruct { __u32 yst_rdev; - void *myInode; +#ifdef __KERNEL__ + struct inode *myInode; + +#endif yaffs_ObjectType variantType; @@ -472,6 +484,13 @@ struct yaffs_ObjectStruct { typedef struct yaffs_ObjectStruct yaffs_Object; +struct yaffs_ObjectList_struct { + yaffs_Object *objects; + struct yaffs_ObjectList_struct *next; +}; + +typedef struct yaffs_ObjectList_struct yaffs_ObjectList; + typedef struct { struct ylist_head list; int count; @@ -513,18 +532,12 @@ typedef struct { /*----------------- Device ---------------------------------*/ +struct yaffs_DeviceStruct { + struct ylist_head devList; + const char *name; -struct yaffs_DeviceParamStruct { - const YCHAR *name; - - /* - * Entry parameters set up way early. Yaffs sets up the rest. - * The structure should be zeroed out before use so that unused - * and defualt values are zero. - */ - - int inbandTags; /* Use unband tags */ - __u32 totalBytesPerChunk; /* Should be >= 512, does not need to be a power of 2 */ + /* 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 */ @@ -533,24 +546,26 @@ struct yaffs_DeviceParamStruct { /* 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 nShortOpCaches; /* If <= 0, then short op caching is disabled, else - * the number of short op caches (don't use too many). - * 10 to 20 is a good bet. + * the number of short op caches (don't use too many) */ - int useNANDECC; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */ - int noTagsECC; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */ - int isYaffs2; /* Use yaffs2 mode on this device */ + int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */ - int emptyLostAndFound; /* Auto-empty lost+found directory on mount */ + int emptyLostAndFound; /* Flasg to determine if lst+found should be emptied on init */ - int refreshPeriod; /* How often we should check to do a block refresh */ + int useNANDECC; /* Flag to decide whether or not to use NANDECC */ - /* Checkpoint control. Can be set before or after initialisation */ - __u8 skipCheckpointRead; - __u8 skipCheckpointWrite; - - int enableXattr; /* Enable xattribs */ + void *genericDevice; /* Pointer to device context + * On an mtd this holds the mtd pointer. + */ + void *superBlock; /* NAND access functions (Must be set before calling YAFFS)*/ @@ -577,6 +592,8 @@ struct yaffs_DeviceParamStruct { yaffs_BlockState *state, __u32 *sequenceNumber); #endif + int isYaffs2; + /* The removeObjectCallback function must be supplied by OS flavours that * need it. * yaffs direct uses it to implement the faster readdir. @@ -584,61 +601,54 @@ struct yaffs_DeviceParamStruct { */ void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj); - /* Callback to mark the superblock dirty */ - void (*markSuperBlockDirty)(struct yaffs_DeviceStruct *dev); - - /* Callback to control garbage collection. */ - unsigned (*gcControl)(struct yaffs_DeviceStruct *dev); + /* Callback to mark the superblock dirsty */ + void (*markSuperBlockDirty)(void *superblock); - /* Debug control flags. Don't use unless you know what you're doing */ - int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */ - int disableLazyLoad; /* Disable lazy loading on this device */ int wideTnodesDisabled; /* Set to disable wide tnodes */ - int disableSoftDelete; /* yaffs 1 only: Set to disable the use of softdeletion. */ - - int deferDirectoryUpdate; /* Set to defer directory updates */ -#ifdef CONFIG_YAFFS_AUTO_UNICODE - int autoUnicode; -#endif - int alwaysCheckErased; /* Force chunk erased check always on */ -}; + YCHAR *pathDividers; /* String of legal path dividers */ -typedef struct yaffs_DeviceParamStruct yaffs_DeviceParam; -struct yaffs_DeviceStruct { - struct yaffs_DeviceParamStruct param; + /* End of stuff that must be set before initialisation. */ - /* Context storage. Holds extra OS specific data for this device */ - - void *osContext; - void *driverContext; - - struct ylist_head devList; + /* Checkpoint control. Can be set before or after initialisation */ + __u8 skipCheckpointRead; + __u8 skipCheckpointWrite; /* Runtime parameters. Set up by YAFFS. */ - int nDataBytesPerChunk; - /* Non-wide tnode stuff */ - __u16 chunkGroupBits; /* Number of bits that need to be resolved if - * the tnodes are not wide enough. - */ + __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */ __u16 chunkGroupSize; /* == 2^^chunkGroupBits */ /* Stuff to support wide tnodes */ __u32 tnodeWidth; __u32 tnodeMask; - __u32 tnodeSize; /* 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 */ + struct rw_semaphore dirLock; /* Lock the directory structure */ + __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); + struct ylist_head searchContexts; + +#endif int isMounted; - int readOnly; + int isCheckpointed; @@ -680,31 +690,51 @@ struct yaffs_DeviceStruct { __u32 allocationPage; int allocationBlockFinder; /* Used to search for next allocation block */ - /* Object and Tnode memory management */ - void *allocator; - int nObjects; - int nTnodes; + /* Runtime state */ + int nTnodesCreated; + yaffs_Tnode *freeTnodes; + int nFreeTnodes; + yaffs_TnodeList *allocatedTnodeList; + + int isDoingGC; + int gcBlock; + int gcChunk; + + int nObjectsCreated; + yaffs_Object *freeObjects; + int nFreeObjects; int nHardLinks; + yaffs_ObjectList *allocatedObjectList; + yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS]; - __u32 bucketFinder; int nFreeChunks; - /* Garbage collection control */ - __u32 *gcCleanupList; /* objects to delete at the end of a GC. */ - __u32 nCleanups; + int currentDirtyChecker; /* Used to find current dirtiest block */ - unsigned hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ - unsigned gcDisable; - unsigned gcBlockFinder; - unsigned gcDirtiest; - unsigned gcPagesInUse; - unsigned gcNotDone; - unsigned gcBlock; - unsigned gcChunk; - unsigned gcSkip; + __u32 *gcCleanupList; /* objects to delete at the end of a GC. */ + int nonAggressiveSkip; /* GC state/mode */ + + /* Statistcs */ + int nPageWrites; + int nPageReads; + int nBlockErasures; + int nErasureFailures; + int nGCCopies; + int garbageCollections; + int passiveGarbageCollections; + int nRetriedWrites; + int nRetiredBlocks; + int eccFixed; + int eccUnfixed; + int tagsEccFixed; + int tagsEccUnfixed; + int nDeletions; + int nUnmarkedDeletions; + + int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ /* Special directories */ yaffs_Object *rootDir; @@ -721,6 +751,8 @@ struct yaffs_DeviceStruct { yaffs_ChunkCache *srCache; int srLastUse; + int cacheHits; + /* Stuff for background deletion and unlinked files.*/ yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */ yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */ @@ -729,6 +761,7 @@ 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; @@ -739,36 +772,6 @@ struct yaffs_DeviceStruct { /* yaffs2 runtime stuff */ unsigned sequenceNumber; /* Sequence number of currently allocating block */ unsigned oldestDirtySequence; - unsigned oldestDirtyBlock; - - /* Block refreshing */ - int refreshSkip; /* A skip down counter. Refresh happens when this gets to zero. */ - - /* Dirty directory handling */ - struct ylist_head dirtyDirectories; /* List of dirty directories */ - - - /* Statistcs */ - __u32 nPageWrites; - __u32 nPageReads; - __u32 nBlockErasures; - __u32 nErasureFailures; - __u32 nGCCopies; - __u32 allGCs; - __u32 passiveGCs; - __u32 oldestDirtyGCs; - __u32 nGCBlocks; - __u32 backgroundGCs; - __u32 nRetriedWrites; - __u32 nRetiredBlocks; - __u32 eccFixed; - __u32 eccUnfixed; - __u32 tagsEccFixed; - __u32 tagsEccUnfixed; - __u32 nDeletions; - __u32 nUnmarkedDeletions; - __u32 refreshCount; - __u32 cacheHits; }; @@ -801,6 +804,7 @@ typedef struct { /* yaffs2 runtime stuff */ unsigned sequenceNumber; /* Sequence number of currently allocating block */ + unsigned oldestDirtySequence; } yaffs_CheckpointDevice; @@ -813,23 +817,6 @@ typedef struct { } yaffs_CheckpointValidity; -struct yaffs_ShadowFixerStruct { - int objectId; - int shadowedId; - struct yaffs_ShadowFixerStruct *next; -}; - -/* Structure for doing xattr modifications */ -typedef struct { - int set; /* If 0 then this is a deletion */ - const YCHAR *name; - const void *data; - int size; - int flags; - int result; -}yaffs_XAttrMod; - - /*----------------------- YAFFS Functions -----------------------*/ int yaffs_GutsInitialise(yaffs_Device *dev); @@ -861,8 +848,7 @@ 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); - -int yaffs_FlushFile(yaffs_Object *obj, int updateTime, int dataSync); +int yaffs_FlushFile(yaffs_Object *obj, int updateTime); /* Flushing and checkpointing */ void yaffs_FlushEntireDeviceCache(yaffs_Device *dev); @@ -895,12 +881,6 @@ YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj); yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name, __u32 mode, __u32 uid, __u32 gid, __u32 rdev); - -int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags); -int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size); -int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size); -int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name); - /* Special directories */ yaffs_Object *yaffs_Root(yaffs_Device *dev); yaffs_Object *yaffs_LostNFound(yaffs_Device *dev); @@ -910,18 +890,18 @@ yaffs_Object *yaffs_LostNFound(yaffs_Device *dev); void yfsd_WinFileTimeNow(__u32 target[2]); #endif +#ifdef __KERNEL__ + void yaffs_HandleDeferedFree(yaffs_Object *obj); - -void yaffs_UpdateDirtyDirectories(yaffs_Device *dev); - -int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency); +#endif /* Debug dump */ int yaffs_DumpObject(yaffs_Object *obj); void yaffs_GutsTest(yaffs_Device *dev); -/* A few useful functions to be used within the core files*/ +/* A few useful functions */ +void yaffs_InitialiseTags(yaffs_ExtendedTags *tags); void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn); int yaffs_CheckFF(__u8 *buffer, int nBytes); void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi); @@ -929,41 +909,4 @@ 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); -yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, - int number, - yaffs_ObjectType type); -int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, - int chunkInNAND, int inScan); -void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name); -void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh); -void yaffs_AddObjectToDirectory(yaffs_Object *directory, - yaffs_Object *obj); -YCHAR *yaffs_CloneString(const YCHAR *str); -void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList); -void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo); -int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, - int force, int isShrink, int shadows, - yaffs_XAttrMod *xop); -void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, - int backwardScanning); -int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks); -yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev); -yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, - yaffs_FileStructure *fStruct, - __u32 chunkId, - yaffs_Tnode *passedTn); - -int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, - int nBytes, int writeThrough); -void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize); -void yaffs_SkipRestOfBlock(yaffs_Device *dev); - -int yaffs_CountFreeChunks(yaffs_Device *dev); - -yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, - yaffs_FileStructure *fStruct, - __u32 chunkId); - -__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos); - #endif diff --git a/fs/yaffs2/yaffs_linux.h b/fs/yaffs2/yaffs_linux.h deleted file mode 100644 index ce059fd2..00000000 --- a/fs/yaffs2/yaffs_linux.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * 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_LINUX_H__ -#define __YAFFS_LINUX_H__ - -#include "devextras.h" -#include "yportenv.h" - -struct yaffs_LinuxContext { - struct ylist_head contextList; /* List of these we have mounted */ - struct yaffs_DeviceStruct *dev; - struct super_block * superBlock; - struct task_struct *bgThread; /* Background thread for this device */ - int bgRunning; - struct semaphore grossLock; /* Gross locking semaphore */ - __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer - * at compile time so we have to allocate it. - */ - struct ylist_head searchContexts; - void (*putSuperFunc)(struct super_block *sb); - - struct task_struct *readdirProcess; - unsigned mount_id; -}; - -#define yaffs_DeviceToLC(dev) ((struct yaffs_LinuxContext *)((dev)->osContext)) -#define yaffs_DeviceToMtd(dev) ((struct mtd_info *)((dev)->driverContext)) - -#endif - diff --git a/fs/yaffs2/yaffs_linux_allocator.c b/fs/yaffs2/yaffs_linux_allocator.c deleted file mode 100644 index d4205fa2..00000000 --- a/fs/yaffs2/yaffs_linux_allocator.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * 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. - * - * Note: Tis code is currently unused. Being checked in in case it becomes useful. - */ - - -#include "yaffs_allocator.h" -#include "yaffs_guts.h" -#include "yaffs_trace.h" -#include "yportenv.h" -#include "yaffs_linux.h" -/* - * Start out with the same allocator as yaffs direct. - * Todo: Change to Linux slab allocator. - */ - - - -#define NAMELEN 20 -struct yaffs_AllocatorStruct { - char tnode_name[NAMELEN+1]; - char object_name[NAMELEN+1]; - struct kmem_cache *tnode_cache; - struct kmem_cache *object_cache; -}; - -typedef struct yaffs_AllocatorStruct yaffs_Allocator; - -int mount_id; - -void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev) -{ - yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; - - T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n"))); - - if(allocator){ - if(allocator->tnode_cache){ - kmem_cache_destroy(allocator->tnode_cache); - allocator->tnode_cache = NULL; - } else { - T(YAFFS_TRACE_ALWAYS, - (TSTR("NULL tnode cache\n"))); - YBUG(); - } - - if(allocator->object_cache){ - kmem_cache_destroy(allocator->object_cache); - allocator->object_cache = NULL; - } else { - T(YAFFS_TRACE_ALWAYS, - (TSTR("NULL object cache\n"))); - YBUG(); - } - - YFREE(allocator); - - } else { - T(YAFFS_TRACE_ALWAYS, - (TSTR("Deinitialising NULL allocator\n"))); - YBUG(); - } - dev->allocator = NULL; -} - - -static void fake_ctor0(void *data){data = data;} -static void fake_ctor1(void *data){data = data;} -static void fake_ctor2(void *data){data = data;} -static void fake_ctor3(void *data){data = data;} -static void fake_ctor4(void *data){data = data;} -static void fake_ctor5(void *data){data = data;} -static void fake_ctor6(void *data){data = data;} -static void fake_ctor7(void *data){data = data;} -static void fake_ctor8(void *data){data = data;} -static void fake_ctor9(void *data){data = data;} - -static void (*fake_ctor_list[10]) (void *) = { - fake_ctor0, - fake_ctor1, - fake_ctor2, - fake_ctor3, - fake_ctor4, - fake_ctor5, - fake_ctor6, - fake_ctor7, - fake_ctor8, - fake_ctor9, -}; - -void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev) -{ - yaffs_Allocator *allocator; - unsigned mount_id = yaffs_DeviceToLC(dev)->mount_id; - - T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n"))); - - if(dev->allocator) - YBUG(); - else if(mount_id >= 10){ - T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id)); - } else { - allocator = YMALLOC(sizeof(yaffs_Allocator)); - memset(allocator,0,sizeof(yaffs_Allocator)); - dev->allocator = allocator; - - if(!dev->allocator){ - T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs allocator creation failed\n"))); - YBUG(); - return; - - } - - sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id); - sprintf(allocator->object_name,"yaffs_o_%u",mount_id); - - allocator->tnode_cache = - kmem_cache_create(allocator->tnode_name, - dev->tnodeSize, - 0, 0, - fake_ctor_list[mount_id]); - if(allocator->tnode_cache) - T(YAFFS_TRACE_ALLOCATE, - (TSTR("tnode cache \"%s\" %p\n"), - allocator->tnode_name,allocator->tnode_cache)); - else { - T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs cache creation failed\n"))); - YBUG(); - } - - - allocator->object_cache = - kmem_cache_create(allocator->object_name, - sizeof(yaffs_Object), - 0, 0, - fake_ctor_list[mount_id]); - - if(allocator->object_cache) - T(YAFFS_TRACE_ALLOCATE, - (TSTR("object cache \"%s\" %p\n"), - allocator->object_name,allocator->object_cache)); - - else { - T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs cache creation failed\n"))); - YBUG(); - } - } -} - - -yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev) -{ - yaffs_Allocator *allocator = dev->allocator; - if(!allocator || !allocator->tnode_cache){ - YBUG(); - return NULL; - } - return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS); -} - -void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn) -{ - yaffs_Allocator *allocator = dev->allocator; - kmem_cache_free(allocator->tnode_cache,tn); -} - -yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev) -{ - yaffs_Allocator *allocator = dev->allocator; - if(!allocator){ - YBUG(); - return NULL; - } - if(!allocator->object_cache){ - YBUG(); - return NULL; - } - return kmem_cache_alloc(allocator->object_cache, GFP_NOFS); -} - -void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj) -{ - yaffs_Allocator *allocator = dev->allocator; - kmem_cache_free(allocator->object_cache,obj); -} diff --git a/fs/yaffs2/yaffs_list.h b/fs/yaffs2/yaffs_list.h deleted file mode 100644 index 09d80b85..00000000 --- a/fs/yaffs2/yaffs_list.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * 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. - */ - -/* - * 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 __YAFFS_LIST_H__ -#define __YAFFS_LIST_H__ - - -#include "yportenv.h" - -/* - * This is a simple doubly linked list implementation that matches the - * way the Linux kernel doubly linked list implementation works. - */ - -struct ylist_head { - struct ylist_head *next; /* next in chain */ - struct ylist_head *prev; /* previous in chain */ -}; - - -/* Initialise a static list */ -#define YLIST_HEAD(name) \ -struct ylist_head name = { &(name), &(name)} - - - -/* Initialise a list head to an empty list */ -#define YINIT_LIST_HEAD(p) \ -do { \ - (p)->next = (p);\ - (p)->prev = (p); \ -} while (0) - - -/* Add an element to a list */ -static Y_INLINE void ylist_add(struct ylist_head *newEntry, - struct ylist_head *list) -{ - struct ylist_head *listNext = list->next; - - list->next = newEntry; - newEntry->prev = list; - newEntry->next = listNext; - listNext->prev = newEntry; - -} - -static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry, - struct ylist_head *list) -{ - struct ylist_head *listPrev = list->prev; - - list->prev = newEntry; - newEntry->next = list; - newEntry->prev = listPrev; - listPrev->next = newEntry; - -} - - -/* Take an element out of its current list, with or without - * reinitialising the links.of the entry*/ -static Y_INLINE void ylist_del(struct ylist_head *entry) -{ - struct ylist_head *listNext = entry->next; - struct ylist_head *listPrev = entry->prev; - - listNext->prev = listPrev; - listPrev->next = listNext; - -} - -static Y_INLINE void ylist_del_init(struct ylist_head *entry) -{ - ylist_del(entry); - entry->next = entry->prev = entry; -} - - -/* Test if the list is empty */ -static Y_INLINE int ylist_empty(struct ylist_head *entry) -{ - return (entry->next == entry); -} - - -/* ylist_entry takes a pointer to a list entry and offsets it to that - * we can find a pointer to the object it is embedded in. - */ - - -#define ylist_entry(entry, type, member) \ - ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member))) - - -/* ylist_for_each and list_for_each_safe iterate over lists. - * ylist_for_each_safe uses temporary storage to make the list delete safe - */ - -#define ylist_for_each(itervar, list) \ - for (itervar = (list)->next; itervar != (list); itervar = itervar->next) - -#define ylist_for_each_safe(itervar, saveVar, list) \ - for (itervar = (list)->next, saveVar = (list)->next->next; \ - itervar != (list); itervar = saveVar, saveVar = saveVar->next) - - -#endif diff --git a/fs/yaffs2/yaffs_mtdif.c b/fs/yaffs2/yaffs_mtdif.c index e073a5ef..72f64203 100644 --- a/fs/yaffs2/yaffs_mtdif.c +++ b/fs/yaffs2/yaffs_mtdif.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -11,6 +11,9 @@ * published by the Free Software Foundation. */ +const char *yaffs_mtdif_c_version = + "$Id$"; + #include "yportenv.h" @@ -21,26 +24,208 @@ #include "linux/time.h" #include "linux/mtd/nand.h" -#include "yaffs_linux.h" +#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18)) +static struct nand_oobinfo yaffs_oobinfo = { + .useecc = 1, + .eccbytes = 6, + .eccpos = {8, 9, 10, 13, 14, 15} +}; + +static struct nand_oobinfo yaffs_noeccinfo = { + .useecc = 0, +}; +#endif + +#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) +static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob) +{ + oob[0] = spare->tagByte0; + oob[1] = spare->tagByte1; + oob[2] = spare->tagByte2; + oob[3] = spare->tagByte3; + oob[4] = spare->tagByte4; + oob[5] = spare->tagByte5 & 0x3f; + oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80; + oob[5] |= spare->pageStatus == 0 ? 0 : 0x40; + oob[6] = spare->tagByte6; + oob[7] = spare->tagByte7; +} + +static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob) +{ + struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare; + spare->tagByte0 = oob[0]; + spare->tagByte1 = oob[1]; + spare->tagByte2 = oob[2]; + spare->tagByte3 = oob[3]; + spare->tagByte4 = oob[4]; + spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f; + spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y'; + spare->pageStatus = oob[5] & 0x40 ? 0xff : 0; + spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff; + spare->tagByte6 = oob[6]; + spare->tagByte7 = oob[7]; + spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff; + + nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */ +} +#endif + +int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND, + const __u8 *data, const yaffs_Spare *spare) +{ + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); +#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 (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) + __u8 spareAsBytes[8]; /* OOB */ + + if (data && !spare) + retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk, + &dummy, data); + else if (spare) { + if (dev->useNANDECC) { + translate_spare2oob(spare, spareAsBytes); + ops.mode = MTD_OOB_AUTO; + ops.ooblen = 8; /* temp hack */ + } else { + ops.mode = MTD_OOB_RAW; + ops.ooblen = YAFFS_BYTES_PER_SPARE; + } + ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen; + ops.datbuf = (u8 *)data; + ops.ooboffs = 0; + ops.oobbuf = spareAsBytes; + retval = mtd->write_oob(mtd, addr, &ops); + } +#else + __u8 *spareAsBytes = (__u8 *) spare; + + if (data && spare) { + if (dev->useNANDECC) + retval = + mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, + &dummy, data, spareAsBytes, + &yaffs_oobinfo); + else + retval = + mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, + &dummy, data, spareAsBytes, + &yaffs_noeccinfo); + } else { + if (data) + retval = + mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, + data); + if (spare) + retval = + mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE, + &dummy, spareAsBytes); + } +#endif + + if (retval == 0) + return YAFFS_OK; + else + return YAFFS_FAIL; +} + +int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, + yaffs_Spare *spare) +{ + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); +#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 (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) + __u8 spareAsBytes[8]; /* OOB */ + + if (data && !spare) + retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, + &dummy, data); + else if (spare) { + if (dev->useNANDECC) { + ops.mode = MTD_OOB_AUTO; + ops.ooblen = 8; /* temp hack */ + } else { + ops.mode = MTD_OOB_RAW; + ops.ooblen = YAFFS_BYTES_PER_SPARE; + } + ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen; + ops.datbuf = data; + ops.ooboffs = 0; + ops.oobbuf = spareAsBytes; + retval = mtd->read_oob(mtd, addr, &ops); + if (dev->useNANDECC) + translate_oob2spare(spare, spareAsBytes); + } +#else + __u8 *spareAsBytes = (__u8 *) spare; + + if (data && spare) { + if (dev->useNANDECC) { + /* Careful, this call adds 2 ints */ + /* to the end of the spare data. Calling function */ + /* should allocate enough memory for spare, */ + /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */ + retval = + mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, + &dummy, data, spareAsBytes, + &yaffs_oobinfo); + } else { + retval = + mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, + &dummy, data, spareAsBytes, + &yaffs_noeccinfo); + } + } else { + if (data) + retval = + mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, + data); + if (spare) + retval = + mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE, + &dummy, spareAsBytes); + } +#endif + + if (retval == 0) + return YAFFS_OK; + else + return YAFFS_FAIL; +} int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) { - struct mtd_info *mtd = yaffs_DeviceToMtd(dev); + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); __u32 addr = - ((loff_t) blockNumber) * dev->param.totalBytesPerChunk - * dev->param.nChunksPerBlock; + ((loff_t) blockNumber) * dev->nDataBytesPerChunk + * dev->nChunksPerBlock; struct erase_info ei; - int retval = 0; ei.mtd = mtd; ei.addr = addr; - ei.len = dev->param.totalBytesPerChunk * dev->param.nChunksPerBlock; + ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock; ei.time = 1000; ei.retries = 2; ei.callback = NULL; ei.priv = (u_long) dev; + /* Todo finish off the ei if required */ + + sema_init(&dev->sem, 0); + retval = mtd->erase(mtd, &ei); if (retval == 0) diff --git a/fs/yaffs2/yaffs_mtdif.h b/fs/yaffs2/yaffs_mtdif.h index fad9d287..e72cfcdd 100644 --- a/fs/yaffs2/yaffs_mtdif.h +++ b/fs/yaffs2/yaffs_mtdif.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -22,6 +22,11 @@ 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, + yaffs_Spare *spare); int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); int nandmtd_InitialiseNAND(yaffs_Device *dev); #endif diff --git a/fs/yaffs2/yaffs_mtdif1.c b/fs/yaffs2/yaffs_mtdif1.c index b14a2549..bcac4702 100644 --- a/fs/yaffs2/yaffs_mtdif1.c +++ b/fs/yaffs2/yaffs_mtdif1.c @@ -2,7 +2,7 @@ * YAFFS: Yet another FFS. A NAND-flash specific file system. * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * 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 @@ -24,11 +24,9 @@ */ #include "yportenv.h" -#include "yaffs_trace.h" #include "yaffs_guts.h" #include "yaffs_packedtags1.h" #include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */ -#include "yaffs_linux.h" #include "linux/kernel.h" #include "linux/version.h" @@ -38,6 +36,8 @@ /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) +const char *yaffs_mtdif1_c_version = "$Id$"; + #ifndef CONFIG_YAFFS_9BYTE_TAGS # define YTAG1_SIZE 8 #else @@ -91,7 +91,7 @@ static struct nand_ecclayout nand_oob_16 = { int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags) { - struct mtd_info *mtd = yaffs_DeviceToMtd(dev); + struct mtd_info *mtd = dev->genericDevice; int chunkBytes = dev->nDataBytesPerChunk; loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; struct mtd_oob_ops ops; @@ -135,9 +135,9 @@ int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, retval = mtd->write_oob(mtd, addr, &ops); if (retval) { - T(YAFFS_TRACE_MTD, - (TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR), - chunkInNAND, retval)); + yaffs_trace(YAFFS_TRACE_MTD, + "write_oob failed, chunk %d, mtd error %d\n", + chunkInNAND, retval); } return retval ? YAFFS_FAIL : YAFFS_OK; } @@ -169,7 +169,7 @@ static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval) int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags) { - struct mtd_info *mtd = yaffs_DeviceToMtd(dev); + struct mtd_info *mtd = dev->genericDevice; int chunkBytes = dev->nDataBytesPerChunk; loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; int eccres = YAFFS_ECC_RESULT_NO_ERROR; @@ -196,9 +196,9 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, */ retval = mtd->read_oob(mtd, addr, &ops); if (retval) { - T(YAFFS_TRACE_MTD, - (TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR), - chunkInNAND, retval)); + yaffs_trace(YAFFS_TRACE_MTD, + "read_oob failed, chunk %d, mtd error %d\n", + chunkInNAND, retval); } switch (retval) { @@ -280,11 +280,11 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, */ int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) { - struct mtd_info *mtd = yaffs_DeviceToMtd(dev); - int blocksize = dev->param.nChunksPerBlock * dev->nDataBytesPerChunk; + struct mtd_info *mtd = dev->genericDevice; + int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; int retval; - T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), 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; @@ -301,9 +301,9 @@ static int nandmtd1_TestPrerequists(struct mtd_info *mtd) int oobavail = mtd->ecclayout->oobavail; if (oobavail < YTAG1_SIZE) { - T(YAFFS_TRACE_ERROR, - (TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR), - oobavail, YTAG1_SIZE)); + yaffs_trace(YAFFS_TRACE_ERROR, + "mtd device has only %d bytes for tags, need %d\n", + oobavail, YTAG1_SIZE); return YAFFS_FAIL; } return YAFFS_OK; @@ -321,8 +321,8 @@ static int nandmtd1_TestPrerequists(struct mtd_info *mtd) int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *pState, __u32 *pSequenceNumber) { - struct mtd_info *mtd = yaffs_DeviceToMtd(dev); - int chunkNo = blockNo * dev->param.nChunksPerBlock; + 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; @@ -338,8 +338,8 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); etags.blockBad = (mtd->block_isbad)(mtd, addr); if (etags.blockBad) { - T(YAFFS_TRACE_BAD_BLOCKS, - (TSTR("block %d is marked bad"TENDSTR), blockNo)); + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, + "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 */ diff --git a/fs/yaffs2/yaffs_mtdif1.h b/fs/yaffs2/yaffs_mtdif1.h index 0e6a56fb..240202cd 100644 --- a/fs/yaffs2/yaffs_mtdif1.h +++ b/fs/yaffs2/yaffs_mtdif1.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * This program is free software; you can redistribute it and/or modify diff --git a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c index 2b0a601f..0c4746bb 100644 --- a/fs/yaffs2/yaffs_mtdif2.c +++ b/fs/yaffs2/yaffs_mtdif2.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -13,8 +13,11 @@ /* mtd interface for YAFFS2 */ +const char *yaffs_mtdif2_c_version = + "$Id$"; + #include "yportenv.h" -#include "yaffs_trace.h" + #include "yaffs_mtdif2.h" @@ -24,7 +27,11 @@ #include "yaffs_packedtags2.h" -#include "yaffs_linux.h" +#ifdef CONFIG_YAFFS_DOES_ECC +#define OOB_TAGS_SIZE sizeof(yaffs_PackedTags2) +#else +#define OOB_TAGS_SIZE sizeof(yaffs_PackedTags2TagsPart) +#endif /* NB For use with inband tags.... * We assume that the data buffer is of size totalBytersPerChunk so that we can also @@ -34,7 +41,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *tags) { - struct mtd_info *mtd = yaffs_DeviceToMtd(dev); + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) struct mtd_oob_ops ops; #else @@ -46,16 +53,12 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, yaffs_PackedTags2 pt; - int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt); - void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t : (void *)&pt; - T(YAFFS_TRACE_MTD, (TSTR ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" TENDSTR), chunkInNAND, data, tags)); - - addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk; + 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 @@ -63,30 +66,30 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, */ if (!data || !tags) BUG(); - else if (dev->param.inbandTags) { + else if (dev->inbandTags) { yaffs_PackedTags2TagsPart *pt2tp; pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); yaffs_PackTags2TagsPart(pt2tp, tags); } else - yaffs_PackTags2(&pt, tags, !dev->param.noTagsECC); + yaffs_PackTags2(&pt, tags); #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ops.mode = MTD_OOB_AUTO; - ops.ooblen = (dev->param.inbandTags) ? 0 : packed_tags_size; - ops.len = dev->param.totalBytesPerChunk; + ops.ooblen = (dev->inbandTags) ? 0 : OOB_TAGS_SIZE; + ops.len = dev->totalBytesPerChunk; ops.ooboffs = 0; ops.datbuf = (__u8 *)data; - ops.oobbuf = (dev->param.inbandTags) ? NULL : packed_tags_ptr; + ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt; retval = mtd->write_oob(mtd, addr, &ops); #else - if (!dev->param.inbandTags) { + if (!dev->inbandTags) { retval = mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, (__u8 *) packed_tags_ptr, NULL); + &dummy, data, (__u8 *) &pt, NULL); } else { retval = - mtd->write(mtd, addr, dev->param.totalBytesPerChunk, &dummy, + mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy, data); } #endif @@ -100,7 +103,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags) { - struct mtd_info *mtd = yaffs_DeviceToMtd(dev); + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) struct mtd_oob_ops ops; #endif @@ -108,19 +111,16 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, int retval = 0; int localData = 0; - loff_t addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk; + loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; yaffs_PackedTags2 pt; - int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt); - void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t: (void *)&pt; - T(YAFFS_TRACE_MTD, (TSTR ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p" TENDSTR), chunkInNAND, data, tags)); - if (dev->param.inbandTags) { + if (dev->inbandTags) { if (!data) { localData = 1; @@ -132,20 +132,20 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) - if (dev->param.inbandTags || (data && !tags)) - retval = mtd->read(mtd, addr, dev->param.totalBytesPerChunk, + if (dev->inbandTags || (data && !tags)) + retval = mtd->read(mtd, addr, dev->totalBytesPerChunk, &dummy, data); else if (tags) { ops.mode = MTD_OOB_AUTO; - ops.ooblen = packed_tags_size; - ops.len = data ? dev->nDataBytesPerChunk : packed_tags_size; + ops.ooblen = OOB_TAGS_SIZE; + ops.len = data ? dev->nDataBytesPerChunk : OOB_TAGS_SIZE; ops.ooboffs = 0; ops.datbuf = data; - ops.oobbuf = yaffs_DeviceToLC(dev)->spareBuffer; + ops.oobbuf = dev->spareBuffer; retval = mtd->read_oob(mtd, addr, &ops); } #else - if (!dev->param.inbandTags && data && tags) { + if (!dev->inbandTags && data && tags) { retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, &dummy, data, dev->spareBuffer, @@ -155,7 +155,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, data); - if (!dev->param.inbandTags && tags) + if (!dev->inbandTags && tags) retval = mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, dev->spareBuffer); @@ -163,7 +163,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, #endif - if (dev->param.inbandTags) { + if (dev->inbandTags) { if (tags) { yaffs_PackedTags2TagsPart *pt2tp; pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; @@ -171,8 +171,8 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, } } else { if (tags) { - memcpy(packed_tags_ptr, yaffs_DeviceToLC(dev)->spareBuffer, packed_tags_size); - yaffs_UnpackTags2(tags, &pt, !dev->param.noTagsECC); + memcpy(&pt, dev->spareBuffer, OOB_TAGS_SIZE); + yaffs_UnpackTags2(tags, &pt); } } @@ -183,7 +183,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; dev->eccUnfixed++; } - if(tags && retval == -EUCLEAN && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) { + if (tags && retval == -EUCLEAN && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) { tags->eccResult = YAFFS_ECC_RESULT_FIXED; dev->eccFixed++; } @@ -195,15 +195,15 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) { - struct mtd_info *mtd = yaffs_DeviceToMtd(dev); + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); int retval; T(YAFFS_TRACE_MTD, (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo)); retval = mtd->block_markbad(mtd, - blockNo * dev->param.nChunksPerBlock * - dev->param.totalBytesPerChunk); + blockNo * dev->nChunksPerBlock * + dev->totalBytesPerChunk); if (retval == 0) return YAFFS_OK; @@ -215,15 +215,15 @@ int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, __u32 *sequenceNumber) { - struct mtd_info *mtd = yaffs_DeviceToMtd(dev); + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); int retval; T(YAFFS_TRACE_MTD, (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo)); retval = mtd->block_isbad(mtd, - blockNo * dev->param.nChunksPerBlock * - dev->param.totalBytesPerChunk); + blockNo * dev->nChunksPerBlock * + dev->totalBytesPerChunk); if (retval) { T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR))); @@ -234,7 +234,7 @@ int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_ExtendedTags t; nandmtd2_ReadChunkWithTagsFromNAND(dev, blockNo * - dev->param.nChunksPerBlock, NULL, + dev->nChunksPerBlock, NULL, &t); if (t.chunkUsed) { diff --git a/fs/yaffs2/yaffs_mtdif2.h b/fs/yaffs2/yaffs_mtdif2.h index 5691267e..b5ff0788 100644 --- a/fs/yaffs2/yaffs_mtdif2.h +++ b/fs/yaffs2/yaffs_mtdif2.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning diff --git a/fs/yaffs2/yaffs_nameval.c b/fs/yaffs2/yaffs_nameval.c deleted file mode 100644 index a4ed2973..00000000 --- a/fs/yaffs2/yaffs_nameval.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * 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 simple implementation of a name-value store assumes a small number of values and fits - * into a small finite buffer. - * - * Each attribute is stored as a record: - * sizeof(int) bytes record size. - * strnlen+1 bytes name null terminated. - * nbytes value. - * ---------- - * total size stored in record size - * - * This code has not been tested with unicode yet. - */ - - -#include "yaffs_nameval.h" - -#include "yportenv.h" - -static int nval_find(const char *xb, int xb_size, const YCHAR *name, - int *exist_size) -{ - int pos=0; - int size; - - memcpy(&size,xb,sizeof(int)); - while(size > 0 && (size < xb_size) && (pos + size < xb_size)){ - if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){ - if(exist_size) - *exist_size = size; - return pos; - } - pos += size; - if(pos < xb_size -sizeof(int)) - memcpy(&size,xb + pos,sizeof(int)); - else - size = 0; - } - if(exist_size) - *exist_size = 0; - return -1; -} - -static int nval_used(const char *xb, int xb_size) -{ - int pos=0; - int size; - - memcpy(&size,xb + pos,sizeof(int)); - while(size > 0 && (size < xb_size) && (pos + size < xb_size)){ - pos += size; - if(pos < xb_size -sizeof(int)) - memcpy(&size,xb + pos,sizeof(int)); - else - size = 0; - } - return pos; -} - -int nval_del(char *xb, int xb_size, const YCHAR *name) -{ - int pos = nval_find(xb, xb_size, name, NULL); - int size; - - if(pos >= 0 && pos < xb_size){ - /* Find size, shift rest over this record, then zero out the rest of buffer */ - memcpy(&size,xb+pos,sizeof(int)); - memcpy(xb + pos, xb + pos + size, xb_size - (pos + size)); - memset(xb + (xb_size - size),0,size); - return 0; - } else - return -ENODATA; -} - -int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags) -{ - int pos; - int namelen = yaffs_strnlen(name,xb_size); - int reclen; - int size_exist = 0; - int space; - int start; - - pos = nval_find(xb,xb_size,name, &size_exist); - - if(flags & XATTR_CREATE && pos >= 0) - return -EEXIST; - if(flags & XATTR_REPLACE && pos < 0) - return -ENODATA; - - start = nval_used(xb,xb_size); - space = xb_size - start + size_exist; - - reclen = (sizeof(int) + namelen + 1 + bsize); - - if(reclen > space) - return -ENOSPC; - - if(pos >= 0){ - nval_del(xb,xb_size,name); - start = nval_used(xb, xb_size); - } - - pos = start; - - memcpy(xb + pos,&reclen,sizeof(int)); - pos +=sizeof(int); - yaffs_strncpy((YCHAR *)(xb + pos), name, reclen); - pos+= (namelen+1); - memcpy(xb + pos,buf,bsize); - return 0; -} - -int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize) -{ - int pos = nval_find(xb,xb_size,name,NULL); - int size; - - if(pos >= 0 && pos< xb_size){ - - memcpy(&size,xb +pos,sizeof(int)); - pos+=sizeof(int); /* advance past record length */ - size -= sizeof(int); - - /* Advance over name string */ - while(xb[pos] && size > 0 && pos < xb_size){ - pos++; - size--; - } - /*Advance over NUL */ - pos++; - size--; - - if(size <= bsize){ - memcpy(buf,xb + pos,size); - return size; - } - - } - if(pos >= 0) - return -ERANGE; - else - return -ENODATA; -} - -int nval_list(const char *xb, int xb_size, char *buf, int bsize) -{ - int pos = 0; - int size; - int name_len; - int ncopied = 0; - int filled = 0; - - memcpy(&size,xb + pos,sizeof(int)); - while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){ - pos+= sizeof(int); - size-=sizeof(int); - name_len = yaffs_strnlen((YCHAR *)(xb + pos), size); - if(ncopied + name_len + 1 < bsize){ - memcpy(buf,xb+pos,name_len * sizeof(YCHAR)); - buf+= name_len; - *buf = '\0'; - buf++; - if(sizeof(YCHAR) > 1){ - *buf = '\0'; - buf++; - } - ncopied += (name_len+1); - } else - filled = 1; - pos+=size; - if(pos < xb_size -sizeof(int)) - memcpy(&size,xb + pos,sizeof(int)); - else - size = 0; - } - return ncopied; -} - - -int nval_hasvalues(const char *xb, int xb_size) -{ - return nval_used(xb, xb_size) > 0; -} diff --git a/fs/yaffs2/yaffs_nameval.h b/fs/yaffs2/yaffs_nameval.h deleted file mode 100644 index 4255f3b0..00000000 --- a/fs/yaffs2/yaffs_nameval.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * 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 __NAMEVAL_H__ -#define __NAMEVAL_H__ - -#include "yportenv.h" - -int nval_del(char *xb, int xb_size, const YCHAR *name); -int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags); -int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize); -int nval_list(const char *xb, int xb_size, char *buf, int bsize); -int nval_hasvalues(const char *xb, int xb_size); -#endif diff --git a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c index 6964ad18..f6ba4c79 100644 --- a/fs/yaffs2/yaffs_nand.c +++ b/fs/yaffs2/yaffs_nand.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -11,6 +11,9 @@ * published by the Free Software Foundation. */ +const char *yaffs_nand_c_version = + "$Id$"; + #include "yaffs_nand.h" #include "yaffs_tagscompat.h" #include "yaffs_tagsvalidity.h" @@ -32,8 +35,8 @@ int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, if (!tags) tags = &localTags; - if (dev->param.readChunkWithTagsFromNAND) - result = dev->param.readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer, + if (dev->readChunkWithTagsFromNAND) + result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer, tags); else result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev, @@ -43,8 +46,7 @@ int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, if (tags && tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) { - yaffs_BlockInfo *bi; - bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->param.nChunksPerBlock); + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock); yaffs_HandleChunkError(dev, bi); } @@ -78,8 +80,8 @@ int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev, YBUG(); } - if (dev->param.writeChunkWithTagsToNAND) - return dev->param.writeChunkWithTagsToNAND(dev, chunkInNAND, buffer, + if (dev->writeChunkWithTagsToNAND) + return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer, tags); else return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev, @@ -93,8 +95,8 @@ int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo) blockNo -= dev->blockOffset; - if (dev->param.markNANDBlockBad) - return dev->param.markNANDBlockBad(dev, blockNo); + if (dev->markNANDBlockBad) + return dev->markNANDBlockBad(dev, blockNo); else return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo); } @@ -106,8 +108,8 @@ int yaffs_QueryInitialBlockState(yaffs_Device *dev, { blockNo -= dev->blockOffset; - if (dev->param.queryNANDBlock) - return dev->param.queryNANDBlock(dev, blockNo, state, sequenceNumber); + if (dev->queryNANDBlock) + return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber); else return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo, state, @@ -124,16 +126,14 @@ int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, dev->nBlockErasures++; - result = dev->param.eraseBlockInNAND(dev, blockInNAND); + result = dev->eraseBlockInNAND(dev, blockInNAND); return result; } int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev) { - if(dev->param.initialiseNAND) - return dev->param.initialiseNAND(dev); - return YAFFS_OK; + return dev->initialiseNAND(dev); } diff --git a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h index 62a46659..e013cdc2 100644 --- a/fs/yaffs2/yaffs_nand.h +++ b/fs/yaffs2/yaffs_nand.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning diff --git a/fs/yaffs2/yaffs_nandemul2k.h b/fs/yaffs2/yaffs_nandemul2k.h index 2f4ce97b..41bc2b5f 100644 --- a/fs/yaffs2/yaffs_nandemul2k.h +++ b/fs/yaffs2/yaffs_nandemul2k.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning diff --git a/fs/yaffs2/yaffs_packedtags1.c b/fs/yaffs2/yaffs_packedtags1.c index b2160c08..3e67e691 100644 --- a/fs/yaffs2/yaffs_packedtags1.c +++ b/fs/yaffs2/yaffs_packedtags1.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning diff --git a/fs/yaffs2/yaffs_packedtags1.h b/fs/yaffs2/yaffs_packedtags1.h index b9cf1a8b..f8c0471d 100644 --- a/fs/yaffs2/yaffs_packedtags1.h +++ b/fs/yaffs2/yaffs_packedtags1.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning diff --git a/fs/yaffs2/yaffs_packedtags2.c b/fs/yaffs2/yaffs_packedtags2.c index f8ae94cc..62efec02 100644 --- a/fs/yaffs2/yaffs_packedtags2.c +++ b/fs/yaffs2/yaffs_packedtags2.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -13,7 +13,6 @@ #include "yaffs_packedtags2.h" #include "yportenv.h" -#include "yaffs_trace.h" #include "yaffs_tagsvalidity.h" /* This code packs a set of extended tags into a binary structure for @@ -38,6 +37,9 @@ #define EXTRA_OBJECT_TYPE_SHIFT (28) #define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) +#ifndef CONFIG_YAFFS_DOES_ECC +#define YAFFS_IGNORE_TAGS_ECC 1 +#endif static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt) { @@ -97,14 +99,17 @@ void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt, } -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC) +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t) { yaffs_PackTags2TagsPart(&pt->t, t); - if(tagsECC) +#ifndef YAFFS_IGNORE_TAGS_ECC + { yaffs_ECCCalculateOther((unsigned char *)&pt->t, sizeof(yaffs_PackedTags2TagsPart), &pt->ecc); + } +#endif } @@ -156,24 +161,27 @@ void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, } -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC) +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt) { yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR; - if (pt->t.sequenceNumber != 0xFFFFFFFF && - tagsECC){ - /* Chunk is in use and we need to do ECC */ - - yaffs_ECCOther ecc; - int result; - yaffs_ECCCalculateOther((unsigned char *)&pt->t, - sizeof(yaffs_PackedTags2TagsPart), - &ecc); - result = yaffs_ECCCorrectOther((unsigned char *)&pt->t, - sizeof(yaffs_PackedTags2TagsPart), - &pt->ecc, &ecc); - switch (result) { + if (pt->t.sequenceNumber != 0xFFFFFFFF) { + /* Page is in use */ +#ifndef YAFFS_IGNORE_TAGS_ECC + { + yaffs_ECCOther ecc; + int result; + yaffs_ECCCalculateOther((unsigned char *)&pt->t, + sizeof + (yaffs_PackedTags2TagsPart), + &ecc); + result = + yaffs_ECCCorrectOther((unsigned char *)&pt->t, + sizeof + (yaffs_PackedTags2TagsPart), + &pt->ecc, &ecc); + switch (result) { case 0: eccResult = YAFFS_ECC_RESULT_NO_ERROR; break; @@ -185,7 +193,9 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC break; default: eccResult = YAFFS_ECC_RESULT_UNKNOWN; + } } +#endif } yaffs_UnpackTags2TagsPart(t, &pt->t); @@ -194,5 +204,6 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC yaffs_DumpPackedTags2(pt); yaffs_DumpTags2(t); + } diff --git a/fs/yaffs2/yaffs_packedtags2.h b/fs/yaffs2/yaffs_packedtags2.h index c132a98c..ec30f843 100644 --- a/fs/yaffs2/yaffs_packedtags2.h +++ b/fs/yaffs2/yaffs_packedtags2.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -34,8 +34,8 @@ typedef struct { } yaffs_PackedTags2; /* Full packed tags with ECC, used for oob tags */ -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC); -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC); +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); diff --git a/fs/yaffs2/yaffs_qsort.h b/fs/yaffs2/yaffs_qsort.h index 4a4981b3..941c7a87 100644 --- a/fs/yaffs2/yaffs_qsort.h +++ b/fs/yaffs2/yaffs_qsort.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -17,18 +17,7 @@ #ifndef __YAFFS_QSORT_H__ #define __YAFFS_QSORT_H__ -#ifdef __KERNEL__ -#include - -extern void yaffs_qsort(void *const base, size_t total_elems, size_t size, - int (*cmp)(const void *, const void *)){ - sort(base, total_elems, size, cmp, NULL); -} - -#else - extern void yaffs_qsort(void *const base, size_t total_elems, size_t size, int (*cmp)(const void *, const void *)); #endif -#endif diff --git a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c index e9ac51d7..e3173cc2 100644 --- a/fs/yaffs2/yaffs_tagscompat.c +++ b/fs/yaffs2/yaffs_tagscompat.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -15,7 +15,6 @@ #include "yaffs_tagscompat.h" #include "yaffs_ecc.h" #include "yaffs_getblockinfo.h" -#include "yaffs_trace.h" static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND); #ifdef NOTYET @@ -164,14 +163,14 @@ static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev, int chunkInNAND, const __u8 *data, yaffs_Spare *spare) { - if (chunkInNAND < dev->param.startBlock * dev->param.nChunksPerBlock) { + if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) { T(YAFFS_TRACE_ERROR, (TSTR("**>> yaffs chunk %d is not valid" TENDSTR), chunkInNAND)); return YAFFS_FAIL; } - return dev->param.writeChunkToNAND(dev, chunkInNAND, data, spare); + return dev->writeChunkToNAND(dev, chunkInNAND, data, spare); } static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, @@ -190,8 +189,8 @@ static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, spare = &localSpare; } - if (!dev->param.useNANDECC) { - retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data, spare); + if (!dev->useNANDECC) { + retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare); if (data && doErrorCorrection) { /* Do ECC correction */ /* Todo handle any errors */ @@ -252,7 +251,7 @@ static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, memset(&nspare, 0, sizeof(nspare)); - retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data, + retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) &nspare); memcpy(spare, &nspare, sizeof(yaffs_Spare)); if (data && doErrorCorrection) { @@ -305,10 +304,10 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK]; static __u8 data[YAFFS_BYTES_PER_CHUNK]; /* Might as well always allocate the larger size for */ - /* dev->param.useNANDECC == true; */ + /* dev->useNANDECC == true; */ static __u8 spare[sizeof(struct yaffs_NANDSpare)]; - dev->param.readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare); + dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare); if (!init) { memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK); @@ -331,7 +330,7 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND) { - int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock; + int blockInNAND = chunkInNAND / dev->nChunksPerBlock; /* Mark the block for retirement */ yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1; @@ -363,7 +362,7 @@ static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND) { - int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock; + int blockInNAND = chunkInNAND / dev->nChunksPerBlock; /* Mark the block for retirement */ yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; @@ -422,7 +421,7 @@ int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, tags.serialNumber = eTags->serialNumber; - if (!dev->param.useNANDECC && data) + if (!dev->useNANDECC && data) yaffs_CalcECC(data, &spare); yaffs_LoadTagsIntoSpare(&spare, &tags); @@ -496,9 +495,9 @@ int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, spare.blockStatus = 'Y'; - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock, NULL, + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL, &spare); - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock + 1, + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, NULL, &spare); return YAFFS_OK; @@ -523,9 +522,9 @@ int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, *sequenceNumber = 0; - yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock, NULL, + yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL, &spare0, &dummy, 1); - yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock + 1, NULL, + yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL, &spare1, &dummy, 1); if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7) diff --git a/fs/yaffs2/yaffs_tagscompat.h b/fs/yaffs2/yaffs_tagscompat.h index 8c663db5..6f95119e 100644 --- a/fs/yaffs2/yaffs_tagscompat.h +++ b/fs/yaffs2/yaffs_tagscompat.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning diff --git a/fs/yaffs2/yaffs_tagsvalidity.c b/fs/yaffs2/yaffs_tagsvalidity.c index 93ad08c1..5233bcba 100644 --- a/fs/yaffs2/yaffs_tagsvalidity.c +++ b/fs/yaffs2/yaffs_tagsvalidity.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning diff --git a/fs/yaffs2/yaffs_tagsvalidity.h b/fs/yaffs2/yaffs_tagsvalidity.h index 60a1aea6..cb11884b 100644 --- a/fs/yaffs2/yaffs_tagsvalidity.h +++ b/fs/yaffs2/yaffs_tagsvalidity.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning diff --git a/fs/yaffs2/yaffs_trace.h b/fs/yaffs2/yaffs_trace.h deleted file mode 100644 index 8b848edb..00000000 --- a/fs/yaffs2/yaffs_trace.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * 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 __YTRACE_H__ -#define __YTRACE_H__ - -extern unsigned int yaffs_traceMask; -extern unsigned int yaffs_wr_attempts; - -/* - * Tracing flags. - * The flags masked in YAFFS_TRACE_ALWAYS are always traced. - */ - -#define YAFFS_TRACE_OS 0x00000002 -#define YAFFS_TRACE_ALLOCATE 0x00000004 -#define YAFFS_TRACE_SCAN 0x00000008 -#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 -#define YAFFS_TRACE_ERASE 0x00000020 -#define YAFFS_TRACE_GC 0x00000040 -#define YAFFS_TRACE_WRITE 0x00000080 -#define YAFFS_TRACE_TRACING 0x00000100 -#define YAFFS_TRACE_DELETION 0x00000200 -#define YAFFS_TRACE_BUFFERS 0x00000400 -#define YAFFS_TRACE_NANDACCESS 0x00000800 -#define YAFFS_TRACE_GC_DETAIL 0x00001000 -#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 -#define YAFFS_TRACE_MTD 0x00004000 -#define YAFFS_TRACE_CHECKPOINT 0x00008000 - -#define YAFFS_TRACE_VERIFY 0x00010000 -#define YAFFS_TRACE_VERIFY_NAND 0x00020000 -#define YAFFS_TRACE_VERIFY_FULL 0x00040000 -#define YAFFS_TRACE_VERIFY_ALL 0x000F0000 - -#define YAFFS_TRACE_SYNC 0x00100000 -#define YAFFS_TRACE_BACKGROUND 0x00200000 -#define YAFFS_TRACE_LOCK 0x00400000 - -#define YAFFS_TRACE_ERROR 0x40000000 -#define YAFFS_TRACE_BUG 0x80000000 -#define YAFFS_TRACE_ALWAYS 0xF0000000 - - -#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0) - -#endif diff --git a/fs/yaffs2/yaffs_verify.c b/fs/yaffs2/yaffs_verify.c deleted file mode 100644 index a600aa6b..00000000 --- a/fs/yaffs2/yaffs_verify.c +++ /dev/null @@ -1,626 +0,0 @@ -/* - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - - -#include "yaffs_verify.h" -#include "yaffs_trace.h" -#include "yaffs_bitmap.h" -#include "yaffs_getblockinfo.h" -#include "yaffs_nand.h" - -int yaffs_SkipVerification(yaffs_Device *dev) -{ - dev=dev; - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); -} - -static int yaffs_SkipFullVerification(yaffs_Device *dev) -{ - dev=dev; - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); -} - -static int yaffs_SkipNANDVerification(yaffs_Device *dev) -{ - dev=dev; - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); -} - - -static const char *blockStateName[] = { -"Unknown", -"Needs scanning", -"Scanning", -"Empty", -"Allocating", -"Full", -"Dirty", -"Checkpoint", -"Collecting", -"Dead" -}; - - -void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n) -{ - int actuallyUsed; - int inUse; - - if (yaffs_SkipVerification(dev)) - return; - - /* Report illegal runtime states */ - if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState)); - - switch (bi->blockState) { - case YAFFS_BLOCK_STATE_UNKNOWN: - case YAFFS_BLOCK_STATE_SCANNING: - case YAFFS_BLOCK_STATE_NEEDS_SCANNING: - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR), - n, blockStateName[bi->blockState])); - } - - /* Check pages in use and soft deletions are legal */ - - actuallyUsed = bi->pagesInUse - bi->softDeletions; - - if (bi->pagesInUse < 0 || bi->pagesInUse > dev->param.nChunksPerBlock || - bi->softDeletions < 0 || bi->softDeletions > dev->param.nChunksPerBlock || - actuallyUsed < 0 || actuallyUsed > dev->param.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)); - -} - - - -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 */ - - 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)); - } -} - -void yaffs_VerifyBlocks(yaffs_Device *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 < 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))); - - for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) - 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), - nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); - - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); - -} - -/* - * Verify the object header. oh must be valid, but obj and tags may be NULL in which - * case those tests will not be performed. - */ -void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) -{ - if (obj && yaffs_SkipVerification(obj->myDev)) - return; - - if (!(tags && obj && oh)) { - T(YAFFS_TRACE_VERIFY, - (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR), - tags, obj, oh)); - return; - } - - if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || - oh->type > YAFFS_OBJECT_TYPE_MAX) - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), - tags->objectId, oh->type)); - - if (tags->objectId != obj->objectId) - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header mismatch objectId %d"TENDSTR), - tags->objectId, obj->objectId)); - - - /* - * 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 != 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), - obj->objectId)); - - if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header name is 0xFF"TENDSTR), - obj->objectId)); -} - - -#if 0 -/* Not being used, but don't want to throw away yet */ -int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn, - __u32 level, int chunkOffset) -{ - int i; - yaffs_Device *dev = obj->myDev; - int ok = 1; - - if (tn) { - if (level > 0) { - - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { - if (tn->internal[i]) { - ok = yaffs_VerifyTnodeWorker(obj, - tn->internal[i], - level - 1, - (chunkOffset<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); - if (tags.objectId != objectId || tags.chunkId != chunkOffset) { - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), - objectId, chunkOffset, theChunk, - tags.objectId, tags.chunkId)); - } - } - chunkOffset++; - } - } - } - - return ok; - -} - -#endif - -void yaffs_VerifyFile(yaffs_Object *obj) -{ - int requiredTallness; - int actualTallness; - __u32 lastChunk; - __u32 x; - __u32 i; - yaffs_Device *dev; - yaffs_ExtendedTags tags; - yaffs_Tnode *tn; - __u32 objectId; - - 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; - requiredTallness = 0; - while (x > 0) { - x >>= YAFFS_TNODES_INTERNAL_BITS; - requiredTallness++; - } - - actualTallness = obj->variant.fileVariant.topLevel; - - /* 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); - - if (tn) { - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i); - if (theChunk > 0) { - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */ - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags); - if (tags.objectId != objectId || tags.chunkId != i) { - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), - objectId, i, theChunk, - tags.objectId, tags.chunkId)); - } - } - } - } -} - - -void yaffs_VerifyHardLink(yaffs_Object *obj) -{ - if (obj && yaffs_SkipVerification(obj->myDev)) - return; - - /* Verify sane equivalent object */ -} - -void yaffs_VerifySymlink(yaffs_Object *obj) -{ - if (obj && yaffs_SkipVerification(obj->myDev)) - return; - - /* Verify symlink string */ -} - -void yaffs_VerifySpecial(yaffs_Object *obj) -{ - if (obj && yaffs_SkipVerification(obj->myDev)) - return; -} - -void yaffs_VerifyObject(yaffs_Object *obj) -{ - yaffs_Device *dev; - - __u32 chunkMin; - __u32 chunkMax; - - __u32 chunkIdOk; - __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->param.nChunksPerBlock; - chunkMax = (dev->internalEndBlock+1) * dev->param.nChunksPerBlock - 1; - - chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax); - chunkIdOk = chunkInRange || (obj->hdrChunk == 0); - chunkValid = chunkInRange && - yaffs_CheckChunkBit(dev, - obj->hdrChunk / dev->param.nChunksPerBlock, - obj->hdrChunk % dev->param.nChunksPerBlock); - chunkShouldNotBeDeleted = chunkInRange && !chunkValid; - - if (!obj->fake && - (!chunkIdOk || chunkShouldNotBeDeleted)) { - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), - obj->objectId, obj->hdrChunk, - chunkIdOk ? "" : ",out of range", - chunkShouldNotBeDeleted ? ",marked as deleted" : "")); - } - - if (chunkValid && !yaffs_SkipNANDVerification(dev)) { - yaffs_ExtendedTags tags; - yaffs_ObjectHeader *oh; - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); - - oh = (yaffs_ObjectHeader *)buffer; - - 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)); - } - - /* 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)); - } - - switch (obj->variantType) { - case YAFFS_OBJECT_TYPE_FILE: - yaffs_VerifyFile(obj); - break; - case YAFFS_OBJECT_TYPE_SYMLINK: - yaffs_VerifySymlink(obj); - break; - case YAFFS_OBJECT_TYPE_DIRECTORY: - yaffs_VerifyDirectory(obj); - break; - case YAFFS_OBJECT_TYPE_HARDLINK: - yaffs_VerifyHardLink(obj); - break; - case YAFFS_OBJECT_TYPE_SPECIAL: - yaffs_VerifySpecial(obj); - break; - case YAFFS_OBJECT_TYPE_UNKNOWN: - default: - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d has illegaltype %d"TENDSTR), - obj->objectId, obj->variantType)); - break; - } -} - -void yaffs_VerifyObjects(yaffs_Device *dev) -{ - 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); - } - } - } -} - - -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(); - return; - } - - if (yaffs_SkipVerification(obj->myDev)) - return; - - if (!obj->parent) { - T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR))); - YBUG(); - return; - } - - 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(); - } -} - -void yaffs_VerifyDirectory(yaffs_Object *directory) -{ - struct ylist_head *lh; - yaffs_Object *listObj; - - if (!directory) { - YBUG(); - return; - } - - 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); - } - } -} - -static int yaffs_freeVerificationFailures; - -void yaffs_VerifyFreeChunks(yaffs_Device *dev) -{ - int counted; - int difference; - - if (yaffs_SkipVerification(dev)) - return; - - counted = yaffs_CountFreeChunks(dev); - - difference = dev->nFreeChunks - counted; - - if (difference) { - T(YAFFS_TRACE_ALWAYS, - (TSTR("Freechunks verification failure %d %d %d" TENDSTR), - dev->nFreeChunks, counted, difference)); - yaffs_freeVerificationFailures++; - } -} - -int yaffs_VerifyFileSanity(yaffs_Object *in) -{ -#if 0 - int chunk; - int nChunks; - int fSize; - int failed = 0; - int objId; - yaffs_Tnode *tn; - yaffs_Tags localTags; - yaffs_Tags *tags = &localTags; - int theChunk; - int chunkDeleted; - - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) - return YAFFS_FAIL; - - objId = in->objectId; - fSize = in->variant.fileVariant.fileSize; - nChunks = - (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk; - - for (chunk = 1; chunk <= nChunks; chunk++) { - tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant, - chunk); - - if (tn) { - - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk); - - if (yaffs_CheckChunkBits - (dev, theChunk / dev->param.nChunksPerBlock, - theChunk % dev->param.nChunksPerBlock)) { - - yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk, - tags, - &chunkDeleted); - if (yaffs_TagsMatch - (tags, in->objectId, chunk, chunkDeleted)) { - /* found it; */ - - } - } else { - - failed = 1; - } - - } else { - /* T(("No level 0 found for %d\n", chunk)); */ - } - } - - return failed ? YAFFS_FAIL : YAFFS_OK; -#else - in=in; - return YAFFS_OK; -#endif -} diff --git a/fs/yaffs2/yaffs_verify.h b/fs/yaffs2/yaffs_verify.h deleted file mode 100644 index 8a6f7510..00000000 --- a/fs/yaffs2/yaffs_verify.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * 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. - */ - -#ifndef __YAFFS_VERIFY_H__ -#define __YAFFS_VERIFY_H__ - -#include "yaffs_guts.h" - -void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n); -void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n); -void yaffs_VerifyBlocks(yaffs_Device *dev); - -void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck); -void yaffs_VerifyFile(yaffs_Object *obj); -void yaffs_VerifyHardLink(yaffs_Object *obj); -void yaffs_VerifySymlink(yaffs_Object *obj); -void yaffs_VerifySpecial(yaffs_Object *obj); -void yaffs_VerifyObject(yaffs_Object *obj); -void yaffs_VerifyObjects(yaffs_Device *dev); -void yaffs_VerifyObjectInDirectory(yaffs_Object *obj); -void yaffs_VerifyDirectory(yaffs_Object *directory); -void yaffs_VerifyFreeChunks(yaffs_Device *dev); - -int yaffs_VerifyFileSanity(yaffs_Object *obj); - -int yaffs_SkipVerification(yaffs_Device *dev); - -#endif - diff --git a/fs/yaffs2/yaffs_yaffs1.c b/fs/yaffs2/yaffs_yaffs1.c deleted file mode 100644 index 78cc8199..00000000 --- a/fs/yaffs2/yaffs_yaffs1.c +++ /dev/null @@ -1,465 +0,0 @@ -/* - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include "yaffs_yaffs1.h" -#include "yportenv.h" -#include "yaffs_trace.h" -#include "yaffs_bitmap.h" -#include "yaffs_getblockinfo.h" -#include "yaffs_nand.h" - - -int yaffs1_Scan(yaffs_Device *dev) -{ - yaffs_ExtendedTags tags; - int blk; - int blockIterator; - int startIterator; - int endIterator; - int result; - - int chunk; - int c; - int deleted; - yaffs_BlockState state; - yaffs_Object *hardList = NULL; - yaffs_BlockInfo *bi; - __u32 sequenceNumber; - yaffs_ObjectHeader *oh; - yaffs_Object *in; - yaffs_Object *parent; - - int alloc_failed = 0; - - struct yaffs_ShadowFixerStruct *shadowFixerList = NULL; - - - __u8 *chunkData; - - - - T(YAFFS_TRACE_SCAN, - (TSTR("yaffs1_Scan starts intstartblk %d intendblk %d..." TENDSTR), - dev->internalStartBlock, dev->internalEndBlock)); - - chunkData = yaffs_GetTempBuffer(dev, __LINE__); - - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; - - /* Scan all the blocks to determine their state */ - bi = dev->blockInfo; - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { - yaffs_ClearChunkBits(dev, blk); - bi->pagesInUse = 0; - bi->softDeletions = 0; - - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); - - bi->blockState = state; - bi->sequenceNumber = sequenceNumber; - - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK) - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD; - - T(YAFFS_TRACE_SCAN_DEBUG, - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, - state, sequenceNumber)); - - if (state == YAFFS_BLOCK_STATE_DEAD) { - T(YAFFS_TRACE_BAD_BLOCKS, - (TSTR("block %d is bad" TENDSTR), blk)); - } else if (state == YAFFS_BLOCK_STATE_EMPTY) { - T(YAFFS_TRACE_SCAN_DEBUG, - (TSTR("Block empty " TENDSTR))); - dev->nErasedBlocks++; - dev->nFreeChunks += dev->param.nChunksPerBlock; - } - bi++; - } - - startIterator = dev->internalStartBlock; - endIterator = dev->internalEndBlock; - - /* For each block.... */ - for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; - blockIterator++) { - - YYIELD(); - - YYIELD(); - - blk = blockIterator; - - bi = yaffs_GetBlockInfo(dev, blk); - state = bi->blockState; - - deleted = 0; - - /* For each chunk in each block that needs scanning....*/ - for (c = 0; !alloc_failed && c < dev->param.nChunksPerBlock && - state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { - /* Read the tags and decide what to do */ - chunk = blk * dev->param.nChunksPerBlock + c; - - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, - &tags); - - /* Let's have a good look at this chunk... */ - - if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) { - /* YAFFS1 only... - * A deleted chunk - */ - deleted++; - dev->nFreeChunks++; - /*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 is the one being allocated from - */ - - if (c == 0) { - /* We're looking at the first chunk in the block so the block is unused */ - state = YAFFS_BLOCK_STATE_EMPTY; - dev->nErasedBlocks++; - } else { - /* this is the block being allocated from */ - T(YAFFS_TRACE_SCAN, - (TSTR - (" Allocating from %d %d" TENDSTR), - blk, c)); - state = YAFFS_BLOCK_STATE_ALLOCATING; - dev->allocationBlock = blk; - dev->allocationPage = c; - dev->allocationBlockFinder = blk; - /* Set block finder here to encourage the allocator to go forth from here. */ - - } - - dev->nFreeChunks += (dev->param.nChunksPerBlock - c); - } else if (tags.chunkId > 0) { - /* chunkId > 0 so it is a data chunk... */ - unsigned int endpos; - - yaffs_SetChunkBit(dev, blk, c); - bi->pagesInUse++; - - in = yaffs_FindOrCreateObjectByNumber(dev, - tags. - objectId, - YAFFS_OBJECT_TYPE_FILE); - /* PutChunkIntoFile checks for a clash (two data chunks with - * the same chunkId). - */ - - if (!in) - alloc_failed = 1; - - if (in) { - if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1)) - alloc_failed = 1; - } - - endpos = - (tags.chunkId - 1) * dev->nDataBytesPerChunk + - tags.byteCount; - if (in && - in->variantType == YAFFS_OBJECT_TYPE_FILE - && in->variant.fileVariant.scannedFileSize < - endpos) { - in->variant.fileVariant. - scannedFileSize = endpos; - if (!dev->param.useHeaderFileSize) { - in->variant.fileVariant. - fileSize = - in->variant.fileVariant. - scannedFileSize; - } - - } - /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */ - } else { - /* chunkId == 0, so it is an ObjectHeader. - * Thus, we read in the object header and make the object - */ - yaffs_SetChunkBit(dev, blk, c); - bi->pagesInUse++; - - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, - chunkData, - NULL); - - oh = (yaffs_ObjectHeader *) chunkData; - - in = yaffs_FindObjectByNumber(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 - * deleted, and worse still it has changed type. Delete the old object. - */ - - yaffs_DeleteObject(in); - - in = 0; - } - - in = yaffs_FindOrCreateObjectByNumber(dev, - tags. - objectId, - oh->type); - - if (!in) - alloc_failed = 1; - - if (in && 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; - T(YAFFS_TRACE_SCAN, - (TSTR - (" Shadow fixer: %d shadows %d" TENDSTR), - fixer->objectId, fixer->shadowedId)); - - } - - } - - if (in && in->valid) { - /* We have already filled this one. We have a duplicate and need to resolve it. */ - - unsigned existingSerial = in->serial; - unsigned newSerial = tags.serialNumber; - - if (((existingSerial + 1) & 3) == newSerial) { - /* Use new one - destroy the exisiting one */ - yaffs_DeleteChunk(dev, - in->hdrChunk, - 1, __LINE__); - in->valid = 0; - } else { - /* Use existing - destroy this one. */ - yaffs_DeleteChunk(dev, chunk, 1, - __LINE__); - } - } - - if (in && !in->valid && - (tags.objectId == YAFFS_OBJECTID_ROOT || - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) { - /* We only load some info, don't fiddle with directory structure */ - in->valid = 1; - in->variantType = oh->type; - - in->yst_mode = oh->yst_mode; -#ifdef CONFIG_YAFFS_WINCE - in->win_atime[0] = oh->win_atime[0]; - in->win_ctime[0] = oh->win_ctime[0]; - in->win_mtime[0] = oh->win_mtime[0]; - in->win_atime[1] = oh->win_atime[1]; - in->win_ctime[1] = oh->win_ctime[1]; - in->win_mtime[1] = oh->win_mtime[1]; -#else - in->yst_uid = oh->yst_uid; - in->yst_gid = oh->yst_gid; - in->yst_atime = oh->yst_atime; - in->yst_mtime = oh->yst_mtime; - in->yst_ctime = oh->yst_ctime; - in->yst_rdev = oh->yst_rdev; -#endif - in->hdrChunk = chunk; - in->serial = tags.serialNumber; - - } else if (in && !in->valid) { - /* we need to load this info */ - - in->valid = 1; - in->variantType = oh->type; - - in->yst_mode = oh->yst_mode; -#ifdef CONFIG_YAFFS_WINCE - in->win_atime[0] = oh->win_atime[0]; - in->win_ctime[0] = oh->win_ctime[0]; - in->win_mtime[0] = oh->win_mtime[0]; - in->win_atime[1] = oh->win_atime[1]; - in->win_ctime[1] = oh->win_ctime[1]; - in->win_mtime[1] = oh->win_mtime[1]; -#else - in->yst_uid = oh->yst_uid; - in->yst_gid = oh->yst_gid; - in->yst_atime = oh->yst_atime; - in->yst_mtime = oh->yst_mtime; - in->yst_ctime = oh->yst_ctime; - in->yst_rdev = oh->yst_rdev; -#endif - in->hdrChunk = chunk; - in->serial = tags.serialNumber; - - yaffs_SetObjectNameFromOH(in, oh); - in->dirty = 0; - - /* directory stuff... - * hook up to parent - */ - - parent = - yaffs_FindOrCreateObjectByNumber - (dev, oh->parentObjectId, - YAFFS_OBJECT_TYPE_DIRECTORY); - if (!parent) - alloc_failed = 1; - if (parent && parent->variantType == - YAFFS_OBJECT_TYPE_UNKNOWN) { - /* Set up as a directory */ - parent->variantType = - YAFFS_OBJECT_TYPE_DIRECTORY; - YINIT_LIST_HEAD(&parent->variant. - directoryVariant. - children); - } else if (!parent || parent->variantType != - YAFFS_OBJECT_TYPE_DIRECTORY) { - /* Hoosterman, another problem.... - * We're trying to use a non-directory as a directory - */ - - T(YAFFS_TRACE_ERROR, - (TSTR - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." - TENDSTR))); - parent = dev->lostNFoundDir; - } - - yaffs_AddObjectToDirectory(parent, in); - - if (0 && (parent == dev->deletedDir || - parent == dev->unlinkedDir)) { - in->deleted = 1; /* If it is unlinked at start up then it wants deleting */ - dev->nDeletedFiles++; - } - /* Note re hardlinks. - * 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. - */ - - switch (in->variantType) { - case YAFFS_OBJECT_TYPE_UNKNOWN: - /* Todo got a problem */ - break; - case YAFFS_OBJECT_TYPE_FILE: - if (dev->param.useHeaderFileSize) - - in->variant.fileVariant. - fileSize = - oh->fileSize; - - break; - case YAFFS_OBJECT_TYPE_HARDLINK: - in->variant.hardLinkVariant. - 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: - in->variant.symLinkVariant.alias = - yaffs_CloneString(oh->alias); - if (!in->variant.symLinkVariant.alias) - alloc_failed = 1; - break; - } - - } - } - } - - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { - /* If we got this far while scanning, then the block is fully allocated.*/ - state = YAFFS_BLOCK_STATE_FULL; - } - - if (state == YAFFS_BLOCK_STATE_ALLOCATING) { - /* If the block was partially allocated then treat it as fully allocated.*/ - state = YAFFS_BLOCK_STATE_FULL; - dev->allocationBlock = -1; - } - - bi->blockState = state; - - /* Now let's see if it was dirty */ - if (bi->pagesInUse == 0 && - !bi->hasShrinkHeader && - bi->blockState == YAFFS_BLOCK_STATE_FULL) { - yaffs_BlockBecameDirty(dev, blk); - } - - } - - - /* 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 - * hardlinks. - */ - - yaffs_HardlinkFixup(dev, hardList); - - /* Fix up any shadowed objects */ - { - 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_DeleteObject(obj); - - obj = yaffs_FindObjectByNumber(dev, fixer->objectId); - - if (obj) - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL); - - YFREE(fixer); - } - } - - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); - - if (alloc_failed) - return YAFFS_FAIL; - - T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_Scan ends" TENDSTR))); - - - return YAFFS_OK; -} - diff --git a/fs/yaffs2/yaffs_yaffs1.h b/fs/yaffs2/yaffs_yaffs1.h deleted file mode 100644 index 9769eed3..00000000 --- a/fs/yaffs2/yaffs_yaffs1.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * 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_YAFFS1_H__ -#define __YAFFS_YAFFS1_H__ - -#include "yaffs_guts.h" -int yaffs1_Scan(yaffs_Device *dev); - -#endif diff --git a/fs/yaffs2/yaffs_yaffs2.c b/fs/yaffs2/yaffs_yaffs2.c deleted file mode 100644 index e13dd41c..00000000 --- a/fs/yaffs2/yaffs_yaffs2.c +++ /dev/null @@ -1,1540 +0,0 @@ -/* - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - - -#include "yaffs_guts.h" -#include "yaffs_trace.h" -#include "yaffs_yaffs2.h" -#include "yaffs_checkptrw.h" -#include "yaffs_bitmap.h" -#include "yaffs_qsort.h" -#include "yaffs_nand.h" -#include "yaffs_getblockinfo.h" -#include "yaffs_verify.h" - -/* - * Checkpoints are really no benefit on very small partitions. - * - * To save space on small partitions don't bother with checkpoints unless - * the partition is at least this big. - */ -#define YAFFS_CHECKPOINT_MIN_BLOCKS 60 - -#define YAFFS_SMALL_HOLE_THRESHOLD 4 - - -/* - * Oldest Dirty Sequence Number handling. - */ - -/* yaffs2_CalcOldestDirtySequence() - * yaffs2_FindOldestDirtySequence() - * Calculate the oldest dirty sequence number if we don't know it. - */ -void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev) -{ - int i; - unsigned seq; - unsigned blockNo = 0; - yaffs_BlockInfo *b; - - if(!dev->param.isYaffs2) - return; - - /* Find the oldest dirty sequence number. */ - seq = dev->sequenceNumber + 1; - b = dev->blockInfo; - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { - if (b->blockState == YAFFS_BLOCK_STATE_FULL && - (b->pagesInUse - b->softDeletions) < dev->param.nChunksPerBlock && - b->sequenceNumber < seq) { - seq = b->sequenceNumber; - blockNo = i; - } - b++; - } - - if(blockNo){ - dev->oldestDirtySequence = seq; - dev->oldestDirtyBlock = blockNo; - } - -} - - -void yaffs2_FindOldestDirtySequence(yaffs_Device *dev) -{ - if(!dev->param.isYaffs2) - return; - - if(!dev->oldestDirtySequence) - yaffs2_CalcOldestDirtySequence(dev); -} - -/* - * yaffs_ClearOldestDirtySequence() - * Called when a block is erased or marked bad. (ie. when its sequenceNumber - * becomes invalid). If the value matches the oldest then we clear - * dev->oldestDirtySequence to force its recomputation. - */ -void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi) -{ - - if(!dev->param.isYaffs2) - return; - - if(!bi || bi->sequenceNumber == dev->oldestDirtySequence){ - dev->oldestDirtySequence = 0; - dev->oldestDirtyBlock = 0; - } -} - -/* - * yaffs2_UpdateOldestDirtySequence() - * Update the oldest dirty sequence number whenever we dirty a block. - * Only do this if the oldestDirtySequence is actually being tracked. - */ -void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi) -{ - if(!dev->param.isYaffs2) - return; - - if(dev->oldestDirtySequence){ - if(dev->oldestDirtySequence > bi->sequenceNumber){ - dev->oldestDirtySequence = bi->sequenceNumber; - dev->oldestDirtyBlock = blockNo; - } - } -} - -int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev, - yaffs_BlockInfo *bi) -{ - - if (!dev->param.isYaffs2) - return 1; /* disqualification only applies to yaffs2. */ - - if (!bi->hasShrinkHeader) - return 1; /* can gc */ - - yaffs2_FindOldestDirtySequence(dev); - - /* Can't do gc of this block if there are any blocks older than this one that have - * discarded pages. - */ - return (bi->sequenceNumber <= dev->oldestDirtySequence); -} - -/* - * yaffs2_FindRefreshBlock() - * periodically finds the oldest full block by sequence number for refreshing. - * Only for yaffs2. - */ -__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev) -{ - __u32 b ; - - __u32 oldest = 0; - __u32 oldestSequence = 0; - - yaffs_BlockInfo *bi; - - if(!dev->param.isYaffs2) - return oldest; - - /* - * If refresh period < 10 then refreshing is disabled. - */ - if(dev->param.refreshPeriod < 10) - return oldest; - - /* - * Fix broken values. - */ - if(dev->refreshSkip > dev->param.refreshPeriod) - dev->refreshSkip = dev->param.refreshPeriod; - - if(dev->refreshSkip > 0) - return oldest; - - /* - * Refresh skip is now zero. - * We'll do a refresh this time around.... - * Update the refresh skip and find the oldest block. - */ - dev->refreshSkip = dev->param.refreshPeriod; - dev->refreshCount++; - bi = dev->blockInfo; - for (b = dev->internalStartBlock; b <=dev->internalEndBlock; b++){ - - if (bi->blockState == YAFFS_BLOCK_STATE_FULL){ - - if(oldest < 1 || - bi->sequenceNumber < oldestSequence){ - oldest = b; - oldestSequence = bi->sequenceNumber; - } - } - bi++; - } - - if (oldest > 0) { - T(YAFFS_TRACE_GC, - (TSTR("GC refresh count %d selected block %d with sequenceNumber %d" TENDSTR), - dev->refreshCount, oldest, oldestSequence)); - } - - return oldest; -} - -int yaffs2_CheckpointRequired(yaffs_Device *dev) -{ - int nblocks; - - if(!dev->param.isYaffs2) - return 0; - - nblocks = dev->internalEndBlock - dev->internalStartBlock + 1 ; - - return !dev->param.skipCheckpointWrite && - !dev->readOnly && - (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS); -} - -int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev) -{ - int retval; - - if(!dev->param.isYaffs2) - return 0; - - if (!dev->nCheckpointBlocksRequired && - yaffs2_CheckpointRequired(dev)){ - /* Not a valid value so recalculate */ - int nBytes = 0; - int nBlocks; - int devBlocks = (dev->param.endBlock - dev->param.startBlock + 1); - - nBytes += sizeof(yaffs_CheckpointValidity); - nBytes += sizeof(yaffs_CheckpointDevice); - nBytes += devBlocks * sizeof(yaffs_BlockInfo); - nBytes += devBlocks * dev->chunkBitmapStride; - nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjects); - nBytes += (dev->tnodeSize + sizeof(__u32)) * (dev->nTnodes); - 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->param.nChunksPerBlock)) + 3; - - dev->nCheckpointBlocksRequired = nBlocks; - } - - retval = dev->nCheckpointBlocksRequired - dev->blocksInCheckpoint; - if(retval < 0) - retval = 0; - return retval; -} - -/*--------------------- Checkpointing --------------------*/ - - -static int yaffs2_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 (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ? - 1 : 0; -} - -static int yaffs2_ReadCheckpointValidityMarker(yaffs_Device *dev, int head) -{ - yaffs_CheckpointValidity cp; - int ok; - - ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); - - if (ok) - ok = (cp.structType == sizeof(cp)) && - (cp.magic == YAFFS_MAGIC) && - (cp.version == YAFFS_CHECKPOINT_VERSION) && - (cp.head == ((head) ? 1 : 0)); - return ok ? 1 : 0; -} - -static void yaffs2_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; - -} - -static void yaffs2_CheckpointDeviceToDevice(yaffs_Device *dev, - yaffs_CheckpointDevice *cp) -{ - dev->nErasedBlocks = cp->nErasedBlocks; - dev->allocationBlock = cp->allocationBlock; - dev->allocationPage = cp->allocationPage; - dev->nFreeChunks = cp->nFreeChunks; - - dev->nDeletedFiles = cp->nDeletedFiles; - dev->nUnlinkedFiles = cp->nUnlinkedFiles; - dev->nBackgroundDeletions = cp->nBackgroundDeletions; - dev->sequenceNumber = cp->sequenceNumber; -} - - -static int yaffs2_WriteCheckpointDevice(yaffs_Device *dev) -{ - yaffs_CheckpointDevice cp; - __u32 nBytes; - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); - - int ok; - - /* Write device runtime values*/ - yaffs2_DeviceToCheckpointDevice(&cp, dev); - cp.structType = sizeof(cp); - - ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); - - /* Write block info */ - if (ok) { - nBytes = nBlocks * sizeof(yaffs_BlockInfo); - ok = (yaffs2_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes); - } - - /* Write chunk bits */ - if (ok) { - nBytes = nBlocks * dev->chunkBitmapStride; - ok = (yaffs2_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes); - } - return ok ? 1 : 0; - -} - -static int yaffs2_ReadCheckpointDevice(yaffs_Device *dev) -{ - yaffs_CheckpointDevice cp; - __u32 nBytes; - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); - - int ok; - - ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); - if (!ok) - return 0; - - if (cp.structType != sizeof(cp)) - return 0; - - - yaffs2_CheckpointDeviceToDevice(dev, &cp); - - nBytes = nBlocks * sizeof(yaffs_BlockInfo); - - ok = (yaffs2_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes); - - if (!ok) - return 0; - nBytes = nBlocks * dev->chunkBitmapStride; - - ok = (yaffs2_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes); - - return ok ? 1 : 0; -} - -static void yaffs2_ObjectToCheckpointObject(yaffs_CheckpointObject *cp, - yaffs_Object *obj) -{ - - cp->objectId = obj->objectId; - cp->parentId = (obj->parent) ? obj->parent->objectId : 0; - cp->hdrChunk = obj->hdrChunk; - cp->variantType = obj->variantType; - cp->deleted = obj->deleted; - cp->softDeleted = obj->softDeleted; - cp->unlinked = obj->unlinked; - cp->fake = obj->fake; - cp->renameAllowed = obj->renameAllowed; - 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) - cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId; -} - -static int yaffs2_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp) -{ - - yaffs_Object *parent; - - if (obj->variantType != cp->variantType) { - T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d " - TCONT("chunk %d does not match existing object type %d") - TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk, - obj->variantType)); - return 0; - } - - obj->objectId = cp->objectId; - - if (cp->parentId) - parent = yaffs_FindOrCreateObjectByNumber( - obj->myDev, - cp->parentId, - YAFFS_OBJECT_TYPE_DIRECTORY); - else - parent = NULL; - - if (parent) { - if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { - T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d" - TCONT(" chunk %d Parent type, %d, not directory") - TENDSTR), - cp->objectId, cp->parentId, cp->variantType, - cp->hdrChunk, parent->variantType)); - return 0; - } - yaffs_AddObjectToDirectory(parent, obj); - } - - obj->hdrChunk = cp->hdrChunk; - obj->variantType = cp->variantType; - obj->deleted = cp->deleted; - obj->softDeleted = cp->softDeleted; - obj->unlinked = cp->unlinked; - obj->fake = cp->fake; - obj->renameAllowed = cp->renameAllowed; - 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->hdrChunk > 0) - obj->lazyLoaded = 1; - return 1; -} - - - -static int yaffs2_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn, - __u32 level, int chunkOffset) -{ - int i; - yaffs_Device *dev = in->myDev; - int ok = 1; - - if (tn) { - if (level > 0) { - - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { - if (tn->internal[i]) { - ok = yaffs2_CheckpointTnodeWorker(in, - tn->internal[i], - level - 1, - (chunkOffset<tnodeSize) == dev->tnodeSize); - } - } - - return ok; - -} - -static int yaffs2_WriteCheckpointTnodes(yaffs_Object *obj) -{ - __u32 endMarker = ~0; - int ok = 1; - - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) { - ok = yaffs2_CheckpointTnodeWorker(obj, - obj->variant.fileVariant.top, - obj->variant.fileVariant.topLevel, - 0); - if (ok) - ok = (yaffs2_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) == - sizeof(endMarker)); - } - - return ok ? 1 : 0; -} - -static int yaffs2_ReadCheckpointTnodes(yaffs_Object *obj) -{ - __u32 baseChunk; - int ok = 1; - yaffs_Device *dev = obj->myDev; - yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant; - yaffs_Tnode *tn; - int nread = 0; - - ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk)); - - while (ok && (~baseChunk)) { - nread++; - /* Read level 0 tnode */ - - - tn = yaffs_GetTnode(dev); - if (tn){ - ok = (yaffs2_CheckpointRead(dev, tn, dev->tnodeSize) == dev->tnodeSize); - } else - ok = 0; - - if (tn && ok) - ok = yaffs_AddOrFindLevel0Tnode(dev, - fileStructPtr, - baseChunk, - tn) ? 1 : 0; - - if (ok) - ok = (yaffs2_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; -} - - -static int yaffs2_WriteCheckpointObjects(yaffs_Device *dev) -{ - yaffs_Object *obj; - yaffs_CheckpointObject cp; - int i; - int ok = 1; - struct ylist_head *lh; - - - /* Iterate through the objects in each hash entry, - * dumping them to the checkpointing stream. - */ - - 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) { - yaffs2_ObjectToCheckpointObject(&cp, obj); - cp.structType = sizeof(cp); - - T(YAFFS_TRACE_CHECKPOINT, ( - TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR), - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, obj)); - - ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); - - if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE) - ok = yaffs2_WriteCheckpointTnodes(obj); - } - } - } - } - - /* Dump end of list */ - memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject)); - cp.structType = sizeof(cp); - - if (ok) - ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); - - return ok ? 1 : 0; -} - -static int yaffs2_ReadCheckpointObjects(yaffs_Device *dev) -{ - yaffs_Object *obj; - yaffs_CheckpointObject cp; - int ok = 1; - int done = 0; - yaffs_Object *hardList = NULL; - - while (ok && !done) { - ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); - if (cp.structType != sizeof(cp)) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR), - cp.structType, (int)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.hdrChunk)); - - if (ok && cp.objectId == ~0) - done = 1; - else if (ok) { - obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType); - if (obj) { - ok = yaffs2_CheckpointObjectToObject(obj, &cp); - if (!ok) - break; - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) { - ok = yaffs2_ReadCheckpointTnodes(obj); - } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { - obj->hardLinks.next = - (struct ylist_head *) hardList; - hardList = obj; - } - } else - ok = 0; - } - } - - if (ok) - yaffs_HardlinkFixup(dev, hardList); - - return ok ? 1 : 0; -} - -static int yaffs2_WriteCheckpointSum(yaffs_Device *dev) -{ - __u32 checkpointSum; - int ok; - - yaffs2_GetCheckpointSum(dev, &checkpointSum); - - ok = (yaffs2_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum)); - - if (!ok) - return 0; - - return 1; -} - -static int yaffs2_ReadCheckpointSum(yaffs_Device *dev) -{ - __u32 checkpointSum0; - __u32 checkpointSum1; - int ok; - - yaffs2_GetCheckpointSum(dev, &checkpointSum0); - - ok = (yaffs2_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1)); - - if (!ok) - return 0; - - if (checkpointSum0 != checkpointSum1) - return 0; - - return 1; -} - - -static int yaffs2_WriteCheckpointData(yaffs_Device *dev) -{ - int ok = 1; - - if (!yaffs2_CheckpointRequired(dev)) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR))); - ok = 0; - } - - if (ok) - ok = yaffs2_CheckpointOpen(dev, 1); - - if (ok) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR))); - ok = yaffs2_WriteCheckpointValidityMarker(dev, 1); - } - if (ok) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR))); - ok = yaffs2_WriteCheckpointDevice(dev); - } - if (ok) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR))); - ok = yaffs2_WriteCheckpointObjects(dev); - } - if (ok) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR))); - ok = yaffs2_WriteCheckpointValidityMarker(dev, 0); - } - - if (ok) - ok = yaffs2_WriteCheckpointSum(dev); - - if (!yaffs2_CheckpointClose(dev)) - ok = 0; - - if (ok) - dev->isCheckpointed = 1; - else - dev->isCheckpointed = 0; - - return dev->isCheckpointed; -} - -static int yaffs2_ReadCheckpointData(yaffs_Device *dev) -{ - int ok = 1; - - if(!dev->param.isYaffs2) - ok = 0; - - if (ok && dev->param.skipCheckpointRead) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR))); - ok = 0; - } - - if (ok) - ok = yaffs2_CheckpointOpen(dev, 0); /* open for read */ - - if (ok) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR))); - ok = yaffs2_ReadCheckpointValidityMarker(dev, 1); - } - if (ok) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR))); - ok = yaffs2_ReadCheckpointDevice(dev); - } - if (ok) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR))); - ok = yaffs2_ReadCheckpointObjects(dev); - } - if (ok) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR))); - ok = yaffs2_ReadCheckpointValidityMarker(dev, 0); - } - - if (ok) { - ok = yaffs2_ReadCheckpointSum(dev); - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok)); - } - - if (!yaffs2_CheckpointClose(dev)) - ok = 0; - - if (ok) - dev->isCheckpointed = 1; - else - dev->isCheckpointed = 0; - - return ok ? 1 : 0; - -} - -void yaffs2_InvalidateCheckpoint(yaffs_Device *dev) -{ - if (dev->isCheckpointed || - dev->blocksInCheckpoint > 0) { - dev->isCheckpointed = 0; - yaffs2_CheckpointInvalidateStream(dev); - } - if (dev->param.markSuperBlockDirty) - dev->param.markSuperBlockDirty(dev); -} - - -int yaffs_CheckpointSave(yaffs_Device *dev) -{ - - T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); - - yaffs_VerifyObjects(dev); - yaffs_VerifyBlocks(dev); - yaffs_VerifyFreeChunks(dev); - - if (!dev->isCheckpointed) { - yaffs2_InvalidateCheckpoint(dev); - yaffs2_WriteCheckpointData(dev); - } - - T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); - - return dev->isCheckpointed; -} - -int yaffs2_CheckpointRestore(yaffs_Device *dev) -{ - int retval; - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); - - retval = yaffs2_ReadCheckpointData(dev); - - if (dev->isCheckpointed) { - yaffs_VerifyObjects(dev); - yaffs_VerifyBlocks(dev); - yaffs_VerifyFreeChunks(dev); - } - - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); - - return retval; -} - -int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize) -{ - /* if newsSize > oldFileSize. - * We're going to be writing a hole. - * If the hole is small then write zeros otherwise write a start of hole marker. - */ - - - loff_t oldFileSize; - int increase; - int smallHole ; - int result = YAFFS_OK; - yaffs_Device *dev = NULL; - - __u8 *localBuffer = NULL; - - int smallIncreaseOk = 0; - - if(!obj) - return YAFFS_FAIL; - - if(obj->variantType != YAFFS_OBJECT_TYPE_FILE) - return YAFFS_FAIL; - - dev = obj->myDev; - - /* Bail out if not yaffs2 mode */ - if(!dev->param.isYaffs2) - return YAFFS_OK; - - oldFileSize = obj->variant.fileVariant.fileSize; - - if (newSize <= oldFileSize) - return YAFFS_OK; - - increase = newSize - oldFileSize; - - if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->nDataBytesPerChunk && - yaffs_CheckSpaceForAllocation(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1)) - smallHole = 1; - else - smallHole = 0; - - if(smallHole) - localBuffer= yaffs_GetTempBuffer(dev, __LINE__); - - if(localBuffer){ - /* fill hole with zero bytes */ - int pos = oldFileSize; - int thisWrite; - int written; - memset(localBuffer,0,dev->nDataBytesPerChunk); - smallIncreaseOk = 1; - - while(increase > 0 && smallIncreaseOk){ - thisWrite = increase; - if(thisWrite > dev->nDataBytesPerChunk) - thisWrite = dev->nDataBytesPerChunk; - written = yaffs_DoWriteDataToFile(obj,localBuffer,pos,thisWrite,0); - if(written == thisWrite){ - pos += thisWrite; - increase -= thisWrite; - } else - smallIncreaseOk = 0; - } - - yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__); - - /* If we were out of space then reverse any chunks we've added */ - if(!smallIncreaseOk) - yaffs_ResizeDown(obj, oldFileSize); - } - - if (!smallIncreaseOk && - obj->parent && - obj->parent->objectId != YAFFS_OBJECTID_UNLINKED && - obj->parent->objectId != YAFFS_OBJECTID_DELETED){ - /* Write a hole start header with the old file size */ - yaffs_UpdateObjectHeader(obj, NULL, 0, 1, 0, NULL); - } - - return result; - -} - - -typedef struct { - int seq; - int block; -} yaffs_BlockIndex; - - -static int yaffs2_ybicmp(const void *a, const void *b) -{ - register int aseq = ((yaffs_BlockIndex *)a)->seq; - register int bseq = ((yaffs_BlockIndex *)b)->seq; - register int ablock = ((yaffs_BlockIndex *)a)->block; - register int bblock = ((yaffs_BlockIndex *)b)->block; - if (aseq == bseq) - return ablock - bblock; - else - return aseq - bseq; -} - -int yaffs2_ScanBackwards(yaffs_Device *dev) -{ - yaffs_ExtendedTags tags; - int blk; - int blockIterator; - int startIterator; - int endIterator; - int nBlocksToScan = 0; - - int chunk; - int result; - int c; - int deleted; - yaffs_BlockState state; - yaffs_Object *hardList = NULL; - yaffs_BlockInfo *bi; - __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; - - T(YAFFS_TRACE_SCAN, - (TSTR - ("yaffs2_ScanBackwards starts intstartblk %d intendblk %d..." - TENDSTR), dev->internalStartBlock, dev->internalEndBlock)); - - - 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("yaffs2_ScanBackwards() 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 */ - bi = dev->blockInfo; - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { - yaffs_ClearChunkBits(dev, blk); - bi->pagesInUse = 0; - bi->softDeletions = 0; - - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); - - bi->blockState = state; - bi->sequenceNumber = sequenceNumber; - - if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) - bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT; - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK) - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD; - - 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)); - } else if (state == YAFFS_BLOCK_STATE_EMPTY) { - T(YAFFS_TRACE_SCAN_DEBUG, - (TSTR("Block empty " TENDSTR))); - dev->nErasedBlocks++; - dev->nFreeChunks += dev->param.nChunksPerBlock; - } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { - - /* Determine the highest sequence number */ - if (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 { - /* TODO: Nasty sequence number! */ - T(YAFFS_TRACE_SCAN, - (TSTR - ("Block scanning block %d has bad sequence number %d" - TENDSTR), blk, sequenceNumber)); - - } - } - bi++; - } - - T(YAFFS_TRACE_SCAN, - (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan)); - - - - YYIELD(); - - /* Sort the blocks by sequence number*/ - yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp); - - YYIELD(); - - T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR))); - - /* Now scan the blocks looking at the data. */ - startIterator = 0; - endIterator = nBlocksToScan - 1; - T(YAFFS_TRACE_SCAN_DEBUG, - (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); - - /* For each block.... backwards */ - for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator; - blockIterator--) { - /* Cooperative multitasking! This loop can run for so - long that watchdog timers expire. */ - YYIELD(); - - /* get the block to scan in the correct order */ - 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->param.nChunksPerBlock - 1; - !alloc_failed && c >= 0 && - (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || - state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { - /* Scan backwards... - * Read the tags and decide what to do - */ - - chunk = blk * dev->param.nChunksPerBlock + c; - - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, - &tags); - - /* Let's have a good look at this chunk... */ - - if (!tags.chunkUsed) { - /* An unassigned chunk in the block. - * If there are used chunks after this one, then - * 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 - * 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; - dev->nErasedBlocks++; - } else { - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || - 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" - TENDSTR), blk, c)); - - state = YAFFS_BLOCK_STATE_ALLOCATING; - dev->allocationBlock = blk; - dev->allocationPage = c; - dev->allocationBlockFinder = blk; - } else { - /* This is a partially written block that is not - * the current allocation block. - */ - - T(YAFFS_TRACE_SCAN, - (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)); - - dev->nFreeChunks++; - - } else if (tags.objectId > YAFFS_MAX_OBJECT_ID || - tags.chunkId > YAFFS_MAX_CHUNK_ID || - (tags.chunkId > 0 && tags.byteCount > dev->nDataBytesPerChunk) || - tags.sequenceNumber != bi->sequenceNumber ) { - T(YAFFS_TRACE_SCAN, - (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunkId = %d, byteCount = %d, ignored"TENDSTR), - blk, c,tags.objectId, tags.chunkId, tags.byteCount)); - - 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; - - - yaffs_SetChunkBit(dev, blk, c); - bi->pagesInUse++; - - in = yaffs_FindOrCreateObjectByNumber(dev, - tags. - objectId, - YAFFS_OBJECT_TYPE_FILE); - if (!in) { - /* Out of memory */ - alloc_failed = 1; - } - - if (in && - in->variantType == YAFFS_OBJECT_TYPE_FILE - && chunkBase < in->variant.fileVariant.shrinkSize) { - /* This has not been invalidated by a resize */ - if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, -1)) { - alloc_failed = 1; - } - - /* 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 = chunkBase + tags.byteCount; - - if (!in->valid && /* have not got an object header yet */ - in->variant.fileVariant.scannedFileSize < endpos) { - in->variant.fileVariant.scannedFileSize = endpos; - in->variant.fileVariant.fileSize = endpos; - } - - } else if (in) { - /* This chunk has been invalidated by a resize, or a past file deletion - * so delete the chunk*/ - yaffs_DeleteChunk(dev, chunk, 1, __LINE__); - - } - } else { - /* chunkId == 0, so it is an ObjectHeader. - * Thus, we read in the object header and make the object - */ - foundChunksInBlock = 1; - - yaffs_SetChunkBit(dev, blk, c); - bi->pagesInUse++; - - oh = NULL; - in = NULL; - - if (tags.extraHeaderInfoAvailable) { - in = yaffs_FindOrCreateObjectByNumber(dev, - tags.objectId, - tags.extraObjectType); - if (!in) - alloc_failed = 1; - } - - if (!in || - (!in->valid && dev->param.disableLazyLoad) || - tags.extraShadows || - (!in->valid && - (tags.objectId == YAFFS_OBJECTID_ROOT || - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) { - - /* 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 - * living with invalid data until needed. - */ - - result = yaffs_ReadChunkWithTagsFromNAND(dev, - chunk, - chunkData, - NULL); - - oh = (yaffs_ObjectHeader *) chunkData; - - if (dev->param.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); - if (!in) - alloc_failed = 1; - } - - } - - if (!in) { - /* 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" - TENDSTR), tags.objectId, chunk)); - continue; - } - - if (in->valid) { - /* We have already filled this one. - * 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 && - oh->type == YAFFS_OBJECT_TYPE_FILE) || - (tags.extraHeaderInfoAvailable && - tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) { - __u32 thisSize = - (oh) ? oh->fileSize : tags. - extraFileLength; - __u32 parentObjectId = - (oh) ? oh-> - parentObjectId : tags. - extraParentObjectId; - - - isShrink = - (oh) ? oh->isShrink : tags. - extraIsShrinkHeader; - - /* If it is deleted (unlinked at start also means deleted) - * we treat the file size as being zeroed at this point. - */ - if (parentObjectId == - YAFFS_OBJECTID_DELETED - || parentObjectId == - YAFFS_OBJECTID_UNLINKED) { - thisSize = 0; - isShrink = 1; - } - - if (isShrink && in->variant.fileVariant.shrinkSize > thisSize) - in->variant.fileVariant.shrinkSize = thisSize; - - if (isShrink) - bi->hasShrinkHeader = 1; - - } - /* Use existing - destroy this one. */ - yaffs_DeleteChunk(dev, chunk, 1, __LINE__); - - } - - if (!in->valid && in->variantType != - (oh ? oh->type : tags.extraObjectType)) - T(YAFFS_TRACE_ERROR, ( - TSTR("yaffs tragedy: Bad object type, " - TCONT("%d != %d, for object %d at chunk ") - TCONT("%d during scan") - TENDSTR), oh ? - oh->type : tags.extraObjectType, - in->variantType, tags.objectId, - chunk)); - - if (!in->valid && - (tags.objectId == YAFFS_OBJECTID_ROOT || - tags.objectId == - YAFFS_OBJECTID_LOSTNFOUND)) { - /* We only load some info, don't fiddle with directory structure */ - in->valid = 1; - - if (oh) { - - in->yst_mode = oh->yst_mode; -#ifdef CONFIG_YAFFS_WINCE - in->win_atime[0] = oh->win_atime[0]; - in->win_ctime[0] = oh->win_ctime[0]; - in->win_mtime[0] = oh->win_mtime[0]; - in->win_atime[1] = oh->win_atime[1]; - in->win_ctime[1] = oh->win_ctime[1]; - in->win_mtime[1] = oh->win_mtime[1]; -#else - in->yst_uid = oh->yst_uid; - in->yst_gid = oh->yst_gid; - in->yst_atime = oh->yst_atime; - in->yst_mtime = oh->yst_mtime; - in->yst_ctime = oh->yst_ctime; - in->yst_rdev = oh->yst_rdev; - - in->lazyLoaded = 0; - -#endif - } else - in->lazyLoaded = 1; - - in->hdrChunk = chunk; - - } else if (!in->valid) { - /* we need to load this info */ - - in->valid = 1; - in->hdrChunk = chunk; - - if (oh) { - in->variantType = oh->type; - - in->yst_mode = oh->yst_mode; -#ifdef CONFIG_YAFFS_WINCE - in->win_atime[0] = oh->win_atime[0]; - in->win_ctime[0] = oh->win_ctime[0]; - in->win_mtime[0] = oh->win_mtime[0]; - in->win_atime[1] = oh->win_atime[1]; - in->win_ctime[1] = oh->win_ctime[1]; - in->win_mtime[1] = oh->win_mtime[1]; -#else - in->yst_uid = oh->yst_uid; - in->yst_gid = oh->yst_gid; - in->yst_atime = oh->yst_atime; - in->yst_mtime = oh->yst_mtime; - in->yst_ctime = oh->yst_ctime; - in->yst_rdev = oh->yst_rdev; -#endif - - if (oh->shadowsObject > 0) - yaffs_HandleShadowedObject(dev, - oh-> - shadowsObject, - 1); - - - - yaffs_SetObjectNameFromOH(in, oh); - parent = - yaffs_FindOrCreateObjectByNumber - (dev, oh->parentObjectId, - YAFFS_OBJECT_TYPE_DIRECTORY); - - fileSize = oh->fileSize; - isShrink = oh->isShrink; - equivalentObjectId = oh->equivalentObjectId; - - } else { - in->variantType = tags.extraObjectType; - parent = - yaffs_FindOrCreateObjectByNumber - (dev, tags.extraParentObjectId, - YAFFS_OBJECT_TYPE_DIRECTORY); - fileSize = tags.extraFileLength; - isShrink = tags.extraIsShrinkHeader; - equivalentObjectId = tags.extraEquivalentObjectId; - in->lazyLoaded = 1; - - } - in->dirty = 0; - - if (!parent) - alloc_failed = 1; - - /* directory stuff... - * hook up to parent - */ - - if (parent && parent->variantType == - YAFFS_OBJECT_TYPE_UNKNOWN) { - /* Set up as a directory */ - parent->variantType = - YAFFS_OBJECT_TYPE_DIRECTORY; - YINIT_LIST_HEAD(&parent->variant. - directoryVariant. - children); - } else if (!parent || parent->variantType != - YAFFS_OBJECT_TYPE_DIRECTORY) { - /* Hoosterman, another problem.... - * We're trying to use a non-directory as a directory - */ - - T(YAFFS_TRACE_ERROR, - (TSTR - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." - TENDSTR))); - parent = dev->lostNFoundDir; - } - - yaffs_AddObjectToDirectory(parent, in); - - itsUnlinked = (parent == dev->deletedDir) || - (parent == dev->unlinkedDir); - - if (isShrink) { - /* Mark the block as having a shrinkHeader */ - bi->hasShrinkHeader = 1; - } - - /* Note re hardlinks. - * 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. - */ - - switch (in->variantType) { - case YAFFS_OBJECT_TYPE_UNKNOWN: - /* Todo got a problem */ - break; - case YAFFS_OBJECT_TYPE_FILE: - - if (in->variant.fileVariant. - 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 - * than its current data extents. - */ - in->variant.fileVariant.fileSize = fileSize; - in->variant.fileVariant.scannedFileSize = fileSize; - } - - if (in->variant.fileVariant.shrinkSize > fileSize) - in->variant.fileVariant.shrinkSize = fileSize; - - - break; - case YAFFS_OBJECT_TYPE_HARDLINK: - if (!itsUnlinked) { - in->variant.hardLinkVariant.equivalentObjectId = - 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: - if (oh) { - in->variant.symLinkVariant.alias = - yaffs_CloneString(oh->alias); - if (!in->variant.symLinkVariant.alias) - alloc_failed = 1; - } - break; - } - - } - - } - - } /* End of scanning for each chunk */ - - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { - /* If we got this far while scanning, then the block is fully allocated. */ - state = YAFFS_BLOCK_STATE_FULL; - } - - - bi->blockState = state; - - /* Now let's see if it was dirty */ - if (bi->pagesInUse == 0 && - !bi->hasShrinkHeader && - bi->blockState == YAFFS_BLOCK_STATE_FULL) { - yaffs_BlockBecameDirty(dev, blk); - } - - } - - yaffs_SkipRestOfBlock(dev); - - 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 - * hardlinks. - */ - yaffs_HardlinkFixup(dev, hardList); - - - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); - - if (alloc_failed) - return YAFFS_FAIL; - - T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_ScanBackwards ends" TENDSTR))); - - return YAFFS_OK; -} diff --git a/fs/yaffs2/yaffs_yaffs2.h b/fs/yaffs2/yaffs_yaffs2.h deleted file mode 100644 index 67dc8f15..00000000 --- a/fs/yaffs2/yaffs_yaffs2.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. - * - * Copyright (C) 2002-2010 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning - * - * 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. - */ - -#ifndef __YAFFS_YAFFS2_H__ -#define __YAFFS_YAFFS2_H__ - -#include "yaffs_guts.h" - -void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev); -void yaffs2_FindOldestDirtySequence(yaffs_Device *dev); -void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi); -void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi); -int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi); -__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev); -int yaffs2_CheckpointRequired(yaffs_Device *dev); -int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev); - - -void yaffs2_InvalidateCheckpoint(yaffs_Device *dev); -int yaffs2_CheckpointSave(yaffs_Device *dev); -int yaffs2_CheckpointRestore(yaffs_Device *dev); - -int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize); -int yaffs2_ScanBackwards(yaffs_Device *dev); - -#endif diff --git a/fs/yaffs2/yaffsinterface.h b/fs/yaffs2/yaffsinterface.h index ca36cfc4..810837a3 100644 --- a/fs/yaffs2/yaffsinterface.h +++ b/fs/yaffs2/yaffsinterface.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning diff --git a/fs/yaffs2/yportenv.h b/fs/yaffs2/yportenv.h index 83203c88..aff59411 100644 --- a/fs/yaffs2/yportenv.h +++ b/fs/yaffs2/yportenv.h @@ -1,7 +1,7 @@ /* * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002-2010 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -41,14 +41,12 @@ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) #include #endif - #include #include #include #include #include #include -#include #define YCHAR char #define YUCHAR unsigned char @@ -57,11 +55,11 @@ #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) -#define yaffs_strnlen(s,m) strnlen(s,m) +#define yaffs_strlen(s) strlen(s) #define yaffs_sprintf sprintf #define yaffs_toupper(a) toupper(a) -#define Y_INLINE __inline__ +#define Y_INLINE inline #define YAFFS_LOSTNFOUND_NAME "lost+found" #define YAFFS_LOSTNFOUND_PREFIX "obj" @@ -73,11 +71,11 @@ #define YFREE_ALT(x) vfree(x) #define YMALLOC_DMA(x) YMALLOC(x) +/* KR - added for use in scan so processes aren't blocked indefinitely. */ #define YYIELD() schedule() -#define Y_DUMP_STACK() dump_stack() -#define YAFFS_ROOT_MODE 0755 -#define YAFFS_LOSTNFOUND_MODE 0700 +#define YAFFS_ROOT_MODE 0666 +#define YAFFS_LOSTNFOUND_MODE 0666 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) #define Y_CURRENT_TIME CURRENT_TIME.tv_sec @@ -91,10 +89,15 @@ #define yaffs_strcmp(a, b) strcmp(a, b) #define TENDSTR "\n" -#define TSTR(x) KERN_DEBUG x +#define TSTR(x) KERN_WARNING x #define TCONT(x) x #define TOUT(p) printk p +#define yaffs_trace(mask, fmt, args...) \ + do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \ + printk(KERN_WARNING "yaffs: " fmt, ## args); \ + } while (0) + #define compile_time_assertion(assertion) \ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) @@ -113,6 +116,7 @@ #include "stdio.h" #include "string.h" +#include "devextras.h" #define YMALLOC(x) malloc(x) #define YFREE(x) free(x) @@ -125,7 +129,7 @@ #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_strnlen(s,m) strnlen(s,m) +#define yaffs_strlen(s) strlen(s) #define yaffs_sprintf sprintf #define yaffs_toupper(a) toupper(a) @@ -142,8 +146,8 @@ #define YAFFS_LOSTNFOUND_PREFIX "obj" /* #define YPRINTF(x) printf x */ -#define YAFFS_ROOT_MODE 0755 -#define YAFFS_LOSTNFOUND_MODE 0700 +#define YAFFS_ROOT_MODE 0666 +#define YAFFS_LOSTNFOUND_MODE 0666 #define yaffs_SumCompare(x, y) ((x) == (y)) #define yaffs_strcmp(a, b) strcmp(a, b) @@ -154,180 +158,46 @@ #endif -#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE) +/* see yaffs_fs.c */ +extern unsigned int yaffs_traceMask; +extern unsigned int yaffs_wr_attempts; -#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES +/* + * Tracing flags. + * The flags masked in YAFFS_TRACE_ALWAYS are always traced. + */ -#ifndef O_RDONLY -#define O_RDONLY 00 -#endif +#define YAFFS_TRACE_OS 0x00000002 +#define YAFFS_TRACE_ALLOCATE 0x00000004 +#define YAFFS_TRACE_SCAN 0x00000008 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 +#define YAFFS_TRACE_ERASE 0x00000020 +#define YAFFS_TRACE_GC 0x00000040 +#define YAFFS_TRACE_WRITE 0x00000080 +#define YAFFS_TRACE_TRACING 0x00000100 +#define YAFFS_TRACE_DELETION 0x00000200 +#define YAFFS_TRACE_BUFFERS 0x00000400 +#define YAFFS_TRACE_NANDACCESS 0x00000800 +#define YAFFS_TRACE_GC_DETAIL 0x00001000 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 +#define YAFFS_TRACE_MTD 0x00004000 +#define YAFFS_TRACE_CHECKPOINT 0x00008000 -#ifndef O_WRONLY -#define O_WRONLY 01 -#endif +#define YAFFS_TRACE_VERIFY 0x00010000 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000 +#define YAFFS_TRACE_VERIFY_ALL 0x000F0000 +#define YAFFS_TRACE_HTC_DEBUG 0x00100000 -#ifndef O_RDWR -#define O_RDWR 02 -#endif - -#ifndef O_CREAT -#define O_CREAT 0100 -#endif - -#ifndef O_EXCL -#define O_EXCL 0200 -#endif - -#ifndef O_TRUNC -#define O_TRUNC 01000 -#endif - -#ifndef O_APPEND -#define O_APPEND 02000 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifndef EBUSY -#define EBUSY 16 -#endif - -#ifndef ENODEV -#define ENODEV 19 -#endif - -#ifndef EINVAL -#define EINVAL 22 -#endif - -#ifndef EBADF -#define EBADF 9 -#endif - -#ifndef EACCES -#define EACCES 13 -#endif - -#ifndef EXDEV -#define EXDEV 18 -#endif - -#ifndef ENOENT -#define ENOENT 2 -#endif - -#ifndef ENOSPC -#define ENOSPC 28 -#endif - -#ifndef ERANGE -#define ERANGE 34 -#endif - -#ifndef ENODATA -#define ENODATA 61 -#endif - -#ifndef ENOTEMPTY -#define ENOTEMPTY 39 -#endif - -#ifndef ENAMETOOLONG -#define ENAMETOOLONG 36 -#endif - -#ifndef ENOMEM -#define ENOMEM 12 -#endif - -#ifndef EEXIST -#define EEXIST 17 -#endif - -#ifndef ENOTDIR -#define ENOTDIR 20 -#endif - -#ifndef EISDIR -#define EISDIR 21 -#endif +#define YAFFS_TRACE_ERROR 0x40000000 +#define YAFFS_TRACE_BUG 0x80000000 +#define YAFFS_TRACE_ALWAYS 0xF0000000 -// Mode flags - -#ifndef S_IFMT -#define S_IFMT 0170000 -#endif - -#ifndef S_IFLNK -#define S_IFLNK 0120000 -#endif - -#ifndef S_IFDIR -#define S_IFDIR 0040000 -#endif - -#ifndef S_IFREG -#define S_IFREG 0100000 -#endif - -#ifndef S_IREAD -#define S_IREAD 0000400 -#endif - -#ifndef S_IWRITE -#define S_IWRITE 0000200 -#endif - -#ifndef S_IEXEC -#define S_IEXEC 0000100 -#endif - -#ifndef XATTR_CREATE -#define XATTR_CREATE 1 -#endif - -#ifndef XATTR_REPLACE -#define XATTR_REPLACE 2 -#endif - -#ifndef R_OK -#define R_OK 4 -#define W_OK 2 -#define X_OK 1 -#define F_OK 0 -#endif - -#else -#include -#include -#include -#endif - -#endif - -#ifndef Y_DUMP_STACK -#define Y_DUMP_STACK() do { } while (0) -#endif +#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0) #ifndef YBUG -#define YBUG() do {\ - T(YAFFS_TRACE_BUG,\ - (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\ - __LINE__));\ - Y_DUMP_STACK();\ -} while (0) +#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0) #endif - #endif From e4b408efabf34884e12d0fc0dac465737088d9c8 Mon Sep 17 00:00:00 2001 From: rajkosto Date: Thu, 4 Nov 2010 19:36:01 +0100 Subject: [PATCH 2/2] silly htc, you shouldn't use dma_sync_single on dma mapped PAGES --- arch/arm/mm/dma-mapping.c | 6 +++++ drivers/mtd/devices/htcleo_nand.c | 42 ++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 4bacba58..2b2dbf81 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -544,6 +544,12 @@ void dma_cache_maint(const void *start, size_t size, int direction) void (*inner_op)(const void *, const void *); void (*outer_op)(unsigned long, unsigned long); + if (!virt_addr_valid(start) || !virt_addr_valid(start + size - 1)) + { + printk(KERN_ERR "%s: %08x not a valid virt address, PAGE_OFFSET=%08x, high_memory=%08x\n", + __func__, (uint32_t)start,(uint32_t)PAGE_OFFSET, (uint32_t)high_memory ); + } + BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(start + size - 1)); switch (direction) { diff --git a/drivers/mtd/devices/htcleo_nand.c b/drivers/mtd/devices/htcleo_nand.c index 07dc26c3..2140bcbc 100755 --- a/drivers/mtd/devices/htcleo_nand.c +++ b/drivers/mtd/devices/htcleo_nand.c @@ -497,6 +497,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_o unsigned page_oob_done; uint32_t oob_count=0; uint32_t oob_done_size=0; + uint32_t data_count=0; //number of bytes mapped into dma int readdata=0; int readoob=0; uint32_t readcmd; @@ -620,6 +621,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_o { /* memset(ops->datbuf, 0x55, ops->len); */ data_dma_addr_curr = data_dma_addr = msm_nand_dma_map(chip->dev, ops->datbuf, ops->len, DMA_FROM_DEVICE); + data_count = ops->len; //initially map whole buf to dma if (dma_mapping_error(chip->dev, data_dma_addr)) { pr_err("msm_nand_read_oob: failed to get dma addr for %p\n", ops->datbuf); @@ -821,11 +823,14 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_o if (readdata) { uint8_t *datbuf = ops->datbuf + pages_read * mtd->writesize; - - dma_sync_single_for_cpu(chip->dev, - data_dma_addr_curr-mtd->writesize, - mtd->writesize, DMA_BIDIRECTIONAL); - + uint32_t data_done = data_dma_addr_curr-data_dma_addr; +#if VERBOSE + printk("msm_nand_read_oob dma_unmap_page %08x\n", (uint32_t)data_dma_addr_curr); +#endif + dma_unmap_page(chip->dev, data_dma_addr, data_count, DMA_FROM_DEVICE); + data_count -= data_done; // we wont be mapping the already transferred bytes to avoid corruption + //data now ready to be read by cpu + for (n = 0; n < mtd->writesize; n++) { if ((n % 512) == 0xF3 && datbuf[n] == 0x76) @@ -842,13 +847,26 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_o } } - dma_sync_single_for_device(chip->dev, - data_dma_addr_curr-mtd->writesize, - mtd->writesize, DMA_BIDIRECTIONAL); - + //remap dma if there's still data to be read + if (data_count > 0) + { +#if VERBOSE + printk("msm_nand_read_oob dma_map_page offset=%d length=%d\n", (uint32_t)(ops->len-data_count), data_count); +#endif + data_dma_addr = msm_nand_dma_map(chip->dev, ops->datbuf+(ops->len-data_count), data_count, DMA_FROM_DEVICE); + data_dma_addr_curr = data_dma_addr; +#if VERBOSE + printk("msm_nand_read_oob dma_map_page returned %08x\n", (uint32_t)data_dma_addr); +#endif + } + else + { + data_dma_addr_curr = data_dma_addr = 0; + } } if (readoob && oob_done_size < oob_count) { + //no sync needed for BIDIR dma buffers uint8_t *pageoobbuf = ops->oobbuf + oob_done_size; for (n = 0; n < page_oob_done; n++) @@ -909,7 +927,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_o } else { - pr_info("error status: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \n", + pr_info("msm_nand_read_oob error status: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \n", dma_buffer->data.result[0].flash_status, dma_buffer->data.result[0].buffer_status, dma_buffer->data.result[1].flash_status, @@ -950,9 +968,9 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_o msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer)); if (readoob) - dma_unmap_page(chip->dev, oob_dma_addr, oob_count, DMA_FROM_DEVICE); + dma_unmap_page(chip->dev, oob_dma_addr, oob_count, DMA_BIDIRECTIONAL); err_dma_map_oobbuf_failed: - if (readdata) + if (readdata && data_dma_addr != 0) dma_unmap_page(chip->dev, data_dma_addr, ops->len, DMA_FROM_DEVICE); #ifdef ENABLE_FLASH_RW_DUMP