summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kconfig20
-rw-r--r--direct/Makefile4
-rw-r--r--direct/yaffs_fileem2k.c9
-rw-r--r--yaffs_guts.c113
-rw-r--r--yaffs_guts.h6
-rw-r--r--yaffs_mtdif2.c5
-rw-r--r--yaffs_nand.c22
-rw-r--r--yaffs_packedtags2.c18
8 files changed, 151 insertions, 46 deletions
diff --git a/Kconfig b/Kconfig
index f314f60..9cc372e 100644
--- a/Kconfig
+++ b/Kconfig
@@ -105,15 +105,21 @@ config YAFFS_DISABLE_WIDE_TNODES
If unsure, say N.
-config YAFFS_DISABLE_CHUNK_ERASED_CHECK
- bool "Turn off debug chunk erase check"
+config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
+ bool "Force chunk erase check"
depends on YAFFS_FS
- default y
+ default n
help
- Enabling this turns off the test that chunks are erased in flash
- before writing to them. This is safe, since the write verification
- will fail. Suggest enabling the test (ie. say N)
- during development to help debug things.
+ Normally YAFFS only checks chunks before writing until an erased
+ chunk is found. This helps to detect any partially written chunks
+ that might have happened due to power loss.
+
+ Enabling this forces on the test that chunks are erased in flash
+ before writing to them. This takes more time but is potentially a
+ bit more secure.
+
+ Suggest setting Y during development and ironing out driver issues
+ etc. Suggest setting to N if you want faster writing.
If unsure, say Y.
diff --git a/direct/Makefile b/direct/Makefile
index ff9ac16..47a25a9 100644
--- a/direct/Makefile
+++ b/direct/Makefile
@@ -10,9 +10,9 @@
#
# NB Warning this Makefile does not include header dependencies.
#
-# $Id: Makefile,v 1.10 2006-05-21 09:39:12 charles Exp $
+# $Id: Makefile,v 1.11 2006-09-21 08:13:59 charles Exp $
-EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
+#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
CFLAGS = -Wall -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -g $(EXTRA_COMPILE_FLAGS)
#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations
diff --git a/direct/yaffs_fileem2k.c b/direct/yaffs_fileem2k.c
index 4c5e200..7e867f6 100644
--- a/direct/yaffs_fileem2k.c
+++ b/direct/yaffs_fileem2k.c
@@ -15,7 +15,7 @@
// This provides a YAFFS nand emulation on a file for emulating 2kB pages.
// THis is only intended as test code to test persistence etc.
-const char *yaffs_flashif_c_version = "$Id: yaffs_fileem2k.c,v 1.4 2005-07-18 23:12:00 charles Exp $";
+const char *yaffs_flashif_c_version = "$Id: yaffs_fileem2k.c,v 1.5 2006-09-21 08:13:59 charles Exp $";
#include "yportenv.h"
@@ -55,6 +55,8 @@ typedef struct
static yflash_Device filedisk;
+int yaffs_testPartialWrite = 0;
+
static int CheckInit(void)
{
static int initialised = 0;
@@ -138,6 +140,11 @@ int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8
lseek(filedisk.handle,pos,SEEK_SET);
written = write(filedisk.handle,data,dev->nBytesPerChunk);
+ if(yaffs_testPartialWrite){
+ close(filedisk.handle);
+ exit(1);
+ }
+
if(written != dev->nBytesPerChunk) return YAFFS_FAIL;
}
diff --git a/yaffs_guts.c b/yaffs_guts.c
index 6b42a9c..db47608 100644
--- a/yaffs_guts.c
+++ b/yaffs_guts.c
@@ -13,7 +13,7 @@
*/
const char *yaffs_guts_c_version =
- "$Id: yaffs_guts.c,v 1.36 2006-09-05 23:23:34 charles Exp $";
+ "$Id: yaffs_guts.c,v 1.37 2006-09-21 08:13:59 charles Exp $";
#include "yportenv.h"
@@ -44,7 +44,7 @@ void yfsd_UnlockYAFFS(BOOL fsLockOnly);
/* Robustification (if it ever comes about...) */
static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND);
-static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);
+static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk);
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags * tags);
@@ -93,7 +93,7 @@ static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId,
loff_t yaffs_GetFileSize(yaffs_Object * obj);
-static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve);
+static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr);
static void yaffs_VerifyFreeChunks(yaffs_Device * dev);
@@ -299,6 +299,10 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
yaffs_ExtendedTags tags;
yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
+
+ if(tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
+ retval = YAFFS_FAIL;
+
if (!yaffs_CheckFF(data, dev->nBytesPerChunk) || tags.chunkUsed) {
T(YAFFS_TRACE_NANDACCESS,
@@ -319,21 +323,46 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
{
int chunk;
- int writeOk = 1;
+ int writeOk = 0;
+ int erasedOk = 1;
int attempts = 0;
+ yaffs_BlockInfo *bi;
yaffs_InvalidateCheckpoint(dev);
do {
- chunk = yaffs_AllocateChunk(dev, useReserve);
+ chunk = yaffs_AllocateChunk(dev, useReserve,&bi);
if (chunk >= 0) {
-
- /* First check this chunk is erased... */
-#ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
- writeOk = yaffs_CheckChunkErased(dev, chunk);
+ /* First check this chunk is erased, if it needs checking.
+ * The checking policy (unless forced always on) is as follows:
+ * Check the first page we try to write in a block.
+ * - If the check passes then we don't need to check any more.
+ * - If the check fails, we check again...
+ * If the block has been erased, we don't need to check.
+ *
+ * However, if the block has been prioritised for gc, then
+ * we think there might be something odd about this block
+ * and should continue doing erased checks.
+ *
+ * Rationale:
+ * We should only ever see chunks that have not been erased
+ * if there was a partially written chunk due to power loss
+ * This checking policy should catch that case with very
+ * few checks and thus save a lot of checks that are most likely not
+ * needed.
+ */
+
+#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
+ bi->skipErasedCheck = 1;
#endif
- if (!writeOk) {
+ if(!bi->skipErasedCheck){
+ erasedOk = yaffs_CheckChunkErased(dev, chunk);
+ if(erasedOk && !bi->gcPrioritise)
+ bi->skipErasedCheck = 1;
+ }
+
+ if (!erasedOk) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>> yaffs chunk %d was not erased"
@@ -343,6 +372,7 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
yaffs_WriteChunkWithTagsToNAND(dev, chunk,
data, tags);
}
+
attempts++;
if (writeOk) {
@@ -351,10 +381,11 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
* NB We do this at the end to prevent duplicates in the case of a write error.
* Todo
*/
- yaffs_HandleWriteChunkOk(dev, chunk, data,
- tags);
+ yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
+
} else {
- yaffs_HandleWriteChunkError(dev, chunk);
+ /* The erased check or write failed */
+ yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
}
}
@@ -403,12 +434,19 @@ static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
{
}
-static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
+static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk)
{
+
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
+ bi->gcPrioritise = 1;
+
+ if(erasedOk) {
+ /* Was an actual write failure, so mark the block for retirement */
- /* Mark the block for retirement */
- yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
+ bi->needsRetiring = 1;
+ }
+
/* Delete the chunk */
yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
}
@@ -1895,6 +1933,7 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev,
int iterations;
int dirtiest = -1;
int pagesInUse;
+ int prioritised;
yaffs_BlockInfo *bi;
static int nonAggressiveSkip = 0;
@@ -1925,7 +1964,7 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev,
}
}
- for (i = 0; i <= iterations && pagesInUse > 0; i++) {
+ for (i = 0, prioritised = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
b++;
if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
b = dev->internalStartBlock;
@@ -1948,10 +1987,12 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev,
#endif
if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
- (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
+ (bi->gcPrioritise || (bi->pagesInUse - bi->softDeletions)) < pagesInUse &&
yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
dirtiest = b;
pagesInUse = (bi->pagesInUse - bi->softDeletions);
+ if(bi->gcPrioritise)
+ prioritised = 1; /* Trick it into selecting this one */
}
}
@@ -1959,8 +2000,8 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev,
if (dirtiest > 0) {
T(YAFFS_TRACE_GC,
- (TSTR("GC Selected block %d with %d free" TENDSTR), dirtiest,
- dev->nChunksPerBlock - pagesInUse));
+ (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
+ dev->nChunksPerBlock - pagesInUse,prioritised));
}
dev->oldestDirtySequence = 0;
@@ -2013,6 +2054,8 @@ static void yaffs_BlockBecameDirty(yaffs_Device * dev, int blockNo)
bi->pagesInUse = 0;
bi->softDeletions = 0;
bi->hasShrinkHeader = 0;
+ bi->skipErasedCheck = 1; /* This is clean, so no need to check */
+ bi->gcPrioritise = 0;
yaffs_ClearChunkBits(dev, blockNo);
T(YAFFS_TRACE_ERASE,
@@ -2092,7 +2135,7 @@ static int yaffs_CheckSpaceForAllocation(yaffs_Device * dev)
return (dev->nFreeChunks > reservedChunks);
}
-static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve)
+static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr)
{
int retVal;
yaffs_BlockInfo *bi;
@@ -2133,6 +2176,9 @@ static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve)
dev->allocationBlock = -1;
}
+ if(blockUsedPtr)
+ *blockUsedPtr = bi;
+
return retVal;
}
@@ -5028,6 +5074,7 @@ static int yaffs_ScanBackwards(yaffs_Device * dev)
int fileSize;
int isShrink;
+ int foundChunksInBlock;
int equivalentObjectId;
@@ -5177,6 +5224,7 @@ static int yaffs_ScanBackwards(yaffs_Device * dev)
deleted = 0;
/* For each chunk in each block that needs scanning.... */
+ foundChunksInBlock = 0;
for (c = dev->nChunksPerBlock - 1; c >= 0 &&
(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
@@ -5191,11 +5239,20 @@ static int yaffs_ScanBackwards(yaffs_Device * dev)
/* Let's have a good look at this chunk... */
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
+ /* An unassigned chunk in the block.
+ * If there are used chunks after this one, then
+ * it is a chunk that was skipped due to failing the erased
+ * check. Just skip it so that it can be deleted.
+ * But, more typically, We get here when this is an unallocated
+ * chunk and his means that either the block is empty or
+ * this is the one being allocated from
+ */
- if (c == 0) {
+ if(foundChunksInBlock)
+ {
+ /* This is a chunk that was skipped due to failing the erased check */
+
+ } else if (c == 0) {
/* We're looking at the first chunk in the block so the block is unused */
state = YAFFS_BLOCK_STATE_EMPTY;
dev->nErasedBlocks++;
@@ -5236,9 +5293,11 @@ static int yaffs_ScanBackwards(yaffs_Device * dev)
} else if (tags.chunkId > 0) {
/* chunkId > 0 so it is a data chunk... */
unsigned int endpos;
-
__u32 chunkBase =
(tags.chunkId - 1) * dev->nBytesPerChunk;
+
+ foundChunksInBlock = 1;
+
yaffs_SetChunkBit(dev, blk, c);
bi->pagesInUse++;
@@ -5282,6 +5341,8 @@ static int yaffs_ScanBackwards(yaffs_Device * dev)
/* chunkId == 0, so it is an ObjectHeader.
* Thus, we read in the object header and make the object
*/
+ foundChunksInBlock = 1;
+
yaffs_SetChunkBit(dev, blk, c);
bi->pagesInUse++;
diff --git a/yaffs_guts.h b/yaffs_guts.h
index de0627e..e66efcf 100644
--- a/yaffs_guts.h
+++ b/yaffs_guts.h
@@ -14,7 +14,7 @@
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*
- * $Id: yaffs_guts.h,v 1.22 2006-05-17 09:31:06 charles Exp $
+ * $Id: yaffs_guts.h,v 1.23 2006-09-21 08:13:59 charles Exp $
*/
#ifndef __YAFFS_GUTS_H__
@@ -273,6 +273,10 @@ typedef struct {
yaffs_BlockState blockState:4; /* One of the above block states */
__u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
/* and retire the block. */
+ __u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */
+ __u32 gcPrioritise: 1; /* An ECC check or bank check has failed on this block.
+ It should be prioritised for GC */
+
#ifdef CONFIG_YAFFS_YAFFS2
__u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
__u32 sequenceNumber; /* block sequence number for yaffs2 */
diff --git a/yaffs_mtdif2.c b/yaffs_mtdif2.c
index d3a6552..1b917be 100644
--- a/yaffs_mtdif2.c
+++ b/yaffs_mtdif2.c
@@ -16,7 +16,7 @@
/* mtd interface for YAFFS2 */
const char *yaffs_mtdif2_c_version =
- "$Id: yaffs_mtdif2.c,v 1.11 2006-04-25 00:41:43 wookey Exp $";
+ "$Id: yaffs_mtdif2.c,v 1.12 2006-09-21 08:13:59 charles Exp $";
#include "yportenv.h"
@@ -120,6 +120,9 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
if (tags)
yaffs_UnpackTags2(tags, &pt);
+
+ if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
+ tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
if (retval == 0)
return YAFFS_OK;
diff --git a/yaffs_nand.c b/yaffs_nand.c
index cd39d51..989e8d9 100644
--- a/yaffs_nand.c
+++ b/yaffs_nand.c
@@ -13,7 +13,7 @@
*/
const char *yaffs_nand_c_version =
- "$Id: yaffs_nand.c,v 1.1 2006-05-08 10:13:34 charles Exp $";
+ "$Id: yaffs_nand.c,v 1.2 2006-09-21 08:13:59 charles Exp $";
#include "yaffs_nand.h"
#include "yaffs_tagscompat.h"
@@ -24,16 +24,26 @@ int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer,
yaffs_ExtendedTags * tags)
{
- chunkInNAND -= dev->chunkOffset;
+ int result;
+
+ int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
if (dev->readChunkWithTagsFromNAND)
- return dev->readChunkWithTagsFromNAND(dev, chunkInNAND, buffer,
+ result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
tags);
else
- return yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
- chunkInNAND,
+ result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
+ realignedChunkInNAND,
buffer,
- tags);
+ tags);
+ if(tags &&
+ tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){
+
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
+ bi->gcPrioritise = 1;
+ }
+
+ return result;
}
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
diff --git a/yaffs_packedtags2.c b/yaffs_packedtags2.c
index 5cc68af..69d78b2 100644
--- a/yaffs_packedtags2.c
+++ b/yaffs_packedtags2.c
@@ -114,20 +114,34 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
/* Page is in use */
#ifdef YAFFS_IGNORE_TAGS_ECC
{
- t->eccResult = 0;
+ t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
}
#else
{
yaffs_ECCOther ecc;
+ int result;
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
sizeof
(yaffs_PackedTags2TagsPart),
&ecc);
- t->eccResult =
+ result =
yaffs_ECCCorrectOther((unsigned char *)&pt->t,
sizeof
(yaffs_PackedTags2TagsPart),
&pt->ecc, &ecc);
+ switch(result){
+ case 0:
+ t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+ break;
+ case 1:
+ t->eccResult = YAFFS_ECC_RESULT_FIXED;
+ break;
+ case -1:
+ t->eccResult = YAFFS_ECC_RESULT_UNFIXED;
+ break;
+ default:
+ t->eccResult = YAFFS_ECC_RESULT_UNKNOWN;
+ }
}
#endif
t->blockBad = 0;