diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/Kconfig fs/yaffs2/Kconfig --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/Kconfig 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/Kconfig 2009-08-05 14:02:22.762595000 -0400 @@ -12,8 +12,8 @@ YAFFS2, or Yet Another Flash Filing System, is a filing system optimised for NAND Flash chips. - To compile the YAFFS2 file system support as a module, choose M here: - the module will be called yaffs2. + To compile the YAFFS2 file system support as a module, choose M + here: the module will be called yaffs2. If unsure, say N. @@ -27,11 +27,30 @@ help Enable YAFFS1 support -- yaffs for 512 byte / page devices + Not needed for 2K-page devices. + If unsure, say Y. +config YAFFS_9BYTE_TAGS + bool "Use older-style on-NAND data format with pageStatus byte" + depends on YAFFS_YAFFS1 + default n + help + + Older-style on-NAND data format has a "pageStatus" byte to record + chunk/page state. This byte is zero when the page is discarded. + Choose this option if you have existing on-NAND data using this + format that you need to continue to support. New data written + also uses the older-style format. Note: Use of this option + generally requires that MTD's oob layout be adjusted to use the + older-style format. See notes on tags formats and MTD versions + in yaffs_mtdif1.c. + + If unsure, say N. + config YAFFS_DOES_ECC bool "Lets Yaffs do its own ECC" - depends on YAFFS_FS && YAFFS_YAFFS1 + depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS default n help This enables Yaffs to use its own ECC functions instead of using @@ -41,12 +60,12 @@ config YAFFS_ECC_WRONG_ORDER bool "Use the same ecc byte order as Steven Hill's nand_ecc.c" - depends on YAFFS_FS && YAFFS_DOES_ECC + depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS default n help - This makes yaffs_ecc.c use the same ecc byte order as - Steven Hill's nand_ecc.c. If not set, then you get the - same ecc byte order as SmartMedia. + This makes yaffs_ecc.c use the same ecc byte order as Steven + Hill's nand_ecc.c. If not set, then you get the same ecc byte + order as SmartMedia. If unsure, say N. @@ -55,7 +74,7 @@ depends on YAFFS_FS default y help - Enable YAFFS2 support -- yaffs for >= 2048 byte / page larger devices + Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices If unsure, say Y. @@ -66,7 +85,8 @@ help Without this, you need to explicitely use yaffs2 as the file system type. With this, you can say "yaffs" and yaffs or yaffs2 - will be used depending on the device page size. + will be used depending on the device page size (yaffs on + 512-byte page devices, yaffs2 on 2K page devices). If unsure, say Y. @@ -90,36 +110,19 @@ If unsure, say N. -config YAFFS_CHECKPOINT_RESERVED_BLOCKS - int "Reserved blocks for checkpointing" - depends on YAFFS_YAFFS2 - default 10 - help - Give the number of Blocks to reserve for checkpointing. These Blocks - are reserved per partition, so if you have very small partitions the - default (10) may be a mess for you. - You can set this value to 0, but that does not mean checkpointing is - disabled at all. There only won't be any specially reserved blocks for - checkpointing, so if there is enough free space on the filesystem, - it will be used for checkpointing. - - If unsure, leave at default (10), but don't wonder if there are always - 2MB used on your large page device partition (10 x 2k pagesize). When - using small partitions or when being very small on space, you probably - want to set this to zero. config YAFFS_DISABLE_WIDE_TNODES bool "Turn off wide tnodes" depends on YAFFS_FS default n help - Wide tnodes are only used for large NAND arrays (>=32MB for - 512-byte page devices and >=128MB for 2k page devices). They use - slightly more RAM but are faster since they eliminate chunk group + Wide tnodes are only used for NAND arrays >=32MB for 512-byte + page devices and >=128MB for 2k page devices. They use slightly + more RAM but are faster since they eliminate chunk group searching. - Setting this to 'y' will force tnode width to 16 bits and make - large arrays slower. + Setting this to 'y' will force tnode width to 16 bits and save + memory but make large arrays slower. If unsure, say N. @@ -129,15 +132,15 @@ default n help Normally YAFFS only checks chunks before writing until an erased - chunk is found. This helps to detect any partially written chunks - that might have happened due to power loss. + chunk is found. This helps to detect any partially written + chunks that might have happened due to power loss. Enabling this forces on the test that chunks are erased in flash - before writing to them. This takes more time but is potentially a - bit more secure. - - Suggest setting Y during development and ironing out driver issues - etc. Suggest setting to N if you want faster writing. + before writing to them. This takes more time but is potentially + a bit more secure. + + Suggest setting Y during development and ironing out driver + issues etc. Suggest setting to N if you want faster writing. If unsure, say Y. diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/Makefile fs/yaffs2/Makefile --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/Makefile 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/Makefile 2009-08-05 14:02:23.602509000 -0400 @@ -5,6 +5,6 @@ obj-$(CONFIG_YAFFS_FS) += yaffs.o yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o -yaffs-y += yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o -yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o +yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/devextras.h fs/yaffs2/devextras.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/devextras.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/devextras.h 2009-08-05 14:02:22.743600000 -0400 @@ -1,8 +1,7 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * devextras.h + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -12,206 +11,148 @@ * 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 used during development. - * Most of these are from kernel includes placed here so we can use them in - * applications. - * - * $Id: devextras.h,v 1.2 2005/08/11 02:37:49 marty Exp $ + */ + +/* + * This file is just holds extra declarations of macros that would normally + * be providesd in the Linux kernel. These macros have been written from + * scratch but are functionally equivalent to the Linux ones. * */ #ifndef __EXTRAS_H__ #define __EXTRAS_H__ -#if defined WIN32 -#define __inline__ __inline -#define new newHack -#endif - -#if !(defined __KERNEL__) || (defined WIN32) -/* User space defines */ +#if !(defined __KERNEL__) +/* Definition of types */ typedef unsigned char __u8; typedef unsigned short __u16; typedef unsigned __u32; +#endif + /* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. + * This is a simple doubly linked list implementation that matches the + * way the Linux kernel doubly linked list implementation works. */ -#define prefetch(x) 1 - -struct list_head { - struct list_head *next, *prev; +struct ylist_head { + struct ylist_head *next; /* next in chain */ + struct ylist_head *prev; /* previous in chain */ }; -#define LIST_HEAD_INIT(name) { &(name), &(name) } -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) +/* Initialise a static list */ +#define YLIST_HEAD(name) \ +struct ylist_head name = { &(name),&(name)} -#define INIT_LIST_HEAD(ptr) do { \ - (ptr)->next = (ptr); (ptr)->prev = (ptr); \ -} while (0) -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static __inline__ void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static __inline__ void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} +/* Initialise a list head to an empty list */ +#define YINIT_LIST_HEAD(p) \ +do { \ + (p)->next = (p);\ + (p)->prev = (p); \ +} while(0) -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static __inline__ void list_add_tail(struct list_head *new, - struct list_head *head) + +/* Add an element to a list */ +static __inline__ void ylist_add(struct ylist_head *newEntry, + struct ylist_head *list) { - __list_add(new, head->prev, head); + struct ylist_head *listNext = list->next; + + list->next = newEntry; + newEntry->prev = list; + newEntry->next = listNext; + listNext->prev = newEntry; + } -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static __inline__ void __list_del(struct list_head *prev, - struct list_head *next) +static __inline__ void ylist_add_tail(struct ylist_head *newEntry, + struct ylist_head *list) { - next->prev = prev; - prev->next = next; + struct ylist_head *listPrev = list->prev; + + list->prev = newEntry; + newEntry->next = list; + newEntry->prev = listPrev; + listPrev->next = newEntry; + } -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty on entry does not return true after this, the entry is - * in an undefined state. - */ -static __inline__ void list_del(struct list_head *entry) + +/* Take an element out of its current list, with or without + * reinitialising the links.of the entry*/ +static __inline__ void ylist_del(struct ylist_head *entry) { - __list_del(entry->prev, entry->next); + struct ylist_head *listNext = entry->next; + struct ylist_head *listPrev = entry->prev; + + listNext->prev = listPrev; + listPrev->next = listNext; + } -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static __inline__ void list_del_init(struct list_head *entry) +static __inline__ void ylist_del_init(struct ylist_head *entry) { - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); + ylist_del(entry); + entry->next = entry->prev = entry; } -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static __inline__ int list_empty(struct list_head *head) + +/* Test if the list is empty */ +static __inline__ int ylist_empty(struct ylist_head *entry) { - return head->next == head; + return (entry->next == entry); } -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. + +/* ylist_entry takes a pointer to a list entry and offsets it to that + * we can find a pointer to the object it is embedded in. */ -static __inline__ void list_splice(struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - if (first != list) { - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; - } -} -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) +#define ylist_entry(entry, type, member) \ + ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member))) -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next, prefetch(pos->next); pos != (head); \ - pos = pos->next, prefetch(pos->next)) - -/** - * list_for_each_safe - iterate over a list safe against removal - * of list entry - * @pos: the &struct list_head to use as a loop counter. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) -/* - * File types +/* 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 DT_UNKNOWN 0 -#define DT_FIFO 1 -#define DT_CHR 2 + +#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__) + + +#ifndef WIN32 +#include +#endif + + +#ifdef CONFIG_YAFFS_PROVIDE_DEFS +/* File types */ + + +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 #define DT_DIR 4 #define DT_BLK 6 -#define DT_REG 8 -#define DT_LNK 10 -#define DT_SOCK 12 -#define DT_WHT 14 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + #ifndef WIN32 #include @@ -221,17 +162,13 @@ * Attribute flags. These should be or-ed together to figure out what * has been changed! */ -#define ATTR_MODE 1 -#define ATTR_UID 2 +#define ATTR_MODE 1 +#define ATTR_UID 2 #define ATTR_GID 4 #define ATTR_SIZE 8 #define ATTR_ATIME 16 #define ATTR_MTIME 32 #define ATTR_CTIME 64 -#define ATTR_ATIME_SET 128 -#define ATTR_MTIME_SET 256 -#define ATTR_FORCE 512 /* Not a change, but a change it */ -#define ATTR_ATTR_FLAG 1024 struct iattr { unsigned int ia_valid; @@ -242,24 +179,21 @@ unsigned ia_atime; unsigned ia_mtime; unsigned ia_ctime; - unsigned int ia_attr_flags; + unsigned int ia_attr_flags; }; +#endif + + #define KERN_DEBUG #else -#ifndef WIN32 #include -#include #include #include -#endif #endif -#if defined WIN32 -#undef new -#endif #endif diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/moduleconfig.h fs/yaffs2/moduleconfig.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/moduleconfig.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/moduleconfig.h 2009-08-05 14:02:25.579321000 -0400 @@ -1,3 +1,18 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Martin Fouts + * + * 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_CONFIG_H__ #define __YAFFS_CONFIG_H__ @@ -29,7 +44,21 @@ /* Default: 10 */ /* Meaning: set the count of blocks to reserve for checkpointing */ -#define YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 +#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 + +/* +Older-style on-NAND data format has a "pageStatus" byte to record +chunk/page state. This byte is zeroed when the page is discarded. +Choose this option if you have existing on-NAND data in this format +that you need to continue to support. New data written also uses the +older-style format. +Note: Use of this option generally requires that MTD's oob layout be +adjusted to use the older-style format. See notes on tags formats and +MTD versions in yaffs_mtdif1.c. +*/ +/* Default: Not selected */ +/* Meaning: Use older-style on-NAND data format with pageStatus byte */ +//#define CONFIG_YAFFS_9BYTE_TAGS #endif /* YAFFS_OUT_OF_TREE */ diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_checkptrw.c fs/yaffs2/yaffs_checkptrw.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_checkptrw.c 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_checkptrw.c 2009-08-05 14:02:27.402130000 -0400 @@ -1,6 +1,7 @@ -/* YAFFS: Yet another FFS. A NAND-flash specific file system. +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -8,42 +9,40 @@ * 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. - * */ const char *yaffs_checkptrw_c_version = - "$Id: yaffs_checkptrw.c,v 1.11 2006/11/11 23:27:04 charles Exp $"; + "$Id$"; #include "yaffs_checkptrw.h" - +#include "yaffs_getblockinfo.h" static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) { int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; - + T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpt blocks available = %d" TENDSTR), blocksAvailable)); - - + + return (blocksAvailable <= 0) ? 0 : 1; } - static int yaffs_CheckpointErase(yaffs_Device *dev) { - + int i; - - if(!dev->eraseBlockInNAND) + + if(!dev->eraseBlockInNAND) return 0; T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR), dev->internalStartBlock,dev->internalEndBlock)); - + for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){ @@ -59,9 +58,9 @@ } } } - + dev->blocksInCheckpoint = 0; - + return 1; } @@ -73,11 +72,11 @@ T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock)); - + if(dev->checkpointNextBlock >= 0 && dev->checkpointNextBlock <= dev->internalEndBlock && blocksAvailable > 0){ - + for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){ @@ -89,7 +88,7 @@ } } T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR))); - + dev->checkpointNextBlock = -1; dev->checkpointCurrentBlock = -1; } @@ -98,19 +97,19 @@ { int i; yaffs_ExtendedTags tags; - + T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR), dev->blocksInCheckpoint, dev->checkpointNextBlock)); - - if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks) + + if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks) for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){ int chunk = i * dev->nChunksPerBlock; int realignedChunk = chunk - dev->chunkOffset; 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), + 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)); - + if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){ /* Right kind of block */ dev->checkpointNextBlock = tags.objectId; @@ -131,7 +130,7 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) { - + /* Got the functions we need? */ if (!dev->writeChunkWithTagsToNAND || !dev->readChunkWithTagsFromNAND || @@ -141,29 +140,31 @@ if(forWriting && !yaffs_CheckpointSpaceOk(dev)) return 0; - + if(!dev->checkpointBuffer) - dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk); + dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk); if(!dev->checkpointBuffer) return 0; - + dev->checkpointPageSequence = 0; - + dev->checkpointOpenForWrite = forWriting; - + dev->checkpointByteCount = 0; + dev->checkpointSum = 0; + dev->checkpointXor = 0; dev->checkpointCurrentBlock = -1; dev->checkpointCurrentChunk = -1; dev->checkpointNextBlock = dev->internalStartBlock; - + /* Erase all the blocks in the checkpoint area */ if(forWriting){ memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk); dev->checkpointByteOffset = 0; return yaffs_CheckpointErase(dev); - - + + } else { int i; /* Set to a value that will kick off a read */ @@ -176,7 +177,15 @@ for(i = 0; i < dev->checkpointMaxBlocks; i++) dev->checkpointBlockList[i] = -1; } - + + return 1; +} + +int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) +{ + __u32 compositeSum; + compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF); + *sum = compositeSum; return 1; } @@ -187,15 +196,15 @@ int realignedChunk; yaffs_ExtendedTags tags; - + if(dev->checkpointCurrentBlock < 0){ yaffs_CheckpointFindNextErasedBlock(dev); dev->checkpointCurrentChunk = 0; } - + if(dev->checkpointCurrentBlock < 0) return 0; - + tags.chunkDeleted = 0; tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */ tags.chunkId = dev->checkpointPageSequence + 1; @@ -208,25 +217,25 @@ bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; dev->blocksInCheckpoint++; } - + chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; - + T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), - chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId)); - + chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId)); + realignedChunk = chunk - dev->chunkOffset; - + dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags); dev->checkpointByteOffset = 0; - dev->checkpointPageSequence++; + dev->checkpointPageSequence++; dev->checkpointCurrentChunk++; if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){ dev->checkpointCurrentChunk = 0; dev->checkpointCurrentBlock = -1; } memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk); - + return 1; } @@ -236,31 +245,37 @@ int i=0; int ok = 1; - + __u8 * dataBytes = (__u8 *)data; - - + + if(!dev->checkpointBuffer) return 0; + if(!dev->checkpointOpenForWrite) + return -1; + while(i < nBytes && ok) { - - - dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ; + + + dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ; + dev->checkpointSum += *dataBytes; + dev->checkpointXor ^= *dataBytes; + dev->checkpointByteOffset++; i++; dataBytes++; dev->checkpointByteCount++; - - + + if(dev->checkpointByteOffset < 0 || - dev->checkpointByteOffset >= dev->nDataBytesPerChunk) + dev->checkpointByteOffset >= dev->nDataBytesPerChunk) ok = yaffs_CheckpointFlushBuffer(dev); } - + return i; } @@ -270,70 +285,76 @@ int ok = 1; yaffs_ExtendedTags tags; - + int chunk; int realignedChunk; __u8 *dataBytes = (__u8 *)data; - + if(!dev->checkpointBuffer) return 0; + if(dev->checkpointOpenForWrite) + return -1; + while(i < nBytes && ok) { - - + + if(dev->checkpointByteOffset < 0 || dev->checkpointByteOffset >= dev->nDataBytesPerChunk) { - + if(dev->checkpointCurrentBlock < 0){ yaffs_CheckpointFindNextCheckpointBlock(dev); dev->checkpointCurrentChunk = 0; } - + if(dev->checkpointCurrentBlock < 0) ok = 0; else { - - chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + + + chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; realignedChunk = chunk - dev->chunkOffset; /* read in the next chunk */ /* printf("read checkpoint page %d\n",dev->checkpointPage); */ - dev->readChunkWithTagsFromNAND(dev, realignedChunk, + dev->readChunkWithTagsFromNAND(dev, realignedChunk, dev->checkpointBuffer, &tags); - + if(tags.chunkId != (dev->checkpointPageSequence + 1) || + tags.eccResult > YAFFS_ECC_RESULT_FIXED || tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA) ok = 0; dev->checkpointByteOffset = 0; dev->checkpointPageSequence++; dev->checkpointCurrentChunk++; - + if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock) dev->checkpointCurrentBlock = -1; } } - + if(ok){ *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset]; + dev->checkpointSum += *dataBytes; + dev->checkpointXor ^= *dataBytes; dev->checkpointByteOffset++; i++; dataBytes++; dev->checkpointByteCount++; } } - + return i; } int yaffs_CheckpointClose(yaffs_Device *dev) { - if(dev->checkpointOpenForWrite){ + if(dev->checkpointOpenForWrite){ if(dev->checkpointByteOffset != 0) yaffs_CheckpointFlushBuffer(dev); } else { @@ -353,19 +374,19 @@ dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock; dev->nErasedBlocks -= dev->blocksInCheckpoint; - + T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR), dev->checkpointByteCount)); - + if(dev->checkpointBuffer){ - /* free the buffer */ + /* free the buffer */ YFREE(dev->checkpointBuffer); dev->checkpointBuffer = NULL; return 1; } else return 0; - + } int yaffs_CheckpointInvalidateStream(yaffs_Device *dev) diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_checkptrw.h fs/yaffs2/yaffs_checkptrw.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_checkptrw.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_checkptrw.h 2009-08-05 14:02:29.058038000 -0400 @@ -1,3 +1,18 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + #ifndef __YAFFS_CHECKPTRW_H__ #define __YAFFS_CHECKPTRW_H__ @@ -9,6 +24,8 @@ int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes); +int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); + int yaffs_CheckpointClose(yaffs_Device *dev); int yaffs_CheckpointInvalidateStream(yaffs_Device *dev); diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_ecc.c fs/yaffs2/yaffs_ecc.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_ecc.c 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_ecc.c 2009-08-05 14:02:30.817853000 -0400 @@ -1,27 +1,25 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * yaffs_ecc.c: ECC generation/correction algorithms. - * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * version 2.1 as published by the Free Software Foundation. + * 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 code implements the ECC algorithm used in SmartMedia. - * - * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. - * The two unused bit are set to 1. - * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC - * blocks are used on a 512-byte NAND page. - * - */ +/* + * This code implements the ECC algorithm used in SmartMedia. + * + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. + * The two unused bit are set to 1. + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC + * blocks are used on a 512-byte NAND page. + * + */ /* Table generated by gen-ecc.c * Using a table means we do not have to calculate p1..p4 and p1'..p4' @@ -31,7 +29,7 @@ */ const char *yaffs_ecc_c_version = - "$Id: yaffs_ecc.c,v 1.7 2006/09/14 22:02:46 charles Exp $"; + "$Id$"; #include "yportenv.h" @@ -230,8 +228,8 @@ return 1; /* Corrected the error */ } - if ((yaffs_CountBits(d0) + - yaffs_CountBits(d1) + + if ((yaffs_CountBits(d0) + + yaffs_CountBits(d1) + yaffs_CountBits(d2)) == 1) { /* Reccoverable error in ecc */ @@ -241,7 +239,7 @@ return 1; /* Corrected the error */ } - + /* Unrecoverable error */ return -1; @@ -295,7 +293,7 @@ if ((cDelta | lDelta | lDeltaPrime) == 0) return 0; /* no error */ - if (lDelta == ~lDeltaPrime && + if (lDelta == ~lDeltaPrime && (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) { /* Single bit (recoverable) error in data */ @@ -311,7 +309,7 @@ if(lDelta >= nBytes) return -1; - + data[lDelta] ^= (1 << bit); return 1; /* corrected */ diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_ecc.h fs/yaffs2/yaffs_ecc.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_ecc.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_ecc.h 2009-08-05 14:02:30.846852000 -0400 @@ -1,24 +1,24 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * yaffs_ecc.c: ECC generation/correction algorithms. - * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as + * 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 code implements the ECC algorithm used in SmartMedia. * - * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. * The two unused bit are set to 1. - * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC * blocks are used on a 512-byte NAND page. * */ diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_fs.c fs/yaffs2/yaffs_fs.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_fs.c 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_fs.c 2009-08-05 14:02:32.643666000 -0400 @@ -1,46 +1,48 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffs_fs.c + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning + * Acknowledgements: + * Luc van OostenRyck for numerous patches. + * Nick Bane for numerous patches. + * Nick Bane for 2.5/2.6 integration. + * Andras Toth for mknod rdev issue. + * Michael Fischer for finding the problem with inode inconsistency. + * Some code bodily lifted from JFFS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. + */ + +/* * * This is the file system front-end to YAFFS that hooks it up to * the VFS. * - * Special notes: + * Special notes: * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with * this superblock * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this * superblock * >> inode->u.generic_ip points to the associated yaffs_Object. - * - * Acknowledgements: - * * Luc van OostenRyck for numerous patches. - * * Nick Bane for numerous patches. - * * Nick Bane for 2.5/2.6 integration. - * * Andras Toth for mknod rdev issue. - * * Michael Fischer for finding the problem with inode inconsistency. - * * Some code bodily lifted from JFFS2. */ const char *yaffs_fs_c_version = - "$Id: yaffs_fs.c,v 1.55 2006/12/19 21:33:41 charles Exp $"; + "$Id$"; extern const char *yaffs_guts_c_version; +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) #include +#endif #include #include -#include #include #include -#include #include #include #include @@ -50,6 +52,8 @@ #include #include +#include "asm/div64.h" + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) #include /* Added NCB 15-8-2003 */ @@ -73,22 +77,67 @@ #endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) +#define YPROC_ROOT &proc_root +#else +#define YPROC_ROOT NULL +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +#define WRITE_SIZE_STR "writesize" +#define WRITE_SIZE(mtd) (mtd)->writesize +#else +#define WRITE_SIZE_STR "oobblock" +#define WRITE_SIZE(mtd) (mtd)->oobblock +#endif + #include #include "yportenv.h" #include "yaffs_guts.h" -unsigned yaffs_traceMask = YAFFS_TRACE_ALWAYS | - YAFFS_TRACE_BAD_BLOCKS - /* | 0xFFFFFFFF */; - #include #include "yaffs_mtdif.h" +#include "yaffs_mtdif1.h" #include "yaffs_mtdif2.h" +unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS; +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; +unsigned int yaffs_auto_checkpoint = 1; + +/* Module Parameters */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +module_param(yaffs_traceMask,uint,0644); +module_param(yaffs_wr_attempts,uint,0644); +module_param(yaffs_auto_checkpoint,uint,0644); +#else +MODULE_PARM(yaffs_traceMask,"i"); +MODULE_PARM(yaffs_wr_attempts,"i"); +MODULE_PARM(yaffs_auto_checkpoint,"i"); +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)) +/* use iget and read_inode */ +#define Y_IGET(sb,inum) iget((sb),(inum)) +static void yaffs_read_inode(struct inode *inode); + +#else +/* Call local equivalent */ +#define YAFFS_USE_OWN_IGET +#define Y_IGET(sb,inum) yaffs_iget((sb),(inum)) + +static struct inode * yaffs_iget(struct super_block *sb, unsigned long ino); +#endif + /*#define T(x) printk x */ -#define yaffs_InodeToObject(iptr) ((yaffs_Object *)((iptr)->u.generic_ip)) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) +#define yaffs_InodeToObjectLV(iptr) (iptr)->i_private +#else +#define yaffs_InodeToObjectLV(iptr) (iptr)->u.generic_ip +#endif + +#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr))) #define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode) #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) @@ -155,9 +204,11 @@ #else static int yaffs_statfs(struct super_block *sb, struct statfs *buf); #endif -static void yaffs_read_inode(struct inode *inode); +#ifdef YAFFS_HAS_PUT_INODE static void yaffs_put_inode(struct inode *inode); +#endif + static void yaffs_delete_inode(struct inode *); static void yaffs_clear_inode(struct inode *); @@ -187,6 +238,34 @@ .commit_write = yaffs_commit_write, }; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)) +static struct file_operations yaffs_file_operations = { + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, + .mmap = generic_file_mmap, + .flush = yaffs_file_flush, + .fsync = yaffs_sync_object, + .splice_read = generic_file_splice_read, + .splice_write = generic_file_splice_write, +}; + +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) + +static struct file_operations yaffs_file_operations = { + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, + .mmap = generic_file_mmap, + .flush = yaffs_file_flush, + .fsync = yaffs_sync_object, + .sendfile = generic_file_sendfile, +}; + +#else + static struct file_operations yaffs_file_operations = { .read = generic_file_read, .write = generic_file_write, @@ -196,8 +275,8 @@ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) .sendfile = generic_file_sendfile, #endif - }; +#endif static struct inode_operations yaffs_file_inode_operations = { .setattr = yaffs_setattr, @@ -230,8 +309,13 @@ static struct super_operations yaffs_super_ops = { .statfs = yaffs_statfs, + +#ifndef YAFFS_USE_OWN_IGET .read_inode = yaffs_read_inode, +#endif +#ifdef YAFFS_HAS_PUT_INODE .put_inode = yaffs_put_inode, +#endif .put_super = yaffs_put_super, .delete_inode = yaffs_delete_inode, .clear_inode = yaffs_clear_inode, @@ -337,7 +421,7 @@ dentry->d_name.name); obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */ - + /* Can't hold gross lock when calling yaffs_get_inode() */ yaffs_GrossUnlock(dev); @@ -375,6 +459,9 @@ } + +#ifdef YAFFS_HAS_PUT_INODE + /* For now put inode is just for debugging * Put inode is called when the inode **structure** is put. */ @@ -385,6 +472,7 @@ atomic_read(&inode->i_count))); } +#endif /* clear is called to tell the fs to release any per-inode data it holds */ static void yaffs_clear_inode(struct inode *inode) @@ -407,7 +495,7 @@ * the yaffs_Object. */ obj->myInode = NULL; - inode->u.generic_ip = NULL; + yaffs_InodeToObjectLV(inode) = NULL; /* If the object freeing was deferred, then the real * free happens now. @@ -629,13 +717,19 @@ unsigned to) { - void *addr = page_address(pg) + offset; + void *addr, *kva; + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset; int nBytes = to - offset; int nWritten; unsigned spos = pos; - unsigned saddr = (unsigned)addr; + unsigned saddr; + + kva=kmap(pg); + addr = kva + offset; + + saddr = (unsigned)addr; T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_commit_write addr %x pos %x nBytes %d\n", saddr, @@ -654,6 +748,8 @@ SetPageUptodate(pg); } + kunmap(pg); + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_commit_write returning %d\n", nWritten == nBytes ? 0 : nWritten)); @@ -675,21 +771,21 @@ obj->yst_mode &= ~S_IFMT; obj->yst_mode |= S_IFREG; } - + break; case YAFFS_OBJECT_TYPE_SYMLINK : if( ! S_ISLNK(mode) ){ obj->yst_mode &= ~S_IFMT; obj->yst_mode |= S_IFLNK; } - + break; case YAFFS_OBJECT_TYPE_DIRECTORY : if( ! S_ISDIR(mode) ){ obj->yst_mode &= ~S_IFMT; obj->yst_mode |= S_IFDIR; } - + break; case YAFFS_OBJECT_TYPE_UNKNOWN : case YAFFS_OBJECT_TYPE_HARDLINK : @@ -699,11 +795,15 @@ break; } + inode->i_flags |= S_NOATIME; + inode->i_ino = obj->objectId; inode->i_mode = obj->yst_mode; inode->i_uid = obj->yst_uid; inode->i_gid = obj->yst_gid; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) inode->i_blksize = inode->i_sb->s_blocksize; +#endif #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) inode->i_rdev = old_decode_dev(obj->yst_rdev); @@ -755,7 +855,8 @@ break; } - inode->u.generic_ip = obj; + yaffs_InodeToObjectLV(inode) = obj; + obj->myInode = inode; } else { @@ -787,7 +888,9 @@ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_get_inode for object %d\n", obj->objectId)); - inode = iget(sb, obj->objectId); + inode = Y_IGET(sb, obj->objectId); + if(IS_ERR(inode)) + return NULL; /* NB Side effect: iget calls back to yaffs_read_inode(). */ /* iget also increments the inode's i_count */ @@ -859,7 +962,7 @@ yaffs_Device *dev; struct inode *inode = f->f_dentry->d_inode; unsigned long offset, curoffs; - struct list_head *i; + struct ylist_head *i; yaffs_Object *l; char name[YAFFS_MAX_NAME_LENGTH + 1]; @@ -908,10 +1011,10 @@ f->f_version = inode->i_version; } - list_for_each(i, &obj->variant.directoryVariant.children) { + ylist_for_each(i, &obj->variant.directoryVariant.children) { curoffs++; if (curoffs >= offset) { - l = list_entry(i, yaffs_Object, siblings); + l = ylist_entry(i, yaffs_Object, siblings); yaffs_GetObjectName(l, name, YAFFS_MAX_NAME_LENGTH + 1); @@ -963,7 +1066,7 @@ int error = -ENOSPC; uid_t uid = current->fsuid; gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; - + if((dir->i_mode & S_ISGID) && S_ISDIR(mode)) mode |= S_ISGID; @@ -1018,7 +1121,7 @@ obj = NULL; /* Do we ever get here? */ break; } - + /* Can not call yaffs_get_inode() with gross lock held */ yaffs_GrossUnlock(dev); @@ -1207,13 +1310,13 @@ target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir), new_dentry->d_name.name); - - + + if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && - !list_empty(&target->variant.directoryVariant.children)) { - + !ylist_empty(&target->variant.directoryVariant.children)) { + T(YAFFS_TRACE_OS, (KERN_DEBUG "target is non-empty dir\n")); retVal = YAFFS_FAIL; @@ -1221,7 +1324,7 @@ /* Now does unlinking internally using shadowing mechanism */ T(YAFFS_TRACE_OS, (KERN_DEBUG "calling yaffs_RenameObject\n")); - + retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir), old_dentry->d_name.name, @@ -1293,25 +1396,47 @@ buf->f_type = YAFFS_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_namelen = 255; - if (sb->s_blocksize > dev->nDataBytesPerChunk) { - buf->f_blocks = - (dev->endBlock - dev->startBlock + - 1) * dev->nChunksPerBlock / (sb->s_blocksize / - dev->nDataBytesPerChunk); - buf->f_bfree = - yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize / - dev->nDataBytesPerChunk); - } else { + if(dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)){ + /* Do this if chunk size is not a power of 2 */ + + uint64_t bytesInDev; + uint64_t bytesFree; + + bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock +1))) * + ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk)); + + do_div(bytesInDev,sb->s_blocksize); /* bytesInDev becomes the number of blocks */ + buf->f_blocks = bytesInDev; + + bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) * + ((uint64_t)(dev->nDataBytesPerChunk)); + + do_div(bytesFree,sb->s_blocksize); + + buf->f_bfree = bytesFree; + + } else if (sb->s_blocksize > dev->nDataBytesPerChunk) { buf->f_blocks = - (dev->endBlock - dev->startBlock + - 1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk / - sb->s_blocksize); - buf->f_bfree = - yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk / - sb->s_blocksize); + (dev->endBlock - dev->startBlock + 1) * + dev->nChunksPerBlock / + (sb->s_blocksize / dev->nDataBytesPerChunk); + buf->f_bfree = + yaffs_GetNumberOfFreeChunks(dev) / + (sb->s_blocksize / dev->nDataBytesPerChunk); + } else { + buf->f_blocks = + (dev->endBlock - dev->startBlock + 1) * + dev->nChunksPerBlock * + (dev->nDataBytesPerChunk / sb->s_blocksize); + + buf->f_bfree = + yaffs_GetNumberOfFreeChunks(dev) * + (dev->nDataBytesPerChunk / sb->s_blocksize); } + + buf->f_files = 0; buf->f_ffree = 0; buf->f_bavail = buf->f_bfree; @@ -1321,7 +1446,6 @@ } - static int yaffs_do_sync_fs(struct super_block *sb) { @@ -1331,9 +1455,11 @@ if(sb->s_dirt) { yaffs_GrossLock(dev); - if(dev) + if(dev){ + yaffs_FlushEntireDeviceCache(dev); yaffs_CheckpointSave(dev); - + } + yaffs_GrossUnlock(dev); sb->s_dirt = 0; @@ -1350,8 +1476,10 @@ { T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_super\n")); + if (yaffs_auto_checkpoint >= 2) + yaffs_do_sync_fs(sb); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) - return 0; /* yaffs_do_sync_fs(sb);*/ + return 0; #endif } @@ -1364,16 +1492,54 @@ { T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n")); + + if (yaffs_auto_checkpoint >= 1) + yaffs_do_sync_fs(sb); - return 0; /* yaffs_do_sync_fs(sb);*/ + return 0; + +} + +#ifdef YAFFS_USE_OWN_IGET + +static struct inode * yaffs_iget(struct super_block *sb, unsigned long ino) +{ + struct inode *inode; + yaffs_Object *obj; + yaffs_Device *dev = yaffs_SuperToDevice(sb); + + T(YAFFS_TRACE_OS, + (KERN_DEBUG "yaffs_iget for %lu\n", ino)); + + inode = iget_locked(sb, ino); + if (!inode) + return ERR_PTR(-ENOMEM); + if (!(inode->i_state & I_NEW)) + return inode; + + /* NB This is called as a side effect of other functions, but + * we had to release the lock to prevent deadlocks, so + * need to lock again. + */ + + yaffs_GrossLock(dev); + + obj = yaffs_FindObjectByNumber(dev, inode->i_ino); + + yaffs_FillInodeFromObject(inode, obj); + + yaffs_GrossUnlock(dev); + unlock_new_inode(inode); + return inode; } +#else static void yaffs_read_inode(struct inode *inode) { /* NB This is called as a side effect of other functions, but - * we had to release the lock to prevent deadlocks, so + * we had to release the lock to prevent deadlocks, so * need to lock again. */ @@ -1384,7 +1550,7 @@ (KERN_DEBUG "yaffs_read_inode for %d\n", (int)inode->i_ino)); yaffs_GrossLock(dev); - + obj = yaffs_FindObjectByNumber(dev, inode->i_ino); yaffs_FillInodeFromObject(inode, obj); @@ -1392,7 +1558,40 @@ yaffs_GrossUnlock(dev); } -static LIST_HEAD(yaffs_dev_list); +#endif + +static YLIST_HEAD(yaffs_dev_list); + +#if 0 // not used +static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) +{ + yaffs_Device *dev = yaffs_SuperToDevice(sb); + + if( *flags & MS_RDONLY ) { + struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; + + T(YAFFS_TRACE_OS, + (KERN_DEBUG "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, + (KERN_DEBUG "yaffs_remount_fs: %s: RW\n", dev->name )); + } + + return 0; +} +#endif static void yaffs_put_super(struct super_block *sb) { @@ -1401,21 +1600,22 @@ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_put_super\n")); yaffs_GrossLock(dev); - + yaffs_FlushEntireDeviceCache(dev); - + + yaffs_CheckpointSave(dev); + if (dev->putSuperFunc) { dev->putSuperFunc(sb); } - - yaffs_CheckpointSave(dev); + yaffs_Deinitialise(dev); - + yaffs_GrossUnlock(dev); /* we assume this is protected by lock_kernel() in mount/umount */ - list_del(&dev->devList); - + ylist_del(&dev->devList); + if(dev->spareBuffer){ YFREE(dev->spareBuffer); dev->spareBuffer = NULL; @@ -1441,10 +1641,59 @@ static void yaffs_MarkSuperBlockDirty(void *vsb) { struct super_block *sb = (struct super_block *)vsb; - + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_MarkSuperBlockDirty() sb = %p\n",sb)); -// if(sb) -// sb->s_dirt = 1; + if(sb) + sb->s_dirt = 1; +} + +typedef struct { + int inband_tags; + int skip_checkpoint_read; + int skip_checkpoint_write; + int no_cache; +} yaffs_options; + +#define MAX_OPT_LEN 20 +static int yaffs_parse_options(yaffs_options *options, const char *options_str) +{ + char cur_opt[MAX_OPT_LEN+1]; + int p; + int error = 0; + + /* Parse through the options which is a comma seperated list */ + + while(options_str && *options_str && !error){ + memset(cur_opt,0,MAX_OPT_LEN+1); + p = 0; + + while(*options_str && *options_str != ','){ + if(p < MAX_OPT_LEN){ + cur_opt[p] = *options_str; + p++; + } + options_str++; + } + + if(!strcmp(cur_opt,"inband-tags")) + options->inband_tags = 1; + else if(!strcmp(cur_opt,"no-cache")) + options->no_cache = 1; + else if(!strcmp(cur_opt,"no-checkpoint-read")) + options->skip_checkpoint_read = 1; + else if(!strcmp(cur_opt,"no-checkpoint-write")) + options->skip_checkpoint_write = 1; + else if(!strcmp(cur_opt,"no-checkpoint")){ + options->skip_checkpoint_read = 1; + options->skip_checkpoint_write = 1; + } else { + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",cur_opt); + error = 1; + } + + } + + return error; } static struct super_block *yaffs_internal_read_super(int yaffsVersion, @@ -1458,9 +1707,13 @@ char devname_buf[BDEVNAME_SIZE + 1]; struct mtd_info *mtd; int err; + char *data_str = (char *)data; + + yaffs_options options; sb->s_magic = YAFFS_MAGIC; sb->s_op = &yaffs_super_ops; + sb->s_flags |= MS_NOATIME; if (!sb) printk(KERN_INFO "yaffs: sb is NULL\n"); @@ -1473,6 +1726,19 @@ sb->s_dev, yaffs_devname(sb, devname_buf)); + if(!data_str) + data_str = ""; + + printk(KERN_INFO "yaffs: passed flags \"%s\"\n",data_str); + + memset(&options,0,sizeof(options)); + + if(yaffs_parse_options(&options,data_str)){ + /* Option parsing failed */ + return NULL; + } + + sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion)); @@ -1516,37 +1782,26 @@ 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)); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - T(YAFFS_TRACE_OS, (" writesize %d\n", mtd->writesize)); -#else - T(YAFFS_TRACE_OS, (" oobblock %d\n", mtd->oobblock)); -#endif + 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, (" size %d\n", mtd->size)); - + #ifdef CONFIG_YAFFS_AUTO_YAFFS2 - if (yaffsVersion == 1 && -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - mtd->writesize >= 2048) { -#else - mtd->oobblock >= 2048) { -#endif + if (yaffsVersion == 1 && + WRITE_SIZE(mtd) >= 2048) { T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n")); yaffsVersion = 2; - } - + } + /* Added NCB 26/5/2006 for completeness */ if (yaffsVersion == 2 && -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - mtd->writesize == 512) { -#else - mtd->oobblock == 512) { -#endif + !options.inband_tags && + WRITE_SIZE(mtd) == 512){ T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n")); yaffsVersion = 1; - } + } #endif @@ -1569,12 +1824,9 @@ return NULL; } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE || -#else - if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE || -#endif - mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) { + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && + !options.inband_tags) { T(YAFFS_TRACE_ALWAYS, ("yaffs: MTD device does not have the " "right page sizes\n")); @@ -1597,11 +1849,7 @@ return NULL; } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - if (mtd->writesize < YAFFS_BYTES_PER_CHUNK || -#else - if (mtd->oobblock < YAFFS_BYTES_PER_CHUNK || -#endif + 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 " @@ -1638,9 +1886,10 @@ dev->startBlock = 0; dev->endBlock = nBlocks - 1; dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; - dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK; + dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK; dev->nReservedBlocks = 5; - dev->nShortOpCaches = 10; /* Enable short op caching */ + dev->nShortOpCaches = (options.no_cache) ? 0 : 10; + dev->inbandTags = options.inband_tags; /* ... and the functions. */ if (yaffsVersion == 2) { @@ -1653,20 +1902,29 @@ dev->spareBuffer = YMALLOC(mtd->oobsize); dev->isYaffs2 = 1; #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - dev->nDataBytesPerChunk = mtd->writesize; + dev->totalBytesPerChunk = mtd->writesize; dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; #else - dev->nDataBytesPerChunk = mtd->oobblock; + dev->totalBytesPerChunk = mtd->oobblock; dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; #endif nBlocks = mtd->size / mtd->erasesize; - dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS; dev->startBlock = 0; dev->endBlock = nBlocks - 1; } else { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + /* use the MTD interface in yaffs_mtdif1.c */ + dev->writeChunkWithTagsToNAND = + nandmtd1_WriteChunkWithTagsToNAND; + dev->readChunkWithTagsFromNAND = + nandmtd1_ReadChunkWithTagsFromNAND; + dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad; + dev->queryNANDBlock = nandmtd1_QueryNANDBlock; +#else dev->writeChunkToNAND = nandmtd_WriteChunkToNAND; dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND; +#endif dev->isYaffs2 = 0; } /* ... and common functions */ @@ -1674,10 +1932,10 @@ dev->initialiseNAND = nandmtd_InitialiseNAND; dev->putSuperFunc = yaffs_MTDPutSuper; - + dev->superBlock = (void *)sb; dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; - + #ifndef CONFIG_YAFFS_DOES_ECC dev->useNANDECC = 1; @@ -1687,8 +1945,11 @@ dev->wideTnodesDisabled = 1; #endif + dev->skipCheckpointRead = options.skip_checkpoint_read; + dev->skipCheckpointWrite = options.skip_checkpoint_write; + /* we assume this is protected by lock_kernel() in mount/umount */ - list_add_tail(&dev->devList, &yaffs_dev_list); + ylist_add_tail(&dev->devList, &yaffs_dev_list); init_MUTEX(&dev->grossLock); @@ -1699,7 +1960,7 @@ T(YAFFS_TRACE_OS, ("yaffs_read_super: guts initialised %s\n", (err == YAFFS_OK) ? "OK" : "FAILED")); - + /* Release lock before yaffs_get_inode() */ yaffs_GrossUnlock(dev); @@ -1725,6 +1986,9 @@ return NULL; } sb->s_root = root; + sb->s_dirt = !dev->isCheckpointed; + T(YAFFS_TRACE_ALWAYS, + ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed)); T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n")); return sb; @@ -1831,9 +2095,13 @@ { 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); @@ -1843,12 +2111,11 @@ buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads); buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures); buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies); - buf += - sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections); - buf += - sprintf(buf, "passiveGCs......... %d\n", + buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections); + buf += sprintf(buf, "passiveGCs......... %d\n", dev->passiveGarbageCollections); buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites); + buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches); buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks); buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed); buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed); @@ -1861,6 +2128,7 @@ 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; } @@ -1869,7 +2137,7 @@ char **start, off_t offset, int count, int *eof, void *data) { - struct list_head *item; + struct ylist_head *item; char *buf = page; int step = offset; int n = 0; @@ -1893,8 +2161,8 @@ lock_kernel(); /* Locate and print the Nth entry. Order N-squared but N is small. */ - list_for_each(item, &yaffs_dev_list) { - yaffs_Device *dev = list_entry(item, yaffs_Device, devList); + ylist_for_each(item, &yaffs_dev_list) { + yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList); if (n < step) { n++; continue; @@ -1911,6 +2179,7 @@ /** * Set the verbosity of the warnings and error messages. * + * Note that the names can only be a..z or _ with the current code. */ static struct { @@ -1922,6 +2191,7 @@ {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, {"buffers", YAFFS_TRACE_BUFFERS}, {"bug", YAFFS_TRACE_BUG}, + {"checkpt", YAFFS_TRACE_CHECKPOINT}, {"deletion", YAFFS_TRACE_DELETION}, {"erase", YAFFS_TRACE_ERASE}, {"error", YAFFS_TRACE_ERROR}, @@ -1933,20 +2203,30 @@ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, {"scan", YAFFS_TRACE_SCAN}, {"tracing", YAFFS_TRACE_TRACING}, + + {"verify", YAFFS_TRACE_VERIFY}, + {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, + {"verify_full", YAFFS_TRACE_VERIFY_FULL}, + {"verify_all", YAFFS_TRACE_VERIFY_ALL}, + {"write", YAFFS_TRACE_WRITE}, {"all", 0xffffffff}, {"none", 0}, {NULL, 0}, }; +#define MAX_MASK_NAME_LENGTH 40 static int yaffs_proc_write(struct file *file, const char *buf, unsigned long count, void *data) { unsigned rg = 0, mask_bitfield; - char *end, *mask_name; + char *end; + char *mask_name; + const char *x; + char substring[MAX_MASK_NAME_LENGTH+1]; int i; int done = 0; - int add, len; + int add, len = 0; int pos = 0; rg = yaffs_traceMask; @@ -1970,16 +2250,22 @@ break; } mask_name = NULL; + mask_bitfield = simple_strtoul(buf + pos, &end, 0); if (end > buf + pos) { mask_name = "numeral"; len = end - (buf + pos); + pos += len; done = 0; } else { + for(x = buf + pos, i = 0; + (*x == '_' || (*x >='a' && *x <= 'z')) && + i write_proc = yaffs_proc_write; @@ -2094,7 +2381,7 @@ T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__ " removing. \n")); - remove_proc_entry("yaffs", &proc_root); + remove_proc_entry("yaffs", YPROC_ROOT); fsinst = fs_to_install; diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_getblockinfo.h fs/yaffs2/yaffs_getblockinfo.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_getblockinfo.h 1969-12-31 19:00:00.000000000 -0500 +++ fs/yaffs2/yaffs_getblockinfo.h 2009-08-05 14:02:32.656670000 -0400 @@ -0,0 +1,34 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_GETBLOCKINFO_H__ +#define __YAFFS_GETBLOCKINFO_H__ + +#include "yaffs_guts.h" + +/* Function to manipulate block info */ +static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk) +{ + if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR), + blk)); + YBUG(); + } + return &dev->blockInfo[blk - dev->internalStartBlock]; +} + +#endif diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_guts.c fs/yaffs2/yaffs_guts.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_guts.c 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_guts.c 2009-08-06 12:10:47.340293000 -0400 @@ -1,7 +1,7 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -9,20 +9,20 @@ * 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. - * */ const char *yaffs_guts_c_version = - "$Id: yaffs_guts.c,v 1.45 2006/11/14 03:07:17 charles Exp $"; + "$Id$"; #include "yportenv.h" #include "yaffsinterface.h" #include "yaffs_guts.h" #include "yaffs_tagsvalidity.h" +#include "yaffs_getblockinfo.h" #include "yaffs_tagscompat.h" -#ifndef CONFIG_YAFFS_OWN_SORT +#ifndef CONFIG_YAFFS_USE_OWN_SORT #include "yaffs_qsort.h" #endif #include "yaffs_nand.h" @@ -79,9 +79,6 @@ static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blockNo); -static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo); -static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, - int lineNo); static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, int chunkInNAND); @@ -98,6 +95,8 @@ static void yaffs_VerifyFreeChunks(yaffs_Device * dev); +static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in); + #ifdef YAFFS_PARANOID static int yaffs_CheckFileSanity(yaffs_Object * in); #else @@ -109,27 +108,43 @@ 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); /* Function to calculate chunk and offset */ -static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, __u32 *chunk, __u32 *offset) +static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut, __u32 *offsetOut) { - if(dev->chunkShift){ - /* Easy-peasy power of 2 case */ - *chunk = (__u32)(addr >> dev->chunkShift); - *offset = (__u32)(addr & dev->chunkMask); - } - else if(dev->crumbsPerChunk) + int chunk; + __u32 offset; + + chunk = (__u32)(addr >> dev->chunkShift); + + if(dev->chunkDiv == 1) { - /* Case where we're using "crumbs" */ - *offset = (__u32)(addr & dev->crumbMask); - addr >>= dev->crumbShift; - *chunk = ((__u32)addr)/dev->crumbsPerChunk; - *offset += ((addr - (*chunk * dev->crumbsPerChunk)) << dev->crumbShift); + /* easy power of 2 case */ + offset = (__u32)(addr & dev->chunkMask); } else - YBUG(); + { + /* Non power-of-2 case */ + + loff_t chunkBase; + + chunk /= dev->chunkDiv; + + chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk; + offset = (__u32)(addr - chunkBase); + } + + *chunkOut = chunk; + *offsetOut = offset; } /* Function to return the number of shifts for a power of 2 greater than or equal @@ -160,7 +175,7 @@ /* Function to return the number of shifts to get a 1 in bit 0 */ -static __u32 ShiftDiv(__u32 x) +static __u32 Shifts(__u32 x) { int nShifts; @@ -182,9 +197,31 @@ * Temporary buffer manipulations. */ -static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo) +static int yaffs_InitialiseTempBuffers(yaffs_Device *dev) +{ + int i; + __u8 *buf = (__u8 *)1; + + memset(dev->tempBuffer,0,sizeof(dev->tempBuffer)); + + for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { + dev->tempBuffer[i].line = 0; /* not in use */ + dev->tempBuffer[i].buffer = buf = + YMALLOC_DMA(dev->totalBytesPerChunk); + } + + return buf ? YAFFS_OK : YAFFS_FAIL; + +} + +__u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo) { int i, j; + + dev->tempInUse++; + if(dev->tempInUse > dev->maxTemp) + dev->maxTemp = dev->tempInUse; + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { if (dev->tempBuffer[i].line == 0) { dev->tempBuffer[i].line = lineNo; @@ -217,10 +254,13 @@ } -static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, +void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, int lineNo) { int i; + + dev->tempInUse--; + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { if (dev->tempBuffer[i].buffer == buffer) { dev->tempBuffer[i].line = 0; @@ -265,6 +305,8 @@ return 0; } + + /* * Chunk bitmap manipulations */ @@ -281,6 +323,16 @@ (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); @@ -292,6 +344,8 @@ { __u8 *blkBits = yaffs_BlockBits(dev, blk); + yaffs_VerifyChunkBitId(dev,blk,chunk); + blkBits[chunk / 8] &= ~(1 << (chunk & 7)); } @@ -299,12 +353,16 @@ { __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; } @@ -320,6 +378,492 @@ 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)); +} + +#if 0 +static int yaffs_SkipFullVerification(yaffs_Device *dev) +{ + return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); +} + +#endif + +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 <0 || 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 */ + /* TODO: This will need to change if we do partial gc */ + + if(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 >=0 && 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(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)); +} + + + +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; + +} + + +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 && 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_VerifyDirectory(yaffs_Object *obj) +{ + if(obj && yaffs_SkipVerification(obj->myDev)) + return; + +} + +static void yaffs_VerifyHardLink(yaffs_Object *obj) +{ + if(obj && yaffs_SkipVerification(obj->myDev)) + return; + + /* Verify sane equivalent object */ +} + +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 chunkIsLive; + + if(!obj) + return; + + dev = obj->myDev; + + if(yaffs_SkipVerification(dev)) + return; + + /* Check sane object header chunk */ + + chunkMin = dev->internalStartBlock * dev->nChunksPerBlock; + chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1; + + chunkIdOk = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax); + chunkIsLive = chunkIdOk && + yaffs_CheckChunkBit(dev, + obj->hdrChunk / dev->nChunksPerBlock, + obj->hdrChunk % dev->nChunksPerBlock); + if(!obj->fake && + (!chunkIdOk || !chunkIsLive)) { + T(YAFFS_TRACE_VERIFY, + (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), + obj->objectId,obj->hdrChunk, + chunkIdOk ? "" : ",out of range", + chunkIsLive || !chunkIdOk ? "" : ",marked as deleted")); + } + + if(chunkIdOk && chunkIsLive &&!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); + } + } + } + +} + + /* * Simple hash function. Needs to have a reasonable spread */ @@ -331,7 +875,8 @@ } /* - * Access functions to useful fake objects + * Access functions to useful fake objects. + * Note that root might have a presence in NAND if permissions are set. */ yaffs_Object *yaffs_Root(yaffs_Device * dev) @@ -392,86 +937,88 @@ yaffs_ExtendedTags * tags, int useReserve) { + int attempts = 0; + int writeOk = 0; int chunk; - int writeOk = 0; - int erasedOk = 1; - int attempts = 0; - yaffs_BlockInfo *bi; - yaffs_InvalidateCheckpoint(dev); do { - chunk = yaffs_AllocateChunk(dev, useReserve,&bi); + yaffs_BlockInfo *bi = 0; + int erasedOk = 0; - if (chunk >= 0) { - /* First check this chunk is erased, if it needs checking. - * The checking policy (unless forced always on) is as follows: - * Check the first page we try to write in a block. - * - If the check passes then we don't need to check any more. - * - If the check fails, we check again... - * If the block has been erased, we don't need to check. - * - * However, if the block has been prioritised for gc, then - * we think there might be something odd about this block - * and stop using it. - * - * Rationale: - * We should only ever see chunks that have not been erased - * if there was a partially written chunk due to power loss - * This checking policy should catch that case with very - * few checks and thus save a lot of checks that are most likely not - * needed. - */ - - if(bi->gcPrioritise){ - yaffs_DeleteChunk(dev, chunk, 1, __LINE__); - } else { -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED + chunk = yaffs_AllocateChunk(dev, useReserve, &bi); + if (chunk < 0) { + /* no space */ + break; + } - bi->skipErasedCheck = 0; + /* First check this chunk is erased, if it needs + * checking. The checking policy (unless forced + * always on) is as follows: + * + * Check the first page we try to write in a block. + * If the check passes then we don't need to check any + * more. If the check fails, we check again... + * If the block has been erased, we don't need to check. + * + * However, if the block has been prioritised for gc, + * then we think there might be something odd about + * this block and stop using it. + * + * Rationale: We should only ever see chunks that have + * not been erased if there was a partially written + * chunk due to power loss. This checking policy should + * catch that case with very few checks and thus save a + * lot of checks that are most likely not needed. + */ + if (bi->gcPrioritise) { + yaffs_DeleteChunk(dev, chunk, 1, __LINE__); + /* try another chunk */ + continue; + } -#endif - if(!bi->skipErasedCheck){ - erasedOk = yaffs_CheckChunkErased(dev, chunk); - if(erasedOk && !bi->gcPrioritise) - bi->skipErasedCheck = 1; - } + /* let's give it a try */ + attempts++; - if (!erasedOk) { - T(YAFFS_TRACE_ERROR, - (TSTR - ("**>> yaffs chunk %d was not erased" - TENDSTR), chunk)); - } else { - writeOk = - yaffs_WriteChunkWithTagsToNAND(dev, chunk, - data, tags); - } - - attempts++; +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED + bi->skipErasedCheck = 0; +#endif + if (!bi->skipErasedCheck) { + erasedOk = yaffs_CheckChunkErased(dev, chunk); + if (erasedOk != YAFFS_OK) { + T(YAFFS_TRACE_ERROR, + (TSTR ("**>> yaffs chunk %d was not erased" + TENDSTR), chunk)); - if (writeOk) { - /* - * Copy the data into the robustification buffer. - * NB We do this at the end to prevent duplicates in the case of a write error. - * Todo - */ - yaffs_HandleWriteChunkOk(dev, chunk, data, tags); - - } else { - /* The erased check or write failed */ - yaffs_HandleWriteChunkError(dev, chunk, erasedOk); - } + /* try another chunk */ + continue; } + bi->skipErasedCheck = 1; } - } while (chunk >= 0 && !writeOk); + writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, + data, tags); + if (writeOk != YAFFS_OK) { + yaffs_HandleWriteChunkError(dev, chunk, erasedOk); + /* try another chunk */ + continue; + } + + /* Copy the data into the robustification buffer */ + yaffs_HandleWriteChunkOk(dev, chunk, data, tags); + + } while (writeOk != YAFFS_OK && + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); + + if(!writeOk) + chunk = -1; if (attempts > 1) { T(YAFFS_TRACE_ERROR, - (TSTR("**>> yaffs write required %d attempts" TENDSTR), - attempts)); + (TSTR("**>> yaffs write required %d attempts" TENDSTR), + attempts)); + dev->nRetriedWrites += (attempts - 1); } @@ -488,7 +1035,30 @@ yaffs_InvalidateCheckpoint(dev); - yaffs_MarkBlockBad(dev, blockInNAND); + if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) { + if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) { + T(YAFFS_TRACE_ALWAYS, (TSTR( + "yaffs: Failed to mark bad and erase block %d" + TENDSTR), blockInNAND)); + } + else { + yaffs_ExtendedTags tags; + int chunkId = blockInNAND * dev->nChunksPerBlock; + + __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); + + memset(buffer, 0xff, dev->nDataBytesPerChunk); + yaffs_InitialiseTags(&tags); + tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK; + if (dev->writeChunkWithTagsToNAND(dev, chunkId - + dev->chunkOffset, buffer, &tags) != YAFFS_OK) + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to " + "write bad block marker to block %d" + TENDSTR), blockInNAND)); + + yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); + } + } bi->blockState = YAFFS_BLOCK_STATE_DEAD; bi->gcPrioritise = 0; @@ -529,21 +1099,6 @@ } } -static void yaffs_ReportOddballBlocks(yaffs_Device *dev) -{ - int i; - - for(i = dev->internalStartBlock; i <= dev->internalEndBlock && (yaffs_traceMask & YAFFS_TRACE_BAD_BLOCKS); i++){ - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); - if(bi->needsRetiring || bi->gcPrioritise) - T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("yaffs block %d%s%s" TENDSTR), - i, - bi->needsRetiring ? " needs retiring" : "", - bi->gcPrioritise ? " gc prioritised" : "")); - - } -} - static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk) { @@ -576,7 +1131,7 @@ YUCHAR *bname = (YUCHAR *) name; if (bname) { - while ((*bname) && (i <= YAFFS_MAX_NAME_LENGTH)) { + while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) { #ifdef CONFIG_YAFFS_CASE_INSENSITIVE sum += yaffs_toupper(*bname) * i; @@ -631,6 +1186,10 @@ * 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); @@ -684,6 +1243,7 @@ T(YAFFS_TRACE_ERROR, (TSTR ("yaffs: Could not add tnodes to management list" TENDSTR))); + return YAFFS_FAIL; } else { tnl->tnodes = newTnodes; @@ -720,15 +1280,21 @@ dev->nFreeTnodes--; } + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ + return tn; } static yaffs_Tnode *yaffs_GetTnode(yaffs_Device * dev) { yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev); + int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + + if(tnodeSize < sizeof(yaffs_Tnode)) + tnodeSize = sizeof(yaffs_Tnode); if(tn) - memset(tn, 0, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); + memset(tn, 0, tnodeSize); return tn; } @@ -749,6 +1315,8 @@ dev->freeTnodes = tn; dev->nFreeTnodes++; } + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ + } static void yaffs_DeinitialiseTnodes(yaffs_Device * dev) @@ -808,7 +1376,7 @@ } } -__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos) +static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos) { __u32 *map = (__u32 *)tn; __u32 bitInMap; @@ -1326,35 +1894,34 @@ /* make these things */ newObjects = YMALLOC(nObjects * sizeof(yaffs_Object)); + list = YMALLOC(sizeof(yaffs_ObjectList)); - if (!newObjects) { + 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 list_head *)(&newObjects[i + 1]); - } + /* 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; + 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 = YMALLOC(sizeof(yaffs_ObjectList)); - if (!list) { - T(YAFFS_TRACE_ALLOCATE, - (TSTR("Could not add objects to management list" TENDSTR))); - } else { - list->objects = newObjects; - list->next = dev->allocatedObjectList; - dev->allocatedObjectList = list; - } + list->objects = newObjects; + list->next = dev->allocatedObjectList; + dev->allocatedObjectList = list; return YAFFS_OK; } @@ -1380,14 +1947,14 @@ memset(tn, 0, sizeof(yaffs_Object)); tn->myDev = dev; - tn->chunkId = -1; + tn->hdrChunk = 0; tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN; - INIT_LIST_HEAD(&(tn->hardLinks)); - INIT_LIST_HEAD(&(tn->hashLink)); - INIT_LIST_HEAD(&tn->siblings); + YINIT_LIST_HEAD(&(tn->hardLinks)); + YINIT_LIST_HEAD(&(tn->hashLink)); + YINIT_LIST_HEAD(&tn->siblings); - /* Add it to the lost and found directory. - * NB Can't put root or lostNFound in lostNFound so + /* Add it to the lost and found directory. + * NB Can't put root or lostNFound in lostNFound so * check if lostNFound exists first */ if (dev->lostNFoundDir) { @@ -1395,6 +1962,8 @@ } } + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ + return tn; } @@ -1405,14 +1974,14 @@ yaffs_Object *obj = yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); if (obj) { - obj->fake = 1; /* it is fake so it has no NAND presence... */ + obj->fake = 1; /* it is fake so it might have no NAND presence... */ obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */ obj->unlinkAllowed = 0; /* ... or unlink it */ obj->deleted = 0; obj->unlinked = 0; obj->yst_mode = mode; obj->myDev = dev; - obj->chunkId = 0; /* Not a valid chunk. */ + obj->hdrChunk = 0; /* Not a valid chunk. */ } return obj; @@ -1422,14 +1991,14 @@ static void yaffs_UnhashObject(yaffs_Object * tn) { int bucket; - yaffs_Device *dev = tn->myDev; + yaffs_Device *dev = tn->myDev; - /* If it is still linked into the bucket list, free from the list */ - if (!list_empty(&tn->hashLink)) { - list_del_init(&tn->hashLink); - bucket = yaffs_HashFunction(tn->objectId); - dev->objectBucket[bucket].count--; - } + /* If it is still linked into the bucket list, free from the list */ + if (!ylist_empty(&tn->hashLink)) { + ylist_del_init(&tn->hashLink); + bucket = yaffs_HashFunction(tn->objectId); + dev->objectBucket[bucket].count--; + } } @@ -1449,12 +2018,15 @@ } #endif - yaffs_UnhashObject(tn); + yaffs_UnhashObject(tn); + + /* Link into the free list. */ + tn->siblings.next = (struct ylist_head *)(dev->freeObjects); + dev->freeObjects = tn; + dev->nFreeObjects++; + + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ - /* Link into the free list. */ - tn->siblings.next = (struct list_head *)(dev->freeObjects); - dev->freeObjects = tn; - dev->nFreeObjects++; } #ifdef __KERNEL__ @@ -1492,12 +2064,12 @@ dev->allocatedObjectList = NULL; dev->freeObjects = NULL; - dev->nFreeObjects = 0; + dev->nFreeObjects = 0; - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { - INIT_LIST_HEAD(&dev->objectBucket[i].list); - dev->objectBucket[i].count = 0; - } + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { + YINIT_LIST_HEAD(&dev->objectBucket[i].list); + dev->objectBucket[i].count = 0; + } } @@ -1543,26 +2115,26 @@ /* Now find an object value that has not already been taken * by scanning the list. - */ + */ - int found = 0; - struct list_head *i; + int found = 0; + struct ylist_head *i; - __u32 n = (__u32) bucket; + __u32 n = (__u32) bucket; /* yaffs_CheckObjectHashSanity(); */ while (!found) { - found = 1; - n += YAFFS_NOBJECT_BUCKETS; - if (1 || dev->objectBucket[bucket].count > 0) { - list_for_each(i, &dev->objectBucket[bucket].list) { - /* If there is already one in the list */ - if (i - && list_entry(i, yaffs_Object, - hashLink)->objectId == n) { - found = 0; - } + found = 1; + n += YAFFS_NOBJECT_BUCKETS; + if (1 || dev->objectBucket[bucket].count > 0) { + ylist_for_each(i, &dev->objectBucket[bucket].list) { + /* If there is already one in the list */ + if (i + && ylist_entry(i, yaffs_Object, + hashLink)->objectId == n) { + found = 0; + } } } } @@ -1573,27 +2145,27 @@ static void yaffs_HashObject(yaffs_Object * in) { - int bucket = yaffs_HashFunction(in->objectId); - yaffs_Device *dev = in->myDev; + int bucket = yaffs_HashFunction(in->objectId); + yaffs_Device *dev = in->myDev; - list_add(&in->hashLink, &dev->objectBucket[bucket].list); - dev->objectBucket[bucket].count++; + ylist_add(&in->hashLink, &dev->objectBucket[bucket].list); + dev->objectBucket[bucket].count++; } yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number) { - int bucket = yaffs_HashFunction(number); - struct list_head *i; - yaffs_Object *in; - - list_for_each(i, &dev->objectBucket[bucket].list) { - /* Look if it is in the list */ - if (i) { - in = list_entry(i, yaffs_Object, hashLink); - if (in->objectId == number) { + int bucket = yaffs_HashFunction(number); + struct ylist_head *i; + yaffs_Object *in; + + ylist_for_each(i, &dev->objectBucket[bucket].list) { + /* Look if it is in the list */ + if (i) { + in = ylist_entry(i, yaffs_Object, hashLink); + if (in->objectId == number) { #ifdef __KERNEL__ - /* Don't tell the VFS about this one if it is defered free */ + /* Don't tell the VFS about this one if it is defered free */ if (in->deferedFree) return NULL; #endif @@ -1611,12 +2183,25 @@ { yaffs_Object *theObject; + yaffs_Tnode *tn = NULL; if (number < 0) { number = yaffs_CreateNewObjectNumber(dev); } theObject = yaffs_AllocateEmptyObject(dev); + if(!theObject) + return NULL; + + if(type == YAFFS_OBJECT_TYPE_FILE){ + tn = yaffs_GetTnode(dev); + if(!tn){ + yaffs_FreeObject(theObject); + return NULL; + } + } + + if (theObject) { theObject->fake = 0; @@ -1643,14 +2228,13 @@ theObject->variant.fileVariant.scannedFileSize = 0; theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */ theObject->variant.fileVariant.topLevel = 0; - theObject->variant.fileVariant.top = - yaffs_GetTnode(dev); - break; - case YAFFS_OBJECT_TYPE_DIRECTORY: - INIT_LIST_HEAD(&theObject->variant.directoryVariant. - children); - break; - case YAFFS_OBJECT_TYPE_SYMLINK: + theObject->variant.fileVariant.top = tn; + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + YINIT_LIST_HEAD(&theObject->variant.directoryVariant. + children); + break; + case YAFFS_OBJECT_TYPE_SYMLINK: case YAFFS_OBJECT_TYPE_HARDLINK: case YAFFS_OBJECT_TYPE_SPECIAL: /* No action required */ @@ -1689,7 +2273,8 @@ if (str && *str) { newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); - yaffs_strcpy(newStr, str); + if(newStr) + yaffs_strcpy(newStr, str); } return newStr; @@ -1713,6 +2298,7 @@ const YCHAR * aliasString, __u32 rdev) { yaffs_Object *in; + YCHAR *str = NULL; yaffs_Device *dev = parent->myDev; @@ -1723,8 +2309,18 @@ in = yaffs_CreateNewObject(dev, -1, type); + if(type == YAFFS_OBJECT_TYPE_SYMLINK){ + str = yaffs_CloneString(aliasString); + if(!str){ + yaffs_FreeObject(in); + return NULL; + } + } + + + if (in) { - in->chunkId = -1; + in->hdrChunk = 0; in->valid = 1; in->variantType = type; @@ -1753,18 +2349,17 @@ switch (type) { case YAFFS_OBJECT_TYPE_SYMLINK: - in->variant.symLinkVariant.alias = - yaffs_CloneString(aliasString); + in->variant.symLinkVariant.alias = str; break; case YAFFS_OBJECT_TYPE_HARDLINK: in->variant.hardLinkVariant.equivalentObject = - equivalentObject; - in->variant.hardLinkVariant.equivalentObjectId = - equivalentObject->objectId; - list_add(&in->hardLinks, &equivalentObject->hardLinks); - break; - case YAFFS_OBJECT_TYPE_FILE: - case YAFFS_OBJECT_TYPE_DIRECTORY: + equivalentObject; + in->variant.hardLinkVariant.equivalentObjectId = + equivalentObject->objectId; + ylist_add(&in->hardLinks, &equivalentObject->hardLinks); + break; + case YAFFS_OBJECT_TYPE_FILE: + case YAFFS_OBJECT_TYPE_DIRECTORY: case YAFFS_OBJECT_TYPE_SPECIAL: case YAFFS_OBJECT_TYPE_UNKNOWN: /* do nothing */ @@ -1919,13 +2514,13 @@ /* Now do the handling for an existing target, if there is one */ - existingTarget = yaffs_FindObjectByName(newDir, newName); - if (existingTarget && - existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && - !list_empty(&existingTarget->variant.directoryVariant.children)) { - /* There is a target that is a non-empty directory, so we fail */ - return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */ - } else if (existingTarget && existingTarget != obj) { + existingTarget = yaffs_FindObjectByName(newDir, newName); + if (existingTarget && + existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && + !ylist_empty(&existingTarget->variant.directoryVariant.children)) { + /* There is a target that is a non-empty directory, so we fail */ + return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */ + } else if (existingTarget && existingTarget != obj) { /* Nuke the target first, using shadowing, * but only if it isn't the same object */ @@ -1945,9 +2540,12 @@ { int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; + dev->blockInfo = NULL; + dev->chunkBits = NULL; + dev->allocationBlock = -1; /* force it to get a new one */ - /* Todo we're assuming the malloc will pass. */ + /* If the first allocation strategy fails, thry the alternate one */ dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo)); if(!dev->blockInfo){ dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo)); @@ -1955,16 +2553,19 @@ } else dev->blockInfoAlt = 0; + + if(dev->blockInfo){ - /* Set up dynamic blockinfo stuff. */ - dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ - dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); - if(!dev->chunkBits){ - dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); - dev->chunkBitsAlt = 1; + /* Set up dynamic blockinfo stuff. */ + dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ + dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); + if(!dev->chunkBits){ + dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); + dev->chunkBitsAlt = 1; + } + else + dev->chunkBitsAlt = 0; } - else - dev->chunkBitsAlt = 0; if (dev->blockInfo && dev->chunkBits) { memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo)); @@ -1978,17 +2579,18 @@ static void yaffs_DeinitialiseBlocks(yaffs_Device * dev) { - if(dev->blockInfoAlt) + if(dev->blockInfoAlt && dev->blockInfo) YFREE_ALT(dev->blockInfo); - else + else if(dev->blockInfo) YFREE(dev->blockInfo); + dev->blockInfoAlt = 0; dev->blockInfo = NULL; - if(dev->chunkBitsAlt) + if(dev->chunkBitsAlt && dev->chunkBits) YFREE_ALT(dev->chunkBits); - else + else if(dev->chunkBits) YFREE(dev->chunkBits); dev->chunkBitsAlt = 0; dev->chunkBits = NULL; @@ -2045,10 +2647,9 @@ int i; int iterations; int dirtiest = -1; - int pagesInUse; + int pagesInUse = 0; int prioritised=0; yaffs_BlockInfo *bi; - static int nonAggressiveSkip = 0; int pendingPrioritisedExist = 0; /* First let's see if we need to grab a prioritised block */ @@ -2056,6 +2657,8 @@ 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 && @@ -2078,9 +2681,9 @@ * block has only a few pages in use. */ - nonAggressiveSkip--; + dev->nonAggressiveSkip--; - if (!aggressive && (nonAggressiveSkip > 0)) { + if (!aggressive && (dev->nonAggressiveSkip > 0)) { return -1; } @@ -2141,7 +2744,7 @@ dev->oldestDirtySequence = 0; if (dirtiest > 0) { - nonAggressiveSkip = 4; + dev->nonAggressiveSkip = 4; } return dirtiest; @@ -2173,7 +2776,8 @@ } } - if (erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE)) { + if (erasedOk && + ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) { int i; for (i = 0; i < dev->nChunksPerBlock; i++) { if (!yaffs_CheckChunkErased @@ -2257,6 +2861,40 @@ } + +static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev) +{ + if(!dev->nCheckpointBlocksRequired){ + /* 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) @@ -2265,7 +2903,7 @@ int reservedBlocks = dev->nReservedBlocks; int checkpointBlocks; - checkpointBlocks = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; + checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; if(checkpointBlocks < 0) checkpointBlocks = 0; @@ -2351,6 +2989,7 @@ int cleanups = 0; int i; int isCheckpointBlock; + int matchingChunk; int chunksBefore = yaffs_GetErasedChunks(dev); int chunksAfter; @@ -2391,6 +3030,8 @@ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); + yaffs_VerifyBlock(dev,bi,block); + for (chunkInBlock = 0, oldChunk = block * dev->nChunksPerBlock; chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev, block); @@ -2416,11 +3057,27 @@ chunkInBlock, tags.objectId, tags.chunkId, tags.byteCount)); + if(object && !yaffs_SkipVerification(dev)){ + if(tags.chunkId == 0) + matchingChunk = object->hdrChunk; + else if(object->softDeleted) + matchingChunk = oldChunk; /* Defeat the test */ + else + matchingChunk = yaffs_FindChunkInFile(object,tags.chunkId,NULL); + + if(oldChunk != matchingChunk) + T(YAFFS_TRACE_ERROR, + (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR), + oldChunk,matchingChunk,tags.objectId, tags.chunkId)); + + } + if (!object) { T(YAFFS_TRACE_ERROR, (TSTR - ("page %d in gc has no object " - TENDSTR), oldChunk)); + ("page %d in gc has no object: %d %d %d " + TENDSTR), oldChunk, + tags.objectId, tags.chunkId, tags.byteCount)); } if (object && object->deleted @@ -2446,7 +3103,7 @@ /* Deleted object header with no data chunks. * Can be discarded and the file deleted. */ - object->chunkId = 0; + object->hdrChunk = 0; yaffs_FreeTnode(object->myDev, object->variant. fileVariant.top); @@ -2474,9 +3131,11 @@ yaffs_ObjectHeader *oh; oh = (yaffs_ObjectHeader *)buffer; oh->isShrink = 0; - oh->shadowsObject = -1; + oh->shadowsObject = oh->inbandShadowsObject = -1; tags.extraShadows = 0; tags.extraIsShrinkHeader = 0; + + yaffs_VerifyObjectHeader(object,oh,&tags,1); } newChunk = @@ -2490,7 +3149,7 @@ if (tags.chunkId == 0) { /* It's a header */ - object->chunkId = newChunk; + object->hdrChunk = newChunk; object->serial = tags.serialNumber; } else { /* It's a data chunk */ @@ -2533,6 +3192,8 @@ } + yaffs_VerifyCollectedBlock(dev,bi,block); + if (chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev))) { T(YAFFS_TRACE_GC, (TSTR @@ -2575,11 +3236,11 @@ do { maxTries++; - checkpointBlockAdjust = (dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint); + checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; if(checkpointBlockAdjust < 0) checkpointBlockAdjust = 0; - if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust)) { + if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) { /* We need a block soon...*/ aggressive = 1; } else { @@ -2807,7 +3468,7 @@ * Update: For backward scanning we don't need to re-read tags so this is quite cheap. */ - if (existingChunk != 0) { + if (existingChunk > 0) { /* NB Right now existing chunk will not be real chunkId if the device >= 32MB * thus we have to do a FindChunkInFile to get the real chunk id. * @@ -2908,10 +3569,17 @@ if (chunkId <= 0) return; + dev->nDeletions++; block = chunkId / dev->nChunksPerBlock; page = chunkId % dev->nChunksPerBlock; + + if(!yaffs_CheckChunkBit(dev,block,page)) + T(YAFFS_TRACE_VERIFY, + (TSTR("Deleting invalid chunk %d"TENDSTR), + chunkId)); + bi = yaffs_GetBlockInfo(dev, block); T(YAFFS_TRACE_DELETION, @@ -3022,24 +3690,34 @@ int newChunkId; yaffs_ExtendedTags newTags; + yaffs_ExtendedTags oldTags; __u8 *buffer = NULL; YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1]; - yaffs_ObjectHeader *oh = NULL; + yaffs_ObjectHeader *oh = NULL; + + yaffs_strcpy(oldName,_Y("silly old name")); - if (!in->fake || force) { + + if (!in->fake || + in == dev->rootDir || /* The rootDir should also be saved */ + force) { yaffs_CheckGarbageCollection(dev); + yaffs_CheckObjectDetailsLoaded(in); buffer = yaffs_GetTempBuffer(in->myDev, __LINE__); oh = (yaffs_ObjectHeader *) buffer; - prevChunkId = in->chunkId; + prevChunkId = in->hdrChunk; - if (prevChunkId >= 0) { + if (prevChunkId > 0) { result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId, - buffer, NULL); + buffer, &oldTags); + + yaffs_VerifyObjectHeader(in,oh,&oldTags,0); + memcpy(oldName, oh->name, sizeof(oh->name)); } @@ -3047,7 +3725,7 @@ oh->type = in->variantType; oh->yst_mode = in->yst_mode; - oh->shadowsObject = shadows; + oh->shadowsObject = oh->inbandShadowsObject = shadows; #ifdef CONFIG_YAFFS_WINCE oh->win_atime[0] = in->win_atime[0]; @@ -3073,7 +3751,7 @@ if (name && *name) { memset(oh->name, 0, sizeof(oh->name)); yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH); - } else if (prevChunkId) { + } else if (prevChunkId>=0) { memcpy(oh->name, oldName, sizeof(oh->name)); } else { memset(oh->name, 0, sizeof(oh->name)); @@ -3127,6 +3805,8 @@ newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0; newTags.extraObjectType = in->variantType; + yaffs_VerifyObjectHeader(in,oh,&newTags,1); + /* Create new chunk in NAND */ newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, @@ -3134,7 +3814,7 @@ if (newChunkId >= 0) { - in->chunkId = newChunkId; + in->hdrChunk = newChunkId; if (prevChunkId >= 0) { yaffs_DeleteChunk(dev, prevChunkId, 1, @@ -3449,6 +4129,9 @@ 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; @@ -3571,8 +4254,8 @@ cp->objectId = obj->objectId; cp->parentId = (obj->parent) ? obj->parent->objectId : 0; - cp->chunkId = obj->chunkId; - cp->variantType = obj->variantType; + cp->hdrChunk = obj->hdrChunk; + cp->variantType = obj->variantType; cp->deleted = obj->deleted; cp->softDeleted = obj->softDeleted; cp->unlinked = obj->unlinked; @@ -3588,10 +4271,18 @@ cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId; } -static void yaffs_CheckpointObjectToObject( yaffs_Object *obj,yaffs_CheckpointObject *cp) +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 " + "chunk %d does not match existing object type %d" + TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk, + obj->variantType)); + return 0; + } obj->objectId = cp->objectId; @@ -3603,11 +4294,17 @@ else parent = NULL; - if(parent) + if(parent) { + if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { + T(YAFFS_TRACE_ALWAYS,(TSTR("Checkpoint read object %d parent %d type %d 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->chunkId = cp->chunkId; - obj->variantType = cp->variantType; + } + + obj->hdrChunk = cp->hdrChunk; + obj->variantType = cp->variantType; obj->deleted = cp->deleted; obj->softDeleted = cp->softDeleted; obj->unlinked = cp->unlinked; @@ -3621,9 +4318,10 @@ obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId; else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId; - - if(obj->objectId >= YAFFS_NOBJECT_BUCKETS) + + if(obj->hdrChunk > 0) obj->lazyLoaded = 1; + return 1; } @@ -3634,7 +4332,11 @@ int i; yaffs_Device *dev = in->myDev; int ok = 1; - int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + + if(tnodeSize < sizeof(yaffs_Tnode)) + tnodeSize = sizeof(yaffs_Tnode); + if (tn) { if (level > 0) { @@ -3652,7 +4354,7 @@ /* printf("write tnode at %d\n",baseOffset); */ ok = (yaffs_CheckpointWrite(dev,&baseOffset,sizeof(baseOffset)) == sizeof(baseOffset)); if(ok) - ok = (yaffs_CheckpointWrite(dev,tn,nTnodeBytes) == nTnodeBytes); + ok = (yaffs_CheckpointWrite(dev,tn,tnodeSize) == tnodeSize); } } @@ -3685,17 +4387,23 @@ 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 */ + /* printf("read tnode at %d\n",baseChunk); */ tn = yaffs_GetTnodeRaw(dev); if(tn) - ok = (yaffs_CheckpointRead(dev,tn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8) == - (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); + ok = (yaffs_CheckpointRead(dev,tn,tnodeSize) == tnodeSize); else ok = 0; @@ -3704,6 +4412,7 @@ fileStructPtr, baseChunk, tn) ? 1 : 0; + } if(ok) @@ -3711,6 +4420,10 @@ } + T(YAFFS_TRACE_CHECKPOINT,( + TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR), + nread,baseChunk,ok)); + return ok ? 1 : 0; } @@ -3718,28 +4431,28 @@ static int yaffs_WriteCheckpointObjects(yaffs_Device *dev) { yaffs_Object *obj; - yaffs_CheckpointObject cp; - int i; - int ok = 1; - struct list_head *lh; + yaffs_CheckpointObject cp; + int i; + int ok = 1; + struct ylist_head *lh; - - /* Iterate through the objects in each hash entry, + + /* Iterate through the objects in each hash entry, * dumping them to the checkpointing stream. - */ - - for(i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++){ - list_for_each(lh, &dev->objectBucket[i].list) { - if (lh) { - obj = list_entry(lh, yaffs_Object, hashLink); - if (!obj->deferedFree) { - yaffs_ObjectToCheckpointObject(&cp,obj); - cp.structType = sizeof(cp); + */ + + for(i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++){ + ylist_for_each(lh, &dev->objectBucket[i].list) { + if (lh) { + obj = ylist_entry(lh, yaffs_Object, hashLink); + if (!obj->deferedFree) { + yaffs_ObjectToCheckpointObject(&cp,obj); + cp.structType = sizeof(cp); T(YAFFS_TRACE_CHECKPOINT,( TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR), - cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj)); - + cp.objectId,cp.parentId,cp.variantType,cp.hdrChunk,(unsigned) obj)); + ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){ @@ -3771,28 +4484,34 @@ while(ok && !done) { ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); if(cp.structType != sizeof(cp)) { - /* printf("structure parsing failed\n"); */ + 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); - T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d obj addr %x" TENDSTR), - cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj)); if(obj) { - yaffs_CheckpointObjectToObject(obj,&cp); + 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 list_head *) - hardList; - hardList = obj; - } + ok = yaffs_ReadCheckpointTnodes(obj); + } else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { + obj->hardLinks.next = + (struct ylist_head *) + hardList; + hardList = obj; + } } + else + ok = 0; } } @@ -3802,22 +4521,76 @@ return ok ? 1 : 0; } -static int yaffs_WriteCheckpointData(yaffs_Device *dev) +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; - ok = yaffs_CheckpointOpen(dev,1); + 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) + } + if(ok){ + T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint device" TENDSTR))); ok = yaffs_WriteCheckpointDevice(dev); - if(ok) + } + if(ok){ + T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint objects" TENDSTR))); ok = yaffs_WriteCheckpointObjects(dev); - if(ok) + } + 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; @@ -3831,20 +4604,37 @@ static int yaffs_ReadCheckpointData(yaffs_Device *dev) { - int ok; + int ok = 1; - ok = yaffs_CheckpointOpen(dev,0); /* open for read */ + 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) + } + if(ok){ + T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint device" TENDSTR))); ok = yaffs_ReadCheckpointDevice(dev); - if(ok) + } + if(ok){ + T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint objects" TENDSTR))); ok = yaffs_ReadCheckpointObjects(dev); - if(ok) + } + 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; @@ -3872,13 +4662,19 @@ int yaffs_CheckpointSave(yaffs_Device *dev) { - yaffs_ReportOddballBlocks(dev); + T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); - if(!dev->isCheckpointed) + yaffs_VerifyObjects(dev); + yaffs_VerifyBlocks(dev); + yaffs_VerifyFreeChunks(dev); + + if(!dev->isCheckpointed) { + yaffs_InvalidateCheckpoint(dev); yaffs_WriteCheckpointData(dev); + } - T(YAFFS_TRACE_CHECKPOINT,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); + T(YAFFS_TRACE_ALWAYS,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); return dev->isCheckpointed; } @@ -3887,13 +4683,17 @@ { 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)); - yaffs_ReportOddballBlocks(dev); - return retval; } @@ -3912,7 +4712,7 @@ { int chunk; - int start; + __u32 start; int nToCopy; int n = nBytes; int nDone = 0; @@ -3940,10 +4740,10 @@ cache = yaffs_FindChunkCache(in, chunk); /* If the chunk is already in the cache or it is less than a whole chunk - * then use the cache (if there is caching) + * or we're using inband tags then use the cache (if there is caching) * else bypass the cache. */ - if (cache || nToCopy != dev->nDataBytesPerChunk) { + if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) { if (dev->nShortOpCaches > 0) { /* If we can't find the data in the cache, then load it up. */ @@ -4032,14 +4832,14 @@ { int chunk; - int start; + __u32 start; int nToCopy; - int n = nBytes; - int nDone = 0; - int nToWriteBack; - int startOfWrite = offset; - int chunkWritten = 0; - int nBytesRead; + int n = nBytes; + int nDone = 0; + int nToWriteBack; + int startOfWrite = offset; + int chunkWritten = 0; + int nBytesRead; yaffs_Device *dev; @@ -4080,8 +4880,10 @@ nToWriteBack = dev->nDataBytesPerChunk; } - if (nToCopy != dev->nDataBytesPerChunk) { - /* An incomplete start or end chunk (or maybe both start and end chunk) */ + if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) { + /* An incomplete start or end chunk (or maybe both start and end chunk), + * or we're using inband tags, so we want to use the cache buffers. + */ if (dev->nShortOpCaches > 0) { yaffs_ChunkCache *cache; /* If we can't find the data in the cache, then load the cache */ @@ -4169,6 +4971,7 @@ } } else { + /* A full chunk. Write directly from the supplied buffer. */ #ifdef CONFIG_YAFFS_WINCE /* Under WinCE can't do direct transfer. Need to use a local buffer. @@ -4188,7 +4991,7 @@ 0); yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); #else - /* A full chunk. Write directly from the supplied buffer. */ + chunkWritten = yaffs_WriteChunkDataToObject(in, chunk, buffer, dev->nDataBytesPerChunk, @@ -4266,27 +5069,27 @@ { int oldFileSize = in->variant.fileVariant.fileSize; - int newSizeOfPartialChunk; + __u32 newSizeOfPartialChunk; int newFullChunks; yaffs_Device *dev = in->myDev; - + yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk); yaffs_FlushFilesChunkCache(in); yaffs_InvalidateWholeChunkCache(in); - yaffs_CheckGarbageCollection(dev); + yaffs_CheckGarbageCollection(dev); - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { - return yaffs_GetFileSize(in); - } + if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { + return YAFFS_FAIL; + } - if (newSize == oldFileSize) { - return oldFileSize; - } + if (newSize == oldFileSize) { + return YAFFS_OK; + } - if (newSize < oldFileSize) { + if (newSize < oldFileSize) { yaffs_PruneResizedChunks(in, newSize); @@ -4311,7 +5114,13 @@ in->variant.fileVariant.fileSize = newSize; yaffs_PruneFileStructure(dev, &in->variant.fileVariant); + } else { + /* newsSize > oldFileSize */ + in->variant.fileVariant.fileSize = newSize; } + + + /* Write a new object header. * show we've shrunk the file, if need be * Do this only if the file is not in the deleted directories. @@ -4322,7 +5131,7 @@ (newSize < oldFileSize) ? 1 : 0, 0); } - return newSize; + return YAFFS_OK; } loff_t yaffs_GetFileSize(yaffs_Object * obj) @@ -4375,13 +5184,13 @@ 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, NULL, 0, 0); + yaffs_ChangeObjectName(in, in->myDev->deletedDir,_Y("deleted"), 0, 0); } yaffs_RemoveObjectFromDirectory(in); - yaffs_DeleteChunk(in->myDev, in->chunkId, 1, __LINE__); - in->chunkId = -1; + yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__); + in->hdrChunk = 0; yaffs_FreeObject(in); return YAFFS_OK; @@ -4413,7 +5222,7 @@ if (immediateDeletion) { retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir, - NULL, 0, 0); + _Y("deleted"), 0, 0); T(YAFFS_TRACE_TRACING, (TSTR("yaffs: immediate deletion of file %d" TENDSTR), in->objectId)); @@ -4426,7 +5235,7 @@ } else { retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir, - NULL, 0, 0); + _Y("unlinked"), 0, 0); } } @@ -4460,10 +5269,10 @@ static int yaffs_DeleteDirectory(yaffs_Object * in) { - /* First check that the directory is empty. */ - if (list_empty(&in->variant.directoryVariant.children)) { - return yaffs_DoGenericObjectDeletion(in); - } + /* First check that the directory is empty. */ + if (ylist_empty(&in->variant.directoryVariant.children)) { + return yaffs_DoGenericObjectDeletion(in); + } return YAFFS_FAIL; @@ -4478,11 +5287,11 @@ static int yaffs_DeleteHardLink(yaffs_Object * in) { - /* remove this hardlink from the list assocaited with the equivalent - * object - */ - list_del(&in->hardLinks); - return yaffs_DoGenericObjectDeletion(in); + /* remove this hardlink from the list assocaited with the equivalent + * object + */ + ylist_del(&in->hardLinks); + return yaffs_DoGenericObjectDeletion(in); } static void yaffs_DestroyObject(yaffs_Object * obj) @@ -4511,12 +5320,12 @@ static int yaffs_UnlinkWorker(yaffs_Object * obj) { - if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { - return yaffs_DeleteHardLink(obj); - } else if (!list_empty(&obj->hardLinks)) { - /* Curve ball: We're unlinking an object that has a hardlink. - * - * This problem arises because we are not strictly following + if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { + return yaffs_DeleteHardLink(obj); + } else if (!ylist_empty(&obj->hardLinks)) { + /* Curve ball: We're unlinking an object that has a hardlink. + * + * This problem arises because we are not strictly following * The Linux link/inode model. * * We can't really delete the object. @@ -4529,15 +5338,15 @@ */ yaffs_Object *hl; - int retVal; - YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; + int retVal; + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; - hl = list_entry(obj->hardLinks.next, yaffs_Object, hardLinks); + hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks); - list_del_init(&hl->hardLinks); - list_del_init(&hl->siblings); + ylist_del_init(&hl->hardLinks); + ylist_del_init(&hl->siblings); - yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1); + yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1); retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0); @@ -4614,6 +5423,8 @@ obj = yaffs_FindOrCreateObjectByNumber(dev, objId, YAFFS_OBJECT_TYPE_FILE); + if (!obj) + return; yaffs_AddObjectToDirectory(dev->unlinkedDir, obj); obj->variant.fileVariant.shrinkSize = 0; obj->valid = 1; /* So that we don't read any other info for this file */ @@ -4639,18 +5450,18 @@ hl->variant.hardLinkVariant. equivalentObjectId); - if (in) { - /* Add the hardlink pointers */ - hl->variant.hardLinkVariant.equivalentObject = in; - list_add(&hl->hardLinks, &in->hardLinks); - } else { - /* Todo Need to report/handle this better. - * Got a problem... hardlink to a non-existant object - */ - hl->variant.hardLinkVariant.equivalentObject = NULL; - INIT_LIST_HEAD(&hl->hardLinks); + if (in) { + /* Add the hardlink pointers */ + hl->variant.hardLinkVariant.equivalentObject = in; + ylist_add(&hl->hardLinks, &in->hardLinks); + } else { + /* Todo Need to report/handle this better. + * Got a problem... hardlink to a non-existant object + */ + hl->variant.hardLinkVariant.equivalentObject = NULL; + YINIT_LIST_HEAD(&hl->hardLinks); - } + } } @@ -4672,6 +5483,42 @@ } + +struct yaffs_ShadowFixerStruct { + int objectId; + int shadowedId; + struct yaffs_ShadowFixerStruct *next; +}; + + +static void yaffs_StripDeletedObjects(yaffs_Device *dev) +{ + /* + * Sort out state of unlinked and deleted objects after scanning. + */ + struct ylist_head *i; + struct ylist_head *n; + yaffs_Object *l; + + /* Soft delete all the unlinked files */ + ylist_for_each_safe(i, n, + &dev->unlinkedDir->variant.directoryVariant.children) { + if (i) { + l = ylist_entry(i, yaffs_Object, siblings); + yaffs_DestroyObject(l); + } + } + + ylist_for_each_safe(i, n, + &dev->deletedDir->variant.directoryVariant.children) { + if (i) { + l = ylist_entry(i, yaffs_Object, siblings); + yaffs_DestroyObject(l); + } + } + +} + static int yaffs_Scan(yaffs_Device * dev) { yaffs_ExtendedTags tags; @@ -4679,7 +5526,6 @@ int blockIterator; int startIterator; int endIterator; - int nBlocksToScan = 0; int result; int chunk; @@ -4687,25 +5533,20 @@ int deleted; yaffs_BlockState state; yaffs_Object *hardList = NULL; - yaffs_Object *hl; yaffs_BlockInfo *bi; - int sequenceNumber; + __u32 sequenceNumber; yaffs_ObjectHeader *oh; yaffs_Object *in; yaffs_Object *parent; - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; - __u8 *chunkData; + int alloc_failed = 0; - yaffs_BlockIndex *blockIndex = NULL; + struct yaffs_ShadowFixerStruct *shadowFixerList = NULL; + + + __u8 *chunkData; - if (dev->isYaffs2) { - T(YAFFS_TRACE_SCAN, - (TSTR("yaffs_Scan is not for YAFFS2!" TENDSTR))); - return YAFFS_FAIL; - } - //TODO Throw all the yaffs2 stuuf out of yaffs_Scan since it is only for yaffs1 format. T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR), @@ -4715,10 +5556,6 @@ dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; - if (dev->isYaffs2) { - blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); - } - /* Scan all the blocks to determine their state */ for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { bi = yaffs_GetBlockInfo(dev, blk); @@ -4731,6 +5568,9 @@ 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)); @@ -4743,70 +5583,21 @@ (TSTR("Block empty " TENDSTR))); dev->nErasedBlocks++; dev->nFreeChunks += dev->nChunksPerBlock; - } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { - - /* Determine the highest sequence number */ - if (dev->isYaffs2 && - sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && - sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) { - - blockIndex[nBlocksToScan].seq = sequenceNumber; - blockIndex[nBlocksToScan].block = blk; - - nBlocksToScan++; - - if (sequenceNumber >= dev->sequenceNumber) { - dev->sequenceNumber = sequenceNumber; - } - } else if (dev->isYaffs2) { - /* TODO: Nasty sequence number! */ - T(YAFFS_TRACE_SCAN, - (TSTR - ("Block scanning block %d has bad sequence number %d" - TENDSTR), blk, sequenceNumber)); - - } } } - /* Sort the blocks - * Dungy old bubble sort for now... - */ - if (dev->isYaffs2) { - yaffs_BlockIndex temp; - int i; - int j; - - for (i = 0; i < nBlocksToScan; i++) - for (j = i + 1; j < nBlocksToScan; j++) - if (blockIndex[i].seq > blockIndex[j].seq) { - temp = blockIndex[j]; - blockIndex[j] = blockIndex[i]; - blockIndex[i] = temp; - } - } - - /* Now scan the blocks looking at the data. */ - if (dev->isYaffs2) { - startIterator = 0; - endIterator = nBlocksToScan - 1; - T(YAFFS_TRACE_SCAN_DEBUG, - (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); - } else { - startIterator = dev->internalStartBlock; - endIterator = dev->internalEndBlock; - } + startIterator = dev->internalStartBlock; + endIterator = dev->internalEndBlock; /* For each block.... */ - for (blockIterator = startIterator; blockIterator <= endIterator; + for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; blockIterator++) { - if (dev->isYaffs2) { - /* get the block to scan in the correct order */ - blk = blockIndex[blockIterator].block; - } else { - blk = blockIterator; - } + YYIELD(); + + YYIELD(); + + blk = blockIterator; bi = yaffs_GetBlockInfo(dev, blk); state = bi->blockState; @@ -4814,7 +5605,7 @@ deleted = 0; /* For each chunk in each block that needs scanning....*/ - for (c = 0; c < dev->nChunksPerBlock && + 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; @@ -4824,7 +5615,7 @@ /* Let's have a good look at this chunk... */ - if (!dev->isYaffs2 && tags.chunkDeleted) { + if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) { /* YAFFS1 only... * A deleted chunk */ @@ -4853,18 +5644,6 @@ dev->allocationBlockFinder = blk; /* Set it to here to encourage the allocator to go forth from here. */ - /* Yaffs2 sanity check: - * This should be the one with the highest sequence number - */ - if (dev->isYaffs2 - && (dev->sequenceNumber != - bi->sequenceNumber)) { - T(YAFFS_TRACE_ALWAYS, - (TSTR - ("yaffs: Allocation block %d was not highest sequence id:" - " block seq = %d, dev seq = %d" - TENDSTR), blk,bi->sequenceNumber,dev->sequenceNumber)); - } } dev->nFreeChunks += (dev->nChunksPerBlock - c); @@ -4882,12 +5661,20 @@ /* PutChunkIntoFile checks for a clash (two data chunks with * the same chunkId). */ - yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, - 1); + + 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->variantType == YAFFS_OBJECT_TYPE_FILE + if (in && + in->variantType == YAFFS_OBJECT_TYPE_FILE && in->variant.fileVariant.scannedFileSize < endpos) { in->variant.fileVariant. @@ -4932,25 +5719,32 @@ objectId, oh->type); - if (oh->shadowsObject > 0) { - yaffs_HandleShadowedObject(dev, - oh-> - shadowsObject, - 0); + 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->valid) { + 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 (dev->isYaffs2 || - ((existingSerial + 1) & 3) == - newSerial) { + if (((existingSerial + 1) & 3) == newSerial) { /* Use new one - destroy the exisiting one */ yaffs_DeleteChunk(dev, - in->chunkId, + in->hdrChunk, 1, __LINE__); in->valid = 0; } else { @@ -4960,7 +5754,7 @@ } } - if (!in->valid && + 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 */ @@ -4983,9 +5777,9 @@ in->yst_ctime = oh->yst_ctime; in->yst_rdev = oh->yst_rdev; #endif - in->chunkId = chunk; + in->hdrChunk = chunk; - } else if (!in->valid) { + } else if (in && !in->valid) { /* we need to load this info */ in->valid = 1; @@ -5007,7 +5801,7 @@ in->yst_ctime = oh->yst_ctime; in->yst_rdev = oh->yst_rdev; #endif - in->chunkId = chunk; + in->hdrChunk = chunk; yaffs_SetObjectName(in, oh->name); in->dirty = 0; @@ -5020,15 +5814,17 @@ yaffs_FindOrCreateObjectByNumber (dev, oh->parentObjectId, YAFFS_OBJECT_TYPE_DIRECTORY); - if (parent->variantType == + if(!parent) + alloc_failed = 1; + if (parent && parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN) { - /* Set up as a directory */ - parent->variantType = - YAFFS_OBJECT_TYPE_DIRECTORY; - INIT_LIST_HEAD(&parent->variant. - directoryVariant. - children); - } else if (parent->variantType != + /* Set up as a directory */ + parent->variantType = + YAFFS_OBJECT_TYPE_DIRECTORY; + YINIT_LIST_HEAD(&parent->variant. + directoryVariant. + children); + } else if (!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { /* Hoosterman, another problem.... @@ -5037,8 +5833,7 @@ T(YAFFS_TRACE_ERROR, (TSTR - ("yaffs tragedy: attempting to use non-directory as" - " a directory in scan. Put in lost+found." + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR))); parent = dev->lostNFoundDir; } @@ -5062,15 +5857,6 @@ /* Todo got a problem */ break; case YAFFS_OBJECT_TYPE_FILE: - if (dev->isYaffs2 - && oh->isShrink) { - /* Prune back the shrunken chunks */ - yaffs_PruneResizedChunks - (in, oh->fileSize); - /* Mark the block as having a shrinkHeader */ - bi->hasShrinkHeader = 1; - } - if (dev->useHeaderFileSize) in->variant.fileVariant. @@ -5080,13 +5866,13 @@ break; case YAFFS_OBJECT_TYPE_HARDLINK: in->variant.hardLinkVariant. - equivalentObjectId = - oh->equivalentObjectId; - in->hardLinks.next = - (struct list_head *) - hardList; - hardList = in; - break; + equivalentObjectId = + oh->equivalentObjectId; + in->hardLinks.next = + (struct ylist_head *) + hardList; + hardList = in; + break; case YAFFS_OBJECT_TYPE_DIRECTORY: /* Do nothing */ break; @@ -5094,9 +5880,10 @@ /* Do nothing */ break; case YAFFS_OBJECT_TYPE_SYMLINK: - in->variant.symLinkVariant. - alias = + in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias); + if(!in->variant.symLinkVariant.alias) + alloc_failed = 1; break; } @@ -5124,10 +5911,6 @@ } - if (blockIndex) { - YFREE(blockIndex); - } - /* Ok, we've done all the scanning. * Fix up the hard link chains. @@ -5137,29 +5920,39 @@ yaffs_HardlinkFixup(dev,hardList); - /* Handle the unlinked files. Since they were left in an unlinked state we should - * just delete them. - */ + /* Fix up any shadowed objects */ { - struct list_head *i; - struct list_head *n; + struct yaffs_ShadowFixerStruct *fixer; + yaffs_Object *obj; - yaffs_Object *l; - /* Soft delete all the unlinked files */ - list_for_each_safe(i, n, - &dev->unlinkedDir->variant.directoryVariant. - children) { - if (i) { - l = list_entry(i, yaffs_Object, siblings); - yaffs_DestroyObject(l); + while(shadowFixerList){ + fixer = shadowFixerList; + shadowFixerList = fixer->next; + /* Complete the rename transaction by deleting the shadowed object + * then setting the object header to unshadowed. + */ + obj = yaffs_FindObjectByNumber(dev,fixer->shadowedId); + if(obj) + yaffs_DestroyObject(obj); + + obj = yaffs_FindObjectByNumber(dev,fixer->objectId); + if(obj){ + yaffs_UpdateObjectHeader(obj,NULL,1,0,0); } + + YFREE(fixer); } } yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); + if(alloc_failed){ + return YAFFS_FAIL; + } + T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR))); + return YAFFS_OK; } @@ -5170,19 +5963,23 @@ yaffs_Device *dev = in->myDev; yaffs_ExtendedTags tags; int result; - + int alloc_failed = 0; + + if(!in) + return; + #if 0 T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR), in->objectId, in->lazyLoaded ? "not yet" : "already")); #endif - - if(in->lazyLoaded){ + + if(in->lazyLoaded && in->hdrChunk > 0){ in->lazyLoaded = 0; chunkData = yaffs_GetTempBuffer(dev, __LINE__); - result = yaffs_ReadChunkWithTagsFromNAND(dev,in->chunkId,chunkData,&tags); - oh = (yaffs_ObjectHeader *) chunkData; + result = yaffs_ReadChunkWithTagsFromNAND(dev,in->hdrChunk,chunkData,&tags); + oh = (yaffs_ObjectHeader *) chunkData; in->yst_mode = oh->yst_mode; #ifdef CONFIG_YAFFS_WINCE @@ -5203,9 +6000,12 @@ #endif yaffs_SetObjectName(in, oh->name); - if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) + if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK){ in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias); + if(!in->variant.symLinkVariant.alias) + alloc_failed = 1; /* Not returned to caller */ + } yaffs_ReleaseTempBuffer(dev,chunkData, __LINE__); } @@ -5227,7 +6027,7 @@ yaffs_BlockState state; yaffs_Object *hardList = NULL; yaffs_BlockInfo *bi; - int sequenceNumber; + __u32 sequenceNumber; yaffs_ObjectHeader *oh; yaffs_Object *in; yaffs_Object *parent; @@ -5239,6 +6039,7 @@ int isShrink; int foundChunksInBlock; int equivalentObjectId; + int alloc_failed = 0; yaffs_BlockIndex *blockIndex = NULL; @@ -5271,6 +6072,8 @@ return YAFFS_FAIL; } + dev->blocksInCheckpoint = 0; + chunkData = yaffs_GetTempBuffer(dev, __LINE__); /* Scan all the blocks to determine their state */ @@ -5287,6 +6090,8 @@ 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, @@ -5294,7 +6099,7 @@ if(state == YAFFS_BLOCK_STATE_CHECKPOINT){ - /* todo .. fix free space ? */ + dev->blocksInCheckpoint++; } else if (state == YAFFS_BLOCK_STATE_DEAD) { T(YAFFS_TRACE_BAD_BLOCKS, @@ -5307,8 +6112,7 @@ } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { /* Determine the highest sequence number */ - if (dev->isYaffs2 && - sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && + if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) { blockIndex[nBlocksToScan].seq = sequenceNumber; @@ -5319,7 +6123,7 @@ if (sequenceNumber >= dev->sequenceNumber) { dev->sequenceNumber = sequenceNumber; } - } else if (dev->isYaffs2) { + } else { /* TODO: Nasty sequence number! */ T(YAFFS_TRACE_SCAN, (TSTR @@ -5341,7 +6145,7 @@ #ifndef CONFIG_YAFFS_USE_OWN_SORT { /* Use qsort now. */ - qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); + yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); } #else { @@ -5372,7 +6176,7 @@ (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); /* For each block.... backwards */ - for (blockIterator = endIterator; blockIterator >= startIterator; + for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator; blockIterator--) { /* Cooperative multitasking! This loop can run for so long that watchdog timers expire. */ @@ -5382,18 +6186,22 @@ 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; c >= 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, @@ -5441,12 +6249,12 @@ * had a write failure, so set up for retirement. */ - bi->needsRetiring = 1; + /* bi->needsRetiring = 1; ??? TODO */ bi->gcPrioritise = 1; - T(YAFFS_TRACE_ALWAYS, - (TSTR("Partially written block %d being set for retirement" TENDSTR), - blk)); +// T(YAFFS_TRACE_ALWAYS, +// (TSTR("Partially written block %d detected" TENDSTR), +// blk)); } } @@ -5455,7 +6263,13 @@ dev->nFreeChunks++; - } else if (tags.chunkId > 0) { + } 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 = @@ -5471,12 +6285,20 @@ tags. objectId, YAFFS_OBJECT_TYPE_FILE); - if (in->variantType == 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 */ - yaffs_PutChunkIntoFile(in, tags.chunkId, - chunk, -1); + 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. @@ -5497,7 +6319,7 @@ scannedFileSize; } - } else { + } else if(in) { /* This chunk has been invalidated by a resize, so delete */ yaffs_DeleteChunk(dev, chunk, 1, __LINE__); @@ -5518,6 +6340,8 @@ in = yaffs_FindOrCreateObjectByNumber (dev, tags.objectId, tags.extraObjectType); + if (!in) + alloc_failed = 1; } if (!in || @@ -5542,8 +6366,17 @@ oh = (yaffs_ObjectHeader *) chunkData; - if (!in) + 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; + } } @@ -5551,10 +6384,9 @@ /* TODO Hoosterman we have a problem! */ T(YAFFS_TRACE_ERROR, (TSTR - ("yaffs tragedy: Could not make object for object %d " - "at chunk %d during scan" + ("yaffs tragedy: Could not make object for object %d at chunk %d during scan" TENDSTR), tags.objectId, chunk)); - + continue; } if (in->valid) { @@ -5609,6 +6441,16 @@ } + if (!in->valid && in->variantType != + (oh ? oh->type : tags.extraObjectType)) + T(YAFFS_TRACE_ERROR, (TSTR + ("yaffs tragedy: Bad object type, " + "%d != %d, for object %d at chunk " + "%d during scan" TENDSTR), oh ? + oh->type : tags.extraObjectType, + in->variantType, tags.objectId, + chunk)); + if (!in->valid && (tags.objectId == YAFFS_OBJECTID_ROOT || tags.objectId == @@ -5640,15 +6482,15 @@ in->variantType = tags.extraObjectType; in->lazyLoaded = 1; } - - in->chunkId = chunk; + + in->hdrChunk = chunk; } else if (!in->valid) { /* we need to load this info */ in->valid = 1; - in->chunkId = chunk; - + in->hdrChunk = chunk; + if(oh) { in->variantType = oh->type; @@ -5701,19 +6543,22 @@ } in->dirty = 0; + if (!parent) + alloc_failed = 1; + /* directory stuff... * hook up to parent */ - if (parent->variantType == + if (parent && parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN) { - /* Set up as a directory */ - parent->variantType = - YAFFS_OBJECT_TYPE_DIRECTORY; - INIT_LIST_HEAD(&parent->variant. - directoryVariant. - children); - } else if (parent->variantType != + /* Set up as a directory */ + parent->variantType = + YAFFS_OBJECT_TYPE_DIRECTORY; + YINIT_LIST_HEAD(&parent->variant. + directoryVariant. + children); + } else if (!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { /* Hoosterman, another problem.... @@ -5722,8 +6567,7 @@ T(YAFFS_TRACE_ERROR, (TSTR - ("yaffs tragedy: attempting to use non-directory as" - " a directory in scan. Put in lost+found." + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR))); parent = dev->lostNFoundDir; } @@ -5771,13 +6615,13 @@ break; case YAFFS_OBJECT_TYPE_HARDLINK: if(!itsUnlinked) { - in->variant.hardLinkVariant.equivalentObjectId = - equivalentObjectId; - in->hardLinks.next = - (struct list_head *) hardList; - hardList = in; - } - break; + in->variant.hardLinkVariant.equivalentObjectId = + equivalentObjectId; + in->hardLinks.next = + (struct ylist_head *) hardList; + hardList = in; + } + break; case YAFFS_OBJECT_TYPE_DIRECTORY: /* Do nothing */ break; @@ -5785,16 +6629,21 @@ /* Do nothing */ break; case YAFFS_OBJECT_TYPE_SYMLINK: - if(oh) + 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. */ @@ -5824,40 +6673,13 @@ */ yaffs_HardlinkFixup(dev,hardList); - - /* - * Sort out state of unlinked and deleted objects. - */ - { - struct list_head *i; - struct list_head *n; - - yaffs_Object *l; - /* Soft delete all the unlinked files */ - list_for_each_safe(i, n, - &dev->unlinkedDir->variant.directoryVariant. - children) { - if (i) { - l = list_entry(i, yaffs_Object, siblings); - yaffs_DestroyObject(l); - } - } - - /* Soft delete all the deletedDir files */ - list_for_each_safe(i, n, - &dev->deletedDir->variant.directoryVariant. - children) { - if (i) { - l = list_entry(i, yaffs_Object, siblings); - yaffs_DestroyObject(l); + yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); - } - } + if(alloc_failed){ + return YAFFS_FAIL; } - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR))); return YAFFS_OK; @@ -5869,11 +6691,11 @@ { yaffs_Device *dev = obj->myDev; - if(dev && dev->removeObjectCallback) - dev->removeObjectCallback(obj); - - list_del_init(&obj->siblings); - obj->parent = NULL; + if(dev && dev->removeObjectCallback) + dev->removeObjectCallback(obj); + + ylist_del_init(&obj->siblings); + obj->parent = NULL; } @@ -5896,19 +6718,19 @@ YBUG(); } - if (obj->siblings.prev == NULL) { - /* Not initialised */ - INIT_LIST_HEAD(&obj->siblings); - - } else if (!list_empty(&obj->siblings)) { - /* If it is holed up somewhere else, un hook it */ - yaffs_RemoveObjectFromDirectory(obj); - } - /* Now add it */ - list_add(&obj->siblings, &directory->variant.directoryVariant.children); - obj->parent = directory; + if (obj->siblings.prev == NULL) { + /* Not initialised */ + YINIT_LIST_HEAD(&obj->siblings); + + } else if (!ylist_empty(&obj->siblings)) { + /* If it is holed up somewhere else, un hook it */ + yaffs_RemoveObjectFromDirectory(obj); + } + /* Now add it */ + ylist_add(&obj->siblings, &directory->variant.directoryVariant.children); + obj->parent = directory; - if (directory == obj->myDev->unlinkedDir + if (directory == obj->myDev->unlinkedDir || directory == obj->myDev->deletedDir) { obj->unlinked = 1; obj->myDev->nUnlinkedFiles++; @@ -5919,12 +6741,12 @@ yaffs_Object *yaffs_FindObjectByName(yaffs_Object * directory, const YCHAR * name) { - int sum; + int sum; - struct list_head *i; - YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; + struct ylist_head *i; + YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; - yaffs_Object *l; + yaffs_Object *l; if (!name) { return NULL; @@ -5944,27 +6766,26 @@ YBUG(); } - sum = yaffs_CalcNameSum(name); + sum = yaffs_CalcNameSum(name); - list_for_each(i, &directory->variant.directoryVariant.children) { - if (i) { - l = list_entry(i, yaffs_Object, siblings); - - yaffs_CheckObjectDetailsLoaded(l); + ylist_for_each(i, &directory->variant.directoryVariant.children) { + if (i) { + l = ylist_entry(i, yaffs_Object, siblings); + + yaffs_CheckObjectDetailsLoaded(l); /* Special case for lost-n-found */ if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) { if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) { return l; } - } else if (yaffs_SumCompare(l->sum, sum) || l->chunkId <= 0) - { - /* LostnFound cunk called Objxxx + } else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0){ + /* LostnFound chunk called Objxxx * Do a real check */ yaffs_GetObjectName(l, buffer, YAFFS_MAX_NAME_LENGTH); - if (yaffs_strcmp(name, buffer) == 0) { + if (yaffs_strncmp(name, buffer,YAFFS_MAX_NAME_LENGTH) == 0) { return l; } @@ -5978,12 +6799,12 @@ #if 0 int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir, - int (*fn) (yaffs_Object *)) + int (*fn) (yaffs_Object *)) { - struct list_head *i; - yaffs_Object *l; + struct ylist_head *i; + yaffs_Object *l; - if (!theDir) { + if (!theDir) { T(YAFFS_TRACE_ALWAYS, (TSTR ("tragedy: yaffs_FindObjectByName: null pointer directory" @@ -5994,15 +6815,15 @@ T(YAFFS_TRACE_ALWAYS, (TSTR ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR))); - YBUG(); - } + YBUG(); + } - list_for_each(i, &theDir->variant.directoryVariant.children) { - if (i) { - l = list_entry(i, yaffs_Object, siblings); - if (l && !fn(l)) { - return YAFFS_FAIL; - } + ylist_for_each(i, &theDir->variant.directoryVariant.children) { + if (i) { + l = ylist_entry(i, yaffs_Object, siblings); + if (l && !fn(l)) { + return YAFFS_FAIL; + } } } @@ -6020,6 +6841,7 @@ if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { /* We want the object id of the equivalent object, not this one */ obj = obj->variant.hardLinkVariant.equivalentObject; + yaffs_CheckObjectDetailsLoaded(obj); } return obj; @@ -6033,7 +6855,7 @@ if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1); - } else if (obj->chunkId <= 0) { + } else if (obj->hdrChunk <= 0) { YCHAR locName[20]; /* make up a name */ yaffs_sprintf(locName, _Y("%s%d"), YAFFS_LOSTNFOUND_PREFIX, @@ -6054,9 +6876,9 @@ memset(buffer, 0, obj->myDev->nDataBytesPerChunk); - if (obj->chunkId >= 0) { + if (obj->hdrChunk > 0) { result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev, - obj->chunkId, buffer, + obj->hdrChunk, buffer, NULL); } yaffs_strncpy(name, oh->name, buffSize - 1); @@ -6086,16 +6908,16 @@ int yaffs_GetObjectLinkCount(yaffs_Object * obj) { - int count = 0; - struct list_head *i; + int count = 0; + struct ylist_head *i; - if (!obj->unlinked) { - count++; /* the object itself */ - } - list_for_each(i, &obj->hardLinks) { - count++; /* add the hard links; */ - } - return count; + if (!obj->unlinked) { + count++; /* the object itself */ + } + ylist_for_each(i, &obj->hardLinks) { + count++; /* add the hard links; */ + } + return count; } @@ -6217,7 +7039,7 @@ ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d" " chunk %d type %d size %d\n" TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name, - obj->dirty, obj->valid, obj->serial, obj->sum, obj->chunkId, + obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj))); return YAFFS_OK; @@ -6257,7 +7079,7 @@ } -static void yaffs_CreateInitialDirectories(yaffs_Device *dev) +static int yaffs_CreateInitialDirectories(yaffs_Device *dev) { /* Initialise the unlinked, deleted, root and lost and found directories */ @@ -6266,6 +7088,7 @@ dev->unlinkedDir = yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); + dev->deletedDir = yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); @@ -6275,11 +7098,18 @@ dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND, YAFFS_LOSTNFOUND_MODE | S_IFDIR); - yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir); + + if(dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir){ + yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir); + return YAFFS_OK; + } + + return YAFFS_FAIL; } int yaffs_GutsInitialise(yaffs_Device * dev) { + int init_failed = 0; unsigned x; int bits; @@ -6307,8 +7137,9 @@ /* Check geometry parameters. */ - if ((dev->isYaffs2 && dev->nDataBytesPerChunk < 1024) || - (!dev->isYaffs2 && dev->nDataBytesPerChunk != 512) || + 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 || @@ -6317,8 +7148,8 @@ ) { T(YAFFS_TRACE_ALWAYS, (TSTR - ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " - TENDSTR), dev->nDataBytesPerChunk, dev->isYaffs2 ? "2" : "")); + ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d " + TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags)); return YAFFS_FAIL; } @@ -6328,6 +7159,12 @@ return YAFFS_FAIL; } + /* Sort out space for inband tags, if required */ + if(dev->inbandTags) + dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart); + else + dev->nDataBytesPerChunk = dev->totalBytesPerChunk; + /* Got the right mix of functions? */ if (!yaffs_CheckDevFunctions(dev)) { /* Function missing */ @@ -6360,24 +7197,16 @@ /* OK now calculate a few things for the device */ /* - * Calculate all the chunk size manipulation numbers: + * Calculate all the chunk size manipulation numbers: */ - /* Start off assuming it is a power of 2 */ - dev->chunkShift = ShiftDiv(dev->nDataBytesPerChunk); - dev->chunkMask = (1<chunkShift) - 1; - - if(dev->nDataBytesPerChunk == (dev->chunkMask + 1)){ - /* Yes it is a power of 2, disable crumbs */ - dev->crumbMask = 0; - dev->crumbShift = 0; - dev->crumbsPerChunk = 0; - } else { - /* Not a power of 2, use crumbs instead */ - dev->crumbShift = ShiftDiv(sizeof(yaffs_PackedTags2TagsPart)); - dev->crumbMask = (1<crumbShift)-1; - dev->crumbsPerChunk = dev->nDataBytesPerChunk/(1 << dev->crumbShift); - dev->chunkShift = 0; - dev->chunkMask = 0; + { + __u32 x = dev->nDataBytesPerChunk; + /* We always use dev->chunkShift and dev->chunkDiv */ + dev->chunkShift = Shifts(x); + x >>= dev->chunkShift; + dev->chunkDiv = x; + /* We only use chunk mask if chunkDiv is 1 */ + dev->chunkMask = (1<chunkShift) - 1; } @@ -6451,71 +7280,114 @@ dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */ /* Initialise temporary buffers and caches. */ - { - int i; - for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { - dev->tempBuffer[i].line = 0; /* not in use */ - dev->tempBuffer[i].buffer = - YMALLOC_DMA(dev->nDataBytesPerChunk); - } - } + if(!yaffs_InitialiseTempBuffers(dev)) + init_failed = 1; - if (dev->nShortOpCaches > 0) { + dev->srCache = NULL; + dev->gcCleanupList = NULL; + + + if (!init_failed && + dev->nShortOpCaches > 0) { int i; + void *buf; + int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache); if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) { dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; } - dev->srCache = - YMALLOC(dev->nShortOpCaches * sizeof(yaffs_ChunkCache)); + buf = dev->srCache = YMALLOC(srCacheBytes); - for (i = 0; i < dev->nShortOpCaches; i++) { + if(dev->srCache) + memset(dev->srCache,0,srCacheBytes); + + for (i = 0; i < dev->nShortOpCaches && buf; i++) { dev->srCache[i].object = NULL; dev->srCache[i].lastUse = 0; dev->srCache[i].dirty = 0; - dev->srCache[i].data = YMALLOC_DMA(dev->nDataBytesPerChunk); + dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk); } + if(!buf) + init_failed = 1; + dev->srLastUse = 0; } dev->cacheHits = 0; - dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); + if(!init_failed){ + dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); + if(!dev->gcCleanupList) + init_failed = 1; + } if (dev->isYaffs2) { dev->useHeaderFileSize = 1; } + if(!init_failed && !yaffs_InitialiseBlocks(dev)) + init_failed = 1; - yaffs_InitialiseBlocks(dev); yaffs_InitialiseTnodes(dev); yaffs_InitialiseObjects(dev); - yaffs_CreateInitialDirectories(dev); + if(!init_failed && !yaffs_CreateInitialDirectories(dev)) + init_failed = 1; - /* Now scan the flash. */ - if (dev->isYaffs2) { - if(yaffs_CheckpointRestore(dev)) { - T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs: restored from checkpoint" TENDSTR))); - } else { + if(!init_failed){ + /* Now scan the flash. */ + if (dev->isYaffs2) { + if(yaffs_CheckpointRestore(dev)) { + yaffs_CheckObjectDetailsLoaded(dev->rootDir); + T(YAFFS_TRACE_ALWAYS, + (TSTR("yaffs: restored from checkpoint" TENDSTR))); + } else { - /* Clean up the mess caused by an aborted checkpoint load - * and scan backwards. - */ - yaffs_DeinitialiseBlocks(dev); - yaffs_DeinitialiseTnodes(dev); - yaffs_DeinitialiseObjects(dev); - yaffs_InitialiseBlocks(dev); - yaffs_InitialiseTnodes(dev); - yaffs_InitialiseObjects(dev); - yaffs_CreateInitialDirectories(dev); + /* Clean up the mess caused by an aborted checkpoint load + * and scan backwards. + */ + yaffs_DeinitialiseBlocks(dev); + yaffs_DeinitialiseTnodes(dev); + yaffs_DeinitialiseObjects(dev); - yaffs_ScanBackwards(dev); - } - }else - yaffs_Scan(dev); + + dev->nErasedBlocks = 0; + dev->nFreeChunks = 0; + dev->allocationBlock = -1; + dev->allocationPage = -1; + dev->nDeletedFiles = 0; + dev->nUnlinkedFiles = 0; + dev->nBackgroundDeletions = 0; + dev->oldestDirtySequence = 0; + + if(!init_failed && !yaffs_InitialiseBlocks(dev)) + init_failed = 1; + + yaffs_InitialiseTnodes(dev); + yaffs_InitialiseObjects(dev); + + if(!init_failed && !yaffs_CreateInitialDirectories(dev)) + init_failed = 1; + + if(!init_failed && !yaffs_ScanBackwards(dev)) + init_failed = 1; + } + }else + if(!yaffs_Scan(dev)) + init_failed = 1; + + yaffs_StripDeletedObjects(dev); + } + + if(init_failed){ + /* Clean up the mess */ + T(YAFFS_TRACE_TRACING, + (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR))); + + yaffs_Deinitialise(dev); + return YAFFS_FAIL; + } /* Zero out stats */ dev->nPageReads = 0; @@ -6527,6 +7399,8 @@ dev->nRetiredBlocks = 0; yaffs_VerifyFreeChunks(dev); + yaffs_VerifyBlocks(dev); + T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); @@ -6542,13 +7416,17 @@ yaffs_DeinitialiseBlocks(dev); yaffs_DeinitialiseTnodes(dev); yaffs_DeinitialiseObjects(dev); - if (dev->nShortOpCaches > 0) { + if (dev->nShortOpCaches > 0 && + dev->srCache) { for (i = 0; i < dev->nShortOpCaches; i++) { - YFREE(dev->srCache[i].data); + if(dev->srCache[i].data) + YFREE(dev->srCache[i].data); + dev->srCache[i].data = NULL; } YFREE(dev->srCache); + dev->srCache = NULL; } YFREE(dev->gcCleanupList); @@ -6557,6 +7435,7 @@ YFREE(dev->tempBuffer[i].buffer); } + dev->isMounted = 0; } @@ -6622,7 +7501,7 @@ nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); /* Now we figure out how much to reserve for the checkpoint and report that... */ - blocksForCheckpoint = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; + blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; if(blocksForCheckpoint < 0) blocksForCheckpoint = 0; @@ -6639,9 +7518,15 @@ static void yaffs_VerifyFreeChunks(yaffs_Device * dev) { - int counted = yaffs_CountFreeChunks(dev); + int counted; + int difference; + + if(yaffs_SkipVerification(dev)) + return; + + counted = yaffs_CountFreeChunks(dev); - int difference = dev->nFreeChunks - counted; + difference = dev->nFreeChunks - counted; if (difference) { T(YAFFS_TRACE_ALWAYS, @@ -6654,22 +7539,25 @@ /*---------------------------------------- YAFFS test code ----------------------*/ #define yaffs_CheckStruct(structure,syze, name) \ + do { \ if(sizeof(structure) != syze) \ { \ T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),\ name,syze,sizeof(structure))); \ return YAFFS_FAIL; \ - } + } \ + } while(0) static int yaffs_CheckStructures(void) { -/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags") */ -/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion") */ -/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare") */ +/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */ +/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */ +/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */ #ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG - yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode") + yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); +#endif +#ifndef CONFIG_YAFFS_WINCE + yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader"); #endif - yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader") - return YAFFS_OK; } diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_guts.h fs/yaffs2/yaffs_guts.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_guts.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_guts.h 2009-08-05 14:02:36.014387000 -0400 @@ -1,8 +1,7 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffs_guts.h: Configuration etc for yaffs_guts + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -11,10 +10,7 @@ * 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. - * - * $Id: yaffs_guts.h,v 1.25 2006/10/13 08:52:49 charles Exp $ */ #ifndef __YAFFS_GUTS_H__ @@ -67,9 +63,7 @@ #define YAFFS_OBJECT_SPACE 0x40000 -#define YAFFS_NCHECKPOINT_OBJECTS 5000 - -#define YAFFS_CHECKPOINT_VERSION 2 +#define YAFFS_CHECKPOINT_VERSION 3 #ifdef CONFIG_YAFFS_UNICODE #define YAFFS_MAX_NAME_LENGTH 127 @@ -96,7 +90,13 @@ #define YAFFS_MAX_SHORT_OP_CACHES 20 -#define YAFFS_N_TEMP_BUFFERS 4 +#define YAFFS_N_TEMP_BUFFERS 6 + +/* We limit the number attempts at sucessfully saving a chunk of data. + * Small-page devices have 32 pages per block; large-page devices have 64. + * Default to something in the order of 5 to 10 blocks worth of chunks. + */ +#define YAFFS_WR_ATTEMPTS (5*64) /* Sequence numbers are used in YAFFS2 to determine block allocation order. * The range is limited slightly to help distinguish bad numbers from good. @@ -108,6 +108,9 @@ #define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 #define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00 +/* Special sequence number for bad block that failed to be marked bad */ +#define YAFFS_SEQUENCE_BAD_BLOCK 0xFFFF0000 + /* ChunkCache is used for short read/write operations.*/ typedef struct { struct yaffs_ObjectStruct *object; @@ -166,6 +169,8 @@ YAFFS_OBJECT_TYPE_SPECIAL } yaffs_ObjectType; +#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL + typedef struct { unsigned validMarker0; @@ -268,15 +273,18 @@ /* This block has failed and is not in use */ } yaffs_BlockState; +#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) + + typedef struct { int softDeletions:10; /* number of soft deleted pages */ int pagesInUse:10; /* number of pages in use */ - yaffs_BlockState blockState:4; /* One of the above block states */ + unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */ __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */ /* and retire the block. */ __u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */ - __u32 gcPrioritise: 1; /* An ECC check or bank check has failed on this block. + __u32 gcPrioritise: 1; /* An ECC check or blank check has failed on this block. It should be prioritised for GC */ __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */ @@ -295,11 +303,11 @@ /* Apply to everything */ int parentObjectId; - __u16 sum__NoLongerUsed; /* checksum of name. No longer used */ - YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; + __u16 sum__NoLongerUsed; /* checksum of name. No longer used */ + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; - /* Thes following apply to directories, files, symlinks - not hard links */ - __u32 yst_mode; /* protection */ + /* The following apply to directories, files, symlinks - not hard links */ + __u32 yst_mode; /* protection */ #ifdef CONFIG_YAFFS_WINCE __u32 notForWinCE[5]; @@ -326,11 +334,14 @@ __u32 win_ctime[2]; __u32 win_atime[2]; __u32 win_mtime[2]; - __u32 roomToGrow[4]; #else - __u32 roomToGrow[10]; + __u32 roomToGrow[6]; + #endif + __u32 inbandShadowsObject; + __u32 inbandIsShrink; + __u32 reservedSpace[2]; int shadowsObject; /* This object header shadows the specified object if > 0 */ /* isShrink applies to object headers written when we shrink the file (ie resize) */ @@ -376,7 +387,7 @@ } yaffs_FileStructure; typedef struct { - struct list_head children; /* list of child links */ + struct ylist_head children; /* list of child links */ } yaffs_DirectoryStructure; typedef struct { @@ -417,19 +428,19 @@ __u8 serial; /* serial number of chunk in NAND. Cached here */ __u16 sum; /* sum of the name to speed searching */ - struct yaffs_DeviceStruct *myDev; /* The device I'm on */ + struct yaffs_DeviceStruct *myDev; /* The device I'm on */ - struct list_head hashLink; /* list of objects in this hash bucket */ + struct ylist_head hashLink; /* list of objects in this hash bucket */ - struct list_head hardLinks; /* all the equivalent hard linked objects */ + struct ylist_head hardLinks; /* all the equivalent hard linked objects */ - /* directory structure stuff */ - /* also used for linking up the free list */ - struct yaffs_ObjectStruct *parent; - struct list_head siblings; + /* directory structure stuff */ + /* also used for linking up the free list */ + struct yaffs_ObjectStruct *parent; + struct ylist_head siblings; /* Where's my object header in NAND? */ - int chunkId; + int hdrChunk; int nDataChunks; /* Number of data chunks attached to the file. */ @@ -480,8 +491,8 @@ typedef struct yaffs_ObjectList_struct yaffs_ObjectList; typedef struct { - struct list_head list; - int count; + struct ylist_head list; + int count; } yaffs_ObjectBucket; @@ -493,8 +504,7 @@ int structType; __u32 objectId; __u32 parentId; - int chunkId; - + int hdrChunk; yaffs_ObjectType variantType:3; __u8 deleted:1; __u8 softDeleted:1; @@ -523,26 +533,23 @@ /*----------------- Device ---------------------------------*/ struct yaffs_DeviceStruct { - struct list_head devList; - const char *name; + struct ylist_head devList; + const char *name; - /* Entry parameters set up way early. Yaffs sets up the rest.*/ - int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */ - int nChunksPerBlock; /* does not need to be a power of 2 */ - int nBytesPerSpare; /* spare area size */ - int startBlock; /* Start block we're allowed to use */ - int endBlock; /* End block we're allowed to use */ - int nReservedBlocks; /* We want this tuneable so that we can reduce */ + /* Entry parameters set up way early. Yaffs sets up the rest.*/ + int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */ + int nChunksPerBlock; /* does not need to be a power of 2 */ + int spareBytesPerChunk;/* spare area size */ + int startBlock; /* Start block we're allowed to use */ + int endBlock; /* End block we're allowed to use */ + int nReservedBlocks; /* We want this tuneable so that we can reduce */ /* reserved blocks on NOR and RAM. */ - /* Stuff used by the partitioned checkpointing mechanism */ - int checkpointStartBlock; - int checkpointEndBlock; /* Stuff used by the shared space checkpointing mechanism */ /* If this value is zero, then this mechanism is disabled */ - int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */ +// int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */ @@ -581,7 +588,7 @@ yaffs_ExtendedTags * tags); int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo); int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo, - yaffs_BlockState * state, int *sequenceNumber); + yaffs_BlockState * state, __u32 *sequenceNumber); #endif int isYaffs2; @@ -597,9 +604,15 @@ int wideTnodesDisabled; /* Set to disable wide tnodes */ + YCHAR *pathDividers; /* String of legal path dividers */ + /* End of stuff that must be set before initialisation. */ + /* Checkpoint control. Can be set before or after initialisation */ + __u8 skipCheckpointRead; + __u8 skipCheckpointWrite; + /* Runtime parameters. Set up by YAFFS. */ __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */ @@ -609,16 +622,14 @@ __u32 tnodeWidth; __u32 tnodeMask; - /* Stuff to support various file offses to chunk/offset translations */ - /* "Crumbs" for nDataBytesPerChunk not being a power of 2 */ - __u32 crumbMask; - __u32 crumbShift; - __u32 crumbsPerChunk; - - /* Straight shifting for nDataBytesPerChunk being a power of 2 */ - __u32 chunkShift; - __u32 chunkMask; - + /* Stuff for figuring out file offset to chunk conversions */ + __u32 chunkShift; /* Shift value */ + __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */ + __u32 chunkMask; /* Mask to use for power-of-2 case */ + + /* Stuff to handle inband tags */ + int inbandTags; + __u32 totalBytesPerChunk; #ifdef __KERNEL__ @@ -654,6 +665,10 @@ int checkpointNextBlock; int *checkpointBlockList; int checkpointMaxBlocks; + __u32 checkpointSum; + __u32 checkpointXor; + + int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */ /* Block Info */ yaffs_BlockInfo *blockInfo; @@ -681,6 +696,8 @@ yaffs_Object *freeObjects; int nFreeObjects; + int nHardLinks; + yaffs_ObjectList *allocatedObjectList; yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS]; @@ -690,6 +707,7 @@ int currentDirtyChecker; /* Used to find current dirtiest block */ __u32 *gcCleanupList; /* objects to delete at the end of a GC. */ + int nonAggressiveSkip; /* GC state/mode */ /* Statistcs */ int nPageWrites; @@ -736,8 +754,10 @@ int nBackgroundDeletions; /* Count of background deletions. */ + /* Temporary buffer management */ yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS]; int maxTemp; + int tempInUse; int unmanagedTempAllocations; int unmanagedTempDeallocations; @@ -749,10 +769,10 @@ typedef struct yaffs_DeviceStruct yaffs_Device; -/* The static layout of bllock usage etc is stored in the super block header */ +/* The static layout of block usage etc is stored in the super block header */ typedef struct { int StructType; - int version; + int version; int checkpointStartBlock; int checkpointEndBlock; int startBlock; @@ -788,18 +808,6 @@ __u32 head; } yaffs_CheckpointValidity; -/* Function to manipulate block info */ -static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk) -{ - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { - T(YAFFS_TRACE_ERROR, - (TSTR - ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR), - blk)); - YBUG(); - } - return &dev->blockInfo[blk - dev->internalStartBlock]; -} /*----------------------- YAFFS Functions -----------------------*/ @@ -825,13 +833,13 @@ /* File operations */ int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, loff_t offset, - int nBytes); + int nBytes); int yaffs_WriteDataToFile(yaffs_Object * obj, const __u8 * buffer, loff_t offset, - int nBytes, int writeThrough); + int nBytes, int writeThrough); int yaffs_ResizeFile(yaffs_Object * obj, loff_t newSize); yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name, - __u32 mode, __u32 uid, __u32 gid); + __u32 mode, __u32 uid, __u32 gid); int yaffs_FlushFile(yaffs_Object * obj, int updateTime); /* Flushing and checkpointing */ @@ -890,4 +898,7 @@ int yaffs_CheckFF(__u8 * buffer, int nBytes); void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi); +__u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo); +void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, int lineNo); + #endif diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_mtdif.c fs/yaffs2/yaffs_mtdif.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_mtdif.c 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_mtdif.c 2009-08-05 14:02:43.895646000 -0400 @@ -1,8 +1,7 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffs_mtdif.c NAND mtd wrapper functions. + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -10,11 +9,10 @@ * 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. - * */ const char *yaffs_mtdif_c_version = - "$Id: yaffs_mtdif.c,v 1.17 2006/11/29 20:21:12 charles Exp $"; + "$Id$"; #include "yportenv.h" @@ -26,7 +24,7 @@ #include "linux/time.h" #include "linux/mtd/nand.h" -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) +#if (MTD_VERSION_CODE < MTD_VERSION(2,6,18)) static struct nand_oobinfo yaffs_oobinfo = { .useecc = 1, .eccbytes = 6, @@ -38,7 +36,7 @@ }; #endif -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob) { oob[0] = spare->tagByte0; @@ -77,14 +75,14 @@ const __u8 * data, const yaffs_Spare * spare) { struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) struct mtd_oob_ops ops; #endif size_t dummy; int retval = 0; loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) __u8 spareAsBytes[8]; /* OOB */ if (data && !spare) @@ -141,14 +139,14 @@ yaffs_Spare * spare) { struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) struct mtd_oob_ops ops; #endif size_t dummy; int retval = 0; loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) __u8 spareAsBytes[8]; /* OOB */ if (data && !spare) @@ -174,7 +172,7 @@ __u8 *spareAsBytes = (__u8 *) spare; if (data && spare) { - if (dev->useNANDECC) { + if (dev->useNANDECC) { /* Careful, this call adds 2 ints */ /* to the end of the spare data. Calling function */ /* should allocate enough memory for spare, */ diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_mtdif.h fs/yaffs2/yaffs_mtdif.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_mtdif.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_mtdif.h 2009-08-05 14:02:45.596497000 -0400 @@ -1,8 +1,7 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffs_mtdif.h NAND mtd interface wrappers + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -11,10 +10,7 @@ * 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. - * - * $Id: yaffs_mtdif.h,v 1.3 2005/08/11 01:07:43 marty Exp $ */ #ifndef __YAFFS_MTDIF_H__ @@ -22,6 +18,11 @@ #include "yaffs_guts.h" +#if (MTD_VERSION_CODE < MTD_VERSION(2,6,18)) +extern struct nand_oobinfo yaffs_oobinfo; +extern struct nand_oobinfo yaffs_noeccinfo; +#endif + int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND, const __u8 * data, const yaffs_Spare * spare); int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data, diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_mtdif1.c fs/yaffs2/yaffs_mtdif1.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_mtdif1.c 1969-12-31 19:00:00.000000000 -0500 +++ fs/yaffs2/yaffs_mtdif1.c 2009-08-05 14:02:38.239194000 -0400 @@ -0,0 +1,369 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND. + * + * Copyright (C) 2002 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This module provides the interface between yaffs_nand.c and the + * MTD API. This version is used when the MTD interface supports the + * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17, + * and we have small-page NAND device. + * + * These functions are invoked via function pointers in yaffs_nand.c. + * This replaces functionality provided by functions in yaffs_mtdif.c + * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are + * called in yaffs_mtdif.c when the function pointers are NULL. + * We assume the MTD layer is performing ECC (useNANDECC is true). + */ + +#include "yportenv.h" +#include "yaffs_guts.h" +#include "yaffs_packedtags1.h" +#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC + +#include "linux/kernel.h" +#include "linux/version.h" +#include "linux/types.h" +#include "linux/mtd/mtd.h" + +/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ +#if (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 +# define YTAG1_SIZE 9 +#endif + +#if 0 +/* Use the following nand_ecclayout with MTD when using + * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout. + * If you have existing Yaffs images and the byte order differs from this, + * adjust 'oobfree' to match your existing Yaffs data. + * + * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the + * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to + * the 9th byte. + * + * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5 + * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P + * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus + * byte and B is the small-page bad-block indicator byte. + */ +static struct nand_ecclayout nand_oob_16 = { + .eccbytes = 6, + .eccpos = { 8, 9, 10, 13, 14, 15 }, + .oobavail = 9, + .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } } +}; +#endif + +/* Write a chunk (page) of data to NAND. + * + * Caller always provides ExtendedTags data which are converted to a more + * compact (packed) form for storage in NAND. A mini-ECC runs over the + * contents of the tags meta-data; used to valid the tags when read. + * + * - Pack ExtendedTags to PackedTags1 form + * - Compute mini-ECC for PackedTags1 + * - Write data and packed tags to NAND. + * + * Note: Due to the use of the PackedTags1 meta-data which does not include + * a full sequence number (as found in the larger PackedTags2 form) it is + * necessary for Yaffs to re-write a chunk/page (just once) to mark it as + * discarded and dirty. This is not ideal: newer NAND parts are supposed + * to be written just once. When Yaffs performs this operation, this + * function is called with a NULL data pointer -- calling MTD write_oob + * without data is valid usage (2.6.17). + * + * Any underlying MTD error results in YAFFS_FAIL. + * Returns YAFFS_OK or YAFFS_FAIL. + */ +int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, + int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags) +{ + struct mtd_info * mtd = dev->genericDevice; + int chunkBytes = dev->nDataBytesPerChunk; + loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; + struct mtd_oob_ops ops; + yaffs_PackedTags1 pt1; + int retval; + + /* we assume that PackedTags1 and yaffs_Tags are compatible */ + compile_time_assertion(sizeof(yaffs_PackedTags1) == 12); + compile_time_assertion(sizeof(yaffs_Tags) == 8); + + dev->nPageWrites++; + + yaffs_PackTags1(&pt1, etags); + yaffs_CalcTagsECC((yaffs_Tags *)&pt1); + + /* When deleting a chunk, the upper layer provides only skeletal + * etags, one with chunkDeleted set. However, we need to update the + * tags, not erase them completely. So we use the NAND write property + * that only zeroed-bits stick and set tag bytes to all-ones and + * zero just the (not) deleted bit. + */ +#ifndef CONFIG_YAFFS_9BYTE_TAGS + if (etags->chunkDeleted) { + memset(&pt1, 0xff, 8); + /* clear delete status bit to indicate deleted */ + pt1.deleted = 0; + } +#else + ((__u8 *)&pt1)[8] = 0xff; + if (etags->chunkDeleted) { + memset(&pt1, 0xff, 8); + /* zero pageStatus byte to indicate deleted */ + ((__u8 *)&pt1)[8] = 0; + } +#endif + + memset(&ops, 0, sizeof(ops)); + ops.mode = MTD_OOB_AUTO; + ops.len = (data) ? chunkBytes : 0; + ops.ooblen = YTAG1_SIZE; + ops.datbuf = (__u8 *)data; + ops.oobbuf = (__u8 *)&pt1; + + retval = mtd->write_oob(mtd, addr, &ops); + if (retval) { + yaffs_trace(YAFFS_TRACE_MTD, + "write_oob failed, chunk %d, mtd error %d\n", + chunkInNAND, retval); + } + return retval ? YAFFS_FAIL : YAFFS_OK; +} + +/* Return with empty ExtendedTags but add eccResult. + */ +static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval) +{ + if (etags) { + memset(etags, 0, sizeof(*etags)); + etags->eccResult = eccResult; + } + return retval; +} + +/* Read a chunk (page) from NAND. + * + * Caller expects ExtendedTags data to be usable even on error; that is, + * all members except eccResult and blockBad are zeroed. + * + * - Check ECC results for data (if applicable) + * - Check for blank/erased block (return empty ExtendedTags if blank) + * - Check the PackedTags1 mini-ECC (correct if necessary/possible) + * - Convert PackedTags1 to ExtendedTags + * - Update eccResult and blockBad members to refect state. + * + * Returns YAFFS_OK or YAFFS_FAIL. + */ +int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, + int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags) +{ + struct mtd_info * mtd = dev->genericDevice; + int chunkBytes = dev->nDataBytesPerChunk; + loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; + int eccres = YAFFS_ECC_RESULT_NO_ERROR; + struct mtd_oob_ops ops; + yaffs_PackedTags1 pt1; + int retval; + int deleted; + + dev->nPageReads++; + + memset(&ops, 0, sizeof(ops)); + ops.mode = MTD_OOB_AUTO; + ops.len = (data) ? chunkBytes : 0; + ops.ooblen = YTAG1_SIZE; + ops.datbuf = data; + ops.oobbuf = (__u8 *)&pt1; + +#if (MTD_VERSION_CODE < MTD_VERSION(2,6,20)) + /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; + * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. + */ + ops.len = (ops.datbuf) ? ops.len : ops.ooblen; +#endif + /* Read page and oob using MTD. + * Check status and determine ECC result. + */ + retval = mtd->read_oob(mtd, addr, &ops); + if (retval) { + yaffs_trace(YAFFS_TRACE_MTD, + "read_oob failed, chunk %d, mtd error %d\n", + chunkInNAND, retval); + } + + switch (retval) { + case 0: + /* no error */ + break; + + case -EUCLEAN: + /* MTD's ECC fixed the data */ + eccres = YAFFS_ECC_RESULT_FIXED; + dev->eccFixed++; + break; + + case -EBADMSG: + /* MTD's ECC could not fix the data */ + dev->eccUnfixed++; + /* fall into... */ + default: + rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0); + etags->blockBad = (mtd->block_isbad)(mtd, addr); + return YAFFS_FAIL; + } + + /* Check for a blank/erased chunk. + */ + if (yaffs_CheckFF((__u8 *)&pt1, 8)) { + /* when blank, upper layers want eccResult to be <= NO_ERROR */ + return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK); + } + +#ifndef CONFIG_YAFFS_9BYTE_TAGS + /* Read deleted status (bit) then return it to it's non-deleted + * state before performing tags mini-ECC check. pt1.deleted is + * inverted. + */ + deleted = !pt1.deleted; + pt1.deleted = 1; +#else + deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7); +#endif + + /* Check the packed tags mini-ECC and correct if necessary/possible. + */ + retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1); + switch (retval) { + case 0: + /* no tags error, use MTD result */ + break; + case 1: + /* recovered tags-ECC error */ + dev->tagsEccFixed++; + if (eccres == YAFFS_ECC_RESULT_NO_ERROR) + eccres = YAFFS_ECC_RESULT_FIXED; + break; + default: + /* unrecovered tags-ECC error */ + dev->tagsEccUnfixed++; + return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL); + } + + /* Unpack the tags to extended form and set ECC result. + * [set shouldBeFF just to keep yaffs_UnpackTags1 happy] + */ + pt1.shouldBeFF = 0xFFFFFFFF; + yaffs_UnpackTags1(etags, &pt1); + etags->eccResult = eccres; + + /* Set deleted state */ + etags->chunkDeleted = deleted; + return YAFFS_OK; +} + +/* Mark a block bad. + * + * This is a persistant state. + * Use of this function should be rare. + * + * Returns YAFFS_OK or YAFFS_FAIL. + */ +int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) +{ + struct mtd_info * mtd = dev->genericDevice; + int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; + int retval; + + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo); + + retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo); + return (retval) ? YAFFS_FAIL : YAFFS_OK; +} + +/* Check any MTD prerequists. + * + * Returns YAFFS_OK or YAFFS_FAIL. + */ +static int nandmtd1_TestPrerequists(struct mtd_info * mtd) +{ + /* 2.6.18 has mtd->ecclayout->oobavail */ + /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */ + int oobavail = mtd->ecclayout->oobavail; + + if (oobavail < YTAG1_SIZE) { + yaffs_trace(YAFFS_TRACE_ERROR, + "mtd device has only %d bytes for tags, need %d\n", + oobavail, YTAG1_SIZE); + return YAFFS_FAIL; + } + return YAFFS_OK; +} + +/* Query for the current state of a specific block. + * + * Examine the tags of the first chunk of the block and return the state: + * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad + * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use + * - YAFFS_BLOCK_STATE_EMPTY, the block is clean + * + * Always returns YAFFS_OK. + */ +int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, + yaffs_BlockState * pState, __u32 *pSequenceNumber) +{ + struct mtd_info * mtd = dev->genericDevice; + int chunkNo = blockNo * dev->nChunksPerBlock; + loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk; + yaffs_ExtendedTags etags; + int state = YAFFS_BLOCK_STATE_DEAD; + int seqnum = 0; + int retval; + + /* We don't yet have a good place to test for MTD config prerequists. + * Do it here as we are called during the initial scan. + */ + if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) { + return YAFFS_FAIL; + } + + retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); + etags.blockBad = (mtd->block_isbad)(mtd, addr); + if (etags.blockBad) { + 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 */ + state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; + } + else if (etags.chunkUsed) { + state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; + seqnum = etags.sequenceNumber; + } + else { + state = YAFFS_BLOCK_STATE_EMPTY; + } + + *pState = state; + *pSequenceNumber = seqnum; + + /* query always succeeds */ + return YAFFS_OK; +} + +#endif /*MTD_VERSION*/ diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_mtdif1.h fs/yaffs2/yaffs_mtdif1.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_mtdif1.h 1969-12-31 19:00:00.000000000 -0500 +++ fs/yaffs2/yaffs_mtdif1.h 2009-08-05 14:02:38.289144000 -0400 @@ -0,0 +1,28 @@ +/* + * YAFFS: Yet another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * 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_MTDIF1_H__ +#define __YAFFS_MTDIF1_H__ + +int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, + const __u8 * data, const yaffs_ExtendedTags * tags); + +int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, + __u8 * data, yaffs_ExtendedTags * tags); + +int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); + +int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, + yaffs_BlockState * state, __u32 *sequenceNumber); + +#endif diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_mtdif2.c fs/yaffs2/yaffs_mtdif2.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_mtdif2.c 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_mtdif2.c 2009-08-05 14:02:39.902014000 -0400 @@ -1,8 +1,7 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffs_mtdif.c NAND mtd wrapper functions. + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -10,13 +9,12 @@ * 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. - * */ /* mtd interface for YAFFS2 */ const char *yaffs_mtdif2_c_version = - "$Id: yaffs_mtdif2.c,v 1.15 2006/11/08 06:24:34 charles Exp $"; + "$Id$"; #include "yportenv.h" @@ -29,19 +27,23 @@ #include "yaffs_packedtags2.h" +/* NB For use with inband tags.... + * We assume that the data buffer is of size totalBytersPerChunk so that we can also + * use it to load the tags. + */ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * tags) { struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) struct mtd_oob_ops ops; #else size_t dummy; #endif int retval = 0; - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; + loff_t addr; yaffs_PackedTags2 pt; @@ -50,46 +52,42 @@ ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" TENDSTR), chunkInNAND, data, tags)); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - if (tags) - yaffs_PackTags2(&pt, tags); - else - BUG(); /* both tags and data should always be present */ + dev->nPageWrites++; - if (data) { - ops.mode = MTD_OOB_AUTO; - ops.ooblen = sizeof(pt); - ops.len = dev->nDataBytesPerChunk; - ops.ooboffs = 0; - ops.datbuf = (__u8 *)data; - ops.oobbuf = (void *)&pt; - retval = mtd->write_oob(mtd, addr, &ops); - } else - BUG(); /* both tags and data should always be present */ -#else - if (tags) { - yaffs_PackTags2(&pt, tags); + addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; + + /* For yaffs2 writing there must be both data and tags. + * If we're using inband tags, then the tags are stuffed into + * the end of the data buffer. + */ + if(!data || !tags) + BUG(); + else if(dev->inbandTags){ + yaffs_PackedTags2TagsPart *pt2tp; + pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); + yaffs_PackTags2TagsPart(pt2tp,tags); } + else + yaffs_PackTags2(&pt, tags); - if (data && tags) { - if (dev->useNANDECC) - retval = - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, (__u8 *) & pt, NULL); - else - retval = - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, (__u8 *) & pt, NULL); - } else { - if (data) - retval = - mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, - data); - if (tags) - retval = - mtd->write_oob(mtd, addr, mtd->oobsize, &dummy, - (__u8 *) & pt); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + ops.mode = MTD_OOB_AUTO; + ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt); + ops.len = dev->totalBytesPerChunk; + ops.ooboffs = 0; + ops.datbuf = (__u8 *)data; + ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt; + retval = mtd->write_oob(mtd, addr, &ops); +#else + if (!dev->inbandTags) { + retval = + mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, + &dummy, data, (__u8 *) & pt, NULL); + } else { + retval = + mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy, + data); } #endif @@ -103,11 +101,12 @@ __u8 * data, yaffs_ExtendedTags * tags) { struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17)) struct mtd_oob_ops ops; #endif size_t dummy; int retval = 0; + int localData = 0; loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; @@ -118,9 +117,22 @@ ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p" TENDSTR), chunkInNAND, data, tags)); + dev->nPageReads++; + + if(dev->inbandTags){ + + if(!data) { + localData = 1; + data = yaffs_GetTempBuffer(dev,__LINE__); + } + + + } + + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - if (data && !tags) - retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, + if (dev->inbandTags || (data && !tags)) + retval = mtd->read(mtd, addr, dev->totalBytesPerChunk, &dummy, data); else if (tags) { ops.mode = MTD_OOB_AUTO; @@ -132,38 +144,49 @@ retval = mtd->read_oob(mtd, addr, &ops); } #else - if (data && tags) { - if (dev->useNANDECC) { - retval = - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, dev->spareBuffer, - NULL); - } else { - retval = - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, + if (!dev->inbandTags && data && tags) { + + retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, &dummy, data, dev->spareBuffer, NULL); - } } else { if (data) retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, data); - if (tags) + if (!dev->inbandTags && tags) retval = mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, dev->spareBuffer); } #endif - memcpy(&pt, dev->spareBuffer, sizeof(pt)); - if (tags) - yaffs_UnpackTags2(tags, &pt); - - if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) - tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; + if(dev->inbandTags){ + if(tags){ + yaffs_PackedTags2TagsPart * pt2tp; + pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; + yaffs_UnpackTags2TagsPart(tags,pt2tp); + } + } + else { + if (tags){ + memcpy(&pt, dev->spareBuffer, sizeof(pt)); + yaffs_UnpackTags2(tags, &pt); + } + } + + if(localData) + yaffs_ReleaseTempBuffer(dev,data,__LINE__); + if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) { + tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; + dev->eccUnfixed++; + } + if(tags && retval == -EUCLEAN && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) { + tags->eccResult = YAFFS_ECC_RESULT_FIXED; + dev->eccFixed++; + } if (retval == 0) return YAFFS_OK; else @@ -190,7 +213,7 @@ } int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, - yaffs_BlockState * state, int *sequenceNumber) + yaffs_BlockState * state, __u32 *sequenceNumber) { struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); int retval; diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_mtdif2.h fs/yaffs2/yaffs_mtdif2.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_mtdif2.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_mtdif2.h 2009-08-05 14:02:41.920837000 -0400 @@ -1,16 +1,16 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffs_mtdif.c NAND mtd wrapper functions. + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as + * 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_MTDIF2_H__ @@ -24,6 +24,6 @@ __u8 * data, yaffs_ExtendedTags * tags); int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, - yaffs_BlockState * state, int *sequenceNumber); + yaffs_BlockState * state, __u32 *sequenceNumber); #endif diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_nand.c fs/yaffs2/yaffs_nand.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_nand.c 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_nand.c 2009-08-05 14:02:47.354270000 -0400 @@ -1,7 +1,7 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -9,16 +9,16 @@ * 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. - * */ - + const char *yaffs_nand_c_version = - "$Id: yaffs_nand.c,v 1.5 2006/11/08 09:52:12 charles Exp $"; + "$Id$"; #include "yaffs_nand.h" #include "yaffs_tagscompat.h" #include "yaffs_tagsvalidity.h" +#include "yaffs_getblockinfo.h" int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * buffer, @@ -26,9 +26,9 @@ { int result; yaffs_ExtendedTags localTags; - + int realignedChunkInNAND = chunkInNAND - dev->chunkOffset; - + /* If there are no tags provided, use local tags to get prioritised gc working */ if(!tags) tags = &localTags; @@ -40,14 +40,14 @@ result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer, - tags); - if(tags && + tags); + if(tags && tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){ - + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock); yaffs_HandleChunkError(dev,bi); } - + return result; } @@ -58,7 +58,7 @@ { chunkInNAND -= dev->chunkOffset; - + if (tags) { tags->sequenceNumber = dev->sequenceNumber; tags->chunkUsed = 1; @@ -99,7 +99,7 @@ int yaffs_QueryInitialBlockState(yaffs_Device * dev, int blockNo, yaffs_BlockState * state, - unsigned *sequenceNumber) + __u32 *sequenceNumber) { blockNo -= dev->blockOffset; @@ -132,4 +132,4 @@ } - + diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_nand.h fs/yaffs2/yaffs_nand.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_nand.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_nand.h 2009-08-05 14:02:51.000008000 -0400 @@ -1,15 +1,16 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as + * 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_NAND_H__ diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_nandemul2k.h fs/yaffs2/yaffs_nandemul2k.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_nandemul2k.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_nandemul2k.h 2009-08-05 14:02:49.230180000 -0400 @@ -1,7 +1,7 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -10,14 +10,11 @@ * 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. - * - * yaffs_nandemul2k.h: Interface to emulated NAND functions (2k page size) - * - * $Id: yaffs_nandemul2k.h,v 1.2 2005/08/11 02:37:49 marty Exp $ */ +/* Interface to emulated NAND functions (2k page size) */ + #ifndef __YAFFS_NANDEMUL2K_H__ #define __YAFFS_NANDEMUL2K_H__ @@ -25,13 +22,13 @@ int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, int chunkInNAND, const __u8 * data, - yaffs_ExtendedTags * tags); + const yaffs_ExtendedTags * tags); int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev, int chunkInNAND, __u8 * data, yaffs_ExtendedTags * tags); int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, - yaffs_BlockState * state, int *sequenceNumber); + yaffs_BlockState * state, __u32 *sequenceNumber); int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, int blockInNAND); int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev); diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_packedtags1.c fs/yaffs2/yaffs_packedtags1.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_packedtags1.c 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_packedtags1.c 2009-08-05 14:02:52.766853000 -0400 @@ -1,3 +1,16 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + #include "yaffs_packedtags1.h" #include "yportenv.h" diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_packedtags1.h fs/yaffs2/yaffs_packedtags1.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_packedtags1.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_packedtags1.h 2009-08-05 14:02:54.466621000 -0400 @@ -1,4 +1,19 @@ -// This is used to pack YAFFS1 tags, not YAFFS2 tags. +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */ #ifndef __YAFFS_PACKEDTAGS1_H__ #define __YAFFS_PACKEDTAGS1_H__ diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_packedtags2.c fs/yaffs2/yaffs_packedtags2.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_packedtags2.c 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_packedtags2.c 2009-08-05 14:02:56.187526000 -0400 @@ -1,16 +1,14 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * yaffs_packedtags2.c: Tags packing for YAFFS2 - * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * version 2.1 as published by the Free Software Foundation. + * 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_packedtags2.h" @@ -39,60 +37,73 @@ #define EXTRA_OBJECT_TYPE_SHIFT (28) #define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) -static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt) +#ifndef CONFIG_YAFFS_DOES_ECC +#define YAFFS_IGNORE_TAGS_ECC 1 +#endif + +static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart * ptt) { T(YAFFS_TRACE_MTD, (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), - pt->t.objectId, pt->t.chunkId, pt->t.byteCount, - pt->t.sequenceNumber)); + ptt->objectId, ptt->chunkId, ptt->byteCount, + ptt->sequenceNumber)); +} +static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt) +{ + yaffs_DumpPackedTags2TagsPart(&pt->t); } static void yaffs_DumpTags2(const yaffs_ExtendedTags * t) { T(YAFFS_TRACE_MTD, (TSTR - ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte " - "%d del %d ser %d seq %d" + ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d" TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId, t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, t->sequenceNumber)); } -void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t) +void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart * ptt, const yaffs_ExtendedTags * t) { - pt->t.chunkId = t->chunkId; - pt->t.sequenceNumber = t->sequenceNumber; - pt->t.byteCount = t->byteCount; - pt->t.objectId = t->objectId; + ptt->chunkId = t->chunkId; + ptt->sequenceNumber = t->sequenceNumber; + ptt->byteCount = t->byteCount; + ptt->objectId = t->objectId; if (t->chunkId == 0 && t->extraHeaderInfoAvailable) { /* Store the extra header info instead */ /* We save the parent object in the chunkId */ - pt->t.chunkId = EXTRA_HEADER_INFO_FLAG + ptt->chunkId = EXTRA_HEADER_INFO_FLAG | t->extraParentObjectId; if (t->extraIsShrinkHeader) { - pt->t.chunkId |= EXTRA_SHRINK_FLAG; + ptt->chunkId |= EXTRA_SHRINK_FLAG; } if (t->extraShadows) { - pt->t.chunkId |= EXTRA_SHADOWS_FLAG; + ptt->chunkId |= EXTRA_SHADOWS_FLAG; } - pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK; - pt->t.objectId |= + ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK; + ptt->objectId |= (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT); if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { - pt->t.byteCount = t->extraEquivalentObjectId; + ptt->byteCount = t->extraEquivalentObjectId; } else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) { - pt->t.byteCount = t->extraFileLength; + ptt->byteCount = t->extraFileLength; } else { - pt->t.byteCount = 0; + ptt->byteCount = 0; } } - yaffs_DumpPackedTags2(pt); + yaffs_DumpPackedTags2TagsPart(ptt); yaffs_DumpTags2(t); +} + + +void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t) +{ + yaffs_PackTags2TagsPart(&pt->t,t); #ifndef YAFFS_IGNORE_TAGS_ECC { @@ -103,13 +114,60 @@ #endif } -void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt) + +void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags * t, yaffs_PackedTags2TagsPart * ptt) { memset(t, 0, sizeof(yaffs_ExtendedTags)); yaffs_InitialiseTags(t); + if (ptt->sequenceNumber != 0xFFFFFFFF) { + t->blockBad = 0; + t->chunkUsed = 1; + t->objectId = ptt->objectId; + t->chunkId = ptt->chunkId; + t->byteCount = ptt->byteCount; + t->chunkDeleted = 0; + t->serialNumber = 0; + t->sequenceNumber = ptt->sequenceNumber; + + /* Do extra header info stuff */ + + if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) { + t->chunkId = 0; + t->byteCount = 0; + + t->extraHeaderInfoAvailable = 1; + t->extraParentObjectId = + ptt->chunkId & (~(ALL_EXTRA_FLAGS)); + t->extraIsShrinkHeader = + (ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0; + t->extraShadows = + (ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0; + t->extraObjectType = + ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT; + t->objectId &= ~EXTRA_OBJECT_TYPE_MASK; + + if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { + t->extraEquivalentObjectId = ptt->byteCount; + } else { + t->extraFileLength = ptt->byteCount; + } + } + } + + yaffs_DumpPackedTags2TagsPart(ptt); + yaffs_DumpTags2(t); + +} + + +void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt) +{ + + yaffs_UnpackTags2TagsPart(t,&pt->t); + if (pt->t.sequenceNumber != 0xFFFFFFFF) { /* Page is in use */ #ifdef YAFFS_IGNORE_TAGS_ECC @@ -130,10 +188,10 @@ (yaffs_PackedTags2TagsPart), &pt->ecc, &ecc); switch(result){ - case 0: - t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; + case 0: + t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; break; - case 1: + case 1: t->eccResult = YAFFS_ECC_RESULT_FIXED; break; case -1: @@ -144,41 +202,10 @@ } } #endif - t->blockBad = 0; - t->chunkUsed = 1; - t->objectId = pt->t.objectId; - t->chunkId = pt->t.chunkId; - t->byteCount = pt->t.byteCount; - t->chunkDeleted = 0; - t->serialNumber = 0; - t->sequenceNumber = pt->t.sequenceNumber; - - /* Do extra header info stuff */ - - if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) { - t->chunkId = 0; - t->byteCount = 0; - - t->extraHeaderInfoAvailable = 1; - t->extraParentObjectId = - pt->t.chunkId & (~(ALL_EXTRA_FLAGS)); - t->extraIsShrinkHeader = - (pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0; - t->extraShadows = - (pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0; - t->extraObjectType = - pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT; - t->objectId &= ~EXTRA_OBJECT_TYPE_MASK; - - if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { - t->extraEquivalentObjectId = pt->t.byteCount; - } else { - t->extraFileLength = pt->t.byteCount; - } - } } yaffs_DumpPackedTags2(pt); yaffs_DumpTags2(t); } + diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_packedtags2.h fs/yaffs2/yaffs_packedtags2.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_packedtags2.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_packedtags2.h 2009-08-05 14:02:57.915340000 -0400 @@ -1,3 +1,18 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + /* This is used to pack YAFFS2 tags, not YAFFS1tags. */ #ifndef __YAFFS_PACKEDTAGS2_H__ @@ -18,6 +33,11 @@ yaffs_ECCOther ecc; } yaffs_PackedTags2; +/* Full packed tags with ECC, used for oob tags */ void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t); void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt); + +/* Only the tags part (no ECC for use with inband tags */ +void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart * pt, const yaffs_ExtendedTags * t); +void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags * t, yaffs_PackedTags2TagsPart * pt); #endif diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_qsort.c fs/yaffs2/yaffs_qsort.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_qsort.c 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_qsort.c 2009-08-05 14:02:59.716163000 -0400 @@ -50,7 +50,7 @@ static __inline void swapfunc(char *a, char *b, int n, int swaptype) { - if (swaptype <= 1) + if (swaptype <= 1) swapcode(long, a, b, n) else swapcode(char, a, b, n) @@ -74,9 +74,13 @@ :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); } +#ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + void -qsort(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *)) +yaffs_qsort(void *aa, size_t n, size_t es, + int (*cmp)(const void *, const void *)) { char *pa, *pb, *pc, *pd, *pl, *pm, *pn; int d, r, swaptype, swap_cnt; @@ -133,7 +137,7 @@ } if (swap_cnt == 0) { /* Switch to insertion sort */ for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) - for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; pl -= es) swap(pl, pl - es); return; @@ -145,12 +149,12 @@ r = min((long)(pd - pc), (long)(pn - pd - es)); vecswap(pb, pn - r, r); if ((r = pb - pa) > es) - qsort(a, r / es, es, cmp); - if ((r = pd - pc) > es) { + yaffs_qsort(a, r / es, es, cmp); + if ((r = pd - pc) > es) { /* Iterate rather than recurse to save stack space */ a = pn - r; n = r / es; goto loop; } -/* qsort(pn - r, r / es, es, cmp);*/ +/* yaffs_qsort(pn - r, r / es, es, cmp);*/ } diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_qsort.h fs/yaffs2/yaffs_qsort.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_qsort.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_qsort.h 2009-08-05 14:03:01.370994000 -0400 @@ -1,8 +1,7 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffs_qsort.h: Interface to BSD-licensed qsort routine. + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -11,13 +10,14 @@ * it under the terms of the GNU Lesser General Public License version 2.1 as * published by the Free Software Foundation. * - * $Id: yaffs_qsort.h,v 1.2 2006/11/07 23:20:09 charles Exp $ + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. */ + #ifndef __YAFFS_QSORT_H__ #define __YAFFS_QSORT_H__ -extern void qsort (void *const base, size_t total_elems, size_t size, +extern void yaffs_qsort (void *const base, size_t total_elems, size_t size, int (*cmp)(const void *, const void *)); #endif diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_tagscompat.c fs/yaffs2/yaffs_tagscompat.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_tagscompat.c 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_tagscompat.c 2009-08-05 14:03:02.794877000 -0400 @@ -1,21 +1,20 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffs_tagscompat.h: Tags compatability layer to use YAFFS1 formatted NAND. + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - * - * $Id: yaffs_tagscompat.c,v 1.8 2005/11/29 20:54:32 marty Exp $ */ #include "yaffs_guts.h" #include "yaffs_tagscompat.h" #include "yaffs_ecc.h" +#include "yaffs_getblockinfo.h" static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND); #ifdef NOTYET @@ -47,7 +46,7 @@ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 }; -static int yaffs_CountBits(__u8 x) +int yaffs_CountBits(__u8 x) { int retVal; retVal = yaffs_countBitsTable[x]; @@ -254,6 +253,9 @@ /* Must allocate enough memory for spare+2*sizeof(int) */ /* for ecc results from device. */ struct yaffs_NANDSpare nspare; + + memset(&nspare,0,sizeof(nspare)); + retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) & nspare); @@ -338,7 +340,7 @@ int blockInNAND = chunkInNAND / dev->nChunksPerBlock; /* Mark the block for retirement */ - yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; + yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1; T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND)); @@ -440,7 +442,7 @@ yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN; static yaffs_Spare spareFF; - static int init; + static int init = 0; if (!init) { memset(&spareFF, 0xFF, sizeof(spareFF)); @@ -499,9 +501,9 @@ } int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, - int blockNo, yaffs_BlockState * - state, - int *sequenceNumber) + int blockNo, + yaffs_BlockState *state, + __u32 *sequenceNumber) { yaffs_Spare spare0, spare1; diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_tagscompat.h fs/yaffs2/yaffs_tagscompat.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_tagscompat.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_tagscompat.h 2009-08-05 14:03:04.965701000 -0400 @@ -1,22 +1,18 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffs_ramdisk.h: yaffs ram disk component + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as + * it under the terms of the GNU Lesser General Public License version 2.1 as * published by the Free Software Foundation. * - * $Id: yaffs_tagscompat.h,v 1.2 2005/08/11 02:33:03 marty Exp $ + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. */ -/* This provides a ram disk under yaffs. - * NB this is not intended for NAND emulation. - * Use this with dev->useNANDECC enabled, then ECC overheads are not required. - */ #ifndef __YAFFS_TAGSCOMPAT_H__ #define __YAFFS_TAGSCOMPAT_H__ @@ -34,7 +30,12 @@ int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, - int blockNo, yaffs_BlockState * - state, int *sequenceNumber); + int blockNo, + yaffs_BlockState *state, + __u32 *sequenceNumber); + +void yaffs_CalcTagsECC(yaffs_Tags * tags); +int yaffs_CheckECCOnTags(yaffs_Tags * tags); +int yaffs_CountBits(__u8 byte); #endif diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_tagsvalidity.c fs/yaffs2/yaffs_tagsvalidity.c --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_tagsvalidity.c 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_tagsvalidity.c 2009-08-05 14:03:07.137504000 -0400 @@ -1,8 +1,7 @@ - /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -10,8 +9,6 @@ * 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. - * - * $Id: yaffs_tagsvalidity.c,v 1.2 2005/08/11 02:33:03 marty Exp $ */ #include "yaffs_tagsvalidity.h" diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_tagsvalidity.h fs/yaffs2/yaffs_tagsvalidity.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffs_tagsvalidity.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffs_tagsvalidity.h 2009-08-05 14:03:08.812328000 -0400 @@ -1,19 +1,18 @@ - /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as + * it under the terms of the GNU Lesser General Public License version 2.1 as * published by the Free Software Foundation. * - * $Id: yaffs_tagsvalidity.h,v 1.2 2005/08/11 02:33:03 marty Exp $ + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. */ -//yaffs_tagsvalidity.h + #ifndef __YAFFS_TAGS_VALIDITY_H__ #define __YAFFS_TAGS_VALIDITY_H__ diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffsinterface.h fs/yaffs2/yaffsinterface.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yaffsinterface.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yaffsinterface.h 2009-08-05 14:02:38.206203000 -0400 @@ -1,8 +1,7 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffsinterface.h: Interface to the guts of yaffs. + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -12,7 +11,6 @@ * published by the Free Software Foundation. * * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. - * */ #ifndef __YAFFSINTERFACE_H__ diff -urN /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yportenv.h fs/yaffs2/yportenv.h --- /opt/mv_pro_5.0.0/montavista/pro/devkit/lsp/ti-davinci/linux-2.6.18_pro500/fs/yaffs2/yportenv.h 2009-05-22 11:19:26.000000000 -0400 +++ fs/yaffs2/yportenv.h 2009-08-05 14:03:10.516134000 -0400 @@ -1,9 +1,7 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yportenv.h: Portable services used by yaffs. This is done to allow - * simple migration from kernel space into app space for testing. + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -12,16 +10,21 @@ * 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. - * - * $Id: yportenv.h,v 1.11 2006/05/21 09:39:12 charles Exp $ - * */ + #ifndef __YPORTENV_H__ #define __YPORTENV_H__ +/* + * Define the MTD version in terms of Linux Kernel versions + * This allows yaffs to be used independantly of the kernel + * as well as with it. + */ + +#define MTD_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) + #if defined CONFIG_YAFFS_WINCE #include "ywinceenv.h" @@ -31,10 +34,16 @@ #include "moduleconfig.h" /* Linux kernel */ + +#include +#define MTD_VERSION_CODE LINUX_VERSION_CODE + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) #include +#endif #include -#include #include +#include #include #include #include @@ -44,6 +53,7 @@ #define _Y(x) x #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_sprintf sprintf #define yaffs_toupper(a) toupper(a) @@ -54,7 +64,7 @@ #define YAFFS_LOSTNFOUND_PREFIX "obj" /* #define YPRINTF(x) printk x */ -#define YMALLOC(x) kmalloc(x,GFP_KERNEL) +#define YMALLOC(x) kmalloc(x,GFP_NOFS) #define YFREE(x) kfree(x) #define YMALLOC_ALT(x) vmalloc(x) #define YFREE_ALT(x) vfree(x) @@ -63,7 +73,7 @@ // KR - added for use in scan so processes aren't blocked indefinitely. #define YYIELD() schedule() -#define YAFFS_ROOT_MODE 0666 +#define YAFFS_ROOT_MODE 0666 #define YAFFS_LOSTNFOUND_MODE 0666 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) @@ -81,8 +91,18 @@ #define TSTR(x) KERN_WARNING 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; }) + #elif defined CONFIG_YAFFS_DIRECT +#define MTD_VERSION_CODE MTD_VERSION(2,6,22) + /* Direct interface */ #include "ydirectenv.h" @@ -135,9 +155,15 @@ #endif -extern unsigned yaffs_traceMask; +/* see yaffs_fs.c */ +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_ERROR 0x00000001 #define YAFFS_TRACE_OS 0x00000002 #define YAFFS_TRACE_ALLOCATE 0x00000004 #define YAFFS_TRACE_SCAN 0x00000008 @@ -153,13 +179,22 @@ #define YAFFS_TRACE_SCAN_DEBUG 0x00002000 #define YAFFS_TRACE_MTD 0x00004000 #define YAFFS_TRACE_CHECKPOINT 0x00008000 -#define YAFFS_TRACE_ALWAYS 0x40000000 + +#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_ERROR 0x40000000 #define YAFFS_TRACE_BUG 0x80000000 +#define YAFFS_TRACE_ALWAYS 0xF0000000 + -#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ERROR)) TOUT(p);} while(0) +#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0) -#ifndef CONFIG_YAFFS_WINCE -#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__)) +#ifndef YBUG +#define YBUG() do {T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__));} while(0) #endif #endif