From e97d7c88a7566b17912d82e115f02e6fab11699e Mon Sep 17 00:00:00 2001 From: rajkosto Date: Wed, 3 Nov 2010 22:24:52 +0100 Subject: [PATCH 1/8] 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 76df0ff485383d30e1c25ff5fe27822a4cca24e4 Mon Sep 17 00:00:00 2001 From: Markinus Date: Thu, 4 Nov 2010 18:49:09 +0100 Subject: [PATCH 2/8] htcleo: fixed small BL settings for no sense builds and autobl rights --- arch/arm/mach-msm/board-htcleo-bl-led.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-msm/board-htcleo-bl-led.c b/arch/arm/mach-msm/board-htcleo-bl-led.c index 3a492260..a2df550d 100644 --- a/arch/arm/mach-msm/board-htcleo-bl-led.c +++ b/arch/arm/mach-msm/board-htcleo-bl-led.c @@ -85,7 +85,7 @@ static ssize_t htcleo_auto_bl_set(struct device *dev, } -static DEVICE_ATTR(auto_bl, 0644, htcleo_auto_bl_get, htcleo_auto_bl_set); +static DEVICE_ATTR(auto_bl, 0666, htcleo_auto_bl_get, htcleo_auto_bl_set); static int htcleo_brightness_onoff_bkl(int enable) { @@ -131,14 +131,14 @@ static void htcleo_brightness_set(struct led_classdev *led_cdev, enum led_bright LCMDBG("htcleo_brightness_set: %d\n", val); if (val > 255) val = 255; led_cdev->brightness = val; - if (val < 30) + if (val < 1) { htcleo_brightness_onoff_bkl(0); } else { htcleo_brightness_onoff_bkl(1); - htcleo_brightness_set_bkl((val - 30) / 23); + htcleo_brightness_set_bkl((val - 1) / 23); } mutex_unlock(&htcleo_backlight_lock); } From ec2505f81cf9cb83c3da830795d84c6108928aad Mon Sep 17 00:00:00 2001 From: Markinus Date: Thu, 4 Nov 2010 18:50:10 +0100 Subject: [PATCH 3/8] htcleo: changed the LS polling to 5s. Liblights is using now internal mictop bl. The polling every second for backlight is much for the bus, so it's better to use the internal autobl functionality. The 5s is enough for other lightsensor applications. --- arch/arm/mach-msm/board-htcleo-ls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-msm/board-htcleo-ls.c b/arch/arm/mach-msm/board-htcleo-ls.c index 206dff4c..c40d2b83 100644 --- a/arch/arm/mach-msm/board-htcleo-ls.c +++ b/arch/arm/mach-msm/board-htcleo-ls.c @@ -47,7 +47,7 @@ user may be able to adjust time in future //#define LSENSOR_ABLK_ONLY 2 -#define LSENSOR_POLL_PROMESHUTOK 1000 +#define LSENSOR_POLL_PROMESHUTOK 5000 #define D(x...) pr_debug(x) // pr_info(x) From 375f6355e60e14a8fd3ed1ef738792709daee614 Mon Sep 17 00:00:00 2001 From: Jon Benson Date: Sat, 30 Oct 2010 18:12:01 +1100 Subject: [PATCH 4/8] Applied patch for ppp driver. See http://docs.openmoko.org/trac/ticket/2212 --- drivers/net/ppp_deflate.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c index 034c1c65..222fc1a3 100644 --- a/drivers/net/ppp_deflate.c +++ b/drivers/net/ppp_deflate.c @@ -306,7 +306,7 @@ static void z_decomp_free(void *arg) if (state) { zlib_inflateEnd(&state->strm); - kfree(state->strm.workspace); + vfree(state->strm.workspace); kfree(state); } } @@ -346,8 +346,7 @@ static void *z_decomp_alloc(unsigned char *options, int opt_len) state->w_size = w_size; state->strm.next_out = NULL; - state->strm.workspace = kmalloc(zlib_inflate_workspacesize(), - GFP_KERNEL|__GFP_REPEAT); + state->strm.workspace = vmalloc(zlib_inflate_workspacesize()); if (state->strm.workspace == NULL) goto out_free; From e4b408efabf34884e12d0fc0dac465737088d9c8 Mon Sep 17 00:00:00 2001 From: rajkosto Date: Thu, 4 Nov 2010 19:36:01 +0100 Subject: [PATCH 5/8] 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 From 3cdd43b0d4ae37d252b0149bcf2f74d909f32752 Mon Sep 17 00:00:00 2001 From: Markinus Date: Thu, 4 Nov 2010 21:55:11 +0100 Subject: [PATCH 6/8] Revert "go back to using google's version of yaffs for higher stability" This reverts commit e97d7c88a7566b17912d82e115f02e6fab11699e. --- 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_getblockinfo.h | 3 +- fs/yaffs2/yaffs_guts.c | 4492 +++++--------------- fs/yaffs2/yaffs_guts.h | 323 +- 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_fs.c => yaffs_vfs_glue.c} | 1684 ++++++-- 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, 7002 insertions(+), 4479 deletions(-) create mode 100644 fs/yaffs2/yaffs_allocator.c create mode 100644 fs/yaffs2/yaffs_allocator.h create mode 100644 fs/yaffs2/yaffs_bitmap.c create mode 100644 fs/yaffs2/yaffs_bitmap.h create mode 100644 fs/yaffs2/yaffs_linux.h create mode 100644 fs/yaffs2/yaffs_linux_allocator.c create mode 100644 fs/yaffs2/yaffs_list.h create mode 100644 fs/yaffs2/yaffs_nameval.c create mode 100644 fs/yaffs2/yaffs_nameval.h create mode 100644 fs/yaffs2/yaffs_trace.h create mode 100644 fs/yaffs2/yaffs_verify.c create mode 100644 fs/yaffs2/yaffs_verify.h rename fs/yaffs2/{yaffs_fs.c => yaffs_vfs_glue.c} (59%) create mode 100644 fs/yaffs2/yaffs_yaffs1.c create mode 100644 fs/yaffs2/yaffs_yaffs1.h create mode 100644 fs/yaffs2/yaffs_yaffs2.c create mode 100644 fs/yaffs2/yaffs_yaffs2.h diff --git a/arch/arm/configs/htcleo_defconfig b/arch/arm/configs/htcleo_defconfig index 6bf3ed03..85503ae6 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 -# Wed Nov 3 19:18:32 2010 +# Fri Oct 29 13:59:28 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -1688,11 +1688,14 @@ CONFIG_YAFFS_YAFFS1=y # CONFIG_YAFFS_DOES_ECC is not set CONFIG_YAFFS_YAFFS2=y CONFIG_YAFFS_AUTO_YAFFS2=y -# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set +CONFIG_YAFFS_DISABLE_TAGS_ECC=y # 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 85844504..7b3988c3 100644 --- a/fs/yaffs2/Kconfig +++ b/fs/yaffs2/Kconfig @@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2 If unsure, say Y. -config YAFFS_DISABLE_LAZY_LOAD - bool "Disable lazy loading" - depends on YAFFS_YAFFS2 +config YAFFS_DISABLE_TAGS_ECC + bool "Disable YAFFS from doing ECC on tags by default" + depends on YAFFS_FS && YAFFS_YAFFS2 default n help - "Lazy loading" defers loading file details until they are - required. This saves mount time, but makes the first look-up - a bit longer. - - Lazy loading will only happen if enabled by this option being 'n' - and if the appropriate tags are available, else yaffs2 will - automatically fall back to immediate loading and do the right - thing. - - Lazy laoding will be required by checkpointing. - - Setting this to 'y' will disable lazy loading. + This defaults Yaffs to using its own ECC calculations on tags instead of + just relying on the MTD. + This behavior can also be overridden with tags_ecc_on and + tags_ecc_off mount options. If unsure, say N. @@ -156,9 +148,43 @@ config YAFFS_SHORT_NAMES_IN_RAM If unsure, say Y. config YAFFS_EMPTY_LOST_AND_FOUND - bool "Empty lost and found on mount" + bool "Empty lost and found on boot" depends on YAFFS_FS default n help If this is enabled then the contents of lost and found is automatically dumped at mount. + + If unsure, say N. + +config YAFFS_DISABLE_BLOCK_REFRESHING + bool "Disable yaffs2 block refreshing" + depends on YAFFS_FS + default n + help + If this is set, then block refreshing is disabled. + Block refreshing infrequently refreshes the oldest block in + a yaffs2 file system. This mechanism helps to refresh flash to + mitigate against data loss. This is particularly useful for MLC. + + If unsure, say N. + +config YAFFS_DISABLE_BACKGROUND + bool "Disable yaffs2 background processing" + depends on YAFFS_FS + default n + help + If this is set, then background processing is disabled. + Background processing makes many foreground activities faster. + + If unsure, say N. + +config YAFFS_XATTR + bool "Enable yaffs2 xattr support" + depends on YAFFS_FS + default y + help + If this is set then yaffs2 will provide xattr support. + If unsure, say Y. + + diff --git a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile index 382ee614..fbdbd4a0 100644 --- a/fs/yaffs2/Makefile +++ b/fs/yaffs2/Makefile @@ -4,7 +4,14 @@ obj-$(CONFIG_YAFFS_FS) += yaffs.o -yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o -yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o +yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o +yaffs-y += yaffs_nameval.o +yaffs-y += yaffs_allocator.o +yaffs-y += yaffs_yaffs1.o +yaffs-y += yaffs_yaffs2.o +yaffs-y += yaffs_bitmap.o +yaffs-y += yaffs_verify.o + diff --git a/fs/yaffs2/devextras.h b/fs/yaffs2/devextras.h index 7df46dc2..ce30c820 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -24,6 +24,8 @@ #define __EXTRAS_H__ +#include "yportenv.h" + #if !(defined __KERNEL__) /* Definition of types */ @@ -33,103 +35,6 @@ typedef unsigned __u32; #endif -/* - * This is a simple doubly linked list implementation that matches the - * way the Linux kernel doubly linked list implementation works. - */ - -struct ylist_head { - struct ylist_head *next; /* next in chain */ - struct ylist_head *prev; /* previous in chain */ -}; - - -/* Initialise a static list */ -#define YLIST_HEAD(name) \ -struct ylist_head name = { &(name), &(name)} - - - -/* Initialise a list head to an empty list */ -#define YINIT_LIST_HEAD(p) \ -do { \ - (p)->next = (p);\ - (p)->prev = (p); \ -} while (0) - - -/* Add an element to a list */ -static __inline__ void ylist_add(struct ylist_head *newEntry, - struct ylist_head *list) -{ - struct ylist_head *listNext = list->next; - - list->next = newEntry; - newEntry->prev = list; - newEntry->next = listNext; - listNext->prev = newEntry; - -} - -static __inline__ void ylist_add_tail(struct ylist_head *newEntry, - struct ylist_head *list) -{ - struct ylist_head *listPrev = list->prev; - - list->prev = newEntry; - newEntry->next = list; - newEntry->prev = listPrev; - listPrev->next = newEntry; - -} - - -/* Take an element out of its current list, with or without - * reinitialising the links.of the entry*/ -static __inline__ void ylist_del(struct ylist_head *entry) -{ - struct ylist_head *listNext = entry->next; - struct ylist_head *listPrev = entry->prev; - - listNext->prev = listPrev; - listPrev->next = listNext; - -} - -static __inline__ void ylist_del_init(struct ylist_head *entry) -{ - ylist_del(entry); - entry->next = entry->prev = entry; -} - - -/* Test if the list is empty */ -static __inline__ int ylist_empty(struct ylist_head *entry) -{ - return (entry->next == entry); -} - - -/* ylist_entry takes a pointer to a list entry and offsets it to that - * we can find a pointer to the object it is embedded in. - */ - - -#define ylist_entry(entry, type, member) \ - ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member))) - - -/* ylist_for_each and list_for_each_safe iterate over lists. - * ylist_for_each_safe uses temporary storage to make the list delete safe - */ - -#define ylist_for_each(itervar, list) \ - for (itervar = (list)->next; itervar != (list); itervar = itervar->next) - -#define ylist_for_each_safe(itervar, saveVar, list) \ - for (itervar = (list)->next, saveVar = (list)->next->next; \ - itervar != (list); itervar = saveVar, saveVar = saveVar->next) - #if !(defined __KERNEL__) diff --git a/fs/yaffs2/moduleconfig.h b/fs/yaffs2/moduleconfig.h index a344baf3..43f11447 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Martin Fouts @@ -29,22 +29,43 @@ /* Meaning: Yaffs does its own ECC, rather than using MTD ECC */ /* #define CONFIG_YAFFS_DOES_ECC */ +/* Default: Selected */ +/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */ +#define CONFIG_YAFFS_DOES_TAGS_ECC + /* Default: Not selected */ /* Meaning: ECC byte order is 'wrong'. Only meaningful if */ /* CONFIG_YAFFS_DOES_ECC is set */ /* #define CONFIG_YAFFS_ECC_WRONG_ORDER */ -/* Default: Selected */ -/* Meaning: Disables testing whether chunks are erased before writing to them*/ -#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK +/* Default: Not selected */ +/* Meaning: Always test whether chunks are erased before writing to them. + Use during mtd debugging and init. */ +/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */ + +/* Default: Not Selected */ +/* Meaning: At mount automatically empty all files from lost and found. */ +/* This is done to fix an old problem where rmdir was not checking for an */ +/* empty directory. This can also be achieved with a mount option. */ +#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND /* Default: Selected */ /* Meaning: Cache short names, taking more RAM, but faster look-ups */ #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM -/* Default: 10 */ -/* Meaning: set the count of blocks to reserve for checkpointing */ -#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 +/* Default: Unselected */ +/* Meaning: Select to disable block refreshing. */ +/* Block Refreshing periodically rewrites the oldest block. */ +/* #define CONFIG_DISABLE_BLOCK_REFRESHING */ + +/* Default: Unselected */ +/* Meaning: Select to disable background processing */ +/* #define CONFIG_DISABLE_BACKGROUND */ + + +/* Default: Selected */ +/* Meaning: Enable XATTR support */ +#define CONFIG_YAFFS_XATTR /* Older-style on-NAND data format has a "pageStatus" byte to record diff --git a/fs/yaffs2/yaffs_allocator.c b/fs/yaffs2/yaffs_allocator.c new file mode 100644 index 00000000..ab44bc7d --- /dev/null +++ b/fs/yaffs2/yaffs_allocator.c @@ -0,0 +1,409 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2010 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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 new file mode 100644 index 00000000..b0a5d11b --- /dev/null +++ b/fs/yaffs2/yaffs_allocator.h @@ -0,0 +1,30 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2010 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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 new file mode 100644 index 00000000..c7e9e8c4 --- /dev/null +++ b/fs/yaffs2/yaffs_bitmap.c @@ -0,0 +1,105 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2010 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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 new file mode 100644 index 00000000..a0ad1308 --- /dev/null +++ b/fs/yaffs2/yaffs_bitmap.h @@ -0,0 +1,31 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2010 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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 7b69a640..16c9f849 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -11,16 +11,12 @@ * published by the Free Software Foundation. */ -const char *yaffs_checkptrw_c_version = - "$Id$"; - - #include "yaffs_checkptrw.h" #include "yaffs_getblockinfo.h" -static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) +static int yaffs2_CheckpointSpaceOk(yaffs_Device *dev) { - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; + int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks; T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpt blocks available = %d" TENDSTR), @@ -30,11 +26,11 @@ static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) } -static int yaffs_CheckpointErase(yaffs_Device *dev) +static int yaffs2_CheckpointErase(yaffs_Device *dev) { int i; - if (!dev->eraseBlockInNAND) + if (!dev->param.eraseBlockInNAND) return 0; T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR), dev->internalStartBlock, dev->internalEndBlock)); @@ -46,12 +42,12 @@ static int yaffs_CheckpointErase(yaffs_Device *dev) dev->nBlockErasures++; - if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) { + if (dev->param.eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) { bi->blockState = YAFFS_BLOCK_STATE_EMPTY; dev->nErasedBlocks++; - dev->nFreeChunks += dev->nChunksPerBlock; + dev->nFreeChunks += dev->param.nChunksPerBlock; } else { - dev->markNANDBlockBad(dev, i); + dev->param.markNANDBlockBad(dev, i); bi->blockState = YAFFS_BLOCK_STATE_DEAD; } } @@ -63,13 +59,13 @@ static int yaffs_CheckpointErase(yaffs_Device *dev) } -static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev) +static void yaffs2_CheckpointFindNextErasedBlock(yaffs_Device *dev) { int i; - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; + int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks; T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), - dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock)); + dev->nErasedBlocks, dev->param.nReservedBlocks, blocksAvailable, dev->checkpointNextBlock)); if (dev->checkpointNextBlock >= 0 && dev->checkpointNextBlock <= dev->internalEndBlock && @@ -91,7 +87,7 @@ static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev) dev->checkpointCurrentBlock = -1; } -static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) +static void yaffs2_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) { int i; yaffs_ExtendedTags tags; @@ -101,10 +97,10 @@ static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks) for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) { - int chunk = i * dev->nChunksPerBlock; + int chunk = i * dev->param.nChunksPerBlock; int realignedChunk = chunk - dev->chunkOffset; - dev->readChunkWithTagsFromNAND(dev, realignedChunk, + dev->param.readChunkWithTagsFromNAND(dev, realignedChunk, NULL, &tags); T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR), i, tags.objectId, tags.sequenceNumber, tags.eccResult)); @@ -127,24 +123,24 @@ static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) } -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) +int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting) { dev->checkpointOpenForWrite = forWriting; /* Got the functions we need? */ - if (!dev->writeChunkWithTagsToNAND || - !dev->readChunkWithTagsFromNAND || - !dev->eraseBlockInNAND || - !dev->markNANDBlockBad) + if (!dev->param.writeChunkWithTagsToNAND || + !dev->param.readChunkWithTagsFromNAND || + !dev->param.eraseBlockInNAND || + !dev->param.markNANDBlockBad) return 0; - if (forWriting && !yaffs_CheckpointSpaceOk(dev)) + if (forWriting && !yaffs2_CheckpointSpaceOk(dev)) return 0; if (!dev->checkpointBuffer) - dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk); + dev->checkpointBuffer = YMALLOC_DMA(dev->param.totalBytesPerChunk); if (!dev->checkpointBuffer) return 0; @@ -161,7 +157,7 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) if (forWriting) { memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk); dev->checkpointByteOffset = 0; - return yaffs_CheckpointErase(dev); + return yaffs2_CheckpointErase(dev); } else { int i; /* Set to a value that will kick off a read */ @@ -181,7 +177,7 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) return 1; } -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) +int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) { __u32 compositeSum; compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF); @@ -189,7 +185,7 @@ int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) return 1; } -static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) +static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev) { int chunk; int realignedChunk; @@ -197,7 +193,7 @@ static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) yaffs_ExtendedTags tags; if (dev->checkpointCurrentBlock < 0) { - yaffs_CheckpointFindNextErasedBlock(dev); + yaffs2_CheckpointFindNextErasedBlock(dev); dev->checkpointCurrentChunk = 0; } @@ -217,7 +213,7 @@ static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) dev->blocksInCheckpoint++; } - chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; + chunk = dev->checkpointCurrentBlock * dev->param.nChunksPerBlock + dev->checkpointCurrentChunk; T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), @@ -227,12 +223,12 @@ static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) dev->nPageWrites++; - dev->writeChunkWithTagsToNAND(dev, realignedChunk, + dev->param.writeChunkWithTagsToNAND(dev, realignedChunk, dev->checkpointBuffer, &tags); dev->checkpointByteOffset = 0; dev->checkpointPageSequence++; dev->checkpointCurrentChunk++; - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) { + if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock) { dev->checkpointCurrentChunk = 0; dev->checkpointCurrentBlock = -1; } @@ -242,7 +238,7 @@ static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) } -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes) +int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes) { int i = 0; int ok = 1; @@ -271,13 +267,13 @@ int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes) if (dev->checkpointByteOffset < 0 || dev->checkpointByteOffset >= dev->nDataBytesPerChunk) - ok = yaffs_CheckpointFlushBuffer(dev); + ok = yaffs2_CheckpointFlushBuffer(dev); } return i; } -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) +int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) { int i = 0; int ok = 1; @@ -302,7 +298,7 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) dev->checkpointByteOffset >= dev->nDataBytesPerChunk) { if (dev->checkpointCurrentBlock < 0) { - yaffs_CheckpointFindNextCheckpointBlock(dev); + yaffs2_CheckpointFindNextCheckpointBlock(dev); dev->checkpointCurrentChunk = 0; } @@ -310,7 +306,7 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) ok = 0; else { chunk = dev->checkpointCurrentBlock * - dev->nChunksPerBlock + + dev->param.nChunksPerBlock + dev->checkpointCurrentChunk; realignedChunk = chunk - dev->chunkOffset; @@ -319,7 +315,7 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) /* read in the next chunk */ /* printf("read checkpoint page %d\n",dev->checkpointPage); */ - dev->readChunkWithTagsFromNAND(dev, + dev->param.readChunkWithTagsFromNAND(dev, realignedChunk, dev->checkpointBuffer, &tags); @@ -333,7 +329,7 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) dev->checkpointPageSequence++; dev->checkpointCurrentChunk++; - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) + if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock) dev->checkpointCurrentBlock = -1; } } @@ -352,12 +348,12 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) return i; } -int yaffs_CheckpointClose(yaffs_Device *dev) +int yaffs2_CheckpointClose(yaffs_Device *dev) { if (dev->checkpointOpenForWrite) { if (dev->checkpointByteOffset != 0) - yaffs_CheckpointFlushBuffer(dev); + yaffs2_CheckpointFlushBuffer(dev); } else if(dev->checkpointBlockList){ int i; for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) { @@ -375,7 +371,7 @@ int yaffs_CheckpointClose(yaffs_Device *dev) dev->checkpointBlockList = NULL; } - dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock; + dev->nFreeChunks -= dev->blocksInCheckpoint * dev->param.nChunksPerBlock; dev->nErasedBlocks -= dev->blocksInCheckpoint; @@ -391,12 +387,15 @@ int yaffs_CheckpointClose(yaffs_Device *dev) return 0; } -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev) +int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev) { /* Erase the checkpoint data */ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR), dev->blocksInCheckpoint)); - return yaffs_CheckpointErase(dev); + return yaffs2_CheckpointErase(dev); } + + + diff --git a/fs/yaffs2/yaffs_checkptrw.h b/fs/yaffs2/yaffs_checkptrw.h index 5d426ea8..ea4f0276 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -18,18 +18,17 @@ #include "yaffs_guts.h" -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting); +int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting); -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes); +int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes); -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes); +int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes); -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); +int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); -int yaffs_CheckpointClose(yaffs_Device *dev); +int yaffs2_CheckpointClose(yaffs_Device *dev); -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev); +int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev); #endif - diff --git a/fs/yaffs2/yaffs_ecc.c b/fs/yaffs2/yaffs_ecc.c index 4676346c..da6145aa 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -28,9 +28,6 @@ * 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 60765176..a1ee69ac 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning diff --git a/fs/yaffs2/yaffs_getblockinfo.h b/fs/yaffs2/yaffs_getblockinfo.h index 5b0a1ac2..71fe1dee 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -17,6 +17,7 @@ #define __YAFFS_GETBLOCKINFO_H__ #include "yaffs_guts.h" +#include "yaffs_trace.h" /* Function to manipulate block info */ static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk) diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c index 5003e52f..7e97a5f0 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -10,11 +10,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - -const char *yaffs_guts_c_version = - "$Id$"; - #include "yportenv.h" +#include "yaffs_trace.h" #include "yaffsinterface.h" #include "yaffs_guts.h" @@ -22,22 +19,28 @@ const char *yaffs_guts_c_version = #include "yaffs_getblockinfo.h" #include "yaffs_tagscompat.h" -#ifndef CONFIG_YAFFS_USE_OWN_SORT -#include "yaffs_qsort.h" -#endif + #include "yaffs_nand.h" -#include "yaffs_checkptrw.h" +#include "yaffs_yaffs1.h" +#include "yaffs_yaffs2.h" +#include "yaffs_bitmap.h" +#include "yaffs_verify.h" #include "yaffs_nand.h" #include "yaffs_packedtags2.h" +#include "yaffs_nameval.h" +#include "yaffs_allocator.h" -#define YAFFS_PASSIVE_GC_CHUNKS 2 +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ +#define YAFFS_GC_GOOD_ENOUGH 2 +#define YAFFS_GC_PASSIVE_THRESHOLD 4 #include "yaffs_ecc.h" + /* Robustification (if it ever comes about...) */ static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND); static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, @@ -53,30 +56,22 @@ static void yaffs_UpdateParent(yaffs_Object *obj); static int yaffs_UnlinkObject(yaffs_Object *obj); static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj); -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList); - static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve); -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, - int chunkInNAND, int inScan); + static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, yaffs_ObjectType type); -static void yaffs_AddObjectToDirectory(yaffs_Object *directory, - yaffs_Object *obj); -static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, - int force, int isShrink, int shadows); + + +static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod); + static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj); static int yaffs_CheckStructures(void); -/*static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, - int chunkOffset, int *limit);*/ /*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); @@ -88,30 +83,23 @@ 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 __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, - unsigned pos); -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, - yaffs_FileStructure *fStruct, - __u32 chunkId); +static int yaffs_VerifyChunkWritten(yaffs_Device *dev, + int chunkInNAND, + const __u8 *data, + yaffs_ExtendedTags *tags); + + +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize); +static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev,YCHAR *ohName, const YCHAR *name); + /* Function to calculate chunk and offset */ @@ -172,7 +160,7 @@ static __u32 ShiftsGE(__u32 x) static __u32 Shifts(__u32 x) { - int nShifts; + __u32 nShifts; nShifts = 0; @@ -203,7 +191,7 @@ static int yaffs_InitialiseTempBuffers(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->totalBytesPerChunk); + YMALLOC_DMA(dev->param.totalBytesPerChunk); } return buf ? YAFFS_OK : YAFFS_FAIL; @@ -286,7 +274,7 @@ int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer) return 1; } - for (i = 0; i < dev->nShortOpCaches; i++) { + for (i = 0; i < dev->param.nShortOpCaches; i++) { if (dev->srCache[i].data == buffer) return 1; } @@ -299,557 +287,11 @@ 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); - } - } - } -} /* @@ -918,6 +360,29 @@ 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, @@ -927,7 +392,7 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, int writeOk = 0; int chunk; - yaffs_InvalidateCheckpoint(dev); + yaffs2_InvalidateCheckpoint(dev); do { yaffs_BlockInfo *bi = 0; @@ -957,19 +422,18 @@ 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++; -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED - bi->skipErasedCheck = 0; -#endif + if(dev->param.alwaysCheckErased) + bi->skipErasedCheck = 0; + if (!bi->skipErasedCheck) { erasedOk = yaffs_CheckChunkErased(dev, chunk); if (erasedOk != YAFFS_OK) { @@ -977,20 +441,30 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, (TSTR("**>> yaffs chunk %d was not erased" TENDSTR), chunk)); - /* try another chunk */ + /* If not erased, delete this one, + * skip rest of block and + * try another chunk */ + yaffs_DeleteChunk(dev,chunk,1,__LINE__); + yaffs_SkipRestOfBlock(dev); continue; } - 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); @@ -1011,80 +485,8 @@ 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. */ @@ -1093,9 +495,9 @@ static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND) { yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); - yaffs_InvalidateCheckpoint(dev); - - yaffs_ClearOldestDirtySequence(dev, bi); + yaffs2_InvalidateCheckpoint(dev); + + yaffs2_ClearOldestDirtySequence(dev,bi); if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) { if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) { @@ -1104,14 +506,14 @@ static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND) TENDSTR), blockInNAND)); } else { yaffs_ExtendedTags tags; - int chunkId = blockInNAND * dev->nChunksPerBlock; + int chunkId = blockInNAND * dev->param.nChunksPerBlock; __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); memset(buffer, 0xff, dev->nDataBytesPerChunk); yaffs_InitialiseTags(&tags); tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK; - if (dev->writeChunkWithTagsToNAND(dev, chunkId - + if (dev->param.writeChunkWithTagsToNAND(dev, chunkId - dev->chunkOffset, buffer, &tags) != YAFFS_OK) T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to " TCONT("write bad block marker to block %d") @@ -1137,11 +539,18 @@ 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) @@ -1162,7 +571,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->nChunksPerBlock; + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock; yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); yaffs_HandleChunkError(dev, bi); @@ -1176,6 +585,7 @@ static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, /* Delete the chunk */ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); + yaffs_SkipRestOfBlock(dev); } @@ -1202,11 +612,11 @@ static __u16 yaffs_CalcNameSum(const YCHAR *name) return sum; } -static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name) +void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name) { #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1)); - if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) + if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH) yaffs_strcpy(obj->shortName, name); else obj->shortName[0] = _Y('\0'); @@ -1214,6 +624,18 @@ static 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 @@ -1221,117 +643,13 @@ static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name) * in the tnode. */ -/* yaffs_CreateTnodes creates a bunch more tnodes and - * adds them to the tnode free list. - * Don't use this function directly - */ -static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes) +yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev) { - 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--; + yaffs_Tnode *tn = yaffs_AllocateRawTnode(dev); + if (tn){ + memset(tn, 0, dev->tnodeSize); + dev->nTnodes++; } dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ @@ -1339,67 +657,23 @@ static yaffs_Tnode *yaffs_GetTnodeRaw(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) { - 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++; - } + yaffs_FreeRawTnode(dev,tn); + dev->nTnodes--; dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ } -static void yaffs_DeinitialiseTnodes(yaffs_Device *dev) +static void yaffs_DeinitialiseTnodesAndObjects(yaffs_Device *dev) { - /* Free the list of allocated tnodes */ - yaffs_TnodeList *tmp; - - while (dev->allocatedTnodeList) { - tmp = dev->allocatedTnodeList->next; - - YFREE(dev->allocatedTnodeList->tnodes); - YFREE(dev->allocatedTnodeList); - dev->allocatedTnodeList = tmp; - - } - - dev->freeTnodes = NULL; - dev->nFreeTnodes = 0; -} - -static void yaffs_InitialiseTnodes(yaffs_Device *dev) -{ - dev->allocatedTnodeList = NULL; - dev->freeTnodes = NULL; - dev->nFreeTnodes = 0; - dev->nTnodesCreated = 0; + yaffs_DeinitialiseRawTnodesAndObjects(dev); + dev->nObjects = 0; + dev->nTnodes = 0; } -void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, +void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, unsigned val) { __u32 *map = (__u32 *)tn; @@ -1429,7 +703,7 @@ void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, } } -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, +__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos) { __u32 *map = (__u32 *)tn; @@ -1466,7 +740,7 @@ static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, */ /* FindLevel0Tnode finds the level 0 tnode, if one exists. */ -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, +yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId) { @@ -1475,6 +749,8 @@ static 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; @@ -1518,7 +794,7 @@ static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, * be plugged into the ttree. */ -static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, +yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId, yaffs_Tnode *passedTn) @@ -1557,13 +833,13 @@ static 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))); + (TSTR("yaffs: no more tnodes" TENDSTR))); + return NULL; } } - - fStruct->topLevel = requiredTallness; } /* Traverse down to level 0, adding anything we need */ @@ -1582,7 +858,8 @@ static 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) { @@ -1594,6 +871,8 @@ static 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; } } @@ -1618,8 +897,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->nChunksPerBlock, - theChunk % dev->nChunksPerBlock)) { + if (yaffs_CheckChunkBit(dev, theChunk / dev->param.nChunksPerBlock, + theChunk % dev->param.nChunksPerBlock)) { if(dev->chunkGroupSize == 1) return theChunk; @@ -1637,13 +916,14 @@ 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) { @@ -1717,7 +997,7 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, } - yaffs_PutLevel0Tnode(dev, tn, i, 0); + yaffs_LoadLevel0Tnode(dev, tn, i, 0); } } @@ -1730,18 +1010,22 @@ 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)); - theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock); + blockNo = chunk / dev->param.nChunksPerBlock; + theBlock = yaffs_GetBlockInfo(dev, blockNo); if (theBlock) { theBlock->softDeletions++; dev->nFreeChunks++; - yaffs_UpdateOldestDirtySequence(dev, theBlock); + yaffs2_UpdateOldestDirtySequence(dev, blockNo, theBlock); } } @@ -1795,7 +1079,7 @@ static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, * a block. */ yaffs_SoftDeleteChunk(dev, theChunk); - yaffs_PutLevel0Tnode(dev, tn, i, 0); + yaffs_LoadLevel0Tnode(dev, tn, i, 0); } } @@ -1841,6 +1125,10 @@ 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, @@ -1852,17 +1140,27 @@ static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, if (tn) { hasData = 0; - for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { - if (tn->internal[i] && level > 0) { - tn->internal[i] = - yaffs_PruneWorker(dev, tn->internal[i], - level - 1, - (i == 0) ? del0 : 1); - } + if(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++; - } + if (tn->internal[i]) + hasData++; + } + } 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 (hasData == 0 && del0) { /* Free and return NULL */ @@ -1920,90 +1218,32 @@ 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 *tn = NULL; + yaffs_Object *obj = yaffs_AllocateRawObject(dev); -#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 (obj) { + dev->nObjects++; - if (dev->freeObjects) { - tn = dev->freeObjects; - dev->freeObjects = - (yaffs_Object *) (dev->freeObjects->siblings.next); - dev->nFreeObjects--; - } -#endif - if (tn) { /* Now sweeten it up... */ - memset(tn, 0, sizeof(yaffs_Object)); - tn->beingCreated = 1; + memset(obj, 0, sizeof(yaffs_Object)); + obj->beingCreated = 1; - tn->myDev = dev; - tn->hdrChunk = 0; - tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN; - YINIT_LIST_HEAD(&(tn->hardLinks)); - YINIT_LIST_HEAD(&(tn->hashLink)); - YINIT_LIST_HEAD(&tn->siblings); + 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); /* Now make the directory sane */ if (dev->rootDir) { - tn->parent = dev->rootDir; - ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children); + obj->parent = dev->rootDir; + ylist_add(&(obj->siblings), &dev->rootDir->variant.directoryVariant.children); } /* Add it to the lost and found directory. @@ -2011,14 +1251,14 @@ static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev) * check if lostNFound exists first */ if (dev->lostNFoundDir) - yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn); + yaffs_AddObjectToDirectory(dev->lostNFoundDir, obj); - tn->beingCreated = 0; + obj->beingCreated = 0; } dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ - return tn; + return obj; } static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number, @@ -2042,58 +1282,49 @@ static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number, } -static void yaffs_UnhashObject(yaffs_Object *tn) +static void yaffs_UnhashObject(yaffs_Object *obj) { int bucket; - yaffs_Device *dev = tn->myDev; + yaffs_Device *dev = obj->myDev; /* If it is still linked into the bucket list, free from the list */ - if (!ylist_empty(&tn->hashLink)) { - ylist_del_init(&tn->hashLink); - bucket = yaffs_HashFunction(tn->objectId); + if (!ylist_empty(&obj->hashLink)) { + ylist_del_init(&obj->hashLink); + bucket = yaffs_HashFunction(obj->objectId); dev->objectBucket[bucket].count--; } } /* FreeObject frees up a Object and puts it back on the free list */ -static void yaffs_FreeObject(yaffs_Object *tn) +static void yaffs_FreeObject(yaffs_Object *obj) { - yaffs_Device *dev = tn->myDev; + yaffs_Device *dev = obj->myDev; -#ifdef __KERNEL__ - T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode)); -#endif + T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->myInode)); - if (tn->parent) + if (!obj) YBUG(); - if (!ylist_empty(&tn->siblings)) + if (obj->parent) + YBUG(); + if (!ylist_empty(&obj->siblings)) YBUG(); -#ifdef __KERNEL__ - if (tn->myInode) { + if (obj->myInode) { /* We're still hooked up to a cached inode. * Don't delete now, but mark for later deletion */ - tn->deferedFree = 1; + obj->deferedFree = 1; return; } -#endif - yaffs_UnhashObject(tn); + yaffs_UnhashObject(obj); -#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 + yaffs_FreeRawObject(dev,obj); + dev->nObjects--; dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ } -#ifdef __KERNEL__ void yaffs_HandleDeferedFree(yaffs_Object *obj) { @@ -2101,33 +1332,14 @@ void yaffs_HandleDeferedFree(yaffs_Object *obj) yaffs_FreeObject(obj); } -#endif - -static void yaffs_DeinitialiseObjects(yaffs_Device *dev) -{ - /* Free the list of allocated Objects */ - - yaffs_ObjectList *tmp; - - while (dev->allocatedObjectList) { - tmp = dev->allocatedObjectList->next; - YFREE(dev->allocatedObjectList->objects); - YFREE(dev->allocatedObjectList); - - dev->allocatedObjectList = tmp; - } - - dev->freeObjects = NULL; - dev->nFreeObjects = 0; -} - -static void yaffs_InitialiseObjects(yaffs_Device *dev) +static void yaffs_InitialiseTnodesAndObjects(yaffs_Device *dev) { int i; - dev->allocatedObjectList = NULL; - dev->freeObjects = NULL; - dev->nFreeObjects = 0; + dev->nObjects = 0; + dev->nTnodes = 0; + + yaffs_InitialiseRawTnodesAndObjects(dev); for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { YINIT_LIST_HEAD(&dev->objectBucket[i].list); @@ -2137,33 +1349,21 @@ static void yaffs_InitialiseObjects(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. */ - 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 + /* Search for the shortest list or one that + * isn't too long. */ - 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; + 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; } } @@ -2223,11 +1423,10 @@ 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; } @@ -2240,24 +1439,26 @@ yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number) yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, yaffs_ObjectType type) { - yaffs_Object *theObject; + yaffs_Object *theObject=NULL; yaffs_Tnode *tn = NULL; if (number < 0) number = yaffs_CreateNewObjectNumber(dev); - theObject = yaffs_AllocateEmptyObject(dev); - if (!theObject) - return NULL; - if (type == YAFFS_OBJECT_TYPE_FILE) { tn = yaffs_GetTnode(dev); - if (!tn) { - yaffs_FreeObject(theObject); + if (!tn) return NULL; - } } + theObject = yaffs_AllocateEmptyObject(dev); + if (!theObject){ + if(tn) + yaffs_FreeTnode(dev,tn); + return NULL; + } + + if (theObject) { theObject->fake = 0; theObject->renameAllowed = 1; @@ -2288,6 +1489,8 @@ 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: @@ -2303,9 +1506,9 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, return theObject; } -static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, - int number, - yaffs_ObjectType type) +yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, + int number, + yaffs_ObjectType type) { yaffs_Object *theObject = NULL; @@ -2320,16 +1523,20 @@ static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, } -static YCHAR *yaffs_CloneString(const YCHAR *str) +YCHAR *yaffs_CloneString(const YCHAR *str) { YCHAR *newStr = NULL; + int len; - if (str && *str) { - newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); - if (newStr) - yaffs_strcpy(newStr, str); + if (!str) + str = _Y(""); + + len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH); + newStr = YMALLOC((len + 1) * sizeof(YCHAR)); + if (newStr){ + yaffs_strncpy(newStr, str,len); + newStr[len] = 0; } - return newStr; } @@ -2337,7 +1544,7 @@ static 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 sumlink. + * aliasString only has meaning for a symlink. * rdev only has meaning for devices (a subset of special objects) */ @@ -2359,19 +1566,22 @@ static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, if (yaffs_FindObjectByName(parent, name)) return NULL; - in = yaffs_CreateNewObject(dev, -1, type); - - if (!in) - return YAFFS_FAIL; - if (type == YAFFS_OBJECT_TYPE_SYMLINK) { str = yaffs_CloneString(aliasString); - if (!str) { - yaffs_FreeObject(in); + if (!str) return NULL; - } } + in = yaffs_CreateNewObject(dev, -1, type); + + if (!in){ + if(str) + YFREE(str); + return NULL; + } + + + if (in) { @@ -2421,7 +1631,7 @@ static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, break; } - if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) { + if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0, NULL) < 0) { /* Could not create the object header, fail the creation */ yaffs_DeleteObject(in); in = NULL; @@ -2499,7 +1709,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->isYaffs2) + if (obj->myDev->param.isYaffs2) unlinkOp = (newDir == obj->myDev->unlinkedDir); else unlinkOp = (newDir == obj->myDev->unlinkedDir @@ -2529,7 +1739,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) >= 0) + if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows, NULL) >= 0) return YAFFS_OK; } @@ -2562,7 +1772,7 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, force = 1; #endif - if(yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) + if(yaffs_strnlen(newName,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH) /* ENAMETOOLONG */ return YAFFS_FAIL; @@ -2585,12 +1795,12 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, * Note we must disable gc otherwise it can mess up the shadowing. * */ - dev->isDoingGC=1; + dev->gcDisable=1; yaffs_ChangeObjectName(obj, newDir, newName, force, existingTarget->objectId); existingTarget->isShadowed = 1; yaffs_UnlinkObject(existingTarget); - dev->isDoingGC=0; + dev->gcDisable=0; } result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0); @@ -2598,7 +1808,7 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_UpdateParent(oldDir); if(newDir != oldDir) yaffs_UpdateParent(newDir); - + return result; } return YAFFS_FAIL; @@ -2625,7 +1835,7 @@ static int yaffs_InitialiseBlocks(yaffs_Device *dev) if (dev->blockInfo) { /* Set up dynamic blockinfo stuff. */ - dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ + dev->chunkBitmapStride = (dev->param.nChunksPerBlock + 7) / 8; /* round up bytes */ dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); if (!dev->chunkBits) { dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); @@ -2662,122 +1872,7 @@ static void yaffs_DeinitialiseBlocks(yaffs_Device *dev) dev->chunkBits = NULL; } -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) +void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) { yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo); @@ -2791,12 +1886,22 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR), blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : "")); - yaffs_ClearOldestDirtySequence(dev, bi); + yaffs2_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) { - yaffs_InvalidateCheckpoint(dev); + yaffs2_InvalidateCheckpoint(dev); erasedOk = yaffs_EraseBlockInNAND(dev, blockNo); if (!erasedOk) { dev->nErasureFailures++; @@ -2808,9 +1913,9 @@ static 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->nChunksPerBlock; i++) { + for (i = 0; i < dev->param.nChunksPerBlock; i++) { if (!yaffs_CheckChunkErased - (dev, blockNo * dev->nChunksPerBlock + i)) { + (dev, blockNo * dev->param.nChunksPerBlock + i)) { T(YAFFS_TRACE_ERROR, (TSTR (">>Block %d erasure supposedly OK, but chunk %d not erased" @@ -2822,6 +1927,7 @@ static 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; @@ -2833,7 +1939,7 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) T(YAFFS_TRACE_ERASE, (TSTR("Erased block %d" TENDSTR), blockNo)); } else { - dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */ + dev->nFreeChunks -= dev->param.nChunksPerBlock; /* We lost a block of free space */ yaffs_RetireBlock(dev, blockNo); T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, @@ -2890,63 +1996,21 @@ 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()? */ -static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev) +int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks) { int reservedChunks; - int reservedBlocks = dev->nReservedBlocks; + int reservedBlocks = dev->param.nReservedBlocks; int checkpointBlocks; - if (dev->isYaffs2) { - checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - - dev->blocksInCheckpoint; - if (checkpointBlocks < 0) - checkpointBlocks = 0; - } else { - checkpointBlocks = 0; - } + checkpointBlocks = yaffs2_CalcCheckpointBlocksRequired(dev); - reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); + reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.nChunksPerBlock); - return (dev->nFreeChunks > reservedChunks); + return (dev->nFreeChunks > (reservedChunks + nChunks)); } static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, @@ -2961,12 +2025,12 @@ static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, dev->allocationPage = 0; } - if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) { + if (!useReserve && !yaffs_CheckSpaceForAllocation(dev, 1)) { /* Not enough space to allocate unless we're allowed to use the reserve. */ return -1; } - if (dev->nErasedBlocks < dev->nReservedBlocks + if (dev->nErasedBlocks < dev->param.nReservedBlocks && dev->allocationPage == 0) { T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR))); } @@ -2975,7 +2039,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, if (dev->allocationBlock >= 0) { bi = yaffs_GetBlockInfo(dev, dev->allocationBlock); - retVal = (dev->allocationBlock * dev->nChunksPerBlock) + + retVal = (dev->allocationBlock * dev->param.nChunksPerBlock) + dev->allocationPage; bi->pagesInUse++; yaffs_SetChunkBit(dev, dev->allocationBlock, @@ -2986,7 +2050,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->nChunksPerBlock) { + if (dev->allocationPage >= dev->param.nChunksPerBlock) { bi->blockState = YAFFS_BLOCK_STATE_FULL; dev->allocationBlock = -1; } @@ -3007,15 +2071,31 @@ static int yaffs_GetErasedChunks(yaffs_Device *dev) { int n; - n = dev->nErasedBlocks * dev->nChunksPerBlock; + n = dev->nErasedBlocks * dev->param.nChunksPerBlock; if (dev->allocationBlock > 0) - n += (dev->nChunksPerBlock - dev->allocationPage); + n += (dev->param.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) { @@ -3023,7 +2103,6 @@ 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; @@ -3055,13 +2134,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */ - /* Take off the number of soft deleted entries because - * they're going to get really deleted during GC. - */ - if(dev->gcChunk == 0) /* first time through for this block */ - dev->nFreeChunks -= bi->softDeletions; - - dev->isDoingGC = 1; + dev->gcDisable = 1; if (isCheckpointBlock || !yaffs_StillSomeChunkBits(dev, block)) { @@ -3076,12 +2149,12 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, yaffs_VerifyBlock(dev, bi, block); - maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10; - oldChunk = block * dev->nChunksPerBlock + dev->gcChunk; + maxCopies = (wholeBlock) ? dev->param.nChunksPerBlock : 5; + oldChunk = block * dev->param.nChunksPerBlock + dev->gcChunk; for (/* init already done */; retVal == YAFFS_OK && - dev->gcChunk < dev->nChunksPerBlock && + dev->gcChunk < dev->param.nChunksPerBlock && (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) && maxCopies > 0; dev->gcChunk++, oldChunk++) { @@ -3140,14 +2213,22 @@ 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[cleanups] = + dev->gcCleanupList[dev->nCleanups] = tags.objectId; - cleanups++; + dev->nCleanups++; } markNAND = 0; } else if (0) { @@ -3182,17 +2263,26 @@ 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; - yaffs_VerifyObjectHeader(object, oh, &tags, 1); - } + /* Update file size */ + if(object->variantType == YAFFS_OBJECT_TYPE_FILE){ + oh->fileSize = object->variant.fileVariant.fileSize; + tags.extraFileLength = oh->fileSize; + } - newChunk = - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1); + yaffs_VerifyObjectHeader(object, oh, &tags, 1); + newChunk = + yaffs_WriteNewChunkWithTagsToNAND(dev,(__u8 *) oh, &tags, 1); + } else + newChunk = + yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1); if (newChunk < 0) { retVal = YAFFS_FAIL; @@ -3206,7 +2296,8 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, object->serial = tags.serialNumber; } else { /* It's a data chunk */ - yaffs_PutChunkIntoFile + int ok; + ok = yaffs_PutChunkIntoFile (object, tags.chunkId, newChunk, 0); @@ -3223,8 +2314,23 @@ 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 < cleanups; i++) { + for (i = 0; i < dev->nCleanups; i++) { /* Time to delete the file too */ object = yaffs_FindObjectByNumber(dev, @@ -3244,29 +2350,185 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, } - } - 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; + 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->isDoingGC = 0; + dev->gcDisable = 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. @@ -3276,72 +2538,111 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, * 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) +static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background) { - int block; - int aggressive; + int aggressive = 0; int gcOk = YAFFS_OK; int maxTries = 0; - + int minErased; + int erasedChunks; int checkpointBlockAdjust; - if (dev->isDoingGC) { + if(dev->param.gcControl && + (dev->param.gcControl(dev) & 1) == 0) + return YAFFS_OK; + + if (dev->gcDisable) { /* Bail out so we don't get recursive gc */ return YAFFS_OK; } /* This loop should pass the first time. - * We'll only see looping here if the erase of the collected block fails. + * We'll only see looping here if the collection does not increase space. */ do { maxTries++; - checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; - if (checkpointBlockAdjust < 0) - checkpointBlockAdjust = 0; + checkpointBlockAdjust = yaffs2_CalcCheckpointBlocksRequired(dev); - if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) { - /* We need a block soon...*/ + 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) aggressive = 1; - } else { - /* We're in no hurry */ - aggressive = 0; + 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; + } } - if (dev->gcBlock <= 0) { - dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive); + 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); dev->gcChunk = 0; + dev->nCleanups=0; + } + if (dev->gcBlock < 1) { + dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background); + dev->gcChunk = 0; + dev->nCleanups=0; } - block = dev->gcBlock; - - if (block > 0) { - dev->garbageCollections++; + if (dev->gcBlock > 0) { + dev->allGCs++; if (!aggressive) - dev->passiveGarbageCollections++; + dev->passiveGCs++; T(YAFFS_TRACE_GC, (TSTR ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR), dev->nErasedBlocks, aggressive)); - gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive); + gcOk = yaffs_GarbageCollectBlock(dev, dev->gcBlock, aggressive); } - if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) { + if (dev->nErasedBlocks < (dev->param.nReservedBlocks) && dev->gcBlock > 0) { T(YAFFS_TRACE_GC, (TSTR ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" - TENDSTR), dev->nErasedBlocks, maxTries, block)); + TENDSTR), dev->nErasedBlocks, maxTries, dev->gcBlock)); } - } while ((dev->nErasedBlocks < dev->nReservedBlocks) && - (block > 0) && + } while ((dev->nErasedBlocks < dev->param.nReservedBlocks) && + (dev->gcBlock > 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, @@ -3411,76 +2712,21 @@ static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode, /* Delete the entry in the filestructure (if found) */ if (retVal != -1) - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0); + yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, 0); } return retVal; } -#ifdef YAFFS_PARANOID -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) +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; @@ -3512,6 +2758,10 @@ static 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); @@ -3526,7 +2776,7 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, */ if (existingChunk > 0) { - /* NB Right now existing chunk will not be real chunkId if the device >= 32MB + /* NB Right now existing chunk will not be real chunkId if the chunk group size > 1 * 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: @@ -3568,8 +2818,7 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, } if ((inScan > 0) && - (in->myDev->isYaffs2 || - existingChunk <= 0 || + (existingChunk <= 0 || ((existingSerial + 1) & 3) == newSerial)) { /* Forward scanning. * Use new @@ -3593,7 +2842,7 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, if (existingChunk == 0) in->nDataChunks++; - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND); + yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, chunkInNAND); return YAFFS_OK; } @@ -3628,8 +2877,8 @@ void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn) return; dev->nDeletions++; - block = chunkId / dev->nChunksPerBlock; - page = chunkId % dev->nChunksPerBlock; + block = chunkId / dev->param.nChunksPerBlock; + page = chunkId % dev->param.nChunksPerBlock; if (!yaffs_CheckChunkBit(dev, block, page)) @@ -3638,14 +2887,14 @@ void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn) chunkId)); bi = yaffs_GetBlockInfo(dev, block); - - yaffs_UpdateOldestDirtySequence(dev, bi); + + yaffs2_UpdateOldestDirtySequence(dev, block, bi); T(YAFFS_TRACE_DELETION, (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId)); - if (markNAND && - bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) { + if (!dev->param.isYaffs2 && markNAND && + bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) { yaffs_InitialiseTags(&tags); @@ -3698,10 +2947,16 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, yaffs_Device *dev = in->myDev; - yaffs_CheckGarbageCollection(dev); + yaffs_CheckGarbageCollection(dev,0); - /* Get the previous chunk at this location in the file if it exists */ + /* 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. + */ prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags); + if(prevChunkId < 1 && + !yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0)) + return 0; /* Set up new tags */ yaffs_InitialiseTags(&newTags); @@ -3712,23 +2967,24 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, (prevChunkId > 0) ? prevTags.serialNumber + 1 : 1; newTags.byteCount = nBytes; - if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) { + if (nBytes < 1 || nBytes > dev->param.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_CheckFileSanity(in); + yaffs_VerifyFileSanity(in); } return newChunkId; @@ -3738,7 +2994,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) + int isShrink, int shadows, yaffs_XAttrMod *xmod) { yaffs_BlockInfo *bi; @@ -3752,6 +3008,7 @@ 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]; @@ -3763,9 +3020,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) { + force || xmod) { - yaffs_CheckGarbageCollection(dev); + yaffs_CheckGarbageCollection(dev,0); yaffs_CheckObjectDetailsLoaded(in); buffer = yaffs_GetTempBuffer(in->myDev, __LINE__); @@ -3780,9 +3037,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, dev->nDataBytesPerChunk); + memset(buffer, 0xFF, sizeof(yaffs_ObjectHeader)); + } else + memset(buffer, 0xFF, dev->nDataBytesPerChunk); oh->type = in->variantType; oh->yst_mode = in->yst_mode; @@ -3810,7 +3067,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, if (name && *name) { memset(oh->name, 0, sizeof(oh->name)); - yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH); + yaffs_LoadObjectHeaderFromName(dev,oh->name,name); } else if (prevChunkId > 0) memcpy(oh->name, oldName, sizeof(oh->name)); else @@ -3840,13 +3097,21 @@ 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, - in->variant.symLinkVariant.alias, + 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++; @@ -3886,7 +3151,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->nChunksPerBlock); + newChunkId / in->myDev->param.nChunksPerBlock); bi->hasShrinkHeader = 1; } @@ -3920,7 +3185,7 @@ static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj) yaffs_Device *dev = obj->myDev; int i; yaffs_ChunkCache *cache; - int nCaches = obj->myDev->nShortOpCaches; + int nCaches = obj->myDev->param.nShortOpCaches; for (i = 0; i < nCaches; i++) { cache = &dev->srCache[i]; @@ -3940,7 +3205,7 @@ static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) int i; yaffs_ChunkCache *cache; int chunkWritten = 0; - int nCaches = obj->myDev->nShortOpCaches; + int nCaches = obj->myDev->param.nShortOpCaches; if (nCaches > 0) { do { @@ -3992,7 +3257,7 @@ static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) void yaffs_FlushEntireDeviceCache(yaffs_Device *dev) { yaffs_Object *obj; - int nCaches = dev->nShortOpCaches; + int nCaches = dev->param.nShortOpCaches; int i; /* Find a dirty object in the cache and flush it... @@ -4023,8 +3288,8 @@ static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev) { int i; - if (dev->nShortOpCaches > 0) { - for (i = 0; i < dev->nShortOpCaches; i++) { + if (dev->param.nShortOpCaches > 0) { + for (i = 0; i < dev->param.nShortOpCaches; i++) { if (!dev->srCache[i].object) return &dev->srCache[i]; } @@ -4041,7 +3306,7 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) int i; int pushout; - if (dev->nShortOpCaches > 0) { + if (dev->param.nShortOpCaches > 0) { /* Try find a non-dirty one... */ cache = yaffs_GrabChunkCacheWorker(dev); @@ -4060,7 +3325,7 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) cache = NULL; pushout = -1; - for (i = 0; i < dev->nShortOpCaches; i++) { + for (i = 0; i < dev->param.nShortOpCaches; i++) { if (dev->srCache[i].object && !dev->srCache[i].locked && (dev->srCache[i].lastUse < usage || !cache)) { @@ -4090,8 +3355,8 @@ static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, { yaffs_Device *dev = obj->myDev; int i; - if (dev->nShortOpCaches > 0) { - for (i = 0; i < dev->nShortOpCaches; i++) { + if (dev->param.nShortOpCaches > 0) { + for (i = 0; i < dev->param.nShortOpCaches; i++) { if (dev->srCache[i].object == obj && dev->srCache[i].chunkId == chunkId) { dev->cacheHits++; @@ -4108,11 +3373,11 @@ static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int isAWrite) { - if (dev->nShortOpCaches > 0) { + if (dev->param.nShortOpCaches > 0) { if (dev->srLastUse < 0 || dev->srLastUse > 100000000) { /* Reset the cache usages */ int i; - for (i = 1; i < dev->nShortOpCaches; i++) + for (i = 1; i < dev->param.nShortOpCaches; i++) dev->srCache[i].lastUse = 0; dev->srLastUse = 0; @@ -4133,7 +3398,7 @@ static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, */ static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId) { - if (object->myDev->nShortOpCaches > 0) { + if (object->myDev->param.nShortOpCaches > 0) { yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId); if (cache) @@ -4149,577 +3414,15 @@ static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in) int i; yaffs_Device *dev = in->myDev; - if (dev->nShortOpCaches > 0) { + if (dev->param.nShortOpCaches > 0) { /* Invalidate it. */ - for (i = 0; i < dev->nShortOpCaches; i++) { + for (i = 0; i < dev->param.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. @@ -4766,8 +3469,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->inbandTags) { - if (dev->nShortOpCaches > 0) { + if (cache || nToCopy != dev->nDataBytesPerChunk || dev->param.inbandTags) { + if (dev->param.nShortOpCaches > 0) { /* If we can't find the data in the cache, then load it up. */ @@ -4823,7 +3526,7 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset, return nDone; } -int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, +int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, int nBytes, int writeThrough) { @@ -4843,8 +3546,6 @@ int yaffs_WriteDataToFile(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 || @@ -4854,7 +3555,7 @@ int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, TENDSTR), (int)offset, chunk, start)); } - chunk++; + chunk++; /* File pos to chunk in file offset */ /* OK now check for the curveball where the start and end are in * the same chunk. @@ -4890,29 +3591,27 @@ int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, nToWriteBack = dev->nDataBytesPerChunk; } - if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) { + if (nToCopy != dev->nDataBytesPerChunk || dev->param.inbandTags) { /* An incomplete start or end chunk (or maybe both start and end chunk), * or we're using inband tags, so we want to use the cache buffers. */ - if (dev->nShortOpCaches > 0) { + if (dev->param.nShortOpCaches > 0) { yaffs_ChunkCache *cache; /* If we can't find the data in the cache, then load the cache */ cache = yaffs_FindChunkCache(in, chunk); if (!cache - && yaffs_CheckSpaceForAllocation(in-> - myDev)) { - cache = yaffs_GrabChunkCache(in->myDev); + && yaffs_CheckSpaceForAllocation(dev, 1)) { + cache = yaffs_GrabChunkCache(dev); 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(in->myDev)) { + !yaffs_CheckSpaceForAllocation(dev, 1)) { /* Drop the cache if it was a read cache item and * no space check has been made for it. */ @@ -5003,6 +3702,14 @@ int yaffs_WriteDataToFile(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 ------------------ */ @@ -5031,10 +3738,10 @@ static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize) chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL); if (chunkId > 0) { if (chunkId < - (dev->internalStartBlock * dev->nChunksPerBlock) + (dev->internalStartBlock * dev->param.nChunksPerBlock) || chunkId >= ((dev->internalEndBlock + - 1) * dev->nChunksPerBlock)) { + 1) * dev->param.nChunksPerBlock)) { T(YAFFS_TRACE_ALWAYS, (TSTR("Found daft chunkId %d for %d" TENDSTR), chunkId, i)); @@ -5047,58 +3754,61 @@ static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize) } -int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize) + +void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize) { - - int oldFileSize = in->variant.fileVariant.fileSize; - __u32 newSizeOfPartialChunk; int newFullChunks; - - yaffs_Device *dev = in->myDev; + __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; + yaffs_FlushFilesChunkCache(in); yaffs_InvalidateWholeChunkCache(in); - yaffs_CheckGarbageCollection(dev); + yaffs_CheckGarbageCollection(dev,0); if (in->variantType != YAFFS_OBJECT_TYPE_FILE) return YAFFS_FAIL; if (newSize == oldFileSize) return YAFFS_OK; - - 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__); - } - + + if(newSize > oldFileSize){ + yaffs2_HandleHole(in,newSize); in->variant.fileVariant.fileSize = newSize; - - yaffs_PruneFileStructure(dev, &in->variant.fileVariant); } else { - /* newsSize > oldFileSize */ - in->variant.fileVariant.fileSize = newSize; - } - + /* newSize < oldFileSize */ + yaffs_ResizeDown(in, newSize); + } /* Write a new object header to reflect the resize. * show we've shrunk the file, if need be @@ -5109,21 +3819,25 @@ 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, - (newSize < oldFileSize) ? 1 : 0, 0); + yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL); + 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: - return yaffs_strlen(obj->variant.symLinkVariant.alias); + alias = obj->variant.symLinkVariant.alias; + if(!alias) + return 0; + return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH); default: return 0; } @@ -5131,23 +3845,27 @@ loff_t yaffs_GetFileSize(yaffs_Object *obj) -int yaffs_FlushFile(yaffs_Object *in, int updateTime) +int yaffs_FlushFile(yaffs_Object *in, int updateTime, int dataSync) { int retVal; if (in->dirty) { yaffs_FlushFilesChunkCache(in); - if (updateTime) { + if(dataSync) /* Only sync data */ + retVal=YAFFS_OK; + else { + 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) >= - 0) ? YAFFS_OK : YAFFS_FAIL; + retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL) >= + 0) ? YAFFS_OK : YAFFS_FAIL; + } } else { retVal = YAFFS_OK; } @@ -5162,7 +3880,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->isYaffs2 && (in->parent != in->myDev->deletedDir)) { + if (in->myDev->param.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); @@ -5186,14 +3904,10 @@ 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 = @@ -5204,7 +3918,7 @@ static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in) in->objectId)); in->deleted = 1; in->myDev->nDeletedFiles++; - if (1 || in->myDev->isYaffs2) + if (dev->param.disableSoftDelete || dev->param.isYaffs2) yaffs_ResizeFile(in, 0); yaffs_SoftDeleteFile(in); } else { @@ -5220,9 +3934,11 @@ static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in) int yaffs_DeleteFile(yaffs_Object *in) { int retVal = YAFFS_OK; - int deleted = in->deleted; + int deleted; /* Need to cache value on stack if in is freed */ + yaffs_Device *dev = in->myDev; - yaffs_ResizeFile(in, 0); + if (dev->param.disableSoftDelete || dev->param.isYaffs2) + yaffs_ResizeFile(in, 0); if (in->nDataChunks > 0) { /* Use soft deletion if there is data in the file. @@ -5231,6 +3947,8 @@ 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; @@ -5265,7 +3983,9 @@ static int yaffs_DeleteDirectory(yaffs_Object *obj) static int yaffs_DeleteSymLink(yaffs_Object *in) { - YFREE(in->variant.symLinkVariant.alias); + if(in->variant.symLinkVariant.alias) + YFREE(in->variant.symLinkVariant.alias); + in->variant.symLinkVariant.alias=NULL; return yaffs_DoGenericObjectDeletion(in); } @@ -5287,6 +4007,10 @@ 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: @@ -5311,13 +4035,8 @@ 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); @@ -5334,23 +4053,26 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj) * Instead, we do the following: * - Select a hardlink. * - Unhook it from the hard links - * - Unhook it from its parent directory (so that the rename can work) + * - Move 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); - ylist_del_init(&hl->hardLinks); - ylist_del_init(&hl->siblings); - yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1); + parent = hl->parent; - retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0); + ylist_del_init(&hl->hardLinks); + + yaffs_AddObjectToDirectory(obj->myDev->unlinkedDir, hl); + + retVal = yaffs_ChangeObjectName(obj,parent, name, 0, 0); if (retVal == YAFFS_OK) retVal = yaffs_DoGenericObjectDeletion(hl); @@ -5363,6 +4085,7 @@ 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: @@ -5403,7 +4126,7 @@ int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name) /*----------------------- Initialisation Scanning ---------------------- */ -static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, +void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, int backwardScanning) { yaffs_Object *obj; @@ -5437,13 +4160,8 @@ static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, } -typedef struct { - int seq; - int block; -} yaffs_BlockIndex; - -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList) +void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList) { yaffs_Object *hl; yaffs_Object *in; @@ -5472,29 +4190,6 @@ static 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) { /* @@ -5504,6 +4199,9 @@ 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) { @@ -5539,7 +4237,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 || @@ -5557,6 +4255,8 @@ 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. @@ -5568,7 +4268,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; @@ -5596,8 +4296,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); } } @@ -5617,7 +4317,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); @@ -5631,10 +4331,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) @@ -5642,445 +4342,6 @@ 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; @@ -6125,7 +4386,7 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) in->yst_rdev = oh->yst_rdev; #endif - yaffs_SetObjectName(in, oh->name); + yaffs_SetObjectNameFromOH(in, oh); if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { in->variant.symLinkVariant.alias = @@ -6138,749 +4399,8 @@ 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. @@ -6889,21 +4409,61 @@ static void yaffs_VerifyDirectory(yaffs_Object *directory) * 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)); + } -#if 0 - yaffs_UpdateObjectHeader(obj,NULL,0,0,0); + } else + yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL); #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; @@ -6914,8 +4474,8 @@ static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj) yaffs_VerifyDirectory(parent); - if (dev && dev->removeObjectCallback) - dev->removeObjectCallback(obj); + if (dev && dev->param.removeObjectCallback) + dev->param.removeObjectCallback(obj); ylist_del_init(&obj->siblings); @@ -6924,7 +4484,7 @@ static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj) yaffs_VerifyDirectory(parent); } -static void yaffs_AddObjectToDirectory(yaffs_Object *directory, +void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj) { if (!directory) { @@ -7078,36 +4638,124 @@ yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj) return obj; } -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize) +/* + * 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) { - 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) { + /* Create an object name if we could not find one. */ + if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 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); - } -#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM - else if (obj->shortName[0]) - yaffs_strcpy(name, obj->shortName); +} + +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 - else { + 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]) { + yaffs_strcpy(name, obj->shortName); + } +#endif + else if(obj->hdrChunk > 0) { int result; __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__); @@ -7120,14 +4768,17 @@ int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize) obj->hdrChunk, buffer, NULL); } - yaffs_strncpy(name, oh->name, buffSize - 1); + yaffs_LoadNameFromObjectHeader(obj->myDev,name,oh->name,buffSize); yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__); } - return yaffs_strlen(name); + yaffs_FixNullName(obj,name,buffSize); + + return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH); } + int yaffs_GetObjectFileLength(yaffs_Object *obj) { /* Dereference any hard linking */ @@ -7135,9 +4786,11 @@ 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) - return yaffs_strlen(obj->variant.symLinkVariant.alias); - else { + 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 { /* Only a directory should drop through to here */ return obj->myDev->nDataBytesPerChunk; } @@ -7228,7 +4881,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); + yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL); return YAFFS_OK; @@ -7261,6 +4914,123 @@ 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) { @@ -7286,30 +5056,32 @@ static int yaffs_CheckDevFunctions(const yaffs_Device *dev) { /* Common functions, gotta have */ - if (!dev->eraseBlockInNAND || !dev->initialiseNAND) + if (!dev->param.eraseBlockInNAND || !dev->param.initialiseNAND) return 0; #ifdef CONFIG_YAFFS_YAFFS2 /* Can use the "with tags" style interface for yaffs1 or yaffs2 */ - if (dev->writeChunkWithTagsToNAND && - dev->readChunkWithTagsFromNAND && - !dev->writeChunkToNAND && - !dev->readChunkFromNAND && - dev->markNANDBlockBad && dev->queryNANDBlock) + if (dev->param.writeChunkWithTagsToNAND && + dev->param.readChunkWithTagsFromNAND && + !dev->param.writeChunkToNAND && + !dev->param.readChunkFromNAND && + dev->param.markNANDBlockBad && + dev->param.queryNANDBlock) return 1; #endif /* Can use the "spare" style interface for yaffs1 */ - if (!dev->isYaffs2 && - !dev->writeChunkWithTagsToNAND && - !dev->readChunkWithTagsFromNAND && - dev->writeChunkToNAND && - dev->readChunkFromNAND && - !dev->markNANDBlockBad && !dev->queryNANDBlock) + if (!dev->param.isYaffs2 && + !dev->param.writeChunkWithTagsToNAND && + !dev->param.readChunkWithTagsFromNAND && + dev->param.writeChunkToNAND && + dev->param.readChunkFromNAND && + !dev->param.markNANDBlockBad && + !dev->param.queryNANDBlock) return 1; - return 0; /* bad */ + return 0; /* bad */ } @@ -7356,35 +5128,35 @@ int yaffs_GutsInitialise(yaffs_Device *dev) return YAFFS_FAIL; } - dev->internalStartBlock = dev->startBlock; - dev->internalEndBlock = dev->endBlock; + dev->internalStartBlock = dev->param.startBlock; + dev->internalEndBlock = dev->param.endBlock; dev->blockOffset = 0; dev->chunkOffset = 0; dev->nFreeChunks = 0; - dev->gcBlock = -1; + dev->gcBlock = 0; - if (dev->startBlock == 0) { - dev->internalStartBlock = dev->startBlock + 1; - dev->internalEndBlock = dev->endBlock + 1; + if (dev->param.startBlock == 0) { + dev->internalStartBlock = dev->param.startBlock + 1; + dev->internalEndBlock = dev->param.endBlock + 1; dev->blockOffset = 1; - dev->chunkOffset = dev->nChunksPerBlock; + dev->chunkOffset = dev->param.nChunksPerBlock; } /* Check geometry parameters. */ - if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) || - (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) || - (dev->inbandTags && !dev->isYaffs2) || - dev->nChunksPerBlock < 2 || - dev->nReservedBlocks < 2 || + 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 || dev->internalStartBlock <= 0 || dev->internalEndBlock <= 0 || - dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) { /* otherwise it is too small */ + dev->internalEndBlock <= (dev->internalStartBlock + dev->param.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->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags)); + TENDSTR), dev->param.totalBytesPerChunk, dev->param.isYaffs2 ? "2" : "", dev->param.inbandTags)); return YAFFS_FAIL; } @@ -7395,10 +5167,10 @@ int yaffs_GutsInitialise(yaffs_Device *dev) } /* Sort out space for inband tags, if required */ - if (dev->inbandTags) - dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart); + if (dev->param.inbandTags) + dev->nDataBytesPerChunk = dev->param.totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart); else - dev->nDataBytesPerChunk = dev->totalBytesPerChunk; + dev->nDataBytesPerChunk = dev->param.totalBytesPerChunk; /* Got the right mix of functions? */ if (!yaffs_CheckDevFunctions(dev)) { @@ -7445,12 +5217,12 @@ int yaffs_GutsInitialise(yaffs_Device *dev) * We need to find the next power of 2 > than internalEndBlock */ - x = dev->nChunksPerBlock * (dev->internalEndBlock + 1); + x = dev->param.nChunksPerBlock * (dev->internalEndBlock + 1); bits = ShiftsGE(x); /* Set up tnode width if wide tnodes are enabled. */ - if (!dev->wideTnodesDisabled) { + if (!dev->param.wideTnodesDisabled) { /* bits must be even so that we end up with 32-bit words */ if (bits & 1) bits++; @@ -7474,10 +5246,13 @@ 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->nChunksPerBlock < dev->chunkGroupSize) { + if (dev->param.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". @@ -7491,9 +5266,11 @@ int yaffs_GutsInitialise(yaffs_Device *dev) /* OK, we've finished verifying the device, lets continue with initialisation */ /* More device initialisation */ - dev->garbageCollections = 0; - dev->passiveGarbageCollections = 0; - dev->currentDirtyChecker = 0; + dev->allGCs = 0; + dev->passiveGCs = 0; + dev->oldestDirtyGCs = 0; + dev->backgroundGCs = 0; + dev->gcBlockFinder = 0; dev->bufferedBlock = -1; dev->doingBufferedBlockRewrite = 0; dev->nDeletedFiles = 0; @@ -7505,9 +5282,11 @@ int yaffs_GutsInitialise(yaffs_Device *dev) dev->tagsEccUnfixed = 0; dev->nErasureFailures = 0; dev->nErasedBlocks = 0; - dev->isDoingGC = 0; + dev->gcDisable= 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)) @@ -7518,13 +5297,13 @@ int yaffs_GutsInitialise(yaffs_Device *dev) if (!init_failed && - dev->nShortOpCaches > 0) { + dev->param.nShortOpCaches > 0) { int i; void *buf; - int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache); + int srCacheBytes = dev->param.nShortOpCaches * sizeof(yaffs_ChunkCache); - if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) - dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; + if (dev->param.nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) + dev->param.nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; dev->srCache = YMALLOC(srCacheBytes); @@ -7533,11 +5312,11 @@ int yaffs_GutsInitialise(yaffs_Device *dev) if (dev->srCache) memset(dev->srCache, 0, srCacheBytes); - for (i = 0; i < dev->nShortOpCaches && buf; i++) { + for (i = 0; i < dev->param.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->totalBytesPerChunk); + dev->srCache[i].data = buf = YMALLOC_DMA(dev->param.totalBytesPerChunk); } if (!buf) init_failed = 1; @@ -7548,19 +5327,18 @@ int yaffs_GutsInitialise(yaffs_Device *dev) dev->cacheHits = 0; if (!init_failed) { - dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); + dev->gcCleanupList = YMALLOC(dev->param.nChunksPerBlock * sizeof(__u32)); if (!dev->gcCleanupList) init_failed = 1; } - if (dev->isYaffs2) - dev->useHeaderFileSize = 1; + if (dev->param.isYaffs2) + dev->param.useHeaderFileSize = 1; if (!init_failed && !yaffs_InitialiseBlocks(dev)) init_failed = 1; - yaffs_InitialiseTnodes(dev); - yaffs_InitialiseObjects(dev); + yaffs_InitialiseTnodesAndObjects(dev); if (!init_failed && !yaffs_CreateInitialDirectories(dev)) init_failed = 1; @@ -7568,8 +5346,8 @@ int yaffs_GutsInitialise(yaffs_Device *dev) if (!init_failed) { /* Now scan the flash. */ - if (dev->isYaffs2) { - if (yaffs_CheckpointRestore(dev)) { + if (dev->param.isYaffs2) { + if (yaffs2_CheckpointRestore(dev)) { yaffs_CheckObjectDetailsLoaded(dev->rootDir); T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: restored from checkpoint" TENDSTR))); @@ -7579,9 +5357,8 @@ 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; @@ -7594,21 +5371,20 @@ int yaffs_GutsInitialise(yaffs_Device *dev) if (!init_failed && !yaffs_InitialiseBlocks(dev)) init_failed = 1; - yaffs_InitialiseTnodes(dev); - yaffs_InitialiseObjects(dev); + yaffs_InitialiseTnodesAndObjects(dev); if (!init_failed && !yaffs_CreateInitialDirectories(dev)) init_failed = 1; - if (!init_failed && !yaffs_ScanBackwards(dev)) + if (!init_failed && !yaffs2_ScanBackwards(dev)) init_failed = 1; } - } else if (!yaffs_Scan(dev)) + } else if (!yaffs1_Scan(dev)) init_failed = 1; yaffs_StripDeletedObjects(dev); yaffs_FixHangingObjects(dev); - if(dev->emptyLostAndFound) + if(dev->param.emptyLostAndFound) yaffs_EmptyLostAndFound(dev); } @@ -7634,8 +5410,8 @@ int yaffs_GutsInitialise(yaffs_Device *dev) yaffs_VerifyBlocks(dev); /* Clean up any aborted checkpoint data */ - if (!dev->isCheckpointed && dev->blocksInCheckpoint > 0) - yaffs_InvalidateCheckpoint(dev); + if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0) + yaffs2_InvalidateCheckpoint(dev); T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); @@ -7649,12 +5425,11 @@ void yaffs_Deinitialise(yaffs_Device *dev) int i; yaffs_DeinitialiseBlocks(dev); - yaffs_DeinitialiseTnodes(dev); - yaffs_DeinitialiseObjects(dev); - if (dev->nShortOpCaches > 0 && + yaffs_DeinitialiseTnodesAndObjects(dev); + if (dev->param.nShortOpCaches > 0 && dev->srCache) { - for (i = 0; i < dev->nShortOpCaches; i++) { + for (i = 0; i < dev->param.nShortOpCaches; i++) { if (dev->srCache[i].data) YFREE(dev->srCache[i].data); dev->srCache[i].data = NULL; @@ -7671,34 +5446,33 @@ void yaffs_Deinitialise(yaffs_Device *dev) dev->isMounted = 0; - if (dev->deinitialiseNAND) - dev->deinitialiseNAND(dev); + if (dev->param.deinitialiseNAND) + dev->param.deinitialiseNAND(dev); } } -static int yaffs_CountFreeChunks(yaffs_Device *dev) +int yaffs_CountFreeChunks(yaffs_Device *dev) { - int nFree; + int nFree=0; int b; yaffs_BlockInfo *blk; - for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; - b++) { - blk = yaffs_GetBlockInfo(dev, b); - + blk = dev->blockInfo; + for (b = dev->internalStartBlock; b <= dev->internalEndBlock; 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->nChunksPerBlock - blk->pagesInUse + + (dev->param.nChunksPerBlock - blk->pagesInUse + blk->softDeletions); break; default: break; } + blk++; } return nFree; @@ -7723,21 +5497,19 @@ 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->nShortOpCaches; i++) { + for (nDirtyCacheChunks = 0, i = 0; i < dev->param.nShortOpCaches; i++) { if (dev->srCache[i].dirty) nDirtyCacheChunks++; } nFree -= nDirtyCacheChunks; - nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); + nFree -= ((dev->param.nReservedBlocks + 1) * dev->param.nChunksPerBlock); /* Now we figure out how much to reserve for the checkpoint and report that... */ - blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; - if (blocksForCheckpoint < 0) - blocksForCheckpoint = 0; + blocksForCheckpoint = yaffs2_CalcCheckpointBlocksRequired(dev); - nFree -= (blocksForCheckpoint * dev->nChunksPerBlock); + nFree -= (blocksForCheckpoint * dev->param.nChunksPerBlock); if (nFree < 0) nFree = 0; @@ -7746,27 +5518,6 @@ 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 ----------------------*/ @@ -7774,7 +5525,7 @@ static void yaffs_VerifyFreeChunks(yaffs_Device *dev) do { \ if (sizeof(structure) != syze) { \ T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\ - name, syze, sizeof(structure))); \ + name, syze, (int) sizeof(structure))); \ return YAFFS_FAIL; \ } \ } while (0) @@ -7784,9 +5535,8 @@ 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"); */ -#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG - yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); -#endif +/* yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); */ + #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 1305909e..4dc70a2a 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -16,8 +16,9 @@ #ifndef __YAFFS_GUTS_H__ #define __YAFFS_GUTS_H__ -#include "devextras.h" #include "yportenv.h" +#include "devextras.h" +#include "yaffs_list.h" #define YAFFS_OK 1 #define YAFFS_FAIL 0 @@ -52,7 +53,6 @@ #define YAFFS_MAX_CHUNK_ID 0x000FFFFF -#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF #define YAFFS_ALLOCATION_NOBJECTS 100 #define YAFFS_ALLOCATION_NTNODES 100 @@ -62,8 +62,9 @@ #define YAFFS_OBJECT_SPACE 0x40000 +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1) -#define YAFFS_CHECKPOINT_VERSION 3 +#define YAFFS_CHECKPOINT_VERSION 4 #ifdef CONFIG_YAFFS_UNICODE #define YAFFS_MAX_NAME_LENGTH 127 @@ -81,12 +82,11 @@ #define YAFFS_OBJECTID_UNLINKED 3 #define YAFFS_OBJECTID_DELETED 4 -/* Sseudo object ids for checkpointing */ +/* Pseudo 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,11 +119,7 @@ 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; @@ -234,6 +230,8 @@ 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. @@ -249,21 +247,23 @@ 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 + * allocation. Should never be more than one of these. + * If a block is only partially allocated at mount it is treated as full. */ 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, - /* All pages have been allocated and deleted. + /* The block was full and now all chunks have been 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,23 +351,12 @@ 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: @@ -387,6 +376,7 @@ 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 { @@ -405,6 +395,8 @@ 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 */ @@ -424,7 +416,10 @@ 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 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 serial; /* serial number of chunk in NAND. Cached here */ __u16 sum; /* sum of the name to speed searching */ @@ -453,10 +448,6 @@ 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]; @@ -471,10 +462,7 @@ struct yaffs_ObjectStruct { __u32 yst_rdev; -#ifdef __KERNEL__ - struct inode *myInode; - -#endif + void *myInode; yaffs_ObjectType variantType; @@ -484,13 +472,6 @@ 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; @@ -532,12 +513,18 @@ typedef struct { /*----------------- Device ---------------------------------*/ -struct yaffs_DeviceStruct { - struct ylist_head devList; - const char *name; - /* Entry parameters set up way early. Yaffs sets up the rest.*/ - int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */ +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 */ 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 */ @@ -546,26 +533,24 @@ struct yaffs_DeviceStruct { /* 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) + * the number of short op caches (don't use too many). + * 10 to 20 is a good bet. */ + 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 useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */ + int isYaffs2; /* Use yaffs2 mode on this device */ - int emptyLostAndFound; /* Flasg to determine if lst+found should be emptied on init */ + int emptyLostAndFound; /* Auto-empty lost+found directory on mount */ - int useNANDECC; /* Flag to decide whether or not to use NANDECC */ + int refreshPeriod; /* How often we should check to do a block refresh */ - void *genericDevice; /* Pointer to device context - * On an mtd this holds the mtd pointer. - */ - void *superBlock; + /* Checkpoint control. Can be set before or after initialisation */ + __u8 skipCheckpointRead; + __u8 skipCheckpointWrite; + + int enableXattr; /* Enable xattribs */ /* NAND access functions (Must be set before calling YAFFS)*/ @@ -592,8 +577,6 @@ struct yaffs_DeviceStruct { 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. @@ -601,54 +584,61 @@ struct yaffs_DeviceStruct { */ void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj); - /* Callback to mark the superblock dirsty */ - void (*markSuperBlockDirty)(void *superblock); + /* Callback to mark the superblock dirty */ + void (*markSuperBlockDirty)(struct yaffs_DeviceStruct *dev); + + /* Callback to control garbage collection. */ + unsigned (*gcControl)(struct yaffs_DeviceStruct *dev); + /* 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 */ - YCHAR *pathDividers; /* String of legal path dividers */ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + int autoUnicode; +#endif + int alwaysCheckErased; /* Force chunk erased check always on */ +}; +typedef struct yaffs_DeviceParamStruct yaffs_DeviceParam; - /* End of stuff that must be set before initialisation. */ +struct yaffs_DeviceStruct { + struct yaffs_DeviceParamStruct param; - /* Checkpoint control. Can be set before or after initialisation */ - __u8 skipCheckpointRead; - __u8 skipCheckpointWrite; + /* Context storage. Holds extra OS specific data for this device */ + + void *osContext; + void *driverContext; + + struct ylist_head devList; /* Runtime parameters. Set up by YAFFS. */ + int nDataBytesPerChunk; - __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */ + /* Non-wide tnode stuff */ + __u16 chunkGroupBits; /* Number of bits that need to be resolved if + * the tnodes are not wide enough. + */ __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; @@ -690,51 +680,31 @@ struct yaffs_DeviceStruct { __u32 allocationPage; int allocationBlockFinder; /* Used to search for next allocation block */ - /* 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; + /* Object and Tnode memory management */ + void *allocator; + int nObjects; + int nTnodes; int nHardLinks; - yaffs_ObjectList *allocatedObjectList; - yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS]; + __u32 bucketFinder; int nFreeChunks; - int currentDirtyChecker; /* Used to find current dirtiest block */ - + /* Garbage collection control */ __u32 *gcCleanupList; /* objects to delete at the end of a GC. */ - int nonAggressiveSkip; /* GC state/mode */ + __u32 nCleanups; - /* 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 */ + 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; /* Special directories */ yaffs_Object *rootDir; @@ -751,8 +721,6 @@ 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. */ @@ -761,7 +729,6 @@ 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; @@ -772,6 +739,36 @@ 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; }; @@ -804,7 +801,6 @@ typedef struct { /* yaffs2 runtime stuff */ unsigned sequenceNumber; /* Sequence number of currently allocating block */ - unsigned oldestDirtySequence; } yaffs_CheckpointDevice; @@ -817,6 +813,23 @@ 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); @@ -848,7 +861,8 @@ 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 yaffs_FlushFile(yaffs_Object *obj, int updateTime, int dataSync); /* Flushing and checkpointing */ void yaffs_FlushEntireDeviceCache(yaffs_Device *dev); @@ -881,6 +895,12 @@ 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); @@ -890,18 +910,18 @@ yaffs_Object *yaffs_LostNFound(yaffs_Device *dev); void yfsd_WinFileTimeNow(__u32 target[2]); #endif -#ifdef __KERNEL__ - void yaffs_HandleDeferedFree(yaffs_Object *obj); -#endif + +void yaffs_UpdateDirtyDirectories(yaffs_Device *dev); + +int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency); /* Debug dump */ int yaffs_DumpObject(yaffs_Object *obj); void yaffs_GutsTest(yaffs_Device *dev); -/* A few useful functions */ -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags); +/* A few useful functions to be used within the core files*/ 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); @@ -909,4 +929,41 @@ 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 new file mode 100644 index 00000000..ce059fd2 --- /dev/null +++ b/fs/yaffs2/yaffs_linux.h @@ -0,0 +1,43 @@ +/* + * 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 new file mode 100644 index 00000000..d4205fa2 --- /dev/null +++ b/fs/yaffs2/yaffs_linux_allocator.c @@ -0,0 +1,200 @@ +/* + * 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 new file mode 100644 index 00000000..09d80b85 --- /dev/null +++ b/fs/yaffs2/yaffs_list.h @@ -0,0 +1,127 @@ +/* + * 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 72f64203..e073a5ef 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -11,9 +11,6 @@ * published by the Free Software Foundation. */ -const char *yaffs_mtdif_c_version = - "$Id$"; - #include "yportenv.h" @@ -24,208 +21,26 @@ const char *yaffs_mtdif_c_version = #include "linux/time.h" #include "linux/mtd/nand.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; -} +#include "yaffs_linux.h" int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) { - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); + struct mtd_info *mtd = yaffs_DeviceToMtd(dev); __u32 addr = - ((loff_t) blockNumber) * dev->nDataBytesPerChunk - * dev->nChunksPerBlock; + ((loff_t) blockNumber) * dev->param.totalBytesPerChunk + * dev->param.nChunksPerBlock; struct erase_info ei; + int retval = 0; ei.mtd = mtd; ei.addr = addr; - ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock; + ei.len = dev->param.totalBytesPerChunk * dev->param.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 e72cfcdd..fad9d287 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -22,11 +22,6 @@ 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 bcac4702..b14a2549 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 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * This program is free software; you can redistribute it and/or modify @@ -24,9 +24,11 @@ */ #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" @@ -36,8 +38,6 @@ /* 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 = dev->genericDevice; + struct mtd_info *mtd = yaffs_DeviceToMtd(dev); 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) { - yaffs_trace(YAFFS_TRACE_MTD, - "write_oob failed, chunk %d, mtd error %d\n", - chunkInNAND, retval); + T(YAFFS_TRACE_MTD, + (TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR), + 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 = dev->genericDevice; + struct mtd_info *mtd = yaffs_DeviceToMtd(dev); 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) { - yaffs_trace(YAFFS_TRACE_MTD, - "read_oob failed, chunk %d, mtd error %d\n", - chunkInNAND, retval); + T(YAFFS_TRACE_MTD, + (TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR), + 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 = dev->genericDevice; - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; + struct mtd_info *mtd = yaffs_DeviceToMtd(dev); + int blocksize = dev->param.nChunksPerBlock * dev->nDataBytesPerChunk; int retval; - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo); + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), 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) { - yaffs_trace(YAFFS_TRACE_ERROR, - "mtd device has only %d bytes for tags, need %d\n", - oobavail, YTAG1_SIZE); + T(YAFFS_TRACE_ERROR, + (TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR), + 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 = dev->genericDevice; - int chunkNo = blockNo * dev->nChunksPerBlock; + struct mtd_info *mtd = yaffs_DeviceToMtd(dev); + int chunkNo = blockNo * dev->param.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) { - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, - "block %d is marked bad\n", blockNo); + T(YAFFS_TRACE_BAD_BLOCKS, + (TSTR("block %d is marked bad"TENDSTR), 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 240202cd..0e6a56fb 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 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 0c4746bb..2b0a601f 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -13,11 +13,8 @@ /* mtd interface for YAFFS2 */ -const char *yaffs_mtdif2_c_version = - "$Id$"; - #include "yportenv.h" - +#include "yaffs_trace.h" #include "yaffs_mtdif2.h" @@ -27,11 +24,7 @@ const char *yaffs_mtdif2_c_version = #include "yaffs_packedtags2.h" -#ifdef CONFIG_YAFFS_DOES_ECC -#define OOB_TAGS_SIZE sizeof(yaffs_PackedTags2) -#else -#define OOB_TAGS_SIZE sizeof(yaffs_PackedTags2TagsPart) -#endif +#include "yaffs_linux.h" /* NB For use with inband tags.... * We assume that the data buffer is of size totalBytersPerChunk so that we can also @@ -41,7 +34,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *tags) { - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); + struct mtd_info *mtd = yaffs_DeviceToMtd(dev); #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) struct mtd_oob_ops ops; #else @@ -53,12 +46,16 @@ 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->totalBytesPerChunk; + + addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk; /* For yaffs2 writing there must be both data and tags. * If we're using inband tags, then the tags are stuffed into @@ -66,30 +63,30 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, */ if (!data || !tags) BUG(); - else if (dev->inbandTags) { + else if (dev->param.inbandTags) { yaffs_PackedTags2TagsPart *pt2tp; pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); yaffs_PackTags2TagsPart(pt2tp, tags); } else - yaffs_PackTags2(&pt, tags); + yaffs_PackTags2(&pt, tags, !dev->param.noTagsECC); #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ops.mode = MTD_OOB_AUTO; - ops.ooblen = (dev->inbandTags) ? 0 : OOB_TAGS_SIZE; - ops.len = dev->totalBytesPerChunk; + ops.ooblen = (dev->param.inbandTags) ? 0 : packed_tags_size; + ops.len = dev->param.totalBytesPerChunk; ops.ooboffs = 0; ops.datbuf = (__u8 *)data; - ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt; + ops.oobbuf = (dev->param.inbandTags) ? NULL : packed_tags_ptr; retval = mtd->write_oob(mtd, addr, &ops); #else - if (!dev->inbandTags) { + if (!dev->param.inbandTags) { retval = mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, (__u8 *) &pt, NULL); + &dummy, data, (__u8 *) packed_tags_ptr, NULL); } else { retval = - mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy, + mtd->write(mtd, addr, dev->param.totalBytesPerChunk, &dummy, data); } #endif @@ -103,7 +100,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 = (struct mtd_info *)(dev->genericDevice); + struct mtd_info *mtd = yaffs_DeviceToMtd(dev); #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) struct mtd_oob_ops ops; #endif @@ -111,16 +108,19 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, int retval = 0; int localData = 0; - loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; + loff_t addr = ((loff_t) chunkInNAND) * dev->param.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->inbandTags) { + if (dev->param.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->inbandTags || (data && !tags)) - retval = mtd->read(mtd, addr, dev->totalBytesPerChunk, + if (dev->param.inbandTags || (data && !tags)) + retval = mtd->read(mtd, addr, dev->param.totalBytesPerChunk, &dummy, data); else if (tags) { ops.mode = MTD_OOB_AUTO; - ops.ooblen = OOB_TAGS_SIZE; - ops.len = data ? dev->nDataBytesPerChunk : OOB_TAGS_SIZE; + ops.ooblen = packed_tags_size; + ops.len = data ? dev->nDataBytesPerChunk : packed_tags_size; ops.ooboffs = 0; ops.datbuf = data; - ops.oobbuf = dev->spareBuffer; + ops.oobbuf = yaffs_DeviceToLC(dev)->spareBuffer; retval = mtd->read_oob(mtd, addr, &ops); } #else - if (!dev->inbandTags && data && tags) { + if (!dev->param.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->inbandTags && tags) + if (!dev->param.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->inbandTags) { + if (dev->param.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(&pt, dev->spareBuffer, OOB_TAGS_SIZE); - yaffs_UnpackTags2(tags, &pt); + memcpy(packed_tags_ptr, yaffs_DeviceToLC(dev)->spareBuffer, packed_tags_size); + yaffs_UnpackTags2(tags, &pt, !dev->param.noTagsECC); } } @@ -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 = (struct mtd_info *)(dev->genericDevice); + struct mtd_info *mtd = yaffs_DeviceToMtd(dev); int retval; T(YAFFS_TRACE_MTD, (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo)); retval = mtd->block_markbad(mtd, - blockNo * dev->nChunksPerBlock * - dev->totalBytesPerChunk); + blockNo * dev->param.nChunksPerBlock * + dev->param.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 = (struct mtd_info *)(dev->genericDevice); + struct mtd_info *mtd = yaffs_DeviceToMtd(dev); int retval; T(YAFFS_TRACE_MTD, (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo)); retval = mtd->block_isbad(mtd, - blockNo * dev->nChunksPerBlock * - dev->totalBytesPerChunk); + blockNo * dev->param.nChunksPerBlock * + dev->param.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->nChunksPerBlock, NULL, + dev->param.nChunksPerBlock, NULL, &t); if (t.chunkUsed) { diff --git a/fs/yaffs2/yaffs_mtdif2.h b/fs/yaffs2/yaffs_mtdif2.h index b5ff0788..5691267e 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 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 new file mode 100644 index 00000000..a4ed2973 --- /dev/null +++ b/fs/yaffs2/yaffs_nameval.c @@ -0,0 +1,197 @@ +/* + * 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 new file mode 100644 index 00000000..4255f3b0 --- /dev/null +++ b/fs/yaffs2/yaffs_nameval.h @@ -0,0 +1,25 @@ +/* + * 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 f6ba4c79..6964ad18 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -11,9 +11,6 @@ * 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" @@ -35,8 +32,8 @@ int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, if (!tags) tags = &localTags; - if (dev->readChunkWithTagsFromNAND) - result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer, + if (dev->param.readChunkWithTagsFromNAND) + result = dev->param.readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer, tags); else result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev, @@ -46,7 +43,8 @@ int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, if (tags && tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) { - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock); + yaffs_BlockInfo *bi; + bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->param.nChunksPerBlock); yaffs_HandleChunkError(dev, bi); } @@ -80,8 +78,8 @@ int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev, YBUG(); } - if (dev->writeChunkWithTagsToNAND) - return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer, + if (dev->param.writeChunkWithTagsToNAND) + return dev->param.writeChunkWithTagsToNAND(dev, chunkInNAND, buffer, tags); else return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev, @@ -95,8 +93,8 @@ int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo) blockNo -= dev->blockOffset; - if (dev->markNANDBlockBad) - return dev->markNANDBlockBad(dev, blockNo); + if (dev->param.markNANDBlockBad) + return dev->param.markNANDBlockBad(dev, blockNo); else return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo); } @@ -108,8 +106,8 @@ int yaffs_QueryInitialBlockState(yaffs_Device *dev, { blockNo -= dev->blockOffset; - if (dev->queryNANDBlock) - return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber); + if (dev->param.queryNANDBlock) + return dev->param.queryNANDBlock(dev, blockNo, state, sequenceNumber); else return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo, state, @@ -126,14 +124,16 @@ int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, dev->nBlockErasures++; - result = dev->eraseBlockInNAND(dev, blockInNAND); + result = dev->param.eraseBlockInNAND(dev, blockInNAND); return result; } int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev) { - return dev->initialiseNAND(dev); + if(dev->param.initialiseNAND) + return dev->param.initialiseNAND(dev); + return YAFFS_OK; } diff --git a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h index e013cdc2..62a46659 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 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 41bc2b5f..2f4ce97b 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 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 3e67e691..b2160c08 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 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 f8c0471d..b9cf1a8b 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 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 62efec02..f8ae94cc 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -13,6 +13,7 @@ #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 @@ -37,9 +38,6 @@ #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) { @@ -99,17 +97,14 @@ void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt, } -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t) +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC) { yaffs_PackTags2TagsPart(&pt->t, t); -#ifndef YAFFS_IGNORE_TAGS_ECC - { + if(tagsECC) yaffs_ECCCalculateOther((unsigned char *)&pt->t, sizeof(yaffs_PackedTags2TagsPart), &pt->ecc); - } -#endif } @@ -161,27 +156,24 @@ void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, } -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt) +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC) { yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR; - 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) { + 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) { case 0: eccResult = YAFFS_ECC_RESULT_NO_ERROR; break; @@ -193,9 +185,7 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt) break; default: eccResult = YAFFS_ECC_RESULT_UNKNOWN; - } } -#endif } yaffs_UnpackTags2TagsPart(t, &pt->t); @@ -204,6 +194,5 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt) yaffs_DumpPackedTags2(pt); yaffs_DumpTags2(t); - } diff --git a/fs/yaffs2/yaffs_packedtags2.h b/fs/yaffs2/yaffs_packedtags2.h index ec30f843..c132a98c 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 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); -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt); +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC); +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC); /* 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 941c7a87..4a4981b3 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -17,7 +17,18 @@ #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 e3173cc2..e9ac51d7 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -15,6 +15,7 @@ #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 @@ -163,14 +164,14 @@ static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev, int chunkInNAND, const __u8 *data, yaffs_Spare *spare) { - if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) { + if (chunkInNAND < dev->param.startBlock * dev->param.nChunksPerBlock) { T(YAFFS_TRACE_ERROR, (TSTR("**>> yaffs chunk %d is not valid" TENDSTR), chunkInNAND)); return YAFFS_FAIL; } - return dev->writeChunkToNAND(dev, chunkInNAND, data, spare); + return dev->param.writeChunkToNAND(dev, chunkInNAND, data, spare); } static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, @@ -189,8 +190,8 @@ static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, spare = &localSpare; } - if (!dev->useNANDECC) { - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare); + if (!dev->param.useNANDECC) { + retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data, spare); if (data && doErrorCorrection) { /* Do ECC correction */ /* Todo handle any errors */ @@ -251,7 +252,7 @@ static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, memset(&nspare, 0, sizeof(nspare)); - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, + retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) &nspare); memcpy(spare, &nspare, sizeof(yaffs_Spare)); if (data && doErrorCorrection) { @@ -304,10 +305,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->useNANDECC == true; */ + /* dev->param.useNANDECC == true; */ static __u8 spare[sizeof(struct yaffs_NANDSpare)]; - dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare); + dev->param.readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare); if (!init) { memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK); @@ -330,7 +331,7 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND) { - int blockInNAND = chunkInNAND / dev->nChunksPerBlock; + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock; /* Mark the block for retirement */ yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1; @@ -362,7 +363,7 @@ static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND) { - int blockInNAND = chunkInNAND / dev->nChunksPerBlock; + int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock; /* Mark the block for retirement */ yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; @@ -421,7 +422,7 @@ int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, tags.serialNumber = eTags->serialNumber; - if (!dev->useNANDECC && data) + if (!dev->param.useNANDECC && data) yaffs_CalcECC(data, &spare); yaffs_LoadTagsIntoSpare(&spare, &tags); @@ -495,9 +496,9 @@ int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, spare.blockStatus = 'Y'; - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL, + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock, NULL, &spare); - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock + 1, NULL, &spare); return YAFFS_OK; @@ -522,9 +523,9 @@ int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, *sequenceNumber = 0; - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL, + yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock, NULL, &spare0, &dummy, 1); - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL, + yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.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 6f95119e..8c663db5 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 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 5233bcba..93ad08c1 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 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 cb11884b..60a1aea6 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 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 new file mode 100644 index 00000000..8b848edb --- /dev/null +++ b/fs/yaffs2/yaffs_trace.h @@ -0,0 +1,60 @@ +/* + * 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 new file mode 100644 index 00000000..a600aa6b --- /dev/null +++ b/fs/yaffs2/yaffs_verify.c @@ -0,0 +1,626 @@ +/* + * 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 new file mode 100644 index 00000000..8a6f7510 --- /dev/null +++ b/fs/yaffs2/yaffs_verify.h @@ -0,0 +1,39 @@ +/* + * 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_fs.c b/fs/yaffs2/yaffs_vfs_glue.c similarity index 59% rename from fs/yaffs2/yaffs_fs.c rename to fs/yaffs2/yaffs_vfs_glue.c index 2c89d16b..c61da67d 100644 --- a/fs/yaffs2/yaffs_fs.c +++ b/fs/yaffs2/yaffs_vfs_glue.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2009 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -31,14 +31,41 @@ * >> inode->u.generic_ip points to the associated yaffs_Object. */ -const char *yaffs_fs_c_version = - "$Id$"; -extern const char *yaffs_guts_c_version; - +/* + * There are two variants of the VFS glue code. This variant should compile + * for any version of Linux. + */ #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 @@ -52,12 +79,28 @@ extern const char *yaffs_guts_c_version; #include #include -#include "asm/div64.h" +#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 #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) @@ -83,6 +126,12 @@ extern const char *yaffs_guts_c_version; #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) @@ -109,28 +158,36 @@ 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 +#include "yaffs_linux.h" + #include "yaffs_mtdif.h" #include "yaffs_mtdif1.h" #include "yaffs_mtdif2.h" -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS; +unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS; 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)) @@ -146,8 +203,6 @@ 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 @@ -181,8 +236,12 @@ 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); @@ -233,8 +292,12 @@ 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)) @@ -243,6 +306,15 @@ 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, @@ -261,12 +333,20 @@ 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 (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) +#if (YAFFS_NEW_FOLLOW_LINK == 1) +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias); 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, @@ -279,6 +359,7 @@ 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, @@ -320,14 +401,40 @@ 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 = { @@ -341,12 +448,19 @@ 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 = { @@ -359,25 +473,123 @@ 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_OS, ("yaffs locking %p\n", current)); - down(&dev->grossLock); - T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current)); + 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)); } static void yaffs_GrossUnlock(yaffs_Device *dev) { - T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current)); - up(&dev->grossLock); + T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current)); + up(&(yaffs_DeviceToLC(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 @@ -425,7 +637,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,&dev->searchContexts); + ylist_add(&sc->others,&(yaffs_DeviceToLC(dev)->searchContexts)); } return sc; } @@ -474,7 +686,7 @@ static void yaffs_RemoveObjectCallback(yaffs_Object *obj) struct ylist_head *i; struct yaffs_SearchContext *sc; - struct ylist_head *search_contexts = &obj->myDev->searchContexts; + struct ylist_head *search_contexts = &(yaffs_DeviceToLC(obj->myDev)->searchContexts); /* Iterate through the directory search contexts. @@ -516,7 +728,7 @@ static int yaffs_readlink(struct dentry *dentry, char __user *buffer, return ret; } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) +#if (YAFFS_NEW_FOLLOW_LINK == 1) static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) #else static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) @@ -529,7 +741,6 @@ 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) { @@ -537,16 +748,25 @@ 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); @@ -566,10 +786,11 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev; - yaffs_GrossLock(dev); + if(current != yaffs_DeviceToLC(dev)->readdirProcess) + yaffs_GrossLock(dev); T(YAFFS_TRACE_OS, - ("yaffs_lookup for %d:%s\n", + (TSTR("yaffs_lookup for %d:%s\n"), yaffs_InodeToObject(dir)->objectId, dentry->d_name.name)); obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir), @@ -578,17 +799,18 @@ 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() */ - yaffs_GrossUnlock(dev); + if(current != yaffs_DeviceToLC(dev)->readdirProcess) + yaffs_GrossUnlock(dev); if (obj) { T(YAFFS_TRACE_OS, - ("yaffs_lookup found %d\n", obj->objectId)); + (TSTR("yaffs_lookup found %d\n"), obj->objectId)); inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); if (inode) { T(YAFFS_TRACE_OS, - ("yaffs_loookup dentry \n")); + (TSTR("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 @@ -601,7 +823,7 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) } } else { - T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n")); + T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n"))); } @@ -621,13 +843,75 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) static void yaffs_put_inode(struct inode *inode) { T(YAFFS_TRACE_OS, - ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino, + (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino, atomic_read(&inode->i_count))); } #endif -/* clear is called to tell the fs to release any per-inode data it holds */ + +static void yaffs_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() + */ + static void yaffs_clear_inode(struct inode *inode) { yaffs_Object *obj; @@ -636,27 +920,14 @@ static void yaffs_clear_inode(struct inode *inode) obj = yaffs_InodeToObject(inode); T(YAFFS_TRACE_OS, - ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino, + (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino, atomic_read(&inode->i_count), obj ? "object exists" : "null object")); if (obj) { dev = obj->myDev; yaffs_GrossLock(dev); - - /* Clear the association between the inode and - * the yaffs_Object. - */ - obj->myInode = NULL; - yaffs_InodeToObjectLV(inode) = NULL; - - /* If the object freeing was deferred, then the real - * free happens now. - * This should fix the inode inconsistency problem. - */ - - yaffs_HandleDeferedFree(obj); - + yaffs_UnstitchObject(inode,obj); yaffs_GrossUnlock(dev); } @@ -673,7 +944,7 @@ static void yaffs_delete_inode(struct inode *inode) yaffs_Device *dev; T(YAFFS_TRACE_OS, - ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino, + (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino, atomic_read(&inode->i_count), obj ? "object exists" : "null object")); @@ -688,6 +959,8 @@ 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) @@ -700,19 +973,18 @@ static int yaffs_file_flush(struct file *file) yaffs_Device *dev = obj->myDev; T(YAFFS_TRACE_OS, - ("yaffs_file_flush object %d (%s)\n", obj->objectId, + (TSTR("yaffs_file_flush object %d (%s)\n"), obj->objectId, obj->dirty ? "dirty" : "clean")); yaffs_GrossLock(dev); - yaffs_FlushFile(obj, 1); + yaffs_FlushFile(obj, 1, 0); yaffs_GrossUnlock(dev); return 0; } -#define buffsize 100 static int yaffs_readpage_nolock(struct file *f, struct page *pg) { /* Lifted from jffs2 */ @@ -721,26 +993,12 @@ 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, ("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; - } - } + T(YAFFS_TRACE_OS, + (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"), + (unsigned)(pg->index << PAGE_CACHE_SHIFT), + (unsigned)PAGE_CACHE_SIZE)); obj = yaffs_DentryToObject(f->f_dentry); @@ -778,7 +1036,7 @@ static int yaffs_readpage_nolock(struct file *f, struct page *pg) flush_dcache_page(pg); kunmap(pg); - T(YAFFS_TRACE_OS, ("yaffs_readpage done\n")); + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n"))); return ret; } @@ -791,7 +1049,12 @@ static int yaffs_readpage_unlock(struct file *f, struct page *pg) static int yaffs_readpage(struct file *f, struct page *pg) { - return yaffs_readpage_unlock(f, 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; } /* writepage inspired by/stolen from smbfs */ @@ -802,66 +1065,79 @@ 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); - if (offset > inode->i_size) { - T(YAFFS_TRACE_OS, - ("yaffs_writepage at %08x, inode size = %08x!!!\n", - (unsigned)(page->index << PAGE_CACHE_SHIFT), - (unsigned)inode->i_size)); - T(YAFFS_TRACE_OS, - (" -> don't care!!\n")); - unlock_page(page); - return 0; + end_index = 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; + } } - 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); + if(nBytes != PAGE_CACHE_SIZE) + zero_user_segment(page,nBytes,PAGE_CACHE_SIZE); get_page(page); buffer = kmap(page); obj = yaffs_InodeToObject(inode); - yaffs_GrossLock(obj->myDev); + dev = obj->myDev; + yaffs_GrossLock(dev); T(YAFFS_TRACE_OS, - ("yaffs_writepage at %08x, size %08x\n", + (TSTR("yaffs_writepage at %08x, size %08x\n"), (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes)); T(YAFFS_TRACE_OS, - ("writepag0: obj = %05x, ino = %05x\n", + (TSTR("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, - ("writepag1: obj = %05x, ino = %05x\n", + (TSTR("writepag1: obj = %05x, ino = %05x\n"), (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); - yaffs_GrossUnlock(obj->myDev); + yaffs_GrossUnlock(dev); kunmap(page); - SetPageUptodate(page); - UnlockPage(page); + set_page_writeback(page); + unlock_page(page); + end_page_writeback(page); put_page(page); return (nWritten == nBytes) ? 0 : -ENOSPC; @@ -875,15 +1151,12 @@ 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); @@ -894,6 +1167,10 @@ 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); @@ -904,19 +1181,20 @@ static int yaffs_write_begin(struct file *filp, struct address_space *mapping, /* Update page if required */ - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) + if (!Page_Uptodate(pg)) ret = yaffs_readpage_nolock(filp, pg); if (ret) goto out; /* Happy path return */ - T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n")); + T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n"))); return 0; out: - T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret)); + T(YAFFS_TRACE_OS, + (TSTR("end yaffs_write_begin fail returning %d\n"), ret)); if (space_held) yaffs_release_space(filp); if (pg) { @@ -931,9 +1209,9 @@ out: static int yaffs_prepare_write(struct file *f, struct page *pg, unsigned offset, unsigned to) { - T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n")); + T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n"))); - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) + if (!Page_Uptodate(pg)) return yaffs_readpage_nolock(f, pg); return 0; } @@ -952,20 +1230,18 @@ 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 %x pos %x nBytes %d\n", - (unsigned) addr, - (int)pos, copied)); + ("yaffs_write_end addr %p pos %x nBytes %d\n", + addr,(unsigned)pos, copied)); ret = yaffs_file_write(filp, addr, copied, &pos); if (ret != copied) { T(YAFFS_TRACE_OS, - ("yaffs_write_end not same size ret %d copied %d\n", + (TSTR("yaffs_write_end not same size ret %d copied %d\n"), ret, copied)); SetPageError(pg); - ClearPageUptodate(pg); } else { - SetPageUptodate(pg); + /* Nothing */ } kunmap(pg); @@ -995,25 +1271,24 @@ static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, saddr = (unsigned) addr; T(YAFFS_TRACE_OS, - ("yaffs_commit_write addr %x pos %x nBytes %d\n", + (TSTR("yaffs_commit_write addr %x pos %x nBytes %d\n"), saddr, spos, nBytes)); nWritten = yaffs_file_write(f, addr, nBytes, &pos); if (nWritten != nBytes) { T(YAFFS_TRACE_OS, - ("yaffs_commit_write not same size nWritten %d nBytes %d\n", + (TSTR("yaffs_commit_write not same size nWritten %d nBytes %d\n"), nWritten, nBytes)); SetPageError(pg); - ClearPageUptodate(pg); } else { - SetPageUptodate(pg); + /* Nothing */ } kunmap(pg); T(YAFFS_TRACE_OS, - ("yaffs_commit_write returning %d\n", + (TSTR("yaffs_commit_write returning %d\n"), nWritten == nBytes ? 0 : nWritten)); return nWritten == nBytes ? 0 : nWritten; @@ -1088,7 +1363,7 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj) inode->i_nlink = yaffs_GetObjectLinkCount(obj); T(YAFFS_TRACE_OS, - ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n", + (TSTR("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))); @@ -1123,7 +1398,7 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj) } else { T(YAFFS_TRACE_OS, - ("yaffs_FileInode invalid parameters\n")); + (TSTR("yaffs_FileInode invalid parameters\n"))); } } @@ -1135,20 +1410,20 @@ struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, if (!sb) { T(YAFFS_TRACE_OS, - ("yaffs_get_inode for NULL super_block!!\n")); + (TSTR("yaffs_get_inode for NULL super_block!!\n"))); return NULL; } if (!obj) { T(YAFFS_TRACE_OS, - ("yaffs_get_inode for NULL object!!\n")); + (TSTR("yaffs_get_inode for NULL object!!\n"))); return NULL; } T(YAFFS_TRACE_OS, - ("yaffs_get_inode for object %d\n", obj->objectId)); + (TSTR("yaffs_get_inode for object %d\n"), obj->objectId)); inode = Y_IGET(sb, obj->objectId); if (IS_ERR(inode)) @@ -1184,18 +1459,20 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, if (!obj) T(YAFFS_TRACE_OS, - ("yaffs_file_write: hey obj is null!\n")); + (TSTR("yaffs_file_write: hey obj is null!\n"))); else T(YAFFS_TRACE_OS, - ("yaffs_file_write about to write writing %zu bytes" - "to object %d at %d\n", - n, obj->objectId, ipos)); + (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)); nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0); + yaffs_MarkSuperBlockDirty(dev); + T(YAFFS_TRACE_OS, - ("yaffs_file_write writing %zu bytes, %d written at %d\n", - n, nWritten, ipos)); + (TSTR("yaffs_file_write: %d(%x) bytes written\n"), + (unsigned )n,(unsigned)n)); if (nWritten > 0) { ipos += nWritten; @@ -1205,8 +1482,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, - ("yaffs_file_write size updated to %d bytes, " - "%d blocks\n", + (TSTR("yaffs_file_write size updated to %d bytes, " + "%d blocks\n"), ipos, (int)(inode->i_blocks))); } @@ -1256,6 +1533,33 @@ 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; @@ -1273,35 +1577,41 @@ 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 unlock_out; + goto out; } - T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset)); + T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset)); if (offset == 0) { T(YAFFS_TRACE_OS, - ("yaffs_readdir: entry . ino %d \n", + (TSTR("yaffs_readdir: entry . ino %d \n"), (int)inode->i_ino)); yaffs_GrossUnlock(dev); - if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){ + yaffs_GrossLock(dev); goto out; + } yaffs_GrossLock(dev); offset++; f->f_pos++; } if (offset == 1) { T(YAFFS_TRACE_OS, - ("yaffs_readdir: entry .. ino %d \n", + (TSTR("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) + f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){ + yaffs_GrossLock(dev); goto out; + } yaffs_GrossLock(dev); offset++; f->f_pos++; @@ -1311,7 +1621,6 @@ 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; @@ -1328,8 +1637,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, - ("yaffs_readdir: %s inode %d\n", name, - yaffs_GetObjectInode(l))); + (TSTR("yaffs_readdir: %s inode %d\n"), + name, yaffs_GetObjectInode(l))); yaffs_GrossUnlock(dev); @@ -1338,8 +1647,10 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) strlen(name), offset, this_inode, - this_type) < 0) + this_type) < 0){ + yaffs_GrossLock(dev); goto out; + } yaffs_GrossLock(dev); @@ -1349,14 +1660,16 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) yaffs_SearchAdvance(sc); } -unlock_out: - yaffs_GrossUnlock(dev); out: - yaffs_EndSearch(sc); + yaffs_EndSearch(sc); + yaffs_DeviceToLC(dev)->readdirProcess = NULL; + yaffs_GrossUnlock(dev); return retVal; } + + /* * File creation. Allocate an inode, and we're done.. */ @@ -1391,16 +1704,16 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, if (parent) { T(YAFFS_TRACE_OS, - ("yaffs_mknod: parent object %d type %d\n", + (TSTR("yaffs_mknod: parent object %d type %d\n"), parent->objectId, parent->variantType)); } else { T(YAFFS_TRACE_OS, - ("yaffs_mknod: could not get parent object\n")); + (TSTR("yaffs_mknod: could not get parent object\n"))); return -EPERM; } - T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, " - "mode %x dev %x\n", + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, " + "mode %x dev %x\n"), dentry->d_name.name, mode, rdev)); dev = parent->myDev; @@ -1410,7 +1723,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, ("yaffs_mknod: making special\n")); + T(YAFFS_TRACE_OS, (TSTR("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)); @@ -1420,18 +1733,18 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, #endif break; case S_IFREG: /* file */ - T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n")); + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n"))); obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid, gid); break; case S_IFDIR: /* directory */ T(YAFFS_TRACE_OS, - ("yaffs_mknod: making directory\n")); + (TSTR("yaffs_mknod: making directory\n"))); obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode, uid, gid); break; case S_IFLNK: /* symlink */ - T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n")); + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n"))); obj = NULL; /* Do we ever get here? */ break; } @@ -1444,12 +1757,13 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, d_instantiate(dentry, inode); update_dir_time(dir); T(YAFFS_TRACE_OS, - ("yaffs_mknod created object %d count = %d\n", + (TSTR("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, - ("yaffs_mknod failed making object\n")); + (TSTR("yaffs_mknod failed making object\n"))); error = -ENOMEM; } @@ -1459,7 +1773,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, ("yaffs_mkdir\n")); + T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n"))); retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); return retVal; } @@ -1471,7 +1785,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, ("yaffs_create\n")); + T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n"))); return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); } @@ -1480,16 +1794,18 @@ static int yaffs_unlink(struct inode *dir, struct dentry *dentry) int retVal; yaffs_Device *dev; + yaffs_Object *obj; T(YAFFS_TRACE_OS, - ("yaffs_unlink %d:%s\n", (int)(dir->i_ino), + (TSTR("yaffs_unlink %d:%s\n"), + (int)(dir->i_ino), dentry->d_name.name)); - - dev = yaffs_InodeToObject(dir)->myDev; + obj = yaffs_InodeToObject(dir); + dev = obj->myDev; yaffs_GrossLock(dev); - retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name); + retVal = yaffs_Unlink(obj, dentry->d_name.name); if (retVal == YAFFS_OK) { dentry->d_inode->i_nlink--; @@ -1514,7 +1830,7 @@ static int yaffs_link(struct dentry *old_dentry, struct inode *dir, yaffs_Object *link = NULL; yaffs_Device *dev; - T(YAFFS_TRACE_OS, ("yaffs_link\n")); + T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n"))); obj = yaffs_InodeToObject(inode); dev = obj->myDev; @@ -1530,7 +1846,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, - ("yaffs_link link count %d i_count %d\n", + (TSTR("yaffs_link link count %d i_count %d\n"), old_dentry->d_inode->i_nlink, atomic_read(&old_dentry->d_inode->i_count))); } @@ -1553,7 +1869,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, ("yaffs_symlink\n")); + T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n"))); dev = yaffs_InodeToObject(dir)->myDev; yaffs_GrossLock(dev); @@ -1567,29 +1883,37 @@ 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, ("symlink created OK\n")); + T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n"))); return 0; } else { - T(YAFFS_TRACE_OS, ("symlink not created\n")); + T(YAFFS_TRACE_OS, (TSTR("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_sync_object\n")); + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, + (TSTR("yaffs_sync_object\n"))); yaffs_GrossLock(dev); - yaffs_FlushFile(obj, 1); + yaffs_FlushFile(obj, 1, datasync); yaffs_GrossUnlock(dev); return 0; } @@ -1606,7 +1930,7 @@ static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, int retVal = YAFFS_FAIL; yaffs_Object *target; - T(YAFFS_TRACE_OS, ("yaffs_rename\n")); + T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n"))); dev = yaffs_InodeToObject(old_dir)->myDev; yaffs_GrossLock(dev); @@ -1620,12 +1944,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, ("target is non-empty dir\n")); + T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n"))); retVal = YAFFS_FAIL; } else { /* Now does unlinking internally using shadowing mechanism */ - T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n")); + T(YAFFS_TRACE_OS, (TSTR("calling yaffs_RenameObject\n"))); retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir), old_dentry->d_name.name, @@ -1652,30 +1976,168 @@ 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; + int error = 0; yaffs_Device *dev; T(YAFFS_TRACE_OS, - ("yaffs_setattr of object %d\n", + (TSTR("yaffs_setattr of object %d\n"), yaffs_InodeToObject(inode)->objectId)); - error = inode_change_ok(inode, attr); + /* 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); 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); - if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) == - YAFFS_OK) { + result = yaffs_SetAttributes(yaffs_InodeToObject(inode), attr); + if(result == 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) { @@ -1691,7 +2153,7 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) yaffs_Device *dev = yaffs_SuperToDevice(sb); #endif - T(YAFFS_TRACE_OS, ("yaffs_statfs\n")); + T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n"))); yaffs_GrossLock(dev); @@ -1705,8 +2167,8 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) uint64_t bytesInDev; uint64_t bytesFree; - bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) * - ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk)); + bytesInDev = ((uint64_t)((dev->param.endBlock - dev->param.startBlock + 1))) * + ((uint64_t)(dev->param.nChunksPerBlock * dev->nDataBytesPerChunk)); do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */ buf->f_blocks = bytesInDev; @@ -1721,16 +2183,16 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) } else if (sb->s_blocksize > dev->nDataBytesPerChunk) { buf->f_blocks = - (dev->endBlock - dev->startBlock + 1) * - dev->nChunksPerBlock / + (dev->param.endBlock - dev->param.startBlock + 1) * + dev->param.nChunksPerBlock / (sb->s_blocksize / dev->nDataBytesPerChunk); buf->f_bfree = yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize / dev->nDataBytesPerChunk); } else { buf->f_blocks = - (dev->endBlock - dev->startBlock + 1) * - dev->nChunksPerBlock * + (dev->param.endBlock - dev->param.startBlock + 1) * + dev->param.nChunksPerBlock * (dev->nDataBytesPerChunk / sb->s_blocksize); buf->f_bfree = @@ -1747,27 +2209,238 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) } -static int yaffs_do_sync_fs(struct super_block *sb) + +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) { yaffs_Device *dev = yaffs_SuperToDevice(sb); - T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n")); + unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4); + unsigned gc_urgent = yaffs_bg_gc_urgency(dev); + int do_checkpoint; - if (sb->s_dirt) { - yaffs_GrossLock(dev); + 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" : "" )); - if (dev) { - yaffs_FlushEntireDeviceCache(dev); - yaffs_CheckpointSave(dev); - } - - yaffs_GrossUnlock(dev); + 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 + yaffs_GrossLock(dev); + + now = jiffies; + + if(time_after(now, next_dir_update) && yaffs_bg_enable){ + yaffs_UpdateDirtyDirectories(dev); + next_dir_update = now + HZ; + } + + 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 + } + + 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) @@ -1775,10 +2448,14 @@ 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 @@ -1791,10 +2468,13 @@ static int yaffs_sync_fs(struct super_block *sb, int wait) static int yaffs_sync_fs(struct super_block *sb) #endif { - T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n")); + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1); - if (yaffs_auto_checkpoint >= 1) - yaffs_do_sync_fs(sb); + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, + (TSTR("yaffs_sync_fs%s\n"), + request_checkpoint ? " checkpt" : "")); + + yaffs_do_sync_fs(sb, request_checkpoint); return 0; } @@ -1808,7 +2488,7 @@ static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) yaffs_Device *dev = yaffs_SuperToDevice(sb); T(YAFFS_TRACE_OS, - ("yaffs_iget for %lu\n", ino)); + (TSTR("yaffs_iget for %lu\n"), ino)); inode = iget_locked(sb, ino); if (!inode) @@ -1846,76 +2526,55 @@ static void yaffs_read_inode(struct inode *inode) yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb); T(YAFFS_TRACE_OS, - ("yaffs_read_inode for %d\n", (int)inode->i_ino)); + (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino)); - yaffs_GrossLock(dev); + if(current != yaffs_DeviceToLC(dev)->readdirProcess) + yaffs_GrossLock(dev); obj = yaffs_FindObjectByNumber(dev, inode->i_ino); yaffs_FillInodeFromObject(inode, obj); - yaffs_GrossUnlock(dev); -} - -#endif - -static YLIST_HEAD(yaffs_dev_list); - -#if 0 /* not used */ -static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) -{ - yaffs_Device *dev = yaffs_SuperToDevice(sb); - - if (*flags & MS_RDONLY) { - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; - - T(YAFFS_TRACE_OS, - ("yaffs_remount_fs: %s: RO\n", dev->name)); - - yaffs_GrossLock(dev); - - yaffs_FlushEntireDeviceCache(dev); - - yaffs_CheckpointSave(dev); - - if (mtd->sync) - mtd->sync(mtd); - + if(current != yaffs_DeviceToLC(dev)->readdirProcess) yaffs_GrossUnlock(dev); - } else { - T(YAFFS_TRACE_OS, - ("yaffs_remount_fs: %s: RW\n", dev->name)); - } - - return 0; } + #endif +static YLIST_HEAD(yaffs_context_list); +struct semaphore yaffs_context_lock; + static void yaffs_put_super(struct super_block *sb) { yaffs_Device *dev = yaffs_SuperToDevice(sb); - T(YAFFS_TRACE_OS, ("yaffs_put_super\n")); + 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"))); yaffs_GrossLock(dev); - yaffs_FlushEntireDeviceCache(dev); + yaffs_FlushSuperBlock(sb,1); - yaffs_CheckpointSave(dev); + if (yaffs_DeviceToLC(dev)->putSuperFunc) + yaffs_DeviceToLC(dev)->putSuperFunc(sb); - if (dev->putSuperFunc) - dev->putSuperFunc(sb); yaffs_Deinitialise(dev); yaffs_GrossUnlock(dev); - /* we assume this is protected by lock_kernel() in mount/umount */ - ylist_del(&dev->devList); + down(&yaffs_context_lock); + ylist_del_init(&(yaffs_DeviceToLC(dev)->contextList)); + up(&yaffs_context_lock); - if (dev->spareBuffer) { - YFREE(dev->spareBuffer); - dev->spareBuffer = NULL; + if (yaffs_DeviceToLC(dev)->spareBuffer) { + YFREE(yaffs_DeviceToLC(dev)->spareBuffer); + yaffs_DeviceToLC(dev)->spareBuffer = NULL; } kfree(dev); @@ -1924,7 +2583,7 @@ static void yaffs_put_super(struct super_block *sb) static void yaffs_MTDPutSuper(struct super_block *sb) { - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; + struct mtd_info *mtd = yaffs_DeviceToMtd(yaffs_SuperToDevice(sb)); if (mtd->sync) mtd->sync(mtd); @@ -1933,11 +2592,11 @@ static void yaffs_MTDPutSuper(struct super_block *sb) } -static void yaffs_MarkSuperBlockDirty(void *vsb) +static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev) { - struct super_block *sb = (struct super_block *)vsb; + struct super_block *sb = yaffs_DeviceToLC(dev)->superBlock; - T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb)); + T(YAFFS_TRACE_OS, (TSTR("yaffs_MarkSuperBlockDirty() sb = %p\n"), sb)); if (sb) sb->s_dirt = 1; } @@ -1947,11 +2606,15 @@ typedef struct { int skip_checkpoint_read; int skip_checkpoint_write; int no_cache; - int empty_lost_and_found_overridden; + 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; } yaffs_options; -#define MAX_OPT_LEN 20 +#define MAX_OPT_LEN 30 static int yaffs_parse_options(yaffs_options *options, const char *options_str) { char cur_opt[MAX_OPT_LEN + 1]; @@ -1964,7 +2627,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 != ',') { @@ -1977,7 +2640,25 @@ 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, "no-cache")) + 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")) options->no_cache = 1; else if (!strcmp(cur_opt, "no-checkpoint-read")) options->skip_checkpoint_read = 1; @@ -1986,12 +2667,6 @@ 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); @@ -2014,13 +2689,29 @@ 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) @@ -2028,9 +2719,10 @@ 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\"\n", + printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n", sb->s_dev, - yaffs_devname(sb, devname_buf)); + yaffs_devname(sb, devname_buf), + readOnly ? "ro" : "rw"); if (!data_str) data_str = ""; @@ -2047,20 +2739,17 @@ 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, - ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize))); -#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY T(YAFFS_TRACE_OS, - ("yaffs: Write verification disabled. All guarantees " - "null and void\n")); -#endif + (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))); - 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))); + 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))); /* Check it's an mtd device..... */ if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) @@ -2070,50 +2759,46 @@ 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, - ("yaffs: MTD device #%u doesn't appear to exist\n", - MINOR(sb->s_dev))); + (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"), + MINOR(sb->s_dev))); return NULL; } /* Check it's NAND */ if (mtd->type != MTD_NANDFLASH) { T(YAFFS_TRACE_ALWAYS, - ("yaffs: MTD device is not NAND it's type %d\n", mtd->type)); + (TSTR("yaffs: MTD device is not NAND it's type %d\n"), + mtd->type)); return NULL; } - T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase)); - T(YAFFS_TRACE_OS, (" read %p\n", mtd->read)); - T(YAFFS_TRACE_OS, (" write %p\n", mtd->write)); - T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob)); - T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob)); - T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad)); - T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad)); - T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd))); - T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize)); - T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize)); + 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)); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) - T(YAFFS_TRACE_OS, (" size %u\n", mtd->size)); + T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size)); #else - T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size)); + T(YAFFS_TRACE_OS, (TSTR(" 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, ("yaffs: auto selecting yaffs2\n")); + T(YAFFS_TRACE_ALWAYS, + (TSTR("yaffs: auto selecting yaffs2\n"))); yaffsVersion = 2; } /* Added NCB 26/5/2006 for completeness */ if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) { - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n")); + T(YAFFS_TRACE_ALWAYS, + (TSTR("yaffs: auto selecting yaffs1\n"))); yaffsVersion = 1; } @@ -2133,8 +2818,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, - ("yaffs: MTD device does not support required " - "functions\n"));; + (TSTR("yaffs: MTD device does not support required " + "functions\n"))); return NULL; } @@ -2142,8 +2827,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, - ("yaffs: MTD device does not have the " - "right page sizes\n")); + (TSTR("yaffs: MTD device does not have the " + "right page sizes\n"))); return NULL; } } else { @@ -2158,16 +2843,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, - ("yaffs: MTD device does not support required " - "functions\n"));; + (TSTR("yaffs: MTD device does not support required " + "functions\n"))); return NULL; } if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || mtd->oobsize != YAFFS_BYTES_PER_SPARE) { T(YAFFS_TRACE_ALWAYS, - ("yaffs: MTD device does not support have the " - "right page sizes\n")); + (TSTR("yaffs: MTD device does not support have the " + "right page sizes\n"))); return NULL; } } @@ -2177,108 +2862,196 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, * Set the yaffs_Device up for mtd */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) - sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); -#else - sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); -#endif + if (!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 (!dev) { /* Deep shit could not allocate device structure */ T(YAFFS_TRACE_ALWAYS, - ("yaffs_read_super: Failed trying to allocate " - "yaffs_Device. \n")); + (TSTR("yaffs_read_super: Failed trying to allocate " + "yaffs_Device. \n"))); return NULL; } - memset(dev, 0, sizeof(yaffs_Device)); - dev->genericDevice = mtd; - dev->name = mtd->name; + 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; /* Set up the memory size parameters.... */ nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK)); - dev->startBlock = 0; - dev->endBlock = nBlocks - 1; - dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; - dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK; - dev->nReservedBlocks = 5; - dev->nShortOpCaches = (options.no_cache) ? 0 : 10; - dev->inbandTags = options.inband_tags; + 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; /* ... and the functions. */ if (yaffsVersion == 2) { - dev->writeChunkWithTagsToNAND = + param->writeChunkWithTagsToNAND = nandmtd2_WriteChunkWithTagsToNAND; - dev->readChunkWithTagsFromNAND = + param->readChunkWithTagsFromNAND = nandmtd2_ReadChunkWithTagsFromNAND; - dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad; - dev->queryNANDBlock = nandmtd2_QueryNANDBlock; - dev->spareBuffer = YMALLOC(mtd->oobsize); - dev->isYaffs2 = 1; + param->markNANDBlockBad = nandmtd2_MarkNANDBlockBad; + param->queryNANDBlock = nandmtd2_QueryNANDBlock; + yaffs_DeviceToLC(dev)->spareBuffer = YMALLOC(mtd->oobsize); + param->isYaffs2 = 1; #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) - dev->totalBytesPerChunk = mtd->writesize; - dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; + param->totalBytesPerChunk = mtd->writesize; + param->nChunksPerBlock = mtd->erasesize / mtd->writesize; #else - dev->totalBytesPerChunk = mtd->oobblock; - dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; + param->totalBytesPerChunk = mtd->oobblock; + param->nChunksPerBlock = mtd->erasesize / mtd->oobblock; #endif nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize); - dev->startBlock = 0; - dev->endBlock = nBlocks - 1; + param->startBlock = 0; + param->endBlock = nBlocks - 1; } else { #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) /* use the MTD interface in yaffs_mtdif1.c */ - dev->writeChunkWithTagsToNAND = + param->writeChunkWithTagsToNAND = nandmtd1_WriteChunkWithTagsToNAND; - dev->readChunkWithTagsFromNAND = + param->readChunkWithTagsFromNAND = nandmtd1_ReadChunkWithTagsFromNAND; - dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad; - dev->queryNANDBlock = nandmtd1_QueryNANDBlock; + param->markNANDBlockBad = nandmtd1_MarkNANDBlockBad; + param->queryNANDBlock = nandmtd1_QueryNANDBlock; #else - dev->writeChunkToNAND = nandmtd_WriteChunkToNAND; - dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND; + param->writeChunkToNAND = nandmtd_WriteChunkToNAND; + param->readChunkFromNAND = nandmtd_ReadChunkFromNAND; #endif - dev->isYaffs2 = 0; + param->isYaffs2 = 0; } /* ... and common functions */ - dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND; - dev->initialiseNAND = nandmtd_InitialiseNAND; + param->eraseBlockInNAND = nandmtd_EraseBlockInNAND; + param->initialiseNAND = nandmtd_InitialiseNAND; - dev->putSuperFunc = yaffs_MTDPutSuper; + yaffs_DeviceToLC(dev)->putSuperFunc = yaffs_MTDPutSuper; - dev->superBlock = (void *)sb; - dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; + param->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; + param->gcControl = yaffs_gc_control_callback; + yaffs_DeviceToLC(dev)->superBlock= sb; + #ifndef CONFIG_YAFFS_DOES_ECC - dev->useNANDECC = 1; + param->useNANDECC = 1; #endif #ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES - dev->wideTnodesDisabled = 1; + param->wideTnodesDisabled = 1; #endif - dev->skipCheckpointRead = options.skip_checkpoint_read; - dev->skipCheckpointWrite = options.skip_checkpoint_write; + param->skipCheckpointRead = options.skip_checkpoint_read; + param->skipCheckpointWrite = options.skip_checkpoint_write; - /* we assume this is protected by lock_kernel() in mount/umount */ - ylist_add_tail(&dev->devList, &yaffs_dev_list); + 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); /* Directory search handling...*/ - YINIT_LIST_HEAD(&dev->searchContexts); - dev->removeObjectCallback = yaffs_RemoveObjectCallback; + YINIT_LIST_HEAD(&(yaffs_DeviceToLC(dev)->searchContexts)); + param->removeObjectCallback = yaffs_RemoveObjectCallback; - init_MUTEX(&dev->grossLock); + init_MUTEX(&(yaffs_DeviceToLC(dev)->grossLock)); yaffs_GrossLock(dev); err = yaffs_GutsInitialise(dev); T(YAFFS_TRACE_OS, - ("yaffs_read_super: guts initialised %s\n", + (TSTR("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); @@ -2294,11 +3067,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, ("yaffs_read_super: got root inode\n")); + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n"))); root = d_alloc_root(inode); - T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n")); + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n"))); if (!root) { iput(inode); @@ -2307,9 +3080,10 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, sb->s_root = root; sb->s_dirt = !dev->isCheckpointed; T(YAFFS_TRACE_ALWAYS, - ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed)); + (TSTR("yaffs_read_super: isCheckpointed %d\n"), + dev->isCheckpointed)); - T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n")); + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n"))); return sb; } @@ -2409,45 +3183,63 @@ 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(char *buf, yaffs_Device * dev) +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) { - buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock); - buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); - buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk); buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk); buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits); buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize); buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks); - buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks); buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint); - buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated); - buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes); - buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated); - buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects); + buf += sprintf(buf, "\n"); + buf += sprintf(buf, "nTnodes............ %d\n", dev->nTnodes); + buf += sprintf(buf, "nObjects........... %d\n", dev->nObjects); buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks); - buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites); - buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads); - buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures); - buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies); - buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections); - buf += sprintf(buf, "passiveGCs......... %d\n", - dev->passiveGarbageCollections); - buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites); - buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches); - buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks); - buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed); - buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed); - buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed); - buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed); - buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits); - buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles); - buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles); + buf += sprintf(buf, "\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, "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); + sprintf(buf, "nBackgroudDeletions %u\n", dev->nBackgroundDeletions); return buf; } @@ -2470,27 +3262,64 @@ static int yaffs_proc_read(char *page, *(int *)start = 1; /* Print header first */ - if (step == 0) { - buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__ - "\n%s\n%s\n", yaffs_fs_c_version, - yaffs_guts_c_version); + 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); } - /* hold lock_kernel while traversing yaffs_dev_list */ - lock_kernel(); + 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); /* Locate and print the Nth entry. Order N-squared but N is small. */ - ylist_for_each(item, &yaffs_dev_list) { - yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList); - if (n < step) { - n++; - continue; - } - buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name); - buf = yaffs_dump_dev(buf, dev); - break; + 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); } - unlock_kernel(); + up(&yaffs_context_lock); + return buf - page < count ? buf - page : count; } @@ -2507,6 +3336,7 @@ 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}, @@ -2516,26 +3346,28 @@ 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(struct file *file, const char *buf, +static int yaffs_proc_write_trace_options(struct file *file, const char *buf, unsigned long count, void *data) { unsigned rg = 0, mask_bitfield; @@ -2619,7 +3451,8 @@ static int yaffs_proc_write(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); } } @@ -2627,6 +3460,13 @@ static int yaffs_proc_write(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; @@ -2645,9 +3485,19 @@ static int __init init_yaffs_fs(void) struct file_system_to_install *fsinst; T(YAFFS_TRACE_ALWAYS, - ("yaffs " __DATE__ " " __TIME__ " Installing. \n")); + (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n"))); - /* Install the proc_fs entry */ +#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 */ my_proc_entry = create_proc_entry("yaffs", S_IRUGO | S_IFREG, YPROC_ROOT); @@ -2659,6 +3509,17 @@ 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; @@ -2691,10 +3552,11 @@ static void __exit exit_yaffs_fs(void) struct file_system_to_install *fsinst; - T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__ - " removing. \n")); + T(YAFFS_TRACE_ALWAYS, + (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n"))); remove_proc_entry("yaffs", YPROC_ROOT); + remove_proc_entry("yaffs_stats", YPROC_ROOT); fsinst = fs_to_install; @@ -2711,5 +3573,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-2006"); +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010"); MODULE_LICENSE("GPL"); diff --git a/fs/yaffs2/yaffs_yaffs1.c b/fs/yaffs2/yaffs_yaffs1.c new file mode 100644 index 00000000..78cc8199 --- /dev/null +++ b/fs/yaffs2/yaffs_yaffs1.c @@ -0,0 +1,465 @@ +/* + * 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 new file mode 100644 index 00000000..9769eed3 --- /dev/null +++ b/fs/yaffs2/yaffs_yaffs1.h @@ -0,0 +1,22 @@ +/* + * 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 new file mode 100644 index 00000000..e13dd41c --- /dev/null +++ b/fs/yaffs2/yaffs_yaffs2.c @@ -0,0 +1,1540 @@ +/* + * 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 new file mode 100644 index 00000000..67dc8f15 --- /dev/null +++ b/fs/yaffs2/yaffs_yaffs2.h @@ -0,0 +1,36 @@ +/* + * 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 810837a3..ca36cfc4 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 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 aff59411..83203c88 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-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -41,12 +41,14 @@ #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 @@ -55,11 +57,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_strlen(s) strlen(s) +#define yaffs_strnlen(s,m) strnlen(s,m) #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" @@ -71,11 +73,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 0666 -#define YAFFS_LOSTNFOUND_MODE 0666 +#define YAFFS_ROOT_MODE 0755 +#define YAFFS_LOSTNFOUND_MODE 0700 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) #define Y_CURRENT_TIME CURRENT_TIME.tv_sec @@ -89,15 +91,10 @@ #define yaffs_strcmp(a, b) strcmp(a, b) #define TENDSTR "\n" -#define TSTR(x) KERN_WARNING x +#define TSTR(x) KERN_DEBUG 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; }) @@ -116,7 +113,6 @@ #include "stdio.h" #include "string.h" -#include "devextras.h" #define YMALLOC(x) malloc(x) #define YFREE(x) free(x) @@ -129,7 +125,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_strlen(s) strlen(s) +#define yaffs_strnlen(s,m) strnlen(s,m) #define yaffs_sprintf sprintf #define yaffs_toupper(a) toupper(a) @@ -146,8 +142,8 @@ #define YAFFS_LOSTNFOUND_PREFIX "obj" /* #define YPRINTF(x) printf x */ -#define YAFFS_ROOT_MODE 0666 -#define YAFFS_LOSTNFOUND_MODE 0666 +#define YAFFS_ROOT_MODE 0755 +#define YAFFS_LOSTNFOUND_MODE 0700 #define yaffs_SumCompare(x, y) ((x) == (y)) #define yaffs_strcmp(a, b) strcmp(a, b) @@ -158,46 +154,180 @@ #endif -/* see yaffs_fs.c */ -extern unsigned int yaffs_traceMask; -extern unsigned int yaffs_wr_attempts; +#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE) -/* - * Tracing flags. - * The flags masked in YAFFS_TRACE_ALWAYS are always traced. - */ +#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES -#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_RDONLY +#define O_RDONLY 00 +#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_WRONLY +#define O_WRONLY 01 +#endif -#define YAFFS_TRACE_ERROR 0x40000000 -#define YAFFS_TRACE_BUG 0x80000000 -#define YAFFS_TRACE_ALWAYS 0xF0000000 +#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 T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0) +// 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 #ifndef YBUG -#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0) +#define YBUG() do {\ + T(YAFFS_TRACE_BUG,\ + (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\ + __LINE__));\ + Y_DUMP_STACK();\ +} while (0) #endif + #endif From bb612364fc92222e48349530daae9b0ac69f6887 Mon Sep 17 00:00:00 2001 From: LeTama Date: Fri, 5 Nov 2010 11:45:13 +0100 Subject: [PATCH 7/8] battery driver: reduce dmesg verbosity for normal use --- drivers/power/ds2746_battery.c | 16 ++++++++++++++++ drivers/power/ds2746_param.c | 2 ++ 2 files changed, 18 insertions(+) diff --git a/drivers/power/ds2746_battery.c b/drivers/power/ds2746_battery.c index 56fbcc66..931191b4 100644 --- a/drivers/power/ds2746_battery.c +++ b/drivers/power/ds2746_battery.c @@ -580,7 +580,9 @@ static void __update_capacity(void) { INT32 next_capacity_01p; +#if HTC_BATTERY_DS2746_DEBUG_ENABLE pr_info("ds2746_batt:__update_capacity start\n"); +#endif if (poweralg.charge_state == CHARGE_STATE_PREDICTION || poweralg.charge_state == CHARGE_STATE_UNKNOWN){ @@ -789,6 +791,7 @@ BOOL do_power_alg(BOOL is_event_triggered) /*powerlog_to_file(&poweralg); update_os_batt_status(&poweralg);*/ +#if HTC_BATTERY_DS2746_DEBUG_ENABLE printk(DRIVER_ZONE "[%d] P=%d cable=%d%d flags=%d%d%d debug=%d%d%d%d fst_discharge=%d/%d [%u]\n", poweralg.charge_state, poweralg.capacity_01p, @@ -804,6 +807,7 @@ BOOL do_power_alg(BOOL is_event_triggered) poweralg.fst_discharge_capacity_01p, poweralg.fst_discharge_acr_mAh, BAHW_MyGetMSecs()); +#endif return TRUE; } @@ -881,7 +885,9 @@ void power_alg_preinit(void) static BLOCKING_NOTIFIER_HEAD(ds2746_notifier_list); int ds2746_register_notifier(struct notifier_block *nb) { +#if HTC_BATTERY_DS2746_DEBUG_ENABLE pr_info("%s\n", __func__); +#endif return blocking_notifier_chain_register(&ds2746_notifier_list, nb); } @@ -894,7 +900,9 @@ int ds2746_unregister_notifier(struct notifier_block *nb) int ds2746_blocking_notify(unsigned long val, void *v) { int chg_ctl; +#if HTC_BATTERY_DS2746_DEBUG_ENABLE pr_info("%s\n", __func__); +#endif if (val == DS2784_CHARGING_CONTROL){ chg_ctl = *(int *) v; @@ -1044,17 +1052,23 @@ void ds2746_charger_control(int type) else if (htc_batt_info.rep.battery_full) pr_info("batt: charging OFF [FULL]\n"); else*/ +#if HTC_BATTERY_DS2746_DEBUG_ENABLE pr_info("batt: charging OFF\n"); +#endif break; case CHARGE_SLOW: chg_ctl = ENABLE_SLOW_CHG; ds2746_blocking_notify(DS2784_CHARGING_CONTROL, &chg_ctl); +#if HTC_BATTERY_DS2746_DEBUG_ENABLE pr_info("batt: charging SLOW\n"); +#endif break; case CHARGE_FAST: chg_ctl = ENABLE_FAST_CHG; ds2746_blocking_notify(DS2784_CHARGING_CONTROL, &chg_ctl); +#if HTC_BATTERY_DS2746_DEBUG_ENABLE pr_info("batt: charging FAST\n"); +#endif break; } } @@ -1077,7 +1091,9 @@ static void ds2746_battery_work(struct work_struct *work) struct ds2746_device_info, monitor_work); unsigned long flags; +#if HTC_BATTERY_DS2746_DEBUG_ENABLE pr_info("[ds2746_batt] ds2746_battery_work*\n"); +#endif do_power_alg(0); get_state_check_interval_min_sec(); di->last_poll = alarm_get_elapsed_realtime(); diff --git a/drivers/power/ds2746_param.c b/drivers/power/ds2746_param.c index 714bc7ad..7744465c 100644 --- a/drivers/power/ds2746_param.c +++ b/drivers/power/ds2746_param.c @@ -507,6 +507,7 @@ static BOOL __ds2746_battery_adc_udpate(struct battery_type *battery) return FALSE; } +#if HTC_ENABLE_POWER_DEBUG printk(DRIVER_ZONE " [x0]%x [x8]%x %x %x %x %x %x %x %x %x %x\n", reg[0], reg[2], @@ -519,6 +520,7 @@ static BOOL __ds2746_battery_adc_udpate(struct battery_type *battery) reg[9], reg[10], reg[11]); +#endif if (!(reg[0] & DS2746_STATUS_AIN0) || !(reg[0] & DS2746_STATUS_AIN1)) { printk(DRIVER_ZONE " AIN not ready...\n"); From 83f65b4212950a5a2a126a8ba03f805b0a04bdab Mon Sep 17 00:00:00 2001 From: Markinus Date: Fri, 5 Nov 2010 12:15:26 +0100 Subject: [PATCH 8/8] cpu: Added interactive governor --- Documentation/cpu-freq/governors.txt | 24 ++ arch/arm/configs/htcleo_defconfig | 2 + drivers/cpufreq/Kconfig | 15 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/cpufreq_interactive.c | 324 ++++++++++++++++++++++++++ include/linux/cpufreq.h | 3 + kernel/sched.c | 1 + 7 files changed, 370 insertions(+) create mode 100644 drivers/cpufreq/cpufreq_interactive.c diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt index aed082f4..d155c054 100644 --- a/Documentation/cpu-freq/governors.txt +++ b/Documentation/cpu-freq/governors.txt @@ -28,6 +28,7 @@ Contents: 2.3 Userspace 2.4 Ondemand 2.5 Conservative +2.6 Interactive 3. The Governor Interface in the CPUfreq Core @@ -182,6 +183,29 @@ governor but for the opposite direction. For example when set to its default value of '20' it means that if the CPU usage needs to be below 20% between samples to have the frequency decreased. + +2.6 Interactive +--------------- + +The CPUfreq governor "interactive" is designed for low latency, +interactive workloads. This governor sets the CPU speed depending on +usage, similar to "ondemand" and "conservative" governors. However +there is no polling, or 'sample_rate' required to scale the CPU up. + +Sampling CPU load every X ms can lead to under powering the CPU +for X ms, leading to dropped framerate, stuttering UI etc.. + +Scaling the CPU up is done when coming out of idle, and like "ondemand" +scaling up will always go to MAX, then step down based off of cpu load. + +There is only one tuneable value for this governor: + +min_sample_time: The ammount of time the CPU must spend (in uS) +at the current frequency before scaling DOWN. This is done to +more accurately determine the cpu workload and the best speed for that +workload. The default is 50ms. + + 3. The Governor Interface in the CPUfreq Core ============================================= diff --git a/arch/arm/configs/htcleo_defconfig b/arch/arm/configs/htcleo_defconfig index 85503ae6..7593df05 100644 --- a/arch/arm/configs/htcleo_defconfig +++ b/arch/arm/configs/htcleo_defconfig @@ -418,10 +418,12 @@ CONFIG_CPU_FREQ_STAT_DETAILS=y # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set CONFIG_CPU_FREQ_GOV_PERFORMANCE=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y # CONFIG_CPU_IDLE is not set diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index a8c8d9c1..ca7b0887 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -110,6 +110,14 @@ config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE Be aware that not all cpufreq drivers support the conservative governor. If unsure have a look at the help section of the driver. Fallback governor will be the performance governor. + +config CPU_FREQ_DEFAULT_GOV_INTERACTIVE + bool "interactive" + select CPU_FREQ_GOV_INTERACTIVE + help + Use the 'interactive' governor as default. This gets full cpu frequency + scaling for workloads that are latency sensitive, typically interactive + workloads. endchoice config CPU_FREQ_GOV_PERFORMANCE @@ -167,6 +175,13 @@ config CPU_FREQ_GOV_ONDEMAND If in doubt, say N. +config CPU_FREQ_GOV_INTERACTIVE + tristate "'interactive' cpufreq governor" + help + 'interactive' - This driver adds a dynamic cpufreq policy governor. + Designed for low latency burst workloads. Sclaing is done when + coming out idle instead of polling. + config CPU_FREQ_GOV_CONSERVATIVE tristate "'conservative' cpufreq governor" depends on CPU_FREQ diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 71fc3b41..30629f7d 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o +obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE) += cpufreq_interactive.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c new file mode 100644 index 00000000..36859a78 --- /dev/null +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -0,0 +1,324 @@ +/* + * drivers/cpufreq/cpufreq_interactive.c + * + * Copyright (C) 2010 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Author: Mike Chan (mike@android.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static void (*pm_idle_old)(void); +static atomic_t active_count = ATOMIC_INIT(0); + +static DEFINE_PER_CPU(struct timer_list, cpu_timer); + +static DEFINE_PER_CPU(u64, time_in_idle); +static DEFINE_PER_CPU(u64, idle_exit_time); + +static struct cpufreq_policy *policy; +static unsigned int target_freq; + +/* Workqueues handle frequency scaling */ +static struct workqueue_struct *up_wq; +static struct workqueue_struct *down_wq; +static struct work_struct freq_scale_work; + +static u64 freq_change_time; +static u64 freq_change_time_in_idle; + +static cpumask_t work_cpumask; + +/* + * The minimum ammount of time to spend at a frequency before we can ramp down, + * default is 50ms. + */ +#define DEFAULT_MIN_SAMPLE_TIME 50000; +static unsigned long min_sample_time; + +static int cpufreq_governor_interactive(struct cpufreq_policy *policy, + unsigned int event); + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE +static +#endif +struct cpufreq_governor cpufreq_gov_interactive = { + .name = "interactive", + .governor = cpufreq_governor_interactive, + .max_transition_latency = 10000000, + .owner = THIS_MODULE, +}; + +static void cpufreq_interactive_timer(unsigned long data) +{ + u64 delta_idle; + u64 update_time; + u64 *cpu_time_in_idle; + u64 *cpu_idle_exit_time; + struct timer_list *t; + + u64 now_idle = get_cpu_idle_time_us(data, + &update_time); + + + cpu_time_in_idle = &per_cpu(time_in_idle, data); + cpu_idle_exit_time = &per_cpu(idle_exit_time, data); + + if (update_time == *cpu_idle_exit_time) + return; + + delta_idle = cputime64_sub(now_idle, *cpu_time_in_idle); + + /* Scale up if there were no idle cycles since coming out of idle */ + if (delta_idle == 0) { + if (policy->cur == policy->max) + return; + + if (nr_running() < 1) + return; + + target_freq = policy->max; + cpumask_set_cpu(data, &work_cpumask); + queue_work(up_wq, &freq_scale_work); + return; + } + + /* + * There is a window where if the cpu utlization can go from low to high + * between the timer expiring, delta_idle will be > 0 and the cpu will + * be 100% busy, preventing idle from running, and this timer from + * firing. So setup another timer to fire to check cpu utlization. + * Do not setup the timer if there is no scheduled work. + */ + t = &per_cpu(cpu_timer, data); + if (!timer_pending(t) && nr_running() > 0) { + *cpu_time_in_idle = get_cpu_idle_time_us( + data, cpu_idle_exit_time); + mod_timer(t, jiffies + 2); + } + + if (policy->cur == policy->min) + return; + + /* + * Do not scale down unless we have been at this frequency for the + * minimum sample time. + */ + if (cputime64_sub(update_time, freq_change_time) < min_sample_time) + return; + + target_freq = policy->min; + cpumask_set_cpu(data, &work_cpumask); + queue_work(down_wq, &freq_scale_work); +} + +static void cpufreq_idle(void) +{ + struct timer_list *t; + u64 *cpu_time_in_idle; + u64 *cpu_idle_exit_time; + + pm_idle_old(); + + if (!cpumask_test_cpu(smp_processor_id(), policy->cpus)) + return; + + /* Timer to fire in 1-2 ticks, jiffie aligned. */ + t = &per_cpu(cpu_timer, smp_processor_id()); + cpu_idle_exit_time = &per_cpu(idle_exit_time, smp_processor_id()); + cpu_time_in_idle = &per_cpu(time_in_idle, smp_processor_id()); + + if (timer_pending(t) == 0) { + *cpu_time_in_idle = get_cpu_idle_time_us( + smp_processor_id(), cpu_idle_exit_time); + mod_timer(t, jiffies + 2); + } +} + +/* + * Choose the cpu frequency based off the load. For now choose the minimum + * frequency that will satisfy the load, which is not always the lower power. + */ +static unsigned int cpufreq_interactive_calc_freq(unsigned int cpu) +{ + unsigned int delta_time; + unsigned int idle_time; + unsigned int cpu_load; + u64 current_wall_time; + u64 current_idle_time;; + + current_idle_time = get_cpu_idle_time_us(cpu, ¤t_wall_time); + + idle_time = (unsigned int) current_idle_time - freq_change_time_in_idle; + delta_time = (unsigned int) current_wall_time - freq_change_time; + + cpu_load = 100 * (delta_time - idle_time) / delta_time; + + return policy->cur * cpu_load / 100; +} + + +/* We use the same work function to sale up and down */ +static void cpufreq_interactive_freq_change_time_work(struct work_struct *work) +{ + unsigned int cpu; + cpumask_t *tmp_mask = &work_cpumask; + for_each_cpu(cpu, tmp_mask) { + if (target_freq == policy->max) { + if (nr_running() == 1) { + cpumask_clear_cpu(cpu, &work_cpumask); + return; + } + + __cpufreq_driver_target(policy, target_freq, + CPUFREQ_RELATION_H); + } else { + target_freq = cpufreq_interactive_calc_freq(cpu); + __cpufreq_driver_target(policy, target_freq, + CPUFREQ_RELATION_L); + } + freq_change_time_in_idle = get_cpu_idle_time_us(cpu, + &freq_change_time); + + cpumask_clear_cpu(cpu, &work_cpumask); + } + + +} + +static ssize_t show_min_sample_time(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", min_sample_time); +} + +static ssize_t store_min_sample_time(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + return strict_strtoul(buf, 0, &min_sample_time); +} + +static struct global_attr min_sample_time_attr = __ATTR(min_sample_time, 0644, + show_min_sample_time, store_min_sample_time); + +static struct attribute *interactive_attributes[] = { + &min_sample_time_attr.attr, + NULL, +}; + +static struct attribute_group interactive_attr_group = { + .attrs = interactive_attributes, + .name = "interactive", +}; + +static int cpufreq_governor_interactive(struct cpufreq_policy *new_policy, + unsigned int event) +{ + int rc; + switch (event) { + case CPUFREQ_GOV_START: + if (!cpu_online(new_policy->cpu)) + return -EINVAL; + + /* + * Do not register the idle hook and create sysfs + * entries if we have already done so. + */ + if (atomic_inc_return(&active_count) > 1) + return 0; + + rc = sysfs_create_group(cpufreq_global_kobject, + &interactive_attr_group); + if (rc) + return rc; + + pm_idle_old = pm_idle; + pm_idle = cpufreq_idle; + policy = new_policy; + break; + + case CPUFREQ_GOV_STOP: + if (atomic_dec_return(&active_count) > 1) + return 0; + + sysfs_remove_group(cpufreq_global_kobject, + &interactive_attr_group); + + pm_idle = pm_idle_old; + del_timer(&per_cpu(cpu_timer, new_policy->cpu)); + break; + + case CPUFREQ_GOV_LIMITS: + if (new_policy->max < new_policy->cur) + __cpufreq_driver_target(new_policy, + new_policy->max, CPUFREQ_RELATION_H); + else if (new_policy->min > new_policy->cur) + __cpufreq_driver_target(new_policy, + new_policy->min, CPUFREQ_RELATION_L); + break; + } + return 0; +} + +static int __init cpufreq_interactive_init(void) +{ + unsigned int i; + struct timer_list *t; + min_sample_time = DEFAULT_MIN_SAMPLE_TIME; + + /* Initalize per-cpu timers */ + for_each_possible_cpu(i) { + t = &per_cpu(cpu_timer, i); + init_timer_deferrable(t); + t->function = cpufreq_interactive_timer; + t->data = i; + } + + /* Scale up is high priority */ + up_wq = create_rt_workqueue("kinteractive_up"); + down_wq = create_workqueue("knteractive_down"); + + INIT_WORK(&freq_scale_work, cpufreq_interactive_freq_change_time_work); + + return cpufreq_register_governor(&cpufreq_gov_interactive); +} + +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE +pure_initcall(cpufreq_interactive_init); +#else +module_init(cpufreq_interactive_init); +#endif + +static void __exit cpufreq_interactive_exit(void) +{ + cpufreq_unregister_governor(&cpufreq_gov_interactive); + destroy_workqueue(up_wq); + destroy_workqueue(down_wq); +} + +module_exit(cpufreq_interactive_exit); + +MODULE_AUTHOR("Mike Chan "); +MODULE_DESCRIPTION("'cpufreq_interactive' - A cpufreq governor for " + "Latency sensitive workloads"); +MODULE_LICENSE("GPL"); + diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 79a2340d..61dca28f 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -338,6 +338,9 @@ extern struct cpufreq_governor cpufreq_gov_ondemand; #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE) extern struct cpufreq_governor cpufreq_gov_conservative; #define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_conservative) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE) +extern struct cpufreq_governor cpufreq_gov_interactive; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_interactive) #endif diff --git a/kernel/sched.c b/kernel/sched.c index f03aff63..a7ee0eb5 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2910,6 +2910,7 @@ unsigned long nr_running(void) return sum; } +EXPORT_SYMBOL_GPL(nr_running); unsigned long nr_uninterruptible(void) {