*** empty log message ***
authorcharles <charles>
Mon, 27 May 2002 18:57:25 +0000 (18:57 +0000)
committercharles <charles>
Mon, 27 May 2002 18:57:25 +0000 (18:57 +0000)
Makefile
nand_ecc.c [new file with mode: 0644]
yaffs_fs.c
yaffs_guts.c
yaffs_guts.h
yaffs_ramem.c
yaffs_super.c [deleted file]

index a0d81383aa194256bc783f4d000da2a26726fd56..c8731295c701aa1daadccf9be291ff02c49a3775 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,7 @@ USE_MTD = -DYAFFS_MTD_ENABLED
 CFLAGS = -D__KERNEL__ -DMODULE $(USE_RAM_FOR_TEST) $(USE_MTD)  -I$(KERNELDIR)/include -O2 -Wall
 
 
 CFLAGS = -D__KERNEL__ -DMODULE $(USE_RAM_FOR_TEST) $(USE_MTD)  -I$(KERNELDIR)/include -O2 -Wall
 
 
-OBJS = yaffs_fs.o yaffs_guts.o yaffs_ramem.o yaffs_mtdif.o
+OBJS = yaffs_fs.o yaffs_guts.o yaffs_ramem.o yaffs_mtdif.o nand_ecc.o
 
 
 all: yaffs.o
 
 
 all: yaffs.o
diff --git a/nand_ecc.c b/nand_ecc.c
new file mode 100644 (file)
index 0000000..84b270d
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ *  drivers/mtd/nand_ecc.c
+ *
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ *                     Toshiba America Electronics Components, Inc.
+ *
+ * $Id: nand_ecc.c,v 1.1 2002-05-27 18:57:25 charles Exp $
+ *
+ * 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 file contains an ECC algorithm from Toshiba that detects and
+ * corrects 1 bit errors in a 256 byte block of data.
+ *
+ *
+ *  Slightly hacked to fit in with YAFFS by Charles Manning.
+ */
+#if 0
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#endif
+
+#include "yportenv.h"
+
+/*
+ * Pre-calculated 256-way 1 byte column parity
+ */
+static const u_char nand_ecc_precalc_table[] = {
+       0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+       0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+       0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+       0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+       0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+       0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+       0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+       0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+       0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+       0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+       0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+       0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+       0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+       0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+       0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+       0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
+};
+
+
+/*
+ * Creates non-inverted ECC code from line parity
+ */
+static void nand_trans_result(u_char reg2, u_char reg3,
+       u_char *ecc_code)
+{
+       u_char a, b, i, tmp1, tmp2;
+       
+       /* Initialize variables */
+       a = b = 0x80;
+       tmp1 = tmp2 = 0;
+       
+       /* Calculate first ECC byte */
+       for (i = 0; i < 4; i++) {
+               if (reg3 & a)           /* LP15,13,11,9 --> ecc_code[0] */
+                       tmp1 |= b;
+               b >>= 1;
+               if (reg2 & a)           /* LP14,12,10,8 --> ecc_code[0] */
+                       tmp1 |= b;
+               b >>= 1;
+               a >>= 1;
+       }
+       
+       /* Calculate second ECC byte */
+       b = 0x80;
+       for (i = 0; i < 4; i++) {
+               if (reg3 & a)           /* LP7,5,3,1 --> ecc_code[1] */
+                       tmp2 |= b;
+               b >>= 1;
+               if (reg2 & a)           /* LP6,4,2,0 --> ecc_code[1] */
+                       tmp2 |= b;
+               b >>= 1;
+               a >>= 1;
+       }
+       
+       /* Store two of the ECC bytes */
+       ecc_code[0] = tmp1;
+       ecc_code[1] = tmp2;
+}
+
+/*
+ * Calculate 3 byte ECC code for 256 byte block
+ */
+void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
+{
+       u_char idx, reg1, reg2, reg3;
+       int j;
+       
+       /* Initialize variables */
+       reg1 = reg2 = reg3 = 0;
+       ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
+       
+       /* Build up column parity */ 
+       for(j = 0; j < 256; j++) {
+               
+               /* Get CP0 - CP5 from table */
+               idx = nand_ecc_precalc_table[dat[j]];
+               reg1 ^= (idx & 0x3f);
+               
+               /* All bit XOR = 1 ? */
+               if (idx & 0x40) {
+                       reg3 ^= (u_char) j;
+                       reg2 ^= ~((u_char) j);
+               }
+       }
+       
+       /* Create non-inverted ECC code from line parity */
+       nand_trans_result(reg2, reg3, ecc_code);
+       
+       /* Calculate final ECC code */
+       ecc_code[0] = ~ecc_code[0];
+       ecc_code[1] = ~ecc_code[1];
+       ecc_code[2] = ((~reg1) << 2) | 0x03;
+}
+
+/*
+ * Detect and correct a 1 bit error for 256 byte block
+ */
+int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+       u_char a, b, c, d1, d2, d3, add, bit, i;
+       
+       /* Do error detection */ 
+       d1 = calc_ecc[0] ^ read_ecc[0];
+       d2 = calc_ecc[1] ^ read_ecc[1];
+       d3 = calc_ecc[2] ^ read_ecc[2];
+       
+       if ((d1 | d2 | d3) == 0) {
+               /* No errors */
+               return 0;
+       }
+       else {
+               a = (d1 ^ (d1 >> 1)) & 0x55;
+               b = (d2 ^ (d2 >> 1)) & 0x55;
+               c = (d3 ^ (d3 >> 1)) & 0x54;
+               
+               /* Found and will correct single bit error in the data */
+               if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
+                       c = 0x80;
+                       add = 0;
+                       a = 0x80;
+                       for (i=0; i<4; i++) {
+                               if (d1 & c)
+                                       add |= a;
+                               c >>= 2;
+                               a >>= 1;
+                       }
+                       c = 0x80;
+                       for (i=0; i<4; i++) {
+                               if (d2 & c)
+                                       add |= a;
+                               c >>= 2;
+                               a >>= 1;
+                       }
+                       bit = 0;
+                       b = 0x04;
+                       c = 0x80;
+                       for (i=0; i<3; i++) {
+                               if (d3 & c)
+                                       bit |= b;
+                               c >>= 2;
+                               b >>= 1;
+                       }
+                       b = 0x01;
+                       a = dat[add];
+                       a ^= (b << bit);
+                       dat[add] = a;
+                       return 1;
+               }
+               else {
+                       i = 0;
+                       while (d1) {
+                               if (d1 & 0x01)
+                                       ++i;
+                               d1 >>= 1;
+                       }
+                       while (d2) {
+                               if (d2 & 0x01)
+                                       ++i;
+                               d2 >>= 1;
+                       }
+                       while (d3) {
+                               if (d3 & 0x01)
+                                       ++i;
+                               d3 >>= 1;
+                       }
+                       if (i == 1) {
+                               /* ECC Code Error Correction */
+                               read_ecc[0] = calc_ecc[0];
+                               read_ecc[1] = calc_ecc[1];
+                               read_ecc[2] = calc_ecc[2];
+                               return 2;
+                       }
+                       else {
+                               /* Uncorrectable Error */
+                               return -1;
+                       }
+               }
+       }
+       
+       /* Should never happen */
+       return -1;
+}
+
+
+#if 0
+EXPORT_SYMBOL(nand_calculate_ecc);
+EXPORT_SYMBOL(nand_correct_data);
+#endif
+
index 125d66913b100b019b15cc7f132b4cda178896e6..f12e13abe75036d84d9781e5be7ed5c6ba994bd8 100644 (file)
@@ -609,7 +609,7 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
        buf->f_blocks = yaffs_SuperToDevice(sb)->nBlocks * YAFFS_CHUNKS_PER_BLOCK;
        buf->f_files = 0;
        buf->f_ffree = 0;
        buf->f_blocks = yaffs_SuperToDevice(sb)->nBlocks * YAFFS_CHUNKS_PER_BLOCK;
        buf->f_files = 0;
        buf->f_ffree = 0;
-       buf->f_bavail = yaffs_GetNumberOfFreeChunks(yaffs_SuperToDevice(sb));
+       buf->f_bavail = buf->f_bfree = yaffs_GetNumberOfFreeChunks(yaffs_SuperToDevice(sb));
        return 0;
 }
 
        return 0;
 }
 
index 6bc6136e807285f2b4c692f3bf683bb2a77a24d7..66014bb3f449d95b5a94aec02ff026c17c622c0c 100644 (file)
 #define T(x)
 #endif
 
 #define T(x)
 #endif
 
+// External functions for ECC on data
+void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
+int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+
 
 // countBits is a quick way of counting the number of bits in a byte.
 // ie. countBits[n] holds the number of 1 bits in a byte with the value n.
 
 // countBits is a quick way of counting the number of bits in a byte.
 // ie. countBits[n] holds the number of 1 bits in a byte with the value n.
@@ -63,7 +67,7 @@ static const char yaffs_countBits[256] =
 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);
 static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);
 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);
 static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);
-static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND);
+static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
 
 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
 
 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
@@ -108,7 +112,28 @@ static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND
 
 int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
 {
 
 int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
 {
-       return dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
+       int retVal;
+       __u8 calcEcc[3];
+       yaffs_Spare localSpare;
+       
+       if(!spare && data)
+       {
+               // If we don't have a real spare, then we use a local one.
+               // Need this for the calculation of the ecc
+               spare = &localSpare;
+       }
+       
+       retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
+       if(data)
+       {
+               // Do ECC correction
+               //Todo handle any errors
+                nand_calculate_ecc(data,calcEcc);
+                nand_correct_data (data,spare->ecc1, calcEcc);
+                nand_calculate_ecc(&data[256],calcEcc);
+                nand_correct_data (&data[256],spare->ecc2, calcEcc);
+       }
+       return retVal;
 }
 
 int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
 }
 
 int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
@@ -127,6 +152,9 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8
        
        int writeOk = 0;
        
        
        int writeOk = 0;
        
+       unsigned char rbData[YAFFS_BYTES_PER_CHUNK];
+       yaffs_Spare rbSpare;
+       
        do{
                chunk = yaffs_AllocateChunk(dev,useReserve);
        
        do{
                chunk = yaffs_AllocateChunk(dev,useReserve);
        
@@ -135,8 +163,33 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8
                        writeOk =  yaffs_WriteChunkToNAND(dev,chunk,data,spare);
                        if(writeOk)
                        {
                        writeOk =  yaffs_WriteChunkToNAND(dev,chunk,data,spare);
                        if(writeOk)
                        {
-                               //Todo read-back and verify
+                               // Readback & verify
                                // If verify fails, then delete this chunk and try again
                                // If verify fails, then delete this chunk and try again
+                               // To verify we compare everything except the block and 
+                               // page status bytes.
+                               yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare);
+                               
+                               if(memcmp(data,rbData,YAFFS_BYTES_PER_CHUNK) != 0 ||
+                                       spare->tagByte0 != rbSpare.tagByte0 ||
+                                       spare->tagByte1 != rbSpare.tagByte1 ||
+                                       spare->tagByte2 != rbSpare.tagByte2 ||
+                                       spare->tagByte3 != rbSpare.tagByte3 ||
+                                       spare->tagByte4 != rbSpare.tagByte4 ||
+                                       spare->tagByte5 != rbSpare.tagByte5 ||
+                                       spare->tagByte6 != rbSpare.tagByte6 ||
+                                       spare->tagByte7 != rbSpare.tagByte7 ||
+                                       spare->ecc1[0]  != rbSpare.ecc1[0]  ||
+                                       spare->ecc1[1]  != rbSpare.ecc1[1]  ||
+                                       spare->ecc1[2]  != rbSpare.ecc1[2]  ||
+                                       spare->ecc2[0]  != rbSpare.ecc2[0]  ||
+                                       spare->ecc2[1]  != rbSpare.ecc2[1]  ||
+                                       spare->ecc2[2]  != rbSpare.ecc2[2] )
+                               {
+                                       // Didn't verify
+                                       yaffs_DeleteChunk(dev,chunk);
+                                       writeOk = 0;
+                               }                                       
+                               
                        }
                }
        } while(chunk >= 0 && ! writeOk);
                        }
                }
        } while(chunk >= 0 && ! writeOk);
@@ -178,20 +231,60 @@ static __u16 yaffs_CalcNameSum(const char *name)
 }
 
 
 }
 
 
-void yaffs_CalcECC(const __u8 *buffer, yaffs_Spare *spare)
+void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
 {
 {
-
-       // Todo do nothing now. Need to put in ecc
-       spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xFF;
-       spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xFF;
+       nand_calculate_ecc (data , spare->ecc1);
+       nand_calculate_ecc (&data[256] , spare->ecc2);
 }
 
 void yaffs_CalcTagsECC(yaffs_Tags *tags)
 {
        // Todo don't do anything yet. Need to calculate ecc
 }
 
 void yaffs_CalcTagsECC(yaffs_Tags *tags)
 {
        // Todo don't do anything yet. Need to calculate ecc
-       tags->ecc = 0xFFFFFFFF;
+       unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
+       unsigned  i,j;
+       unsigned  ecc = 0;
+       unsigned bit = 0;
+
+       tags->ecc = 0;
+       
+       for(i = 0; i < 8; i++)
+       {
+               for(j = 1; j &0x7f; j<<=1)
+               {
+                       bit++;
+                       if(b[i] & j)
+                       {
+                               ecc ^= bit;
+                       }
+               }
+       }
+       
+       tags->ecc = ecc;
+       
+       
 }
 
 }
 
+void yaffs_CheckECCOnTags(yaffs_Tags *tags)
+{
+       unsigned ecc = tags->ecc;
+       
+       yaffs_CalcTagsECC(tags);
+       
+       ecc ^= tags->ecc;
+       
+       if(ecc)
+       {
+               // Needs fixing
+               unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
+
+               ecc--;
+                               
+               b[ecc / 8] ^= (1 << (ecc & 7));
+               
+               // Now recvalc the ecc
+               yaffs_CalcTagsECC(tags);
+       }
+}
 
 
 ///////////////////////// TNODES ///////////////////////
 
 
 ///////////////////////// TNODES ///////////////////////
@@ -939,8 +1032,10 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectTyp
                                INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
                                break;
                        case YAFFS_OBJECT_TYPE_SYMLINK:
                                INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
                                break;
                        case YAFFS_OBJECT_TYPE_SYMLINK:
+                               // No action required
                                break;
                        case YAFFS_OBJECT_TYPE_HARDLINK:
                                break;
                        case YAFFS_OBJECT_TYPE_HARDLINK:
+                               // No action required
                                break;
                        case YAFFS_OBJECT_TYPE_UNKNOWN:
                                // todo this should not happen
                                break;
                        case YAFFS_OBJECT_TYPE_UNKNOWN:
                                // todo this should not happen
@@ -1411,7 +1506,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
                        else
                        {
                                // It's a data chunk
                        else
                        {
                                // It's a data chunk
-                               yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk);
+                               yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
 
                        }
                        
 
                        }
                        
@@ -1476,7 +1571,7 @@ static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
        tu->asBytes[6]= sparePtr->tagByte6;
        tu->asBytes[7]= sparePtr->tagByte7;
        
        tu->asBytes[6]= sparePtr->tagByte6;
        tu->asBytes[7]= sparePtr->tagByte7;
        
-       // Todo Check ECC on tags
+       yaffs_CheckECCOnTags(tagsPtr);
 }
 
 static void yaffs_SpareInitialise(yaffs_Spare *spare)
 }
 
 static void yaffs_SpareInitialise(yaffs_Spare *spare)
@@ -1721,13 +1816,53 @@ static int yaffs_CheckFileSanity(yaffs_Object *in)
 
 #endif
 
 
 #endif
 
-static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND)
+static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
 {
        yaffs_Tnode *tn;
        yaffs_Device *dev = in->myDev;
 {
        yaffs_Tnode *tn;
        yaffs_Device *dev = in->myDev;
+       int existingChunk;
+       yaffs_Tags existingTags;
+       yaffs_Tags newTags;
+       unsigned existingSerial, newSerial;
+       
        
        tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
        
        tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
+       
+       if(inScan)
+       {
+               // If we're scanning then we need to test for duplicates
+               // NB This does not need to be efficient since it should only ever 
+               // happen when the power fails during a write, then only one
+               // chunk should ever be affected.
+       
+               existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];            
+               
+               if(existingChunk != 0)
+               {
+                       // We have a duplicate now we need to decide which one to use
+                       // To do this we get both sets of tags and compare serial numbers.
+                       yaffs_ReadChunkTagsFromNAND(dev,chunkInInode, &newTags);
+                       yaffs_ReadChunkTagsFromNAND(dev,existingChunk, &existingTags);
+                       newSerial = newTags.serialNumber;
+                       existingSerial = existingTags.serialNumber;
+                       if(((existingSerial+1) & 3) == newSerial)
+                       {
+                               // Use new
+                               // Delete the old one and drop through to update the tnode
+                               yaffs_DeleteChunk(dev,existingChunk);
+                       }
+                       else
+                       {
+                               // Use existing.
+                               // Delete the new one and return early so that the tnode isn't changed
+                               yaffs_DeleteChunk(dev,chunkInInode);
+                               return YAFFS_OK;
+                       }
+               }
+       }
+       
        tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = chunkInNAND;
        tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = chunkInNAND;
+       
        return YAFFS_OK;
 }
 
        return YAFFS_OK;
 }
 
@@ -1782,7 +1917,7 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId)
        }
        else
        {
        }
        else
        {
-               T(("Bad news deteing chunk %d\n",chunkId));
+               T(("Bad news deleting chunk %d\n",chunkId));
        }
        
 }
        }
        
 }
@@ -1851,7 +1986,7 @@ int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *
        newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
        if(newChunkId >= 0)
        {
        newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
        if(newChunkId >= 0)
        {
-               yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId);
+               yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0);
                
                
                if(prevChunkId >= 0)
                
                
                if(prevChunkId >= 0)
@@ -1927,7 +2062,8 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
        
                switch(in->variantType)
                {
        
                switch(in->variantType)
                {
-                       case YAFFS_OBJECT_TYPE_UNKNOWN:         // Todo got a problem
+                       case YAFFS_OBJECT_TYPE_UNKNOWN:         
+                               // Should not happen
                                break;
                        case YAFFS_OBJECT_TYPE_FILE:
                                oh->fileSize = in->variant.fileVariant.fileSize;
                                break;
                        case YAFFS_OBJECT_TYPE_FILE:
                                oh->fileSize = in->variant.fileVariant.fileSize;
@@ -1935,7 +2071,8 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
                        case YAFFS_OBJECT_TYPE_HARDLINK:
                                oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
                                break;
                        case YAFFS_OBJECT_TYPE_HARDLINK:
                                oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
                                break;
-                       case YAFFS_OBJECT_TYPE_DIRECTORY:       // Do nothing
+                       case YAFFS_OBJECT_TYPE_DIRECTORY:       
+                               // Do nothing
                                break;
                        case YAFFS_OBJECT_TYPE_SYMLINK:
                                strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
                                break;
                        case YAFFS_OBJECT_TYPE_SYMLINK:
                                strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
@@ -2535,9 +2672,9 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        inuse++;
                                        pageBits |= ( 1 <<c);                           
                                        in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
                                        inuse++;
                                        pageBits |= ( 1 <<c);                           
                                        in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
-                                       // todo check for a clash (two data chunks with
+                                       // PutChuunkIntoFIle checks for a clash (two data chunks with
                                        // the same chunkId).
                                        // the same chunkId).
-                                       yaffs_PutChunkIntoFile(in,tags.chunkId,chunk);
+                                       yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
                                        T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));    
                                }
                                else
                                        T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));    
                                }
                                else
index d1e29730fa26a27d32313d3ff8d3ee8573502ee1..e6f74ddbc72daa600a13cc19951eaa5f8e65fdaa 100644 (file)
@@ -93,7 +93,9 @@ typedef struct
     __u8  tagByte1;
     __u8  tagByte2;
     __u8  tagByte3;
     __u8  tagByte1;
     __u8  tagByte2;
     __u8  tagByte3;
-    __u8  pageStatus;
+    __u8  pageStatus; // Currently unused, but sort of set aside to distinguish
+                                 // unused - vs- used -vs- deleted chunks. We achieve this by
+                                         // using the objectId tags.
     __u8  blockStatus;
     __u8  tagByte4;
     __u8  tagByte5;
     __u8  blockStatus;
     __u8  tagByte4;
     __u8  tagByte5;
@@ -318,7 +320,12 @@ struct yaffs_DeviceStruct
        
        void *genericDevice; // Pointer to device context
                                                 // On an mtd this holds the mtd pointer.
        
        void *genericDevice; // Pointer to device context
                                                 // On an mtd this holds the mtd pointer.
+       
+#ifdef __KERNEL__
+
        struct semaphore sem;// Semaphore for waiting on erasure.
        struct semaphore sem;// Semaphore for waiting on erasure.
+
+#endif
        
        
        // NAND access functions (Must be set before calling YAFFS)
        
        
        // NAND access functions (Must be set before calling YAFFS)
index 7143dffee677df1df58b0245f6099dff9a0b564b..2c8d0bce05bb43249f622c329d7d4aecc11ae8ac 100644 (file)
  //yaffs_ramem.c
  // Since this creates the RAM block at start up it is pretty useless for testing the scanner.
 
  //yaffs_ramem.c
  // Since this creates the RAM block at start up it is pretty useless for testing the scanner.
 
+#ifndef __KERNEL__
+#define YAFFS_RAM_ENABLED
+#endif
+
 #ifdef YAFFS_RAM_ENABLED
 
 #include "yportenv.h"
 #ifdef YAFFS_RAM_ENABLED
 
 #include "yportenv.h"
diff --git a/yaffs_super.c b/yaffs_super.c
deleted file mode 100644 (file)
index 04dc17e..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2001 Red Hat, Inc.
- *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
- *
- * The original JFFS, from which the design for JFFS2 was derived,
- * was designed and implemented by Axis Communications AB.
- *
- * The contents of this file are subject to the Red Hat eCos Public
- * License Version 1.1 (the "Licence"); you may not use this file
- * except in compliance with the Licence.  You may obtain a copy of
- * the Licence at http://www.redhat.com/
- *
- * Software distributed under the Licence is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- * See the Licence for the specific language governing rights and
- * limitations under the Licence.
- *
- * The Original Code is JFFS2 - Journalling Flash File System, version 2
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the RHEPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the RHEPL or the GPL.
- *
- * $Id: yaffs_super.c,v 1.1 2002-05-20 17:42:08 aleph1 Exp $
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/fs.h>
-#include <linux/jffs2.h>
-#include <linux/pagemap.h>
-#include <linux/mtd/mtd.h>
-#include <linux/interrupt.h>
-#include "nodelist.h"
-
-#ifndef MTD_BLOCK_MAJOR
-#define MTD_BLOCK_MAJOR 31
-#endif
-
-extern void jffs2_read_inode (struct inode *);
-void jffs2_put_super (struct super_block *);
-void jffs2_write_super (struct super_block *);
-static int jffs2_statfs (struct super_block *, struct statfs *);
-int jffs2_remount_fs (struct super_block *, int *, char *);
-extern void jffs2_clear_inode (struct inode *);
-
-static struct super_operations jffs2_super_operations =
-{
-       read_inode:     jffs2_read_inode,
-//     delete_inode:   jffs2_delete_inode,
-       put_super:      jffs2_put_super,
-       write_super:    jffs2_write_super,
-       statfs:         jffs2_statfs,
-       remount_fs:     jffs2_remount_fs,
-       clear_inode:    jffs2_clear_inode
-};
-
-static int jffs2_statfs(struct super_block *sb, struct statfs *buf)
-{
-       struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-       unsigned long avail;
-
-       buf->f_type = JFFS2_SUPER_MAGIC;
-       buf->f_bsize = 1 << PAGE_SHIFT;
-       buf->f_blocks = c->flash_size >> PAGE_SHIFT;
-       buf->f_files = 0;
-       buf->f_ffree = 0;
-       buf->f_namelen = JFFS2_MAX_NAME_LEN;
-
-       spin_lock_bh(&c->erase_completion_lock);
-
-       avail = c->dirty_size + c->free_size;
-       if (avail > c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE)
-               avail -= c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE;
-       else
-               avail = 0;
-
-       buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT;
-
-#if CONFIG_JFFS2_FS_DEBUG > 0
-       printk(KERN_DEBUG "STATFS:\n");
-       printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size);
-       printk(KERN_DEBUG "used_size: %08x\n", c->used_size);
-       printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size);
-       printk(KERN_DEBUG "free_size: %08x\n", c->free_size);
-       printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size);
-       printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size);
-       printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size);
-
-       if (c->nextblock) {
-               printk(KERN_DEBUG "nextblock: 0x%08x\n", c->nextblock->offset);
-       } else {
-               printk(KERN_DEBUG "nextblock: NULL\n");
-       }
-       if (c->gcblock) {
-               printk(KERN_DEBUG "gcblock: 0x%08x\n", c->gcblock->offset);
-       } else {
-               printk(KERN_DEBUG "gcblock: NULL\n");
-       }
-       if (list_empty(&c->clean_list)) {
-               printk(KERN_DEBUG "clean_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->clean_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "clean_list: %08x\n", jeb->offset);
-               }
-       }
-       if (list_empty(&c->dirty_list)) {
-               printk(KERN_DEBUG "dirty_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->dirty_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "dirty_list: %08x\n", jeb->offset);
-               }
-       }
-       if (list_empty(&c->erasing_list)) {
-               printk(KERN_DEBUG "erasing_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->erasing_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "erasing_list: %08x\n", jeb->offset);
-               }
-       }
-       if (list_empty(&c->erase_pending_list)) {
-               printk(KERN_DEBUG "erase_pending_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->erase_pending_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "erase_pending_list: %08x\n", jeb->offset);
-               }
-       }
-       if (list_empty(&c->free_list)) {
-               printk(KERN_DEBUG "free_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->free_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "free_list: %08x\n", jeb->offset);
-               }
-       }
-       if (list_empty(&c->bad_list)) {
-               printk(KERN_DEBUG "bad_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->bad_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "bad_list: %08x\n", jeb->offset);
-               }
-       }
-       if (list_empty(&c->bad_used_list)) {
-               printk(KERN_DEBUG "bad_used_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->bad_used_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "bad_used_list: %08x\n", jeb->offset);
-               }
-       }
-#endif /* CONFIG_JFFS2_FS_DEBUG */
-
-       spin_unlock_bh(&c->erase_completion_lock);
-
-
-       return 0;
-}
-
-static struct super_block *jffs2_read_super(struct super_block *sb, void *data, int silent)
-{
-       struct jffs2_sb_info *c;
-       struct inode *root_i;
-       int i;
-
-       D1(printk(KERN_DEBUG "jffs2: read_super for device %s\n", kdevname(sb->s_dev)));
-
-       if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) {
-               if (!silent)
-                       printk(KERN_DEBUG "jffs2: attempt to mount non-MTD device %s\n", kdevname(sb->s_dev));
-               return NULL;
-       }
-
-       c = JFFS2_SB_INFO(sb);
-       memset(c, 0, sizeof(*c));
-       
-       c->mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
-       if (!c->mtd) {
-               D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev)));
-               return NULL;
-       }
-       c->sector_size = c->mtd->erasesize;
-       c->free_size = c->flash_size = c->mtd->size;
-       c->nr_blocks = c->mtd->size / c->mtd->erasesize;
-       c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
-       if (!c->blocks)
-               goto out_mtd;
-       for (i=0; i<c->nr_blocks; i++) {
-               INIT_LIST_HEAD(&c->blocks[i].list);
-               c->blocks[i].offset = i * c->sector_size;
-               c->blocks[i].free_size = c->sector_size;
-               c->blocks[i].dirty_size = 0;
-               c->blocks[i].used_size = 0;
-               c->blocks[i].first_node = NULL;
-               c->blocks[i].last_node = NULL;
-       }
-               
-       spin_lock_init(&c->nodelist_lock);
-       init_MUTEX(&c->alloc_sem);
-       init_waitqueue_head(&c->erase_wait);
-       spin_lock_init(&c->erase_completion_lock);
-       spin_lock_init(&c->inocache_lock);
-
-       INIT_LIST_HEAD(&c->clean_list);
-       INIT_LIST_HEAD(&c->dirty_list);
-       INIT_LIST_HEAD(&c->erasing_list);
-       INIT_LIST_HEAD(&c->erase_pending_list);
-       INIT_LIST_HEAD(&c->erase_complete_list);
-       INIT_LIST_HEAD(&c->free_list);
-       INIT_LIST_HEAD(&c->bad_list);
-       INIT_LIST_HEAD(&c->bad_used_list);
-       c->highest_ino = 1;
-
-       if (jffs2_build_filesystem(c)) {
-               D1(printk(KERN_DEBUG "build_fs failed\n"));
-               goto out_nodes;
-       }
-       sb->s_op = &jffs2_super_operations;
-
-       D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
-       root_i = iget(sb, 1);
-       if (is_bad_inode(root_i)) {
-               D1(printk(KERN_WARNING "get root inode failed\n"));
-               goto out_nodes;
-       }
-
-       D1(printk(KERN_DEBUG "jffs2_read_super(): d_alloc_root()\n"));
-       sb->s_root = d_alloc_root(root_i);
-       if (!sb->s_root)
-               goto out_root_i;
-
-#if LINUX_VERSION_CODE >= 0x20403
-       sb->s_maxbytes = 0xFFFFFFFF;
-#endif
-       sb->s_blocksize = PAGE_CACHE_SIZE;
-       sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-       sb->s_magic = JFFS2_SUPER_MAGIC;
-       if (!(sb->s_flags & MS_RDONLY))
-               jffs2_start_garbage_collect_thread(c);
-       return sb;
-
- out_root_i:
-       iput(root_i);
- out_nodes:
-       jffs2_free_ino_caches(c);
-       jffs2_free_raw_node_refs(c);
-       kfree(c->blocks);
- out_mtd:
-       put_mtd_device(c->mtd);
-       return NULL;
-}
-
-void jffs2_put_super (struct super_block *sb)
-{
-       struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-
-       D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
-
-       if (!(sb->s_flags & MS_RDONLY))
-               jffs2_stop_garbage_collect_thread(c);
-       jffs2_free_ino_caches(c);
-       jffs2_free_raw_node_refs(c);
-       kfree(c->blocks);
-       if (c->mtd->sync)
-               c->mtd->sync(c->mtd);
-       put_mtd_device(c->mtd);
-       
-       D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
-}
-
-int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
-{
-       struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-
-       if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY))
-               return -EROFS;
-
-       /* We stop if it was running, then restart if it needs to.
-          This also catches the case where it was stopped and this
-          is just a remount to restart it */
-       if (!(sb->s_flags & MS_RDONLY))
-               jffs2_stop_garbage_collect_thread(c);
-
-       if (!(*flags & MS_RDONLY))
-               jffs2_start_garbage_collect_thread(c);
-       
-       sb->s_flags = (sb->s_flags & ~MS_RDONLY)|(*flags & MS_RDONLY);
-
-       return 0;
-}
-
-void jffs2_write_super (struct super_block *sb)
-{
-       struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-       sb->s_dirt = 0;
-
-       if (sb->s_flags & MS_RDONLY)
-               return;
-
-       jffs2_garbage_collect_trigger(c);
-       jffs2_erase_pending_blocks(c);
-       jffs2_mark_erased_blocks(c);
-}
-
-
-static DECLARE_FSTYPE_DEV(jffs2_fs_type, "jffs2", jffs2_read_super);
-
-static int __init init_jffs2_fs(void)
-{
-       int ret;
-
-       printk(KERN_NOTICE "JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.\n");
-
-#ifdef JFFS2_OUT_OF_KERNEL
-       /* sanity checks. Could we do these at compile time? */
-       if (sizeof(struct jffs2_sb_info) > sizeof (((struct super_block *)NULL)->u)) {
-               printk(KERN_ERR "JFFS2 error: struct jffs2_sb_info (%d bytes) doesn't fit in the super_block union (%d bytes)\n", 
-                      sizeof(struct jffs2_sb_info), sizeof (((struct super_block *)NULL)->u));
-               return -EIO;
-       }
-
-       if (sizeof(struct jffs2_inode_info) > sizeof (((struct inode *)NULL)->u)) {
-               printk(KERN_ERR "JFFS2 error: struct jffs2_inode_info (%d bytes) doesn't fit in the inode union (%d bytes)\n", 
-                      sizeof(struct jffs2_inode_info), sizeof (((struct inode *)NULL)->u));
-               return -EIO;
-       }
-#endif
-
-       ret = jffs2_create_slab_caches();
-       if (ret) {
-               printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
-               return ret;
-       }
-       ret = register_filesystem(&jffs2_fs_type);
-       if (ret) {
-               printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
-               jffs2_destroy_slab_caches();
-       }
-       return ret;
-}
-
-static void __exit exit_jffs2_fs(void)
-{
-       jffs2_destroy_slab_caches();
-       unregister_filesystem(&jffs2_fs_type);
-}
-
-module_init(init_jffs2_fs);
-module_exit(exit_jffs2_fs);
-
-MODULE_DESCRIPTION("The Journalling Flash File System, v2");
-MODULE_AUTHOR("Red Hat, Inc.");
-MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for 
-                      // the sake of this tag. It's Free Software.
-/*
- * YAFFS: Yet another FFS. A NAND-flash specific file system. 
- *
- * Copyright (C) 2002 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.
- *
- */