From d3a46536d1812c81e1c494235ce8f7e25ebb0e1b Mon Sep 17 00:00:00 2001 From: charles Date: Tue, 14 Jan 2003 23:15:29 +0000 Subject: [PATCH] *** empty log message *** --- Documentation/yaffs2.html | 40 +- mtdemul/nandemul.c | 2 +- snMakefile | 6 +- utils/Makefile | 2 +- utils/mkyaffs | Bin 16029 -> 16029 bytes wince/yaffsfsd.c | 1137 +++++++++++++++++++++++-------------- yaffs_fileem.c | 2 +- yaffs_fs.c | 51 +- yaffs_guts.c | 982 +++++++++++++++++++++----------- yaffs_guts.h | 106 ++-- yaffs_mtdif.c | 28 +- yaffsdev.c | 76 ++- yaffsdev.proj | Bin 53248 -> 53248 bytes yportenv.h | 48 +- 14 files changed, 1662 insertions(+), 818 deletions(-) diff --git a/Documentation/yaffs2.html b/Documentation/yaffs2.html index e83dcc6..9014465 100644 --- a/Documentation/yaffs2.html +++ b/Documentation/yaffs2.html @@ -7,7 +7,7 @@ - +

YAFFS2

@@ -224,7 +224,7 @@ sequence Id order) rather than in their order on the media. This implies that at start up, the blocks must be read and their block sequence determined.

Performance

-

These numbers are indicative of relative performance. These only +

These numbers are indicative of relative performance. These only apply to the NAND data transfer and do not include other overheads.

As an example, read/write cycle times of 100nS are used (though NAND can typically do 50nS), "seek time" of 10uS and @@ -747,7 +747,41 @@ transfer time relative to an 8-bit bus.



-

$Id: yaffs2.html,v 1.1 2002-11-26 01:15:37 charles Exp $

+

MTD Interface

+

As mentioned before, YAFFS2 requires a chunk-size of at least 1kB +to get a large enough spare area to support the increased size of the +tags. This is not really a disadvantage, but should rather be viewed +as an opportunity to exploit the NAND hardware more effectively. In +particular:

+ +

To this end, yaffs_guts is being re-crafted to support arbitrary +chunk size (power of 2, >= 1024), with arbitrary block size.

+

Currently, YAFFS also makes some other assumptions which will need +to be changed:

+ +

Some of these differences can be absorbed in the yaffs_mtd layer. +Some will need to be handles inside the mtd itself.

+

$Id: yaffs2.html,v 1.2 2003-01-14 23:15:41 charles Exp $





diff --git a/mtdemul/nandemul.c b/mtdemul/nandemul.c index 12fe39d..52a6a64 100644 --- a/mtdemul/nandemul.c +++ b/mtdemul/nandemul.c @@ -30,7 +30,7 @@ #include #include #include - +#include #define T(x) printk x #define ALLOCATE(x) kmalloc(x,GFP_KERNEL) diff --git a/snMakefile b/snMakefile index c27a5cb..cbd34df 100644 --- a/snMakefile +++ b/snMakefile @@ -1,6 +1,6 @@ ######################################################### # Makefile auto generated by Cygnus Source Navigator. -# Target: yaffsdev_disk Date: Nov 26 2002 Time: 01:05:25 PM +# Target: yaffsdev_disk Date: Dec 18 2002 Time: 04:44:42 PM # @@ -70,9 +70,9 @@ yaffsdev: $(yaffsdev_disk_OBJECTS) nand_ecc.o: /opt/yaffs/yportenv.h -yaffs_fileem.o: /opt/2.4.18/linux/include/linux/stat.h /opt/2.4.18/linux/include/linux/types.h /usr/include/fcntl.h /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h /usr/include/unistd.h /opt/yaffs/yaffs_fileem.h /opt/yaffs/yaffs_guts.h /opt/yaffs/yaffsinterface.h +yaffs_fileem.o: /opt/yaffs/yaffs_fileem.h /opt/yaffs/yaffs_guts.h /opt/yaffs/yaffsinterface.h yaffs_guts.o: /opt/yaffs/yaffs_guts.h /opt/yaffs/yaffsinterface.h /opt/yaffs/yportenv.h -yaffsdev.o: /usr/include/fcntl.h /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h /usr/include/unistd.h /opt/yaffs/yaffs_fileem.h /opt/yaffs/yaffs_guts.h /opt/yaffs/yaffs_nandemul.h /opt/yaffs/yaffsinterface.h /opt/yaffs/yportenv.h +yaffsdev.o: /opt/yaffs/yaffs_fileem.h /opt/yaffs/yaffs_guts.h /opt/yaffs/yaffs_nandemul.h /opt/yaffs/yaffsinterface.h /opt/yaffs/yportenv.h clean: rm -f *.o diff --git a/utils/Makefile b/utils/Makefile index 1e0d432..f4f94c0 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -16,7 +16,7 @@ KERNELDIR = /usr/src/kernel-headers-2.4.18 -CFLAGS = -I$(KERNELDIR)/include -I.. -O2 -Wall +CFLAGS = -I$(KERNELDIR)/include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline diff --git a/utils/mkyaffs b/utils/mkyaffs index 5ed31f26b564af6b8a6523109ab970bf6083aa4f..28870e6b1680b473b66eae66a0c0a3652651968b 100755 GIT binary patch delta 34 pcmbPRJGXYjM@~^Q1tS9kV_gG7T|*NEBV#K=Q!5k0&1_uLO#r^~34s6r delta 34 ocmbPRJGXYjM@~^w1tS9kBV9uvGFC7!urf5ZGBDfB#x>mp0KSU}dH?_b diff --git a/wince/yaffsfsd.c b/wince/yaffsfsd.c index dc64c1a..7e202bf 100644 --- a/wince/yaffsfsd.c +++ b/wince/yaffsfsd.c @@ -1,6 +1,6 @@ /* * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffsfsd.c: The FSD layer for the WinCE version of YAFFS. + * ynandif.c: NAND interface functions for the WinCE port of YAFFS. * * Copyright (C) 2002 Trimble Navigation Ltd. * @@ -18,27 +18,42 @@ * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * $Id: yaffsfsd.c,v 1.1 2002-11-08 07:30:00 charles Exp $ + * Acknowledgements: + * Various clean-ups and WinCE4 support by Steve Fogle + * $Id: yaffsfsd.c,v 1.2 2003-01-14 23:15:41 charles Exp $ */ #include #include #include -#include +#include +//slf021104b begin +#include +//slf021104b end #define MAX_WIN_FILE 200 #define YFSD_NAME_LENGTH 128 #define YFSD_FULL_PATH_NAME_SIZE 500 - + #define YFSD_DISK_NAME L"Disk" -#define YFSD_BOOT_NAME L"Boot" +#define YFSD_BOOT_NAME L"Boot" #define PARTITION_START_NUMBER (1280) -#define MSGSTATE 1 +//#define MSGSTATE 1 +#define MSGSTATE 0 //#define DISABLE_BOOT_PARTITION - -unsigned yaffs_traceMask=0xffffffff; +//slf021105a begin +// Define DO_PARTITION_TABLE to cause the partition table +// information to be retrieved from the block driver. +//#define DO_PARTITION_TABLE +// How many partitions the disk might have. 2 gives +// space for the "Disk" and "Boot" partitions. +#define MAXPARTITIONS (2) +//slf021105a end + +//unsigned yaffs_traceMask=0xffffffff; +unsigned yaffs_traceMask=0; typedef struct @@ -59,10 +74,13 @@ typedef struct yaffs_Object *obj; DWORD offset; BOOL isopen; - BOOL writePermitted; BOOL dirty; WCHAR *fullName; yfsd_Volume *myVolume; + BOOL writePermitted; + BOOL readPermitted; + BOOL shareRead; + BOOL shareWrite; } yfsd_WinFile; @@ -92,9 +110,11 @@ typedef struct #include - -static yfsd_Volume disk_volume; -static yfsd_Volume boot_volume; +//slf021105a begin +//static yfsd_Volume disk_volume; +//static yfsd_Volume boot_volume; +static yfsd_Volume * disk_volumes[MAXPARTITIONS]; +//slf021105a end; static CRITICAL_SECTION yaffsLock; static CRITICAL_SECTION winFileLock; @@ -192,7 +212,10 @@ yfsd_WinFile * yfsd_GetWinFile(void) if(!yfsd_winFile[i].isopen) { yfsd_winFile[i].isopen = 1; - yfsd_winFile[i].writePermitted = 0; + yfsd_winFile[i].writePermitted = 0; + yfsd_winFile[i].readPermitted = 0; + yfsd_winFile[i].shareRead = 0; + yfsd_winFile[i].shareWrite = 0; yfsd_winFile[i].dirty = 0; yfsd_winFile[i].fullName = NULL; yfsd_winFile[i].obj = NULL; @@ -238,19 +261,47 @@ void yfsd_FlushAllFiles(void) if(yfsd_winFile[i].isopen && yfsd_winFile[i].obj) { - yaffs_FlushFile(yfsd_winFile[i].obj); + yaffs_FlushFile(yfsd_winFile[i].obj,1); } } yfsd_UnlockWinFiles(); yfsd_UnlockYAFFS(); -} +} + +//slf021104d begin +////////////////////////////////////////////////////////////////////// +// Search through winFiles to see if any are open. + +BOOL yfsd_FilesOpen(void) +{ + int i; + BOOL rval; + RETAILMSG (MSGSTATE, (L"YAFFS::FilesOpen?\r\n")); + + yfsd_LockWinFiles(); + for(i = 0, rval = FALSE; i < MAX_WIN_FILE; i++) + { + if(yfsd_winFile[i].isopen) + { + rval = TRUE; + break; + } + } + yfsd_UnlockWinFiles(); + return rval; +} +//slf021104d end PWSTR yfsd_FullPathName(PVOLUME vol, PWSTR fpn,int slength,PCWSTR pathName) { - // todo check for bounds - wcscpy(fpn,L"\\"); - wcscat(fpn,vol->volName); + // todo check for bounds + //slf021104b begin + //volName already has the initial backslash if it needs it. + //wcscpy(fpn,L"\\"); + //wcscat(fpn,vol->volName); + wcscpy(fpn,vol->volName); + //slf021104b end if(pathName[0] != '\\') { wcscat(fpn,L"\\"); @@ -263,7 +314,7 @@ PWSTR yfsd_FullPathName(PVOLUME vol, PWSTR fpn,int slength,PCWSTR pathName) // FILETIME is a 64-bit value as 100-nanosecond intervals since January 1, 1601. - + void yfsd_U32sToWinFileTime(__u32 target[2], FILETIME *wft) { @@ -347,15 +398,15 @@ void yfsd_ShellDirectoryChanged(PVOLUME pVolume, PWSTR fullPathName) } - - -// Minimal name test for now -BOOL yfsd_NameIsValid (const char *name) -{ - int length = strlen(name); - - return (length > 0 && length <= YFSD_NAME_LENGTH); - + + +// Minimal name test for now +BOOL yfsd_NameIsValid (const char *name) +{ + int length = strlen(name); + + return (length > 0 && length <= YFSD_NAME_LENGTH); + } // File attributes: @@ -375,58 +426,58 @@ BOOL yfsd_NameIsValid (const char *name) // // // in addition, GetAttributes also returns FILE_ATTRIBUTE_DIRECTORY - -// The following are valid ones we get presented with, -// but must filter out the stuff we don't unserstand -//#define FILE_ATTRIBUTE_READONLY 0x00000001 -//#define FILE_ATTRIBUTE_HIDDEN 0x00000002 -//#define FILE_ATTRIBUTE_SYSTEM 0x00000004 -//#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 -//#define FILE_ATTRIBUTE_ARCHIVE 0x00000020 -//#define FILE_ATTRIBUTE_INROM 0x00000040 -//#define FILE_ATTRIBUTE_ENCRYPTED 0x00000040 -//#define FILE_ATTRIBUTE_NORMAL 0x00000080 -//#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 -//#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 -//#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 -//#define FILE_ATTRIBUTE_COMPRESSED 0x00000800 -//#define FILE_ATTRIBUTE_OFFLINE 0x00001000 -//#define FILE_ATTRIBUTE_ROMSTATICREF 0x00001000 -//#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 -//#define FILE_ATTRIBUTE_ROMMODULE 0x00002000 - - -BOOL yfsd_CheckValidAttributes(DWORD attribs) -{ - - RETAILMSG (MSGSTATE, (L"Attributes:%X\r\n", attribs)); - -#if 0 - // If NORMAL, then nothing else - if(attribs & FILE_ATTRIBUTE_NORMAL && attribs != FILE_ATTRIBUTE_NORMAL) - return FALSE; - if(attribs == FILE_ATTRIBUTE_NORMAL) - return TRUE; -#endif - // Check that the bits are in the valid set - if(attribs & ~(0x3FE7)) - return FALSE; - - return TRUE; - + +// The following are valid ones we get presented with, +// but must filter out the stuff we don't unserstand +//#define FILE_ATTRIBUTE_READONLY 0x00000001 +//#define FILE_ATTRIBUTE_HIDDEN 0x00000002 +//#define FILE_ATTRIBUTE_SYSTEM 0x00000004 +//#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 +//#define FILE_ATTRIBUTE_ARCHIVE 0x00000020 +//#define FILE_ATTRIBUTE_INROM 0x00000040 +//#define FILE_ATTRIBUTE_ENCRYPTED 0x00000040 +//#define FILE_ATTRIBUTE_NORMAL 0x00000080 +//#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 +//#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 +//#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 +//#define FILE_ATTRIBUTE_COMPRESSED 0x00000800 +//#define FILE_ATTRIBUTE_OFFLINE 0x00001000 +//#define FILE_ATTRIBUTE_ROMSTATICREF 0x00001000 +//#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 +//#define FILE_ATTRIBUTE_ROMMODULE 0x00002000 + + +BOOL yfsd_CheckValidAttributes(DWORD attribs) +{ + + RETAILMSG (MSGSTATE, (L"Attributes:%X\r\n", attribs)); + +#if 0 + // If NORMAL, then nothing else + if(attribs & FILE_ATTRIBUTE_NORMAL && attribs != FILE_ATTRIBUTE_NORMAL) + return FALSE; + if(attribs == FILE_ATTRIBUTE_NORMAL) + return TRUE; +#endif + // Check that the bits are in the valid set + if(attribs & ~(0x3FE7)) + return FALSE; + + return TRUE; + } DWORD yfsd_GetObjectWinAttributes(yaffs_Object *obj) { DWORD result; - result = obj->st_mode & - (FILE_ATTRIBUTE_READONLY | - FILE_ATTRIBUTE_ARCHIVE | - FILE_ATTRIBUTE_HIDDEN | + result = obj->st_mode & + (FILE_ATTRIBUTE_READONLY | + FILE_ATTRIBUTE_ARCHIVE | + FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); - - if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) result |= FILE_ATTRIBUTE_DIRECTORY; + + if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) result |= FILE_ATTRIBUTE_DIRECTORY; if(result & ~FILE_ATTRIBUTE_NORMAL) { @@ -436,7 +487,7 @@ DWORD yfsd_GetObjectWinAttributes(yaffs_Object *obj) { result = FILE_ATTRIBUTE_NORMAL; } - + return result; } @@ -496,7 +547,7 @@ yaffs_Object *yfsd_FindDirectoryByWinPath(yaffs_Device *device, const wchar_t *p RETAILMSG (MSGSTATE, (L"YAFFS::FindByWinPath (%s) : ", path)); // start at the root of this device - current = yaffs_Root(device); + current = yaffs_Root(device); *processed = '\0'; do @@ -553,8 +604,14 @@ yaffs_Object *yfsd_FindObjectByWinPath(yaffs_Device *dev, PCWSTR pwsFileName ) BOOL YFSD_InitVolume(HDSK hdsk, yfsd_Volume *vol, int startBlock, int endBlock, PWSTR volName) { - RETAILMSG (MSGSTATE, (L"YAFFS::InitVolume\r\n")); - vol->volName = volName; + //slf021104b Begin + WCHAR szName[MAX_PATH]; + DWORD dwAvail; + //slf021104b end + RETAILMSG (MSGSTATE, (L"YAFFS::InitVolume\r\n")); + //slf021104b Begin filled in later. + //vol->volName = volName; + //slf021104b end yfsd_LockYAFFS(); @@ -568,7 +625,8 @@ BOOL YFSD_InitVolume(HDSK hdsk, yfsd_Volume *vol, int startBlock, int endBlock, vol->dev.initialiseNAND = ynandif_InitialiseNAND; vol->dev.startBlock = startBlock; if (endBlock != -1) - vol->dev.endBlock = endBlock; + vol->dev.endBlock = endBlock; + vol->dev.nShortOpCaches = 10; // a nice number of caches. // nBlocks is set the total size of the disk, not the partition // vol->dev.nBlocks = endBlock - startBlock + 1; @@ -611,11 +669,51 @@ BOOL YFSD_InitVolume(HDSK hdsk, yfsd_Volume *vol, int startBlock, int endBlock, yfsd_UnlockYAFFS(); vol->isMounted = 1; - - vol->mgrVolume = FSDMGR_RegisterVolume(hdsk,vol->volName,vol); + + //slf021104b begin + //vol->mgrVolume = FSDMGR_RegisterVolume(hdsk,vol->volName,vol); + // If the caller passed a volume name use it. + if (volName[0]) + wcscpy( szName, volName); +#if WINCEOSVER >= 400 + // The user passed an empty volume name. On CE 4.xx try to get + // if from the block driver (which got it from the registry). + else if (!FSDMGR_DiskIoControl(hdsk, DISK_IOCTL_GETNAME, NULL, 0, (LPVOID)szName, sizeof(szName), &dwAvail, NULL)) +#else + else +#endif + { + // Didn't get a volume name so use "Disk" by default. + wcscpy( szName, YFSD_DISK_NAME); + } + vol->mgrVolume = FSDMGR_RegisterVolume(hdsk,szName,vol); + //slf021104b end if(vol->mgrVolume) - { + { + //slf021104b Begin + // Get some space for the volume name. + vol->volName = malloc( MAX_PATH * sizeof(WCHAR)); + if (vol->volName) + { +#if WINCEOSVER >= 400 + // Get the name we were really mounted under. + FSDMGR_GetVolumeName(vol->mgrVolume, vol->volName, MAX_PATH); + + // If we got mounted as root then throw away the backslash + // so we won't get a double backslash when volName is + // prepended to the path in the full path name calculation + // that is used for shell callbacks. + if (0 == wcscmp(vol->volName,L"\\")) + vol->volName[0] = 0; +#else + // Use the name we asked to be mounted under for + // our root. + wcscpy(vol->volName,L"\\"); + wcscat(vol->volName, szName); +#endif + } + //slf021104b end return TRUE; } else @@ -629,6 +727,14 @@ BOOL YFSD_InitVolume(HDSK hdsk, yfsd_Volume *vol, int startBlock, int endBlock, BOOL YFSD_MountDisk(HDSK hdsk) { +//slf021105a begin +#ifdef DO_PARTITION_TABLE + ynandif_partition PartTable[MAXPARTITIONS]; + DWORD dwAvail; + int i; + BOOL rval = FALSE; +#endif +//slf021105a end int deadBlox=0,emptyBlox=0,fullBlox=0,allocatingBlox=0,dirtyBlox=0; //int i; // Called to mount a disk. @@ -646,29 +752,124 @@ BOOL YFSD_MountDisk(HDSK hdsk) yfsd_InitialiseWinFiles(); yaffsLockInited = 1; } - -#ifdef DISABLE_BOOT_PARTITION - // Only want disk volume - YFSD_InitVolume(hdsk, &disk_volume, 1, -1, YFSD_DISK_NAME); - - - if(disk_volume.isMounted) - { - return TRUE; - } + + //slf021105a begin + memset(disk_volumes,0,sizeof(disk_volumes)); +#ifdef DO_PARTITION_TABLE + memset(&PartTable,0,sizeof(PartTable)); + // Call the block driver to get the partition table from it. + if (FSDMGR_DiskIoControl(hdsk, YNANDIF_GETPARTITIONS, NULL, 0, (LPVOID)&PartTable, sizeof(PartTable), &dwAvail, NULL)) + { + // Scan throught the table it return. + for (i=0; i PartTable[i].startBlock)) + { + // Found a partion. Get a volume structure to hold it. + disk_volumes[i] = malloc(sizeof(yfsd_Volume)); + if (disk_volumes[i]) + { + memset(disk_volumes[i],0,sizeof(yfsd_Volume)); + // Go init the volume. Note that if the block driver wants the + // name to come from the registry it will have returned an + // empty name string. + YFSD_InitVolume(hdsk,disk_volumes[i],PartTable[i].startBlock,PartTable[i].endBlock,PartTable[i].volName); + if (disk_volumes[i]->isMounted) + rval = TRUE; //Hey, we found at least on partition. + } + } + } + } + + return rval; + #else - // Want both boot and disk - YFSD_InitVolume(hdsk, &disk_volume, PARTITION_START_NUMBER+1, -1, YFSD_DISK_NAME); - YFSD_InitVolume(hdsk, &boot_volume, 1, PARTITION_START_NUMBER, YFSD_BOOT_NAME); - - - if(disk_volume.isMounted && boot_volume.isMounted) - { - return TRUE; - } -#endif - - return FALSE; +#ifdef DISABLE_BOOT_PARTITION + // Only want disk volume + disk_volumes[0] = malloc(sizeof(yfsd_Volume)); + if (disk_volumes[0]) + { + memset(disk_volumes[0],0,sizeof(yfsd_Volume)); + YFSD_InitVolume(hdsk, disk_volumes[0], 1, -1, YFSD_DISK_NAME); + + if(disk_volumes[0].isMounted) + { + return TRUE; + } + } + if (disk_volumes[0]) + { + free(disk_volumes[0]; + disk_volumes[0] = NULL; + } +#else + // Want both boot and disk + disk_volumes[0] = malloc(sizeof(yfsd_Volume)); + disk_volumes[1] = malloc(sizeof(yfsd_Volume)); + if (disk_volumes[0] && disk_volumes[1]) + { + memset(disk_volumes[0],0,sizeof(yfsd_Volume)); + memset(disk_volumes[1],0,sizeof(yfsd_Volume)); + YFSD_InitVolume(hdsk, disk_volumes[0], PARTITION_START_NUMBER+1, -1, YFSD_DISK_NAME); + YFSD_InitVolume(hdsk, disk_volumes[1], 1, PARTITION_START_NUMBER, YFSD_BOOT_NAME); + + if(disk_volumes[0]->isMounted && disk_volumes[1]->isMounted) + { + return TRUE; + } + } + + // If we got this far something went wrong. Make sure to + // free any memory we allocated. + if (disk_volumes[0]) + { + if (disk_volumes[0]->volName) + { + free(disk_volumes[0]->volName); + } + free(disk_volumes[0]); + disk_volumes[0] = NULL; + } + if (disk_volumes[1]) + { + if (disk_volumes[1]->volName) + { + free(disk_volumes[1]->volName); + } + free(disk_volumes[1]); + disk_volumes[1] = NULL; + } +#endif + + return FALSE; + + // Only want disk volume +// YFSD_InitVolume(hdsk, &disk_volume, 1, -1, YFSD_DISK_NAME); +// +// +// if(disk_volume.isMounted) +// { +// return TRUE; +// } +//#else +// // Want both boot and disk +// YFSD_InitVolume(hdsk, &disk_volume, PARTITION_START_NUMBER+1, -1, YFSD_DISK_NAME); +// YFSD_InitVolume(hdsk, &boot_volume, 1, PARTITION_START_NUMBER, YFSD_BOOT_NAME); +// +// +// if(disk_volume.isMounted && boot_volume.isMounted) +// { +// return TRUE; +// } +//#endif +// +// return FALSE; +#endif +//slf021105a end // yfsd_SetGuards(); @@ -679,17 +880,47 @@ BOOL YFSD_MountDisk(HDSK hdsk) BOOL YFSD_UnmountDisk(HDSK hdsk) { +//slf021105a begin + int i; +//slf021105a end RETAILMSG (MSGSTATE, (L"YAFFS::UnmountDisk\r\n")); - yfsd_FlushAllFiles(); - - yfsd_LockYAFFS(); - yaffs_Deinitialise(&disk_volume.dev); - yaffs_Deinitialise(&boot_volume.dev); - yfsd_UnlockYAFFS(); - - FSDMGR_DeregisterVolume(disk_volume.mgrVolume); - FSDMGR_DeregisterVolume(boot_volume.mgrVolume); + //slf021104d begin + // If there are any files open don't let them dismount + // it or the system will get very confused. + if (yfsd_FilesOpen()) + return FALSE; + + //yfsd_FlushAllFiles(); + //slf021104d end + + yfsd_LockYAFFS(); +//slf021105a begin +// yaffs_Deinitialise(&disk_volume.dev); +// yaffs_Deinitialise(&boot_volume.dev); +// yfsd_UnlockYAFFS(); +// +// FSDMGR_DeregisterVolume(disk_volume.mgrVolume); +// FSDMGR_DeregisterVolume(boot_volume.mgrVolume); + + // Walk through the partions deinitializing, deregistering + // and freeing them. + for (i=0; idev)); + FSDMGR_DeregisterVolume(disk_volumes[i]->mgrVolume); + if (disk_volumes[i]->volName) + { + free(disk_volumes[i]->volName); + } + free(disk_volumes[i]); + disk_volumes[i] = NULL; + } + } + yfsd_UnlockYAFFS(); +//slf021105a end return TRUE; } @@ -711,22 +942,35 @@ BOOL YFSD_CreateDirectoryW(PVOLUME pVolume, PCWSTR pathName, PSECURITY_ATTRIBUTE parent = yfsd_FindDirectoryByWinPath(&pVolume->dev,pathName,name,YFSD_NAME_LENGTH); - if(parent && yfsd_NameIsValid(name)) - { - newDir = yaffs_MknodDirectory(parent,name,0,0,0); - } - - if(newDir) + //slf021101b begin + if (parent) { - objSize = yaffs_GetObjectFileLength(newDir); - attribs = yfsd_GetObjectWinAttributes(newDir); - modifiedTime[0] = newDir->win_mtime[0]; - modifiedTime[1] = newDir->win_mtime[1]; + if(yfsd_NameIsValid(name)) + { + newDir = yaffs_MknodDirectory(parent,name,0,0,0); + if(newDir) + { + objSize = yaffs_GetObjectFileLength(newDir); + attribs = yfsd_GetObjectWinAttributes(newDir); + modifiedTime[0] = newDir->win_mtime[0]; + modifiedTime[1] = newDir->win_mtime[1]; + } + else + { + if(yaffs_FindObjectByName(parent,name)) + SetLastError(ERROR_ALREADY_EXISTS); + else + SetLastError(ERROR_DISK_FULL); + } + } + else + SetLastError(ERROR_INVALID_NAME); } else { SetLastError(ERROR_PATH_NOT_FOUND); } + //slf021101b end yfsd_UnlockYAFFS(); @@ -752,10 +996,12 @@ BOOL YFSD_CreateDirectoryW(PVOLUME pVolume, PCWSTR pathName, PSECURITY_ATTRIBUTE } - if(parent && !newDir) - { - SetLastError(ERROR_DISK_FULL); - } +//slf021101b begin +// if(parent && !newDir) +// { +// SetLastError(ERROR_DISK_FULL); +// } +//slf021101b end return newDir ? TRUE : FALSE; } @@ -871,19 +1117,19 @@ DWORD YFSD_GetFileAttributesW(PVOLUME pVolume, PCWSTR pwsFileName ) BOOL YFSD_SetFileAttributesW( PVOLUME pVolume,PCWSTR pwsFileName, DWORD dwFileAttributes ) { - yaffs_Object *obj = NULL; - DWORD mtime[2]; - DWORD attribs; + yaffs_Object *obj = NULL; + DWORD mtime[2]; + DWORD attribs; DWORD objSize; int result = 0; - RETAILMSG (MSGSTATE, (L"YAFFS::SetFileAttributes %X\r\n",dwFileAttributes)); - - if(!yfsd_CheckValidAttributes(dwFileAttributes)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; + RETAILMSG (MSGSTATE, (L"YAFFS::SetFileAttributes %X\r\n",dwFileAttributes)); + + if(!yfsd_CheckValidAttributes(dwFileAttributes)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; } yfsd_LockYAFFS(); @@ -894,11 +1140,11 @@ BOOL YFSD_SetFileAttributesW( PVOLUME pVolume,PCWSTR pwsFileName, DWORD dwFileAt { obj->st_mode = dwFileAttributes; obj->dirty = 1; - result = yaffs_FlushFile(obj); - attribs = yfsd_GetObjectWinAttributes(obj); - objSize = yaffs_GetObjectFileLength(obj); - mtime[0] = obj->win_mtime[0]; - mtime[1] = obj->win_mtime[1]; + result = yaffs_FlushFile(obj,0); + attribs = yfsd_GetObjectWinAttributes(obj); + objSize = yaffs_GetObjectFileLength(obj); + mtime[0] = obj->win_mtime[0]; + mtime[1] = obj->win_mtime[1]; } else { @@ -971,7 +1217,7 @@ BOOL YFSD_MoveFileW(PVOLUME pVolume,PCWSTR pwsOldFileName, PCWSTR pwsNewFileName int result = 0; int objIsDir = 0; DWORD attribs; - DWORD objSize; + DWORD objSize; DWORD mtime[2]; RETAILMSG (MSGSTATE, (L"YAFFS::MoveFile\r\n")); @@ -994,9 +1240,9 @@ BOOL YFSD_MoveFileW(PVOLUME pVolume,PCWSTR pwsOldFileName, PCWSTR pwsNewFileName { objIsDir = (obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY); attribs = yfsd_GetObjectWinAttributes(obj); - objSize = yaffs_GetObjectFileLength(obj); - mtime[0] = obj->win_mtime[0]; - mtime[1] = obj->win_mtime[1]; + objSize = yaffs_GetObjectFileLength(obj); + mtime[0] = obj->win_mtime[0]; + mtime[1] = obj->win_mtime[1]; } } else @@ -1036,8 +1282,18 @@ BOOL YFSD_MoveFileW(PVOLUME pVolume,PCWSTR pwsOldFileName, PCWSTR pwsNewFileName BOOL YFSD_DeleteAndRenameFileW(PVOLUME pVolume, PCWSTR pwsOldFileName, PCWSTR pwsNewFileName ) { - RETAILMSG (MSGSTATE, (L"YAFFS::DeleteAndRename\r\n")); - return FALSE; + //slf021104c begin + BOOL fSuccess; + //slf021104c end + + RETAILMSG (MSGSTATE, (L"YAFFS::DeleteAndRename\r\n")); + + //slf021104c begin + if (fSuccess = YFSD_DeleteFileW(pVolume, pwsOldFileName)) + fSuccess = YFSD_MoveFileW(pVolume, pwsNewFileName, pwsOldFileName); + return fSuccess; + //return FALSE; + //slf021104c end } BOOL YFSD_GetDiskFreeSpaceW( PVOLUME pVolume, PCWSTR pwsPathName, PDWORD pSectorsPerCluster,PDWORD pBytesPerSector, PDWORD pFreeClusters, PDWORD pClusters ) @@ -1232,8 +1488,8 @@ BOOL yfsd_ObjectAlreadyFound(PSEARCH pSearch, yaffs_Object *l) return found; } - -#if 0 + +#if 0 // slower one BOOL yfsd_DoFindFile(PSEARCH pSearch, PWIN32_FIND_DATAW pfd) { @@ -1309,77 +1565,77 @@ out_of_here: return found; } - -#else -// faster one -BOOL yfsd_DoFindFile(PSEARCH pSearch, PWIN32_FIND_DATAW pfd) -{ - - struct list_head *i; - yaffs_Object *l; - BOOL found = 0; - - char name[YAFFS_MAX_NAME_LENGTH+1]; - - if(!pSearch->foundObjects) - { - pSearch->foundObjects = malloc(sizeof(yaffs_FoundObject)); - pSearch->foundObjects->next = NULL; - pSearch->foundObjects->obj = 0; - } - - - yfsd_LockYAFFS(); - - list_for_each(i,&pSearch->dir->variant.directoryVariant.children) - { - - l = list_entry(i, yaffs_Object,siblings); - if(!yfsd_ObjectAlreadyFound(pSearch,l)) - { - // Only look at things we have not looked at already - yaffs_GetObjectName(l,name,YAFFS_MAX_NAME_LENGTH+1); - - if(regularMatch(pSearch->pattern,name)) - { - found = 1; - // fill out find data - - pfd->dwFileAttributes = yfsd_GetObjectWinAttributes(l); - - yfsd_U32sToWinFileTime(l->win_ctime,&pfd->ftCreationTime); - yfsd_U32sToWinFileTime(l->win_atime,&pfd->ftLastAccessTime); - yfsd_U32sToWinFileTime(l->win_mtime,&pfd->ftLastWriteTime); - - pfd->nFileSizeHigh = 0; - pfd->nFileSizeLow = yaffs_GetObjectFileLength(l); - pfd->dwOID = 0; // wtf is this??? - - MultiByteToWideChar(CP_ACP,0,name,-1,pfd->cFileName,YFSD_NAME_LENGTH); - - RETAILMSG(MSGSTATE,(L"File %s id %d header %d nDataChunks %d scannedLength %d\r\n", - pfd->cFileName,l->objectId, l->chunkId, l->nDataChunks, - l->variant.fileVariant.scannedFileSize)); - goto out_of_here; - } - - } - - - } - -out_of_here: - yfsd_UnlockYAFFS(); - - - if(!found) - { - SetLastError(ERROR_NO_MORE_FILES); - } - return found; - -} -#endif + +#else +// faster one +BOOL yfsd_DoFindFile(PSEARCH pSearch, PWIN32_FIND_DATAW pfd) +{ + + struct list_head *i; + yaffs_Object *l; + BOOL found = 0; + + char name[YAFFS_MAX_NAME_LENGTH+1]; + + if(!pSearch->foundObjects) + { + pSearch->foundObjects = malloc(sizeof(yaffs_FoundObject)); + pSearch->foundObjects->next = NULL; + pSearch->foundObjects->obj = 0; + } + + + yfsd_LockYAFFS(); + + list_for_each(i,&pSearch->dir->variant.directoryVariant.children) + { + + l = list_entry(i, yaffs_Object,siblings); + if(!yfsd_ObjectAlreadyFound(pSearch,l)) + { + // Only look at things we have not looked at already + yaffs_GetObjectName(l,name,YAFFS_MAX_NAME_LENGTH+1); + + if(regularMatch(pSearch->pattern,name)) + { + found = 1; + // fill out find data + + pfd->dwFileAttributes = yfsd_GetObjectWinAttributes(l); + + yfsd_U32sToWinFileTime(l->win_ctime,&pfd->ftCreationTime); + yfsd_U32sToWinFileTime(l->win_atime,&pfd->ftLastAccessTime); + yfsd_U32sToWinFileTime(l->win_mtime,&pfd->ftLastWriteTime); + + pfd->nFileSizeHigh = 0; + pfd->nFileSizeLow = yaffs_GetObjectFileLength(l); + pfd->dwOID = 0; // wtf is this??? + + MultiByteToWideChar(CP_ACP,0,name,-1,pfd->cFileName,YFSD_NAME_LENGTH); + + RETAILMSG(MSGSTATE,(L"File %s id %d header %d nDataChunks %d scannedLength %d\r\n", + pfd->cFileName,l->objectId, l->chunkId, l->nDataChunks, + l->variant.fileVariant.scannedFileSize)); + goto out_of_here; + } + + } + + + } + +out_of_here: + yfsd_UnlockYAFFS(); + + + if(!found) + { + SetLastError(ERROR_NO_MORE_FILES); + } + return found; + +} +#endif HANDLE YFSD_FindFirstFileW(PVOLUME pVolume, HANDLE hProc,PCWSTR pwsFileSpec, PWIN32_FIND_DATAW pfd ) { @@ -1484,7 +1740,12 @@ HANDLE YFSD_CreateFileW( unsigned modifiedTime[2]; unsigned objSize; - BOOL writePermitted = (dwAccess & GENERIC_WRITE) ? TRUE : FALSE; + BOOL writePermitted = (dwAccess & GENERIC_WRITE) ? TRUE : FALSE; + BOOL readPermitted = (dwAccess & GENERIC_READ) ? TRUE : FALSE; + BOOL shareRead = (dwShareMode & FILE_SHARE_READ) ? TRUE : FALSE; + BOOL shareWrite = (dwShareMode & FILE_SHARE_WRITE) ? TRUE : FALSE; + + BOOL openRead, openWrite, openReadAllowed, openWriteAllowed; BOOL fileCreated = FALSE; @@ -1502,11 +1763,11 @@ HANDLE YFSD_CreateFileW( RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile write not permitted\r\n")); } - if(!yfsd_CheckValidAttributes(mode)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + if(!yfsd_CheckValidAttributes(mode)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } yfsd_LockYAFFS(); @@ -1516,24 +1777,26 @@ HANDLE YFSD_CreateFileW( if(parent && yfsd_NameIsValid(name)) { - - obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName); - if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) - { - // Naughty, naughty. Don't do file ops on directories - SetLastError(ERROR_ACCESS_DENIED); - fileCreated = FALSE; - obj = NULL; - } - else if(dwCreate == CREATE_NEW) + if(dwCreate == CREATE_NEW) { RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile creating file in CREATE_NEW\r\n")); - obj = yaffs_MknodFile(parent,name,mode,0,0); + //slf021101c begin + obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName); if(!obj) - SetLastError(ERROR_DISK_FULL); - fileCreated = TRUE; + { + obj = yaffs_MknodFile(parent,name,mode,0,0); + if(!obj) + SetLastError(ERROR_DISK_FULL); + fileCreated = TRUE; + } + else + { + obj = NULL; + SetLastError(ERROR_ALREADY_EXISTS); + } + //slf021101c end } else if( dwCreate == OPEN_ALWAYS) { @@ -1558,6 +1821,14 @@ HANDLE YFSD_CreateFileW( obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName); if(!obj) SetLastError(ERROR_FILE_NOT_FOUND); + //slf021101c begin + else + if (yfsd_GetObjectWinAttributes(obj) & FILE_ATTRIBUTE_DIRECTORY) + { + SetLastError(ERROR_ACCESS_DENIED); + obj = NULL; + } + //slf021101c end } else if(dwCreate == TRUNCATE_EXISTING) { @@ -1590,7 +1861,7 @@ HANDLE YFSD_CreateFileW( obj->st_mode = mode; obj->dirty = 1; yaffs_ResizeFile(obj,0); - yaffs_FlushFile(obj); + yaffs_FlushFile(obj,1); } } else @@ -1604,7 +1875,41 @@ HANDLE YFSD_CreateFileW( RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile unable to get parent node\r\n")); SetLastError(ERROR_PATH_NOT_FOUND); } - + + if(obj) + { + int i; + yfsd_WinFile *p; + openRead = openWrite =0; + openReadAllowed = openWriteAllowed = 1; + + for(i = 0; i < MAX_WIN_FILE; i++) + { + p = &yfsd_winFile[i]; + + if(p->obj == obj) + { + if (p->readPermitted) openRead = 1; + if (p->writePermitted) openWrite = 1; + if (!p->shareRead) openReadAllowed = 0; + if (!p->shareWrite) openWriteAllowed = 0; + } + + } + + // Now we test if the share works out. + + if((openRead && !shareRead) || // already open for read, but we are not prepared to share it for read + (openWrite && !shareWrite) || // already open for write, but we are not prepared to share it for write + (!openReadAllowed && readPermitted) || // already open with read sharing not permitted + (!openWriteAllowed && writePermitted)) // same... write + { + SetLastError(ERROR_ACCESS_DENIED); + obj = NULL; + } + + + } if(obj) { RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - we have an object\r\n")); @@ -1625,12 +1930,15 @@ HANDLE YFSD_CreateFileW( RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - we have an fsdmgr handle\r\n")); f->obj = obj; f->offset = 0; - f->writePermitted = writePermitted; + f->writePermitted = writePermitted; + f->readPermitted = writePermitted; + f->shareRead= shareRead; + f->shareWrite = shareWrite; f->myVolume = pVolume; obj->inUse++; - modifiedTime[0] = obj->win_mtime[0]; - modifiedTime[1] = obj->win_mtime[1]; + modifiedTime[0] = obj->win_mtime[0]; + modifiedTime[1] = obj->win_mtime[1]; objSize = yaffs_GetObjectFileLength(obj); RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - file size %d\r\n",objSize)); } @@ -1737,8 +2045,8 @@ BOOL yfsd_DoReadFile( { nread = yaffs_ReadDataFromFile(obj,pBuffer,pFile->offset,cbRead); if(nread > 0) - { - pFile->offset += nread; + { + pFile->offset += nread; if(pcbRead) { @@ -1748,9 +2056,9 @@ BOOL yfsd_DoReadFile( } else { - if(pcbRead) - { - *pcbRead = maxRead; + if(pcbRead) + { + *pcbRead = maxRead; } } @@ -1794,7 +2102,7 @@ BOOL YFSD_ReadFileWithSeek( DWORD dwLowOffset, DWORD dwHighOffset ) { - BOOL result; + BOOL result; DWORD rememberedOffset; RETAILMSG (MSGSTATE, (L"YAFFS::ReadFileWithSeek %d bytes at %d high %d pcbRead %X\r\n",cbRead,dwLowOffset,dwHighOffset,pcbRead)); @@ -1813,16 +2121,16 @@ BOOL YFSD_ReadFileWithSeek( return FALSE; } - yfsd_LockYAFFS(); - + yfsd_LockYAFFS(); + rememberedOffset = pFile->offset; pFile->offset = dwLowOffset; // ignore high offset for now result = yfsd_DoReadFile(pFile,pBuffer,cbRead,pcbRead); - - //pFile->offset = rememberedOffset; + + //pFile->offset = rememberedOffset; yfsd_UnlockYAFFS(); @@ -1909,7 +2217,7 @@ BOOL YFSD_WriteFileWithSeek( DWORD rememberedOffset; RETAILMSG (MSGSTATE, (L"YAFFS::WriteFileWithSeek %d bytes at %d,%d pcbWritten %X\r\n",cbWrite,dwHighOffset,dwLowOffset,pcbWritten)); - + if(!pFile || !pFile->obj) { @@ -1918,15 +2226,15 @@ BOOL YFSD_WriteFileWithSeek( } yfsd_LockYAFFS(); - - rememberedOffset = pFile->offset; + + rememberedOffset = pFile->offset; pFile->offset = dwLowOffset; // ignore high offset for now result = yfsd_DoWriteFile(pFile,pBuffer,cbWrite,pcbWritten); - - //pFile->offset = rememberedOffset; + + //pFile->offset = rememberedOffset; yfsd_UnlockYAFFS(); @@ -1953,8 +2261,8 @@ DWORD YFSD_SetFilePointer( return offset; } - yfsd_LockYAFFS(); - + yfsd_LockYAFFS(); + oldPos = pFile->offset; @@ -2028,8 +2336,8 @@ DWORD YFSD_GetFileSize( fileSize = yaffs_GetObjectFileLength(pFile->obj); - yfsd_UnlockYAFFS(); - if(pFileSizeHigh) + yfsd_UnlockYAFFS(); + if(pFileSizeHigh) *pFileSizeHigh = 0; return fileSize; @@ -2047,35 +2355,40 @@ BOOL YFSD_GetFileInformationByHandle( { SetLastError(ERROR_INVALID_HANDLE); return FALSE; - } - - yfsd_LockYAFFS(); - - pFileInfo->dwFileAttributes = yfsd_GetObjectWinAttributes(pFile->obj); - yfsd_U32sToWinFileTime(pFile->obj->win_ctime,&pFileInfo->ftCreationTime); - yfsd_U32sToWinFileTime(pFile->obj->win_atime,&pFileInfo->ftLastAccessTime); - yfsd_U32sToWinFileTime(pFile->obj->win_mtime,&pFileInfo->ftLastWriteTime); - pFileInfo->dwVolumeSerialNumber = 0; //todo is this OK? - pFileInfo->nFileSizeHigh = 0; - pFileInfo->nFileSizeLow = yaffs_GetObjectFileLength(pFile->obj); - pFileInfo->nNumberOfLinks = 1; // only primary link supported like FAT - pFileInfo->nFileIndexHigh = 0; - pFileInfo->nFileIndexLow = pFile->obj->objectId; - + } + + yfsd_LockYAFFS(); + + pFileInfo->dwFileAttributes = yfsd_GetObjectWinAttributes(pFile->obj); + yfsd_U32sToWinFileTime(pFile->obj->win_ctime,&pFileInfo->ftCreationTime); + yfsd_U32sToWinFileTime(pFile->obj->win_atime,&pFileInfo->ftLastAccessTime); + yfsd_U32sToWinFileTime(pFile->obj->win_mtime,&pFileInfo->ftLastWriteTime); + pFileInfo->dwVolumeSerialNumber = 0; //todo is this OK? + pFileInfo->nFileSizeHigh = 0; + pFileInfo->nFileSizeLow = yaffs_GetObjectFileLength(pFile->obj); + pFileInfo->nNumberOfLinks = 1; // only primary link supported like FAT + pFileInfo->nFileIndexHigh = 0; + pFileInfo->nFileIndexLow = pFile->obj->objectId; +//slf021104a Begin Window CE 4.0 added an additional field. +#if _WINCEOSVER >= 400 + pFileInfo->dwOID = (CEOID)(INVALID_HANDLE_VALUE); +#endif +//slf021104a end + yfsd_UnlockYAFFS(); return TRUE; } BOOL YFSD_FlushFileBuffers(PFILE pFile ) -{ - WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE]; - int nameExists = 0; - yfsd_Volume *vol = NULL; - DWORD attribs = 0; - DWORD objSize = 0; - DWORD mtime[2]; - +{ + WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE]; + int nameExists = 0; + yfsd_Volume *vol = NULL; + DWORD attribs = 0; + DWORD objSize = 0; + DWORD mtime[2]; + RETAILMSG (MSGSTATE, (L"YAFFS::FlushFileBuffers\r\n")); @@ -2085,40 +2398,40 @@ BOOL YFSD_FlushFileBuffers(PFILE pFile ) return FALSE; } - yfsd_LockYAFFS(); + yfsd_LockYAFFS(); + + yaffs_FlushFile(pFile->obj,1); + attribs = yfsd_GetObjectWinAttributes(pFile->obj); + objSize = yaffs_GetObjectFileLength(pFile->obj); + mtime[0] = pFile->obj->win_mtime[0]; + mtime[1] = pFile->obj->win_mtime[1]; + if(pFile->fullName) + { + wcscpy(fpn,pFile->fullName); + nameExists = 1; + } + vol = pFile->myVolume; - yaffs_FlushFile(pFile->obj); - attribs = yfsd_GetObjectWinAttributes(pFile->obj); - objSize = yaffs_GetObjectFileLength(pFile->obj); - mtime[0] = pFile->obj->win_mtime[0]; - mtime[1] = pFile->obj->win_mtime[1]; - if(pFile->fullName) - { - wcscpy(fpn,pFile->fullName); - nameExists = 1; - } - vol = pFile->myVolume; - yfsd_UnlockYAFFS(); - - if(vol && vol->shellFunction && nameExists) - { - FILECHANGEINFO fc; - - fc.cbSize = sizeof(FILECHANGEINFO); - fc.wEventId = SHCNE_UPDATEITEM; - fc.uFlags = SHCNF_PATH; - fc.dwItem1 = (DWORD)fpn; - fc.dwItem2 = 0; - fc.dwAttributes = attribs; - yfsd_U32sToWinFileTime(mtime,&fc.ftModified); - fc.nFileSize = objSize; - - vol->shellFunction(&fc); - RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n")); - //yfsd_ShellDirectoryChanged(vol,fpn); - } - + + if(vol && vol->shellFunction && nameExists) + { + FILECHANGEINFO fc; + + fc.cbSize = sizeof(FILECHANGEINFO); + fc.wEventId = SHCNE_UPDATEITEM; + fc.uFlags = SHCNF_PATH; + fc.dwItem1 = (DWORD)fpn; + fc.dwItem2 = 0; + fc.dwAttributes = attribs; + yfsd_U32sToWinFileTime(mtime,&fc.ftModified); + fc.nFileSize = objSize; + + vol->shellFunction(&fc); + RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n")); + //yfsd_ShellDirectoryChanged(vol,fpn); + } + return TRUE; } @@ -2154,15 +2467,15 @@ BOOL YFSD_SetFileTime( CONST FILETIME *pLastAccess, CONST FILETIME *pLastWrite ) { - WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE]; - int nameExists = 0; + WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE]; + int nameExists = 0; int result = FALSE; - yfsd_Volume *vol = NULL; - DWORD attribs = 0; - DWORD objSize = 0; - DWORD mtime[2]; - - + yfsd_Volume *vol = NULL; + DWORD attribs = 0; + DWORD objSize = 0; + DWORD mtime[2]; + + RETAILMSG (MSGSTATE, (L"YAFFS::SetFileTime\r\n")); if(!pFile || !pFile->obj) @@ -2174,60 +2487,60 @@ BOOL YFSD_SetFileTime( yfsd_LockYAFFS(); - if(pCreation) - { - yfsd_WinFileTimeToU32s(pCreation,pFile->obj->win_ctime); - pFile->obj->dirty = 1; + if(pCreation) + { + yfsd_WinFileTimeToU32s(pCreation,pFile->obj->win_ctime); + pFile->obj->dirty = 1; } - if(pLastAccess) - { - yfsd_WinFileTimeToU32s(pLastAccess,pFile->obj->win_atime); - pFile->obj->dirty = 1; + if(pLastAccess) + { + yfsd_WinFileTimeToU32s(pLastAccess,pFile->obj->win_atime); + pFile->obj->dirty = 1; } - if(pLastWrite) - { - yfsd_WinFileTimeToU32s(pLastWrite,pFile->obj->win_mtime); + if(pLastWrite) + { + yfsd_WinFileTimeToU32s(pLastWrite,pFile->obj->win_mtime); pFile->obj->dirty = 1; } if(pCreation || pLastAccess || pLastWrite) { - result = yaffs_FlushFile(pFile->obj); + result = yaffs_FlushFile(pFile->obj,0); } - - if(result) + + if(result) { - attribs = yfsd_GetObjectWinAttributes(pFile->obj); - objSize = yaffs_GetObjectFileLength(pFile->obj); - mtime[0] = pFile->obj->win_mtime[0]; - mtime[1] = pFile->obj->win_mtime[1]; - if(pFile->fullName) - { - wcscpy(fpn,pFile->fullName); - nameExists = 1; - } - vol = pFile->myVolume; - } - + attribs = yfsd_GetObjectWinAttributes(pFile->obj); + objSize = yaffs_GetObjectFileLength(pFile->obj); + mtime[0] = pFile->obj->win_mtime[0]; + mtime[1] = pFile->obj->win_mtime[1]; + if(pFile->fullName) + { + wcscpy(fpn,pFile->fullName); + nameExists = 1; + } + vol = pFile->myVolume; + } + yfsd_UnlockYAFFS(); // Call shell function - if(nameExists && result && vol && vol->shellFunction) - { - FILECHANGEINFO fc; - - fc.cbSize = sizeof(FILECHANGEINFO); - fc.wEventId = SHCNE_UPDATEITEM; - fc.uFlags = SHCNF_PATH; - fc.dwItem1 = (DWORD)fpn; - fc.dwItem2 = 0; - fc.dwAttributes = attribs; - yfsd_U32sToWinFileTime(mtime,&fc.ftModified); - fc.nFileSize = objSize; - - vol->shellFunction(&fc); - RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n")); - //yfsd_ShellDirectoryChanged(vol,fpn); - } + if(nameExists && result && vol && vol->shellFunction) + { + FILECHANGEINFO fc; + + fc.cbSize = sizeof(FILECHANGEINFO); + fc.wEventId = SHCNE_UPDATEITEM; + fc.uFlags = SHCNF_PATH; + fc.dwItem1 = (DWORD)fpn; + fc.dwItem2 = 0; + fc.dwAttributes = attribs; + yfsd_U32sToWinFileTime(mtime,&fc.ftModified); + fc.nFileSize = objSize; + + vol->shellFunction(&fc); + RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n")); + //yfsd_ShellDirectoryChanged(vol,fpn); + } return TRUE; } @@ -2236,12 +2549,12 @@ BOOL YFSD_SetEndOfFile( PFILE pFile ) { - WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE]; - int nameExists = 0; - yfsd_Volume *vol = NULL; - DWORD attribs = 0; - DWORD objSize = 0; - DWORD mtime[2]; + WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE]; + int nameExists = 0; + yfsd_Volume *vol = NULL; + DWORD attribs = 0; + DWORD objSize = 0; + DWORD mtime[2]; static unsigned char zeros[512]; int result; @@ -2303,40 +2616,40 @@ PFILE pFile ) { retVal = TRUE; } - if(retVal) - { - attribs = yfsd_GetObjectWinAttributes(pFile->obj); - objSize = yaffs_GetObjectFileLength(pFile->obj); - mtime[0] = pFile->obj->win_mtime[0]; - mtime[1] = pFile->obj->win_mtime[1]; - if(pFile->fullName) - { - wcscpy(fpn,pFile->fullName); - nameExists = 1; - } - vol = pFile->myVolume; - } - - - yfsd_UnlockYAFFS(); - - if(nameExists && retVal && vol && vol->shellFunction) - { - FILECHANGEINFO fc; - - fc.cbSize = sizeof(FILECHANGEINFO); - fc.wEventId = SHCNE_UPDATEITEM; - fc.uFlags = SHCNF_PATH; - fc.dwItem1 = (DWORD)fpn; - fc.dwItem2 = 0; - fc.dwAttributes = attribs; - yfsd_U32sToWinFileTime(mtime,&fc.ftModified); - fc.nFileSize = objSize; - - vol->shellFunction(&fc); - RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n")); - //yfsd_ShellDirectoryChanged(vol,fpn); - } + if(retVal) + { + attribs = yfsd_GetObjectWinAttributes(pFile->obj); + objSize = yaffs_GetObjectFileLength(pFile->obj); + mtime[0] = pFile->obj->win_mtime[0]; + mtime[1] = pFile->obj->win_mtime[1]; + if(pFile->fullName) + { + wcscpy(fpn,pFile->fullName); + nameExists = 1; + } + vol = pFile->myVolume; + } + + + yfsd_UnlockYAFFS(); + + if(nameExists && retVal && vol && vol->shellFunction) + { + FILECHANGEINFO fc; + + fc.cbSize = sizeof(FILECHANGEINFO); + fc.wEventId = SHCNE_UPDATEITEM; + fc.uFlags = SHCNF_PATH; + fc.dwItem1 = (DWORD)fpn; + fc.dwItem2 = 0; + fc.dwAttributes = attribs; + yfsd_U32sToWinFileTime(mtime,&fc.ftModified); + fc.nFileSize = objSize; + + vol->shellFunction(&fc); + RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n")); + //yfsd_ShellDirectoryChanged(vol,fpn); + } RETAILMSG (MSGSTATE, (L"YAFFS::SetEOF file size %d\r\n",yaffs_GetObjectFileLength(pFile->obj))); @@ -2367,7 +2680,7 @@ BOOL YFSD_CloseFile( PFILE pFile ) yfsd_Volume *vol = NULL; DWORD attribs = 0; DWORD objSize = 0; - DWORD mtime[2]; + DWORD mtime[2]; RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile %X\r\n",pFile)); @@ -2383,11 +2696,11 @@ BOOL YFSD_CloseFile( PFILE pFile ) { pFile->obj->inUse--; RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile on obj\r\n")); - yaffs_FlushFile(pFile->obj); + yaffs_FlushFile(pFile->obj,1); attribs = yfsd_GetObjectWinAttributes(pFile->obj); objSize = yaffs_GetObjectFileLength(pFile->obj); - mtime[0] = pFile->obj->win_mtime[0]; - mtime[1] = pFile->obj->win_mtime[1]; + mtime[0] = pFile->obj->win_mtime[0]; + mtime[1] = pFile->obj->win_mtime[1]; RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile on obj done, size is %d\r\n",objSize)); if(pFile->fullName) { diff --git a/yaffs_fileem.c b/yaffs_fileem.c index f4a324e..3ee50eb 100644 --- a/yaffs_fileem.c +++ b/yaffs_fileem.c @@ -26,7 +26,7 @@ #include #include -#define FILE_SIZE_IN_MEG 4 +#define FILE_SIZE_IN_MEG 2 // #define YAFFS_ERROR_TESTING diff --git a/yaffs_fs.c b/yaffs_fs.c index 81b8ccf..1f4f5b8 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -27,7 +27,7 @@ */ -const char *yaffs_fs_c_version = "$Id: yaffs_fs.c,v 1.21 2002-11-26 01:39:53 charles Exp $"; +const char *yaffs_fs_c_version = "$Id: yaffs_fs.c,v 1.22 2003-01-14 23:15:29 charles Exp $"; extern const char *yaffs_guts_c_version; @@ -352,7 +352,7 @@ static int yaffs_file_flush(struct file* file) yaffs_GrossLock(dev); - yaffs_FlushFile(obj); + yaffs_FlushFile(obj,1); yaffs_GrossUnlock(dev); @@ -853,8 +853,11 @@ static int yaffs_link(struct dentry *old_dentry, struct inode * dir, struct dent dev = obj->myDev; yaffs_GrossLock(dev); - - link = yaffs_Link(yaffs_InodeToObject(dir),dentry->d_name.name,obj); + + if (!S_ISDIR(inode->i_mode)) // Don't link directories + { + link = yaffs_Link(yaffs_InodeToObject(dir),dentry->d_name.name,obj); + } if(link) @@ -926,7 +929,7 @@ static int yaffs_sync_object(struct file * file, struct dentry *dentry, int data T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_sync_object\n")); yaffs_GrossLock(dev); - yaffs_FlushFile(obj); + yaffs_FlushFile(obj,1); yaffs_GrossUnlock(dev); return 0; } @@ -939,22 +942,44 @@ static int yaffs_sync_object(struct file * file, struct dentry *dentry, int data static int yaffs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry) { yaffs_Device *dev; - int retVal; + int retVal = YAFFS_FAIL; + int removed = 0; + yaffs_Object *target; dev = yaffs_InodeToObject(old_dir)->myDev; yaffs_GrossLock(dev); - // Unlink the target if it exists - yaffs_Unlink(yaffs_InodeToObject(new_dir),new_dentry->d_name.name); + // Check if the target is an existing directory that is not empty. + target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),new_dentry->d_name.name); + + if(target && + target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && + !list_empty(&target->variant.directoryVariant.children)) + { + retVal = YAFFS_FAIL; + } + else + { + + // Unlink the target if it exists + removed = yaffs_Unlink(yaffs_InodeToObject(new_dir),new_dentry->d_name.name); - retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),old_dentry->d_name.name, - yaffs_InodeToObject(new_dir),new_dentry->d_name.name); + retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),old_dentry->d_name.name, + yaffs_InodeToObject(new_dir),new_dentry->d_name.name); + + } yaffs_GrossUnlock(dev); if(retVal == YAFFS_OK) { + if(removed == YAFFS_OK) + { + new_dentry->d_inode->i_nlink--; + mark_inode_dirty(new_dentry->d_inode); + } + return 0; } else @@ -1222,6 +1247,10 @@ static struct super_block *yaffs_internal_read_super(int useRam, struct super_bl dev->initialiseNAND = nandmtd_InitialiseNAND; dev->putSuperFunc = yaffs_MTDPutSuper; + +#ifdef CONFIG_YAFFS_USE_NANDECC + dev->useNANDECC = 1; +#endif yaffs_dev = dev; @@ -1312,6 +1341,8 @@ static char * yaffs_dump_dev(char *buf,yaffs_Device *dev,char *name) buf +=sprintf(buf,"nDeletedFiles...... %d\n",dev->nDeletedFiles); buf +=sprintf(buf,"nUnlinkedFiles..... %d\n",dev->nUnlinkedFiles); buf +=sprintf(buf,"nBackgroudDeletions %d\n",dev->nBackgroundDeletions); + buf +=sprintf(buf,"useNANDECC......... %d\n",dev->useNANDECC); + return buf; } diff --git a/yaffs_guts.c b/yaffs_guts.c index 9ddabf6..bb714e0 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -14,7 +14,7 @@ */ //yaffs_guts.c -const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.15 2002-12-13 00:13:06 charles Exp $"; +const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.16 2003-01-14 23:15:29 charles Exp $"; #include "yportenv.h" @@ -72,7 +72,7 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type); static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj); static int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force); -static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId); +static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND); static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj); static int yaffs_CheckStructures(void); static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit); @@ -90,7 +90,7 @@ static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaf static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND); static int yaffs_UnlinkWorker(yaffs_Object *obj); - +static void yaffs_AbortHalfCreatedObject(yaffs_Object *obj); static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1); @@ -113,12 +113,63 @@ static int yaffs_CheckFileSanity(yaffs_Object *in); static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in); static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId); +// Chunk bitmap manipulations +static __inline __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk) +{ + if(blk < dev->startBlock || blk > dev->endBlock) + { + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),blk)); + YBUG(); + } + return dev->chunkBits + (dev->chunkBitmapStride * (blk - dev->startBlock)); +} + +static __inline__ void yaffs_ClearChunkBits(yaffs_Device *dev,int blk) +{ + __u8 *blkBits = yaffs_BlockBits(dev,blk); + + memset(blkBits,0,dev->chunkBitmapStride); +} + +static __inline__ void yaffs_ClearChunkBit(yaffs_Device *dev,int blk,int chunk) +{ + __u8 *blkBits = yaffs_BlockBits(dev,blk); + + blkBits[chunk/8] &= ~ (1<<(chunk & 7)); +} + +static __inline__ void yaffs_SetChunkBit(yaffs_Device *dev,int blk,int chunk) +{ + __u8 *blkBits = yaffs_BlockBits(dev,blk); + + blkBits[chunk/8] |= (1<<(chunk & 7)); +} + +static __inline__ int yaffs_CheckChunkBit(yaffs_Device *dev,int blk,int chunk) +{ + __u8 *blkBits = yaffs_BlockBits(dev,blk); + return (blkBits[chunk/8] & (1<<(chunk & 7))) ? 1 :0; +} + +static __inline__ int yaffs_StillSomeChunkBits(yaffs_Device *dev,int blk) +{ + __u8 *blkBits = yaffs_BlockBits(dev,blk); + int i; + for(i = 0; i < dev->chunkBitmapStride; i++) + { + if(*blkBits) return 1; + blkBits++; + } + return 0; +} + +// Function to manipulate block info static __inline__ yaffs_BlockInfo* yaffs_GetBlockInfo(yaffs_Device *dev, int blk) { if(blk < dev->startBlock || blk > dev->endBlock) { - T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: block %d is not valid" TENDSTR),blk)); + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),blk)); YBUG(); } return &dev->blockInfo[blk - dev->startBlock]; @@ -154,11 +205,7 @@ static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND return dev->writeChunkToNAND(dev,chunkInNAND,data,spare); } -struct nandspare { - yaffs_Spare spare; - int eccres1; - int eccres2; -}; + int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, int chunkInNAND, @@ -169,12 +216,9 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, int retVal; yaffs_Spare localSpare; -#ifndef CONFIG_YAFFS_USE_NANDECC __u8 calcEcc[3]; int eccResult1,eccResult2; -#else - struct nandspare nspare; -#endif + struct yaffs_NANDSpare nspare; dev->nPageReads++; @@ -189,7 +233,8 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, } -#ifndef CONFIG_YAFFS_USE_NANDECC + if(!dev->useNANDECC) + { retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,spare); if(data && doErrorCorrection) { @@ -228,37 +273,39 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, yaffs_HandleReadDataError(dev,chunkInNAND); } } -#else - retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare); - memcpy (spare, &nspare, sizeof(yaffs_Spare)); - if(data && doErrorCorrection) - { - if(nspare.eccres1>0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND)); - } - else if(nspare.eccres1<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND)); - } - - if(nspare.eccres2>0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND)); - } - else if(nspare.eccres2<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND)); - } - - if(nspare.eccres2 || nspare.eccres2) - { - // Hoosterman, we had a data problem on this page - yaffs_HandleReadDataError(dev,chunkInNAND); - } + } + else + { + retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare); + memcpy (spare, &nspare, sizeof(yaffs_Spare)); + if(data && doErrorCorrection) + { + if(nspare.eccres1>0) + { + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND)); + } + else if(nspare.eccres1<0) + { + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND)); + } + if(nspare.eccres2>0) + { + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND)); + } + else if(nspare.eccres2<0) + { + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND)); + } + + if(nspare.eccres2 || nspare.eccres2) + { + // Hoosterman, we had a data problem on this page + yaffs_HandleReadDataError(dev,chunkInNAND); + } + + } } -#endif return retVal; } @@ -448,7 +495,7 @@ static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND) // Mark the block for retirement yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1; // Delete the chunk - yaffs_DeleteChunk(dev,chunkInNAND); + yaffs_DeleteChunk(dev,chunkInNAND,1); } @@ -505,7 +552,8 @@ static __u16 yaffs_CalcNameSum(const char *name) { while ((*bname) && (i <=YAFFS_MAX_NAME_LENGTH)) { -#ifdef CONFIG_YAFFS_WINCE + +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE sum += toupper(*bname) * i; #else sum += (*bname) * i; @@ -639,9 +687,15 @@ static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes) for(i = 0; i < nTnodes - 1; i++) { newTnodes[i].internal[0] = &newTnodes[i+1]; +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG + newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = 1; +#endif } newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes; +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG + newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = 1; +#endif dev->freeTnodes = newTnodes; dev->nFreeTnodes+= nTnodes; dev->nTnodesCreated += nTnodes; @@ -684,6 +738,13 @@ static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev) if(dev->freeTnodes) { tn = dev->freeTnodes; +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG + if(tn->internal[YAFFS_NTNODES_INTERNAL] != 1) + { + // Hoosterman, this thing looks like it isn't in the list + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 1" TENDSTR))); + } +#endif dev->freeTnodes = dev->freeTnodes->internal[0]; dev->nFreeTnodes--; // zero out @@ -698,9 +759,20 @@ static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev) // FreeTnode frees up a tnode and puts it back on the free list static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn) { - tn->internal[0] = dev->freeTnodes; - dev->freeTnodes = tn; - dev->nFreeTnodes++; + if(tn) + { +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG + if(tn->internal[YAFFS_NTNODES_INTERNAL] != 0) + { + // Hoosterman, this thing looks like it is already in the list + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 2" TENDSTR))); + } + tn->internal[YAFFS_NTNODES_INTERNAL] = 1; +#endif + tn->internal[0] = dev->freeTnodes; + dev->freeTnodes = tn; + dev->nFreeTnodes++; + } } @@ -970,7 +1042,9 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, in } else if(level == 0) { - for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0; i--) //NB Don't apply the limit here, always delete a whole level0 + int hitLimit = 0; + + for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0 && !hitLimit; i--) { if(tn->level0[i]) { @@ -998,11 +1072,15 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, in if(found) { - yaffs_DeleteChunk(in->myDev,theChunk); + yaffs_DeleteChunk(in->myDev,theChunk,1); in->nDataChunks--; if(limit) { *limit = *limit-1; + if(limit <= 0) + { + hitLimit = 1; + } } } @@ -1011,7 +1089,7 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, in } } - return 1; + return (i < 0) ? 1 : 0; } @@ -1022,6 +1100,100 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, in } +// SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file. +// All soft deleting does is increment the block's softdelete count and pulls the chunk out +// of the tnode. +// THus, essentially this is the same as DeleteWorker except that the chunks are soft deleted. +// +static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset) +{ + int i; + int chunkInInode; + int theChunk; + yaffs_BlockInfo *theBlock; + yaffs_Tags tags; + int found; + int chunkDeleted; + int allDone = 1; + + + if(tn) + { + if(level > 0) + { + + for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--) + { + if(tn->internal[i]) + { + allDone = yaffs_SoftDeleteWorker(in,tn->internal[i],level - 1, + (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i); + if(allDone) + { + yaffs_FreeTnode(in->myDev,tn->internal[i]); + tn->internal[i] = NULL; + } + else + { + //Hoosterman... how could this happen. + } + } + } + return (allDone) ? 1 : 0; + } + else if(level == 0) + { + + for(i = YAFFS_NTNODES_LEVEL0 -1; i >=0; i--) + { + if(tn->level0[i]) + { + + theChunk = (tn->level0[i] << in->myDev->chunkGroupBits); + theBlock = yaffs_GetBlockInfo(in->myDev, theChunk/ YAFFS_CHUNKS_PER_BLOCK); + if(theBlock) + { + theBlock->softDeletions++; + } + tn->level0[i] = 0; + } + + } + return 1; + + } + + } + + return 1; + +} + + + +static void yaffs_SoftDeleteFile(yaffs_Object *obj) +{ + if(obj->deleted && + obj->variantType == YAFFS_OBJECT_TYPE_FILE && + !obj->softDeleted) + { + if(obj->nDataChunks <= 0) + { + // Empty file, just delete it immediately + yaffs_FreeTnode(obj->myDev,obj->variant.fileVariant.top); + obj->variant.fileVariant.top = NULL; + T(YAFFS_TRACE_TRACING,(TSTR("yaffs: Deleting empty file %d" TENDSTR),obj->objectId)); + yaffs_DoGenericObjectDeletion(obj); + } + else + { + yaffs_SoftDeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0); + obj->softDeleted = 1; + } + } +} + + @@ -1148,7 +1320,7 @@ static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects) // Hook them into the free list for(i = 0; i < nObjects - 1; i++) { - (yaffs_Object *)newObjects[i].siblings.next = &newObjects[i+1]; + newObjects[i].siblings.next = (struct list_head *)(&newObjects[i+1]); } newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects; @@ -1263,7 +1435,7 @@ static void yaffs_FreeObject(yaffs_Object *tn) yaffs_UnhashObject(tn); // Link into the free list. - (yaffs_Object *)(tn->siblings.next) = dev->freeObjects; + tn->siblings.next = (struct list_head *)(dev->freeObjects); dev->freeObjects = tn; dev->nFreeObjects++; } @@ -1581,11 +1753,11 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type, break; } - if(yaffs_GetNumberOfFreeChunks(dev) <= 0 || + if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */ yaffs_UpdateObjectHeader(in,name,0) < 0) { // Could not create the object header, fail the creation - yaffs_UnlinkWorker(in); + yaffs_AbortHalfCreatedObject(in); in = NULL; } @@ -1675,7 +1847,7 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const char *oldName, yaffs_Object * yaffs_Object *obj; int force = 0; -#ifdef CONFIG_YAFFS_WINCE +#ifdef YAFFS_CASE_INSENSITIVE // Special case for WinCE. // While look-up is case insensitive, the name isn't. // THerefore we might want to change x.txt to X.txt @@ -1790,11 +1962,16 @@ static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks) dev->allocationBlock = -1; // force it to get a new one //Todo we're assuming the malloc will pass. dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo)); - if(dev->blockInfo) + // Set up dynamic blockinfo stuff. + dev->chunkBitmapStride = (dev->nChunksPerBlock+7)/8; + dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); + if(dev->blockInfo && dev->chunkBits) { memset(dev->blockInfo,0,nBlocks * sizeof(yaffs_BlockInfo)); + memset(dev->chunkBits,0,dev->chunkBitmapStride * nBlocks); return YAFFS_OK; } + return YAFFS_FAIL; } @@ -1802,6 +1979,9 @@ static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks) static void yaffs_DeinitialiseBlocks(yaffs_Device *dev) { YFREE(dev->blockInfo); + dev->blockInfo = NULL; + YFREE(dev->chunkBits); + dev->chunkBits = NULL; } // FindDiretiestBlock is used to select the dirtiest block (or close enough) @@ -1814,7 +1994,7 @@ static int yaffs_FindDirtiestBlock(yaffs_Device *dev) int i; int dirtiest = -1; - int pagesInUse = 100; // silly big number + int pagesInUse = dev->nChunksPerBlock; yaffs_BlockInfo *bi; for(i = dev->startBlock; i <= dev->endBlock && pagesInUse > 2 ; i++) @@ -1834,10 +2014,10 @@ static int yaffs_FindDirtiestBlock(yaffs_Device *dev) bi = yaffs_GetBlockInfo(dev,b); if(bi->blockState == YAFFS_BLOCK_STATE_FULL && - bi->pagesInUse < pagesInUse) + (bi->pagesInUse - bi->softDeletions )< pagesInUse) { dirtiest = b; - pagesInUse = bi->pagesInUse; + pagesInUse = (bi->pagesInUse - bi->softDeletions); } } @@ -1868,10 +2048,12 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo) if( erasedOk ) { + // Clean it up... bi->blockState = YAFFS_BLOCK_STATE_EMPTY; dev->nErasedBlocks++; bi->pagesInUse = 0; - bi->pageBits = 0; + bi->softDeletions = 0; + yaffs_ClearChunkBits(dev,blockNo); T(YAFFS_TRACE_ERASE,(TSTR("Erased block %d" TENDSTR),blockNo)); } @@ -1886,13 +2068,14 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo) static int yaffs_FindBlockForAllocation(yaffs_Device *dev) { int i; + yaffs_BlockInfo *bi; if(dev->nErasedBlocks < 1) { // Hoosterman we've got a problem. // Can't get space to gc - T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: no space during gc" TENDSTR))); + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no space during gc" TENDSTR))); return -1; } @@ -1902,13 +2085,13 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev) for(i = dev->startBlock; i <= dev->endBlock; i++) { dev->allocationBlockFinder++; - if(dev->allocationBlockFinder < dev->startBlock || - dev->allocationBlockFinder > dev->endBlock) + if(dev->allocationBlockFinder startBlock || dev->allocationBlockFinder> dev->endBlock) { - dev->allocationBlockFinder = dev->startBlock; + dev->allocationBlockFinder = dev->startBlock; } bi = yaffs_GetBlockInfo(dev,dev->allocationBlockFinder); + if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY) { bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING; @@ -1948,7 +2131,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve) retVal = (dev->allocationBlock * YAFFS_CHUNKS_PER_BLOCK) + dev->allocationPage; bi->pagesInUse++; - bi->pageBits |= (1 << (dev->allocationPage)); + yaffs_SetChunkBit(dev,dev->allocationBlock,dev->allocationPage); dev->allocationPage++; @@ -1984,29 +2167,30 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) { int oldChunk; int newChunk; - __u32 mask; + int chunkInBlock; + int markNAND; yaffs_Spare spare; yaffs_Tags tags; __u8 buffer[YAFFS_BYTES_PER_CHUNK]; - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block); +// yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block); yaffs_Object *object; //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits)); - for(mask = 1,oldChunk = block * YAFFS_CHUNKS_PER_BLOCK; - mask && bi->pageBits; - mask <<= 1, oldChunk++ ) + for(chunkInBlock = 0,oldChunk = block * YAFFS_CHUNKS_PER_BLOCK; + chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block); + chunkInBlock++, oldChunk++ ) { - if(bi->pageBits & mask) + if(yaffs_CheckChunkBit(dev,block,chunkInBlock)) { - // This page is in use and needs to be copied off + // This page is in use and might need to be copied off - dev->nGCCopies++; + markNAND = 1; //T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk)); @@ -2023,15 +2207,27 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) // No need to copy this, just forget about it and fix up the // object. - yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0); + //yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0); object->nDataChunks--; + + if(object->nDataChunks <= 0) + { + // Time to delete the file too + yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top); + object->variant.fileVariant.top = NULL; + T(YAFFS_TRACE_TRACING,(TSTR("yaffs: About to finally delete object %d" TENDSTR),object->objectId)); + yaffs_DoGenericObjectDeletion(object); + } + markNAND = 0; } else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */) { // Deleted object header with no data chunks. - // Can be discarded + // Can be discarded and the file deleted. object->chunkId = 0; - //Todo some clean up + yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top); + object->variant.fileVariant.top = NULL; + yaffs_DoGenericObjectDeletion(object); } else if(object) @@ -2043,6 +2239,7 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) tags.serialNumber++; yaffs_LoadTagsIntoSpare(&spare,&tags); + dev->nGCCopies++; newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1); @@ -2065,7 +2262,7 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) } } - yaffs_DeleteChunk(dev,oldChunk); + yaffs_DeleteChunk(dev,oldChunk,markNAND); } } @@ -2076,12 +2273,12 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev) { - // todo find a file to delete + // find a file to delete struct list_head *i; yaffs_Object *l; - // To the free chunks add the chunks that are in the deleted unlinked files. + //Scan the unlinked files looking for one to delete list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children) { l = list_entry(i, yaffs_Object,siblings); @@ -2093,6 +2290,7 @@ static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev) return NULL; } + static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev) { // This does background deletion on unlinked files.. only deleted ones. @@ -2110,18 +2308,8 @@ static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev) int limit; // Number of chunks to delete in a file. // NB this can be exceeded, but not by much. - limit = 5; -#if 0 - if(dev->nErasedBlocks <= (YAFFS_RESERVED_BLOCKS + YAFFS_GARBAGE_COLLECT_LOW_WATER)) - { - limit = 50; // Doing GC soon, so dig deeper - } - else - { - limit = 5; - } -#endif - + limit = -1; + delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit); if(obj->nDataChunks == 0) @@ -2129,6 +2317,7 @@ static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev) // Done all the deleting of data chunks. // Now dump the header and clean up yaffs_FreeTnode(dev,obj->variant.fileVariant.top); + obj->variant.fileVariant.top = NULL; yaffs_DoGenericObjectDeletion(obj); dev->nDeletedFiles--; dev->nUnlinkedFiles--; @@ -2144,7 +2333,7 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev) { int block; - yaffs_DoUnlinkedFileDeletion(dev); + //yaffs_DoUnlinkedFileDeletion(dev); if(dev->nErasedBlocks <= (YAFFS_RESERVED_BLOCKS + YAFFS_GARBAGE_COLLECT_LOW_WATER)) { @@ -2261,12 +2450,10 @@ static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, con yaffs_SpareInitialise(&spare); -#ifndef CONFIG_YAFFS_USE_NANDECC - if(buffer) + if(!dev->useNANDECC && buffer) { yaffs_CalcECC(buffer,&spare); } -#endif yaffs_LoadTagsIntoSpare(&spare,tags); @@ -2290,13 +2477,10 @@ static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buff yaffs_SpareInitialise(&spare); -#ifndef CONFIG_YAFFS_USE_NANDECC - - if(buffer) + if(!dev->useNANDECC && buffer) { yaffs_CalcECC(buffer,&spare); } -#endif yaffs_LoadTagsIntoSpare(&spare,tags); @@ -2523,7 +2707,7 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn { //Hoosterman - how did this happen? - T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: existing chunk < 0 in scan" TENDSTR))); + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: existing chunk < 0 in scan" TENDSTR))); } @@ -2539,13 +2723,13 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn { // Use new // Delete the old one and drop through to update the tnode - yaffs_DeleteChunk(dev,existingChunk); + yaffs_DeleteChunk(dev,existingChunk,1); } else { // Use existing. // Delete the new one and return early so that the tnode isn't changed - yaffs_DeleteChunk(dev,chunkInNAND); + yaffs_DeleteChunk(dev,chunkInNAND,1); return YAFFS_OK; } } @@ -2580,7 +2764,7 @@ int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffe } -static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId) +static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND) { int block; int page; @@ -2588,16 +2772,26 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId) yaffs_BlockInfo *bi; if(chunkId <= 0) return; - + + dev->nDeletions++; block = chunkId / YAFFS_CHUNKS_PER_BLOCK; page = chunkId % YAFFS_CHUNKS_PER_BLOCK; - yaffs_SpareInitialise(&spare); - spare.pageStatus = 0; // To mark it as deleted. + if(markNAND) + { + yaffs_SpareInitialise(&spare); + + spare.pageStatus = 0; // To mark it as deleted. - yaffs_WriteChunkToNAND(dev,chunkId,NULL,&spare); - yaffs_HandleUpdateChunk(dev,chunkId,&spare); + yaffs_WriteChunkToNAND(dev,chunkId,NULL,&spare); + yaffs_HandleUpdateChunk(dev,chunkId,&spare); + } + else + { + dev->nUnmarkedDeletions++; + } + bi = yaffs_GetBlockInfo(dev,block); @@ -2608,7 +2802,7 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId) { dev->nFreeChunks++; - bi->pageBits &= ~(1 << page); + yaffs_ClearChunkBit(dev,block,page); bi->pagesInUse--; if(bi->pagesInUse == 0 && @@ -2664,7 +2858,7 @@ int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 * if(prevChunkId >= 0) { - yaffs_DeleteChunk(dev,prevChunkId); + yaffs_DeleteChunk(dev,prevChunkId,1); } @@ -2791,7 +2985,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force) // Create new chunk in NAND - newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,bufferNew,&newTags,1); + newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,bufferNew,&newTags, (prevChunkId >= 0) ? 1 : 0 ); if(newChunkId >= 0) { @@ -2800,7 +2994,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force) if(prevChunkId >= 0) { - yaffs_DeleteChunk(dev,prevChunkId); + yaffs_DeleteChunk(dev,prevChunkId,1); } in->dirty = 0; @@ -2823,7 +3017,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force) // need a very intelligent search. -#ifdef CONFIG_YAFFS_SHORT_OP_CACHE + static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) @@ -2834,50 +3028,55 @@ static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) yaffs_ChunkCache *cache; int chunkWritten; int nBytes; + int nCaches = obj->myDev->nShortOpCaches; - do{ - cache = NULL; + if (nCaches > 0) + { + do{ + cache = NULL; - // Find the dirty cache for this object with the lowest chunk id. - for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++) - { - if(dev->srCache[i].object == obj && - dev->srCache[i].dirty) + // Find the dirty cache for this object with the lowest chunk id. + for(i = 0; i < nCaches; i++) { - if(!cache || dev->srCache[i].chunkId < lowest) + if(dev->srCache[i].object == obj && + dev->srCache[i].dirty) { - cache = &dev->srCache[i]; - lowest = cache->chunkId; + if(!cache || dev->srCache[i].chunkId < lowest) + { + cache = &dev->srCache[i]; + lowest = cache->chunkId; + } } } - } - if(cache) - { - //Write it out - - nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK); - - if(nBytes > YAFFS_BYTES_PER_CHUNK) + if(cache) { - nBytes= YAFFS_BYTES_PER_CHUNK; - } + //Write it out + +#if 0 + nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK); - chunkWritten = yaffs_WriteChunkDataToObject(cache->object, - cache->chunkId, - cache->data, - nBytes,1); + if(nBytes > YAFFS_BYTES_PER_CHUNK) + { + nBytes= YAFFS_BYTES_PER_CHUNK; + } +#endif + chunkWritten = yaffs_WriteChunkDataToObject(cache->object, + cache->chunkId, + cache->data, + cache->nBytes,1); - cache->dirty = 0; - } + cache->dirty = 0; + } - } while(cache && chunkWritten > 0); + } while(cache && chunkWritten > 0); - if(cache) - { - //Hoosterman, disk full while writing cache out. - T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: no space during caceh write" TENDSTR))); + if(cache) + { + //Hoosterman, disk full while writing cache out. + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no space during cache write" TENDSTR))); + } } } @@ -2893,32 +3092,39 @@ static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev) int usage; int theOne; - for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++) + if(dev->nShortOpCaches > 0) { - if(!dev->srCache[i].object) + for(i = 0; i < dev->nShortOpCaches; i++) { - //T(("Grabbing empty %d\n",i)); + if(!dev->srCache[i].object) + { + //T(("Grabbing empty %d\n",i)); - return &dev->srCache[i]; + return &dev->srCache[i]; + } } - } - theOne = -1; - usage = 0; // just to stop the compiler grizzling + theOne = -1; + usage = 0; // just to stop the compiler grizzling - for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++) - { - if(!dev->srCache[i].dirty && - ((dev->srCache[i].lastUse < usage && theOne >= 0)|| - theOne < 0)) + for(i = 0; i < dev->nShortOpCaches; i++) { - usage = dev->srCache[i].lastUse; - theOne = i; + if(!dev->srCache[i].dirty && + ((dev->srCache[i].lastUse < usage && theOne >= 0)|| + theOne < 0)) + { + usage = dev->srCache[i].lastUse; + theOne = i; + } } - } - //T(("Grabbing non-empty %d\n",theOne)); - return theOne >= 0 ? &dev->srCache[theOne] : NULL; + //T(("Grabbing non-empty %d\n",theOne)); + return theOne >= 0 ? &dev->srCache[theOne] : NULL; + } + else + { + return NULL; + } } @@ -2930,37 +3136,42 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) int usage; int i; - // Try find a non-dirty one... + if(dev->nShortOpCaches > 0) + { + // Try find a non-dirty one... - cache = yaffs_GrabChunkCacheWorker(dev); + cache = yaffs_GrabChunkCacheWorker(dev); - if(!cache) - { - // They were all dirty, find the last recently used object and flush - // its cache, then find again. - // NB what's here is not very accurate, we actually flush the object - // the last recently used page. + if(!cache) + { + // They were all dirty, find the last recently used object and flush + // its cache, then find again. + // NB what's here is not very accurate, we actually flush the object + // the last recently used page. - theObj = dev->srCache[0].object; - usage = dev->srCache[0].lastUse; + theObj = dev->srCache[0].object; + usage = dev->srCache[0].lastUse; - for(i = 1; i < YAFFS_N_CACHE_CHUNKS; i++) - { - if( dev->srCache[i].object && - dev->srCache[i].lastUse < usage) + for(i = 1; i < dev->nShortOpCaches; i++) { - usage = dev->srCache[i].lastUse; - theObj = dev->srCache[i].object; + if( dev->srCache[i].object && + dev->srCache[i].lastUse < usage) + { + usage = dev->srCache[i].lastUse; + theObj = dev->srCache[i].object; + } } - } - yaffs_FlushFilesChunkCache(theObj); + yaffs_FlushFilesChunkCache(theObj); - // Try again - cache = yaffs_GrabChunkCacheWorker(dev); - } + // Try again + cache = yaffs_GrabChunkCacheWorker(dev); + } - return cache; + return cache; + } + else + return NULL; } @@ -2970,43 +3181,48 @@ static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, int chunk { yaffs_Device *dev = obj->myDev; int i; - - for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++) + if(dev->nShortOpCaches > 0) { - if(dev->srCache[i].object == obj && - dev->srCache[i].chunkId == chunkId) + for(i = 0; i < dev->nShortOpCaches; i++) { - dev->cacheHits++; + if(dev->srCache[i].object == obj && + dev->srCache[i].chunkId == chunkId) + { + dev->cacheHits++; - return &dev->srCache[i]; + return &dev->srCache[i]; + } } } - return NULL; } // Mark the chunk for the least recently used algorithym static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int isAWrite) { - if( dev->srLastUse < 0 || - dev->srLastUse > 100000000) + + if(dev->nShortOpCaches > 0) { - // Reset the cache usages - int i; - for(i = 1; i < YAFFS_N_CACHE_CHUNKS; i++) + if( dev->srLastUse < 0 || + dev->srLastUse > 100000000) { - dev->srCache[i].lastUse = 0; + // Reset the cache usages + int i; + for(i = 1; i < dev->nShortOpCaches; i++) + { + dev->srCache[i].lastUse = 0; + } + dev->srLastUse = 0; } - dev->srLastUse = 0; - } - dev->srLastUse++; + dev->srLastUse++; - cache->lastUse = dev->srLastUse; + cache->lastUse = dev->srLastUse; - if(isAWrite) - { - cache->dirty = 1; + if(isAWrite) + { + cache->dirty = 1; + } } } @@ -3015,11 +3231,14 @@ static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int // ie the short cache for this page is no longer valid. static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId) { - yaffs_ChunkCache *cache = yaffs_FindChunkCache(object,chunkId); - - if(cache) + if(object->myDev->nShortOpCaches > 0) { - cache->object = NULL; + yaffs_ChunkCache *cache = yaffs_FindChunkCache(object,chunkId); + + if(cache) + { + cache->object = NULL; + } } } @@ -3031,49 +3250,20 @@ static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in) int i; yaffs_Device *dev = in->myDev; - // Now invalidate it. - for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++) - { - if(dev->srCache[i].object == in) + if(dev->nShortOpCaches > 0) + { + // Now invalidate it. + for(i = 0; i < dev->nShortOpCaches; i++) { - dev->srCache[i].object = NULL; + if(dev->srCache[i].object == in) + { + dev->srCache[i].object = NULL; + } } } } -#else -// Stubs for disabling short op caching - -static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) -{} - -static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) -{ - return NULL; -} - - -static yaffs_ChunkCache *yaffs_FindChunkCache(yaffs_Device *dev, int objectId, int chunkId) -{ - return NULL; -} - -static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache) -{ -} - -static void yaffs_InvalidateChunkCache(yaffs_Object *obj, int chunkId) -{ -} - -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in) -{ -} - - - -#endif @@ -3119,27 +3309,32 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nB if(nToCopy != YAFFS_BYTES_PER_CHUNK) { // An incomplete start or end chunk (or maybe both start and end chunk) -#ifdef CONFIG_YAFFS_SHORT_OP_CACHE - yaffs_ChunkCache *cache; - // If we can't find the data in the cache, then load it up. - cache = yaffs_FindChunkCache(in,chunk); - if(!cache) + if(dev->nShortOpCaches > 0) { - cache = yaffs_GrabChunkCache(in->myDev); - cache->object = in; - cache->chunkId = chunk; - cache->dirty = 0; - yaffs_ReadChunkDataFromObject(in,chunk,cache->data); - } + yaffs_ChunkCache *cache; + // If we can't find the data in the cache, then load it up. + cache = yaffs_FindChunkCache(in,chunk); + if(!cache) + { + cache = yaffs_GrabChunkCache(in->myDev); + cache->object = in; + cache->chunkId = chunk; + cache->dirty = 0; + yaffs_ReadChunkDataFromObject(in,chunk,cache->data); + cache->nBytes = 0; + } - yaffs_UseChunkCache(dev,cache,0); + yaffs_UseChunkCache(dev,cache,0); + + memcpy(buffer,&cache->data[start],nToCopy); + } + else + { + // Read into the local buffer then copy... + yaffs_ReadChunkDataFromObject(in,chunk,dev->localBuffer); + memcpy(buffer,&dev->localBuffer[start],nToCopy); + } - memcpy(buffer,&cache->data[start],nToCopy); -#else - // Read into the local buffer then copy... - yaffs_ReadChunkDataFromObject(in,chunk,dev->localBuffer); - memcpy(buffer,&dev->localBuffer[start],nToCopy); -#endif } else { @@ -3221,42 +3416,44 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in if(nToCopy != YAFFS_BYTES_PER_CHUNK) { // An incomplete start or end chunk (or maybe both start and end chunk) -#ifdef CONFIG_YAFFS_SHORT_OP_CACHE - yaffs_ChunkCache *cache; - // If we can't find the data in the cache, then load it up. - cache = yaffs_FindChunkCache(in,chunk); - if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev)) + if(dev->nShortOpCaches > 0) { - cache = yaffs_GrabChunkCache(in->myDev); - cache->object = in; - cache->chunkId = chunk; - cache->dirty = 0; - yaffs_ReadChunkDataFromObject(in,chunk,cache->data); - } + yaffs_ChunkCache *cache; + // If we can't find the data in the cache, then load it up. + cache = yaffs_FindChunkCache(in,chunk); + if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev)) + { + cache = yaffs_GrabChunkCache(in->myDev); + cache->object = in; + cache->chunkId = chunk; + cache->dirty = 0; + yaffs_ReadChunkDataFromObject(in,chunk,cache->data); + } - if(cache) - { - yaffs_UseChunkCache(dev,cache,1); - memcpy(&cache->data[start],buffer,nToCopy); + if(cache) + { + yaffs_UseChunkCache(dev,cache,1); + memcpy(&cache->data[start],buffer,nToCopy); + cache->nBytes = nToWriteBack; + } + else + { + chunkWritten = -1; // fail the write + } } else { - chunkWritten = -1; // fail the write - } -#else - - - // An incomplete start or end chunk (or maybe both start and end chunk) - // Read into the local buffer then copy, then copy over and write back. + // An incomplete start or end chunk (or maybe both start and end chunk) + // Read into the local buffer then copy, then copy over and write back. - yaffs_ReadChunkDataFromObject(in,chunk,dev->localBuffer); + yaffs_ReadChunkDataFromObject(in,chunk,dev->localBuffer); - memcpy(&dev->localBuffer[start],buffer,nToCopy); + memcpy(&dev->localBuffer[start],buffer,nToCopy); - chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,dev->localBuffer,nToWriteBack,0); + chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,dev->localBuffer,nToWriteBack,0); - //T(("Write with readback to chunk %d %d start %d copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack)); -#endif + //T(("Write with readback to chunk %d %d start %d copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack)); + } } else @@ -3341,7 +3538,7 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize) else { in->nDataChunks--; - yaffs_DeleteChunk(dev,chunkId); + yaffs_DeleteChunk(dev,chunkId,1); } } @@ -3391,7 +3588,7 @@ loff_t yaffs_GetFileSize(yaffs_Object *obj) // yaffs_FlushFile() updates the file's // objectId in NAND -int yaffs_FlushFile(yaffs_Object *in) +int yaffs_FlushFile(yaffs_Object *in, int updateTime) { int retVal; if(in->dirty) @@ -3399,12 +3596,14 @@ int yaffs_FlushFile(yaffs_Object *in) //T(("flushing object header\n")); yaffs_FlushFilesChunkCache(in); - + if(updateTime) + { #ifdef CONFIG_YAFFS_WINCE - yfsd_WinFileTimeNow(in->win_mtime); + yfsd_WinFileTimeNow(in->win_mtime); #else - in->st_mtime = CURRENT_TIME; + in->st_mtime = CURRENT_TIME; #endif + } retVal = yaffs_UpdateObjectHeader(in,NULL,0); } @@ -3425,7 +3624,7 @@ static int yaffs_DoGenericObjectDeletion(yaffs_Object *in) yaffs_InvalidateWholeChunkCache(in); yaffs_RemoveObjectFromDirectory(in); - yaffs_DeleteChunk(in->myDev,in->chunkId); + yaffs_DeleteChunk(in->myDev,in->chunkId,1); #ifdef __KERNEL__ if(in->myInode) { @@ -3445,6 +3644,7 @@ static int yaffs_UnlinkFile(yaffs_Object *in) { #ifdef CONFIG_YAFFS_DISABLE_BACKGROUND_DELETION + // Delete the file data & tnodes yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL); @@ -3457,7 +3657,10 @@ static int yaffs_UnlinkFile(yaffs_Object *in) int retVal; int immediateDeletion=0; retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0); - if(retVal == YAFFS_OK) + if(1 || // Ignore the result of the change name. This will only fail + // if the disk was completely full (an error condition) + // We ignore the error so we can delete files to recover the disk + retVal == YAFFS_OK) { //in->unlinked = 1; //in->myDev->nUnlinkedFiles++; @@ -3468,8 +3671,7 @@ static int yaffs_UnlinkFile(yaffs_Object *in) immediateDeletion = 1; } -#endif -#ifdef CONFIG_YAFFS_WINCE +#else if(in->inUse <= 0) { immediateDeletion = 1; @@ -3482,6 +3684,7 @@ static int yaffs_UnlinkFile(yaffs_Object *in) T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId)); in->deleted=1; in->myDev->nDeletedFiles++; + yaffs_SoftDeleteFile(in); } } @@ -3494,18 +3697,33 @@ static int yaffs_UnlinkFile(yaffs_Object *in) int yaffs_DeleteFile(yaffs_Object *in) { int retVal = YAFFS_OK; - if(!in->unlinked) + + if(in->nDataChunks > 0) { - retVal = yaffs_UnlinkFile(in); + // Use soft deletion + if(!in->unlinked) + { + retVal = yaffs_UnlinkFile(in); + } + if(retVal == YAFFS_OK && + in->unlinked && + !in->deleted) + { + in->deleted = 1; + in->myDev->nDeletedFiles++; + yaffs_SoftDeleteFile(in); + } + return in->deleted ? YAFFS_OK : YAFFS_FAIL; } - if(retVal == YAFFS_OK && - in->unlinked && - !in->deleted) + else { - in->deleted = 1; - in->myDev->nDeletedFiles++; + // The file has no data chunks so we toss it immediately + yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top); + in->variant.fileVariant.top = NULL; + yaffs_DoGenericObjectDeletion(in); + + return YAFFS_OK; } - return in->deleted ? YAFFS_OK : YAFFS_FAIL; } static int yaffs_DeleteDirectory(yaffs_Object *in) @@ -3536,6 +3754,20 @@ static int yaffs_DeleteHardLink(yaffs_Object *in) } +static void yaffs_AbortHalfCreatedObject(yaffs_Object *obj) +{ + switch(obj->variantType) + { + case YAFFS_OBJECT_TYPE_FILE: yaffs_DeleteFile(obj); break; + case YAFFS_OBJECT_TYPE_DIRECTORY: yaffs_DeleteDirectory(obj); break; + case YAFFS_OBJECT_TYPE_SYMLINK: yaffs_DeleteSymLink(obj); break; + case YAFFS_OBJECT_TYPE_HARDLINK: yaffs_DeleteHardLink(obj); break; + case YAFFS_OBJECT_TYPE_SPECIAL: yaffs_DoGenericObjectDeletion(obj); break; + case YAFFS_OBJECT_TYPE_UNKNOWN: break; // should not happen. + } +} + + static int yaffs_UnlinkWorker(yaffs_Object *obj) { @@ -3687,8 +3919,9 @@ static int yaffs_Scan(yaffs_Device *dev) { deleted = 0; bi = yaffs_GetBlockInfo(dev,blk); - bi->pageBits = 0; + yaffs_ClearChunkBits(dev,blk); bi->pagesInUse = 0; + bi->softDeletions = 0; state = YAFFS_BLOCK_STATE_SCANNING; @@ -3746,7 +3979,7 @@ static int yaffs_Scan(yaffs_Device *dev) { int endpos; // A data chunk. - bi->pageBits |= (1 << c); + yaffs_SetChunkBit(dev,blk,c); bi->pagesInUse++; in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE); @@ -3769,7 +4002,7 @@ static int yaffs_Scan(yaffs_Device *dev) { // chunkId == 0, so it is an ObjectHeader. // Thus, we read in the object header and make the object - bi->pageBits |= (1 << c); + yaffs_SetChunkBit(dev,blk,c); bi->pagesInUse++; yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL,1); @@ -3788,13 +4021,13 @@ static int yaffs_Scan(yaffs_Device *dev) if(((existingSerial+1) & 3) == newSerial) { // Use new one - destroy the exisiting one - yaffs_DeleteChunk(dev,in->chunkId); + yaffs_DeleteChunk(dev,in->chunkId,1); in->valid = 0; } else { // Use existing - destroy this one. - yaffs_DeleteChunk(dev,chunk); + yaffs_DeleteChunk(dev,chunk,1); } } @@ -3868,7 +4101,7 @@ static int yaffs_Scan(yaffs_Device *dev) // Hoosterman, another problem.... // We're trying to use a non-directory as a directory // Todo ... handle - T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: attempting to use non-directory as a directory in scan" TENDSTR))); + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan" TENDSTR))); } @@ -3896,7 +4129,7 @@ static int yaffs_Scan(yaffs_Device *dev) break; case YAFFS_OBJECT_TYPE_HARDLINK: in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId; - (yaffs_Object *)(in->hardLinks.next) = hardList; + in->hardLinks.next = (struct list_head *)hardList; hardList = in; break; case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing @@ -3956,6 +4189,19 @@ static int yaffs_Scan(yaffs_Device *dev) } + { + struct list_head *i; + yaffs_Object *l; + // Soft delete all the unlinked files + list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children) + { + l = list_entry(i, yaffs_Object,siblings); + if(l->deleted) + { + yaffs_SoftDeleteFile(l); + } + } + } return YAFFS_OK; @@ -4291,6 +4537,14 @@ int yaffs_GutsInitialise(yaffs_Device *dev) T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs_CheckStructures failed\n" TENDSTR))); return YAFFS_FAIL; } + + if(dev->isMounted) + { + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device already mounted\n" TENDSTR))); + return YAFFS_FAIL; + } + + dev->isMounted = 1; if(dev->startBlock <= 0 || (dev->endBlock - dev->startBlock) < 10) @@ -4332,6 +4586,10 @@ int yaffs_GutsInitialise(yaffs_Device *dev) } dev->chunkGroupSize = 1 << dev->chunkGroupBits; + // Stuff to be taken out later + dev->nBytesPerChunk = YAFFS_BYTES_PER_CHUNK; + dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; + // More device initialisation dev->garbageCollectionRequired = 0; @@ -4348,7 +4606,10 @@ int yaffs_GutsInitialise(yaffs_Device *dev) dev->tagsEccFixed=0; dev->tagsEccUnfixed=0; - dev->localBuffer = YMALLOC(YAFFS_BYTES_PER_CHUNK); + dev->localBuffer = YMALLOC(dev->nBytesPerChunk); + + + yaffs_InitialiseBlocks(dev,nBlocks); @@ -4356,10 +4617,18 @@ int yaffs_GutsInitialise(yaffs_Device *dev) yaffs_InitialiseObjects(dev); -#ifdef CONFIG_YAFFS_SHORT_OP_CACHE + if(dev->nShortOpCaches > 0) { int i; - for(i=0; i < YAFFS_N_CACHE_CHUNKS; i++) + + if(dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) + { + dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; + } + + dev->srCache = YMALLOC( dev->nShortOpCaches * sizeof(yaffs_ChunkCache)); + + for(i=0; i < dev->nShortOpCaches; i++) { dev->srCache[i].object = NULL; dev->srCache[i].lastUse = 0; @@ -4367,7 +4636,6 @@ int yaffs_GutsInitialise(yaffs_Device *dev) } dev->srLastUse = 0; } -#endif dev->cacheHits = 0; @@ -4400,12 +4668,18 @@ int yaffs_GutsInitialise(yaffs_Device *dev) void yaffs_Deinitialise(yaffs_Device *dev) { - yaffs_DeinitialiseBlocks(dev); - yaffs_DeinitialiseTnodes(dev); - yaffs_DeinitialiseObjects(dev); + if(dev->isMounted) + { + + yaffs_DeinitialiseBlocks(dev); + yaffs_DeinitialiseTnodes(dev); + yaffs_DeinitialiseObjects(dev); + } } +#if 0 + int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) { int nFree = dev->nFreeChunks - (YAFFS_CHUNKS_PER_BLOCK * YAFFS_RESERVED_BLOCKS); @@ -4424,13 +4698,75 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) nFree += l->nDataChunks; } } + + + printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree); + + if(nFree < 0) nFree = 0; + + return nFree; + +} + +#endif + +int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) +{ + int nFree; + int pending; + int b; + + yaffs_BlockInfo *blk; + + struct list_head *i; + yaffs_Object *l; + + for(nFree = 0, b = dev->startBlock; b <= dev->endBlock; b++) + { + blk = yaffs_GetBlockInfo(dev,b); + + switch(blk->blockState) + { + case YAFFS_BLOCK_STATE_EMPTY: + case YAFFS_BLOCK_STATE_ALLOCATING: + case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse); break; + default: break; + } + } + + + pending = 0; + + // To the free chunks add the chunks that are in the deleted unlinked files. + list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children) + { + l = list_entry(i, yaffs_Object,siblings); + if(l->deleted) + { + pending++; + pending += l->nDataChunks; + } + } + + + + //printf("___________ really free is %d, pending %d, nFree is %d\n",nFree,pending, nFree+pending); + + if(nFree != dev->nFreeChunks) + { + // printf("___________Different! really free is %d, nFreeChunks %d\n",nFree dev->nFreeChunks); + } + nFree += pending; + + if(nFree < 0) nFree = 0; - return (nFree < 0) ? 0 : nFree; + return nFree; } + /////////////////// YAFFS test code ////////////////////////////////// #define yaffs_CheckStruct(structure,syze, name) \ @@ -4446,7 +4782,9 @@ static int yaffs_CheckStructures(void) yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags") yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion") yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare") +#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG yaffs_CheckStruct(yaffs_Tnode,2* YAFFS_NTNODES_LEVEL0,"yaffs_Tnode") +#endif yaffs_CheckStruct(yaffs_ObjectHeader,512,"yaffs_ObjectHeader") diff --git a/yaffs_guts.h b/yaffs_guts.h index 3ab41f7..0fe8f74 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.13 2002-12-13 00:13:06 charles Exp $ + * $Id: yaffs_guts.h,v 1.14 2003-01-14 23:15:32 charles Exp $ */ #ifndef __YAFFS_GUTS_H__ @@ -42,10 +42,11 @@ #define YAFFS_TNODES_INTERNAL_MASK 0x7 #define YAFFS_TNODES_MAX_LEVEL 6 +#define YAFFS_BYTES_PER_SPARE 16 + #define YAFFS_BYTES_PER_CHUNK 512 -#define YAFFS_CHUNK_SIZE_SHIFT 9 +//#define YAFFS_CHUNK_SIZE_SHIFT 9 -#define YAFFS_BYTES_PER_SPARE 16 #define YAFFS_CHUNKS_PER_BLOCK 32 #define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK) @@ -73,14 +74,7 @@ #define YAFFS_OBJECTID_LOSTNFOUND 2 #define YAFFS_OBJECTID_UNLINKED 3 -#define YAFFS_N_CACHE_CHUNKS 10 - -#ifdef CONFIG_YAFFS_WINCE - -// Force the short operation cache on for WinCE - -#define CONFIG_YAFFS_SHORT_OP_CACHE -#endif +#define YAFFS_MAX_SHORT_OP_CACHES 20 // ChunkCache is used for short read/write operations. @@ -90,11 +84,12 @@ typedef struct int chunkId; int lastUse; int dirty; + int nBytes; // Only valid if the cache is dirty __u8 data[YAFFS_BYTES_PER_CHUNK]; } yaffs_ChunkCache; // Tags structures in RAM -// NB This uses bitfield. Bitfields should not stradle a u32 boundary otherwise +// NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise // the structure size will get blown out. typedef struct @@ -131,10 +126,17 @@ typedef struct __u8 ecc2[3]; } yaffs_Spare; +//Special structure for passing through to mtd +struct yaffs_NANDSpare { + yaffs_Spare spare; + int eccres1; + int eccres2; +}; + // Block data in RAM typedef enum { - YAFFS_BLOCK_STATE_UddNKNOWN = 0, + YAFFS_BLOCK_STATE_UNKNOWN = 0, YAFFS_BLOCK_STATE_SCANNING, // Used while the block is being scanned. // NB Don't erase blocks while they're being scanned @@ -151,7 +153,7 @@ typedef enum { YAFFS_BLOCK_STATE_DIRTY, // All pages have been allocated and deleted. // Erase me, reuse me. - YAFFS_BLOCK_STATE_DEAD = 0x77 // This block has failed and is not in use + YAFFS_BLOCK_STATE_DEAD // This block has failed and is not in use } yaffs_BlockState; @@ -160,10 +162,13 @@ typedef enum { typedef struct { - __u32 pageBits; // bitmap of pages in use - __u8 blockState; // One of the above block states - __u8 pagesInUse; // number of pages in use - __u8 needsRetiring:1; // Data has failed on this block, need to get valid data off +#ifndef CONFIG_YAFFS_NO_YAFFS2 + __u32 sequenceNumber; // block sequence number for yaffs2 +#endif + int softDeletions:8; // number of soft deleted pages + int pagesInUse:8; // number of pages in use + __u32 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. } yaffs_BlockInfo; @@ -231,7 +236,11 @@ typedef struct union yaffs_Tnode_union { +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG + union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL+1]; +#else union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL]; +#endif __u16 level0[YAFFS_NTNODES_LEVEL0]; }; @@ -292,6 +301,7 @@ typedef union struct yaffs_ObjectStruct { __u8 deleted: 1; // This should only apply to unlinked files. + __u8 softDeleted: 1; // it has also been soft deleted __u8 unlinked: 1; // An unlinked file. The file should be in the unlinked pseudo directory. __u8 fake:1; // A fake object has no presence on NAND. __u8 renameAllowed:1; @@ -331,9 +341,11 @@ struct yaffs_ObjectStruct char shortName[YAFFS_SHORT_NAME_LENGTH+1]; #endif -#ifdef CONFIG_YAFFS_WINCE +#ifndef __KERNEL__ __u32 inUse; +#endif +#ifdef CONFIG_YAFFS_WINCE __u32 win_ctime[2]; __u32 win_mtime[2]; __u32 win_atime[2]; @@ -343,9 +355,9 @@ struct yaffs_ObjectStruct __u32 st_atime; // time of last access __u32 st_mtime; // time of last modification __u32 st_ctime; // time of last change - __u32 st_rdev; // device stuff for block and char devices #endif + __u32 st_rdev; // device stuff for block and char devices @@ -386,23 +398,19 @@ typedef struct struct yaffs_DeviceStruct { // Entry parameters set up way early. Yaffs sets up the rest. + int nBytesPerChunk; // Should be a power of 2 >= 512 + int nChunksPerBlock; int startBlock; // Start block we're allowed to use int endBlock; // End block we're allowed to use - __u16 chunkGroupBits; // 0 for devices <= 32MB. else log2(nchunks) - 16 - __u16 chunkGroupSize; // == 2^^chunkGroupBits + + int useNANDECC; // Flag to decide whether or not to use NANDECC + int nShortOpCaches; // If <= 0, then short op caching is disabled, else + // the number of short op caches (don't use too many). 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 grossLock; // Gross locking semaphore -#endif - - // NAND access functions (Must be set before calling YAFFS) int (*writeChunkToNAND)(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare); @@ -410,16 +418,34 @@ struct yaffs_DeviceStruct int (*eraseBlockInNAND)(struct yaffs_DeviceStruct *dev,int blockInNAND); int (*initialiseNAND)(struct yaffs_DeviceStruct *dev); + // Runtime parameters. Set up by YAFFS. + + __u16 chunkGroupBits; // 0 for devices <= 32MB. else log2(nchunks) - 16 + __u16 chunkGroupSize; // == 2^^chunkGroupBits + +#ifdef __KERNEL__ + + struct semaphore sem;// Semaphore for waiting on erasure. + struct semaphore grossLock; // Gross locking semaphore + +#endif #ifdef __KERNEL__ void (*putSuperFunc)(struct super_block *sb); #endif - // Runtime parameters. + int isMounted; + + // Block Info yaffs_BlockInfo *blockInfo; + __u8 *chunkBits; // bitmap of chunks in use + int chunkBitmapStride; // Number of bytes of chunkBits per block. + // Must be consistent with nChunksPerBlock. + + int nErasedBlocks; - int allocationBlock; + int allocationBlock; // Current block being allocated off __u32 allocationPage; - int allocationBlockFinder; + int allocationBlockFinder; // Used to search for next allocation block // Runtime state int nTnodesCreated; @@ -454,22 +480,23 @@ struct yaffs_DeviceStruct int eccUnfixed; int tagsEccFixed; int tagsEccUnfixed; + int nDeletions; + int nUnmarkedDeletions; yaffs_Object *rootDir; yaffs_Object *lostNFoundDir; // Buffer areas for storing data to recover from write failures - __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK]; - yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK]; +// __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK]; +// yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK]; int bufferedBlock; // Which block is buffered here? int doingBufferedBlockRewrite; int blockSelectedForGC; -#ifdef CONFIG_YAFFS_SHORT_OP_CACHE - yaffs_ChunkCache srCache[YAFFS_N_CACHE_CHUNKS]; + yaffs_ChunkCache *srCache; int srLastUse; -#endif + int cacheHits; // Stuff for background deletion and unlinked files. @@ -519,7 +546,7 @@ int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, __u32 offset, i int yaffs_ResizeFile(yaffs_Object *obj, int newSize); yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid); -int yaffs_FlushFile(yaffs_Object *obj); +int yaffs_FlushFile(yaffs_Object *obj,int updateTime); // Directory operations @@ -560,3 +587,4 @@ void yaffs_GutsTest(yaffs_Device *dev); #endif + diff --git a/yaffs_mtdif.c b/yaffs_mtdif.c index 5505d55..14876c8 100644 --- a/yaffs_mtdif.c +++ b/yaffs_mtdif.c @@ -13,7 +13,7 @@ * */ -const char *yaffs_mtdif_c_version = "$Id: yaffs_mtdif.c,v 1.5 2002-12-13 00:13:06 charles Exp $"; +const char *yaffs_mtdif_c_version = "$Id: yaffs_mtdif.c,v 1.6 2003-01-14 23:15:32 charles Exp $"; #ifdef CONFIG_YAFFS_MTD_ENABLED @@ -42,11 +42,10 @@ int nandmtd_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, #ifndef CONFIG_YAFFS_USE_OLD_MTD if(data && spare) { -#ifdef CONFIG_YAFFS_USE_NANDECC - retval = mtd->write_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_YAFFS_OOB); -#else - retval = mtd->write_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_NONE_OOB); -#endif + if(dev->useNANDECC) + mtd->write_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_YAFFS_OOB); + else + mtd->write_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_NONE_OOB); } else { @@ -78,13 +77,16 @@ int nandmtd_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaf #ifndef CONFIG_YAFFS_USE_OLD_MTD if(data && spare) { -#ifdef CONFIG_YAFFS_USE_NANDECC - u8 tmpSpare[ YAFFS_BYTES_PER_SPARE + (2*sizeof(int)) ]; - retval = mtd->read_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,tmpSpare,NAND_YAFFS_OOB); - memcpy(spareAsBytes, tmpSpare, YAFFS_BYTES_PER_SPARE); -#else - retval = mtd->read_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_NONE_OOB); -#endif + if(dev->useNANDECC) + { + u8 tmpSpare[ YAFFS_BYTES_PER_SPARE + (2*sizeof(int)) ]; + retval = mtd->read_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,tmpSpare,NAND_YAFFS_OOB); + memcpy(spareAsBytes, tmpSpare, YAFFS_BYTES_PER_SPARE); + } + else + { + retval = mtd->read_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_NONE_OOB); + } } else { diff --git a/yaffsdev.c b/yaffsdev.c index c44715b..f325b78 100644 --- a/yaffsdev.c +++ b/yaffsdev.c @@ -111,7 +111,7 @@ void TestTimeasasas(yaffs_Device *dev) printf("Flush\n"); - yaffs_FlushFile(f); + yaffs_FlushFile(f,1); yaffs_ApplyToDirectoryChildren(yaffs_Root(dev),yaffs_DumpObject); @@ -129,7 +129,7 @@ void TestTimeasasas(yaffs_Device *dev) yaffs_DumpObject(f); - yaffs_FlushFile(f); + yaffs_FlushFile(f,1); @@ -187,7 +187,7 @@ void TestTimeBigDeletes(yaffs_Device *dev) written = yaffs_WriteDataToFile(f,testStr2,i,strlen(testStr2)); } - yaffs_FlushFile(f); + yaffs_FlushFile(f,1); yaffs_DeleteFile(f); f = yaffs_FindObjectByName(yaffs_Root(dev),"Name1"); @@ -211,7 +211,7 @@ void TestTimeBigDeletes(yaffs_Device *dev) written = yaffs_WriteDataToFile(f,testStr2,i,strlen(testStr2)); } - yaffs_FlushFile(f); + yaffs_FlushFile(f,1); yaffs_DeleteFile(f); f = yaffs_FindObjectByName(yaffs_Root(dev),"Name1"); @@ -235,7 +235,7 @@ void TestTimeBigDeletes(yaffs_Device *dev) written = yaffs_WriteDataToFile(f,testStr2,i,strlen(testStr2)); } - yaffs_FlushFile(f); + yaffs_FlushFile(f,1); yaffs_DeleteFile(f); } @@ -392,7 +392,7 @@ void TestTime(yaffs_Device *dev) printf("Flush\n"); - yaffs_FlushFile(f); + yaffs_FlushFile(f,1); yaffs_ReadDataFromFile(f,data,1000,50); data[50] = 0; @@ -443,7 +443,7 @@ void TestTime(yaffs_Device *dev) - yaffs_FlushFile(f); + yaffs_FlushFile(f,1); printf("Unlink file: %d\n",yaffs_Unlink(yaffs_Root(dev),"Rename")); @@ -573,7 +573,7 @@ void TestTimeDeleteFocussed(yaffs_Device *dev) - yaffs_FlushFile(f); + yaffs_FlushFile(f,1); printf("Unlink file: %d\n",yaffs_Unlink(yaffs_Root(dev),"Rename")); @@ -629,6 +629,56 @@ void TestTimeTnodeFocussed(yaffs_Device *dev) written = yaffs_WriteDataToFile(f,testStr2,0,strlen(testStr2)); } +} +void TestTimeBackgroundDeleteFocussed(yaffs_Device *dev) +{ + yaffs_Object *f; + yaffs_Object *lnf; + + + int x; + int i,j; + int b; + int written; + + + printf("Exisiting objects\n"); + yaffs_ApplyToDirectoryChildren(yaffs_Root(dev),yaffs_DumpObject); + printf("Exisiting objects in lost+found\n"); + lnf = yaffs_FindObjectByName(yaffs_Root(dev),YAFFS_LOSTNFOUND_NAME); + yaffs_ApplyToDirectoryChildren(lnf,yaffs_DumpObject); + + printf("Start\n"); + + + for(j = 0; j < 20; j++) + { + printf("Run %d\n",j); + + f = yaffs_FindObjectByName(yaffs_Root(dev),"Name1"); + if(f) + { + printf("Found\n"); + } + else + { + f = yaffs_MknodFile(yaffs_Root(dev),"Name1",0,0,0); + printf("Created\n"); + } + + printf("@@@@@@@ Run %d, object %d\n",j,f->objectId); + + for(i = 0; i < 1000000; i+=20) + { + + written = yaffs_WriteDataToFile(f,testStr,i,100); + } + + yaffs_FlushFile(f,1); + + yaffs_DeleteFile(f); + } + } int main(int argc,char *argv[]) @@ -637,7 +687,7 @@ int main(int argc,char *argv[]) int nBlocks; #if YAFFS_FILEEM - nBlocks =(4 * 1024 * 1024) / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK) ; + nBlocks =(2 * 1024 * 1024) / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK) ; device.writeChunkToNAND = yaffs_FEWriteChunkToNAND; device.readChunkFromNAND = yaffs_FEReadChunkFromNAND; device.eraseBlockInNAND = yaffs_FEEraseBlockInNAND; @@ -662,14 +712,20 @@ int main(int argc,char *argv[]) device.endBlock = nBlocks; #endif + device.nShortOpCaches = 10; + + yaffs_GutsInitialise(&device); // yaffs_GutsTest(); - TestTime(&device); + TestTimeBackgroundDeleteFocussed(&device); printf("Cache hits %d\n",device.cacheHits); printf("Retired blocks %d\n",device.nRetiredBlocks); + printf("Deletions %d\n",device.nDeletions); + printf("Unmarked deletions %d\n",device.nUnmarkedDeletions); + exit(0); } diff --git a/yaffsdev.proj b/yaffsdev.proj index 770d67c5c763dffc2423e8bee0a725bda635b61e..fa40e294daa7c7730fda1cf8e35ce49bf0e8c1f3 100644 GIT binary patch delta 2201 zcmb7FUu;uV7;o2eJLmxS2iRbYovpw+y0Lq2*Ork<*w$@;Fpw3R@?g2`y?49r_FldB zc5K!nBPKqG3GkU{G?AeaBZ)J$JQ#g2L?yl$<;fQk+?zr|NYrQ~QO~(;*(QT%n%?uB z?>pbW-}jyKot|}_o^_quRdM@7zSp%0W-c}|qGC=s3W-f$dzm}VYtB1`_C2SZp6rw% z$vB&pGw@lw3Eqv=d3i1r-obJlRu+VKT99QkF=R+mRMSP6A6$#ra3}!Jzqrv?lu^Ef zx94y;+_Qtr<#17Zks{1bcfrR8ni0pcVYs)q8QwU!0dXAL4XY3CUGX1{haPQwO+-Jc zsfsosi9?Di!CR3=#Pgw@B+3n)Im`!G?jhx+DiKMQEJfEqc%h?mX|h3f*<^#khfLau z*vY;c@wC~jeJ?t&$?UPQ;f}7_SU5t;}$kZ~G48#16 z?x9=gCc2KkLRZlz=n}e!&ZD#FWpoBP8yt>%t~01`;Y4o*oKMyJMP7iu_yE{U_`A9r{4Fjl&gO7$W-v7$@@w`VHMh zdr$!RP(50QT*!%jb^YS1SmAJ7CTsr2&5A(wq@s!XNgN=?gB%X_usGBmpz9P_{eDXtXann7~IxQN$VgF)c$7 zRS65Ks;30{{`C`L0?WE#vozg78$;LBX@?iI(T(6fvWYr)$r6k)$-9el$1*0 zEZlg1+}Q>B%U$F2_Ir?{a(F zF=}Nb{xG2O@y29CLq_;8LLib76JtU$jX#W)va1SyT3??DHGI;vY+fhp<}=oP(KPFU42>Ejq(7>oPM#l9DWO1;na8?oQ>AOEjrf; zy_uWhVIBN!HNXdhD`3*n0yhVZ@J^&*l`P0&OcO%`vZPT@NO1!5Q=5$cE`#1+ADoLk zZ7wi(6G8M(CTMQZ$S`tk36keqVD&^ZoR73r#%E(JlfZs({nGqg#A5KPM9|0xjRJ|o zqt*?j0A;M$p3ve;hCr=t<70^Kpw+<6?h`a2Ys`YR5xQ&!#IlwO;l{PqOmlXm3M+P# zxOA8RrB&yq1>%F|VK7cqfn~cH>TC^kG$Bhw1ba)feoU1#!j2eG*iK{7I=8(MPDquo zQsUwL=I7e{lO#OFtj2u4I3iM%kXUD!mJAUozQmwz#o4_FHuadqJUbxC;?Vd(64rdP zfLl$lUs`D{27`&%I8k%fS!;q)nB?h+@D$PLeH)(yPfc3&rFxqT#X8~n)@HcYQmrpi z1&b{k4Ml4W6lqN+9evPLJ+EJ2|a^9XRXo)U+@`^3Hd8+?f3- z7L~lqY5q%*&M=-<;@HJ^I&fU0nTcgZjWr5UtR&SL7EMhUXX%5xu|j(up-`HBpbW1C z!-ei6BNjZvQYFl4LsM|JC3bY+RK5UkSS4w^Z>M)~aLAuOxsN1i{BTqW3sD~)CR)zl zK_N!4(_wevT##_CR)S=P%5hjp$Qt&F;*iS3SW~8>IKD*_RLzHJtMg%Rlxft69}}8P zk!;4|_@tt0A!VA`L1iLNQAJUaUQ>g67bY`zFF!;O8Z*M2*90G3X@?&#R+jzN*Dt#MTR?X}*Si&r05Tov`iXYFc%_4#Q1e)CCX8I# zoKNg?lme7tjLTHk79@@&r=kXg;=Y_BwypjpeI<7zd$VX3Of1rlb*wivPo n(8t7sZB__fUB~3`#a=5HPziz8_Ih#?ion~WcQQX*Yi#@nD=N4K diff --git a/yportenv.h b/yportenv.h index 943cffe..b330375 100644 --- a/yportenv.h +++ b/yportenv.h @@ -15,7 +15,7 @@ * * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. * - * $Id: yportenv.h,v 1.7 2002-11-26 01:15:37 charles Exp $ + * $Id: yportenv.h,v 1.8 2003-01-14 23:15:41 charles Exp $ * */ @@ -30,6 +30,8 @@ #include "stdio.h" #include "string.h" +#define CONFIG_YAFFS_CASE_INSENSITIVE + #define YMALLOC(x) malloc(x) #define YFREE(x) free(x) @@ -100,9 +102,44 @@ extern unsigned yfsd_U32FileTimeNow(void); #define TOUT(p) printk p -#else +#elif defined CONFIG_YAFFS_DIRECT + +// Directct interface + +#include "stdlib.h" +#include "stdio.h" +#include "string.h" + +#define YMALLOC(x) malloc(x) +#define YFREE(x) free(x) + + +//#define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) +//#define YALERT(s) YINFO(s) + + +#define TENDSTR "\n" +#define TSTR(x) x +#define TOUT(p) printf p + + +#define YAFFS_LOSTNFOUND_NAME "lost+found" +#define YAFFS_LOSTNFOUND_PREFIX "obj" +//#define YPRINTF(x) printf x + +#include "yaffscfg.h" + +#define CURRENT_TIME yaffsfs_CurrentTime() +#define YAFFS_ROOT_MODE 0666 +#define YAFFS_LOSTNFOUND_MODE 0666 + +#define yaffs_SumCompare(x,y) ((x) == (y)) +#define yaffs_strcmp(a,b) strcmp(a,b) + +#elif defined CONFIG_YAFFS_UTIL + +// Stuff for YAFFS utilities -// Linux application #include "stdlib.h" #include "stdio.h" #include "string.h" @@ -124,6 +161,7 @@ extern unsigned yfsd_U32FileTimeNow(void); #define YAFFS_LOSTNFOUND_PREFIX "obj" //#define YPRINTF(x) printf x + #define CURRENT_TIME 0 #define YAFFS_ROOT_MODE 0666 #define YAFFS_LOSTNFOUND_MODE 0666 @@ -131,6 +169,10 @@ extern unsigned yfsd_U32FileTimeNow(void); #define yaffs_SumCompare(x,y) ((x) == (y)) #define yaffs_strcmp(a,b) strcmp(a,b) +#else +// Should have specified a configuration type +#error Unknown configuration + #endif -- 2.30.2