update yaffs to latest git (required for /system on nand)
This commit is contained in:
		| @@ -1631,11 +1631,14 @@ CONFIG_YAFFS_YAFFS1=y | ||||
| # CONFIG_YAFFS_DOES_ECC is not set | ||||
| CONFIG_YAFFS_YAFFS2=y | ||||
| CONFIG_YAFFS_AUTO_YAFFS2=y | ||||
| # CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set | ||||
| CONFIG_YAFFS_DISABLE_TAGS_ECC=y | ||||
| # CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set | ||||
| # CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set | ||||
| CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y | ||||
| # CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set | ||||
| CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING=y | ||||
| # CONFIG_YAFFS_DISABLE_BACKGROUND is not set | ||||
| CONFIG_YAFFS_XATTR=y | ||||
| # CONFIG_JFFS2_FS is not set | ||||
| # CONFIG_CRAMFS is not set | ||||
| CONFIG_SQUASHFS=y | ||||
|   | ||||
| @@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2 | ||||
|  | ||||
| 	  If unsure, say Y. | ||||
|  | ||||
| config YAFFS_DISABLE_LAZY_LOAD | ||||
| 	bool "Disable lazy loading" | ||||
| 	depends on YAFFS_YAFFS2 | ||||
| config YAFFS_DISABLE_TAGS_ECC | ||||
| 	bool "Disable YAFFS from doing ECC on tags by default" | ||||
| 	depends on YAFFS_FS && YAFFS_YAFFS2 | ||||
| 	default n | ||||
| 	help | ||||
| 	  "Lazy loading" defers loading file details until they are | ||||
| 	  required. This saves mount time, but makes the first look-up | ||||
| 	  a bit longer. | ||||
|  | ||||
| 	  Lazy loading will only happen if enabled by this option being 'n' | ||||
| 	  and if the appropriate tags are available, else yaffs2 will | ||||
| 	  automatically fall back to immediate loading and do the right | ||||
| 	  thing. | ||||
|  | ||||
| 	  Lazy laoding will be required by checkpointing. | ||||
|  | ||||
| 	  Setting this to 'y' will disable lazy loading. | ||||
| 	  This defaults Yaffs to using its own ECC calculations on tags instead of | ||||
| 	  just relying on the MTD. | ||||
| 	  This behavior can also be overridden with tags_ecc_on and | ||||
| 	  tags_ecc_off mount options. | ||||
|  | ||||
| 	  If unsure, say N. | ||||
|  | ||||
| @@ -156,9 +148,43 @@ config YAFFS_SHORT_NAMES_IN_RAM | ||||
| 	  If unsure, say Y. | ||||
|  | ||||
| config YAFFS_EMPTY_LOST_AND_FOUND | ||||
| 	bool "Empty lost and found on mount" | ||||
| 	bool "Empty lost and found on boot" | ||||
| 	depends on YAFFS_FS | ||||
| 	default n | ||||
| 	help | ||||
| 	  If this is enabled then the contents of lost and found is | ||||
| 	  automatically dumped at mount. | ||||
|  | ||||
| 	  If unsure, say N. | ||||
|  | ||||
| config YAFFS_DISABLE_BLOCK_REFRESHING | ||||
| 	bool "Disable yaffs2 block refreshing" | ||||
| 	depends on YAFFS_FS | ||||
| 	default n | ||||
| 	help | ||||
| 	 If this is set, then block refreshing is disabled. | ||||
| 	 Block refreshing infrequently refreshes the oldest block in | ||||
| 	 a yaffs2 file system. This mechanism helps to refresh flash to | ||||
| 	 mitigate against data loss. This is particularly useful for MLC. | ||||
|  | ||||
| 	  If unsure, say N. | ||||
|  | ||||
| config YAFFS_DISABLE_BACKGROUND | ||||
| 	bool "Disable yaffs2 background processing" | ||||
| 	depends on YAFFS_FS | ||||
| 	default n | ||||
| 	help | ||||
| 	 If this is set, then background processing is disabled. | ||||
| 	 Background processing makes many foreground activities faster. | ||||
|  | ||||
| 	  If unsure, say N. | ||||
|  | ||||
| config YAFFS_XATTR | ||||
| 	bool "Enable yaffs2 xattr support" | ||||
| 	depends on YAFFS_FS | ||||
| 	default y | ||||
| 	help | ||||
| 	 If this is set then yaffs2 will provide xattr support. | ||||
| 	 If unsure, say Y. | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -4,7 +4,14 @@ | ||||
|  | ||||
| obj-$(CONFIG_YAFFS_FS) += yaffs.o | ||||
|  | ||||
| yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o | ||||
| yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o | ||||
| yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o | ||||
| yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o | ||||
| yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o | ||||
| yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o | ||||
| yaffs-y += yaffs_nameval.o | ||||
| yaffs-y += yaffs_allocator.o | ||||
| yaffs-y += yaffs_yaffs1.o | ||||
| yaffs-y += yaffs_yaffs2.o | ||||
| yaffs-y += yaffs_bitmap.o | ||||
| yaffs-y += yaffs_verify.o | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -24,6 +24,8 @@ | ||||
| #define __EXTRAS_H__ | ||||
|  | ||||
|  | ||||
| #include "yportenv.h" | ||||
|  | ||||
| #if !(defined __KERNEL__) | ||||
|  | ||||
| /* Definition of types */ | ||||
| @@ -33,103 +35,6 @@ typedef unsigned __u32; | ||||
|  | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * This is a simple doubly linked list implementation that matches the | ||||
|  * way the Linux kernel doubly linked list implementation works. | ||||
|  */ | ||||
|  | ||||
| struct ylist_head { | ||||
| 	struct ylist_head *next; /* next in chain */ | ||||
| 	struct ylist_head *prev; /* previous in chain */ | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* Initialise a static list */ | ||||
| #define YLIST_HEAD(name) \ | ||||
| struct ylist_head name = { &(name), &(name)} | ||||
|  | ||||
|  | ||||
|  | ||||
| /* Initialise a list head to an empty list */ | ||||
| #define YINIT_LIST_HEAD(p) \ | ||||
| do { \ | ||||
| 	(p)->next = (p);\ | ||||
| 	(p)->prev = (p); \ | ||||
| } while (0) | ||||
|  | ||||
|  | ||||
| /* Add an element to a list */ | ||||
| static __inline__ void ylist_add(struct ylist_head *newEntry, | ||||
| 				struct ylist_head *list) | ||||
| { | ||||
| 	struct ylist_head *listNext = list->next; | ||||
|  | ||||
| 	list->next = newEntry; | ||||
| 	newEntry->prev = list; | ||||
| 	newEntry->next = listNext; | ||||
| 	listNext->prev = newEntry; | ||||
|  | ||||
| } | ||||
|  | ||||
| static __inline__ void ylist_add_tail(struct ylist_head *newEntry, | ||||
| 				 struct ylist_head *list) | ||||
| { | ||||
| 	struct ylist_head *listPrev = list->prev; | ||||
|  | ||||
| 	list->prev = newEntry; | ||||
| 	newEntry->next = list; | ||||
| 	newEntry->prev = listPrev; | ||||
| 	listPrev->next = newEntry; | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Take an element out of its current list, with or without | ||||
|  * reinitialising the links.of the entry*/ | ||||
| static __inline__ void ylist_del(struct ylist_head *entry) | ||||
| { | ||||
| 	struct ylist_head *listNext = entry->next; | ||||
| 	struct ylist_head *listPrev = entry->prev; | ||||
|  | ||||
| 	listNext->prev = listPrev; | ||||
| 	listPrev->next = listNext; | ||||
|  | ||||
| } | ||||
|  | ||||
| static __inline__ void ylist_del_init(struct ylist_head *entry) | ||||
| { | ||||
| 	ylist_del(entry); | ||||
| 	entry->next = entry->prev = entry; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Test if the list is empty */ | ||||
| static __inline__ int ylist_empty(struct ylist_head *entry) | ||||
| { | ||||
| 	return (entry->next == entry); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* ylist_entry takes a pointer to a list entry and offsets it to that | ||||
|  * we can find a pointer to the object it is embedded in. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #define ylist_entry(entry, type, member) \ | ||||
| 	((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member))) | ||||
|  | ||||
|  | ||||
| /* ylist_for_each and list_for_each_safe  iterate over lists. | ||||
|  * ylist_for_each_safe uses temporary storage to make the list delete safe | ||||
|  */ | ||||
|  | ||||
| #define ylist_for_each(itervar, list) \ | ||||
| 	for (itervar = (list)->next; itervar != (list); itervar = itervar->next) | ||||
|  | ||||
| #define ylist_for_each_safe(itervar, saveVar, list) \ | ||||
| 	for (itervar = (list)->next, saveVar = (list)->next->next; \ | ||||
| 		itervar != (list); itervar = saveVar, saveVar = saveVar->next) | ||||
|  | ||||
|  | ||||
| #if !(defined __KERNEL__) | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Martin Fouts <Martin.Fouts@palmsource.com> | ||||
| @@ -29,22 +29,43 @@ | ||||
| /* Meaning: Yaffs does its own ECC, rather than using MTD ECC */ | ||||
| /* #define CONFIG_YAFFS_DOES_ECC */ | ||||
|  | ||||
| /* Default: Selected */ | ||||
| /* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */ | ||||
| #define CONFIG_YAFFS_DOES_TAGS_ECC | ||||
|  | ||||
| /* Default: Not selected */ | ||||
| /* Meaning: ECC byte order is 'wrong'.  Only meaningful if */ | ||||
| /*          CONFIG_YAFFS_DOES_ECC is set */ | ||||
| /* #define CONFIG_YAFFS_ECC_WRONG_ORDER */ | ||||
|  | ||||
| /* Default: Selected */ | ||||
| /* Meaning: Disables testing whether chunks are erased before writing to them*/ | ||||
| #define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK | ||||
| /* Default: Not selected */ | ||||
| /* Meaning: Always test whether chunks are erased before writing to them. | ||||
| 	    Use during mtd debugging and init. */ | ||||
| /* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */ | ||||
|  | ||||
| /* Default: Not Selected */ | ||||
| /* Meaning: At mount automatically empty all files from lost and found. */ | ||||
| /* This is done to fix an old problem where rmdir was not checking for an */ | ||||
| /* empty directory. This can also be achieved with a mount option. */ | ||||
| #define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND | ||||
|  | ||||
| /* Default: Selected */ | ||||
| /* Meaning: Cache short names, taking more RAM, but faster look-ups */ | ||||
| #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM | ||||
|  | ||||
| /* Default: 10 */ | ||||
| /* Meaning: set the count of blocks to reserve for checkpointing */ | ||||
| #define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 | ||||
| /* Default: Unselected */ | ||||
| /* Meaning: Select to disable block refreshing. */ | ||||
| /* Block Refreshing periodically rewrites the oldest block. */ | ||||
| /* #define CONFIG_DISABLE_BLOCK_REFRESHING */ | ||||
|  | ||||
| /* Default: Unselected */ | ||||
| /* Meaning: Select to disable background processing */ | ||||
| /* #define CONFIG_DISABLE_BACKGROUND */ | ||||
|  | ||||
|  | ||||
| /* Default: Selected */ | ||||
| /* Meaning: Enable XATTR support */ | ||||
| #define CONFIG_YAFFS_XATTR | ||||
|  | ||||
| /* | ||||
| Older-style on-NAND data format has a "pageStatus" byte to record | ||||
|   | ||||
							
								
								
									
										409
									
								
								fs/yaffs2/yaffs_allocator.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										409
									
								
								fs/yaffs2/yaffs_allocator.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,409 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Lesser General Public License version 2.1 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #include "yaffs_allocator.h" | ||||
| #include "yaffs_guts.h" | ||||
| #include "yaffs_trace.h" | ||||
| #include "yportenv.h" | ||||
|  | ||||
| #ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR | ||||
|  | ||||
| void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev) | ||||
| { | ||||
| 	dev = dev; | ||||
| } | ||||
|  | ||||
| void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev) | ||||
| { | ||||
| 	dev = dev; | ||||
| } | ||||
|  | ||||
| yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev) | ||||
| { | ||||
| 	return (yaffs_Tnode *)YMALLOC(dev->tnodeSize); | ||||
| } | ||||
|  | ||||
| void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn) | ||||
| { | ||||
| 	dev = dev; | ||||
| 	YFREE(tn); | ||||
| } | ||||
|  | ||||
| void yaffs_InitialiseRawObjects(yaffs_Device *dev) | ||||
| { | ||||
| 	dev = dev; | ||||
| } | ||||
|  | ||||
| void yaffs_DeinitialiseRawObjects(yaffs_Device *dev) | ||||
| { | ||||
| 	dev = dev; | ||||
| } | ||||
|  | ||||
| yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev) | ||||
| { | ||||
| 	dev = dev; | ||||
| 	return (yaffs_Object *) YMALLOC(sizeof(yaffs_Object)); | ||||
| } | ||||
|  | ||||
|  | ||||
| void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj) | ||||
| { | ||||
|  | ||||
| 	dev = dev; | ||||
| 	YFREE(obj); | ||||
| } | ||||
|  | ||||
| #else | ||||
|  | ||||
| struct yaffs_TnodeList_struct { | ||||
| 	struct yaffs_TnodeList_struct *next; | ||||
| 	yaffs_Tnode *tnodes; | ||||
| }; | ||||
|  | ||||
| typedef struct yaffs_TnodeList_struct yaffs_TnodeList; | ||||
|  | ||||
| struct yaffs_ObjectList_struct { | ||||
| 	yaffs_Object *objects; | ||||
| 	struct yaffs_ObjectList_struct *next; | ||||
| }; | ||||
|  | ||||
| typedef struct yaffs_ObjectList_struct yaffs_ObjectList; | ||||
|  | ||||
|  | ||||
| struct yaffs_AllocatorStruct { | ||||
| 	int nTnodesCreated; | ||||
| 	yaffs_Tnode *freeTnodes; | ||||
| 	int nFreeTnodes; | ||||
| 	yaffs_TnodeList *allocatedTnodeList; | ||||
|  | ||||
| 	int nObjectsCreated; | ||||
| 	yaffs_Object *freeObjects; | ||||
| 	int nFreeObjects; | ||||
|  | ||||
| 	yaffs_ObjectList *allocatedObjectList; | ||||
| }; | ||||
|  | ||||
| typedef struct yaffs_AllocatorStruct yaffs_Allocator; | ||||
|  | ||||
|  | ||||
| static void yaffs_DeinitialiseRawTnodes(yaffs_Device *dev) | ||||
| { | ||||
|  | ||||
| 	yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; | ||||
|  | ||||
| 	yaffs_TnodeList *tmp; | ||||
|  | ||||
| 	if(!allocator){ | ||||
| 		YBUG(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	while (allocator->allocatedTnodeList) { | ||||
| 		tmp = allocator->allocatedTnodeList->next; | ||||
|  | ||||
| 		YFREE(allocator->allocatedTnodeList->tnodes); | ||||
| 		YFREE(allocator->allocatedTnodeList); | ||||
| 		allocator->allocatedTnodeList = tmp; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	allocator->freeTnodes = NULL; | ||||
| 	allocator->nFreeTnodes = 0; | ||||
| 	allocator->nTnodesCreated = 0; | ||||
| } | ||||
|  | ||||
| static void yaffs_InitialiseRawTnodes(yaffs_Device *dev) | ||||
| { | ||||
| 	yaffs_Allocator *allocator = dev->allocator; | ||||
|  | ||||
| 	if(allocator){ | ||||
| 		allocator->allocatedTnodeList = NULL; | ||||
| 		allocator->freeTnodes = NULL; | ||||
| 		allocator->nFreeTnodes = 0; | ||||
| 		allocator->nTnodesCreated = 0; | ||||
| 	} else | ||||
| 		YBUG(); | ||||
| } | ||||
|  | ||||
| static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes) | ||||
| { | ||||
| 	yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; | ||||
| 	int i; | ||||
| 	yaffs_Tnode *newTnodes; | ||||
| 	__u8 *mem; | ||||
| 	yaffs_Tnode *curr; | ||||
| 	yaffs_Tnode *next; | ||||
| 	yaffs_TnodeList *tnl; | ||||
|  | ||||
| 	if(!allocator){ | ||||
| 		YBUG(); | ||||
| 		return YAFFS_FAIL; | ||||
| 	} | ||||
|  | ||||
| 	if (nTnodes < 1) | ||||
| 		return YAFFS_OK; | ||||
|  | ||||
|  | ||||
| 	/* make these things */ | ||||
|  | ||||
| 	newTnodes = YMALLOC(nTnodes * dev->tnodeSize); | ||||
| 	mem = (__u8 *)newTnodes; | ||||
|  | ||||
| 	if (!newTnodes) { | ||||
| 		T(YAFFS_TRACE_ERROR, | ||||
| 			(TSTR("yaffs: Could not allocate Tnodes" TENDSTR))); | ||||
| 		return YAFFS_FAIL; | ||||
| 	} | ||||
|  | ||||
| 	/* New hookup for wide tnodes */ | ||||
| 	for (i = 0; i < nTnodes - 1; i++) { | ||||
| 		curr = (yaffs_Tnode *) &mem[i * dev->tnodeSize]; | ||||
| 		next = (yaffs_Tnode *) &mem[(i+1) * dev->tnodeSize]; | ||||
| 		curr->internal[0] = next; | ||||
| 	} | ||||
|  | ||||
| 	curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * dev->tnodeSize]; | ||||
| 	curr->internal[0] = allocator->freeTnodes; | ||||
| 	allocator->freeTnodes = (yaffs_Tnode *)mem; | ||||
|  | ||||
| 	allocator->nFreeTnodes += nTnodes; | ||||
| 	allocator->nTnodesCreated += nTnodes; | ||||
|  | ||||
| 	/* Now add this bunch of tnodes to a list for freeing up. | ||||
| 	 * NB If we can't add this to the management list it isn't fatal | ||||
| 	 * but it just means we can't free this bunch of tnodes later. | ||||
| 	 */ | ||||
|  | ||||
| 	tnl = YMALLOC(sizeof(yaffs_TnodeList)); | ||||
| 	if (!tnl) { | ||||
| 		T(YAFFS_TRACE_ERROR, | ||||
| 		  (TSTR | ||||
| 		   ("yaffs: Could not add tnodes to management list" TENDSTR))); | ||||
| 		   return YAFFS_FAIL; | ||||
| 	} else { | ||||
| 		tnl->tnodes = newTnodes; | ||||
| 		tnl->next = allocator->allocatedTnodeList; | ||||
| 		allocator->allocatedTnodeList = tnl; | ||||
| 	} | ||||
|  | ||||
| 	T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR))); | ||||
|  | ||||
| 	return YAFFS_OK; | ||||
| } | ||||
|  | ||||
|  | ||||
| yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev) | ||||
| { | ||||
| 	yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; | ||||
| 	yaffs_Tnode *tn = NULL; | ||||
|  | ||||
| 	if(!allocator){ | ||||
| 		YBUG(); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* If there are none left make more */ | ||||
| 	if (!allocator->freeTnodes) | ||||
| 		yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES); | ||||
|  | ||||
| 	if (allocator->freeTnodes) { | ||||
| 		tn = allocator->freeTnodes; | ||||
| 		allocator->freeTnodes = allocator->freeTnodes->internal[0]; | ||||
| 		allocator->nFreeTnodes--; | ||||
| 	} | ||||
|  | ||||
| 	return tn; | ||||
| } | ||||
|  | ||||
| /* FreeTnode frees up a tnode and puts it back on the free list */ | ||||
| void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn) | ||||
| { | ||||
| 	yaffs_Allocator *allocator = dev->allocator; | ||||
|  | ||||
| 	if(!allocator){ | ||||
| 		YBUG(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (tn) { | ||||
| 		tn->internal[0] = allocator->freeTnodes; | ||||
| 		allocator->freeTnodes = tn; | ||||
| 		allocator->nFreeTnodes++; | ||||
| 	} | ||||
| 	dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| static void yaffs_InitialiseRawObjects(yaffs_Device *dev) | ||||
| { | ||||
| 	yaffs_Allocator *allocator = dev->allocator; | ||||
|  | ||||
| 	if(allocator) { | ||||
| 		allocator->allocatedObjectList = NULL; | ||||
| 		allocator->freeObjects = NULL; | ||||
| 		allocator->nFreeObjects = 0; | ||||
| 	} else | ||||
| 		YBUG(); | ||||
| } | ||||
|  | ||||
| static void yaffs_DeinitialiseRawObjects(yaffs_Device *dev) | ||||
| { | ||||
| 	yaffs_Allocator *allocator = dev->allocator; | ||||
| 	yaffs_ObjectList *tmp; | ||||
|  | ||||
| 	if(!allocator){ | ||||
| 		YBUG(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	while (allocator->allocatedObjectList) { | ||||
| 		tmp = allocator->allocatedObjectList->next; | ||||
| 		YFREE(allocator->allocatedObjectList->objects); | ||||
| 		YFREE(allocator->allocatedObjectList); | ||||
|  | ||||
| 		allocator->allocatedObjectList = tmp; | ||||
| 	} | ||||
|  | ||||
| 	allocator->freeObjects = NULL; | ||||
| 	allocator->nFreeObjects = 0; | ||||
| 	allocator->nObjectsCreated = 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects) | ||||
| { | ||||
| 	yaffs_Allocator *allocator = dev->allocator; | ||||
|  | ||||
| 	int i; | ||||
| 	yaffs_Object *newObjects; | ||||
| 	yaffs_ObjectList *list; | ||||
|  | ||||
| 	if(!allocator){ | ||||
| 		YBUG(); | ||||
| 		return YAFFS_FAIL; | ||||
| 	} | ||||
|  | ||||
| 	if (nObjects < 1) | ||||
| 		return YAFFS_OK; | ||||
|  | ||||
| 	/* make these things */ | ||||
| 	newObjects = YMALLOC(nObjects * sizeof(yaffs_Object)); | ||||
| 	list = YMALLOC(sizeof(yaffs_ObjectList)); | ||||
|  | ||||
| 	if (!newObjects || !list) { | ||||
| 		if (newObjects){ | ||||
| 			YFREE(newObjects); | ||||
| 			newObjects = NULL; | ||||
| 		} | ||||
| 		if (list){ | ||||
| 			YFREE(list); | ||||
| 			list = NULL; | ||||
| 		} | ||||
| 		T(YAFFS_TRACE_ALLOCATE, | ||||
| 		  (TSTR("yaffs: Could not allocate more objects" TENDSTR))); | ||||
| 		return YAFFS_FAIL; | ||||
| 	} | ||||
|  | ||||
| 	/* Hook them into the free list */ | ||||
| 	for (i = 0; i < nObjects - 1; i++) { | ||||
| 		newObjects[i].siblings.next = | ||||
| 				(struct ylist_head *)(&newObjects[i + 1]); | ||||
| 	} | ||||
|  | ||||
| 	newObjects[nObjects - 1].siblings.next = (void *)allocator->freeObjects; | ||||
| 	allocator->freeObjects = newObjects; | ||||
| 	allocator->nFreeObjects += nObjects; | ||||
| 	allocator->nObjectsCreated += nObjects; | ||||
|  | ||||
| 	/* Now add this bunch of Objects to a list for freeing up. */ | ||||
|  | ||||
| 	list->objects = newObjects; | ||||
| 	list->next = allocator->allocatedObjectList; | ||||
| 	allocator->allocatedObjectList = list; | ||||
|  | ||||
| 	return YAFFS_OK; | ||||
| } | ||||
|  | ||||
| yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev) | ||||
| { | ||||
| 	yaffs_Object *obj = NULL; | ||||
| 	yaffs_Allocator *allocator = dev->allocator; | ||||
|  | ||||
| 	if(!allocator) { | ||||
| 		YBUG(); | ||||
| 		return obj; | ||||
| 	} | ||||
|  | ||||
| 	/* If there are none left make more */ | ||||
| 	if (!allocator->freeObjects) | ||||
| 		yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS); | ||||
|  | ||||
| 	if (allocator->freeObjects) { | ||||
| 		obj = allocator->freeObjects; | ||||
| 		allocator->freeObjects = | ||||
| 			(yaffs_Object *) (allocator->freeObjects->siblings.next); | ||||
| 		allocator->nFreeObjects--; | ||||
| 	} | ||||
|  | ||||
| 	return obj; | ||||
| } | ||||
|  | ||||
|  | ||||
| void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj) | ||||
| { | ||||
|  | ||||
| 	yaffs_Allocator *allocator = dev->allocator; | ||||
|  | ||||
| 	if(!allocator) | ||||
| 		YBUG(); | ||||
| 	else { | ||||
| 		/* Link into the free list. */ | ||||
| 		obj->siblings.next = (struct ylist_head *)(allocator->freeObjects); | ||||
| 		allocator->freeObjects = obj; | ||||
| 		allocator->nFreeObjects++; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev) | ||||
| { | ||||
| 	if(dev->allocator){ | ||||
| 		yaffs_DeinitialiseRawTnodes(dev); | ||||
| 		yaffs_DeinitialiseRawObjects(dev); | ||||
|  | ||||
| 		YFREE(dev->allocator); | ||||
| 		dev->allocator=NULL; | ||||
| 	} else | ||||
| 		YBUG(); | ||||
| } | ||||
|  | ||||
| void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev) | ||||
| { | ||||
| 	yaffs_Allocator *allocator; | ||||
|  | ||||
| 	if(!dev->allocator){ | ||||
| 		allocator = YMALLOC(sizeof(yaffs_Allocator)); | ||||
| 		if(allocator){ | ||||
| 			dev->allocator = allocator; | ||||
| 			yaffs_InitialiseRawTnodes(dev); | ||||
| 			yaffs_InitialiseRawObjects(dev); | ||||
| 		} | ||||
| 	} else | ||||
| 		YBUG(); | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										30
									
								
								fs/yaffs2/yaffs_allocator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								fs/yaffs2/yaffs_allocator.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Lesser General Public License version 2.1 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. | ||||
|  */ | ||||
|  | ||||
| #ifndef __YAFFS_ALLOCATOR_H__ | ||||
| #define __YAFFS_ALLOCATOR_H__ | ||||
|  | ||||
| #include "yaffs_guts.h" | ||||
|  | ||||
| void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev); | ||||
| void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev); | ||||
|  | ||||
| yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev); | ||||
| void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn); | ||||
|  | ||||
| yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev); | ||||
| void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										105
									
								
								fs/yaffs2/yaffs_bitmap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								fs/yaffs2/yaffs_bitmap.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
|  | ||||
| #include "yaffs_bitmap.h" | ||||
| #include "yaffs_trace.h" | ||||
| /* | ||||
|  * Chunk bitmap manipulations | ||||
|  */ | ||||
|  | ||||
| static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk) | ||||
| { | ||||
| 	if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { | ||||
| 		T(YAFFS_TRACE_ERROR, | ||||
| 			(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR), | ||||
| 			blk)); | ||||
| 		YBUG(); | ||||
| 	} | ||||
| 	return dev->chunkBits + | ||||
| 		(dev->chunkBitmapStride * (blk - dev->internalStartBlock)); | ||||
| } | ||||
|  | ||||
| void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk) | ||||
| { | ||||
| 	if (blk < dev->internalStartBlock || blk > dev->internalEndBlock || | ||||
| 			chunk < 0 || chunk >= dev->param.nChunksPerBlock) { | ||||
| 		T(YAFFS_TRACE_ERROR, | ||||
| 		(TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR), | ||||
| 			blk, chunk)); | ||||
| 		YBUG(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void yaffs_ClearChunkBits(yaffs_Device *dev, int blk) | ||||
| { | ||||
| 	__u8 *blkBits = yaffs_BlockBits(dev, blk); | ||||
|  | ||||
| 	memset(blkBits, 0, dev->chunkBitmapStride); | ||||
| } | ||||
|  | ||||
| void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk) | ||||
| { | ||||
| 	__u8 *blkBits = yaffs_BlockBits(dev, blk); | ||||
|  | ||||
| 	yaffs_VerifyChunkBitId(dev, blk, chunk); | ||||
|  | ||||
| 	blkBits[chunk / 8] &= ~(1 << (chunk & 7)); | ||||
| } | ||||
|  | ||||
| void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk) | ||||
| { | ||||
| 	__u8 *blkBits = yaffs_BlockBits(dev, blk); | ||||
|  | ||||
| 	yaffs_VerifyChunkBitId(dev, blk, chunk); | ||||
|  | ||||
| 	blkBits[chunk / 8] |= (1 << (chunk & 7)); | ||||
| } | ||||
|  | ||||
| int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk) | ||||
| { | ||||
| 	__u8 *blkBits = yaffs_BlockBits(dev, blk); | ||||
| 	yaffs_VerifyChunkBitId(dev, blk, chunk); | ||||
|  | ||||
| 	return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; | ||||
| } | ||||
|  | ||||
| int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk) | ||||
| { | ||||
| 	__u8 *blkBits = yaffs_BlockBits(dev, blk); | ||||
| 	int i; | ||||
| 	for (i = 0; i < dev->chunkBitmapStride; i++) { | ||||
| 		if (*blkBits) | ||||
| 			return 1; | ||||
| 		blkBits++; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int yaffs_CountChunkBits(yaffs_Device *dev, int blk) | ||||
| { | ||||
| 	__u8 *blkBits = yaffs_BlockBits(dev, blk); | ||||
| 	int i; | ||||
| 	int n = 0; | ||||
| 	for (i = 0; i < dev->chunkBitmapStride; i++) { | ||||
| 		__u8 x = *blkBits; | ||||
| 		while (x) { | ||||
| 			if (x & 1) | ||||
| 				n++; | ||||
| 			x >>= 1; | ||||
| 		} | ||||
|  | ||||
| 		blkBits++; | ||||
| 	} | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
							
								
								
									
										31
									
								
								fs/yaffs2/yaffs_bitmap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								fs/yaffs2/yaffs_bitmap.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Chunk bitmap manipulations | ||||
|  */ | ||||
|  | ||||
| #ifndef __YAFFS_BITMAP_H__ | ||||
| #define __YAFFS_BITMAP_H__ | ||||
|  | ||||
| #include "yaffs_guts.h" | ||||
|  | ||||
| void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk); | ||||
| void yaffs_ClearChunkBits(yaffs_Device *dev, int blk); | ||||
| void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk); | ||||
| void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk); | ||||
| int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk); | ||||
| int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk); | ||||
| int yaffs_CountChunkBits(yaffs_Device *dev, int blk); | ||||
|  | ||||
| #endif | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -11,16 +11,12 @@ | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
|  | ||||
| const char *yaffs_checkptrw_c_version = | ||||
| 	"$Id$"; | ||||
|  | ||||
|  | ||||
| #include "yaffs_checkptrw.h" | ||||
| #include "yaffs_getblockinfo.h" | ||||
|  | ||||
| static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) | ||||
| static int yaffs2_CheckpointSpaceOk(yaffs_Device *dev) | ||||
| { | ||||
| 	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; | ||||
| 	int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks; | ||||
|  | ||||
| 	T(YAFFS_TRACE_CHECKPOINT, | ||||
| 		(TSTR("checkpt blocks available = %d" TENDSTR), | ||||
| @@ -30,11 +26,11 @@ static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) | ||||
| } | ||||
|  | ||||
|  | ||||
| static int yaffs_CheckpointErase(yaffs_Device *dev) | ||||
| static int yaffs2_CheckpointErase(yaffs_Device *dev) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	if (!dev->eraseBlockInNAND) | ||||
| 	if (!dev->param.eraseBlockInNAND) | ||||
| 		return 0; | ||||
| 	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR), | ||||
| 		dev->internalStartBlock, dev->internalEndBlock)); | ||||
| @@ -46,12 +42,12 @@ static int yaffs_CheckpointErase(yaffs_Device *dev) | ||||
|  | ||||
| 			dev->nBlockErasures++; | ||||
|  | ||||
| 			if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) { | ||||
| 			if (dev->param.eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) { | ||||
| 				bi->blockState = YAFFS_BLOCK_STATE_EMPTY; | ||||
| 				dev->nErasedBlocks++; | ||||
| 				dev->nFreeChunks += dev->nChunksPerBlock; | ||||
| 				dev->nFreeChunks += dev->param.nChunksPerBlock; | ||||
| 			} else { | ||||
| 				dev->markNANDBlockBad(dev, i); | ||||
| 				dev->param.markNANDBlockBad(dev, i); | ||||
| 				bi->blockState = YAFFS_BLOCK_STATE_DEAD; | ||||
| 			} | ||||
| 		} | ||||
| @@ -63,13 +59,13 @@ static int yaffs_CheckpointErase(yaffs_Device *dev) | ||||
| } | ||||
|  | ||||
|  | ||||
| static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev) | ||||
| static void yaffs2_CheckpointFindNextErasedBlock(yaffs_Device *dev) | ||||
| { | ||||
| 	int  i; | ||||
| 	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; | ||||
| 	int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks; | ||||
| 	T(YAFFS_TRACE_CHECKPOINT, | ||||
| 		(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), | ||||
| 		dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock)); | ||||
| 		dev->nErasedBlocks, dev->param.nReservedBlocks, blocksAvailable, dev->checkpointNextBlock)); | ||||
|  | ||||
| 	if (dev->checkpointNextBlock >= 0 && | ||||
| 			dev->checkpointNextBlock <= dev->internalEndBlock && | ||||
| @@ -91,7 +87,7 @@ static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev) | ||||
| 	dev->checkpointCurrentBlock = -1; | ||||
| } | ||||
|  | ||||
| static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) | ||||
| static void yaffs2_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) | ||||
| { | ||||
| 	int  i; | ||||
| 	yaffs_ExtendedTags tags; | ||||
| @@ -101,10 +97,10 @@ static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) | ||||
|  | ||||
| 	if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks) | ||||
| 		for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) { | ||||
| 			int chunk = i * dev->nChunksPerBlock; | ||||
| 			int chunk = i * dev->param.nChunksPerBlock; | ||||
| 			int realignedChunk = chunk - dev->chunkOffset; | ||||
|  | ||||
| 			dev->readChunkWithTagsFromNAND(dev, realignedChunk, | ||||
| 			dev->param.readChunkWithTagsFromNAND(dev, realignedChunk, | ||||
| 					NULL, &tags); | ||||
| 			T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR), | ||||
| 				i, tags.objectId, tags.sequenceNumber, tags.eccResult)); | ||||
| @@ -127,24 +123,24 @@ static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) | ||||
| } | ||||
|  | ||||
|  | ||||
| int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) | ||||
| int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting) | ||||
| { | ||||
|  | ||||
|  | ||||
| 	dev->checkpointOpenForWrite = forWriting; | ||||
|  | ||||
| 	/* Got the functions we need? */ | ||||
| 	if (!dev->writeChunkWithTagsToNAND || | ||||
| 			!dev->readChunkWithTagsFromNAND || | ||||
| 			!dev->eraseBlockInNAND || | ||||
| 			!dev->markNANDBlockBad) | ||||
| 	if (!dev->param.writeChunkWithTagsToNAND || | ||||
| 		!dev->param.readChunkWithTagsFromNAND || | ||||
| 		!dev->param.eraseBlockInNAND || | ||||
| 		!dev->param.markNANDBlockBad) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (forWriting && !yaffs_CheckpointSpaceOk(dev)) | ||||
| 	if (forWriting && !yaffs2_CheckpointSpaceOk(dev)) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!dev->checkpointBuffer) | ||||
| 		dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk); | ||||
| 		dev->checkpointBuffer = YMALLOC_DMA(dev->param.totalBytesPerChunk); | ||||
| 	if (!dev->checkpointBuffer) | ||||
| 		return 0; | ||||
|  | ||||
| @@ -161,7 +157,7 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) | ||||
| 	if (forWriting) { | ||||
| 		memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk); | ||||
| 		dev->checkpointByteOffset = 0; | ||||
| 		return yaffs_CheckpointErase(dev); | ||||
| 		return yaffs2_CheckpointErase(dev); | ||||
| 	} else { | ||||
| 		int i; | ||||
| 		/* Set to a value that will kick off a read */ | ||||
| @@ -181,7 +177,7 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) | ||||
| int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) | ||||
| { | ||||
| 	__u32 compositeSum; | ||||
| 	compositeSum =  (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF); | ||||
| @@ -189,7 +185,7 @@ int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) | ||||
| static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev) | ||||
| { | ||||
| 	int chunk; | ||||
| 	int realignedChunk; | ||||
| @@ -197,7 +193,7 @@ static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) | ||||
| 	yaffs_ExtendedTags tags; | ||||
|  | ||||
| 	if (dev->checkpointCurrentBlock < 0) { | ||||
| 		yaffs_CheckpointFindNextErasedBlock(dev); | ||||
| 		yaffs2_CheckpointFindNextErasedBlock(dev); | ||||
| 		dev->checkpointCurrentChunk = 0; | ||||
| 	} | ||||
|  | ||||
| @@ -217,7 +213,7 @@ static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) | ||||
| 		dev->blocksInCheckpoint++; | ||||
| 	} | ||||
|  | ||||
| 	chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; | ||||
| 	chunk = dev->checkpointCurrentBlock * dev->param.nChunksPerBlock + dev->checkpointCurrentChunk; | ||||
|  | ||||
|  | ||||
| 	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), | ||||
| @@ -227,12 +223,12 @@ static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) | ||||
|  | ||||
| 	dev->nPageWrites++; | ||||
|  | ||||
| 	dev->writeChunkWithTagsToNAND(dev, realignedChunk, | ||||
| 	dev->param.writeChunkWithTagsToNAND(dev, realignedChunk, | ||||
| 			dev->checkpointBuffer, &tags); | ||||
| 	dev->checkpointByteOffset = 0; | ||||
| 	dev->checkpointPageSequence++; | ||||
| 	dev->checkpointCurrentChunk++; | ||||
| 	if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) { | ||||
| 	if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock) { | ||||
| 		dev->checkpointCurrentChunk = 0; | ||||
| 		dev->checkpointCurrentBlock = -1; | ||||
| 	} | ||||
| @@ -242,7 +238,7 @@ static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) | ||||
| } | ||||
|  | ||||
|  | ||||
| int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes) | ||||
| int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes) | ||||
| { | ||||
| 	int i = 0; | ||||
| 	int ok = 1; | ||||
| @@ -271,13 +267,13 @@ int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes) | ||||
|  | ||||
| 		if (dev->checkpointByteOffset < 0 || | ||||
| 		   dev->checkpointByteOffset >= dev->nDataBytesPerChunk) | ||||
| 			ok = yaffs_CheckpointFlushBuffer(dev); | ||||
| 			ok = yaffs2_CheckpointFlushBuffer(dev); | ||||
| 	} | ||||
|  | ||||
| 	return i; | ||||
| } | ||||
|  | ||||
| int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) | ||||
| int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) | ||||
| { | ||||
| 	int i = 0; | ||||
| 	int ok = 1; | ||||
| @@ -302,7 +298,7 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) | ||||
| 			dev->checkpointByteOffset >= dev->nDataBytesPerChunk) { | ||||
|  | ||||
| 			if (dev->checkpointCurrentBlock < 0) { | ||||
| 				yaffs_CheckpointFindNextCheckpointBlock(dev); | ||||
| 				yaffs2_CheckpointFindNextCheckpointBlock(dev); | ||||
| 				dev->checkpointCurrentChunk = 0; | ||||
| 			} | ||||
|  | ||||
| @@ -310,7 +306,7 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) | ||||
| 				ok = 0; | ||||
| 			else { | ||||
| 				chunk = dev->checkpointCurrentBlock * | ||||
| 					dev->nChunksPerBlock + | ||||
| 					dev->param.nChunksPerBlock + | ||||
| 					dev->checkpointCurrentChunk; | ||||
|  | ||||
| 				realignedChunk = chunk - dev->chunkOffset; | ||||
| @@ -319,7 +315,7 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) | ||||
|  | ||||
| 				/* read in the next chunk */ | ||||
| 				/* printf("read checkpoint page %d\n",dev->checkpointPage); */ | ||||
| 				dev->readChunkWithTagsFromNAND(dev, | ||||
| 				dev->param.readChunkWithTagsFromNAND(dev, | ||||
| 						realignedChunk, | ||||
| 						dev->checkpointBuffer, | ||||
| 						&tags); | ||||
| @@ -333,7 +329,7 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) | ||||
| 				dev->checkpointPageSequence++; | ||||
| 				dev->checkpointCurrentChunk++; | ||||
|  | ||||
| 				if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) | ||||
| 				if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock) | ||||
| 					dev->checkpointCurrentBlock = -1; | ||||
| 			} | ||||
| 		} | ||||
| @@ -352,12 +348,12 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) | ||||
| 	return 	i; | ||||
| } | ||||
|  | ||||
| int yaffs_CheckpointClose(yaffs_Device *dev) | ||||
| int yaffs2_CheckpointClose(yaffs_Device *dev) | ||||
| { | ||||
|  | ||||
| 	if (dev->checkpointOpenForWrite) { | ||||
| 		if (dev->checkpointByteOffset != 0) | ||||
| 			yaffs_CheckpointFlushBuffer(dev); | ||||
| 			yaffs2_CheckpointFlushBuffer(dev); | ||||
| 	} else if(dev->checkpointBlockList){ | ||||
| 		int i; | ||||
| 		for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) { | ||||
| @@ -375,7 +371,7 @@ int yaffs_CheckpointClose(yaffs_Device *dev) | ||||
| 		dev->checkpointBlockList = NULL; | ||||
| 	} | ||||
|  | ||||
| 	dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock; | ||||
| 	dev->nFreeChunks -= dev->blocksInCheckpoint * dev->param.nChunksPerBlock; | ||||
| 	dev->nErasedBlocks -= dev->blocksInCheckpoint; | ||||
|  | ||||
|  | ||||
| @@ -391,12 +387,15 @@ int yaffs_CheckpointClose(yaffs_Device *dev) | ||||
| 		return 0; | ||||
| } | ||||
|  | ||||
| int yaffs_CheckpointInvalidateStream(yaffs_Device *dev) | ||||
| int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev) | ||||
| { | ||||
| 	/* Erase the checkpoint data */ | ||||
|  | ||||
| 	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR), | ||||
| 		dev->blocksInCheckpoint)); | ||||
|  | ||||
| 	return yaffs_CheckpointErase(dev); | ||||
| 	return yaffs2_CheckpointErase(dev); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -18,18 +18,17 @@ | ||||
|  | ||||
| #include "yaffs_guts.h" | ||||
|  | ||||
| int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting); | ||||
| int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting); | ||||
|  | ||||
| int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes); | ||||
| int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes); | ||||
|  | ||||
| int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes); | ||||
| int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes); | ||||
|  | ||||
| int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); | ||||
| int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); | ||||
|  | ||||
| int yaffs_CheckpointClose(yaffs_Device *dev); | ||||
| int yaffs2_CheckpointClose(yaffs_Device *dev); | ||||
|  | ||||
| int yaffs_CheckpointInvalidateStream(yaffs_Device *dev); | ||||
| int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev); | ||||
|  | ||||
|  | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -28,9 +28,6 @@ | ||||
|  * this bytes influence on the line parity. | ||||
|  */ | ||||
|  | ||||
| const char *yaffs_ecc_c_version = | ||||
| 	"$Id$"; | ||||
|  | ||||
| #include "yportenv.h" | ||||
|  | ||||
| #include "yaffs_ecc.h" | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -17,6 +17,7 @@ | ||||
| #define __YAFFS_GETBLOCKINFO_H__ | ||||
|  | ||||
| #include "yaffs_guts.h" | ||||
| #include "yaffs_trace.h" | ||||
|  | ||||
| /* Function to manipulate block info */ | ||||
| static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk) | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -16,8 +16,9 @@ | ||||
| #ifndef __YAFFS_GUTS_H__ | ||||
| #define __YAFFS_GUTS_H__ | ||||
|  | ||||
| #include "devextras.h" | ||||
| #include "yportenv.h" | ||||
| #include "devextras.h" | ||||
| #include "yaffs_list.h" | ||||
|  | ||||
| #define YAFFS_OK	1 | ||||
| #define YAFFS_FAIL  0 | ||||
| @@ -52,7 +53,6 @@ | ||||
|  | ||||
| #define YAFFS_MAX_CHUNK_ID		0x000FFFFF | ||||
|  | ||||
| #define YAFFS_UNUSED_OBJECT_ID		0x0003FFFF | ||||
|  | ||||
| #define YAFFS_ALLOCATION_NOBJECTS	100 | ||||
| #define YAFFS_ALLOCATION_NTNODES	100 | ||||
| @@ -62,8 +62,9 @@ | ||||
|  | ||||
|  | ||||
| #define YAFFS_OBJECT_SPACE		0x40000 | ||||
| #define YAFFS_MAX_OBJECT_ID		(YAFFS_OBJECT_SPACE -1) | ||||
|  | ||||
| #define YAFFS_CHECKPOINT_VERSION 	3 | ||||
| #define YAFFS_CHECKPOINT_VERSION 	4 | ||||
|  | ||||
| #ifdef CONFIG_YAFFS_UNICODE | ||||
| #define YAFFS_MAX_NAME_LENGTH		127 | ||||
| @@ -81,12 +82,11 @@ | ||||
| #define YAFFS_OBJECTID_UNLINKED		3 | ||||
| #define YAFFS_OBJECTID_DELETED		4 | ||||
|  | ||||
| /* Sseudo object ids for checkpointing */ | ||||
| /* Pseudo object ids for checkpointing */ | ||||
| #define YAFFS_OBJECTID_SB_HEADER	0x10 | ||||
| #define YAFFS_OBJECTID_CHECKPOINT_DATA	0x20 | ||||
| #define YAFFS_SEQUENCE_CHECKPOINT_DATA  0x21 | ||||
|  | ||||
| /* */ | ||||
|  | ||||
| #define YAFFS_MAX_SHORT_OP_CACHES	20 | ||||
|  | ||||
| @@ -119,11 +119,7 @@ typedef struct { | ||||
| 	int dirty; | ||||
| 	int nBytes;		/* Only valid if the cache is dirty */ | ||||
| 	int locked;		/* Can't push out or flush while locked. */ | ||||
| #ifdef CONFIG_YAFFS_YAFFS2 | ||||
| 	__u8 *data; | ||||
| #else | ||||
| 	__u8 data[YAFFS_BYTES_PER_CHUNK]; | ||||
| #endif | ||||
| } yaffs_ChunkCache; | ||||
|  | ||||
|  | ||||
| @@ -234,6 +230,8 @@ typedef enum { | ||||
| 	YAFFS_BLOCK_STATE_UNKNOWN = 0, | ||||
|  | ||||
| 	YAFFS_BLOCK_STATE_SCANNING, | ||||
|         /* Being scanned */ | ||||
|  | ||||
| 	YAFFS_BLOCK_STATE_NEEDS_SCANNING, | ||||
| 	/* The block might have something on it (ie it is allocating or full, perhaps empty) | ||||
| 	 * but it needs to be scanned to determine its true state. | ||||
| @@ -249,21 +247,23 @@ typedef enum { | ||||
| 	/* This block is partially allocated. | ||||
| 	 * At least one page holds valid data. | ||||
| 	 * This is the one currently being used for page | ||||
| 	 * allocation. Should never be more than one of these | ||||
| 	 * allocation. Should never be more than one of these. | ||||
|          * If a block is only partially allocated at mount it is treated as full. | ||||
| 	 */ | ||||
|  | ||||
| 	YAFFS_BLOCK_STATE_FULL, | ||||
| 	/* All the pages in this block have been allocated. | ||||
|          * If a block was only partially allocated when mounted we treat | ||||
|          * it as fully allocated. | ||||
| 	 */ | ||||
|  | ||||
| 	YAFFS_BLOCK_STATE_DIRTY, | ||||
| 	/* All pages have been allocated and deleted. | ||||
| 	/* The block was full and now all chunks have been deleted. | ||||
| 	 * Erase me, reuse me. | ||||
| 	 */ | ||||
|  | ||||
| 	YAFFS_BLOCK_STATE_CHECKPOINT, | ||||
| 	/* This block is assigned to holding checkpoint data. | ||||
| 	 */ | ||||
| 	/* This block is assigned to holding checkpoint data. */ | ||||
|  | ||||
| 	YAFFS_BLOCK_STATE_COLLECTING, | ||||
| 	/* This block is being garbage collected */ | ||||
| @@ -351,23 +351,12 @@ typedef struct { | ||||
| /*--------------------------- Tnode -------------------------- */ | ||||
|  | ||||
| union yaffs_Tnode_union { | ||||
| #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG | ||||
| 	union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1]; | ||||
| #else | ||||
| 	union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL]; | ||||
| #endif | ||||
| /*	__u16 level0[YAFFS_NTNODES_LEVEL0]; */ | ||||
|  | ||||
| }; | ||||
|  | ||||
| typedef union yaffs_Tnode_union yaffs_Tnode; | ||||
|  | ||||
| struct yaffs_TnodeList_struct { | ||||
| 	struct yaffs_TnodeList_struct *next; | ||||
| 	yaffs_Tnode *tnodes; | ||||
| }; | ||||
|  | ||||
| typedef struct yaffs_TnodeList_struct yaffs_TnodeList; | ||||
|  | ||||
| /*------------------------  Object -----------------------------*/ | ||||
| /* An object can be one of: | ||||
| @@ -387,6 +376,7 @@ typedef struct { | ||||
|  | ||||
| typedef struct { | ||||
| 	struct ylist_head children;     /* list of child links */ | ||||
| 	struct ylist_head dirty;	/* Entry for list of dirty directories */ | ||||
| } yaffs_DirectoryStructure; | ||||
|  | ||||
| typedef struct { | ||||
| @@ -405,6 +395,8 @@ typedef union { | ||||
| 	yaffs_HardLinkStructure hardLinkVariant; | ||||
| } yaffs_ObjectVariant; | ||||
|  | ||||
|  | ||||
|  | ||||
| struct yaffs_ObjectStruct { | ||||
| 	__u8 deleted:1;		/* This should only apply to unlinked files. */ | ||||
| 	__u8 softDeleted:1;	/* it has also been soft deleted */ | ||||
| @@ -424,7 +416,10 @@ struct yaffs_ObjectStruct { | ||||
| 				 * until the inode is released. | ||||
| 				 */ | ||||
| 	__u8 beingCreated:1;	/* This object is still being created so skip some checks. */ | ||||
| 	__u8 isShadowed:1;      /* This object is shadowed on the way to being renamed. */ | ||||
| 	__u8 isShadowed:1;	/* This object is shadowed on the way to being renamed. */ | ||||
|  | ||||
| 	__u8 xattrKnown:1;	/* We know if this has object has xattribs or not. */ | ||||
| 	__u8 hasXattr:1;	/* This object has xattribs. Valid if xattrKnown. */ | ||||
|  | ||||
| 	__u8 serial;		/* serial number of chunk in NAND. Cached here */ | ||||
| 	__u16 sum;		/* sum of the name to speed searching */ | ||||
| @@ -453,10 +448,6 @@ struct yaffs_ObjectStruct { | ||||
| 	YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1]; | ||||
| #endif | ||||
|  | ||||
| #ifndef __KERNEL__ | ||||
| 	__u32 inUse; | ||||
| #endif | ||||
|  | ||||
| #ifdef CONFIG_YAFFS_WINCE | ||||
| 	__u32 win_ctime[2]; | ||||
| 	__u32 win_mtime[2]; | ||||
| @@ -471,10 +462,7 @@ struct yaffs_ObjectStruct { | ||||
|  | ||||
| 	__u32 yst_rdev; | ||||
|  | ||||
| #ifdef __KERNEL__ | ||||
| 	struct inode *myInode; | ||||
|  | ||||
| #endif | ||||
| 	void *myInode; | ||||
|  | ||||
| 	yaffs_ObjectType variantType; | ||||
|  | ||||
| @@ -484,13 +472,6 @@ struct yaffs_ObjectStruct { | ||||
|  | ||||
| typedef struct yaffs_ObjectStruct yaffs_Object; | ||||
|  | ||||
| struct yaffs_ObjectList_struct { | ||||
| 	yaffs_Object *objects; | ||||
| 	struct yaffs_ObjectList_struct *next; | ||||
| }; | ||||
|  | ||||
| typedef struct yaffs_ObjectList_struct yaffs_ObjectList; | ||||
|  | ||||
| typedef struct { | ||||
| 	struct ylist_head list; | ||||
| 	int count; | ||||
| @@ -532,12 +513,18 @@ typedef struct { | ||||
|  | ||||
| /*----------------- Device ---------------------------------*/ | ||||
|  | ||||
| struct yaffs_DeviceStruct { | ||||
| 	struct ylist_head devList; | ||||
| 	const char *name; | ||||
|  | ||||
| 	/* Entry parameters set up way early. Yaffs sets up the rest.*/ | ||||
| 	int nDataBytesPerChunk;	/* Should be a power of 2 >= 512 */ | ||||
| struct yaffs_DeviceParamStruct { | ||||
| 	const YCHAR *name; | ||||
|  | ||||
| 	/* | ||||
|          * Entry parameters set up way early. Yaffs sets up the rest. | ||||
|          * The structure should be zeroed out before use so that unused | ||||
|          * and defualt values are zero. | ||||
|          */ | ||||
|  | ||||
| 	int inbandTags;          /* Use unband tags */ | ||||
| 	__u32 totalBytesPerChunk; /* Should be >= 512, does not need to be a power of 2 */ | ||||
| 	int nChunksPerBlock;	/* does not need to be a power of 2 */ | ||||
| 	int spareBytesPerChunk;	/* spare area size */ | ||||
| 	int startBlock;		/* Start block we're allowed to use */ | ||||
| @@ -546,26 +533,24 @@ struct yaffs_DeviceStruct { | ||||
| 				/* reserved blocks on NOR and RAM. */ | ||||
|  | ||||
|  | ||||
| 	/* Stuff used by the shared space checkpointing mechanism */ | ||||
| 	/* If this value is zero, then this mechanism is disabled */ | ||||
|  | ||||
| /*	int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */ | ||||
|  | ||||
|  | ||||
| 	int nShortOpCaches;	/* If <= 0, then short op caching is disabled, else | ||||
| 				 * the number of short op caches (don't use too many) | ||||
| 				 * the number of short op caches (don't use too many). | ||||
|                                  * 10 to 20 is a good bet. | ||||
| 				 */ | ||||
| 	int useNANDECC;		/* Flag to decide whether or not to use NANDECC on data (yaffs1) */ | ||||
| 	int noTagsECC;		/* Flag to decide whether or not to do ECC on packed tags (yaffs2) */  | ||||
|  | ||||
| 	int useHeaderFileSize;	/* Flag to determine if we should use file sizes from the header */ | ||||
| 	int isYaffs2;           /* Use yaffs2 mode on this device */ | ||||
|  | ||||
| 	int emptyLostAndFound;  /* Flasg to determine if lst+found should be emptied on init */ | ||||
| 	int emptyLostAndFound;  /* Auto-empty lost+found directory on mount */ | ||||
|  | ||||
| 	int useNANDECC;		/* Flag to decide whether or not to use NANDECC */ | ||||
| 	int refreshPeriod;	/* How often we should check to do a block refresh */ | ||||
|  | ||||
| 	void *genericDevice;	/* Pointer to device context | ||||
| 				 * On an mtd this holds the mtd pointer. | ||||
| 				 */ | ||||
| 	void *superBlock; | ||||
| 	/* Checkpoint control. Can be set before or after initialisation */ | ||||
| 	__u8 skipCheckpointRead; | ||||
| 	__u8 skipCheckpointWrite; | ||||
|  | ||||
| 	int enableXattr;	/* Enable xattribs */ | ||||
|  | ||||
| 	/* NAND access functions (Must be set before calling YAFFS)*/ | ||||
|  | ||||
| @@ -592,8 +577,6 @@ struct yaffs_DeviceStruct { | ||||
| 			       yaffs_BlockState *state, __u32 *sequenceNumber); | ||||
| #endif | ||||
|  | ||||
| 	int isYaffs2; | ||||
|  | ||||
| 	/* The removeObjectCallback function must be supplied by OS flavours that | ||||
| 	 * need it. | ||||
|          * yaffs direct uses it to implement the faster readdir. | ||||
| @@ -601,54 +584,61 @@ struct yaffs_DeviceStruct { | ||||
| 	 */ | ||||
| 	void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj); | ||||
|  | ||||
| 	/* Callback to mark the superblock dirsty */ | ||||
| 	void (*markSuperBlockDirty)(void *superblock); | ||||
| 	/* Callback to mark the superblock dirty */ | ||||
| 	void (*markSuperBlockDirty)(struct yaffs_DeviceStruct *dev); | ||||
| 	 | ||||
| 	/*  Callback to control garbage collection. */ | ||||
| 	unsigned (*gcControl)(struct yaffs_DeviceStruct *dev); | ||||
|  | ||||
|         /* Debug control flags. Don't use unless you know what you're doing */ | ||||
| 	int useHeaderFileSize;	/* Flag to determine if we should use file sizes from the header */ | ||||
| 	int disableLazyLoad;	/* Disable lazy loading on this device */ | ||||
| 	int wideTnodesDisabled; /* Set to disable wide tnodes */ | ||||
| 	int disableSoftDelete;  /* yaffs 1 only: Set to disable the use of softdeletion. */ | ||||
| 	 | ||||
| 	int deferDirectoryUpdate; /* Set to defer directory updates */ | ||||
|  | ||||
| 	YCHAR *pathDividers;	/* String of legal path dividers */ | ||||
| #ifdef CONFIG_YAFFS_AUTO_UNICODE | ||||
| 	int autoUnicode; | ||||
| #endif | ||||
| 	int alwaysCheckErased; /* Force chunk erased check always on */ | ||||
| }; | ||||
|  | ||||
| typedef struct yaffs_DeviceParamStruct yaffs_DeviceParam; | ||||
|  | ||||
| 	/* End of stuff that must be set before initialisation. */ | ||||
| struct yaffs_DeviceStruct { | ||||
| 	struct yaffs_DeviceParamStruct param; | ||||
|  | ||||
| 	/* Checkpoint control. Can be set before or after initialisation */ | ||||
| 	__u8 skipCheckpointRead; | ||||
| 	__u8 skipCheckpointWrite; | ||||
|         /* Context storage. Holds extra OS specific data for this device */ | ||||
|  | ||||
| 	void *osContext; | ||||
| 	void *driverContext; | ||||
|  | ||||
| 	struct ylist_head devList; | ||||
|  | ||||
| 	/* Runtime parameters. Set up by YAFFS. */ | ||||
| 	int nDataBytesPerChunk;	 | ||||
|  | ||||
| 	__u16 chunkGroupBits;	/* 0 for devices <= 32MB. else log2(nchunks) - 16 */ | ||||
|         /* Non-wide tnode stuff */ | ||||
| 	__u16 chunkGroupBits;	/* Number of bits that need to be resolved if | ||||
|                                  * the tnodes are not wide enough. | ||||
|                                  */ | ||||
| 	__u16 chunkGroupSize;	/* == 2^^chunkGroupBits */ | ||||
|  | ||||
| 	/* Stuff to support wide tnodes */ | ||||
| 	__u32 tnodeWidth; | ||||
| 	__u32 tnodeMask; | ||||
| 	__u32 tnodeSize; | ||||
|  | ||||
| 	/* Stuff for figuring out file offset to chunk conversions */ | ||||
| 	__u32 chunkShift; /* Shift value */ | ||||
| 	__u32 chunkDiv;   /* Divisor after shifting: 1 for power-of-2 sizes */ | ||||
| 	__u32 chunkMask;  /* Mask to use for power-of-2 case */ | ||||
|  | ||||
| 	/* Stuff to handle inband tags */ | ||||
| 	int inbandTags; | ||||
| 	__u32 totalBytesPerChunk; | ||||
|  | ||||
| #ifdef __KERNEL__ | ||||
|  | ||||
| 	struct semaphore sem;	/* Semaphore for waiting on erasure.*/ | ||||
| 	struct semaphore grossLock;	/* Gross locking semaphore */ | ||||
| 	struct rw_semaphore dirLock; /* Lock the directory structure */ | ||||
| 	__u8 *spareBuffer;	/* For mtdif2 use. Don't know the size of the buffer | ||||
| 				 * at compile time so we have to allocate it. | ||||
|  | ||||
| 				 */ | ||||
| 	void (*putSuperFunc) (struct super_block *sb); | ||||
|         struct ylist_head searchContexts; | ||||
|  | ||||
| #endif | ||||
|  | ||||
| 	int isMounted; | ||||
|  | ||||
| 	int readOnly; | ||||
| 	int isCheckpointed; | ||||
|  | ||||
|  | ||||
| @@ -690,51 +680,31 @@ struct yaffs_DeviceStruct { | ||||
| 	__u32 allocationPage; | ||||
| 	int allocationBlockFinder;	/* Used to search for next allocation block */ | ||||
|  | ||||
| 	/* Runtime state */ | ||||
| 	int nTnodesCreated; | ||||
| 	yaffs_Tnode *freeTnodes; | ||||
| 	int nFreeTnodes; | ||||
| 	yaffs_TnodeList *allocatedTnodeList; | ||||
|  | ||||
| 	int isDoingGC; | ||||
| 	int gcBlock; | ||||
| 	int gcChunk; | ||||
|  | ||||
| 	int nObjectsCreated; | ||||
| 	yaffs_Object *freeObjects; | ||||
| 	int nFreeObjects; | ||||
| 	/* Object and Tnode memory management */ | ||||
| 	void *allocator; | ||||
| 	int nObjects; | ||||
| 	int nTnodes; | ||||
|  | ||||
| 	int nHardLinks; | ||||
|  | ||||
| 	yaffs_ObjectList *allocatedObjectList; | ||||
|  | ||||
| 	yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS]; | ||||
| 	__u32 bucketFinder; | ||||
|  | ||||
| 	int nFreeChunks; | ||||
|  | ||||
| 	int currentDirtyChecker;	/* Used to find current dirtiest block */ | ||||
|  | ||||
| 	/* Garbage collection control */ | ||||
| 	__u32 *gcCleanupList;	/* objects to delete at the end of a GC. */ | ||||
| 	int nonAggressiveSkip;	/* GC state/mode */ | ||||
| 	__u32 nCleanups; | ||||
|  | ||||
| 	/* Statistcs */ | ||||
| 	int nPageWrites; | ||||
| 	int nPageReads; | ||||
| 	int nBlockErasures; | ||||
| 	int nErasureFailures; | ||||
| 	int nGCCopies; | ||||
| 	int garbageCollections; | ||||
| 	int passiveGarbageCollections; | ||||
| 	int nRetriedWrites; | ||||
| 	int nRetiredBlocks; | ||||
| 	int eccFixed; | ||||
| 	int eccUnfixed; | ||||
| 	int tagsEccFixed; | ||||
| 	int tagsEccUnfixed; | ||||
| 	int nDeletions; | ||||
| 	int nUnmarkedDeletions; | ||||
|  | ||||
| 	int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ | ||||
| 	unsigned hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ | ||||
| 	unsigned gcDisable; | ||||
| 	unsigned gcBlockFinder; | ||||
| 	unsigned gcDirtiest; | ||||
| 	unsigned gcPagesInUse; | ||||
| 	unsigned gcNotDone; | ||||
| 	unsigned gcBlock; | ||||
| 	unsigned gcChunk; | ||||
| 	unsigned gcSkip; | ||||
|  | ||||
| 	/* Special directories */ | ||||
| 	yaffs_Object *rootDir; | ||||
| @@ -751,8 +721,6 @@ struct yaffs_DeviceStruct { | ||||
| 	yaffs_ChunkCache *srCache; | ||||
| 	int srLastUse; | ||||
|  | ||||
| 	int cacheHits; | ||||
|  | ||||
| 	/* Stuff for background deletion and unlinked files.*/ | ||||
| 	yaffs_Object *unlinkedDir;	/* Directory where unlinked and deleted files live. */ | ||||
| 	yaffs_Object *deletedDir;	/* Directory where deleted objects are sent to disappear. */ | ||||
| @@ -761,7 +729,6 @@ struct yaffs_DeviceStruct { | ||||
| 	int nUnlinkedFiles;		/* Count of unlinked files. */ | ||||
| 	int nBackgroundDeletions;	/* Count of background deletions. */ | ||||
|  | ||||
|  | ||||
| 	/* Temporary buffer management */ | ||||
| 	yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS]; | ||||
| 	int maxTemp; | ||||
| @@ -772,6 +739,36 @@ struct yaffs_DeviceStruct { | ||||
| 	/* yaffs2 runtime stuff */ | ||||
| 	unsigned sequenceNumber;	/* Sequence number of currently allocating block */ | ||||
| 	unsigned oldestDirtySequence; | ||||
| 	unsigned oldestDirtyBlock; | ||||
|  | ||||
| 	/* Block refreshing */ | ||||
| 	int refreshSkip;	/* A skip down counter. Refresh happens when this gets to zero. */ | ||||
|  | ||||
| 	/* Dirty directory handling */ | ||||
| 	struct ylist_head dirtyDirectories; /* List of dirty directories */ | ||||
|  | ||||
|  | ||||
| 	/* Statistcs */ | ||||
| 	__u32 nPageWrites; | ||||
| 	__u32 nPageReads; | ||||
| 	__u32 nBlockErasures; | ||||
| 	__u32 nErasureFailures; | ||||
| 	__u32 nGCCopies; | ||||
| 	__u32 allGCs; | ||||
| 	__u32 passiveGCs; | ||||
| 	__u32 oldestDirtyGCs; | ||||
| 	__u32 nGCBlocks; | ||||
| 	__u32 backgroundGCs; | ||||
| 	__u32 nRetriedWrites; | ||||
| 	__u32 nRetiredBlocks; | ||||
| 	__u32 eccFixed; | ||||
| 	__u32 eccUnfixed; | ||||
| 	__u32 tagsEccFixed; | ||||
| 	__u32 tagsEccUnfixed; | ||||
| 	__u32 nDeletions; | ||||
| 	__u32 nUnmarkedDeletions; | ||||
| 	__u32 refreshCount; | ||||
| 	__u32 cacheHits; | ||||
|  | ||||
| }; | ||||
|  | ||||
| @@ -804,7 +801,6 @@ typedef struct { | ||||
|  | ||||
| 	/* yaffs2 runtime stuff */ | ||||
| 	unsigned sequenceNumber;	/* Sequence number of currently allocating block */ | ||||
| 	unsigned oldestDirtySequence; | ||||
|  | ||||
| } yaffs_CheckpointDevice; | ||||
|  | ||||
| @@ -817,6 +813,23 @@ typedef struct { | ||||
| } yaffs_CheckpointValidity; | ||||
|  | ||||
|  | ||||
| struct yaffs_ShadowFixerStruct { | ||||
| 	int objectId; | ||||
| 	int shadowedId; | ||||
| 	struct yaffs_ShadowFixerStruct *next; | ||||
| }; | ||||
|  | ||||
| /* Structure for doing xattr modifications */ | ||||
| typedef struct { | ||||
| 	int set; /* If 0 then this is a deletion */ | ||||
| 	const YCHAR *name; | ||||
| 	const void *data; | ||||
| 	int size; | ||||
| 	int flags; | ||||
| 	int result; | ||||
| }yaffs_XAttrMod; | ||||
|  | ||||
|  | ||||
| /*----------------------- YAFFS Functions -----------------------*/ | ||||
|  | ||||
| int yaffs_GutsInitialise(yaffs_Device *dev); | ||||
| @@ -848,7 +861,8 @@ int yaffs_ResizeFile(yaffs_Object *obj, loff_t newSize); | ||||
|  | ||||
| yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name, | ||||
| 				__u32 mode, __u32 uid, __u32 gid); | ||||
| int yaffs_FlushFile(yaffs_Object *obj, int updateTime); | ||||
|  | ||||
| int yaffs_FlushFile(yaffs_Object *obj, int updateTime, int dataSync); | ||||
|  | ||||
| /* Flushing and checkpointing */ | ||||
| void yaffs_FlushEntireDeviceCache(yaffs_Device *dev); | ||||
| @@ -881,6 +895,12 @@ YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj); | ||||
| yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name, | ||||
| 				 __u32 mode, __u32 uid, __u32 gid, __u32 rdev); | ||||
|  | ||||
|  | ||||
| int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags); | ||||
| int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size); | ||||
| int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size); | ||||
| int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name); | ||||
|  | ||||
| /* Special directories */ | ||||
| yaffs_Object *yaffs_Root(yaffs_Device *dev); | ||||
| yaffs_Object *yaffs_LostNFound(yaffs_Device *dev); | ||||
| @@ -890,18 +910,18 @@ yaffs_Object *yaffs_LostNFound(yaffs_Device *dev); | ||||
| void yfsd_WinFileTimeNow(__u32 target[2]); | ||||
| #endif | ||||
|  | ||||
| #ifdef __KERNEL__ | ||||
|  | ||||
| void yaffs_HandleDeferedFree(yaffs_Object *obj); | ||||
| #endif | ||||
|  | ||||
| void yaffs_UpdateDirtyDirectories(yaffs_Device *dev); | ||||
|  | ||||
| int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency); | ||||
|  | ||||
| /* Debug dump  */ | ||||
| int yaffs_DumpObject(yaffs_Object *obj); | ||||
|  | ||||
| void yaffs_GutsTest(yaffs_Device *dev); | ||||
|  | ||||
| /* A few useful functions */ | ||||
| void yaffs_InitialiseTags(yaffs_ExtendedTags *tags); | ||||
| /* A few useful functions to be used within the core files*/ | ||||
| void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn); | ||||
| int yaffs_CheckFF(__u8 *buffer, int nBytes); | ||||
| void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi); | ||||
| @@ -909,4 +929,41 @@ void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi); | ||||
| __u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo); | ||||
| void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo); | ||||
|  | ||||
| yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, | ||||
| 					        int number, | ||||
| 					        yaffs_ObjectType type); | ||||
| int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, | ||||
| 			        int chunkInNAND, int inScan); | ||||
| void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name); | ||||
| void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh); | ||||
| void yaffs_AddObjectToDirectory(yaffs_Object *directory, | ||||
| 					yaffs_Object *obj); | ||||
| YCHAR *yaffs_CloneString(const YCHAR *str); | ||||
| void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList); | ||||
| void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo); | ||||
| int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, | ||||
| 				int force, int isShrink, int shadows, | ||||
|                                 yaffs_XAttrMod *xop); | ||||
| void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, | ||||
| 				int backwardScanning); | ||||
| int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks); | ||||
| yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev); | ||||
| yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, | ||||
| 					yaffs_FileStructure *fStruct, | ||||
| 					__u32 chunkId, | ||||
| 					yaffs_Tnode *passedTn); | ||||
|  | ||||
| int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, | ||||
| 			int nBytes, int writeThrough); | ||||
| void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize); | ||||
| void yaffs_SkipRestOfBlock(yaffs_Device *dev); | ||||
|  | ||||
| int yaffs_CountFreeChunks(yaffs_Device *dev); | ||||
|  | ||||
| yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, | ||||
| 				yaffs_FileStructure *fStruct, | ||||
| 				__u32 chunkId); | ||||
|  | ||||
| __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos); | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										43
									
								
								fs/yaffs2/yaffs_linux.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								fs/yaffs2/yaffs_linux.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Lesser General Public License version 2.1 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. | ||||
|  */ | ||||
|  | ||||
| #ifndef __YAFFS_LINUX_H__ | ||||
| #define __YAFFS_LINUX_H__ | ||||
|  | ||||
| #include "devextras.h" | ||||
| #include "yportenv.h" | ||||
|  | ||||
| struct yaffs_LinuxContext { | ||||
| 	struct ylist_head	contextList; /* List of these we have mounted */ | ||||
| 	struct yaffs_DeviceStruct *dev; | ||||
| 	struct super_block * superBlock; | ||||
| 	struct task_struct *bgThread; /* Background thread for this device */ | ||||
| 	int bgRunning; | ||||
|         struct semaphore grossLock;     /* Gross locking semaphore */ | ||||
| 	__u8 *spareBuffer;      /* For mtdif2 use. Don't know the size of the buffer | ||||
| 				 * at compile time so we have to allocate it. | ||||
| 				 */ | ||||
| 	struct ylist_head searchContexts; | ||||
| 	void (*putSuperFunc)(struct super_block *sb); | ||||
|  | ||||
| 	struct task_struct *readdirProcess; | ||||
| 	unsigned mount_id; | ||||
| }; | ||||
|  | ||||
| #define yaffs_DeviceToLC(dev) ((struct yaffs_LinuxContext *)((dev)->osContext)) | ||||
| #define yaffs_DeviceToMtd(dev) ((struct mtd_info *)((dev)->driverContext)) | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										200
									
								
								fs/yaffs2/yaffs_linux_allocator.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								fs/yaffs2/yaffs_linux_allocator.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Lesser General Public License version 2.1 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. | ||||
|  * | ||||
|  * Note: Tis code is currently unused. Being checked in in case it becomes useful. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #include "yaffs_allocator.h" | ||||
| #include "yaffs_guts.h" | ||||
| #include "yaffs_trace.h" | ||||
| #include "yportenv.h" | ||||
| #include "yaffs_linux.h" | ||||
| /* | ||||
|  * Start out with the same allocator as yaffs direct. | ||||
|  * Todo: Change to Linux slab allocator. | ||||
|  */ | ||||
|  | ||||
|  | ||||
|  | ||||
| #define NAMELEN  20 | ||||
| struct yaffs_AllocatorStruct { | ||||
| 	char tnode_name[NAMELEN+1]; | ||||
| 	char object_name[NAMELEN+1]; | ||||
| 	struct kmem_cache *tnode_cache; | ||||
| 	struct kmem_cache *object_cache; | ||||
| }; | ||||
|  | ||||
| typedef struct yaffs_AllocatorStruct yaffs_Allocator; | ||||
|  | ||||
| int mount_id; | ||||
|  | ||||
| void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev) | ||||
| { | ||||
| 	yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; | ||||
|  | ||||
| 	T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n"))); | ||||
|  | ||||
| 	if(allocator){ | ||||
| 		if(allocator->tnode_cache){ | ||||
| 			kmem_cache_destroy(allocator->tnode_cache); | ||||
| 			allocator->tnode_cache = NULL; | ||||
| 		} else { | ||||
| 			T(YAFFS_TRACE_ALWAYS, | ||||
| 				(TSTR("NULL tnode cache\n"))); | ||||
| 			YBUG(); | ||||
| 		} | ||||
|  | ||||
| 		if(allocator->object_cache){ | ||||
| 			kmem_cache_destroy(allocator->object_cache); | ||||
| 			allocator->object_cache = NULL; | ||||
| 		} else { | ||||
| 			T(YAFFS_TRACE_ALWAYS, | ||||
| 				(TSTR("NULL object cache\n"))); | ||||
| 			YBUG(); | ||||
| 		} | ||||
|  | ||||
| 		YFREE(allocator); | ||||
|  | ||||
| 	} else { | ||||
| 		T(YAFFS_TRACE_ALWAYS, | ||||
| 			(TSTR("Deinitialising NULL allocator\n"))); | ||||
| 		YBUG(); | ||||
| 	} | ||||
| 	dev->allocator = NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void fake_ctor0(void *data){data = data;} | ||||
| static void fake_ctor1(void *data){data = data;} | ||||
| static void fake_ctor2(void *data){data = data;} | ||||
| static void fake_ctor3(void *data){data = data;} | ||||
| static void fake_ctor4(void *data){data = data;} | ||||
| static void fake_ctor5(void *data){data = data;} | ||||
| static void fake_ctor6(void *data){data = data;} | ||||
| static void fake_ctor7(void *data){data = data;} | ||||
| static void fake_ctor8(void *data){data = data;} | ||||
| static void fake_ctor9(void *data){data = data;} | ||||
|  | ||||
| static void (*fake_ctor_list[10]) (void *) = { | ||||
| 	fake_ctor0, | ||||
| 	fake_ctor1, | ||||
| 	fake_ctor2, | ||||
| 	fake_ctor3, | ||||
| 	fake_ctor4, | ||||
| 	fake_ctor5, | ||||
| 	fake_ctor6, | ||||
| 	fake_ctor7, | ||||
| 	fake_ctor8, | ||||
| 	fake_ctor9, | ||||
| }; | ||||
|  | ||||
| void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev) | ||||
| { | ||||
| 	yaffs_Allocator *allocator; | ||||
| 	unsigned mount_id = yaffs_DeviceToLC(dev)->mount_id; | ||||
|  | ||||
| 	T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n"))); | ||||
|  | ||||
| 	if(dev->allocator) | ||||
| 		YBUG(); | ||||
| 	else if(mount_id >= 10){ | ||||
| 		T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id)); | ||||
| 	} else { | ||||
| 		 allocator = YMALLOC(sizeof(yaffs_Allocator)); | ||||
| 		 memset(allocator,0,sizeof(yaffs_Allocator)); | ||||
| 		 dev->allocator = allocator; | ||||
|  | ||||
| 		if(!dev->allocator){ | ||||
| 			T(YAFFS_TRACE_ALWAYS, | ||||
| 				(TSTR("yaffs allocator creation failed\n"))); | ||||
| 			YBUG(); | ||||
| 			return; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id); | ||||
| 		sprintf(allocator->object_name,"yaffs_o_%u",mount_id); | ||||
|  | ||||
| 		allocator->tnode_cache = | ||||
| 			kmem_cache_create(allocator->tnode_name, | ||||
| 				dev->tnodeSize, | ||||
| 				0, 0, | ||||
| 				fake_ctor_list[mount_id]); | ||||
| 		if(allocator->tnode_cache) | ||||
| 			T(YAFFS_TRACE_ALLOCATE, | ||||
| 				(TSTR("tnode cache \"%s\" %p\n"), | ||||
| 				allocator->tnode_name,allocator->tnode_cache)); | ||||
| 		else { | ||||
| 			T(YAFFS_TRACE_ALWAYS, | ||||
| 				(TSTR("yaffs cache creation failed\n"))); | ||||
| 			YBUG(); | ||||
| 		} | ||||
|  | ||||
|  | ||||
| 		allocator->object_cache =  | ||||
| 			kmem_cache_create(allocator->object_name, | ||||
| 				sizeof(yaffs_Object), | ||||
| 				0, 0, | ||||
| 				fake_ctor_list[mount_id]); | ||||
|  | ||||
| 		if(allocator->object_cache) | ||||
| 			T(YAFFS_TRACE_ALLOCATE, | ||||
| 				(TSTR("object cache \"%s\" %p\n"), | ||||
| 				allocator->object_name,allocator->object_cache)); | ||||
|  | ||||
| 		else { | ||||
| 			T(YAFFS_TRACE_ALWAYS, | ||||
| 				(TSTR("yaffs cache creation failed\n"))); | ||||
| 			YBUG(); | ||||
| 		} | ||||
| 	}  | ||||
| } | ||||
|  | ||||
|  | ||||
| yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev) | ||||
| { | ||||
| 	yaffs_Allocator *allocator = dev->allocator; | ||||
| 	if(!allocator || !allocator->tnode_cache){ | ||||
| 		YBUG(); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS); | ||||
| } | ||||
|  | ||||
| void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn) | ||||
| { | ||||
| 	yaffs_Allocator *allocator = dev->allocator; | ||||
| 	kmem_cache_free(allocator->tnode_cache,tn); | ||||
| } | ||||
|  | ||||
| yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev) | ||||
| { | ||||
| 	yaffs_Allocator *allocator = dev->allocator; | ||||
| 	if(!allocator){ | ||||
| 		YBUG(); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	if(!allocator->object_cache){ | ||||
| 		YBUG(); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	return kmem_cache_alloc(allocator->object_cache, GFP_NOFS); | ||||
| } | ||||
|  | ||||
| void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj) | ||||
| { | ||||
| 	yaffs_Allocator *allocator = dev->allocator; | ||||
| 	kmem_cache_free(allocator->object_cache,obj); | ||||
| } | ||||
							
								
								
									
										127
									
								
								fs/yaffs2/yaffs_list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								fs/yaffs2/yaffs_list.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Lesser General Public License version 2.1 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * This file is just holds extra declarations of macros that would normally | ||||
|  * be providesd in the Linux kernel. These macros have been written from | ||||
|  * scratch but are functionally equivalent to the Linux ones. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef __YAFFS_LIST_H__ | ||||
| #define __YAFFS_LIST_H__ | ||||
|  | ||||
|  | ||||
| #include "yportenv.h" | ||||
|  | ||||
| /* | ||||
|  * This is a simple doubly linked list implementation that matches the | ||||
|  * way the Linux kernel doubly linked list implementation works. | ||||
|  */ | ||||
|  | ||||
| struct ylist_head { | ||||
| 	struct ylist_head *next; /* next in chain */ | ||||
| 	struct ylist_head *prev; /* previous in chain */ | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* Initialise a static list */ | ||||
| #define YLIST_HEAD(name) \ | ||||
| struct ylist_head name = { &(name), &(name)} | ||||
|  | ||||
|  | ||||
|  | ||||
| /* Initialise a list head to an empty list */ | ||||
| #define YINIT_LIST_HEAD(p) \ | ||||
| do { \ | ||||
| 	(p)->next = (p);\ | ||||
| 	(p)->prev = (p); \ | ||||
| } while (0) | ||||
|  | ||||
|  | ||||
| /* Add an element to a list */ | ||||
| static Y_INLINE void ylist_add(struct ylist_head *newEntry, | ||||
| 				struct ylist_head *list) | ||||
| { | ||||
| 	struct ylist_head *listNext = list->next; | ||||
|  | ||||
| 	list->next = newEntry; | ||||
| 	newEntry->prev = list; | ||||
| 	newEntry->next = listNext; | ||||
| 	listNext->prev = newEntry; | ||||
|  | ||||
| } | ||||
|  | ||||
| static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry, | ||||
| 				 struct ylist_head *list) | ||||
| { | ||||
| 	struct ylist_head *listPrev = list->prev; | ||||
|  | ||||
| 	list->prev = newEntry; | ||||
| 	newEntry->next = list; | ||||
| 	newEntry->prev = listPrev; | ||||
| 	listPrev->next = newEntry; | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Take an element out of its current list, with or without | ||||
|  * reinitialising the links.of the entry*/ | ||||
| static Y_INLINE void ylist_del(struct ylist_head *entry) | ||||
| { | ||||
| 	struct ylist_head *listNext = entry->next; | ||||
| 	struct ylist_head *listPrev = entry->prev; | ||||
|  | ||||
| 	listNext->prev = listPrev; | ||||
| 	listPrev->next = listNext; | ||||
|  | ||||
| } | ||||
|  | ||||
| static Y_INLINE void ylist_del_init(struct ylist_head *entry) | ||||
| { | ||||
| 	ylist_del(entry); | ||||
| 	entry->next = entry->prev = entry; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Test if the list is empty */ | ||||
| static Y_INLINE int ylist_empty(struct ylist_head *entry) | ||||
| { | ||||
| 	return (entry->next == entry); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* ylist_entry takes a pointer to a list entry and offsets it to that | ||||
|  * we can find a pointer to the object it is embedded in. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #define ylist_entry(entry, type, member) \ | ||||
| 	((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member))) | ||||
|  | ||||
|  | ||||
| /* ylist_for_each and list_for_each_safe  iterate over lists. | ||||
|  * ylist_for_each_safe uses temporary storage to make the list delete safe | ||||
|  */ | ||||
|  | ||||
| #define ylist_for_each(itervar, list) \ | ||||
| 	for (itervar = (list)->next; itervar != (list); itervar = itervar->next) | ||||
|  | ||||
| #define ylist_for_each_safe(itervar, saveVar, list) \ | ||||
| 	for (itervar = (list)->next, saveVar = (list)->next->next; \ | ||||
| 		itervar != (list); itervar = saveVar, saveVar = saveVar->next) | ||||
|  | ||||
|  | ||||
| #endif | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -11,9 +11,6 @@ | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
|  | ||||
| const char *yaffs_mtdif_c_version = | ||||
| 	"$Id$"; | ||||
|  | ||||
| #include "yportenv.h" | ||||
|  | ||||
|  | ||||
| @@ -24,208 +21,26 @@ const char *yaffs_mtdif_c_version = | ||||
| #include "linux/time.h" | ||||
| #include "linux/mtd/nand.h" | ||||
|  | ||||
| #if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18)) | ||||
| static struct nand_oobinfo yaffs_oobinfo = { | ||||
| 	.useecc = 1, | ||||
| 	.eccbytes = 6, | ||||
| 	.eccpos = {8, 9, 10, 13, 14, 15} | ||||
| }; | ||||
|  | ||||
| static struct nand_oobinfo yaffs_noeccinfo = { | ||||
| 	.useecc = 0, | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) | ||||
| static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob) | ||||
| { | ||||
| 	oob[0] = spare->tagByte0; | ||||
| 	oob[1] = spare->tagByte1; | ||||
| 	oob[2] = spare->tagByte2; | ||||
| 	oob[3] = spare->tagByte3; | ||||
| 	oob[4] = spare->tagByte4; | ||||
| 	oob[5] = spare->tagByte5 & 0x3f; | ||||
| 	oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80; | ||||
| 	oob[5] |= spare->pageStatus == 0 ? 0 : 0x40; | ||||
| 	oob[6] = spare->tagByte6; | ||||
| 	oob[7] = spare->tagByte7; | ||||
| } | ||||
|  | ||||
| static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob) | ||||
| { | ||||
| 	struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare; | ||||
| 	spare->tagByte0 = oob[0]; | ||||
| 	spare->tagByte1 = oob[1]; | ||||
| 	spare->tagByte2 = oob[2]; | ||||
| 	spare->tagByte3 = oob[3]; | ||||
| 	spare->tagByte4 = oob[4]; | ||||
| 	spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f; | ||||
| 	spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y'; | ||||
| 	spare->pageStatus = oob[5] & 0x40 ? 0xff : 0; | ||||
| 	spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff; | ||||
| 	spare->tagByte6 = oob[6]; | ||||
| 	spare->tagByte7 = oob[7]; | ||||
| 	spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff; | ||||
|  | ||||
| 	nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */ | ||||
| } | ||||
| #endif | ||||
|  | ||||
| int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| 			     const __u8 *data, const yaffs_Spare *spare) | ||||
| { | ||||
| 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); | ||||
| #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) | ||||
| 	struct mtd_oob_ops ops; | ||||
| #endif | ||||
| 	size_t dummy; | ||||
| 	int retval = 0; | ||||
|  | ||||
| 	loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; | ||||
| #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) | ||||
| 	__u8 spareAsBytes[8]; /* OOB */ | ||||
|  | ||||
| 	if (data && !spare) | ||||
| 		retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk, | ||||
| 				&dummy, data); | ||||
| 	else if (spare) { | ||||
| 		if (dev->useNANDECC) { | ||||
| 			translate_spare2oob(spare, spareAsBytes); | ||||
| 			ops.mode = MTD_OOB_AUTO; | ||||
| 			ops.ooblen = 8; /* temp hack */ | ||||
| 		} else { | ||||
| 			ops.mode = MTD_OOB_RAW; | ||||
| 			ops.ooblen = YAFFS_BYTES_PER_SPARE; | ||||
| 		} | ||||
| 		ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen; | ||||
| 		ops.datbuf = (u8 *)data; | ||||
| 		ops.ooboffs = 0; | ||||
| 		ops.oobbuf = spareAsBytes; | ||||
| 		retval = mtd->write_oob(mtd, addr, &ops); | ||||
| 	} | ||||
| #else | ||||
| 	__u8 *spareAsBytes = (__u8 *) spare; | ||||
|  | ||||
| 	if (data && spare) { | ||||
| 		if (dev->useNANDECC) | ||||
| 			retval = | ||||
| 			    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, | ||||
| 					   &dummy, data, spareAsBytes, | ||||
| 					   &yaffs_oobinfo); | ||||
| 		else | ||||
| 			retval = | ||||
| 			    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, | ||||
| 					   &dummy, data, spareAsBytes, | ||||
| 					   &yaffs_noeccinfo); | ||||
| 	} else { | ||||
| 		if (data) | ||||
| 			retval = | ||||
| 			    mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, | ||||
| 				       data); | ||||
| 		if (spare) | ||||
| 			retval = | ||||
| 			    mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE, | ||||
| 					   &dummy, spareAsBytes); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	if (retval == 0) | ||||
| 		return YAFFS_OK; | ||||
| 	else | ||||
| 		return YAFFS_FAIL; | ||||
| } | ||||
|  | ||||
| int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, | ||||
| 			      yaffs_Spare *spare) | ||||
| { | ||||
| 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); | ||||
| #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) | ||||
| 	struct mtd_oob_ops ops; | ||||
| #endif | ||||
| 	size_t dummy; | ||||
| 	int retval = 0; | ||||
|  | ||||
| 	loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; | ||||
| #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) | ||||
| 	__u8 spareAsBytes[8]; /* OOB */ | ||||
|  | ||||
| 	if (data && !spare) | ||||
| 		retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, | ||||
| 				&dummy, data); | ||||
| 	else if (spare) { | ||||
| 		if (dev->useNANDECC) { | ||||
| 			ops.mode = MTD_OOB_AUTO; | ||||
| 			ops.ooblen = 8; /* temp hack */ | ||||
| 		} else { | ||||
| 			ops.mode = MTD_OOB_RAW; | ||||
| 			ops.ooblen = YAFFS_BYTES_PER_SPARE; | ||||
| 		} | ||||
| 		ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen; | ||||
| 		ops.datbuf = data; | ||||
| 		ops.ooboffs = 0; | ||||
| 		ops.oobbuf = spareAsBytes; | ||||
| 		retval = mtd->read_oob(mtd, addr, &ops); | ||||
| 		if (dev->useNANDECC) | ||||
| 			translate_oob2spare(spare, spareAsBytes); | ||||
| 	} | ||||
| #else | ||||
| 	__u8 *spareAsBytes = (__u8 *) spare; | ||||
|  | ||||
| 	if (data && spare) { | ||||
| 		if (dev->useNANDECC) { | ||||
| 			/* Careful, this call adds 2 ints */ | ||||
| 			/* to the end of the spare data.  Calling function */ | ||||
| 			/* should allocate enough memory for spare, */ | ||||
| 			/* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */ | ||||
| 			retval = | ||||
| 			    mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, | ||||
| 					  &dummy, data, spareAsBytes, | ||||
| 					  &yaffs_oobinfo); | ||||
| 		} else { | ||||
| 			retval = | ||||
| 			    mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, | ||||
| 					  &dummy, data, spareAsBytes, | ||||
| 					  &yaffs_noeccinfo); | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (data) | ||||
| 			retval = | ||||
| 			    mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, | ||||
| 				      data); | ||||
| 		if (spare) | ||||
| 			retval = | ||||
| 			    mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE, | ||||
| 					  &dummy, spareAsBytes); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	if (retval == 0) | ||||
| 		return YAFFS_OK; | ||||
| 	else | ||||
| 		return YAFFS_FAIL; | ||||
| } | ||||
| #include "yaffs_linux.h" | ||||
|  | ||||
| int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) | ||||
| { | ||||
| 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); | ||||
| 	struct mtd_info *mtd = yaffs_DeviceToMtd(dev); | ||||
| 	__u32 addr = | ||||
| 	    ((loff_t) blockNumber) * dev->nDataBytesPerChunk | ||||
| 		* dev->nChunksPerBlock; | ||||
| 	    ((loff_t) blockNumber) * dev->param.totalBytesPerChunk | ||||
| 		* dev->param.nChunksPerBlock; | ||||
| 	struct erase_info ei; | ||||
| 	 | ||||
| 	int retval = 0; | ||||
|  | ||||
| 	ei.mtd = mtd; | ||||
| 	ei.addr = addr; | ||||
| 	ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock; | ||||
| 	ei.len = dev->param.totalBytesPerChunk * dev->param.nChunksPerBlock; | ||||
| 	ei.time = 1000; | ||||
| 	ei.retries = 2; | ||||
| 	ei.callback = NULL; | ||||
| 	ei.priv = (u_long) dev; | ||||
|  | ||||
| 	/* Todo finish off the ei if required */ | ||||
|  | ||||
| 	sema_init(&dev->sem, 0); | ||||
|  | ||||
| 	retval = mtd->erase(mtd, &ei); | ||||
|  | ||||
| 	if (retval == 0) | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -22,11 +22,6 @@ | ||||
| extern struct nand_oobinfo yaffs_oobinfo; | ||||
| extern struct nand_oobinfo yaffs_noeccinfo; | ||||
| #endif | ||||
|  | ||||
| int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| 			const __u8 *data, const yaffs_Spare *spare); | ||||
| int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, | ||||
| 			yaffs_Spare *spare); | ||||
| int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); | ||||
| int nandmtd_InitialiseNAND(yaffs_Device *dev); | ||||
| #endif | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  * YAFFS: Yet another FFS. A NAND-flash specific file system. | ||||
|  * yaffs_mtdif1.c  NAND mtd interface functions for small-page NAND. | ||||
|  * | ||||
|  * Copyright (C) 2002 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
| @@ -24,9 +24,11 @@ | ||||
|  */ | ||||
|  | ||||
| #include "yportenv.h" | ||||
| #include "yaffs_trace.h" | ||||
| #include "yaffs_guts.h" | ||||
| #include "yaffs_packedtags1.h" | ||||
| #include "yaffs_tagscompat.h"	/* for yaffs_CalcTagsECC */ | ||||
| #include "yaffs_linux.h" | ||||
|  | ||||
| #include "linux/kernel.h" | ||||
| #include "linux/version.h" | ||||
| @@ -36,8 +38,6 @@ | ||||
| /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ | ||||
| #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) | ||||
|  | ||||
| const char *yaffs_mtdif1_c_version = "$Id$"; | ||||
|  | ||||
| #ifndef CONFIG_YAFFS_9BYTE_TAGS | ||||
| # define YTAG1_SIZE 8 | ||||
| #else | ||||
| @@ -91,7 +91,7 @@ static struct nand_ecclayout nand_oob_16 = { | ||||
| int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, | ||||
| 	int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags) | ||||
| { | ||||
| 	struct mtd_info *mtd = dev->genericDevice; | ||||
| 	struct mtd_info *mtd = yaffs_DeviceToMtd(dev); | ||||
| 	int chunkBytes = dev->nDataBytesPerChunk; | ||||
| 	loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; | ||||
| 	struct mtd_oob_ops ops; | ||||
| @@ -135,9 +135,9 @@ int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, | ||||
|  | ||||
| 	retval = mtd->write_oob(mtd, addr, &ops); | ||||
| 	if (retval) { | ||||
| 		yaffs_trace(YAFFS_TRACE_MTD, | ||||
| 			"write_oob failed, chunk %d, mtd error %d\n", | ||||
| 			chunkInNAND, retval); | ||||
| 		T(YAFFS_TRACE_MTD, | ||||
| 			(TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR), | ||||
| 			chunkInNAND, retval)); | ||||
| 	} | ||||
| 	return retval ? YAFFS_FAIL : YAFFS_OK; | ||||
| } | ||||
| @@ -169,7 +169,7 @@ static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval) | ||||
| int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, | ||||
| 	int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags) | ||||
| { | ||||
| 	struct mtd_info *mtd = dev->genericDevice; | ||||
| 	struct mtd_info *mtd = yaffs_DeviceToMtd(dev); | ||||
| 	int chunkBytes = dev->nDataBytesPerChunk; | ||||
| 	loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; | ||||
| 	int eccres = YAFFS_ECC_RESULT_NO_ERROR; | ||||
| @@ -196,9 +196,9 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, | ||||
| 	 */ | ||||
| 	retval = mtd->read_oob(mtd, addr, &ops); | ||||
| 	if (retval) { | ||||
| 		yaffs_trace(YAFFS_TRACE_MTD, | ||||
| 			"read_oob failed, chunk %d, mtd error %d\n", | ||||
| 			chunkInNAND, retval); | ||||
| 		T(YAFFS_TRACE_MTD, | ||||
| 			(TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR), | ||||
| 			chunkInNAND, retval)); | ||||
| 	} | ||||
|  | ||||
| 	switch (retval) { | ||||
| @@ -280,11 +280,11 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, | ||||
|  */ | ||||
| int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) | ||||
| { | ||||
| 	struct mtd_info *mtd = dev->genericDevice; | ||||
| 	int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; | ||||
| 	struct mtd_info *mtd = yaffs_DeviceToMtd(dev); | ||||
| 	int blocksize = dev->param.nChunksPerBlock * dev->nDataBytesPerChunk; | ||||
| 	int retval; | ||||
|  | ||||
| 	yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo); | ||||
| 	T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), blockNo)); | ||||
|  | ||||
| 	retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo); | ||||
| 	return (retval) ? YAFFS_FAIL : YAFFS_OK; | ||||
| @@ -301,9 +301,9 @@ static int nandmtd1_TestPrerequists(struct mtd_info *mtd) | ||||
| 	int oobavail = mtd->ecclayout->oobavail; | ||||
|  | ||||
| 	if (oobavail < YTAG1_SIZE) { | ||||
| 		yaffs_trace(YAFFS_TRACE_ERROR, | ||||
| 			"mtd device has only %d bytes for tags, need %d\n", | ||||
| 			oobavail, YTAG1_SIZE); | ||||
| 		T(YAFFS_TRACE_ERROR, | ||||
| 			(TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR), | ||||
| 			oobavail, YTAG1_SIZE)); | ||||
| 		return YAFFS_FAIL; | ||||
| 	} | ||||
| 	return YAFFS_OK; | ||||
| @@ -321,8 +321,8 @@ static int nandmtd1_TestPrerequists(struct mtd_info *mtd) | ||||
| int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, | ||||
| 	yaffs_BlockState *pState, __u32 *pSequenceNumber) | ||||
| { | ||||
| 	struct mtd_info *mtd = dev->genericDevice; | ||||
| 	int chunkNo = blockNo * dev->nChunksPerBlock; | ||||
| 	struct mtd_info *mtd = yaffs_DeviceToMtd(dev); | ||||
| 	int chunkNo = blockNo * dev->param.nChunksPerBlock; | ||||
| 	loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk; | ||||
| 	yaffs_ExtendedTags etags; | ||||
| 	int state = YAFFS_BLOCK_STATE_DEAD; | ||||
| @@ -338,8 +338,8 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, | ||||
| 	retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); | ||||
| 	etags.blockBad = (mtd->block_isbad)(mtd, addr); | ||||
| 	if (etags.blockBad) { | ||||
| 		yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, | ||||
| 			"block %d is marked bad\n", blockNo); | ||||
| 		T(YAFFS_TRACE_BAD_BLOCKS, | ||||
| 			(TSTR("block %d is marked bad"TENDSTR), blockNo)); | ||||
| 		state = YAFFS_BLOCK_STATE_DEAD; | ||||
| 	} else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) { | ||||
| 		/* bad tags, need to look more closely */ | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -13,11 +13,8 @@ | ||||
|  | ||||
| /* mtd interface for YAFFS2 */ | ||||
|  | ||||
| const char *yaffs_mtdif2_c_version = | ||||
| 	"$Id$"; | ||||
|  | ||||
| #include "yportenv.h" | ||||
|  | ||||
| #include "yaffs_trace.h" | ||||
|  | ||||
| #include "yaffs_mtdif2.h" | ||||
|  | ||||
| @@ -27,11 +24,7 @@ const char *yaffs_mtdif2_c_version = | ||||
|  | ||||
| #include "yaffs_packedtags2.h" | ||||
|  | ||||
| #ifdef CONFIG_YAFFS_DOES_ECC | ||||
| #define OOB_TAGS_SIZE sizeof(yaffs_PackedTags2) | ||||
| #else | ||||
| #define OOB_TAGS_SIZE sizeof(yaffs_PackedTags2TagsPart) | ||||
| #endif | ||||
| #include "yaffs_linux.h" | ||||
|  | ||||
| /* NB For use with inband tags.... | ||||
|  * We assume that the data buffer is of size totalBytersPerChunk so that we can also | ||||
| @@ -41,7 +34,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| 				      const __u8 *data, | ||||
| 				      const yaffs_ExtendedTags *tags) | ||||
| { | ||||
| 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); | ||||
| 	struct mtd_info *mtd = yaffs_DeviceToMtd(dev); | ||||
| #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) | ||||
| 	struct mtd_oob_ops ops; | ||||
| #else | ||||
| @@ -53,12 +46,16 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, | ||||
|  | ||||
| 	yaffs_PackedTags2 pt; | ||||
|  | ||||
| 	int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt); | ||||
| 	void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t : (void *)&pt; | ||||
|  | ||||
| 	T(YAFFS_TRACE_MTD, | ||||
| 	  (TSTR | ||||
| 	   ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" | ||||
| 	    TENDSTR), chunkInNAND, data, tags)); | ||||
|  | ||||
| 	addr  = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; | ||||
|  | ||||
| 	addr  = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk; | ||||
|  | ||||
| 	/* For yaffs2 writing there must be both data and tags. | ||||
| 	 * If we're using inband tags, then the tags are stuffed into | ||||
| @@ -66,30 +63,30 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| 	 */ | ||||
| 	if (!data || !tags) | ||||
| 		BUG(); | ||||
| 	else if (dev->inbandTags) { | ||||
| 	else if (dev->param.inbandTags) { | ||||
| 		yaffs_PackedTags2TagsPart *pt2tp; | ||||
| 		pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); | ||||
| 		yaffs_PackTags2TagsPart(pt2tp, tags); | ||||
| 	} else | ||||
| 		yaffs_PackTags2(&pt, tags); | ||||
| 		yaffs_PackTags2(&pt, tags, !dev->param.noTagsECC); | ||||
|  | ||||
| #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) | ||||
| 	ops.mode = MTD_OOB_AUTO;  | ||||
| 	ops.ooblen = (dev->inbandTags) ? 0 : OOB_TAGS_SIZE; | ||||
| 	ops.len = dev->totalBytesPerChunk; | ||||
| 	ops.mode = MTD_OOB_AUTO; | ||||
| 	ops.ooblen = (dev->param.inbandTags) ? 0 : packed_tags_size; | ||||
| 	ops.len = dev->param.totalBytesPerChunk; | ||||
| 	ops.ooboffs = 0; | ||||
| 	ops.datbuf = (__u8 *)data; | ||||
| 	ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt; | ||||
| 	ops.oobbuf = (dev->param.inbandTags) ? NULL : packed_tags_ptr; | ||||
| 	retval = mtd->write_oob(mtd, addr, &ops); | ||||
|  | ||||
| #else | ||||
| 	if (!dev->inbandTags) { | ||||
| 	if (!dev->param.inbandTags) { | ||||
| 		retval = | ||||
| 		    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, | ||||
| 				   &dummy, data, (__u8 *) &pt, NULL); | ||||
| 				   &dummy, data, (__u8 *) packed_tags_ptr, NULL); | ||||
| 	} else { | ||||
| 		retval = | ||||
| 		    mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy, | ||||
| 		    mtd->write(mtd, addr, dev->param.totalBytesPerChunk, &dummy, | ||||
| 			       data); | ||||
| 	} | ||||
| #endif | ||||
| @@ -103,7 +100,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| 				       __u8 *data, yaffs_ExtendedTags *tags) | ||||
| { | ||||
| 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); | ||||
| 	struct mtd_info *mtd = yaffs_DeviceToMtd(dev); | ||||
| #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) | ||||
| 	struct mtd_oob_ops ops; | ||||
| #endif | ||||
| @@ -111,16 +108,19 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| 	int retval = 0; | ||||
| 	int localData = 0; | ||||
|  | ||||
| 	loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; | ||||
| 	loff_t addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk; | ||||
|  | ||||
| 	yaffs_PackedTags2 pt; | ||||
|  | ||||
| 	int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt); | ||||
| 	void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t: (void *)&pt; | ||||
|  | ||||
| 	T(YAFFS_TRACE_MTD, | ||||
| 	  (TSTR | ||||
| 	   ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p" | ||||
| 	    TENDSTR), chunkInNAND, data, tags)); | ||||
|  | ||||
| 	if (dev->inbandTags) { | ||||
| 	if (dev->param.inbandTags) { | ||||
|  | ||||
| 		if (!data) { | ||||
| 			localData = 1; | ||||
| @@ -132,20 +132,20 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, | ||||
|  | ||||
|  | ||||
| #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) | ||||
| 	if (dev->inbandTags || (data && !tags)) | ||||
| 		retval = mtd->read(mtd, addr, dev->totalBytesPerChunk, | ||||
| 	if (dev->param.inbandTags || (data && !tags)) | ||||
| 		retval = mtd->read(mtd, addr, dev->param.totalBytesPerChunk, | ||||
| 				&dummy, data); | ||||
| 	else if (tags) { | ||||
| 		ops.mode = MTD_OOB_AUTO; | ||||
| 		ops.ooblen = OOB_TAGS_SIZE; | ||||
| 		ops.len = data ? dev->nDataBytesPerChunk : OOB_TAGS_SIZE; | ||||
| 		ops.ooblen = packed_tags_size; | ||||
| 		ops.len = data ? dev->nDataBytesPerChunk : packed_tags_size; | ||||
| 		ops.ooboffs = 0; | ||||
| 		ops.datbuf = data; | ||||
| 		ops.oobbuf = dev->spareBuffer; | ||||
| 		ops.oobbuf = yaffs_DeviceToLC(dev)->spareBuffer; | ||||
| 		retval = mtd->read_oob(mtd, addr, &ops); | ||||
| 	} | ||||
| #else | ||||
| 	if (!dev->inbandTags && data && tags) { | ||||
| 	if (!dev->param.inbandTags && data && tags) { | ||||
|  | ||||
| 		retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, | ||||
| 					  &dummy, data, dev->spareBuffer, | ||||
| @@ -155,7 +155,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| 			retval = | ||||
| 			    mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, | ||||
| 				      data); | ||||
| 		if (!dev->inbandTags && tags) | ||||
| 		if (!dev->param.inbandTags && tags) | ||||
| 			retval = | ||||
| 			    mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, | ||||
| 					  dev->spareBuffer); | ||||
| @@ -163,7 +163,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| #endif | ||||
|  | ||||
|  | ||||
| 	if (dev->inbandTags) { | ||||
| 	if (dev->param.inbandTags) { | ||||
| 		if (tags) { | ||||
| 			yaffs_PackedTags2TagsPart *pt2tp; | ||||
| 			pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; | ||||
| @@ -171,8 +171,8 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (tags) { | ||||
| 			memcpy(&pt, dev->spareBuffer, OOB_TAGS_SIZE); | ||||
| 			yaffs_UnpackTags2(tags, &pt); | ||||
| 			memcpy(packed_tags_ptr, yaffs_DeviceToLC(dev)->spareBuffer, packed_tags_size); | ||||
| 			yaffs_UnpackTags2(tags, &pt, !dev->param.noTagsECC); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -183,7 +183,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| 		tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; | ||||
| 		dev->eccUnfixed++; | ||||
| 	} | ||||
| 	if (tags && retval == -EUCLEAN && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) { | ||||
| 	if(tags && retval == -EUCLEAN && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) { | ||||
| 		tags->eccResult = YAFFS_ECC_RESULT_FIXED; | ||||
| 		dev->eccFixed++; | ||||
| 	} | ||||
| @@ -195,15 +195,15 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, | ||||
|  | ||||
| int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) | ||||
| { | ||||
| 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); | ||||
| 	struct mtd_info *mtd = yaffs_DeviceToMtd(dev); | ||||
| 	int retval; | ||||
| 	T(YAFFS_TRACE_MTD, | ||||
| 	  (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo)); | ||||
|  | ||||
| 	retval = | ||||
| 	    mtd->block_markbad(mtd, | ||||
| 			       blockNo * dev->nChunksPerBlock * | ||||
| 			       dev->totalBytesPerChunk); | ||||
| 			       blockNo * dev->param.nChunksPerBlock * | ||||
| 			       dev->param.totalBytesPerChunk); | ||||
|  | ||||
| 	if (retval == 0) | ||||
| 		return YAFFS_OK; | ||||
| @@ -215,15 +215,15 @@ int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) | ||||
| int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, | ||||
| 			    yaffs_BlockState *state, __u32 *sequenceNumber) | ||||
| { | ||||
| 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); | ||||
| 	struct mtd_info *mtd = yaffs_DeviceToMtd(dev); | ||||
| 	int retval; | ||||
|  | ||||
| 	T(YAFFS_TRACE_MTD, | ||||
| 	  (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo)); | ||||
| 	retval = | ||||
| 	    mtd->block_isbad(mtd, | ||||
| 			     blockNo * dev->nChunksPerBlock * | ||||
| 			     dev->totalBytesPerChunk); | ||||
| 			     blockNo * dev->param.nChunksPerBlock * | ||||
| 			     dev->param.totalBytesPerChunk); | ||||
|  | ||||
| 	if (retval) { | ||||
| 		T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR))); | ||||
| @@ -234,7 +234,7 @@ int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, | ||||
| 		yaffs_ExtendedTags t; | ||||
| 		nandmtd2_ReadChunkWithTagsFromNAND(dev, | ||||
| 						   blockNo * | ||||
| 						   dev->nChunksPerBlock, NULL, | ||||
| 						   dev->param.nChunksPerBlock, NULL, | ||||
| 						   &t); | ||||
|  | ||||
| 		if (t.chunkUsed) { | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|   | ||||
							
								
								
									
										197
									
								
								fs/yaffs2/yaffs_nameval.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								fs/yaffs2/yaffs_nameval.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,197 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * This simple implementation of a name-value store assumes a small number of values and fits | ||||
|  * into a small finite buffer. | ||||
|  * | ||||
|  * Each attribute is stored as a record: | ||||
|  *  sizeof(int) bytes   record size. | ||||
|  *  strnlen+1 bytes name null terminated. | ||||
|  *  nbytes    value. | ||||
|  *  ---------- | ||||
|  *  total size  stored in record size  | ||||
|  * | ||||
|  * This code has not been tested with unicode yet. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #include "yaffs_nameval.h" | ||||
|  | ||||
| #include "yportenv.h" | ||||
|   | ||||
| static int nval_find(const char *xb, int xb_size, const YCHAR *name, | ||||
| 		int *exist_size) | ||||
| { | ||||
| 	int pos=0; | ||||
| 	int size; | ||||
|  | ||||
| 	memcpy(&size,xb,sizeof(int)); | ||||
| 	while(size > 0 && (size < xb_size) && (pos + size < xb_size)){ | ||||
| 		if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){ | ||||
| 			if(exist_size) | ||||
| 				*exist_size = size; | ||||
| 			return pos; | ||||
| 		} | ||||
| 		pos += size; | ||||
| 		if(pos < xb_size -sizeof(int)) | ||||
| 			memcpy(&size,xb + pos,sizeof(int)); | ||||
| 		else | ||||
| 			size = 0; | ||||
| 	} | ||||
| 	if(exist_size) | ||||
| 		*exist_size = 0; | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static int nval_used(const char *xb, int xb_size) | ||||
| { | ||||
| 	int pos=0; | ||||
| 	int size; | ||||
|  | ||||
| 	memcpy(&size,xb + pos,sizeof(int)); | ||||
| 	while(size > 0 && (size < xb_size) && (pos + size < xb_size)){ | ||||
| 		pos += size; | ||||
| 		if(pos < xb_size -sizeof(int)) | ||||
| 			memcpy(&size,xb + pos,sizeof(int)); | ||||
| 		else | ||||
| 			size = 0; | ||||
| 	} | ||||
| 	return pos; | ||||
| } | ||||
|  | ||||
| int nval_del(char *xb, int xb_size, const YCHAR *name) | ||||
| { | ||||
| 	int pos  = nval_find(xb, xb_size, name, NULL); | ||||
| 	int size; | ||||
| 	 | ||||
| 	if(pos >= 0 && pos < xb_size){ | ||||
| 		/* Find size, shift rest over this record, then zero out the rest of buffer */ | ||||
| 		memcpy(&size,xb+pos,sizeof(int)); | ||||
| 		memcpy(xb + pos, xb + pos + size, xb_size - (pos + size)); | ||||
| 		memset(xb + (xb_size - size),0,size); | ||||
| 		return 0; | ||||
| 	} else | ||||
| 		return -ENODATA; | ||||
| } | ||||
|  | ||||
| int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags) | ||||
| { | ||||
| 	int pos; | ||||
| 	int namelen = yaffs_strnlen(name,xb_size); | ||||
| 	int reclen; | ||||
| 	int size_exist = 0; | ||||
| 	int space; | ||||
| 	int start; | ||||
|  | ||||
| 	pos = nval_find(xb,xb_size,name, &size_exist); | ||||
|  | ||||
| 	if(flags & XATTR_CREATE && pos >= 0) | ||||
| 		return -EEXIST; | ||||
| 	if(flags & XATTR_REPLACE && pos < 0) | ||||
| 		return -ENODATA; | ||||
|  | ||||
| 	start = nval_used(xb,xb_size); | ||||
| 	space = xb_size - start + size_exist; | ||||
|  | ||||
| 	reclen = (sizeof(int) + namelen + 1 + bsize); | ||||
|  | ||||
| 	if(reclen > space) | ||||
| 		return -ENOSPC; | ||||
|  | ||||
| 	if(pos >= 0){ | ||||
| 		nval_del(xb,xb_size,name); | ||||
| 		start = nval_used(xb, xb_size); | ||||
| 	} | ||||
|  | ||||
| 	pos = start; | ||||
|  | ||||
| 	memcpy(xb + pos,&reclen,sizeof(int)); | ||||
| 	pos +=sizeof(int); | ||||
| 	yaffs_strncpy((YCHAR *)(xb + pos), name, reclen); | ||||
| 	pos+= (namelen+1); | ||||
| 	memcpy(xb + pos,buf,bsize); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize) | ||||
| { | ||||
| 	int pos = nval_find(xb,xb_size,name,NULL); | ||||
| 	int size; | ||||
| 	 | ||||
| 	if(pos >= 0 && pos< xb_size){ | ||||
| 		 | ||||
| 		memcpy(&size,xb +pos,sizeof(int)); | ||||
| 		pos+=sizeof(int); /* advance past record length */ | ||||
| 		size -= sizeof(int); | ||||
|  | ||||
| 		/* Advance over name string */ | ||||
| 		while(xb[pos] && size > 0 && pos < xb_size){ | ||||
| 			pos++; | ||||
| 			size--; | ||||
| 		} | ||||
| 		/*Advance over NUL */ | ||||
| 		pos++; | ||||
| 		size--; | ||||
|  | ||||
| 		if(size <= bsize){ | ||||
| 			memcpy(buf,xb + pos,size); | ||||
| 			return size; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| 	if(pos >= 0) | ||||
| 		return -ERANGE; | ||||
| 	else | ||||
| 		return -ENODATA; | ||||
| } | ||||
|  | ||||
| int nval_list(const char *xb, int xb_size, char *buf, int bsize) | ||||
| { | ||||
| 	int pos = 0; | ||||
| 	int size; | ||||
| 	int name_len; | ||||
| 	int ncopied = 0; | ||||
| 	int filled = 0; | ||||
|  | ||||
| 	memcpy(&size,xb + pos,sizeof(int)); | ||||
| 	while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){ | ||||
| 		pos+= sizeof(int); | ||||
| 		size-=sizeof(int); | ||||
| 		name_len = yaffs_strnlen((YCHAR *)(xb + pos), size); | ||||
| 		if(ncopied + name_len + 1 < bsize){ | ||||
| 			memcpy(buf,xb+pos,name_len * sizeof(YCHAR)); | ||||
| 			buf+= name_len; | ||||
| 			*buf = '\0'; | ||||
| 			buf++; | ||||
| 			if(sizeof(YCHAR) > 1){ | ||||
| 				*buf = '\0'; | ||||
| 				buf++; | ||||
| 			} | ||||
| 			ncopied += (name_len+1); | ||||
| 		} else | ||||
| 			filled = 1; | ||||
| 		pos+=size; | ||||
| 		if(pos < xb_size -sizeof(int)) | ||||
| 			memcpy(&size,xb + pos,sizeof(int)); | ||||
| 		else | ||||
| 			size = 0; | ||||
| 	} | ||||
| 	return ncopied; | ||||
| } | ||||
|  | ||||
|  | ||||
| int nval_hasvalues(const char *xb, int xb_size) | ||||
| { | ||||
| 	return nval_used(xb, xb_size) > 0; | ||||
| } | ||||
							
								
								
									
										25
									
								
								fs/yaffs2/yaffs_nameval.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								fs/yaffs2/yaffs_nameval.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Lesser General Public License version 2.1 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. | ||||
|  */ | ||||
| #ifndef __NAMEVAL_H__ | ||||
| #define __NAMEVAL_H__ | ||||
|  | ||||
| #include "yportenv.h" | ||||
|  | ||||
| int nval_del(char *xb, int xb_size, const YCHAR *name); | ||||
| int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags); | ||||
| int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize); | ||||
| int nval_list(const char *xb, int xb_size, char *buf, int bsize); | ||||
| int nval_hasvalues(const char *xb, int xb_size); | ||||
| #endif | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -11,9 +11,6 @@ | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
|  | ||||
| const char *yaffs_nand_c_version = | ||||
| 	"$Id$"; | ||||
|  | ||||
| #include "yaffs_nand.h" | ||||
| #include "yaffs_tagscompat.h" | ||||
| #include "yaffs_tagsvalidity.h" | ||||
| @@ -35,8 +32,8 @@ int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| 	if (!tags) | ||||
| 		tags = &localTags; | ||||
|  | ||||
| 	if (dev->readChunkWithTagsFromNAND) | ||||
| 		result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer, | ||||
| 	if (dev->param.readChunkWithTagsFromNAND) | ||||
| 		result = dev->param.readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer, | ||||
| 						      tags); | ||||
| 	else | ||||
| 		result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev, | ||||
| @@ -46,7 +43,8 @@ int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, | ||||
| 	if (tags && | ||||
| 	   tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) { | ||||
|  | ||||
| 		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock); | ||||
| 		yaffs_BlockInfo *bi; | ||||
| 		bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->param.nChunksPerBlock); | ||||
| 		yaffs_HandleChunkError(dev, bi); | ||||
| 	} | ||||
|  | ||||
| @@ -80,8 +78,8 @@ int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev, | ||||
| 		YBUG(); | ||||
| 	} | ||||
|  | ||||
| 	if (dev->writeChunkWithTagsToNAND) | ||||
| 		return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer, | ||||
| 	if (dev->param.writeChunkWithTagsToNAND) | ||||
| 		return dev->param.writeChunkWithTagsToNAND(dev, chunkInNAND, buffer, | ||||
| 						     tags); | ||||
| 	else | ||||
| 		return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev, | ||||
| @@ -95,8 +93,8 @@ int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo) | ||||
| 	blockNo -= dev->blockOffset; | ||||
|  | ||||
|  | ||||
| 	if (dev->markNANDBlockBad) | ||||
| 		return dev->markNANDBlockBad(dev, blockNo); | ||||
| 	if (dev->param.markNANDBlockBad) | ||||
| 		return dev->param.markNANDBlockBad(dev, blockNo); | ||||
| 	else | ||||
| 		return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo); | ||||
| } | ||||
| @@ -108,8 +106,8 @@ int yaffs_QueryInitialBlockState(yaffs_Device *dev, | ||||
| { | ||||
| 	blockNo -= dev->blockOffset; | ||||
|  | ||||
| 	if (dev->queryNANDBlock) | ||||
| 		return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber); | ||||
| 	if (dev->param.queryNANDBlock) | ||||
| 		return dev->param.queryNANDBlock(dev, blockNo, state, sequenceNumber); | ||||
| 	else | ||||
| 		return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo, | ||||
| 							     state, | ||||
| @@ -126,14 +124,16 @@ int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, | ||||
|  | ||||
| 	dev->nBlockErasures++; | ||||
|  | ||||
| 	result = dev->eraseBlockInNAND(dev, blockInNAND); | ||||
| 	result = dev->param.eraseBlockInNAND(dev, blockInNAND); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev) | ||||
| { | ||||
| 	return dev->initialiseNAND(dev); | ||||
| 	if(dev->param.initialiseNAND) | ||||
| 		return dev->param.initialiseNAND(dev); | ||||
| 	return YAFFS_OK; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -13,6 +13,7 @@ | ||||
|  | ||||
| #include "yaffs_packedtags2.h" | ||||
| #include "yportenv.h" | ||||
| #include "yaffs_trace.h" | ||||
| #include "yaffs_tagsvalidity.h" | ||||
|  | ||||
| /* This code packs a set of extended tags into a binary structure for | ||||
| @@ -37,9 +38,6 @@ | ||||
| #define EXTRA_OBJECT_TYPE_SHIFT (28) | ||||
| #define EXTRA_OBJECT_TYPE_MASK  ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) | ||||
|  | ||||
| #ifndef CONFIG_YAFFS_DOES_ECC | ||||
| #define YAFFS_IGNORE_TAGS_ECC 1 | ||||
| #endif | ||||
|  | ||||
| static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt) | ||||
| { | ||||
| @@ -99,17 +97,14 @@ void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt, | ||||
| } | ||||
|  | ||||
|  | ||||
| void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t) | ||||
| void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC) | ||||
| { | ||||
| 	yaffs_PackTags2TagsPart(&pt->t, t); | ||||
|  | ||||
| #ifndef YAFFS_IGNORE_TAGS_ECC | ||||
| 	{ | ||||
| 	if(tagsECC) | ||||
| 		yaffs_ECCCalculateOther((unsigned char *)&pt->t, | ||||
| 					sizeof(yaffs_PackedTags2TagsPart), | ||||
| 					&pt->ecc); | ||||
| 	} | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -161,27 +156,24 @@ void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, | ||||
| } | ||||
|  | ||||
|  | ||||
| void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt) | ||||
| void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC) | ||||
| { | ||||
|  | ||||
| 	yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR; | ||||
|  | ||||
| 	if (pt->t.sequenceNumber != 0xFFFFFFFF) { | ||||
| 		/* Page is in use */ | ||||
| #ifndef YAFFS_IGNORE_TAGS_ECC | ||||
| 		{ | ||||
| 			yaffs_ECCOther ecc; | ||||
| 			int result; | ||||
| 			yaffs_ECCCalculateOther((unsigned char *)&pt->t, | ||||
| 						sizeof | ||||
| 						(yaffs_PackedTags2TagsPart), | ||||
| 						&ecc); | ||||
| 			result = | ||||
| 			    yaffs_ECCCorrectOther((unsigned char *)&pt->t, | ||||
| 						  sizeof | ||||
| 						  (yaffs_PackedTags2TagsPart), | ||||
| 						  &pt->ecc, &ecc); | ||||
| 			switch (result) { | ||||
| 	if (pt->t.sequenceNumber != 0xFFFFFFFF && | ||||
| 	    tagsECC){ | ||||
| 		/* Chunk is in use and we need to do ECC */ | ||||
| 		 | ||||
| 		yaffs_ECCOther ecc; | ||||
| 		int result; | ||||
| 		yaffs_ECCCalculateOther((unsigned char *)&pt->t, | ||||
| 					sizeof(yaffs_PackedTags2TagsPart), | ||||
| 					&ecc); | ||||
| 		result = yaffs_ECCCorrectOther((unsigned char *)&pt->t, | ||||
| 						sizeof(yaffs_PackedTags2TagsPart), | ||||
| 						&pt->ecc, &ecc); | ||||
| 		switch (result) { | ||||
| 			case 0: | ||||
| 				eccResult = YAFFS_ECC_RESULT_NO_ERROR; | ||||
| 				break; | ||||
| @@ -193,9 +185,7 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt) | ||||
| 				break; | ||||
| 			default: | ||||
| 				eccResult = YAFFS_ECC_RESULT_UNKNOWN; | ||||
| 			} | ||||
| 		} | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	yaffs_UnpackTags2TagsPart(t, &pt->t); | ||||
| @@ -204,6 +194,5 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt) | ||||
|  | ||||
| 	yaffs_DumpPackedTags2(pt); | ||||
| 	yaffs_DumpTags2(t); | ||||
|  | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -34,8 +34,8 @@ typedef struct { | ||||
| } yaffs_PackedTags2; | ||||
|  | ||||
| /* Full packed tags with ECC, used for oob tags */ | ||||
| void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t); | ||||
| void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt); | ||||
| void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC); | ||||
| void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC); | ||||
|  | ||||
| /* Only the tags part (no ECC for use with inband tags */ | ||||
| void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -17,7 +17,18 @@ | ||||
| #ifndef __YAFFS_QSORT_H__ | ||||
| #define __YAFFS_QSORT_H__ | ||||
|  | ||||
| #ifdef __KERNEL__ | ||||
| #include <linux/sort.h> | ||||
|  | ||||
| extern void yaffs_qsort(void *const base, size_t total_elems, size_t size, | ||||
| 			int (*cmp)(const void *, const void *)){ | ||||
| 	sort(base, total_elems, size, cmp, NULL); | ||||
| } | ||||
|  | ||||
| #else | ||||
|  | ||||
| extern void yaffs_qsort(void *const base, size_t total_elems, size_t size, | ||||
| 			int (*cmp)(const void *, const void *)); | ||||
|  | ||||
| #endif | ||||
| #endif | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -15,6 +15,7 @@ | ||||
| #include "yaffs_tagscompat.h" | ||||
| #include "yaffs_ecc.h" | ||||
| #include "yaffs_getblockinfo.h" | ||||
| #include "yaffs_trace.h" | ||||
|  | ||||
| static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND); | ||||
| #ifdef NOTYET | ||||
| @@ -163,14 +164,14 @@ static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev, | ||||
| 				int chunkInNAND, const __u8 *data, | ||||
| 				yaffs_Spare *spare) | ||||
| { | ||||
| 	if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) { | ||||
| 	if (chunkInNAND < dev->param.startBlock * dev->param.nChunksPerBlock) { | ||||
| 		T(YAFFS_TRACE_ERROR, | ||||
| 		  (TSTR("**>> yaffs chunk %d is not valid" TENDSTR), | ||||
| 		   chunkInNAND)); | ||||
| 		return YAFFS_FAIL; | ||||
| 	} | ||||
|  | ||||
| 	return dev->writeChunkToNAND(dev, chunkInNAND, data, spare); | ||||
| 	return dev->param.writeChunkToNAND(dev, chunkInNAND, data, spare); | ||||
| } | ||||
|  | ||||
| static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, | ||||
| @@ -189,8 +190,8 @@ static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, | ||||
| 		spare = &localSpare; | ||||
| 	} | ||||
|  | ||||
| 	if (!dev->useNANDECC) { | ||||
| 		retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare); | ||||
| 	if (!dev->param.useNANDECC) { | ||||
| 		retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data, spare); | ||||
| 		if (data && doErrorCorrection) { | ||||
| 			/* Do ECC correction */ | ||||
| 			/* Todo handle any errors */ | ||||
| @@ -251,7 +252,7 @@ static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, | ||||
|  | ||||
| 		memset(&nspare, 0, sizeof(nspare)); | ||||
|  | ||||
| 		retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, | ||||
| 		retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data, | ||||
| 					(yaffs_Spare *) &nspare); | ||||
| 		memcpy(spare, &nspare, sizeof(yaffs_Spare)); | ||||
| 		if (data && doErrorCorrection) { | ||||
| @@ -304,10 +305,10 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, | ||||
| 	static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK]; | ||||
| 	static __u8 data[YAFFS_BYTES_PER_CHUNK]; | ||||
| 	/* Might as well always allocate the larger size for */ | ||||
| 	/* dev->useNANDECC == true; */ | ||||
| 	/* dev->param.useNANDECC == true; */ | ||||
| 	static __u8 spare[sizeof(struct yaffs_NANDSpare)]; | ||||
|  | ||||
| 	dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare); | ||||
| 	dev->param.readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare); | ||||
|  | ||||
| 	if (!init) { | ||||
| 		memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK); | ||||
| @@ -330,7 +331,7 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, | ||||
|  | ||||
| static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND) | ||||
| { | ||||
| 	int blockInNAND = chunkInNAND / dev->nChunksPerBlock; | ||||
| 	int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock; | ||||
|  | ||||
| 	/* Mark the block for retirement */ | ||||
| 	yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1; | ||||
| @@ -362,7 +363,7 @@ static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, | ||||
|  | ||||
| static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND) | ||||
| { | ||||
| 	int blockInNAND = chunkInNAND / dev->nChunksPerBlock; | ||||
| 	int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock; | ||||
|  | ||||
| 	/* Mark the block for retirement */ | ||||
| 	yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; | ||||
| @@ -421,7 +422,7 @@ int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, | ||||
|  | ||||
| 		tags.serialNumber = eTags->serialNumber; | ||||
|  | ||||
| 		if (!dev->useNANDECC && data) | ||||
| 		if (!dev->param.useNANDECC && data) | ||||
| 			yaffs_CalcECC(data, &spare); | ||||
|  | ||||
| 		yaffs_LoadTagsIntoSpare(&spare, &tags); | ||||
| @@ -495,9 +496,9 @@ int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, | ||||
|  | ||||
| 	spare.blockStatus = 'Y'; | ||||
|  | ||||
| 	yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL, | ||||
| 	yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock, NULL, | ||||
| 			       &spare); | ||||
| 	yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, | ||||
| 	yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock + 1, | ||||
| 			       NULL, &spare); | ||||
|  | ||||
| 	return YAFFS_OK; | ||||
| @@ -522,9 +523,9 @@ int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, | ||||
|  | ||||
| 	*sequenceNumber = 0; | ||||
|  | ||||
| 	yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL, | ||||
| 	yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock, NULL, | ||||
| 				&spare0, &dummy, 1); | ||||
| 	yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL, | ||||
| 	yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock + 1, NULL, | ||||
| 				&spare1, &dummy, 1); | ||||
|  | ||||
| 	if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7) | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|   | ||||
							
								
								
									
										60
									
								
								fs/yaffs2/yaffs_trace.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								fs/yaffs2/yaffs_trace.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Lesser General Public License version 2.1 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #ifndef __YTRACE_H__ | ||||
| #define __YTRACE_H__ | ||||
|  | ||||
| extern unsigned int yaffs_traceMask; | ||||
| extern unsigned int yaffs_wr_attempts; | ||||
|  | ||||
| /* | ||||
|  * Tracing flags. | ||||
|  * The flags masked in YAFFS_TRACE_ALWAYS are always traced. | ||||
|  */ | ||||
|  | ||||
| #define YAFFS_TRACE_OS			0x00000002 | ||||
| #define YAFFS_TRACE_ALLOCATE		0x00000004 | ||||
| #define YAFFS_TRACE_SCAN		0x00000008 | ||||
| #define YAFFS_TRACE_BAD_BLOCKS		0x00000010 | ||||
| #define YAFFS_TRACE_ERASE		0x00000020 | ||||
| #define YAFFS_TRACE_GC			0x00000040 | ||||
| #define YAFFS_TRACE_WRITE		0x00000080 | ||||
| #define YAFFS_TRACE_TRACING		0x00000100 | ||||
| #define YAFFS_TRACE_DELETION		0x00000200 | ||||
| #define YAFFS_TRACE_BUFFERS		0x00000400 | ||||
| #define YAFFS_TRACE_NANDACCESS		0x00000800 | ||||
| #define YAFFS_TRACE_GC_DETAIL		0x00001000 | ||||
| #define YAFFS_TRACE_SCAN_DEBUG		0x00002000 | ||||
| #define YAFFS_TRACE_MTD			0x00004000 | ||||
| #define YAFFS_TRACE_CHECKPOINT		0x00008000 | ||||
|  | ||||
| #define YAFFS_TRACE_VERIFY		0x00010000 | ||||
| #define YAFFS_TRACE_VERIFY_NAND		0x00020000 | ||||
| #define YAFFS_TRACE_VERIFY_FULL		0x00040000 | ||||
| #define YAFFS_TRACE_VERIFY_ALL		0x000F0000 | ||||
|  | ||||
| #define YAFFS_TRACE_SYNC		0x00100000 | ||||
| #define YAFFS_TRACE_BACKGROUND		0x00200000 | ||||
| #define YAFFS_TRACE_LOCK		0x00400000 | ||||
|  | ||||
| #define YAFFS_TRACE_ERROR		0x40000000 | ||||
| #define YAFFS_TRACE_BUG			0x80000000 | ||||
| #define YAFFS_TRACE_ALWAYS		0xF0000000 | ||||
|  | ||||
|  | ||||
| #define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0) | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										626
									
								
								fs/yaffs2/yaffs_verify.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										626
									
								
								fs/yaffs2/yaffs_verify.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,626 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #include "yaffs_verify.h" | ||||
| #include "yaffs_trace.h" | ||||
| #include "yaffs_bitmap.h" | ||||
| #include "yaffs_getblockinfo.h" | ||||
| #include "yaffs_nand.h" | ||||
|  | ||||
| int yaffs_SkipVerification(yaffs_Device *dev) | ||||
| { | ||||
| 	dev=dev; | ||||
| 	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); | ||||
| } | ||||
|  | ||||
| static int yaffs_SkipFullVerification(yaffs_Device *dev) | ||||
| { | ||||
| 	dev=dev; | ||||
| 	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); | ||||
| } | ||||
|  | ||||
| static int yaffs_SkipNANDVerification(yaffs_Device *dev) | ||||
| { | ||||
| 	dev=dev; | ||||
| 	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); | ||||
| } | ||||
|  | ||||
|  | ||||
| static const char *blockStateName[] = { | ||||
| "Unknown", | ||||
| "Needs scanning", | ||||
| "Scanning", | ||||
| "Empty", | ||||
| "Allocating", | ||||
| "Full", | ||||
| "Dirty", | ||||
| "Checkpoint", | ||||
| "Collecting", | ||||
| "Dead" | ||||
| }; | ||||
|  | ||||
|  | ||||
| void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n) | ||||
| { | ||||
| 	int actuallyUsed; | ||||
| 	int inUse; | ||||
|  | ||||
| 	if (yaffs_SkipVerification(dev)) | ||||
| 		return; | ||||
|  | ||||
| 	/* Report illegal runtime states */ | ||||
| 	if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) | ||||
| 		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState)); | ||||
|  | ||||
| 	switch (bi->blockState) { | ||||
| 	case YAFFS_BLOCK_STATE_UNKNOWN: | ||||
| 	case YAFFS_BLOCK_STATE_SCANNING: | ||||
| 	case YAFFS_BLOCK_STATE_NEEDS_SCANNING: | ||||
| 		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR), | ||||
| 		n, blockStateName[bi->blockState])); | ||||
| 	} | ||||
|  | ||||
| 	/* Check pages in use and soft deletions are legal */ | ||||
|  | ||||
| 	actuallyUsed = bi->pagesInUse - bi->softDeletions; | ||||
|  | ||||
| 	if (bi->pagesInUse < 0 || bi->pagesInUse > dev->param.nChunksPerBlock || | ||||
| 	   bi->softDeletions < 0 || bi->softDeletions > dev->param.nChunksPerBlock || | ||||
| 	   actuallyUsed < 0 || actuallyUsed > dev->param.nChunksPerBlock) | ||||
| 		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR), | ||||
| 		n, bi->pagesInUse, bi->softDeletions)); | ||||
|  | ||||
|  | ||||
| 	/* Check chunk bitmap legal */ | ||||
| 	inUse = yaffs_CountChunkBits(dev, n); | ||||
| 	if (inUse != bi->pagesInUse) | ||||
| 		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR), | ||||
| 			n, bi->pagesInUse, inUse)); | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n) | ||||
| { | ||||
| 	yaffs_VerifyBlock(dev, bi, n); | ||||
|  | ||||
| 	/* After collection the block should be in the erased state */ | ||||
|  | ||||
| 	if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && | ||||
| 			bi->blockState != YAFFS_BLOCK_STATE_EMPTY) { | ||||
| 		T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), | ||||
| 			n, bi->blockState)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void yaffs_VerifyBlocks(yaffs_Device *dev) | ||||
| { | ||||
| 	int i; | ||||
| 	int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; | ||||
| 	int nIllegalBlockStates = 0; | ||||
|  | ||||
| 	if (yaffs_SkipVerification(dev)) | ||||
| 		return; | ||||
|  | ||||
| 	memset(nBlocksPerState, 0, sizeof(nBlocksPerState)); | ||||
|  | ||||
| 	for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { | ||||
| 		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i); | ||||
| 		yaffs_VerifyBlock(dev, bi, i); | ||||
|  | ||||
| 		if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) | ||||
| 			nBlocksPerState[bi->blockState]++; | ||||
| 		else | ||||
| 			nIllegalBlockStates++; | ||||
| 	} | ||||
|  | ||||
| 	T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); | ||||
| 	T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR))); | ||||
|  | ||||
| 	T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates)); | ||||
| 	if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) | ||||
| 		T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR))); | ||||
|  | ||||
| 	for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 		  (TSTR("%s %d blocks"TENDSTR), | ||||
| 		  blockStateName[i], nBlocksPerState[i])); | ||||
|  | ||||
| 	if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 		 (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), | ||||
| 		 dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); | ||||
|  | ||||
| 	if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 		 (TSTR("Erased block count wrong dev %d count %d"TENDSTR), | ||||
| 		 dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); | ||||
|  | ||||
| 	if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1) | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 		 (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR), | ||||
| 		 nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); | ||||
|  | ||||
| 	T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); | ||||
|  | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Verify the object header. oh must be valid, but obj and tags may be NULL in which | ||||
|  * case those tests will not be performed. | ||||
|  */ | ||||
| void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) | ||||
| { | ||||
| 	if (obj && yaffs_SkipVerification(obj->myDev)) | ||||
| 		return; | ||||
|  | ||||
| 	if (!(tags && obj && oh)) { | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 				(TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR), | ||||
| 				tags, obj, oh)); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || | ||||
| 			oh->type > YAFFS_OBJECT_TYPE_MAX) | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 			(TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), | ||||
| 			tags->objectId, oh->type)); | ||||
|  | ||||
| 	if (tags->objectId != obj->objectId) | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 			(TSTR("Obj %d header mismatch objectId %d"TENDSTR), | ||||
| 			tags->objectId, obj->objectId)); | ||||
|  | ||||
|  | ||||
| 	/* | ||||
| 	 * Check that the object's parent ids match if parentCheck requested. | ||||
| 	 * | ||||
| 	 * Tests do not apply to the root object. | ||||
| 	 */ | ||||
|  | ||||
| 	if (parentCheck && tags->objectId > 1 && !obj->parent) | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 			(TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR), | ||||
| 			tags->objectId, oh->parentObjectId)); | ||||
|  | ||||
| 	if (parentCheck && obj->parent && | ||||
| 			oh->parentObjectId != obj->parent->objectId && | ||||
| 			(oh->parentObjectId != YAFFS_OBJECTID_UNLINKED || | ||||
| 			obj->parent->objectId != YAFFS_OBJECTID_DELETED)) | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 			(TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR), | ||||
| 			tags->objectId, oh->parentObjectId, obj->parent->objectId)); | ||||
|  | ||||
| 	if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */ | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 			(TSTR("Obj %d header name is NULL"TENDSTR), | ||||
| 			obj->objectId)); | ||||
|  | ||||
| 	if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 			(TSTR("Obj %d header name is 0xFF"TENDSTR), | ||||
| 			obj->objectId)); | ||||
| } | ||||
|  | ||||
|  | ||||
| #if 0 | ||||
| /* Not being used, but don't want to throw away yet */ | ||||
| int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn, | ||||
| 					__u32 level, int chunkOffset) | ||||
| { | ||||
| 	int i; | ||||
| 	yaffs_Device *dev = obj->myDev; | ||||
| 	int ok = 1; | ||||
|  | ||||
| 	if (tn) { | ||||
| 		if (level > 0) { | ||||
|  | ||||
| 			for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { | ||||
| 				if (tn->internal[i]) { | ||||
| 					ok = yaffs_VerifyTnodeWorker(obj, | ||||
| 							tn->internal[i], | ||||
| 							level - 1, | ||||
| 							(chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i); | ||||
| 				} | ||||
| 			} | ||||
| 		} else if (level == 0) { | ||||
| 			yaffs_ExtendedTags tags; | ||||
| 			__u32 objectId = obj->objectId; | ||||
|  | ||||
| 			chunkOffset <<=  YAFFS_TNODES_LEVEL0_BITS; | ||||
|  | ||||
| 			for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) { | ||||
| 				__u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i); | ||||
|  | ||||
| 				if (theChunk > 0) { | ||||
| 					/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */ | ||||
| 					yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags); | ||||
| 					if (tags.objectId != objectId || tags.chunkId != chunkOffset) { | ||||
| 						T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), | ||||
| 							objectId, chunkOffset, theChunk, | ||||
| 							tags.objectId, tags.chunkId)); | ||||
| 					} | ||||
| 				} | ||||
| 				chunkOffset++; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return ok; | ||||
|  | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| void yaffs_VerifyFile(yaffs_Object *obj) | ||||
| { | ||||
| 	int requiredTallness; | ||||
| 	int actualTallness; | ||||
| 	__u32 lastChunk; | ||||
| 	__u32 x; | ||||
| 	__u32 i; | ||||
| 	yaffs_Device *dev; | ||||
| 	yaffs_ExtendedTags tags; | ||||
| 	yaffs_Tnode *tn; | ||||
| 	__u32 objectId; | ||||
|  | ||||
| 	if (!obj) | ||||
| 		return; | ||||
|  | ||||
| 	if (yaffs_SkipVerification(obj->myDev)) | ||||
| 		return; | ||||
|  | ||||
| 	dev = obj->myDev; | ||||
| 	objectId = obj->objectId; | ||||
|  | ||||
| 	/* Check file size is consistent with tnode depth */ | ||||
| 	lastChunk =  obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1; | ||||
| 	x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; | ||||
| 	requiredTallness = 0; | ||||
| 	while (x > 0) { | ||||
| 		x >>= YAFFS_TNODES_INTERNAL_BITS; | ||||
| 		requiredTallness++; | ||||
| 	} | ||||
|  | ||||
| 	actualTallness = obj->variant.fileVariant.topLevel; | ||||
|  | ||||
| 	/* Check that the chunks in the tnode tree are all correct. | ||||
| 	 * We do this by scanning through the tnode tree and | ||||
| 	 * checking the tags for every chunk match. | ||||
| 	 */ | ||||
|  | ||||
| 	if (yaffs_SkipNANDVerification(dev)) | ||||
| 		return; | ||||
|  | ||||
| 	for (i = 1; i <= lastChunk; i++) { | ||||
| 		tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i); | ||||
|  | ||||
| 		if (tn) { | ||||
| 			__u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i); | ||||
| 			if (theChunk > 0) { | ||||
| 				/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */ | ||||
| 				yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags); | ||||
| 				if (tags.objectId != objectId || tags.chunkId != i) { | ||||
| 					T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), | ||||
| 						objectId, i, theChunk, | ||||
| 						tags.objectId, tags.chunkId)); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| void yaffs_VerifyHardLink(yaffs_Object *obj) | ||||
| { | ||||
| 	if (obj && yaffs_SkipVerification(obj->myDev)) | ||||
| 		return; | ||||
|  | ||||
| 	/* Verify sane equivalent object */ | ||||
| } | ||||
|  | ||||
| void yaffs_VerifySymlink(yaffs_Object *obj) | ||||
| { | ||||
| 	if (obj && yaffs_SkipVerification(obj->myDev)) | ||||
| 		return; | ||||
|  | ||||
| 	/* Verify symlink string */ | ||||
| } | ||||
|  | ||||
| void yaffs_VerifySpecial(yaffs_Object *obj) | ||||
| { | ||||
| 	if (obj && yaffs_SkipVerification(obj->myDev)) | ||||
| 		return; | ||||
| } | ||||
|  | ||||
| void yaffs_VerifyObject(yaffs_Object *obj) | ||||
| { | ||||
| 	yaffs_Device *dev; | ||||
|  | ||||
| 	__u32 chunkMin; | ||||
| 	__u32 chunkMax; | ||||
|  | ||||
| 	__u32 chunkIdOk; | ||||
| 	__u32 chunkInRange; | ||||
| 	__u32 chunkShouldNotBeDeleted; | ||||
| 	__u32 chunkValid; | ||||
|  | ||||
| 	if (!obj) | ||||
| 		return; | ||||
|  | ||||
| 	if (obj->beingCreated) | ||||
| 		return; | ||||
|  | ||||
| 	dev = obj->myDev; | ||||
|  | ||||
| 	if (yaffs_SkipVerification(dev)) | ||||
| 		return; | ||||
|  | ||||
| 	/* Check sane object header chunk */ | ||||
|  | ||||
| 	chunkMin = dev->internalStartBlock * dev->param.nChunksPerBlock; | ||||
| 	chunkMax = (dev->internalEndBlock+1) * dev->param.nChunksPerBlock - 1; | ||||
|  | ||||
| 	chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax); | ||||
| 	chunkIdOk = chunkInRange || (obj->hdrChunk == 0); | ||||
| 	chunkValid = chunkInRange && | ||||
| 			yaffs_CheckChunkBit(dev, | ||||
| 					obj->hdrChunk / dev->param.nChunksPerBlock, | ||||
| 					obj->hdrChunk % dev->param.nChunksPerBlock); | ||||
| 	chunkShouldNotBeDeleted = chunkInRange && !chunkValid; | ||||
|  | ||||
| 	if (!obj->fake && | ||||
| 			(!chunkIdOk || chunkShouldNotBeDeleted)) { | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 			(TSTR("Obj %d has chunkId %d %s %s"TENDSTR), | ||||
| 			obj->objectId, obj->hdrChunk, | ||||
| 			chunkIdOk ? "" : ",out of range", | ||||
| 			chunkShouldNotBeDeleted ? ",marked as deleted" : "")); | ||||
| 	} | ||||
|  | ||||
| 	if (chunkValid && !yaffs_SkipNANDVerification(dev)) { | ||||
| 		yaffs_ExtendedTags tags; | ||||
| 		yaffs_ObjectHeader *oh; | ||||
| 		__u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); | ||||
|  | ||||
| 		oh = (yaffs_ObjectHeader *)buffer; | ||||
|  | ||||
| 		yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer, | ||||
| 				&tags); | ||||
|  | ||||
| 		yaffs_VerifyObjectHeader(obj, oh, &tags, 1); | ||||
|  | ||||
| 		yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); | ||||
| 	} | ||||
|  | ||||
| 	/* Verify it has a parent */ | ||||
| 	if (obj && !obj->fake && | ||||
| 			(!obj->parent || obj->parent->myDev != dev)) { | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 			(TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), | ||||
| 			obj->objectId, obj->parent)); | ||||
| 	} | ||||
|  | ||||
| 	/* Verify parent is a directory */ | ||||
| 	if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 			(TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), | ||||
| 			obj->objectId, obj->parent->variantType)); | ||||
| 	} | ||||
|  | ||||
| 	switch (obj->variantType) { | ||||
| 	case YAFFS_OBJECT_TYPE_FILE: | ||||
| 		yaffs_VerifyFile(obj); | ||||
| 		break; | ||||
| 	case YAFFS_OBJECT_TYPE_SYMLINK: | ||||
| 		yaffs_VerifySymlink(obj); | ||||
| 		break; | ||||
| 	case YAFFS_OBJECT_TYPE_DIRECTORY: | ||||
| 		yaffs_VerifyDirectory(obj); | ||||
| 		break; | ||||
| 	case YAFFS_OBJECT_TYPE_HARDLINK: | ||||
| 		yaffs_VerifyHardLink(obj); | ||||
| 		break; | ||||
| 	case YAFFS_OBJECT_TYPE_SPECIAL: | ||||
| 		yaffs_VerifySpecial(obj); | ||||
| 		break; | ||||
| 	case YAFFS_OBJECT_TYPE_UNKNOWN: | ||||
| 	default: | ||||
| 		T(YAFFS_TRACE_VERIFY, | ||||
| 		(TSTR("Obj %d has illegaltype %d"TENDSTR), | ||||
| 		obj->objectId, obj->variantType)); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void yaffs_VerifyObjects(yaffs_Device *dev) | ||||
| { | ||||
| 	yaffs_Object *obj; | ||||
| 	int i; | ||||
| 	struct ylist_head *lh; | ||||
|  | ||||
| 	if (yaffs_SkipVerification(dev)) | ||||
| 		return; | ||||
|  | ||||
| 	/* Iterate through the objects in each hash entry */ | ||||
|  | ||||
| 	for (i = 0; i <  YAFFS_NOBJECT_BUCKETS; i++) { | ||||
| 		ylist_for_each(lh, &dev->objectBucket[i].list) { | ||||
| 			if (lh) { | ||||
| 				obj = ylist_entry(lh, yaffs_Object, hashLink); | ||||
| 				yaffs_VerifyObject(obj); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| void yaffs_VerifyObjectInDirectory(yaffs_Object *obj) | ||||
| { | ||||
| 	struct ylist_head *lh; | ||||
| 	yaffs_Object *listObj; | ||||
|  | ||||
| 	int count = 0; | ||||
|  | ||||
| 	if (!obj) { | ||||
| 		T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR))); | ||||
| 		YBUG(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (yaffs_SkipVerification(obj->myDev)) | ||||
| 		return; | ||||
|  | ||||
| 	if (!obj->parent) { | ||||
| 		T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR))); | ||||
| 		YBUG(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { | ||||
| 		T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR))); | ||||
| 		YBUG(); | ||||
| 	} | ||||
|  | ||||
| 	/* Iterate through the objects in each hash entry */ | ||||
|  | ||||
| 	ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) { | ||||
| 		if (lh) { | ||||
| 			listObj = ylist_entry(lh, yaffs_Object, siblings); | ||||
| 			yaffs_VerifyObject(listObj); | ||||
| 			if (obj == listObj) | ||||
| 				count++; | ||||
| 		} | ||||
| 	 } | ||||
|  | ||||
| 	if (count != 1) { | ||||
| 		T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count)); | ||||
| 		YBUG(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void yaffs_VerifyDirectory(yaffs_Object *directory) | ||||
| { | ||||
| 	struct ylist_head *lh; | ||||
| 	yaffs_Object *listObj; | ||||
|  | ||||
| 	if (!directory) { | ||||
| 		YBUG(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (yaffs_SkipFullVerification(directory->myDev)) | ||||
| 		return; | ||||
|  | ||||
| 	if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { | ||||
| 		T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType)); | ||||
| 		YBUG(); | ||||
| 	} | ||||
|  | ||||
| 	/* Iterate through the objects in each hash entry */ | ||||
|  | ||||
| 	ylist_for_each(lh, &directory->variant.directoryVariant.children) { | ||||
| 		if (lh) { | ||||
| 			listObj = ylist_entry(lh, yaffs_Object, siblings); | ||||
| 			if (listObj->parent != directory) { | ||||
| 				T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent)); | ||||
| 				YBUG(); | ||||
| 			} | ||||
| 			yaffs_VerifyObjectInDirectory(listObj); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int yaffs_freeVerificationFailures; | ||||
|  | ||||
| void yaffs_VerifyFreeChunks(yaffs_Device *dev) | ||||
| { | ||||
| 	int counted; | ||||
| 	int difference; | ||||
|  | ||||
| 	if (yaffs_SkipVerification(dev)) | ||||
| 		return; | ||||
|  | ||||
| 	counted = yaffs_CountFreeChunks(dev); | ||||
|  | ||||
| 	difference = dev->nFreeChunks - counted; | ||||
|  | ||||
| 	if (difference) { | ||||
| 		T(YAFFS_TRACE_ALWAYS, | ||||
| 		  (TSTR("Freechunks verification failure %d %d %d" TENDSTR), | ||||
| 		   dev->nFreeChunks, counted, difference)); | ||||
| 		yaffs_freeVerificationFailures++; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int yaffs_VerifyFileSanity(yaffs_Object *in) | ||||
| { | ||||
| #if 0 | ||||
| 	int chunk; | ||||
| 	int nChunks; | ||||
| 	int fSize; | ||||
| 	int failed = 0; | ||||
| 	int objId; | ||||
| 	yaffs_Tnode *tn; | ||||
| 	yaffs_Tags localTags; | ||||
| 	yaffs_Tags *tags = &localTags; | ||||
| 	int theChunk; | ||||
| 	int chunkDeleted; | ||||
|  | ||||
| 	if (in->variantType != YAFFS_OBJECT_TYPE_FILE) | ||||
| 		return YAFFS_FAIL; | ||||
|  | ||||
| 	objId = in->objectId; | ||||
| 	fSize = in->variant.fileVariant.fileSize; | ||||
| 	nChunks = | ||||
| 	    (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk; | ||||
|  | ||||
| 	for (chunk = 1; chunk <= nChunks; chunk++) { | ||||
| 		tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant, | ||||
| 					   chunk); | ||||
|  | ||||
| 		if (tn) { | ||||
|  | ||||
| 			theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk); | ||||
|  | ||||
| 			if (yaffs_CheckChunkBits | ||||
| 			    (dev, theChunk / dev->param.nChunksPerBlock, | ||||
| 			     theChunk % dev->param.nChunksPerBlock)) { | ||||
|  | ||||
| 				yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk, | ||||
| 							    tags, | ||||
| 							    &chunkDeleted); | ||||
| 				if (yaffs_TagsMatch | ||||
| 				    (tags, in->objectId, chunk, chunkDeleted)) { | ||||
| 					/* found it; */ | ||||
|  | ||||
| 				} | ||||
| 			} else { | ||||
|  | ||||
| 				failed = 1; | ||||
| 			} | ||||
|  | ||||
| 		} else { | ||||
| 			/* T(("No level 0 found for %d\n", chunk)); */ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return failed ? YAFFS_FAIL : YAFFS_OK; | ||||
| #else | ||||
| 	in=in; | ||||
| 	return YAFFS_OK; | ||||
| #endif | ||||
| } | ||||
							
								
								
									
										39
									
								
								fs/yaffs2/yaffs_verify.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								fs/yaffs2/yaffs_verify.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
|  | ||||
| #ifndef __YAFFS_VERIFY_H__ | ||||
| #define __YAFFS_VERIFY_H__ | ||||
|  | ||||
| #include "yaffs_guts.h" | ||||
|  | ||||
| void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n); | ||||
| void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n); | ||||
| void yaffs_VerifyBlocks(yaffs_Device *dev); | ||||
|  | ||||
| void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck); | ||||
| void yaffs_VerifyFile(yaffs_Object *obj); | ||||
| void yaffs_VerifyHardLink(yaffs_Object *obj); | ||||
| void yaffs_VerifySymlink(yaffs_Object *obj); | ||||
| void yaffs_VerifySpecial(yaffs_Object *obj); | ||||
| void yaffs_VerifyObject(yaffs_Object *obj); | ||||
| void yaffs_VerifyObjects(yaffs_Device *dev); | ||||
| void yaffs_VerifyObjectInDirectory(yaffs_Object *obj); | ||||
| void yaffs_VerifyDirectory(yaffs_Object *directory); | ||||
| void yaffs_VerifyFreeChunks(yaffs_Device *dev); | ||||
|  | ||||
| int yaffs_VerifyFileSanity(yaffs_Object *obj); | ||||
|  | ||||
| int yaffs_SkipVerification(yaffs_Device *dev); | ||||
|  | ||||
| #endif | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										465
									
								
								fs/yaffs2/yaffs_yaffs1.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										465
									
								
								fs/yaffs2/yaffs_yaffs1.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,465 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
| #include "yaffs_yaffs1.h" | ||||
| #include "yportenv.h" | ||||
| #include "yaffs_trace.h" | ||||
| #include "yaffs_bitmap.h" | ||||
| #include "yaffs_getblockinfo.h" | ||||
| #include "yaffs_nand.h" | ||||
|  | ||||
|  | ||||
| int yaffs1_Scan(yaffs_Device *dev) | ||||
| { | ||||
| 	yaffs_ExtendedTags tags; | ||||
| 	int blk; | ||||
| 	int blockIterator; | ||||
| 	int startIterator; | ||||
| 	int endIterator; | ||||
| 	int result; | ||||
|  | ||||
| 	int chunk; | ||||
| 	int c; | ||||
| 	int deleted; | ||||
| 	yaffs_BlockState state; | ||||
| 	yaffs_Object *hardList = NULL; | ||||
| 	yaffs_BlockInfo *bi; | ||||
| 	__u32 sequenceNumber; | ||||
| 	yaffs_ObjectHeader *oh; | ||||
| 	yaffs_Object *in; | ||||
| 	yaffs_Object *parent; | ||||
|  | ||||
| 	int alloc_failed = 0; | ||||
|  | ||||
| 	struct yaffs_ShadowFixerStruct *shadowFixerList = NULL; | ||||
|  | ||||
|  | ||||
| 	__u8 *chunkData; | ||||
|  | ||||
|  | ||||
|  | ||||
| 	T(YAFFS_TRACE_SCAN, | ||||
| 	  (TSTR("yaffs1_Scan starts  intstartblk %d intendblk %d..." TENDSTR), | ||||
| 	   dev->internalStartBlock, dev->internalEndBlock)); | ||||
|  | ||||
| 	chunkData = yaffs_GetTempBuffer(dev, __LINE__); | ||||
|  | ||||
| 	dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; | ||||
|  | ||||
| 	/* Scan all the blocks to determine their state */ | ||||
| 	bi = dev->blockInfo; | ||||
| 	for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { | ||||
| 		yaffs_ClearChunkBits(dev, blk); | ||||
| 		bi->pagesInUse = 0; | ||||
| 		bi->softDeletions = 0; | ||||
|  | ||||
| 		yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); | ||||
|  | ||||
| 		bi->blockState = state; | ||||
| 		bi->sequenceNumber = sequenceNumber; | ||||
|  | ||||
| 		if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK) | ||||
| 			bi->blockState = state = YAFFS_BLOCK_STATE_DEAD; | ||||
|  | ||||
| 		T(YAFFS_TRACE_SCAN_DEBUG, | ||||
| 		  (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, | ||||
| 		   state, sequenceNumber)); | ||||
|  | ||||
| 		if (state == YAFFS_BLOCK_STATE_DEAD) { | ||||
| 			T(YAFFS_TRACE_BAD_BLOCKS, | ||||
| 			  (TSTR("block %d is bad" TENDSTR), blk)); | ||||
| 		} else if (state == YAFFS_BLOCK_STATE_EMPTY) { | ||||
| 			T(YAFFS_TRACE_SCAN_DEBUG, | ||||
| 			  (TSTR("Block empty " TENDSTR))); | ||||
| 			dev->nErasedBlocks++; | ||||
| 			dev->nFreeChunks += dev->param.nChunksPerBlock; | ||||
| 		} | ||||
| 		bi++; | ||||
| 	} | ||||
|  | ||||
| 	startIterator = dev->internalStartBlock; | ||||
| 	endIterator = dev->internalEndBlock; | ||||
|  | ||||
| 	/* For each block.... */ | ||||
| 	for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; | ||||
| 	     blockIterator++) { | ||||
|  | ||||
| 		YYIELD(); | ||||
|  | ||||
| 		YYIELD(); | ||||
|  | ||||
| 		blk = blockIterator; | ||||
|  | ||||
| 		bi = yaffs_GetBlockInfo(dev, blk); | ||||
| 		state = bi->blockState; | ||||
|  | ||||
| 		deleted = 0; | ||||
|  | ||||
| 		/* For each chunk in each block that needs scanning....*/ | ||||
| 		for (c = 0; !alloc_failed && c < dev->param.nChunksPerBlock && | ||||
| 		     state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { | ||||
| 			/* Read the tags and decide what to do */ | ||||
| 			chunk = blk * dev->param.nChunksPerBlock + c; | ||||
|  | ||||
| 			result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, | ||||
| 							&tags); | ||||
|  | ||||
| 			/* Let's have a good look at this chunk... */ | ||||
|  | ||||
| 			if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) { | ||||
| 				/* YAFFS1 only... | ||||
| 				 * A deleted chunk | ||||
| 				 */ | ||||
| 				deleted++; | ||||
| 				dev->nFreeChunks++; | ||||
| 				/*T((" %d %d deleted\n",blk,c)); */ | ||||
| 			} else if (!tags.chunkUsed) { | ||||
| 				/* An unassigned chunk in the block | ||||
| 				 * This means that either the block is empty or | ||||
| 				 * this is the one being allocated from | ||||
| 				 */ | ||||
|  | ||||
| 				if (c == 0) { | ||||
| 					/* We're looking at the first chunk in the block so the block is unused */ | ||||
| 					state = YAFFS_BLOCK_STATE_EMPTY; | ||||
| 					dev->nErasedBlocks++; | ||||
| 				} else { | ||||
| 					/* this is the block being allocated from */ | ||||
| 					T(YAFFS_TRACE_SCAN, | ||||
| 					  (TSTR | ||||
| 					   (" Allocating from %d %d" TENDSTR), | ||||
| 					   blk, c)); | ||||
| 					state = YAFFS_BLOCK_STATE_ALLOCATING; | ||||
| 					dev->allocationBlock = blk; | ||||
| 					dev->allocationPage = c; | ||||
| 					dev->allocationBlockFinder = blk; | ||||
| 					/* Set block finder here to encourage the allocator to go forth from here. */ | ||||
|  | ||||
| 				} | ||||
|  | ||||
| 				dev->nFreeChunks += (dev->param.nChunksPerBlock - c); | ||||
| 			} else if (tags.chunkId > 0) { | ||||
| 				/* chunkId > 0 so it is a data chunk... */ | ||||
| 				unsigned int endpos; | ||||
|  | ||||
| 				yaffs_SetChunkBit(dev, blk, c); | ||||
| 				bi->pagesInUse++; | ||||
|  | ||||
| 				in = yaffs_FindOrCreateObjectByNumber(dev, | ||||
| 								      tags. | ||||
| 								      objectId, | ||||
| 								      YAFFS_OBJECT_TYPE_FILE); | ||||
| 				/* PutChunkIntoFile checks for a clash (two data chunks with | ||||
| 				 * the same chunkId). | ||||
| 				 */ | ||||
|  | ||||
| 				if (!in) | ||||
| 					alloc_failed = 1; | ||||
|  | ||||
| 				if (in) { | ||||
| 					if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1)) | ||||
| 						alloc_failed = 1; | ||||
| 				} | ||||
|  | ||||
| 				endpos = | ||||
| 				    (tags.chunkId - 1) * dev->nDataBytesPerChunk + | ||||
| 				    tags.byteCount; | ||||
| 				if (in && | ||||
| 				    in->variantType == YAFFS_OBJECT_TYPE_FILE | ||||
| 				    && in->variant.fileVariant.scannedFileSize < | ||||
| 				    endpos) { | ||||
| 					in->variant.fileVariant. | ||||
| 					    scannedFileSize = endpos; | ||||
| 					if (!dev->param.useHeaderFileSize) { | ||||
| 						in->variant.fileVariant. | ||||
| 						    fileSize = | ||||
| 						    in->variant.fileVariant. | ||||
| 						    scannedFileSize; | ||||
| 					} | ||||
|  | ||||
| 				} | ||||
| 				/* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));   */ | ||||
| 			} else { | ||||
| 				/* chunkId == 0, so it is an ObjectHeader. | ||||
| 				 * Thus, we read in the object header and make the object | ||||
| 				 */ | ||||
| 				yaffs_SetChunkBit(dev, blk, c); | ||||
| 				bi->pagesInUse++; | ||||
|  | ||||
| 				result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, | ||||
| 								chunkData, | ||||
| 								NULL); | ||||
|  | ||||
| 				oh = (yaffs_ObjectHeader *) chunkData; | ||||
|  | ||||
| 				in = yaffs_FindObjectByNumber(dev, | ||||
| 							      tags.objectId); | ||||
| 				if (in && in->variantType != oh->type) { | ||||
| 					/* This should not happen, but somehow | ||||
| 					 * Wev'e ended up with an objectId that has been reused but not yet | ||||
| 					 * deleted, and worse still it has changed type. Delete the old object. | ||||
| 					 */ | ||||
|  | ||||
| 					yaffs_DeleteObject(in); | ||||
|  | ||||
| 					in = 0; | ||||
| 				} | ||||
|  | ||||
| 				in = yaffs_FindOrCreateObjectByNumber(dev, | ||||
| 								      tags. | ||||
| 								      objectId, | ||||
| 								      oh->type); | ||||
|  | ||||
| 				if (!in) | ||||
| 					alloc_failed = 1; | ||||
|  | ||||
| 				if (in && oh->shadowsObject > 0) { | ||||
|  | ||||
| 					struct yaffs_ShadowFixerStruct *fixer; | ||||
| 					fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct)); | ||||
| 					if (fixer) { | ||||
| 						fixer->next = shadowFixerList; | ||||
| 						shadowFixerList = fixer; | ||||
| 						fixer->objectId = tags.objectId; | ||||
| 						fixer->shadowedId = oh->shadowsObject; | ||||
| 						T(YAFFS_TRACE_SCAN, | ||||
| 						  (TSTR | ||||
| 						   (" Shadow fixer: %d shadows %d" TENDSTR), | ||||
| 						   fixer->objectId, fixer->shadowedId)); | ||||
|  | ||||
| 					} | ||||
|  | ||||
| 				} | ||||
|  | ||||
| 				if (in && in->valid) { | ||||
| 					/* We have already filled this one. We have a duplicate and need to resolve it. */ | ||||
|  | ||||
| 					unsigned existingSerial = in->serial; | ||||
| 					unsigned newSerial = tags.serialNumber; | ||||
|  | ||||
| 					if (((existingSerial + 1) & 3) == newSerial) { | ||||
| 						/* Use new one - destroy the exisiting one */ | ||||
| 						yaffs_DeleteChunk(dev, | ||||
| 								  in->hdrChunk, | ||||
| 								  1, __LINE__); | ||||
| 						in->valid = 0; | ||||
| 					} else { | ||||
| 						/* Use existing - destroy this one. */ | ||||
| 						yaffs_DeleteChunk(dev, chunk, 1, | ||||
| 								  __LINE__); | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				if (in && !in->valid && | ||||
| 				    (tags.objectId == YAFFS_OBJECTID_ROOT || | ||||
| 				     tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) { | ||||
| 					/* We only load some info, don't fiddle with directory structure */ | ||||
| 					in->valid = 1; | ||||
| 					in->variantType = oh->type; | ||||
|  | ||||
| 					in->yst_mode = oh->yst_mode; | ||||
| #ifdef CONFIG_YAFFS_WINCE | ||||
| 					in->win_atime[0] = oh->win_atime[0]; | ||||
| 					in->win_ctime[0] = oh->win_ctime[0]; | ||||
| 					in->win_mtime[0] = oh->win_mtime[0]; | ||||
| 					in->win_atime[1] = oh->win_atime[1]; | ||||
| 					in->win_ctime[1] = oh->win_ctime[1]; | ||||
| 					in->win_mtime[1] = oh->win_mtime[1]; | ||||
| #else | ||||
| 					in->yst_uid = oh->yst_uid; | ||||
| 					in->yst_gid = oh->yst_gid; | ||||
| 					in->yst_atime = oh->yst_atime; | ||||
| 					in->yst_mtime = oh->yst_mtime; | ||||
| 					in->yst_ctime = oh->yst_ctime; | ||||
| 					in->yst_rdev = oh->yst_rdev; | ||||
| #endif | ||||
| 					in->hdrChunk = chunk; | ||||
| 					in->serial = tags.serialNumber; | ||||
|  | ||||
| 				} else if (in && !in->valid) { | ||||
| 					/* we need to load this info */ | ||||
|  | ||||
| 					in->valid = 1; | ||||
| 					in->variantType = oh->type; | ||||
|  | ||||
| 					in->yst_mode = oh->yst_mode; | ||||
| #ifdef CONFIG_YAFFS_WINCE | ||||
| 					in->win_atime[0] = oh->win_atime[0]; | ||||
| 					in->win_ctime[0] = oh->win_ctime[0]; | ||||
| 					in->win_mtime[0] = oh->win_mtime[0]; | ||||
| 					in->win_atime[1] = oh->win_atime[1]; | ||||
| 					in->win_ctime[1] = oh->win_ctime[1]; | ||||
| 					in->win_mtime[1] = oh->win_mtime[1]; | ||||
| #else | ||||
| 					in->yst_uid = oh->yst_uid; | ||||
| 					in->yst_gid = oh->yst_gid; | ||||
| 					in->yst_atime = oh->yst_atime; | ||||
| 					in->yst_mtime = oh->yst_mtime; | ||||
| 					in->yst_ctime = oh->yst_ctime; | ||||
| 					in->yst_rdev = oh->yst_rdev; | ||||
| #endif | ||||
| 					in->hdrChunk = chunk; | ||||
| 					in->serial = tags.serialNumber; | ||||
|  | ||||
| 					yaffs_SetObjectNameFromOH(in, oh); | ||||
| 					in->dirty = 0; | ||||
|  | ||||
| 					/* directory stuff... | ||||
| 					 * hook up to parent | ||||
| 					 */ | ||||
|  | ||||
| 					parent = | ||||
| 					    yaffs_FindOrCreateObjectByNumber | ||||
| 					    (dev, oh->parentObjectId, | ||||
| 					     YAFFS_OBJECT_TYPE_DIRECTORY); | ||||
| 					if (!parent) | ||||
| 						alloc_failed = 1; | ||||
| 					if (parent && parent->variantType == | ||||
| 					    YAFFS_OBJECT_TYPE_UNKNOWN) { | ||||
| 						/* Set up as a directory */ | ||||
| 						parent->variantType = | ||||
| 							YAFFS_OBJECT_TYPE_DIRECTORY; | ||||
| 						YINIT_LIST_HEAD(&parent->variant. | ||||
| 								directoryVariant. | ||||
| 								children); | ||||
| 					} else if (!parent || parent->variantType != | ||||
| 						   YAFFS_OBJECT_TYPE_DIRECTORY) { | ||||
| 						/* Hoosterman, another problem.... | ||||
| 						 * We're trying to use a non-directory as a directory | ||||
| 						 */ | ||||
|  | ||||
| 						T(YAFFS_TRACE_ERROR, | ||||
| 						  (TSTR | ||||
| 						   ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." | ||||
| 						    TENDSTR))); | ||||
| 						parent = dev->lostNFoundDir; | ||||
| 					} | ||||
|  | ||||
| 					yaffs_AddObjectToDirectory(parent, in); | ||||
|  | ||||
| 					if (0 && (parent == dev->deletedDir || | ||||
| 						  parent == dev->unlinkedDir)) { | ||||
| 						in->deleted = 1;	/* If it is unlinked at start up then it wants deleting */ | ||||
| 						dev->nDeletedFiles++; | ||||
| 					} | ||||
| 					/* Note re hardlinks. | ||||
| 					 * Since we might scan a hardlink before its equivalent object is scanned | ||||
| 					 * we put them all in a list. | ||||
| 					 * After scanning is complete, we should have all the objects, so we run through this | ||||
| 					 * list and fix up all the chains. | ||||
| 					 */ | ||||
|  | ||||
| 					switch (in->variantType) { | ||||
| 					case YAFFS_OBJECT_TYPE_UNKNOWN: | ||||
| 						/* Todo got a problem */ | ||||
| 						break; | ||||
| 					case YAFFS_OBJECT_TYPE_FILE: | ||||
| 						if (dev->param.useHeaderFileSize) | ||||
|  | ||||
| 							in->variant.fileVariant. | ||||
| 							    fileSize = | ||||
| 							    oh->fileSize; | ||||
|  | ||||
| 						break; | ||||
| 					case YAFFS_OBJECT_TYPE_HARDLINK: | ||||
| 						in->variant.hardLinkVariant. | ||||
| 							equivalentObjectId = | ||||
| 							oh->equivalentObjectId; | ||||
| 						in->hardLinks.next = | ||||
| 							(struct ylist_head *) | ||||
| 							hardList; | ||||
| 						hardList = in; | ||||
| 						break; | ||||
| 					case YAFFS_OBJECT_TYPE_DIRECTORY: | ||||
| 						/* Do nothing */ | ||||
| 						break; | ||||
| 					case YAFFS_OBJECT_TYPE_SPECIAL: | ||||
| 						/* Do nothing */ | ||||
| 						break; | ||||
| 					case YAFFS_OBJECT_TYPE_SYMLINK: | ||||
| 						in->variant.symLinkVariant.alias = | ||||
| 						    yaffs_CloneString(oh->alias); | ||||
| 						if (!in->variant.symLinkVariant.alias) | ||||
| 							alloc_failed = 1; | ||||
| 						break; | ||||
| 					} | ||||
|  | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { | ||||
| 			/* If we got this far while scanning, then the block is fully allocated.*/ | ||||
| 			state = YAFFS_BLOCK_STATE_FULL; | ||||
| 		} | ||||
|  | ||||
| 		if (state == YAFFS_BLOCK_STATE_ALLOCATING) { | ||||
| 			/* If the block was partially allocated then treat it as fully allocated.*/ | ||||
| 			state = YAFFS_BLOCK_STATE_FULL; | ||||
| 			dev->allocationBlock = -1; | ||||
| 		} | ||||
|  | ||||
| 		bi->blockState = state; | ||||
|  | ||||
| 		/* Now let's see if it was dirty */ | ||||
| 		if (bi->pagesInUse == 0 && | ||||
| 		    !bi->hasShrinkHeader && | ||||
| 		    bi->blockState == YAFFS_BLOCK_STATE_FULL) { | ||||
| 			yaffs_BlockBecameDirty(dev, blk); | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	/* Ok, we've done all the scanning. | ||||
| 	 * Fix up the hard link chains. | ||||
| 	 * We should now have scanned all the objects, now it's time to add these | ||||
| 	 * hardlinks. | ||||
| 	 */ | ||||
|  | ||||
| 	yaffs_HardlinkFixup(dev, hardList); | ||||
|  | ||||
| 	/* Fix up any shadowed objects */ | ||||
| 	{ | ||||
| 		struct yaffs_ShadowFixerStruct *fixer; | ||||
| 		yaffs_Object *obj; | ||||
|  | ||||
| 		while (shadowFixerList) { | ||||
| 			fixer = shadowFixerList; | ||||
| 			shadowFixerList = fixer->next; | ||||
| 			/* Complete the rename transaction by deleting the shadowed object | ||||
| 			 * then setting the object header to unshadowed. | ||||
| 			 */ | ||||
| 			obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId); | ||||
| 			if (obj) | ||||
| 				yaffs_DeleteObject(obj); | ||||
|  | ||||
| 			obj = yaffs_FindObjectByNumber(dev, fixer->objectId); | ||||
|  | ||||
| 			if (obj) | ||||
| 				yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL); | ||||
|  | ||||
| 			YFREE(fixer); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); | ||||
|  | ||||
| 	if (alloc_failed) | ||||
| 		return YAFFS_FAIL; | ||||
|  | ||||
| 	T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_Scan ends" TENDSTR))); | ||||
|  | ||||
|  | ||||
| 	return YAFFS_OK; | ||||
| } | ||||
|  | ||||
							
								
								
									
										22
									
								
								fs/yaffs2/yaffs_yaffs1.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								fs/yaffs2/yaffs_yaffs1.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Lesser General Public License version 2.1 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * | ||||
|  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. | ||||
|  */ | ||||
|  | ||||
| #ifndef __YAFFS_YAFFS1_H__ | ||||
| #define __YAFFS_YAFFS1_H__ | ||||
|  | ||||
| #include "yaffs_guts.h" | ||||
| int yaffs1_Scan(yaffs_Device *dev); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1540
									
								
								fs/yaffs2/yaffs_yaffs2.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1540
									
								
								fs/yaffs2/yaffs_yaffs2.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										36
									
								
								fs/yaffs2/yaffs_yaffs2.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								fs/yaffs2/yaffs_yaffs2.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| /* | ||||
|  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
|  | ||||
| #ifndef __YAFFS_YAFFS2_H__ | ||||
| #define __YAFFS_YAFFS2_H__ | ||||
|  | ||||
| #include "yaffs_guts.h" | ||||
|  | ||||
| void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev); | ||||
| void yaffs2_FindOldestDirtySequence(yaffs_Device *dev); | ||||
| void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi); | ||||
| void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi); | ||||
| int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi); | ||||
| __u32 yaffs2_FindRefreshBlock(yaffs_Device *dev); | ||||
| int yaffs2_CheckpointRequired(yaffs_Device *dev); | ||||
| int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev); | ||||
|  | ||||
|  | ||||
| void yaffs2_InvalidateCheckpoint(yaffs_Device *dev); | ||||
| int yaffs2_CheckpointSave(yaffs_Device *dev); | ||||
| int yaffs2_CheckpointRestore(yaffs_Device *dev); | ||||
|  | ||||
| int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize); | ||||
| int yaffs2_ScanBackwards(yaffs_Device *dev); | ||||
|  | ||||
| #endif | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * YAFFS: Yet another Flash File System . A NAND-flash specific file system. | ||||
|  * | ||||
|  * Copyright (C) 2002-2007 Aleph One Ltd. | ||||
|  * Copyright (C) 2002-2010 Aleph One Ltd. | ||||
|  *   for Toby Churchill Ltd and Brightstar Engineering | ||||
|  * | ||||
|  * Created by Charles Manning <charles@aleph1.co.uk> | ||||
| @@ -41,12 +41,14 @@ | ||||
| #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) | ||||
| #include <linux/config.h> | ||||
| #endif | ||||
|  | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/mm.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/string.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/vmalloc.h> | ||||
| #include <linux/xattr.h> | ||||
|  | ||||
| #define YCHAR char | ||||
| #define YUCHAR unsigned char | ||||
| @@ -55,11 +57,11 @@ | ||||
| #define yaffs_strcpy(a, b)     strcpy(a, b) | ||||
| #define yaffs_strncpy(a, b, c) strncpy(a, b, c) | ||||
| #define yaffs_strncmp(a, b, c) strncmp(a, b, c) | ||||
| #define yaffs_strlen(s)	       strlen(s) | ||||
| #define yaffs_strnlen(s,m)	strnlen(s,m) | ||||
| #define yaffs_sprintf	       sprintf | ||||
| #define yaffs_toupper(a)       toupper(a) | ||||
|  | ||||
| #define Y_INLINE inline | ||||
| #define Y_INLINE __inline__ | ||||
|  | ||||
| #define YAFFS_LOSTNFOUND_NAME		"lost+found" | ||||
| #define YAFFS_LOSTNFOUND_PREFIX		"obj" | ||||
| @@ -71,11 +73,11 @@ | ||||
| #define YFREE_ALT(x)   vfree(x) | ||||
| #define YMALLOC_DMA(x) YMALLOC(x) | ||||
|  | ||||
| /* KR - added for use in scan so processes aren't blocked indefinitely. */ | ||||
| #define YYIELD() schedule() | ||||
| #define Y_DUMP_STACK() dump_stack() | ||||
|  | ||||
| #define YAFFS_ROOT_MODE			0666 | ||||
| #define YAFFS_LOSTNFOUND_MODE		0666 | ||||
| #define YAFFS_ROOT_MODE			0755 | ||||
| #define YAFFS_LOSTNFOUND_MODE		0700 | ||||
|  | ||||
| #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) | ||||
| #define Y_CURRENT_TIME CURRENT_TIME.tv_sec | ||||
| @@ -89,15 +91,10 @@ | ||||
| #define yaffs_strcmp(a, b) strcmp(a, b) | ||||
|  | ||||
| #define TENDSTR "\n" | ||||
| #define TSTR(x) KERN_WARNING x | ||||
| #define TSTR(x) KERN_DEBUG x | ||||
| #define TCONT(x) x | ||||
| #define TOUT(p) printk p | ||||
|  | ||||
| #define yaffs_trace(mask, fmt, args...) \ | ||||
| 	do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \ | ||||
| 		printk(KERN_WARNING "yaffs: " fmt, ## args); \ | ||||
| 	} while (0) | ||||
|  | ||||
| #define compile_time_assertion(assertion) \ | ||||
| 	({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) | ||||
|  | ||||
| @@ -116,7 +113,6 @@ | ||||
| #include "stdio.h" | ||||
| #include "string.h" | ||||
|  | ||||
| #include "devextras.h" | ||||
|  | ||||
| #define YMALLOC(x) malloc(x) | ||||
| #define YFREE(x)   free(x) | ||||
| @@ -129,7 +125,7 @@ | ||||
| #define yaffs_strcat(a, b)     strcat(a, b) | ||||
| #define yaffs_strcpy(a, b)     strcpy(a, b) | ||||
| #define yaffs_strncpy(a, b, c) strncpy(a, b, c) | ||||
| #define yaffs_strlen(s)	       strlen(s) | ||||
| #define yaffs_strnlen(s,m)	       strnlen(s,m) | ||||
| #define yaffs_sprintf	       sprintf | ||||
| #define yaffs_toupper(a)       toupper(a) | ||||
|  | ||||
| @@ -146,8 +142,8 @@ | ||||
| #define YAFFS_LOSTNFOUND_PREFIX		"obj" | ||||
| /* #define YPRINTF(x) printf x */ | ||||
|  | ||||
| #define YAFFS_ROOT_MODE				0666 | ||||
| #define YAFFS_LOSTNFOUND_MODE		0666 | ||||
| #define YAFFS_ROOT_MODE			0755 | ||||
| #define YAFFS_LOSTNFOUND_MODE		0700 | ||||
|  | ||||
| #define yaffs_SumCompare(x, y) ((x) == (y)) | ||||
| #define yaffs_strcmp(a, b) strcmp(a, b) | ||||
| @@ -158,46 +154,180 @@ | ||||
|  | ||||
| #endif | ||||
|  | ||||
| /* see yaffs_fs.c */ | ||||
| extern unsigned int yaffs_traceMask; | ||||
| extern unsigned int yaffs_wr_attempts; | ||||
| #if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE) | ||||
|  | ||||
| /* | ||||
|  * Tracing flags. | ||||
|  * The flags masked in YAFFS_TRACE_ALWAYS are always traced. | ||||
|  */ | ||||
| #ifdef CONFIG_YAFFSFS_PROVIDE_VALUES | ||||
|  | ||||
| #define YAFFS_TRACE_OS			0x00000002 | ||||
| #define YAFFS_TRACE_ALLOCATE		0x00000004 | ||||
| #define YAFFS_TRACE_SCAN		0x00000008 | ||||
| #define YAFFS_TRACE_BAD_BLOCKS		0x00000010 | ||||
| #define YAFFS_TRACE_ERASE		0x00000020 | ||||
| #define YAFFS_TRACE_GC			0x00000040 | ||||
| #define YAFFS_TRACE_WRITE		0x00000080 | ||||
| #define YAFFS_TRACE_TRACING		0x00000100 | ||||
| #define YAFFS_TRACE_DELETION		0x00000200 | ||||
| #define YAFFS_TRACE_BUFFERS		0x00000400 | ||||
| #define YAFFS_TRACE_NANDACCESS		0x00000800 | ||||
| #define YAFFS_TRACE_GC_DETAIL		0x00001000 | ||||
| #define YAFFS_TRACE_SCAN_DEBUG		0x00002000 | ||||
| #define YAFFS_TRACE_MTD			0x00004000 | ||||
| #define YAFFS_TRACE_CHECKPOINT		0x00008000 | ||||
| #ifndef O_RDONLY | ||||
| #define O_RDONLY        00 | ||||
| #endif | ||||
|  | ||||
| #define YAFFS_TRACE_VERIFY		0x00010000 | ||||
| #define YAFFS_TRACE_VERIFY_NAND		0x00020000 | ||||
| #define YAFFS_TRACE_VERIFY_FULL		0x00040000 | ||||
| #define YAFFS_TRACE_VERIFY_ALL		0x000F0000 | ||||
| #define YAFFS_TRACE_HTC_DEBUG		0x00100000 | ||||
| #ifndef O_WRONLY | ||||
| #define O_WRONLY	01 | ||||
| #endif | ||||
|  | ||||
| #define YAFFS_TRACE_ERROR		0x40000000 | ||||
| #define YAFFS_TRACE_BUG			0x80000000 | ||||
| #define YAFFS_TRACE_ALWAYS		0xF0000000 | ||||
| #ifndef O_RDWR | ||||
| #define O_RDWR		02 | ||||
| #endif | ||||
|  | ||||
| #ifndef O_CREAT		 | ||||
| #define O_CREAT 	0100 | ||||
| #endif | ||||
|  | ||||
| #ifndef O_EXCL | ||||
| #define O_EXCL		0200 | ||||
| #endif | ||||
|  | ||||
| #ifndef O_TRUNC | ||||
| #define O_TRUNC		01000 | ||||
| #endif | ||||
|  | ||||
| #ifndef O_APPEND | ||||
| #define O_APPEND	02000 | ||||
| #endif | ||||
|  | ||||
| #ifndef SEEK_SET | ||||
| #define SEEK_SET	0 | ||||
| #endif | ||||
|  | ||||
| #ifndef SEEK_CUR | ||||
| #define SEEK_CUR	1 | ||||
| #endif | ||||
|  | ||||
| #ifndef SEEK_END | ||||
| #define SEEK_END	2 | ||||
| #endif | ||||
|  | ||||
| #ifndef EBUSY | ||||
| #define EBUSY	16 | ||||
| #endif | ||||
|  | ||||
| #ifndef ENODEV | ||||
| #define ENODEV	19 | ||||
| #endif | ||||
|  | ||||
| #ifndef EINVAL | ||||
| #define EINVAL	22 | ||||
| #endif | ||||
|  | ||||
| #ifndef EBADF | ||||
| #define EBADF	9 | ||||
| #endif | ||||
|  | ||||
| #ifndef EACCES | ||||
| #define EACCES	13 | ||||
| #endif | ||||
|  | ||||
| #ifndef EXDEV	 | ||||
| #define EXDEV	18 | ||||
| #endif | ||||
|  | ||||
| #ifndef ENOENT | ||||
| #define ENOENT	2 | ||||
| #endif | ||||
|  | ||||
| #ifndef ENOSPC | ||||
| #define ENOSPC	28 | ||||
| #endif | ||||
|  | ||||
| #ifndef ERANGE | ||||
| #define ERANGE 34 | ||||
| #endif | ||||
|  | ||||
| #ifndef ENODATA | ||||
| #define ENODATA 61 | ||||
| #endif | ||||
|  | ||||
| #ifndef ENOTEMPTY | ||||
| #define ENOTEMPTY 39 | ||||
| #endif | ||||
|  | ||||
| #ifndef ENAMETOOLONG | ||||
| #define ENAMETOOLONG 36 | ||||
| #endif | ||||
|  | ||||
| #ifndef ENOMEM | ||||
| #define ENOMEM 12 | ||||
| #endif | ||||
|  | ||||
| #ifndef EEXIST | ||||
| #define EEXIST 17 | ||||
| #endif | ||||
|  | ||||
| #ifndef ENOTDIR | ||||
| #define ENOTDIR 20 | ||||
| #endif | ||||
|  | ||||
| #ifndef EISDIR | ||||
| #define EISDIR 21 | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0) | ||||
| // Mode flags | ||||
|  | ||||
| #ifndef S_IFMT | ||||
| #define S_IFMT		0170000 | ||||
| #endif | ||||
|  | ||||
| #ifndef S_IFLNK | ||||
| #define S_IFLNK		0120000 | ||||
| #endif | ||||
|  | ||||
| #ifndef S_IFDIR | ||||
| #define S_IFDIR		0040000 | ||||
| #endif | ||||
|  | ||||
| #ifndef S_IFREG | ||||
| #define S_IFREG		0100000 | ||||
| #endif | ||||
|  | ||||
| #ifndef S_IREAD  | ||||
| #define S_IREAD		0000400 | ||||
| #endif | ||||
|  | ||||
| #ifndef S_IWRITE | ||||
| #define	S_IWRITE	0000200 | ||||
| #endif | ||||
|  | ||||
| #ifndef S_IEXEC | ||||
| #define	S_IEXEC	0000100 | ||||
| #endif | ||||
|  | ||||
| #ifndef XATTR_CREATE | ||||
| #define XATTR_CREATE 1 | ||||
| #endif | ||||
|  | ||||
| #ifndef XATTR_REPLACE | ||||
| #define XATTR_REPLACE 2 | ||||
| #endif | ||||
|  | ||||
| #ifndef R_OK | ||||
| #define R_OK	4 | ||||
| #define W_OK	2 | ||||
| #define X_OK	1 | ||||
| #define F_OK	0 | ||||
| #endif | ||||
|  | ||||
| #else | ||||
| #include <errno.h> | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #ifndef Y_DUMP_STACK | ||||
| #define Y_DUMP_STACK() do { } while (0) | ||||
| #endif | ||||
|  | ||||
| #ifndef YBUG | ||||
| #define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0) | ||||
| #define YBUG() do {\ | ||||
| 	T(YAFFS_TRACE_BUG,\ | ||||
| 		(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\ | ||||
| 		__LINE__));\ | ||||
| 	Y_DUMP_STACK();\ | ||||
| } while (0) | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #endif | ||||
|   | ||||
		Reference in New Issue
	
	Block a user