#
# NB Warning this Makefile does not include header dependencies.
#
-# $Id: Makefile,v 1.18 2008-07-21 01:03:19 charles Exp $
+# $Id: Makefile,v 1.19 2008-11-07 00:32:21 charles Exp $
#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
CFLAGS = -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2
CFLAGS += -DCONFIG_YAFFS_PROVIDE_DEFS -DCONFIG_YAFFSFS_PROVIDE_VALUES -DNO_Y_INLINE
-CFLAGS += -Wall -g $(EXTRA_COMPILE_FLAGS)
-#CFLAGS+= -fstack-check -O0
+CFLAGS += -Wall -g $(EXTRA_COMPILE_FLAGS) -Wstrict-aliasing -fno-strict-aliasing
+CFLAGS += -O0
+#CFLAGS += -DVALGRIND_TEST
#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations
#CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline
-DIRECTTESTOBJS = dtest.o yaffscfg2k.o yaffs_ecc.o yaffs_fileem.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \
+COMMONTESTOBJS = yaffscfg2k.o yaffs_ecc.o yaffs_fileem.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \
yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \
yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \
- yaffs_checkptrw.o yaffs_qsort.o
+ yaffs_checkptrw.o yaffs_qsort.o\
+ yaffs_norif1.o ynorsim.o nor_stress.o
# yaffs_checkptrwtest.o\
-
+
+DIRECTTESTOBJS = $(COMMONTESTOBJS) dtest.o
+YAFFSTESTOBJS = $(COMMONTESTOBJS) yaffs_test.o
BOOTTESTOBJS = bootldtst.o yboot.o yaffs_fileem.o nand_ecc.o
#ALLOBJS = dtest.o nand_ecc.o yaffscfg.o yaffs_fileem.o yaffsfs.o yaffs_ramdisk.o bootldtst.o yboot.o yaffs_ramem2k.o
-ALLOBJS = $(DIRECTTESTOBJS) $(BOOTTESTOBJS)
+ALLOBJS = $(sort $(DIRECTTESTOBJS) $(YAFFSTESTOBJS))
SYMLINKS = devextras.h yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h yaffsinterface.h yportenv.h yaffs_tagscompat.c yaffs_tagscompat.h \
yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h yaffs_nandemul2k.h \
#all: directtest2k boottest
-all: directtest2k
+all: directtest2k yaffs_test
$(ALLOBJS): %.o: %.c
gcc -c $(CFLAGS) -o $@ $<
directtest2k: $(SYMLINKS) $(DIRECTTESTOBJS)
gcc -o $@ $(DIRECTTESTOBJS)
+yaffs_test: $(SYMLINKS) $(YAFFSTESTOBJS)
+ gcc -o $@ $(YAFFSTESTOBJS)
+
boottest: $(SYMLINKS) $(BOOTTESTOBJS)
gcc -o $@ $(BOOTTESTOBJS)
#include "yaffsfs.h"
+#include "nor_stress.h"
+
void dumpDir(const char *dname);
char xx[600];
int main(int argc, char *argv[])
{
+
//return long_test(argc,argv);
//return cache_read_test();
#
# NB Warning this Makefile does not include header dependencies.
#
-# $Id: Makefile,v 1.3 2008-08-07 22:45:44 charles Exp $
+# $Id: Makefile,v 1.4 2008-11-07 00:32:22 charles Exp $
#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \
yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \
yaffs_checkptrw.o yaffs_qsort.o \
+ yaffs_norif1.o ynorsim.o
# yaffs_checkptrwtest.o\
YAFFSDIRECTSYMLINKS = yaffscfg2k.c yaffs_fileem2k.c yaffsfs.c yaffs_flashif.h yaffs_flashif2.h\
yaffs_fileem2k.h yaffsfs.h yaffs_malloc.h yaffs_ramdisk.h ydirectenv.h \
- yaffscfg.h yaffs_fileem.c yaffs_flashif.c yaffs_ramdisk.c yaffs_ramem2k.c
+ yaffscfg.h yaffs_fileem.c yaffs_flashif.c yaffs_ramdisk.c yaffs_ramem2k.c\
+ yaffs_norif1.c yaffs_norif1.h ynorsim.c ynorsim.h
long monitorstart = -1; /* -m flag */
long monitorend = -1; /* -m flag */
int lite = 0; /* -L flag */
-<<<<<<< yaffs_fsx.c
-long numops = 5000; /* -N flag */
-=======
-long numops = /*-1 */ 100000; /* -N flag */
->>>>>>> 1.3
+long numops = /*-1 */ 10000000; /* -N flag */
int randomoplen = 1; /* -O flag disables it */
int seed = 1; /* -S flag */
}
-#define BASE_NAME "/flash/yaffs2"
+#define BASE_NAME "/flash/yaffs1"
int
main(int argc, char **argv)
--- /dev/null
+#include "nor_stress.h"
+
+
+#include "yaffsfs.h"
+
+#include <stdio.h>
+
+
+
+static unsigned powerUps;
+static unsigned cycleStarts;
+static unsigned cycleEnds;
+
+
+char fullPathName[100];
+char fullPowerUpName[100];
+char fullStartName[100];
+char fullEndName[100];
+char fullMainName[100];
+char fullTempMainName[100];
+char fullTempCounterName[100];
+
+
+void MakeName(char *fullName,const char *prefix, const char *name)
+{
+ strcpy(fullName,prefix);
+ strcat(fullName,"/");
+ strcat(fullName,name);
+}
+
+
+void MakeFullNames(const char *prefix)
+{
+ MakeName(fullPathName,prefix,"");
+ MakeName(fullPowerUpName,prefix,"powerUps");
+ MakeName(fullStartName,prefix,"starts");
+ MakeName(fullEndName,prefix,"ends");
+ MakeName(fullMainName,prefix,"main");
+ MakeName(fullTempCounterName,prefix,"tmp-counter");
+ MakeName(fullTempMainName,prefix,"tmp-main");
+}
+
+static void FatalError(void)
+{
+ printf("Integrity error\n");
+ while(1){}
+}
+
+static void UpdateCounter(const char *name, unsigned *val, int initialise)
+{
+ int inh;
+ int outh;
+ unsigned x[2];
+ int nread = 0;
+ int nwritten = 0;
+
+ x[0] = x[1] = 0;
+
+ if(initialise){
+ x[0] = 0;
+ x[1] = 1;
+ } else {
+ inh = yaffs_open(name,O_RDONLY, S_IREAD | S_IWRITE);
+ if(inh >= 0){
+ nread = yaffs_read(inh,x,sizeof(x));
+ yaffs_close(inh);
+ }
+
+ if(nread != sizeof(x) ||
+ x[0] + 1 != x[1]){
+ printf("Error reading counter %s handle %d, x[0] %u x[1] %u last error %d\n",
+ name, inh, x[0], x[1],yaffsfs_GetLastError());
+ FatalError();
+
+ }
+ x[0]++;
+ x[1]++;
+ }
+
+ outh = yaffs_open(fullTempCounterName, O_RDWR | O_TRUNC | O_CREAT, S_IREAD | S_IWRITE);
+ if(outh >= 0){
+ nwritten = yaffs_write(outh,x,sizeof(x));
+ yaffs_close(outh);
+ yaffs_rename(fullTempCounterName,name);
+ }
+
+ if(nwritten != sizeof(x)){
+ printf("Error writing counter %s handle %d, x[0] %u x[1] %u\n",
+ name, inh, x[0], x[1]);
+ FatalError();
+ }
+
+ *val = x[0];
+
+ printf("##\n"
+ "## Set counter %s to %u\n"
+ "##\n", name,x[0]);
+}
+
+
+static void dump_directory_tree_worker(const char *dname,int recursive)
+{
+ yaffs_DIR *d;
+ yaffs_dirent *de;
+ struct yaffs_stat s;
+ char str[1000];
+
+ d = yaffs_opendir(dname);
+
+ if(!d)
+ {
+ printf("opendir failed\n");
+ }
+ else
+ {
+ while((de = yaffs_readdir(d)) != NULL)
+ {
+ strcpy(str,dname);
+ strcat(str,"/");
+ strcat(str,de->d_name);
+
+ yaffs_lstat(str,&s);
+
+ printf("%s inode %d obj %x length %d mode %X ",str,s.st_ino,de->d_dont_use,(int)s.st_size,s.st_mode);
+ switch(s.st_mode & S_IFMT)
+ {
+ case S_IFREG: printf("data file"); break;
+ case S_IFDIR: printf("directory"); break;
+ case S_IFLNK: printf("symlink -->");
+ if(yaffs_readlink(str,str,100) < 0)
+ printf("no alias");
+ else
+ printf("\"%s\"",str);
+ break;
+ default: printf("unknown"); break;
+ }
+
+ printf("\n");
+
+ if((s.st_mode & S_IFMT) == S_IFDIR && recursive)
+ dump_directory_tree_worker(str,1);
+
+ }
+
+ yaffs_closedir(d);
+ }
+
+}
+
+static void dump_directory_tree(const char *dname)
+{
+ dump_directory_tree_worker(dname,1);
+ printf("\n");
+ printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname));
+}
+
+
+
+
+#define XX_SIZE 500
+
+static unsigned xx[XX_SIZE];
+
+static int yWriteFile(const char *fname, unsigned sz32)
+{
+ int h;
+ int r;
+ int i;
+ unsigned checksum = 0;
+
+ printf("Writing file %s\n",fname);
+
+ h = yaffs_open(fname,O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
+
+ if(h < 0){
+ printf("could not open file %s\n",fname);
+ return h;
+ }
+
+ xx[0] = sz32;
+ checksum ^= xx[0];
+
+ if((r = yaffs_write(h,xx,sizeof(unsigned))) != sizeof(unsigned)){
+ goto WRITE_ERROR;
+ }
+
+ while(sz32> 0){
+ for(i = 0; i < XX_SIZE; i++){
+ xx[i] = sz32 + i;
+ checksum ^= xx[i];
+ }
+
+ if((r = yaffs_write(h,xx,sizeof(xx))) != sizeof(xx)){
+ goto WRITE_ERROR;
+ }
+ sz32--;
+ }
+
+ xx[0] = checksum;
+
+ if((r = yaffs_write(h,xx,sizeof(unsigned))) != sizeof(unsigned)){
+ goto WRITE_ERROR;
+ }
+
+
+ yaffs_close(h);
+ return 0;
+
+WRITE_ERROR:
+ printf("ywrite error at position %d\n",(int)yaffs_lseek(h,0,SEEK_END));
+ yaffs_close(h);
+ return -1;
+
+}
+
+static int yVerifyFile(const char *fName)
+{
+ unsigned checksum = 0;
+ unsigned totalSize;
+ unsigned sz32;
+ unsigned recordedSize = 0;
+ int r;
+ int h;
+ int i;
+ int retval = 0;
+
+
+ printf("Verifying file %s\n",fName);
+
+ h = yaffs_open(fName, O_RDONLY,S_IREAD | S_IWRITE);
+
+ if(h < 0){
+ printf("could not open file %s\n",fName);
+ return -1;
+ }
+
+ totalSize = yaffs_lseek(h,0,SEEK_END);
+ yaffs_lseek(h,0,SEEK_SET);
+
+ r = yaffs_read(h,&sz32,sizeof(sz32));
+
+ if(r != sizeof(sz32)){
+ printf("reading size failed ... returned %d\n",r);
+ yaffs_close(h);
+ return -1;
+ }
+
+ recordedSize = sz32 * sizeof(xx) + 8;
+
+ printf("verify %s: file size is %d, recorded size is %d\n", fName, totalSize, recordedSize);
+ if(totalSize != recordedSize){
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!file size is wrong, should be %d, is %d\n", recordedSize,totalSize);
+ yaffs_close(h);
+ return -1;
+ }
+
+ checksum ^= sz32;
+
+
+ while(sz32 > 0){
+ r = yaffs_read(h,xx,sizeof(xx));
+ if(r != sizeof(xx)){
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!reading data failed ... returned %d\n",r);
+ yaffs_close(h);
+ return -1;
+ }
+ for(i = 0; i < XX_SIZE; i++)
+ checksum ^= xx[i];
+ sz32--;
+ }
+ r = yaffs_read(h,xx,sizeof(xx[0]));
+ if(r != sizeof(xx[0])){
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!reading data failed ... returned %d\n",r);
+ yaffs_close(h);
+ return -1;
+ }
+
+ checksum ^= xx[0];
+
+ if(checksum != 0){
+ printf("!!!!!!!!!!!!!!!!!!!!! checksum failed\n");
+ retval = -1;
+ } else
+ printf("verified ok\n");
+ yaffs_close(h);
+
+ return retval;
+}
+
+static unsigned long next = 1;
+int myrand(void) {
+ next = next * 1103515245 + 12345;
+ return((unsigned)(next/65536) % 32768);
+}
+
+static void DoUpdateMainFile(void)
+{
+ int result;
+ int sz32;
+ sz32 = (myrand() % 1000) + 20;
+
+ result = yWriteFile(fullTempMainName,sz32);
+ if(result)
+ FatalError();
+ yaffs_rename(fullTempMainName,fullMainName);
+}
+
+static void DoVerifyMainFile(void)
+{
+ int result;
+ result = yVerifyFile(fullMainName);
+ if(result)
+ FatalError();
+
+}
+
+
+void NorStressTestInitialise(const char *prefix)
+{
+ MakeFullNames(prefix);
+
+ yaffs_StartUp();
+ yaffs_mount(fullPathName);
+ UpdateCounter(fullPowerUpName,&powerUps,1);
+ UpdateCounter(fullStartName,&cycleStarts,1);
+ UpdateCounter(fullEndName,&cycleEnds,1);
+ UpdateCounter(fullPowerUpName,&powerUps,1);
+ DoUpdateMainFile();
+ DoVerifyMainFile();
+ yaffs_unmount(fullPathName);
+}
+
+
+void NorStressTestRun(const char *prefix)
+{
+ MakeFullNames(prefix);
+
+ yaffs_StartUp();
+ yaffs_mount(fullPathName);
+
+ dump_directory_tree(fullPathName);
+
+ UpdateCounter(fullPowerUpName,&powerUps,0);
+
+ while(1){
+ UpdateCounter(fullStartName, &cycleStarts,0);
+ DoVerifyMainFile();
+ DoUpdateMainFile();
+ dump_directory_tree(fullPathName);
+
+ UpdateCounter(fullEndName,&cycleEnds,0);
+ }
+}
--- /dev/null
+#ifndef __NOR_STRESS_H__
+#define __NOR_STRESS_H__
+
+void NorStressTestInitialise(const char *path);
+void NorStressTestRun(const char *path);
+
+#endif
+
--- /dev/null
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <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 is an interface module for handling NOR in yaffs1 mode.
+ */
+
+/* First set up for M18 with 1k chunks and 16-byte spares.
+ *
+ * NB We're using the oddball M18 modes of operation here
+ * The chip is 64MB based at 0x0000, but YAFFS only going to use the top half
+ * ie. YAFFS will be from 32MB to 64MB.
+ *
+ * The M18 has two ways of writing data. Every Programming Region (1kbytes)
+ * can be programmed in two modes:
+ * * Object Mode 1024 bytes of write once data.
+ * * Control Mode: 512bytes of bit-writeable data.
+ * This is arranged as 32 * (16 bytes of bit-writable followed by 16 bytes of "dont touch")
+ *
+ * The block size is 256kB, making 128 blocks in the 32MB YAFFS area.
+ * Each block comprises:
+ * Offset 0k: 248 x 1k data pages
+ * Offset 248k: 248 x 32-byte spare areas implemented as 16 bytes of spare followed by 16 bytes untouched)
+ * Offset 248k + (248 * 32): Format marker
+ *
+ */
+
+const char *yaffs_norif1_c_version = "$Id: yaffs_norif1.c,v 1.1 2008-11-07 00:34:47 charles Exp $";
+
+#include "yaffs_norif1.h"
+
+#include "yportenv.h"
+
+#include "yaffs_flashif.h"
+#include "yaffs_guts.h"
+
+#include "devextras.h"
+
+#define SPARE_BYTES_PER_CHUNK 16
+#define M18_SKIP 16
+#define PROG_REGION_SIZE 1024
+#define BLOCK_SIZE_IN_BYTES (256*1024)
+#define CHUNKS_PER_BLOCK 248
+#define SPARE_AREA_OFFSET (CHUNKS_PER_BLOCK * PROG_REGION_SIZE)
+
+#define FORMAT_OFFSET (SPARE_AREA_OFFSET + CHUNKS_PER_BLOCK * (SPARE_BYTES_PER_CHUNK + M18_SKIP))
+
+#define FORMAT_VALUE 0x1234
+
+#define DATA_BYTES_PER_CHUNK 1024
+#define BLOCKS_IN_DEVICE (32*1024/256)
+
+
+#define YNOR_PREMARKER (0xF6)
+#define YNOR_POSTMARKER (0xF0)
+
+
+#if 1
+
+/* Compile this for a simulation */
+#include "ynorsim.h"
+#define ynorif1_FlashInit() ynorsim_Initialise()
+#define ynorif1_FlashDeinit() ynorsim_Shutdown()
+#define ynorif1_FlashWrite32(addr,buf,nwords) ynorsim_Write32(addr,buf,nwords)
+#define ynorif1_FlashRead32(addr,buf,nwords) ynorsim_Read32(addr,buf,nwords)
+#define ynorif1_FlashEraseBlock(addr) ynorsim_EraseBlock(addr)
+#define DEVICE_BASE ynorsim_GetBase()
+#else
+
+/* Compile this for running on blob, hacked for yaffs access */
+#include "../blob/yflashrw.h"
+#define ynorif1_FlashInit() do{} while(0)
+#define ynorif1_FlashDeinit() do {} while(0)
+#define ynorif1_FlashWrite32(addr,buf,nwords) Y_FlashWrite(addr,buf,nwords)
+#define ynorif1_FlashRead32(addr,buf,nwords) Y_FlashRead(addr,buf,nwords)
+#define ynorif1_FlashEraseBlock(addr) Y_FlashErase(addr,BLOCK_SIZE_IN_BYTES)
+#define DEVICE_BASE (32 * 1024 * 1024)
+#endif
+
+__u32 *Block2Addr(yaffs_Device *dev, int blockNumber)
+{
+ __u32 addr;
+
+ addr = (__u32) DEVICE_BASE;
+ addr += blockNumber * BLOCK_SIZE_IN_BYTES;
+
+ return (__u32 *) addr;
+}
+
+__u32 *Block2FormatAddr(yaffs_Device *dev,int blockNumber)
+{
+ __u32 addr;
+
+ addr = (__u32) Block2Addr(dev,blockNumber);
+ addr += FORMAT_OFFSET;
+
+ return (__u32 *)addr;
+}
+__u32 *Chunk2DataAddr(yaffs_Device *dev,int chunkId)
+{
+ unsigned block;
+ unsigned chunkInBlock;
+ __u32 addr;
+
+ block = chunkId/dev->nChunksPerBlock;
+ chunkInBlock = chunkId % dev->nChunksPerBlock;
+
+ addr = (__u32) Block2Addr(dev,block);
+ addr += chunkInBlock * DATA_BYTES_PER_CHUNK;
+
+ return (__u32 *)addr;
+}
+
+__u32 *Chunk2SpareAddr(yaffs_Device *dev,int chunkId)
+{
+ unsigned block;
+ unsigned chunkInBlock;
+ __u32 addr;
+
+ block = chunkId/dev->nChunksPerBlock;
+ chunkInBlock = chunkId % dev->nChunksPerBlock;
+
+ addr = (__u32) Block2Addr(dev,block);
+ addr += SPARE_AREA_OFFSET;
+ addr += chunkInBlock * (SPARE_BYTES_PER_CHUNK + M18_SKIP);
+ return (__u32 *)addr;
+}
+
+
+void ynorif1_AndBytes(__u8*target, const __u8 *src, int nbytes)
+{
+ while(nbytes > 0){
+ *target &= *src;
+ target++;
+ src++;
+ nbytes--;
+ }
+}
+
+int ynorif1_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare)
+{
+ __u32 *dataAddr = Chunk2DataAddr(dev,chunkInNAND);
+ __u32 *spareAddr = Chunk2SpareAddr(dev,chunkInNAND);
+
+ yaffs_Spare tmpSpare;
+
+ /* We should only be getting called for one of 3 reasons:
+ * Writing a chunk: data and spare will not be NULL
+ * Writing a deletion marker: data will be NULL, spare not NULL
+ * Writing a bad block marker: data will be NULL, spare not NULL
+ */
+
+ if(sizeof(yaffs_Spare) != 16)
+ YBUG();
+
+ if(data && spare)
+ {
+ if(spare->pageStatus != 0xff)
+ YBUG();
+ /* Write a pre-marker */
+ memset(&tmpSpare,0xff,sizeof(tmpSpare));
+ tmpSpare.pageStatus = YNOR_PREMARKER;
+ ynorif1_FlashWrite32(spareAddr,(__u32 *)&tmpSpare,sizeof(yaffs_Spare)/4);
+
+ /* Write the data */
+ ynorif1_FlashWrite32(dataAddr,(__u32 *)data,dev->totalBytesPerChunk / 4);
+
+
+ memcpy(&tmpSpare,spare,sizeof(yaffs_Spare));
+
+ /* Write the real tags, but override the premarker*/
+ tmpSpare.pageStatus = YNOR_PREMARKER;
+ ynorif1_FlashWrite32(spareAddr,(__u32 *)&tmpSpare,sizeof(yaffs_Spare)/4);
+
+ /* Write a post-marker */
+ tmpSpare.pageStatus = YNOR_POSTMARKER;
+ ynorif1_FlashWrite32(spareAddr,(__u32 *)&tmpSpare,sizeof(tmpSpare)/4);
+
+ } else if(spare){
+ /* This has to be a read-modify-write operation to handle NOR-ness */
+
+ ynorif1_FlashRead32(spareAddr,(__u32 *)&tmpSpare,16/ 4);
+
+ ynorif1_AndBytes((__u8 *)&tmpSpare,(__u8 *)spare,sizeof(yaffs_Spare));
+
+ ynorif1_FlashWrite32(spareAddr,(__u32 *)&tmpSpare,16/ 4);
+ }
+ else {
+ YBUG();
+ }
+
+
+ return YAFFS_OK;
+
+}
+
+int ynorif1_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
+{
+
+ __u32 *dataAddr = Chunk2DataAddr(dev,chunkInNAND);
+ __u32 *spareAddr = Chunk2SpareAddr(dev,chunkInNAND);
+
+ if(data)
+ {
+ ynorif1_FlashRead32(dataAddr,(__u32 *)data,dev->totalBytesPerChunk / 4);
+ }
+
+ if(spare)
+ {
+ ynorif1_FlashRead32(spareAddr,(__u32 *)spare,16/ 4);
+
+ /* If the page status is 0xF then it was written properly
+ * so change that to 0xFF so that the rest of yaffs is happy.
+ */
+ if(spare->pageStatus == YNOR_POSTMARKER)
+ spare->pageStatus = 0xFF;
+ }
+
+
+ return YAFFS_OK;
+
+}
+
+static int ynorif1_FormatBlock(yaffs_Device *dev, int blockNumber)
+{
+ __u32 *blockAddr = Block2Addr(dev,blockNumber);
+ __u32 *formatAddr = Block2FormatAddr(dev,blockNumber);
+ __u32 formatValue = FORMAT_VALUE;
+
+ ynorif1_FlashEraseBlock(blockAddr);
+ ynorif1_FlashWrite32(formatAddr,&formatValue,1);
+
+ return YAFFS_OK;
+}
+
+static int ynorif1_UnformatBlock(yaffs_Device *dev, int blockNumber)
+{
+ __u32 *formatAddr = Block2FormatAddr(dev,blockNumber);
+ __u32 formatValue = 0;
+
+ ynorif1_FlashWrite32(formatAddr,&formatValue,1);
+
+ return YAFFS_OK;
+}
+
+static int ynorif1_IsBlockFormatted(yaffs_Device *dev, int blockNumber)
+{
+ __u32 *formatAddr = Block2FormatAddr(dev,blockNumber);
+ __u32 formatValue;
+
+
+ ynorif1_FlashRead32(formatAddr,&formatValue,1);
+
+ return (formatValue == FORMAT_VALUE);
+}
+
+int ynorif1_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
+{
+
+ if(blockNumber < 0 || blockNumber >= BLOCKS_IN_DEVICE)
+ {
+ T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
+ return YAFFS_FAIL;
+ }
+ else
+ {
+ ynorif1_UnformatBlock(dev,blockNumber);
+ ynorif1_FormatBlock(dev,blockNumber);
+ return YAFFS_OK;
+ }
+
+}
+
+int ynorif1_InitialiseNAND(yaffs_Device *dev)
+{
+ int i;
+
+ ynorif1_FlashInit();
+ /* Go through the blocks formatting them if they are not formatted */
+ for(i = dev->startBlock; i <= dev->endBlock; i++){
+ if(!ynorif1_IsBlockFormatted(dev,i)){
+ ynorif1_FormatBlock(dev,i);
+ }
+ }
+ return YAFFS_OK;
+}
+
+int ynorif1_DeinitialiseNAND(yaffs_Device *dev)
+{
+
+ ynorif1_FlashDeinit();
+
+ return YAFFS_OK;
+}
+
+
--- /dev/null
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <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_NOR_IF1_H__
+#define __YAFFS_NOR_IF1_H__
+
+#include "yaffs_guts.h"
+
+int ynorif1_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare);
+int ynorif1_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);
+int ynorif1_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
+int ynorif1_InitialiseNAND(yaffs_Device *dev);
+int ynorif1_DeinitialiseNAND(yaffs_Device *dev);
+
+#endif
+
+
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "yaffsfs.h"
+
+#include "nor_stress.h"
+
+
+
+void BadUsage(void)
+{
+ printf("usage root_dir test_id\n");
+ printf(" test_id: fw_update fw_update_init\n");
+ exit(2);
+}
+int main(int argc, const char *argv[])
+{
+ yaffs_StartUp();
+ if(argc == 3) {
+ if(!strcmp(argv[2],"fw_update_init")){
+ NorStressTestInitialise(argv[1]);
+ }
+ else if(!strcmp(argv[2],"fw_update")){
+ NorStressTestRun(argv[1]);
+ }
+ else
+ BadUsage();
+ }
+ else
+ BadUsage();
+ return 0;
+}
#include "yaffsfs.h"
#include "yaffs_fileem2k.h"
#include "yaffs_nandemul2k.h"
+#include "yaffs_norif1.h"
#include <errno.h>
unsigned yaffs_traceMask =
YAFFS_TRACE_SCAN |
- YAFFS_TRACE_GC | YAFFS_TRACE_GC_DETAIL |
+ YAFFS_TRACE_GC |
YAFFS_TRACE_ERASE |
+ YAFFS_TRACE_ERROR |
YAFFS_TRACE_TRACING |
YAFFS_TRACE_ALLOCATE |
YAFFS_TRACE_CHECKPOINT |
YAFFS_TRACE_BAD_BLOCKS |
+
+/* YAFFS_TRACE_VERIFY | */
0;
#include "yaffs_flashif2.h"
#include "yaffs_nandemul2k.h"
-static yaffs_Device ramDev;
-static yaffs_Device bootDev;
+static yaffs_Device ram1Dev;
+static yaffs_Device nand2;
static yaffs_Device flashDev;
static yaffs_Device ram2kDev;
+static yaffs_Device m18_1Dev;
static yaffsfs_DeviceConfiguration yaffsfs_config[] = {
-#if 0
- { "/ram", &ramDev},
- { "/boot", &bootDev},
- { "/flash/", &flashDev},
- { "/ram2k", &ram2kDev},
- {(void *)0,(void *)0}
-#else
- //{ "/", &ramDev},
- { "/flash/yaffs1", &bootDev},
- { "/flash/yaffs2", &flashDev},
+
+ { "/ram1", &ram1Dev},
+ { "/M18-1", &m18_1Dev},
+ { "/yaffs2", &flashDev},
{ "/ram2k", &ram2kDev},
{ "/flash/bigblock", &flashDev},
{(void *)0,(void *)0} /* Null entry to terminate list */
-#endif
};
yaffsfs_LocalInitialisation();
// Set up devices
- // /ram
- memset(&ramDev,0,sizeof(ramDev));
- ramDev.totalBytesPerChunk = 512;
- ramDev.nChunksPerBlock = 32;
- ramDev.nReservedBlocks = 2; // Set this smaller for RAM
- ramDev.startBlock = 0; // Can use block 0
- ramDev.endBlock = 127; // Last block in 2MB.
- //ramDev.useNANDECC = 1;
- ramDev.nShortOpCaches = 0; // Disable caching on this device.
- ramDev.genericDevice = (void *) 0; // Used to identify the device in fstat.
- ramDev.writeChunkWithTagsToNAND = yramdisk_WriteChunkWithTagsToNAND;
- ramDev.readChunkWithTagsFromNAND = yramdisk_ReadChunkWithTagsFromNAND;
- ramDev.eraseBlockInNAND = yramdisk_EraseBlockInNAND;
- ramDev.initialiseNAND = yramdisk_InitialiseNAND;
-
- // /boot (yaffs1)
- memset(&bootDev,0,sizeof(bootDev));
- bootDev.totalBytesPerChunk = 512;
- bootDev.nChunksPerBlock = 32;
- bootDev.nReservedBlocks = 5;
- bootDev.startBlock = 0; // Can use block 0
- bootDev.endBlock = 63; // Last block
- //bootDev.useNANDECC = 0; // use YAFFS's ECC
- bootDev.nShortOpCaches = 10; // Use caches
- bootDev.genericDevice = (void *) 1; // Used to identify the device in fstat.
- bootDev.writeChunkToNAND = yflash_WriteChunkToNAND;
- bootDev.readChunkFromNAND = yflash_ReadChunkFromNAND;
- bootDev.eraseBlockInNAND = yflash_EraseBlockInNAND;
- bootDev.initialiseNAND = yflash_InitialiseNAND;
-
+ // /ram1 ram, yaffs1
+ memset(&ram1Dev,0,sizeof(ram1Dev));
+ ram1Dev.totalBytesPerChunk = 512;
+ ram1Dev.nChunksPerBlock = 32;
+ ram1Dev.nReservedBlocks = 2; // Set this smaller for RAM
+ ram1Dev.startBlock = 0; // Can use block 0
+ ram1Dev.endBlock = 127; // Last block in 2MB.
+ //ram1Dev.useNANDECC = 1;
+ ram1Dev.nShortOpCaches = 0; // Disable caching on this device.
+ ram1Dev.genericDevice = (void *) 0; // Used to identify the device in fstat.
+ ram1Dev.writeChunkWithTagsToNAND = yramdisk_WriteChunkWithTagsToNAND;
+ ram1Dev.readChunkWithTagsFromNAND = yramdisk_ReadChunkWithTagsFromNAND;
+ ram1Dev.eraseBlockInNAND = yramdisk_EraseBlockInNAND;
+ ram1Dev.initialiseNAND = yramdisk_InitialiseNAND;
+
+ // /M18-1 yaffs1 on M18 nor sim
+ memset(&m18_1Dev,0,sizeof(m18_1Dev));
+ m18_1Dev.totalBytesPerChunk = 1024;
+ m18_1Dev.nChunksPerBlock =248;
+ m18_1Dev.nReservedBlocks = 2;
+ m18_1Dev.startBlock = 0; // Can use block 0
+ m18_1Dev.endBlock = 127; // Last block
+ m18_1Dev.useNANDECC = 0; // use YAFFS's ECC
+ m18_1Dev.nShortOpCaches = 10; // Use caches
+ m18_1Dev.genericDevice = (void *) 1; // Used to identify the device in fstat.
+ m18_1Dev.writeChunkToNAND = ynorif1_WriteChunkToNAND;
+ m18_1Dev.readChunkFromNAND = ynorif1_ReadChunkFromNAND;
+ m18_1Dev.eraseBlockInNAND = ynorif1_EraseBlockInNAND;
+ m18_1Dev.initialiseNAND = ynorif1_InitialiseNAND;
+ m18_1Dev.deinitialiseNAND = ynorif1_DeinitialiseNAND;
// /flash (yaffs2)
--- /dev/null
+
+
+#include "ynorsim.h"
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+
+#define YNORSIM_FNAME "ynorsimdata"
+
+/* Set YNORSIM_BIT_CHANGES to a a value from 1..30 to
+ *simulate bit flipping as the programming happens.
+ * A low value results in faster simulation with less chance of encountering a partially programmed
+ * word.
+ */
+
+//#define YNORSIM_BIT_CHANGES 15
+#define YNORSIM_BIT_CHANGES 1
+
+/* Simulate 32MB of flash in 256k byte blocks.
+ * This stuff is x32.
+ */
+
+#define YNORSIM_BLOCK_SIZE_U32 (256*1024/4)
+#define YNORSIM_DEV_SIZE_U32 (32*1024 * 1024/4)
+
+static __u32 word[YNORSIM_DEV_SIZE_U32];
+
+
+static void NorError(void)
+{
+ printf("Nor error\n");
+ while(1){}
+}
+
+static void ynorsim_SaveImage(void)
+{
+ int h = open(YNORSIM_FNAME, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
+ write(h,word,sizeof(word));
+ close(h);
+}
+
+static void ynorsim_RestoreImage(void)
+{
+ int h = open(YNORSIM_FNAME, O_RDONLY, S_IREAD | S_IWRITE);
+ memset(word,0xFF,sizeof(word));
+ read(h,word,sizeof(word));
+ close(h);
+}
+
+
+static void ynorsim_PowerFail(void)
+{
+ ynorsim_SaveImage();
+ exit(1);
+}
+
+static int initialised = 0;
+static int remaining_ops;
+static int nops_so_far;
+
+static void ynorsim_MaybePowerFail(void)
+{
+
+ nops_so_far++;
+
+
+ remaining_ops--;
+ if(remaining_ops < 1){
+ printf("Simulated power failure after %d operations\n",nops_so_far);
+ ynorsim_PowerFail();
+ }
+}
+
+static void ynorsim_Ready(void)
+{
+ if(initialised)
+ return;
+ srand(time(NULL));
+ remaining_ops = 1000000000;
+ remaining_ops = (rand() % 10000) * 10000;
+ ynorsim_RestoreImage();
+}
+
+void ynorsim_Read32(__u32 *addr,__u32 *buf, int nwords)
+{
+ while(nwords > 0){
+ *buf = *addr;
+ buf++;
+ addr++;
+ nwords--;
+ }
+}
+
+void ynorsim_WriteOneWord32(__u32 *addr,__u32 val)
+{
+ __u32 tmp;
+ __u32 m;
+ int i;
+
+ tmp = *addr;
+ if(val & ~tmp){
+ // Fail due to trying to change a zero into a 1
+ printf("attempt to set a zero to one (%x)->(%x)\n",tmp,val);
+ NorError();
+ }
+
+ for(i = 0; i < YNORSIM_BIT_CHANGES; i++){
+ m = 1 << (rand() & 31);
+ if(!(m & val)){
+ tmp &= ~m;
+ *addr = tmp;
+ ynorsim_MaybePowerFail();
+ }
+
+ }
+
+ *addr = tmp & val;
+ ynorsim_MaybePowerFail();
+}
+
+void ynorsim_Write32(__u32 *addr, __u32 *buf, int nwords)
+{
+ while(nwords >0){
+ ynorsim_WriteOneWord32(addr,*buf);
+ addr++;
+ buf++;
+ nwords--;
+ }
+}
+
+void ynorsim_EraseBlock(__u32 *addr)
+{
+ /* Todo... bit flipping */
+ memset(addr,0xFF,YNORSIM_BLOCK_SIZE_U32 * 4);
+}
+
+void ynorsim_Initialise(void)
+{
+ ynorsim_Ready();
+}
+
+void ynorsim_Shutdown(void)
+{
+ ynorsim_SaveImage();
+ initialised=0;
+}
+
+__u32 *ynorsim_GetBase(void)
+{
+ return word;
+}
--- /dev/null
+
+#ifndef __Y_NORSIM_H__
+#define __Y_NORSIM_H__
+
+#include "yaffs_guts.h"
+
+void ynorsim_Read32(__u32 *addr, __u32 *data, int nwords);
+void ynorsim_Write32(__u32 *addr, __u32 *data, int nwords);
+void ynorsim_EraseBlock(__u32 *addr);
+void ynorsim_Shutdown(void);
+void ynorsim_Initialise(void);
+__u32 * ynorsim_GetBase(void);
+
+#endif
*/
const char *yaffs_guts_c_version =
- "$Id: yaffs_guts.c,v 1.61 2008-10-30 18:25:21 charles Exp $";
+ "$Id: yaffs_guts.c,v 1.62 2008-11-07 00:32:20 charles Exp $";
#include "yportenv.h"
static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
+static void yaffs_VerifyDirectory(yaffs_Object *directory);
#ifdef YAFFS_PARANOID
static int yaffs_CheckFileSanity(yaffs_Object * in);
#else
}
-static void yaffs_VerifyDirectory(yaffs_Object *obj)
-{
- if(obj && yaffs_SkipVerification(obj->myDev))
- return;
-
-}
static void yaffs_VerifyHardLink(yaffs_Object *obj)
{
__u16 sum = 0;
__u16 i = 1;
- YUCHAR *bname = (YUCHAR *) name;
+ const YUCHAR *bname = (const YUCHAR *) name;
if (bname) {
while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
bname++;
}
}
+
return sum;
}
static void yaffs_SetObjectName(yaffs_Object * obj, const YCHAR * name)
{
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+ memset(obj->shortName,0,sizeof (YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) {
yaffs_strcpy(obj->shortName, name);
} else {
{
yaffs_Object *tn = NULL;
+#ifdef VALGRIND_TEST
+ tn = YMALLOC(sizeof(yaffs_Object));
+#else
/* If there are none left make more */
if (!dev->freeObjects) {
yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
dev->freeObjects =
(yaffs_Object *) (dev->freeObjects->siblings.next);
dev->nFreeObjects--;
-
+ }
+#endif
+ if(tn){
/* Now sweeten it up... */
memset(tn, 0, sizeof(yaffs_Object));
YINIT_LIST_HEAD(&(tn->hardLinks));
YINIT_LIST_HEAD(&(tn->hashLink));
YINIT_LIST_HEAD(&tn->siblings);
+
+
+ /* Now make the directory sane */
+ if(dev->rootDir){
+ tn->parent = dev->rootDir;
+ ylist_add(&(tn->siblings),&dev->rootDir->variant.directoryVariant.children);
+ }
/* Add it to the lost and found directory.
* NB Can't put root or lostNFound in lostNFound so
yaffs_Device *dev = tn->myDev;
+
+ if(tn->parent)
+ YBUG();
+ if(!ylist_empty(&tn->siblings))
+ YBUG();
+
+
#ifdef __KERNEL__
if (tn->myInode) {
/* We're still hooked up to a cached inode.
yaffs_UnhashObject(tn);
+#ifdef VALGRIND_TEST
+ YFREE(tn);
+#else
/* Link into the free list. */
tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
dev->freeObjects = tn;
dev->nFreeObjects++;
-
+#endif
dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
}
theObject->yst_atime = theObject->yst_mtime =
theObject->yst_ctime = Y_CURRENT_TIME;
#endif
+
+#if 0
+ theObject->sum_prev = 12345;
+ theObject->sum_trailer = 6789;
+#endif
+
switch (type) {
case YAFFS_OBJECT_TYPE_FILE:
theObject->variant.fileVariant.fileSize = 0;
int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName,
yaffs_Object * newDir, const YCHAR * newName)
{
- yaffs_Object *obj;
- yaffs_Object *existingTarget;
+ yaffs_Object *obj=NULL;
+ yaffs_Object *existingTarget=NULL;
int force = 0;
+
+
+ if(!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ YBUG();
+ if(!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ YBUG();
#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
/* Special case for case insemsitive systems (eg. WinCE).
}
#endif
- obj = yaffs_FindObjectByName(oldDir, oldName);
- /* Check new name to long. */
- if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK &&
- yaffs_strlen(newName) > YAFFS_MAX_ALIAS_LENGTH)
- /* ENAMETOOLONG */
- return YAFFS_FAIL;
- else if (obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK &&
- yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
+ else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
/* ENAMETOOLONG */
return YAFFS_FAIL;
+ obj = yaffs_FindObjectByName(oldDir, oldName);
+
if (obj && obj->renameAllowed) {
/* Now do the handling for an existing target, if there is one */
static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
{
- if(!dev->nCheckpointBlocksRequired){
+ if(!dev->nCheckpointBlocksRequired &&
+ dev->isYaffs2){
/* Not a valid value so recalculate */
int nBytes = 0;
int nBlocks;
int reservedBlocks = dev->nReservedBlocks;
int checkpointBlocks;
- checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
- if(checkpointBlocks < 0)
- checkpointBlocks = 0;
+ if(dev->isYaffs2){
+ checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) -
+ dev->blocksInCheckpoint;
+ if(checkpointBlocks < 0)
+ checkpointBlocks = 0;
+ } else {
+ checkpointBlocks =0;
+ }
reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
tags.objectId, tags.chunkId, tags.byteCount));
}
- if (object && object->deleted
- && tags.chunkId != 0) {
- /* Data chunk in a deleted file, throw it away
+ if (object &&
+ object->deleted &&
+ object->softDeleted &&
+ tags.chunkId != 0) {
+ /* Data chunk in a soft deleted file, throw it away
* It's a soft deleted data chunk,
* No need to copy this, just forget about it and
* fix up the object.
newTags.serialNumber =
(prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
newTags.byteCount = nBytes;
+
+ if(nBytes < 1 || nBytes > dev->totalBytesPerChunk){
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
+ while(1){}
+ }
+
+
newChunkId =
yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
//chunk = offset / dev->nDataBytesPerChunk + 1;
//start = offset % dev->nDataBytesPerChunk;
yaffs_AddrToChunk(dev,offset,&chunk,&start);
+
+ if(chunk * dev->nDataBytesPerChunk + start != offset ||
+ start >= dev->nDataBytesPerChunk){
+ T(YAFFS_TRACE_ERROR,(TSTR("AddrToChunk of offset %d gives chunk %d start %d"TENDSTR),
+ (int)offset, chunk,start));
+ }
chunk++;
/* OK now check for the curveball where the start and end are in
* and the inode associated with the file.
* It does not delete the links associated with the file.
*/
+
static int yaffs_UnlinkFile(yaffs_Object * in)
{
int retVal;
int immediateDeletion = 0;
- if (1) {
#ifdef __KERNEL__
- if (!in->myInode) {
- immediateDeletion = 1;
-
- }
+ if (!in->myInode) {
+ immediateDeletion = 1;
+ }
#else
- if (in->inUse <= 0) {
- immediateDeletion = 1;
-
- }
+ if (in->inUse <= 0) {
+ immediateDeletion = 1;
+ }
#endif
- if (immediateDeletion) {
- retVal =
- yaffs_ChangeObjectName(in, in->myDev->deletedDir,
- _Y("deleted"), 0, 0);
- T(YAFFS_TRACE_TRACING,
- (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
- in->objectId));
- in->deleted = 1;
- in->myDev->nDeletedFiles++;
- if (0 && in->myDev->isYaffs2) {
- yaffs_ResizeFile(in, 0);
- }
- yaffs_SoftDeleteFile(in);
- } else {
- retVal =
- yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
- _Y("unlinked"), 0, 0);
- }
+ if (immediateDeletion) {
+ retVal =
+ yaffs_ChangeObjectName(in, in->myDev->deletedDir,
+ _Y("deleted"), 0, 0);
+ T(YAFFS_TRACE_TRACING,
+ (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
+ in->objectId));
+ in->deleted = 1;
+ in->myDev->nDeletedFiles++;
+ if (1 || in->myDev->isYaffs2) {
+ yaffs_ResizeFile(in, 0);
+ }
+ yaffs_SoftDeleteFile(in);
+ } else {
+ retVal =
+ yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
+ _Y("unlinked"), 0, 0);
}
+
+
return retVal;
}
int yaffs_DeleteFile(yaffs_Object * in)
{
int retVal = YAFFS_OK;
+ int deleted = in->deleted;
+
+ yaffs_ResizeFile(in,0);
if (in->nDataChunks > 0) {
- /* Use soft deletion if there is data in the file */
+ /* Use soft deletion if there is data in the file.
+ * That won't be the case if it has been resized to zero.
+ */
if (!in->unlinked) {
retVal = yaffs_UnlinkFile(in);
}
if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
- in->deleted = 1;
+ in->deleted = deleted = 1;
in->myDev->nDeletedFiles++;
yaffs_SoftDeleteFile(in);
}
- return in->deleted ? YAFFS_OK : YAFFS_FAIL;
+ return deleted ? YAFFS_OK : YAFFS_FAIL;
} else {
/* The file has no data chunks so we toss it immediately */
yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
/* remove this hardlink from the list assocaited with the equivalent
* object
*/
- ylist_del(&in->hardLinks);
+ ylist_del_init(&in->hardLinks);
return yaffs_DoGenericObjectDeletion(in);
}
break;
}
- if (parent == dev->deletedDir) {
+/*
+ if (parent == dev->deletedDir) {
yaffs_DestroyObject(in);
bi->hasShrinkHeader = 1;
}
+*/
}
}
}
/*------------------------------ Directory Functions ----------------------------- */
+static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
+{
+ struct ylist_head *lh;
+ yaffs_Object *listObj;
+
+ int count = 0;
+
+ if(!obj)
+ YBUG();
+
+ if(yaffs_SkipVerification(obj->myDev))
+ return;
+
+ if(!obj->parent)
+ YBUG();
+
+ if(obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ 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)
+ YBUG();
+
+
+}
+
+static void yaffs_VerifyDirectory(yaffs_Object *directory)
+{
+
+ struct ylist_head *lh;
+ yaffs_Object *listObj;
+
+ if(!directory)
+ YBUG();
+
+ if(yaffs_SkipVerification(directory->myDev))
+ return;
+
+
+ if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ 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)
+ YBUG();
+ yaffs_VerifyObjectInDirectory(listObj);
+ }
+ }
+
+}
+
+
static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj)
{
yaffs_Device *dev = obj->myDev;
+ yaffs_Object *parent;
+ yaffs_VerifyObjectInDirectory(obj);
+ parent = obj->parent;
+
+ yaffs_VerifyDirectory(parent);
+
if(dev && dev->removeObjectCallback)
dev->removeObjectCallback(obj);
+
ylist_del_init(&obj->siblings);
obj->parent = NULL;
+
+ yaffs_VerifyDirectory(parent);
+
}
if (obj->siblings.prev == NULL) {
/* Not initialised */
- YINIT_LIST_HEAD(&obj->siblings);
+ YBUG();
- } else if (!ylist_empty(&obj->siblings)) {
- /* If it is holed up somewhere else, un hook it */
- yaffs_RemoveObjectFromDirectory(obj);
- }
+ } else if (ylist_empty(&obj->siblings)) {
+ YBUG();
+ }
+
+
+ yaffs_VerifyDirectory(directory);
+
+ yaffs_RemoveObjectFromDirectory(obj);
+
+
/* Now add it */
ylist_add(&obj->siblings, &directory->variant.directoryVariant.children);
obj->parent = directory;
obj->myDev->nUnlinkedFiles++;
obj->renameAllowed = 0;
}
+
+ yaffs_VerifyDirectory(directory);
+ yaffs_VerifyObjectInDirectory(obj);
+
+
}
yaffs_Object *yaffs_FindObjectByName(yaffs_Object * directory,
if (i) {
l = ylist_entry(i, yaffs_Object, siblings);
+ if(l->parent != directory)
+ YBUG();
+
yaffs_CheckObjectDetailsLoaded(l);
/* Special case for lost-n-found */
/* Check geometry parameters. */
if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) ||
- (!dev->isYaffs2 && dev->totalBytesPerChunk != 512) ||
+ (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) ||
(dev->inbandTags && !dev->isYaffs2 ) ||
dev->nChunksPerBlock < 2 ||
dev->nReservedBlocks < 2 ||
dev->isMounted = 0;
+
+ if(dev->deinitialiseNAND)
+ dev->deinitialiseNAND(dev);
}
}
#ifndef CONFIG_YAFFS_NO_YAFFS1
typedef struct {
- unsigned chunkId:20;
- unsigned serialNumber:2;
- unsigned byteCount:10;
- unsigned objectId:18;
- unsigned ecc:12;
- unsigned unusedStuff:2;
+ unsigned chunkId:20;
+ unsigned serialNumber:2;
+ unsigned byteCountLSB:10;
+ unsigned objectId:18;
+ unsigned ecc:12;
+ unsigned byteCountMSB:2;
} yaffs_Tags;
__u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is
* still in the inode cache. Free of object is defered.
* until the inode is released.
- */
+ */
- __u8 serial; /* serial number of chunk in NAND. Cached here */
- __u16 sum; /* sum of the name to speed searching */
+ __u8 serial; /* serial number of chunk in NAND. Cached here */
+/* __u16 sum_prev; */
+ __u16 sum; /* sum of the name to speed searching */
+/* __u16 sum_trailer; */
struct yaffs_DeviceStruct *myDev; /* The device I'm on */
__u32 objectId; /* the object id value */
- __u32 yst_mode;
+ __u32 yst_mode;
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
- YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
+ YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
#endif
#ifndef __KERNEL__
int (*readChunkFromNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, __u8 * data,
yaffs_Spare * spare);
- int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev,
- int blockInNAND);
- int (*initialiseNAND) (struct yaffs_DeviceStruct * dev);
+ int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev,
+ int blockInNAND);
+ int (*initialiseNAND) (struct yaffs_DeviceStruct * dev);
+ int (*deinitialiseNAND) (struct yaffs_DeviceStruct * dev);
#ifdef CONFIG_YAFFS_YAFFS2
- int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev,
+ int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, const __u8 * data,
const yaffs_ExtendedTags * tags);
int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev,
} else {
tags.objectId = eTags->objectId;
tags.chunkId = eTags->chunkId;
- tags.byteCount = eTags->byteCount;
+
+ tags.byteCountLSB = eTags->byteCount & 0x3ff;
+
+ if(dev->nDataBytesPerChunk >= 1024){
+ tags.byteCountMSB = (eTags->byteCount >> 10) & 3;
+ } else {
+ tags.byteCountMSB = 3;
+ }
+
+
tags.serialNumber = eTags->serialNumber;
if (!dev->useNANDECC && data) {
eTags->objectId = tags.objectId;
eTags->chunkId = tags.chunkId;
- eTags->byteCount = tags.byteCount;
+ eTags->byteCount = tags.byteCountLSB;
+
+ if(dev->nDataBytesPerChunk >= 1024)
+ eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10);
+
eTags->serialNumber = tags.serialNumber;
}
}