diff options
Diffstat (limited to 'fs/yaffs2/direct')
-rw-r--r-- | fs/yaffs2/direct/Makefile | 66 | ||||
-rw-r--r-- | fs/yaffs2/direct/dtest.c | 2280 | ||||
-rw-r--r-- | fs/yaffs2/direct/fsx_test/Makefile | 75 | ||||
-rw-r--r-- | fs/yaffs2/direct/fsx_test/README | 7 | ||||
-rw-r--r-- | fs/yaffs2/direct/fsx_test/yaffs_fsx.c | 1007 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffs_fileem.c | 218 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffs_fileem2k.c | 441 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffs_fileem2k.h | 50 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffs_flashif.c | 229 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffs_flashif.h | 31 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffs_malloc.h | 23 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffs_ramdisk.c | 234 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffs_ramdisk.h | 32 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffs_ramem2k.c | 363 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffscfg.c | 144 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffscfg.h | 45 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffscfg2k.c | 229 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffsfs.c | 1505 | ||||
-rw-r--r-- | fs/yaffs2/direct/yaffsfs.h | 233 | ||||
-rw-r--r-- | fs/yaffs2/direct/ydirectenv.h | 88 |
20 files changed, 7300 insertions, 0 deletions
diff --git a/fs/yaffs2/direct/Makefile b/fs/yaffs2/direct/Makefile new file mode 100644 index 0000000000..6315117cdf --- /dev/null +++ b/fs/yaffs2/direct/Makefile @@ -0,0 +1,66 @@ +# Makefile for YAFFS direct test +# +# +# YAFFS: Yet another Flash File System. A NAND-flash specific file system. +# +# Copyright (C) 2003 Aleph One Ltd. +# +# +# Created by Charles Manning <charles@aleph1.co.uk> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# NB Warning this Makefile does not include header dependencies. +# +# $Id: Makefile,v 1.15 2007/07/18 19:40:38 charles Exp $ + +#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC + +CFLAGS = -Wall -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -g $(EXTRA_COMPILE_FLAGS) -DNO_Y_INLINE +CFLAGS+= -fstack-check -O0 + +#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations +#CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline + + +DIRECTTESTOBJS = dtest.o yaffscfg2k.o yaffs_ecc.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \ + yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \ + yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \ + yaffs_checkptrw.o yaffs_qsort.o \ +# yaffs_checkptrwtest.o\ + + +BOOTTESTOBJS = bootldtst.o yboot.o yaffs_fileem.o nand_ecc.o + +#ALLOBJS = dtest.o nand_ecc.o yaffscfg.o yaffs_fileem.o yaffsfs.o yaffs_ramdisk.o bootldtst.o yboot.o yaffs_ramem2k.o + +ALLOBJS = $(DIRECTTESTOBJS) $(BOOTTESTOBJS) + +SYMLINKS = devextras.h yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h yaffsinterface.h yportenv.h yaffs_tagscompat.c yaffs_tagscompat.h \ + yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h yaffs_nandemul2k.h \ + yaffs_nand.c yaffs_nand.h \ + yaffs_tagsvalidity.c yaffs_tagsvalidity.h yaffs_checkptrw.h yaffs_checkptrw.c \ + yaffs_qsort.c yaffs_qsort.h + +#all: directtest2k boottest + +all: directtest2k + +$(ALLOBJS): %.o: %.c + gcc -c $(CFLAGS) $< -o $@ + +$(SYMLINKS): + ln -s ../$@ $@ + +directtest2k: $(SYMLINKS) $(DIRECTTESTOBJS) + gcc -o $@ $(DIRECTTESTOBJS) + + +boottest: $(SYMLINKS) $(BOOTTESTOBJS) + gcc -o $@ $(BOOTTESTOBJS) + + +clean: + rm -f $(ALLOBJS) core diff --git a/fs/yaffs2/direct/dtest.c b/fs/yaffs2/direct/dtest.c new file mode 100644 index 0000000000..be492b47c9 --- /dev/null +++ b/fs/yaffs2/direct/dtest.c @@ -0,0 +1,2280 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* +* Test code for the "direct" interface. +*/ + + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#include "yaffsfs.h" + +void dumpDir(const char *dname); + +char xx[600]; + +void copy_in_a_file(char *yaffsName,char *inName) +{ + int inh,outh; + unsigned char buffer[100]; + int ni,no; + inh = open(inName,O_RDONLY); + outh = yaffs_open(yaffsName, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); + + while((ni = read(inh,buffer,100)) > 0) + { + no = yaffs_write(outh,buffer,ni); + if(ni != no) + { + printf("problem writing yaffs file\n"); + } + + } + + yaffs_close(outh); + close(inh); +} + +void make_a_file(char *yaffsName,char bval,int sizeOfFile) +{ + int outh; + int i; + unsigned char buffer[100]; + + outh = yaffs_open(yaffsName, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); + + memset(buffer,bval,100); + + do{ + i = sizeOfFile; + if(i > 100) i = 100; + sizeOfFile -= i; + + yaffs_write(outh,buffer,i); + + } while (sizeOfFile > 0); + + + yaffs_close(outh); + +} + +void make_pattern_file(char *fn,int size) +{ + int outh; + int marker; + int i; + outh = yaffs_open(fn, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); + yaffs_lseek(outh,size-1,SEEK_SET); + yaffs_write(outh,"A",1); + + for(i = 0; i < size; i+=256) + { + marker = ~i; + yaffs_lseek(outh,i,SEEK_SET); + yaffs_write(outh,&marker,sizeof(marker)); + } + yaffs_close(outh); + +} + +int check_pattern_file(char *fn) +{ + int h; + int marker; + int i; + int size; + int ok = 1; + + h = yaffs_open(fn, O_RDWR,0); + size = yaffs_lseek(h,0,SEEK_END); + + for(i = 0; i < size; i+=256) + { + yaffs_lseek(h,i,SEEK_SET); + yaffs_read(h,&marker,sizeof(marker)); + ok = (marker == ~i); + if(!ok) + { + printf("pattern check failed on file %s, size %d at position %d. Got %x instead of %x\n", + fn,size,i,marker,~i); + } + } + yaffs_close(h); + return ok; +} + + + + + +int dump_file_data(char *fn) +{ + int h; + int marker; + int i = 0; + int size; + int ok = 1; + unsigned char b; + + h = yaffs_open(fn, O_RDWR,0); + + + printf("%s\n",fn); + while(yaffs_read(h,&b,1)> 0) + { + printf("%02x",b); + i++; + if(i > 32) + { + printf("\n"); + i = 0;; + } + } + printf("\n"); + yaffs_close(h); + return ok; +} + + + +void dump_file(const char *fn) +{ + int i; + int size; + int h; + + h = yaffs_open(fn,O_RDONLY,0); + if(h < 0) + { + printf("*****\nDump file %s does not exist\n",fn); + } + else + { + size = yaffs_lseek(h,0,SEEK_SET); + printf("*****\nDump file %s size %d\n",fn,size); + for(i = 0; i < size; i++) + { + + } + } +} + +void create_file_of_size(const char *fn,int syze) +{ + int h; + int n; + + char xx[200]; + + int iterations = (syze + strlen(fn) -1)/ strlen(fn); + + h = yaffs_open(fn, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); + + while (iterations > 0) + { + sprintf(xx,"%s %8d",fn,iterations); + yaffs_write(h,xx,strlen(xx)); + iterations--; + } + yaffs_close (h); +} + +void verify_file_of_size(const char *fn,int syze) +{ + int h; + int n; + + char xx[200]; + char yy[200]; + int l; + + int iterations = (syze + strlen(fn) -1)/ strlen(fn); + + h = yaffs_open(fn, O_RDONLY, S_IREAD | S_IWRITE); + + while (iterations > 0) + { + sprintf(xx,"%s %8d",fn,iterations); + l = strlen(xx); + + yaffs_read(h,yy,l); + yy[l] = 0; + + if(strcmp(xx,yy)){ + printf("=====>>>>> verification of file %s failed near position %d\n",fn,yaffs_lseek(h,0,SEEK_CUR)); + } + iterations--; + } + yaffs_close (h); +} + +void create_resized_file_of_size(const char *fn,int syze1,int reSyze, int syze2) +{ + int h; + int n; + + + int iterations; + + h = yaffs_open(fn, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); + + iterations = (syze1 + strlen(fn) -1)/ strlen(fn); + while (iterations > 0) + { + yaffs_write(h,fn,strlen(fn)); + iterations--; + } + + yaffs_truncate(h,reSyze); + + yaffs_lseek(h,0,SEEK_SET); + iterations = (syze2 + strlen(fn) -1)/ strlen(fn); + while (iterations > 0) + { + yaffs_write(h,fn,strlen(fn)); + iterations--; + } + + yaffs_close (h); +} + + +void do_some_file_stuff(const char *path) +{ + + char fn[100]; + + sprintf(fn,"%s/%s",path,"f1"); + create_file_of_size(fn,10000); + + sprintf(fn,"%s/%s",path,"fdel"); + create_file_of_size(fn,10000); + yaffs_unlink(fn); + + sprintf(fn,"%s/%s",path,"f2"); + + create_resized_file_of_size(fn,10000,3000,4000); +} + +void yaffs_backward_scan_test(const char *path) +{ + char fn[100]; + + yaffs_StartUp(); + + yaffs_mount(path); + + do_some_file_stuff(path); + + sprintf(fn,"%s/ddd",path); + + yaffs_mkdir(fn,0); + + do_some_file_stuff(fn); + + yaffs_unmount(path); + + yaffs_mount(path); +} + +char xxzz[2000]; + + +void yaffs_device_flush_test(const char *path) +{ + char fn[100]; + int h; + int i; + + yaffs_StartUp(); + + yaffs_mount(path); + + do_some_file_stuff(path); + + // Open and add some data to a few files + for(i = 0; i < 10; i++) { + + sprintf(fn,"%s/ff%d",path,i); + + h = yaffs_open(fn, O_CREAT | O_RDWR | O_TRUNC, S_IWRITE | S_IREAD); + yaffs_write(h,xxzz,2000); + yaffs_write(h,xxzz,2000); + } + yaffs_unmount(path); + + yaffs_mount(path); +} + + + +void short_scan_test(const char *path, int fsize, int niterations) +{ + int i; + char fn[100]; + + sprintf(fn,"%s/%s",path,"f1"); + + yaffs_StartUp(); + for(i = 0; i < niterations; i++) + { + printf("\n*****************\nIteration %d\n",i); + yaffs_mount(path); + printf("\nmount: Directory look-up of %s\n",path); + dumpDir(path); + make_a_file(fn,1,fsize); + yaffs_unmount(path); + } +} + + + +void scan_pattern_test(const char *path, int fsize, int niterations) +{ + int i; + int j; + char fn[3][100]; + int result; + + sprintf(fn[0],"%s/%s",path,"f0"); + sprintf(fn[1],"%s/%s",path,"f1"); + sprintf(fn[2],"%s/%s",path,"f2"); + + yaffs_StartUp(); + + for(i = 0; i < niterations; i++) + { + printf("\n*****************\nIteration %d\n",i); + yaffs_mount(path); + printf("\nmount: Directory look-up of %s\n",path); + dumpDir(path); + for(j = 0; j < 3; j++) + { + result = dump_file_data(fn[j]); + result = check_pattern_file(fn[j]); + make_pattern_file(fn[j],fsize); + result = dump_file_data(fn[j]); + result = check_pattern_file(fn[j]); + } + yaffs_unmount(path); + } +} + +void fill_disk(char *path,int nfiles) +{ + int h; + int n; + int result; + int f; + + char str[50]; + + for(n = 0; n < nfiles; n++) + { + sprintf(str,"%s/%d",path,n); + + h = yaffs_open(str, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); + + printf("writing file %s handle %d ",str, h); + + while ((result = yaffs_write(h,xx,600)) == 600) + { + f = yaffs_freespace(path); + } + result = yaffs_close(h); + printf(" close %d\n",result); + } +} + +void fill_disk_and_delete(char *path, int nfiles, int ncycles) +{ + int i,j; + char str[50]; + int result; + + for(i = 0; i < ncycles; i++) + { + printf("@@@@@@@@@@@@@@ cycle %d\n",i); + fill_disk(path,nfiles); + + for(j = 0; j < nfiles; j++) + { + sprintf(str,"%s/%d",path,j); + result = yaffs_unlink(str); + printf("unlinking file %s, result %d\n",str,result); + } + } +} + + +void fill_files(char *path,int flags, int maxIterations,int siz) +{ + int i; + int j; + char str[50]; + int h; + + i = 0; + + do{ + sprintf(str,"%s/%d",path,i); + h = yaffs_open(str, O_CREAT | O_TRUNC | O_RDWR,S_IREAD | S_IWRITE); + yaffs_close(h); + + if(h >= 0) + { + for(j = 0; j < siz; j++) + { + yaffs_write(h,str,1); + } + } + + if( flags & 1) + { + yaffs_unlink(str); + } + i++; + } while(h >= 0 && i < maxIterations); + + if(flags & 2) + { + i = 0; + do{ + sprintf(str,"%s/%d",path,i); + printf("unlink %s\n",str); + i++; + } while(yaffs_unlink(str) >= 0); + } +} + +void leave_unlinked_file(char *path,int maxIterations,int siz) +{ + int i; + char str[50]; + int h; + + i = 0; + + do{ + sprintf(str,"%s/%d",path,i); + printf("create %s\n",str); + h = yaffs_open(str, O_CREAT | O_TRUNC | O_RDWR,S_IREAD | S_IWRITE); + if(h >= 0) + { + yaffs_unlink(str); + } + i++; + } while(h < 0 && i < maxIterations); + + if(h >= 0) + { + for(i = 0; i < siz; i++) + { + yaffs_write(h,str,1); + } + } + + printf("Leaving file %s open\n",str); + +} + +void dumpDirFollow(const char *dname) +{ + yaffs_DIR *d; + yaffs_dirent *de; + struct yaffs_stat s; + char str[100]; + + d = yaffs_opendir(dname); + + if(!d) + { + printf("opendir failed\n"); + } + else + { + while((de = yaffs_readdir(d)) != NULL) + { + sprintf(str,"%s/%s",dname,de->d_name); + + yaffs_stat(str,&s); + + printf("%s length %d mode %X ",de->d_name,(int)s.st_size,s.st_mode); + switch(s.st_mode & S_IFMT) + { + case S_IFREG: printf("data file"); break; + case S_IFDIR: printf("directory"); break; + case S_IFLNK: printf("symlink -->"); + if(yaffs_readlink(str,str,100) < 0) + printf("no alias"); + else + printf("\"%s\"",str); + break; + default: printf("unknown"); break; + } + + printf("\n"); + } + + yaffs_closedir(d); + } + printf("\n"); + + printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname)); + +} + + +void dump_directory_tree_worker(const char *dname,int recursive) +{ + yaffs_DIR *d; + yaffs_dirent *de; + struct yaffs_stat s; + char str[1000]; + + d = yaffs_opendir(dname); + + if(!d) + { + printf("opendir failed\n"); + } + else + { + while((de = yaffs_readdir(d)) != NULL) + { + sprintf(str,"%s/%s",dname,de->d_name); + + yaffs_lstat(str,&s); + + printf("%s inode %d obj %x length %d mode %X ",str,s.st_ino,de->d_dont_use,(int)s.st_size,s.st_mode); + switch(s.st_mode & S_IFMT) + { + case S_IFREG: printf("data file"); break; + case S_IFDIR: printf("directory"); break; + case S_IFLNK: printf("symlink -->"); + if(yaffs_readlink(str,str,100) < 0) + printf("no alias"); + else + printf("\"%s\"",str); + break; + default: printf("unknown"); break; + } + + printf("\n"); + + if((s.st_mode & S_IFMT) == S_IFDIR && recursive) + dump_directory_tree_worker(str,1); + + } + + yaffs_closedir(d); + } + +} + +static void dump_directory_tree(const char *dname) +{ + dump_directory_tree_worker(dname,1); + printf("\n"); + printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname)); +} + +void dumpDir(const char *dname) +{ dump_directory_tree_worker(dname,0); + printf("\n"); + printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname)); +} + + +static void PermissionsCheck(const char *path, mode_t tmode, int tflags,int expectedResult) +{ + int fd; + + if(yaffs_chmod(path,tmode)< 0) printf("chmod failed\n"); + + fd = yaffs_open(path,tflags,0); + + if((fd >= 0) != (expectedResult > 0)) + { + printf("Permissions check %x %x %d failed\n",tmode,tflags,expectedResult); + } + else + { + printf("Permissions check %x %x %d OK\n",tmode,tflags,expectedResult); + } + + + yaffs_close(fd); + + +} + +int long_test(int argc, char *argv[]) +{ + + int f; + int r; + char buffer[20]; + + char str[100]; + + int h; + mode_t temp_mode; + struct yaffs_stat ystat; + + yaffs_StartUp(); + + yaffs_mount("/boot"); + yaffs_mount("/data"); + yaffs_mount("/flash"); + yaffs_mount("/ram"); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /data\n"); + dumpDir("/data"); + printf("\nDirectory look-up of /flash\n"); + dumpDir("/flash"); + + //leave_unlinked_file("/flash",20000,0); + //leave_unlinked_file("/data",20000,0); + + leave_unlinked_file("/ram",20,0); + + + f = yaffs_open("/boot/b1", O_RDONLY,0); + + printf("open /boot/b1 readonly, f=%d\n",f); + + f = yaffs_open("/boot/b1", O_CREAT,S_IREAD | S_IWRITE); + + printf("open /boot/b1 O_CREAT, f=%d\n",f); + + + r = yaffs_write(f,"hello",1); + printf("write %d attempted to write to a read-only file\n",r); + + r = yaffs_close(f); + + printf("close %d\n",r); + + f = yaffs_open("/boot/b1", O_RDWR,0); + + printf("open /boot/b1 O_RDWR,f=%d\n",f); + + + r = yaffs_write(f,"hello",2); + printf("write %d attempted to write to a writeable file\n",r); + r = yaffs_write(f,"world",3); + printf("write %d attempted to write to a writeable file\n",r); + + r= yaffs_lseek(f,0,SEEK_END); + printf("seek end %d\n",r); + memset(buffer,0,20); + r = yaffs_read(f,buffer,10); + printf("read %d \"%s\"\n",r,buffer); + r= yaffs_lseek(f,0,SEEK_SET); + printf("seek set %d\n",r); + memset(buffer,0,20); + r = yaffs_read(f,buffer,10); + printf("read %d \"%s\"\n",r,buffer); + memset(buffer,0,20); + r = yaffs_read(f,buffer,10); + printf("read %d \"%s\"\n",r,buffer); + + // Check values reading at end. + // A read past end of file should return 0 for 0 bytes read. + + r= yaffs_lseek(f,0,SEEK_END); + r = yaffs_read(f,buffer,10); + printf("read at end returned %d\n",r); + r= yaffs_lseek(f,500,SEEK_END); + r = yaffs_read(f,buffer,10); + printf("read past end returned %d\n",r); + + r = yaffs_close(f); + + printf("close %d\n",r); + + copy_in_a_file("/boot/yyfile","xxx"); + + // Create a file with a long name + + copy_in_a_file("/boot/file with a long name","xxx"); + + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + // Check stat + r = yaffs_stat("/boot/file with a long name",&ystat); + + // Check rename + + r = yaffs_rename("/boot/file with a long name","/boot/r1"); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + // Check unlink + r = yaffs_unlink("/boot/r1"); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + // Check mkdir + + r = yaffs_mkdir("/boot/directory1",0); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /boot/directory1\n"); + dumpDir("/boot/directory1"); + + // add a file to the directory + copy_in_a_file("/boot/directory1/file with a long name","xxx"); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /boot/directory1\n"); + dumpDir("/boot/directory1"); + + // Attempt to delete directory (should fail) + + r = yaffs_rmdir("/boot/directory1"); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /boot/directory1\n"); + dumpDir("/boot/directory1"); + + // Delete file first, then rmdir should work + r = yaffs_unlink("/boot/directory1/file with a long name"); + r = yaffs_rmdir("/boot/directory1"); + + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /boot/directory1\n"); + dumpDir("/boot/directory1"); + +#if 0 + fill_disk_and_delete("/boot",20,20); + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); +#endif + + yaffs_symlink("yyfile","/boot/slink"); + + yaffs_readlink("/boot/slink",str,100); + printf("symlink alias is %s\n",str); + + + + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + printf("\nDirectory look-up of /boot (using stat instead of lstat)\n"); + dumpDirFollow("/boot"); + printf("\nDirectory look-up of /boot/directory1\n"); + dumpDir("/boot/directory1"); + + h = yaffs_open("/boot/slink",O_RDWR,0); + + printf("file length is %d\n",(int)yaffs_lseek(h,0,SEEK_END)); + + yaffs_close(h); + + yaffs_unlink("/boot/slink"); + + + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + // Check chmod + + yaffs_stat("/boot/yyfile",&ystat); + temp_mode = ystat.st_mode; + + yaffs_chmod("/boot/yyfile",0x55555); + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + yaffs_chmod("/boot/yyfile",temp_mode); + printf("\nDirectory look-up of /boot\n"); + dumpDir("/boot"); + + // Permission checks... + PermissionsCheck("/boot/yyfile",0, O_WRONLY,0); + PermissionsCheck("/boot/yyfile",0, O_RDONLY,0); + PermissionsCheck("/boot/yyfile",0, O_RDWR,0); + + PermissionsCheck("/boot/yyfile",S_IREAD, O_WRONLY,0); + PermissionsCheck("/boot/yyfile",S_IREAD, O_RDONLY,1); + PermissionsCheck("/boot/yyfile",S_IREAD, O_RDWR,0); + + PermissionsCheck("/boot/yyfile",S_IWRITE, O_WRONLY,1); + PermissionsCheck("/boot/yyfile",S_IWRITE, O_RDONLY,0); + PermissionsCheck("/boot/yyfile",S_IWRITE, O_RDWR,0); + + PermissionsCheck("/boot/yyfile",S_IREAD | S_IWRITE, O_WRONLY,1); + PermissionsCheck("/boot/yyfile",S_IREAD | S_IWRITE, O_RDONLY,1); + PermissionsCheck("/boot/yyfile",S_IREAD | S_IWRITE, O_RDWR,1); + + yaffs_chmod("/boot/yyfile",temp_mode); + + //create a zero-length file and unlink it (test for scan bug) + + h = yaffs_open("/boot/zlf",O_CREAT | O_TRUNC | O_RDWR,0); + yaffs_close(h); + + yaffs_unlink("/boot/zlf"); + + + yaffs_DumpDevStruct("/boot"); + + fill_disk_and_delete("/boot",20,20); + + yaffs_DumpDevStruct("/boot"); + + fill_files("/boot",1,10000,0); + fill_files("/boot",1,10000,5000); + fill_files("/boot",2,10000,0); + fill_files("/boot",2,10000,5000); + + leave_unlinked_file("/data",20000,0); + leave_unlinked_file("/data",20000,5000); + leave_unlinked_file("/data",20000,5000); + leave_unlinked_file("/data",20000,5000); + leave_unlinked_file("/data",20000,5000); + leave_unlinked_file("/data",20000,5000); + + yaffs_DumpDevStruct("/boot"); + yaffs_DumpDevStruct("/data"); + + + + return 0; + +} + +int huge_directory_test_on_path(char *path) +{ + + yaffs_DIR *d; + yaffs_dirent *de; + struct yaffs_stat s; + + int f; + int i; + int r; + int total = 0; + int lastTotal = 0; + char buffer[20]; + + char str[100]; + char name[100]; + char name2[100]; + + int h; + mode_t temp_mode; + struct yaffs_stat ystat; + + yaffs_StartUp(); + + yaffs_mount(path); + + // Create a large number of files + + for(i = 0; i < 2000; i++) + { + sprintf(str,"%s/%d",path,i); + + f = yaffs_open(str,O_CREAT,S_IREAD | S_IWRITE); + yaffs_close(f); + } + + + + d = yaffs_opendir(path); + i = 0; + if (d) { + while((de = yaffs_readdir(d)) != NULL) { + if (total >lastTotal+100*9*1024||(i & 1023)==0){ + printf("files = %d, total = %d\n",i, total); + lastTotal = total; + } + i++; + sprintf(str,"%s/%s",path,de->d_name); + yaffs_lstat(str,&s); + switch(s.st_mode & S_IFMT){ + case S_IFREG: + //printf("data file"); + total += s.st_size; + break; + } + } + + yaffs_closedir(d); + } + + return 0; +} + +int yaffs_scan_test(const char *path) +{ +} + + +void rename_over_test(const char *mountpt) +{ + int i; + char a[100]; + char b[100]; + + sprintf(a,"%s/a",mountpt); + sprintf(b,"%s/b",mountpt); + + yaffs_StartUp(); + + yaffs_mount(mountpt); + i = yaffs_open(a,O_CREAT | O_TRUNC | O_RDWR, 0); + yaffs_close(i); + i = yaffs_open(b,O_CREAT | O_TRUNC | O_RDWR, 0); + yaffs_close(i); + yaffs_rename(a,b); // rename over + yaffs_rename(b,a); // rename back again (not renaimng over) + yaffs_rename(a,b); // rename back again (not renaimng over) + + + yaffs_unmount(mountpt); + +} + +int resize_stress_test(const char *path) +{ + int a,b,i,j; + int x; + int r; + char aname[100]; + char bname[100]; + + char abuffer[1000]; + char bbuffer[1000]; + + yaffs_StartUp(); + + yaffs_mount(path); + + sprintf(aname,"%s%s",path,"/a"); + sprintf(bname,"%s%s",path,"/b"); + + memset(abuffer,'a',1000); + memset(bbuffer,'b',1000); + + a = yaffs_open(aname, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + b = yaffs_open(bname, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + + printf(" %s %d %s %d\n",aname,a,bname,b); + + x = 0; + + for(j = 0; j < 100; j++) + { + yaffs_lseek(a,0,SEEK_END); + + + for(i = 0; i <20000; i++) + { + //r = yaffs_lseek(b,i,SEEK_SET); + //r = yaffs_write(b,bbuffer,1000); + + if(x & 0x16) + { + // shrink + int syz = yaffs_lseek(a,0,SEEK_END); + + syz -= 500; + if(syz < 0) syz = 0; + yaffs_truncate(a,syz); + + } + else + { + //expand + r = yaffs_lseek(a,i * 500,SEEK_SET); + r = yaffs_write(a,abuffer,1000); + } + x++; + + } + } + + return 0; + +} + + +int resize_stress_test_no_grow_complex(const char *path,int iters) +{ + int a,b,i,j; + int x; + int r; + char aname[100]; + char bname[100]; + + char abuffer[1000]; + char bbuffer[1000]; + + yaffs_StartUp(); + + yaffs_mount(path); + + sprintf(aname,"%s%s",path,"/a"); + sprintf(bname,"%s%s",path,"/b"); + + memset(abuffer,'a',1000); + memset(bbuffer,'b',1000); + + a = yaffs_open(aname, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + b = yaffs_open(bname, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + + printf(" %s %d %s %d\n",aname,a,bname,b); + + x = 0; + + for(j = 0; j < iters; j++) + { + yaffs_lseek(a,0,SEEK_END); + + + for(i = 0; i <20000; i++) + { + //r = yaffs_lseek(b,i,SEEK_SET); + //r = yaffs_write(b,bbuffer,1000); + + if(!(x%20)) + { + // shrink + int syz = yaffs_lseek(a,0,SEEK_END); + + while(syz > 4000) + { + + syz -= 2050; + if(syz < 0) syz = 0; + yaffs_truncate(a,syz); + syz = yaffs_lseek(a,0,SEEK_END); + printf("shrink to %d\n",syz); + } + + + } + else + { + //expand + r = yaffs_lseek(a,500,SEEK_END); + r = yaffs_write(a,abuffer,1000); + } + x++; + + + } + printf("file size is %d\n",yaffs_lseek(a,0,SEEK_END)); + + } + + return 0; + +} + +int resize_stress_test_no_grow(const char *path,int iters) +{ + int a,b,i,j; + int x; + int r; + char aname[100]; + char bname[100]; + + char abuffer[1000]; + char bbuffer[1000]; + + yaffs_StartUp(); + + yaffs_mount(path); + + sprintf(aname,"%s%s",path,"/a"); + sprintf(bname,"%s%s",path,"/b"); + + memset(abuffer,'a',1000); + memset(bbuffer,'b',1000); + + a = yaffs_open(aname, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + b = yaffs_open(bname, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + + printf(" %s %d %s %d\n",aname,a,bname,b); + + x = 0; + + for(j = 0; j < iters; j++) + { + yaffs_lseek(a,0,SEEK_END); + + + for(i = 0; i <20000; i++) + { + //r = yaffs_lseek(b,i,SEEK_SET); + //r = yaffs_write(b,bbuffer,1000); + + if(!(x%20)) + { + // shrink + int syz = yaffs_lseek(a,0,SEEK_END); + + while(syz > 4000) + { + + syz -= 2050; + if(syz < 0) syz = 0; + yaffs_truncate(a,syz); + syz = yaffs_lseek(a,0,SEEK_END); + printf("shrink to %d\n",syz); + } + + + } + else + { + //expand + r = yaffs_lseek(a,-500,SEEK_END); + r = yaffs_write(a,abuffer,1000); + } + x++; + + + } + printf("file size is %d\n",yaffs_lseek(a,0,SEEK_END)); + + } + + return 0; + +} + +int directory_rename_test(void) +{ + int r; + yaffs_StartUp(); + + yaffs_mount("/ram"); + yaffs_mkdir("/ram/a",0); + yaffs_mkdir("/ram/a/b",0); + yaffs_mkdir("/ram/c",0); + + printf("\nDirectory look-up of /ram\n"); + dumpDir("/ram"); + dumpDir("/ram/a"); + dumpDir("/ram/a/b"); + + printf("Do rename (should fail)\n"); + + r = yaffs_rename("/ram/a","/ram/a/b/d"); + printf("\nDirectory look-up of /ram\n"); + dumpDir("/ram"); + dumpDir("/ram/a"); + dumpDir("/ram/a/b"); + + printf("Do rename (should not fail)\n"); + + r = yaffs_rename("/ram/c","/ram/a/b/d"); + printf("\nDirectory look-up of /ram\n"); + dumpDir("/ram"); + dumpDir("/ram/a"); + dumpDir("/ram/a/b"); + + + return 1; + +} + +int cache_read_test(void) +{ + int a,b,c; + int i; + int sizeOfFiles = 500000; + char buffer[100]; + + yaffs_StartUp(); + + yaffs_mount("/boot"); + + make_a_file("/boot/a",'a',sizeOfFiles); + make_a_file("/boot/b",'b',sizeOfFiles); + + a = yaffs_open("/boot/a",O_RDONLY,0); + b = yaffs_open("/boot/b",O_RDONLY,0); + c = yaffs_open("/boot/c", O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); + + do{ + i = sizeOfFiles; + if (i > 100) i = 100; + sizeOfFiles -= i; + yaffs_read(a,buffer,i); + yaffs_read(b,buffer,i); + yaffs_write(c,buffer,i); + } while(sizeOfFiles > 0); + + + + return 1; + +} + +int cache_bypass_bug_test(void) +{ + // This test reporoduces a bug whereby YAFFS caching *was* buypassed + // resulting in erroneous reads after writes. + // This bug has been fixed. + + int a; + int i; + char buffer1[1000]; + char buffer2[1000]; + + memset(buffer1,0,sizeof(buffer1)); + memset(buffer2,0,sizeof(buffer2)); + + yaffs_StartUp(); + + yaffs_mount("/boot"); + + // Create a file of 2000 bytes. + make_a_file("/boot/a",'X',2000); + + a = yaffs_open("/boot/a",O_RDWR, S_IREAD | S_IWRITE); + + // Write a short sequence to the file. + // This will go into the cache. + yaffs_lseek(a,0,SEEK_SET); + yaffs_write(a,"abcdefghijklmnopqrstuvwxyz",20); + + // Read a short sequence from the file. + // This will come from the cache. + yaffs_lseek(a,0,SEEK_SET); + yaffs_read(a,buffer1,30); + + // Read a page size sequence from the file. + yaffs_lseek(a,0,SEEK_SET); + yaffs_read(a,buffer2,512); + + printf("buffer 1 %s\n",buffer1); + printf("buffer 2 %s\n",buffer2); + + if(strncmp(buffer1,buffer2,20)) + { + printf("Cache bypass bug detected!!!!!\n"); + } + + + return 1; +} + + +int free_space_check(void) +{ + int f; + + yaffs_StartUp(); + yaffs_mount("/boot"); + fill_disk("/boot/",2); + f = yaffs_freespace("/boot"); + + printf("%d free when disk full\n",f); + return 1; +} + +int truncate_test(void) +{ + int a; + int r; + int i; + int l; + + char y[10]; + + yaffs_StartUp(); + yaffs_mount("/boot"); + + yaffs_unlink("/boot/trunctest"); + + a = yaffs_open("/boot/trunctest", O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + + yaffs_write(a,"abcdefghijklmnopqrstuvwzyz",26); + + yaffs_truncate(a,3); + l= yaffs_lseek(a,0,SEEK_END); + + printf("truncated length is %d\n",l); + + yaffs_lseek(a,5,SEEK_SET); + yaffs_write(a,"1",1); + + yaffs_lseek(a,0,SEEK_SET); + + r = yaffs_read(a,y,10); + + printf("read %d bytes:",r); + + for(i = 0; i < r; i++) printf("[%02X]",y[i]); + + printf("\n"); + + return 0; + +} + + + + + +void fill_disk_test(const char *mountpt) +{ + int i; + yaffs_StartUp(); + + for(i = 0; i < 5; i++) + { + yaffs_mount(mountpt); + fill_disk_and_delete(mountpt,100,i+1); + yaffs_unmount(mountpt); + } + +} + + + +void lookup_test(const char *mountpt) +{ + int i; + int h; + char a[100]; + char b[100]; + + + yaffs_DIR *d; + yaffs_dirent *de; + struct yaffs_stat s; + char str[100]; + + yaffs_StartUp(); + + yaffs_mount(mountpt); + + d = yaffs_opendir(mountpt); + + if(!d) + { + printf("opendir failed\n"); + } + else + { + + for(i = 0; (de = yaffs_readdir(d)) != NULL; i++) + { + printf("unlinking %s\n",de->d_name); + yaffs_unlink(de->d_name); + } + + printf("%d files deleted\n",i); + } + + + for(i = 0; i < 2000; i++){ + sprintf(a,"%s/%d",mountpt,i); + h = yaffs_open(a,O_CREAT | O_TRUNC | O_RDWR, 0); + yaffs_close(h); + } + + yaffs_rewinddir(d); + for(i = 0; (de = yaffs_readdir(d)) != NULL; i++) + { + printf("%d %s\n",i,de->d_name); + } + + printf("%d files listed\n\n\n",i); + + yaffs_rewinddir(d); + yaffs_readdir(d); + yaffs_readdir(d); + yaffs_readdir(d); + + for(i = 0; i < 2000; i++){ + sprintf(a,"%s/%d",mountpt,i); + yaffs_unlink(a); + } + + + yaffs_unmount(mountpt); + +} + +void link_test(const char *mountpt) +{ + int i; + int h; + char a[100]; + char b[100]; + char c[100]; + + int f0; + int f1; + int f2; + int f3; + sprintf(a,"%s/aaa",mountpt); + sprintf(b,"%s/bbb",mountpt); + sprintf(c,"%s/ccc",mountpt); + + yaffs_StartUp(); + + yaffs_mount(mountpt); + + + h = yaffs_open(a, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + for(i = 0; i < 100; i++) + yaffs_write(h,a,100); + + yaffs_close(h); + + yaffs_unlink(b); + yaffs_unlink(c); + yaffs_link(a,b); + yaffs_link(a,c); + yaffs_unlink(b); + yaffs_unlink(c); + yaffs_unlink(a); + + + yaffs_unmount(mountpt); + yaffs_mount(mountpt); + + printf("link test done\n"); + +} + +void freespace_test(const char *mountpt) +{ + int i; + int h; + char a[100]; + char b[100]; + + int f0; + int f1; + int f2; + int f3; + sprintf(a,"%s/aaa",mountpt); + + yaffs_StartUp(); + + yaffs_mount(mountpt); + + f0 = yaffs_freespace(mountpt); + + h = yaffs_open(a, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + + for(i = 0; i < 100; i++) + yaffs_write(h,a,100); + + yaffs_close(h); + + f1 = yaffs_freespace(mountpt); + + yaffs_unlink(a); + + f2 = yaffs_freespace(mountpt); + + + yaffs_unmount(mountpt); + yaffs_mount(mountpt); + + f3 = yaffs_freespace(mountpt); + + printf("%d\n%d\n%d\n%d\n",f0, f1,f2,f3); + + +} + +void simple_rw_test(const char *mountpt) +{ + int i; + int h; + char a[100]; + + int x; + int result; + + sprintf(a,"%s/aaa",mountpt); + + yaffs_StartUp(); + + yaffs_mount(mountpt); + + yaffs_unlink(a); + + h = yaffs_open(a,O_CREAT| O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + + for(i = 100000;i < 200000; i++){ + result = yaffs_write(h,&i,sizeof(i)); + + if(result != 4) + { + printf("write error\n"); + exit(1); + } + } + + //yaffs_close(h); + + // h = yaffs_open(a,O_RDWR, S_IREAD | S_IWRITE); + + + yaffs_lseek(h,0,SEEK_SET); + + for(i = 100000; i < 200000; i++){ + result = yaffs_read(h,&x,sizeof(x)); + + if(result != 4 || x != i){ + printf("read error %d %x %x\n",i,result,x); + } + } + + printf("Simple rw test passed\n"); + + + +} + + +void scan_deleted_files_test(const char *mountpt) +{ + char fn[100]; + char sub[100]; + + const char *p; + + int i; + int j; + int k; + int h; + + sprintf(sub,"%s/sdir",mountpt); + yaffs_StartUp(); + + for(j = 0; j < 10; j++) + { + printf("\n\n>>>>>>> Run %d <<<<<<<<<<<<<\n\n",j); + yaffs_mount(mountpt); + yaffs_mkdir(sub,0); + + + p = (j & 0) ? mountpt: sub; + + for(i = 0; i < 100; i++) + { + sprintf(fn,"%s/%d",p,i); + + if(i & 1) + { + h = yaffs_open(fn,O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + for(k = 0; k < 1000; k++) + yaffs_write(h,fn,100); + yaffs_close(h); + } + else + yaffs_mkdir(fn,0); + } + + for(i = 0; i < 10; i++) + { + sprintf(fn,"%s/%d",p,i); + if(i & 1) + yaffs_unlink(fn); + else + yaffs_rmdir(fn); + + } + + yaffs_unmount(mountpt); + } + + + + +} + + +void write_10k(int h) +{ + int i; + const char *s="0123456789"; + for(i = 0; i < 1000; i++) + yaffs_write(h,s,10); + +} +void write_200k_file(const char *fn, const char *fdel, const char *fdel1) +{ + int h1; + int i; + int offs; + + h1 = yaffs_open(fn, O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + + for(i = 0; i < 100000; i+= 10000) + { + write_10k(h1); + } + + offs = yaffs_lseek(h1,0,SEEK_CUR); + if( offs != 100000) + { + printf("Could not write file\n"); + } + + yaffs_unlink(fdel); + for(i = 0; i < 100000; i+= 10000) + { + write_10k(h1); + } + + offs = yaffs_lseek(h1,0,SEEK_CUR); + if( offs != 200000) + { + printf("Could not write file\n"); + } + + yaffs_close(h1); + yaffs_unlink(fdel1); + +} + + +void verify_200k_file(const char *fn) +{ + int h1; + int i; + char x[11]; + const char *s="0123456789"; + int errCount = 0; + + h1 = yaffs_open(fn, O_RDONLY, 0); + + for(i = 0; i < 200000 && errCount < 10; i+= 10) + { + yaffs_read(h1,x,10); + if(strncmp(x,s,10) != 0) + { + printf("File %s verification failed at %d\n",fn,i); + errCount++; + } + } + if(errCount >= 10) + printf("Too many errors... aborted\n"); + + yaffs_close(h1); + +} + + +void check_resize_gc_bug(const char *mountpt) +{ + + char a[30]; + char b[30]; + char c[30]; + + int i; + + sprintf(a,"%s/a",mountpt); + sprintf(b,"%s/b",mountpt); + sprintf(c,"%s/c",mountpt); + + + + + yaffs_StartUp(); + yaffs_mount(mountpt); + yaffs_unlink(a); + yaffs_unlink(b); + + for(i = 0; i < 50; i++) + { + printf("A\n");write_200k_file(a,"",c); + printf("B\n");verify_200k_file(a); + printf("C\n");write_200k_file(b,a,c); + printf("D\n");verify_200k_file(b); + yaffs_unmount(mountpt); + yaffs_mount(mountpt); + printf("E\n");verify_200k_file(a); + printf("F\n");verify_200k_file(b); + } + +} + + +void multi_mount_test(const char *mountpt,int nmounts) +{ + + char a[30]; + char b[30]; + char c[30]; + + int i; + int j; + + sprintf(a,"%s/a",mountpt); + + yaffs_StartUp(); + + for(i = 0; i < nmounts; i++){ + int h0; + int h1; + int len0; + int len1; + + static char xx[1000]; + + printf("############### Iteration %d Start\n",i); + if(1 || i == 0 || i == 5) + yaffs_mount(mountpt); + + dump_directory_tree(mountpt); + + + yaffs_mkdir(a,0); + + sprintf(xx,"%s/0",a); + h0 = yaffs_open(xx, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); + + sprintf(xx,"%s/1",a); + h1 = yaffs_open(xx, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); + + for(j = 0; j < 200; j++){ + yaffs_write(h0,xx,1000); + yaffs_write(h1,xx,1000); + } + + len0 = yaffs_lseek(h0,0,SEEK_END); + len1 = yaffs_lseek(h1,0,SEEK_END); + + yaffs_lseek(h0,0,SEEK_SET); + yaffs_lseek(h1,0,SEEK_SET); + + for(j = 0; j < 200; j++){ + yaffs_read(h0,xx,1000); + yaffs_read(h1,xx,1000); + } + + + yaffs_truncate(h0,0); + yaffs_close(h0); + yaffs_close(h1); + + printf("########### %d\n",i); + dump_directory_tree(mountpt); + + if(1 || i == 4 || i == nmounts -1) + yaffs_unmount(mountpt); + } +} + + +void small_mount_test(const char *mountpt,int nmounts) +{ + + char a[30]; + char b[30]; + char c[30]; + + int i; + int j; + + int h0; + int h1; + int len0; + int len1; + int nread; + + sprintf(a,"%s/a",mountpt); + + yaffs_StartUp(); + + + + for(i = 0; i < nmounts; i++){ + + static char xx[1000]; + + printf("############### Iteration %d Start\n",i); + if(1 || i == 0 || i == 5) + yaffs_mount(mountpt); + + dump_directory_tree(mountpt); + + yaffs_mkdir(a,0); + + sprintf(xx,"%s/0",a); + if(i ==0){ + + h0 = yaffs_open(xx, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); + for(j = 0; j < 130; j++) + yaffs_write(h0,xx,1000); + yaffs_close(h0); + } + + h0 = yaffs_open(xx,O_RDONLY,0); + + sprintf(xx,"%s/1",a); + h1 = yaffs_open(xx, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); + + while((nread = yaffs_read(h0,xx,1000)) > 0) + yaffs_write(h1,xx,nread); + + + len0 = yaffs_lseek(h0,0,SEEK_END); + len1 = yaffs_lseek(h1,0,SEEK_END); + + yaffs_lseek(h0,0,SEEK_SET); + yaffs_lseek(h1,0,SEEK_SET); + + for(j = 0; j < 200; j++){ + yaffs_read(h0,xx,1000); + yaffs_read(h1,xx,1000); + } + + yaffs_close(h0); + yaffs_close(h1); + + printf("########### %d\n",i); + dump_directory_tree(mountpt); + + if(1 || i == 4 || i == nmounts -1) + yaffs_unmount(mountpt); + } +} + + +int early_exit; + +void small_overwrite_test(const char *mountpt,int nmounts) +{ + + char a[30]; + char b[30]; + char c[30]; + + int i; + int j; + + int h0; + int h1; + int len0; + int len1; + int nread; + + sprintf(a,"%s/a",mountpt); + + yaffs_StartUp(); + + + + for(i = 0; i < nmounts; i++){ + + static char xx[8000]; + + printf("############### Iteration %d Start\n",i); + if(1) + yaffs_mount(mountpt); + + dump_directory_tree(mountpt); + + yaffs_mkdir(a,0); + + sprintf(xx,"%s/0",a); + h0 = yaffs_open(xx, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); + sprintf(xx,"%s/1",a); + h1 = yaffs_open(xx, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); + + for(j = 0; j < 1000000; j+=1000){ + yaffs_truncate(h0,j); + yaffs_lseek(h0,j,SEEK_SET); + yaffs_write(h0,xx,7000); + yaffs_write(h1,xx,7000); + + if(early_exit) + exit(0); + } + + yaffs_close(h0); + + printf("########### %d\n",i); + dump_directory_tree(mountpt); + + if(1) + yaffs_unmount(mountpt); + } +} + + +void yaffs_touch(const char *fn) +{ + yaffs_chmod(fn, S_IREAD | S_IWRITE); +} + +void checkpoint_fill_test(const char *mountpt,int nmounts) +{ + + char a[50]; + char b[50]; + char c[50]; + + int i; + int j; + int h; + + sprintf(a,"%s/a",mountpt); + + + + + yaffs_StartUp(); + + for(i = 0; i < nmounts; i++){ + printf("############### Iteration %d Start\n",i); + yaffs_mount(mountpt); + dump_directory_tree(mountpt); + yaffs_mkdir(a,0); + + sprintf(b,"%s/zz",a); + + h = yaffs_open(b,O_CREAT | O_RDWR,S_IREAD |S_IWRITE); + + + while(yaffs_write(h,c,50) == 50){} + + yaffs_close(h); + + for(j = 0; j < 2; j++){ + printf("touch %d\n",j); + yaffs_touch(b); + yaffs_unmount(mountpt); + yaffs_mount(mountpt); + } + + dump_directory_tree(mountpt); + yaffs_unmount(mountpt); + } +} + + +int make_file2(const char *name1, const char *name2,int syz) +{ + + char xx[2500]; + int i; + int h1=-1,h2=-1; + int n = 1; + + + if(name1) + h1 = yaffs_open(name1,O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + if(name2) + h2 = yaffs_open(name2,O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); + + while(syz > 0 && n > 0){ + i = (syz > 2500) ? 2500 : syz; + n = yaffs_write(h1,xx,i); + n = yaffs_write(h2,xx,i); + syz -= 500; + } + yaffs_close(h1); + yaffs_close(h2); + +} + + +extern void SetCheckpointReservedBlocks(int n); + +void checkpoint_upgrade_test(const char *mountpt,int nmounts) +{ + + char a[50]; + char b[50]; + char c[50]; + char d[50]; + + int i; + int j; + int h; + + sprintf(a,"%s/a",mountpt); + + + + + printf("Create start condition\n"); + yaffs_StartUp(); + SetCheckpointReservedBlocks(0); + yaffs_mount(mountpt); + yaffs_mkdir(a,0); + sprintf(b,"%s/zz",a); + sprintf(c,"%s/xx",a); + make_file2(b,c,2000000); + sprintf(d,"%s/aa",a); + make_file2(d,NULL,500000000); + dump_directory_tree(mountpt); + + printf("Umount/mount attempt full\n"); + yaffs_unmount(mountpt); + + SetCheckpointReservedBlocks(10); + yaffs_mount(mountpt); + + printf("unlink small file\n"); + yaffs_unlink(c); + dump_directory_tree(mountpt); + + printf("Umount/mount attempt\n"); + yaffs_unmount(mountpt); + yaffs_mount(mountpt); + + for(j = 0; j < 500; j++){ + printf("***** touch %d\n",j); + dump_directory_tree(mountpt); + yaffs_touch(b); + yaffs_unmount(mountpt); + yaffs_mount(mountpt); + } + + for(j = 0; j < 500; j++){ + printf("***** touch %d\n",j); + dump_directory_tree(mountpt); + yaffs_touch(b); + yaffs_unmount(mountpt); + yaffs_mount(mountpt); + } +} + +void huge_array_test(const char *mountpt,int n) +{ + + char a[50]; + + + int i; + int j; + int h; + + int fnum; + + sprintf(a,"mount point %s",mountpt); + + + + yaffs_StartUp(); + + yaffs_mount(mountpt); + + while(n>0){ + n--; + fnum = 0; + printf("\n\n START run\n\n"); + while(yaffs_freespace(mountpt) > 25000000){ + sprintf(a,"%s/file%d",mountpt,fnum); + fnum++; + printf("create file %s\n",a); + create_file_of_size(a,10000000); + printf("verifying file %s\n",a); + verify_file_of_size(a,10000000); + } + + printf("\n\n verification/deletion\n\n"); + + for(i = 0; i < fnum; i++){ + sprintf(a,"%s/file%d",mountpt,i); + printf("verifying file %s\n",a); + verify_file_of_size(a,10000000); + printf("deleting file %s\n",a); + yaffs_unlink(a); + } + printf("\n\n done \n\n"); + + + } +} + + +void random_write(int h) +{ + static char buffer[12000]; + int n; + + n = random() & 0x1FFF; + yaffs_write(h,buffer,n); +} + +void random_seek(int h) +{ + int n; + n = random() & 0xFFFFF; + yaffs_lseek(h,n,SEEK_SET); +} + +void random_truncate(int h, char * name) +{ + int n; + int flen; + n = random() & 0xFFFFF; + flen = yaffs_lseek(h,0,SEEK_END); + if(n > flen) + n = flen / 2; + yaffs_truncate(name,n); + yaffs_lseek(h,n,SEEK_SET); +} + + +#define NSMALLFILES 10 +void random_small_file_test(const char *mountpt,int iterations) +{ + + char a[NSMALLFILES][50]; + + + int i; + int n; + int j; + int h[NSMALLFILES]; + int r; + int fnum; + + + yaffs_StartUp(); + + yaffs_mount(mountpt); + + for(i = 0; i < NSMALLFILES; i++){ + h[i]=-1; + strcpy(a[i],""); + } + + for(n = 0; n < iterations; n++){ + + for(i = 0; i < NSMALLFILES; i++) { + r = random(); + + if(strlen(a[i]) == 0){ + sprintf(a[i],"%s/%dx%d",mountpt,n,i); + h[i] = yaffs_open(a,O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); + } + + if(h[i] < -1) + printf("Could not open yaffs file %d %d error %d\n",n,i,h[i]); + else { + r = r & 7; + switch(r){ + case 0: + case 1: + case 2: + random_write(h[i]); + break; + case 3: + random_truncate(h[i],a[i]); + break; + case 4: + case 5: random_seek(h[i]); + break; + case 6: + yaffs_close(h[i]); + h[i] = -1; + break; + case 7: + yaffs_close(h[i]); + yaffs_unlink(a[i]); + strcpy(a[i],""); + h[i] = -1; + } + } + } + + } + + for(i = 0; i < NSMALLFILES; i++) + yaffs_close(h[i]); + + yaffs_unmount(mountpt); +} + + + +int main(int argc, char *argv[]) +{ + //return long_test(argc,argv); + + //return cache_read_test(); + + resize_stress_test_no_grow("/flash/flash",20); + + //huge_directory_test_on_path("/ram2k"); + + //yaffs_backward_scan_test("/flash/flash"); + // yaffs_device_flush_test("/flash/flash"); + + + //scan_pattern_test("/flash",10000,10); + //short_scan_test("/flash/flash",40000,200); + //small_mount_test("/flash/flash",1000); + //small_overwrite_test("/flash/flash",1000); + //checkpoint_fill_test("/flash/flash",20); + // random_small_file_test("/flash/flash",10000); + // huge_array_test("/flash/flash",10); + + + + + //long_test_on_path("/ram2k"); + // long_test_on_path("/flash"); + //simple_rw_test("/flash/flash"); + //fill_disk_test("/flash/flash"); + // rename_over_test("/flash"); + //lookup_test("/flash"); + //freespace_test("/flash/flash"); + + //link_test("/flash/flash"); + + + + + // cache_bypass_bug_test(); + + //free_space_check(); + + //check_resize_gc_bug("/flash"); + + return 0; + +} diff --git a/fs/yaffs2/direct/fsx_test/Makefile b/fs/yaffs2/direct/fsx_test/Makefile new file mode 100644 index 0000000000..1927865422 --- /dev/null +++ b/fs/yaffs2/direct/fsx_test/Makefile @@ -0,0 +1,75 @@ +# Makefile for YAFFS direct test +# +# +# YAFFS: Yet another Flash File System. A NAND-flash specific file system. +# +# Copyright (C) 2003 Aleph One Ltd. +# +# +# Created by Charles Manning <charles@aleph1.co.uk> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# NB Warning this Makefile does not include header dependencies. +# +# $Id: Makefile,v 1.1 2007/10/16 00:46:33 charles Exp $ + +#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC + +CFLAGS = -Wall -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -g $(EXTRA_COMPILE_FLAGS) -DNO_Y_INLINE +CFLAGS+= -fstack-check -O0 + +#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations +#CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline + + +FSXTESTOBJS = yaffs_fsx.o yaffscfg2k.o yaffs_ecc.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \ + yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \ + yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \ + yaffs_checkptrw.o yaffs_qsort.o \ +# yaffs_checkptrwtest.o\ + + +BOOTTESTOBJS = bootldtst.o yboot.o yaffs_fileem.o nand_ecc.o + +#ALLOBJS = dtest.o nand_ecc.o yaffscfg.o yaffs_fileem.o yaffsfs.o yaffs_ramdisk.o bootldtst.o yboot.o yaffs_ramem2k.o + +ALLOBJS = $(FSXTESTOBJS) $(BOOTTESTOBJS) + +YAFFSSYMLINKS = devextras.h yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h yaffsinterface.h yportenv.h yaffs_tagscompat.c yaffs_tagscompat.h \ + yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h yaffs_nandemul2k.h \ + yaffs_nand.c yaffs_nand.h \ + yaffs_tagsvalidity.c yaffs_tagsvalidity.h yaffs_checkptrw.h yaffs_checkptrw.c \ + yaffs_qsort.c yaffs_qsort.h + +YAFFSDIRECTSYMLINKS = yaffscfg2k.c yaffs_fileem2k.c yaffsfs.c yaffs_flashif.h \ + yaffs_fileem2k.h yaffsfs.h yaffs_malloc.h yaffs_ramdisk.h ydirectenv.h \ + yaffscfg.h yaffs_fileem.c yaffs_flashif.c yaffs_ramdisk.c yaffs_ramem2k.c + + + +#all: fsxtest boottest + +all: fsxtest + +$(ALLOBJS): %.o: %.c + gcc -c $(CFLAGS) $< -o $@ + +$(YAFFSSYMLINKS): + ln -s ../../$@ $@ + +$(YAFFSDIRECTSYMLINKS): + ln -s ../$@ $@ + +fsxtest: $(YAFFSSYMLINKS) $(YAFFSDIRECTSYMLINKS) $(FSXTESTOBJS) + gcc -o $@ $(FSXTESTOBJS) + + +boottest: $(SYMLINKS) $(BOOTTESTOBJS) + gcc -o $@ $(BOOTTESTOBJS) + + +clean: + rm -f $(ALLOBJS) core diff --git a/fs/yaffs2/direct/fsx_test/README b/fs/yaffs2/direct/fsx_test/README new file mode 100644 index 0000000000..725ab07558 --- /dev/null +++ b/fs/yaffs2/direct/fsx_test/README @@ -0,0 +1,7 @@ +NB THis directory uses a hacked version of fsx.c which is released under +Apple Public Source License. + +From what I have been able to determine, it is legally OK to release a hacked +version for the purposes of testing. + +If anyone knows otherwise, please contact me: manningc2@actrix.gen.nz diff --git a/fs/yaffs2/direct/fsx_test/yaffs_fsx.c b/fs/yaffs2/direct/fsx_test/yaffs_fsx.c new file mode 100644 index 0000000000..1e110b9b72 --- /dev/null +++ b/fs/yaffs2/direct/fsx_test/yaffs_fsx.c @@ -0,0 +1,1007 @@ +/* + * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.2 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + * + * WARNING--WARNING--WARNING + * This is not the original fsx.c. It has been modified to run with + * yaffs direct. Seek out the original fsx.c if you want to do anything + * else. + * + * + * + * File: fsx.c + * Author: Avadis Tevanian, Jr. + * + * File system exerciser. + * + * Rewrite and enhancements 1998-2001 Conrad Minshall -- conrad@mac.com + * + * Various features from Joe Sokol, Pat Dirks, and Clark Warner. + * + * Small changes to work under Linux -- davej@suse.de + * + * Sundry porting patches from Guy Harris 12/2001 + * + * Checks for mmap last-page zero fill. + * + * Modified heavily by Charles Manning to exercise via the + * yaffs direct interface. + * + */ + +#include <sys/types.h> +#include <sys/stat.h> +#ifdef _UWIN +# include <sys/param.h> +# include <limits.h> +# include <time.h> +# include <strings.h> +#endif +#include <fcntl.h> +#include <sys/mman.h> +#ifndef MAP_FILE +# define MAP_FILE 0 +#endif +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdarg.h> +#include <errno.h> + +#include "yaffsfs.h" + +#define NUMPRINTCOLUMNS 32 /* # columns of data to print on each line */ + +/* + * A log entry is an operation and a bunch of arguments. + */ + +struct log_entry { + int operation; + int args[3]; +}; + +#define LOGSIZE 1000 + +struct log_entry oplog[LOGSIZE]; /* the log */ +int logptr = 0; /* current position in log */ +int logcount = 0; /* total ops */ + +/* + * Define operations + */ + +#define OP_READ 1 +#define OP_WRITE 2 +#define OP_TRUNCATE 3 +#define OP_CLOSEOPEN 4 +#define OP_MAPREAD 5 +#define OP_MAPWRITE 6 +#define OP_SKIPPED 7 + +int page_size; +int page_mask; + +char *original_buf; /* a pointer to the original data */ +char *good_buf; /* a pointer to the correct data */ +char *temp_buf; /* a pointer to the current data */ +char *fname; /* name of our test file */ +int fd; /* fd for our test file */ + +off_t file_size = 0; +off_t biggest = 0; +char state[256]; +unsigned long testcalls = 0; /* calls to function "test" */ + +unsigned long simulatedopcount = 0; /* -b flag */ +int closeprob = 0; /* -c flag */ +int debug = 0; /* -d flag */ +unsigned long debugstart = 0; /* -D flag */ +unsigned long maxfilelen = 256 * 1024; /* -l flag */ +int sizechecks = 1; /* -n flag disables them */ +int maxoplen = 64 * 1024; /* -o flag */ +int quiet = 0; /* -q flag */ +unsigned long progressinterval = 0; /* -p flag */ +int readbdy = 1; /* -r flag */ +int style = 0; /* -s flag */ +int truncbdy = 1; /* -t flag */ +int writebdy = 1; /* -w flag */ +long monitorstart = -1; /* -m flag */ +long monitorend = -1; /* -m flag */ +int lite = 0; /* -L flag */ +long numops = -1; /* -N flag */ +int randomoplen = 1; /* -O flag disables it */ +int seed = 1; /* -S flag */ + +int mapped_writes = 0; /* yaffs direct does not support mmapped files */ +int mapped_reads = 0; + +int fsxgoodfd = 0; +FILE * fsxlogf = NULL; +int badoff = -1; +int closeopen = 0; + + +void +vwarnc(code, fmt, ap) + int code; + const char *fmt; + va_list ap; +{ + fprintf(stderr, "fsx: "); + if (fmt != NULL) { + vfprintf(stderr, fmt, ap); + fprintf(stderr, ": "); + } + fprintf(stderr, "%s\n", strerror(code)); +} + + +void +warn(const char * fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarnc(errno, fmt, ap); + va_end(ap); +} + + +void +prt(char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vfprintf(stdout, fmt, args); + if (fsxlogf) + vfprintf(fsxlogf, fmt, args); + va_end(args); +} + +void +prterr(char *prefix) +{ + prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno)); +} + + +void +log4(int operation, int arg0, int arg1, int arg2) +{ + struct log_entry *le; + + le = &oplog[logptr]; + le->operation = operation; + if (closeopen) + le->operation = ~ le->operation; + le->args[0] = arg0; + le->args[1] = arg1; + le->args[2] = arg2; + logptr++; + logcount++; + if (logptr >= LOGSIZE) + logptr = 0; +} + + +void +logdump(void) +{ + int i, count, down; + struct log_entry *lp; + + prt("LOG DUMP (%d total operations):\n", logcount); + if (logcount < LOGSIZE) { + i = 0; + count = logcount; + } else { + i = logptr; + count = LOGSIZE; + } + for ( ; count > 0; count--) { + int opnum; + + opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE; + prt("%d(%d mod 256): ", opnum, opnum%256); + lp = &oplog[i]; + if ((closeopen = lp->operation < 0)) + lp->operation = ~ lp->operation; + + switch (lp->operation) { + case OP_MAPREAD: + prt("MAPREAD\t0x%x thru 0x%x\t(0x%x bytes)", + lp->args[0], lp->args[0] + lp->args[1] - 1, + lp->args[1]); + if (badoff >= lp->args[0] && badoff < + lp->args[0] + lp->args[1]) + prt("\t***RRRR***"); + break; + case OP_MAPWRITE: + prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)", + lp->args[0], lp->args[0] + lp->args[1] - 1, + lp->args[1]); + if (badoff >= lp->args[0] && badoff < + lp->args[0] + lp->args[1]) + prt("\t******WWWW"); + break; + case OP_READ: + prt("READ\t0x%x thru 0x%x\t(0x%x bytes)", + lp->args[0], lp->args[0] + lp->args[1] - 1, + lp->args[1]); + if (badoff >= lp->args[0] && + badoff < lp->args[0] + lp->args[1]) + prt("\t***RRRR***"); + break; + case OP_WRITE: + prt("WRITE\t0x%x thru 0x%x\t(0x%x bytes)", + lp->args[0], lp->args[0] + lp->args[1] - 1, + lp->args[1]); + if (lp->args[0] > lp->args[2]) + prt(" HOLE"); + else if (lp->args[0] + lp->args[1] > lp->args[2]) + prt(" EXTEND"); + if ((badoff >= lp->args[0] || badoff >=lp->args[2]) && + badoff < lp->args[0] + lp->args[1]) + prt("\t***WWWW"); + break; + case OP_TRUNCATE: + down = lp->args[0] < lp->args[1]; + prt("TRUNCATE %s\tfrom 0x%x to 0x%x", + down ? "DOWN" : "UP", lp->args[1], lp->args[0]); + if (badoff >= lp->args[!down] && + badoff < lp->args[!!down]) + prt("\t******WWWW"); + break; + case OP_SKIPPED: + prt("SKIPPED (no operation)"); + break; + default: + prt("BOGUS LOG ENTRY (operation code = %d)!", + lp->operation); + } + if (closeopen) + prt("\n\t\tCLOSE/OPEN"); + prt("\n"); + i++; + if (i == LOGSIZE) + i = 0; + } +} + + +void +save_buffer(char *buffer, off_t bufferlength, int fd) +{ + off_t ret; + ssize_t byteswritten; + + if (fd <= 0 || bufferlength == 0) + return; + + if (bufferlength > SSIZE_MAX) { + prt("fsx flaw: overflow in save_buffer\n"); + exit(67); + } + if (lite) { + off_t size_by_seek = yaffs_lseek(fd, (off_t)0, SEEK_END); + if (size_by_seek == (off_t)-1) + prterr("save_buffer: lseek eof"); + else if (bufferlength > size_by_seek) { + warn("save_buffer: .fsxgood file too short... will save 0x%llx bytes instead of 0x%llx\n", (unsigned long long)size_by_seek, + (unsigned long long)bufferlength); + bufferlength = size_by_seek; + } + } + + ret = yaffs_lseek(fd, (off_t)0, SEEK_SET); + if (ret == (off_t)-1) + prterr("save_buffer: lseek 0"); + + byteswritten = yaffs_write(fd, buffer, (size_t)bufferlength); + if (byteswritten != bufferlength) { + if (byteswritten == -1) + prterr("save_buffer write"); + else + warn("save_buffer: short write, 0x%x bytes instead of 0x%llx\n", + (unsigned)byteswritten, + (unsigned long long)bufferlength); + } +} + + +void +report_failure(int status) +{ + logdump(); + + if (fsxgoodfd) { + if (good_buf) { + save_buffer(good_buf, file_size, fsxgoodfd); + prt("Correct content saved for comparison\n"); + prt("(maybe hexdump \"%s\" vs \"%s.fsxgood\")\n", + fname, fname); + } + close(fsxgoodfd); + } + prt("Exiting with %d\n",status); + exit(status); +} + + +#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \ + *(((unsigned char *)(cp)) + 1))) + +void +check_buffers(unsigned offset, unsigned size) +{ + unsigned char c, t; + unsigned i = 0; + unsigned n = 0; + unsigned op = 0; + unsigned bad = 0; + + if (memcmp(good_buf + offset, temp_buf, size) != 0) { + prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n", + offset, size); + prt("OFFSET\tGOOD\tBAD\tRANGE\n"); + while (size > 0) { + c = good_buf[offset]; + t = temp_buf[i]; + if (c != t) { + if (n == 0) { + bad = short_at(&temp_buf[i]); + prt("0x%5x\t0x%04x\t0x%04x", offset, + short_at(&good_buf[offset]), bad); + op = temp_buf[offset & 1 ? i+1 : i]; + } + n++; + badoff = offset; + } + offset++; + i++; + size--; + } + if (n) { + prt("\t0x%5x\n", n); + if (bad) + prt("operation# (mod 256) for the bad data may be %u\n", ((unsigned)op & 0xff)); + else + prt("operation# (mod 256) for the bad data unknown, check HOLE and EXTEND ops\n"); + } else + prt("????????????????\n"); + report_failure(110); + } +} + + +void +check_size(void) +{ + struct yaffs_stat statbuf; + off_t size_by_seek; + + if (yaffs_fstat(fd, &statbuf)) { + prterr("check_size: fstat"); + statbuf.st_size = -1; + } + size_by_seek = yaffs_lseek(fd, (off_t)0, SEEK_END); + if (file_size != statbuf.st_size || file_size != size_by_seek) { + prt("Size error: expected 0x%llx stat 0x%llx seek 0x%llx\n", + (unsigned long long)file_size, + (unsigned long long)statbuf.st_size, + (unsigned long long)size_by_seek); + report_failure(120); + } +} + + +void +check_trunc_hack(void) +{ + struct yaffs_stat statbuf; + + yaffs_truncate(fd, (off_t)0); + yaffs_truncate(fd, (off_t)100000); + yaffs_fstat(fd, &statbuf); + if (statbuf.st_size != (off_t)100000) { + prt("no extend on truncate! not posix!\n"); + exit(130); + } + yaffs_truncate(fd, (off_t)0); +} + + +void +doread(unsigned offset, unsigned size) +{ + off_t ret; + unsigned iret; + + offset -= offset % readbdy; + if (size == 0) { + if (!quiet && testcalls > simulatedopcount) + prt("skipping zero size read\n"); + log4(OP_SKIPPED, OP_READ, offset, size); + return; + } + if (size + offset > file_size) { + if (!quiet && testcalls > simulatedopcount) + prt("skipping seek/read past end of file\n"); + log4(OP_SKIPPED, OP_READ, offset, size); + return; + } + + log4(OP_READ, offset, size, 0); + + if (testcalls <= simulatedopcount) + return; + + if (!quiet && ((progressinterval && + testcalls % progressinterval == 0) || + (debug && + (monitorstart == -1 || + (offset + size > monitorstart && + (monitorend == -1 || offset <= monitorend)))))) + prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, + offset, offset + size - 1, size); + ret = yaffs_lseek(fd, (off_t)offset, SEEK_SET); + if (ret == (off_t)-1) { + prterr("doread: lseek"); + report_failure(140); + } + iret = yaffs_read(fd, temp_buf, size); + if (iret != size) { + if (iret == -1) + prterr("doread: read"); + else + prt("short read: 0x%x bytes instead of 0x%x\n", + iret, size); + report_failure(141); + } + check_buffers(offset, size); +} + + + + + +void +gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size) +{ + while (size--) { + good_buf[offset] = testcalls % 256; + if (offset % 2) + good_buf[offset] += original_buf[offset]; + offset++; + } +} + + +void +dowrite(unsigned offset, unsigned size) +{ + off_t ret; + unsigned iret; + + offset -= offset % writebdy; + if (size == 0) { + if (!quiet && testcalls > simulatedopcount) + prt("skipping zero size write\n"); + log4(OP_SKIPPED, OP_WRITE, offset, size); + return; + } + + log4(OP_WRITE, offset, size, file_size); + + gendata(original_buf, good_buf, offset, size); + if (file_size < offset + size) { + if (file_size < offset) + memset(good_buf + file_size, '\0', offset - file_size); + file_size = offset + size; + if (lite) { + warn("Lite file size bug in fsx!"); + report_failure(149); + } + } + + if (testcalls <= simulatedopcount) + return; + + if (!quiet && ((progressinterval && + testcalls % progressinterval == 0) || + (debug && + (monitorstart == -1 || + (offset + size > monitorstart && + (monitorend == -1 || offset <= monitorend)))))) + prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, + offset, offset + size - 1, size); + ret = yaffs_lseek(fd, (off_t)offset, SEEK_SET); + if (ret == (off_t)-1) { + prterr("dowrite: lseek"); + report_failure(150); + } + iret = yaffs_write(fd, good_buf + offset, size); + if (iret != size) { + if (iret == -1) + prterr("dowrite: write"); + else + prt("short write: 0x%x bytes instead of 0x%x\n", + iret, size); + report_failure(151); + } +} + + + +void +dotruncate(unsigned size) +{ + int oldsize = file_size; + + size -= size % truncbdy; + if (size > biggest) { + biggest = size; + if (!quiet && testcalls > simulatedopcount) + prt("truncating to largest ever: 0x%x\n", size); + } + + log4(OP_TRUNCATE, size, (unsigned)file_size, 0); + + if (size > file_size) + memset(good_buf + file_size, '\0', size - file_size); + file_size = size; + + if (testcalls <= simulatedopcount) + return; + + if ((progressinterval && testcalls % progressinterval == 0) || + (debug && (monitorstart == -1 || monitorend == -1 || + size <= monitorend))) + prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size); + if (yaffs_truncate(fd, (off_t)size) == -1) { + prt("ftruncate1: %x\n", size); + prterr("dotruncate: ftruncate"); + report_failure(160); + } +} + + +void +writefileimage() +{ + ssize_t iret; + + if (yaffs_lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { + prterr("writefileimage: lseek"); + report_failure(171); + } + iret = yaffs_write(fd, good_buf, file_size); + if ((off_t)iret != file_size) { + if (iret == -1) + prterr("writefileimage: write"); + else + prt("short write: 0x%x bytes instead of 0x%llx\n", + iret, (unsigned long long)file_size); + report_failure(172); + } + if (lite ? 0 : yaffs_truncate(fd, file_size) == -1) { + prt("ftruncate2: %llx\n", (unsigned long long)file_size); + prterr("writefileimage: ftruncate"); + report_failure(173); + } +} + + +void +docloseopen(void) +{ + if (testcalls <= simulatedopcount) + return; + + if (debug) + prt("%lu close/open\n", testcalls); + if (yaffs_close(fd)) { + prterr("docloseopen: close"); + report_failure(180); + } + fd = yaffs_open(fname, O_RDWR, 0); + if (fd < 0) { + prterr("docloseopen: open"); + report_failure(181); + } +} + + +void +test(void) +{ + unsigned long offset; + unsigned long size = maxoplen; + unsigned long rv = random(); + unsigned long op = rv % (3 + !lite + mapped_writes); + + /* turn off the map read if necessary */ + + if (op == 2 && !mapped_reads) + op = 0; + + if (simulatedopcount > 0 && testcalls == simulatedopcount) + writefileimage(); + + testcalls++; + + if (closeprob) + closeopen = (rv >> 3) < (1 << 28) / closeprob; + + if (debugstart > 0 && testcalls >= debugstart) + debug = 1; + + if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0) + prt("%lu...\n", testcalls); + + /* + * READ: op = 0 + * WRITE: op = 1 + * MAPREAD: op = 2 + * TRUNCATE: op = 3 + * MAPWRITE: op = 3 or 4 + */ + if (lite ? 0 : op == 3 && (style & 1) == 0) /* vanilla truncate? */ + dotruncate(random() % maxfilelen); + else { + if (randomoplen) + size = random() % (maxoplen+1); + if (lite ? 0 : op == 3) + dotruncate(size); + else { + offset = random(); + if (op == 1 || op == (lite ? 3 : 4)) { + offset %= maxfilelen; + if (offset + size > maxfilelen) + size = maxfilelen - offset; + dowrite(offset, size); + } else { + if (file_size) + offset %= file_size; + else + offset = 0; + if (offset + size > file_size) + size = file_size - offset; + doread(offset, size); + } + } + } + if (sizechecks && testcalls > simulatedopcount) + check_size(); + if (closeopen) + docloseopen(); +} + + +void +cleanup(sig) + int sig; +{ + if (sig) + prt("signal %d\n", sig); + prt("testcalls = %lu\n", testcalls); + exit(sig); +} + + +void +usage(void) +{ + fprintf(stdout, "usage: %s", + "fsx [-dnqLOW] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] fname\n\ + -b opnum: beginning operation number (default 1)\n\ + -c P: 1 in P chance of file close+open at each op (default infinity)\n\ + -d: debug output for all operations\n\ + -l flen: the upper bound on file size (default 262144)\n\ + -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\ + -n: no verifications of file size\n\ + -o oplen: the upper bound on operation size (default 65536)\n\ + -p progressinterval: debug output at specified operation interval\n\ + -q: quieter operation\n\ + -r readbdy: 4096 would make reads page aligned (default 1)\n\ + -s style: 1 gives smaller truncates (default 0)\n\ + -t truncbdy: 4096 would make truncates page aligned (default 1)\n\ + -w writebdy: 4096 would make writes page aligned (default 1)\n\ + -D startingop: debug output starting at specified operation\n\ + -L: fsxLite - no file creations & no file size changes\n\ + -N numops: total # operations to do (default infinity)\n\ + -O: use oplen (see -o flag) for every op (default random)\n\ + -P dirpath: save .fsxlog and .fsxgood files in dirpath (default ./)\n\ + -S seed: for random # generator (default 1) 0 gets timestamp\n\ + fname: this filename is REQUIRED (no default)\n"); + exit(90); +} + + +int +getnum(char *s, char **e) +{ + int ret = -1; + + *e = (char *) 0; + ret = strtol(s, e, 0); + if (*e) + switch (**e) { + case 'b': + case 'B': + ret *= 512; + *e = *e + 1; + break; + case 'k': + case 'K': + ret *= 1024; + *e = *e + 1; + break; + case 'm': + case 'M': + ret *= 1024*1024; + *e = *e + 1; + break; + case 'w': + case 'W': + ret *= 4; + *e = *e + 1; + break; + } + return (ret); +} + + +int +main(int argc, char **argv) +{ + int i, style, ch; + char *endp; + char goodfile[1024]; + char logfile[1024]; + + goodfile[0] = 0; + logfile[0] = 0; + + page_size = getpagesize(); + page_mask = page_size - 1; + + setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */ + + while ((ch = getopt(argc, argv, "b:c:dl:m:no:p:qr:s:t:w:D:LN:OP:RS:W")) + != EOF) + switch (ch) { + case 'b': + simulatedopcount = getnum(optarg, &endp); + if (!quiet) + fprintf(stdout, "Will begin at operation %ld\n", + simulatedopcount); + if (simulatedopcount == 0) + usage(); + simulatedopcount -= 1; + break; + case 'c': + closeprob = getnum(optarg, &endp); + if (!quiet) + fprintf(stdout, + "Chance of close/open is 1 in %d\n", + closeprob); + if (closeprob <= 0) + usage(); + break; + case 'd': + debug = 1; + break; + case 'l': + maxfilelen = getnum(optarg, &endp); + if (maxfilelen <= 0) + usage(); + break; + case 'm': + monitorstart = getnum(optarg, &endp); + if (monitorstart < 0) + usage(); + if (!endp || *endp++ != ':') + usage(); + monitorend = getnum(endp, &endp); + if (monitorend < 0) + usage(); + if (monitorend == 0) + monitorend = -1; /* aka infinity */ + debug = 1; + case 'n': + sizechecks = 0; + break; + case 'o': + maxoplen = getnum(optarg, &endp); + if (maxoplen <= 0) + usage(); + break; + case 'p': + progressinterval = getnum(optarg, &endp); + if (progressinterval < 0) + usage(); + break; + case 'q': + quiet = 1; + break; + case 'r': + readbdy = getnum(optarg, &endp); + if (readbdy <= 0) + usage(); + break; + case 's': + style = getnum(optarg, &endp); + if (style < 0 || style > 1) + usage(); + break; + case 't': + truncbdy = getnum(optarg, &endp); + if (truncbdy <= 0) + usage(); + break; + case 'w': + writebdy = getnum(optarg, &endp); + if (writebdy <= 0) + usage(); + break; + case 'D': + debugstart = getnum(optarg, &endp); + if (debugstart < 1) + usage(); + break; + case 'L': + lite = 1; + break; + case 'N': + numops = getnum(optarg, &endp); + if (numops < 0) + usage(); + break; + case 'O': + randomoplen = 0; + break; + case 'P': + strncpy(goodfile, optarg, sizeof(goodfile)); + strcat(goodfile, "/"); + strncpy(logfile, optarg, sizeof(logfile)); + strcat(logfile, "/"); + break; + case 'R': + mapped_reads = 0; + break; + case 'S': + seed = getnum(optarg, &endp); + if (seed == 0) + seed = time(0) % 10000; + if (!quiet) + fprintf(stdout, "Seed set to %d\n", seed); + if (seed < 0) + usage(); + break; + case 'W': + mapped_writes = 0; + if (!quiet) + fprintf(stdout, "mapped writes DISABLED\n"); + break; + + default: + usage(); + /* NOTREACHED */ + } + argc -= optind; + argv += optind; + + yaffs_StartUp(); + yaffs_mount("/flash/flash"); + + fname = "/flash/flash/fsxdata"; + + signal(SIGHUP, cleanup); + signal(SIGINT, cleanup); + signal(SIGPIPE, cleanup); + signal(SIGALRM, cleanup); + signal(SIGTERM, cleanup); + signal(SIGXCPU, cleanup); + signal(SIGXFSZ, cleanup); + signal(SIGVTALRM, cleanup); + signal(SIGUSR1, cleanup); + signal(SIGUSR2, cleanup); + + initstate(seed, state, 256); + setstate(state); + fd = yaffs_open(fname, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC), 0666); + if (fd < 0) { + prterr(fname); + exit(91); + } + strncat(goodfile, fname, 256); + strcat (goodfile, ".fsxgood"); + fsxgoodfd = yaffs_open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666); + if (fsxgoodfd < 0) { + prterr(goodfile); + exit(92); + } + strncat(logfile, "fsx", 256); + strcat (logfile, ".fsxlog"); + fsxlogf = fopen(logfile, "w"); + if (fsxlogf == NULL) { + prterr(logfile); + exit(93); + } + if (lite) { + off_t ret; + file_size = maxfilelen = yaffs_lseek(fd, (off_t)0, SEEK_END); + if (file_size == (off_t)-1) { + prterr(fname); + warn("main: lseek eof"); + exit(94); + } + ret = yaffs_lseek(fd, (off_t)0, SEEK_SET); + if (ret == (off_t)-1) { + prterr(fname); + warn("main: lseek 0"); + exit(95); + } + } + original_buf = (char *) malloc(maxfilelen); + for (i = 0; i < maxfilelen; i++) + original_buf[i] = random() % 256; + good_buf = (char *) malloc(maxfilelen); + memset(good_buf, '\0', maxfilelen); + temp_buf = (char *) malloc(maxoplen); + memset(temp_buf, '\0', maxoplen); + if (lite) { /* zero entire existing file */ + ssize_t written; + + written = yaffs_write(fd, good_buf, (size_t)maxfilelen); + if (written != maxfilelen) { + if (written == -1) { + prterr(fname); + warn("main: error on write"); + } else + warn("main: short write, 0x%x bytes instead of 0x%x\n", + (unsigned)written, maxfilelen); + exit(98); + } + } else + check_trunc_hack(); + + while (numops == -1 || numops--) + test(); + + if (yaffs_close(fd)) { + prterr("close"); + report_failure(99); + } + + yaffs_close(fsxgoodfd); + + yaffs_unmount("flash/flash"); + prt("All operations completed A-OK!\n"); + + exit(0); + return 0; +} + diff --git a/fs/yaffs2/direct/yaffs_fileem.c b/fs/yaffs2/direct/yaffs_fileem.c new file mode 100644 index 0000000000..e3cc30eb8a --- /dev/null +++ b/fs/yaffs2/direct/yaffs_fileem.c @@ -0,0 +1,218 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This provides a YAFFS nand emulation on a file. + * This is only intended as test code to test persistence etc. + */ + +const char *yaffs_flashif_c_version = "$Id: yaffs_fileem.c,v 1.3 2007/02/14 01:09:06 wookey Exp $"; + + +#include "yportenv.h" + +#include "yaffs_flashif.h" +#include "yaffs_guts.h" + +#include "devextras.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + + + +#define SIZE_IN_MB 16 + +#define BLOCK_SIZE (32 * 528) +#define BLOCKS_PER_MEG ((1024*1024)/(32 * 512)) + + + +typedef struct +{ + __u8 data[528]; // Data + spare +} yflash_Page; + +typedef struct +{ + yflash_Page page[32]; // The pages in the block + +} yflash_Block; + + + +typedef struct +{ + int handle; + int nBlocks; +} yflash_Device; + +static yflash_Device filedisk; + +static int CheckInit(yaffs_Device *dev) +{ + static int initialised = 0; + + int i; + + + int fSize; + int written; + + yflash_Page p; + + if(initialised) + { + return YAFFS_OK; + } + + initialised = 1; + + + filedisk.nBlocks = (SIZE_IN_MB * 1024 * 1024)/(16 * 1024); + + filedisk.handle = open("yaffsemfile", O_RDWR | O_CREAT, S_IREAD | S_IWRITE); + + if(filedisk.handle < 0) + { + perror("Failed to open yaffs emulation file"); + return YAFFS_FAIL; + } + + + fSize = lseek(filedisk.handle,0,SEEK_END); + + if(fSize < SIZE_IN_MB * 1024 * 1024) + { + printf("Creating yaffs emulation file\n"); + + lseek(filedisk.handle,0,SEEK_SET); + + memset(&p,0xff,sizeof(yflash_Page)); + + for(i = 0; i < SIZE_IN_MB * 1024 * 1024; i+= 512) + { + written = write(filedisk.handle,&p,sizeof(yflash_Page)); + + if(written != sizeof(yflash_Page)) + { + printf("Write failed\n"); + return YAFFS_FAIL; + } + } + } + + return 1; +} + +int yflash_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare) +{ + int written; + + CheckInit(dev); + + + + if(data) + { + lseek(filedisk.handle,chunkInNAND * 528,SEEK_SET); + written = write(filedisk.handle,data,512); + + if(written != 512) return YAFFS_FAIL; + } + + if(spare) + { + lseek(filedisk.handle,chunkInNAND * 528 + 512,SEEK_SET); + written = write(filedisk.handle,spare,16); + + if(written != 16) return YAFFS_FAIL; + } + + + return YAFFS_OK; + +} + + +int yflash_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare) +{ + int nread; + + CheckInit(dev); + + + + if(data) + { + lseek(filedisk.handle,chunkInNAND * 528,SEEK_SET); + nread = read(filedisk.handle,data,512); + + if(nread != 512) return YAFFS_FAIL; + } + + if(spare) + { + lseek(filedisk.handle,chunkInNAND * 528 + 512,SEEK_SET); + nread= read(filedisk.handle,spare,16); + + if(nread != 16) return YAFFS_FAIL; + } + + + return YAFFS_OK; + +} + + +int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) +{ + + int i; + + CheckInit(dev); + + if(blockNumber < 0 || blockNumber >= filedisk.nBlocks) + { + T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); + return YAFFS_FAIL; + } + else + { + + yflash_Page pg; + + memset(&pg,0xff,sizeof(yflash_Page)); + + lseek(filedisk.handle, blockNumber * 32 * 528, SEEK_SET); + + for(i = 0; i < 32; i++) + { + write(filedisk.handle,&pg,528); + } + return YAFFS_OK; + } + +} + +int yflash_InitialiseNAND(yaffs_Device *dev) +{ + dev->useNANDECC = 1; // force on useNANDECC which gets faked. + // This saves us doing ECC checks. + + return YAFFS_OK; +} + + diff --git a/fs/yaffs2/direct/yaffs_fileem2k.c b/fs/yaffs2/direct/yaffs_fileem2k.c new file mode 100644 index 0000000000..7a3b299996 --- /dev/null +++ b/fs/yaffs2/direct/yaffs_fileem2k.c @@ -0,0 +1,441 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This provides a YAFFS nand emulation on a file for emulating 2kB pages. + * This is only intended as test code to test persistence etc. + */ + +const char *yaffs_flashif_c_version = "$Id: yaffs_fileem2k.c,v 1.12 2007/02/14 01:09:06 wookey Exp $"; + + +#include "yportenv.h" + +#include "yaffs_flashif.h" +#include "yaffs_guts.h" +#include "devextras.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "yaffs_fileem2k.h" +#include "yaffs_packedtags2.h" + +//#define SIMULATE_FAILURES + +typedef struct +{ + __u8 data[PAGE_SIZE]; // Data + spare +} yflash_Page; + +typedef struct +{ + yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block + +} yflash_Block; + + + +#define MAX_HANDLES 20 +#define BLOCKS_PER_HANDLE 8000 + +typedef struct +{ + int handle[MAX_HANDLES]; + int nBlocks; +} yflash_Device; + +static yflash_Device filedisk; + +int yaffs_testPartialWrite = 0; + + + + +static __u8 localBuffer[PAGE_SIZE]; + +static char *NToName(char *buf,int n) +{ + sprintf(buf,"emfile%d",n); + return buf; +} + +static char dummyBuffer[BLOCK_SIZE]; + +static int GetBlockFileHandle(int n) +{ + int h; + int requiredSize; + + char name[40]; + NToName(name,n); + int fSize; + int i; + + h = open(name, O_RDWR | O_CREAT, S_IREAD | S_IWRITE); + if(h >= 0){ + fSize = lseek(h,0,SEEK_END); + requiredSize = BLOCKS_PER_HANDLE * BLOCK_SIZE; + if(fSize < requiredSize){ + for(i = 0; i < BLOCKS_PER_HANDLE; i++) + if(write(h,dummyBuffer,BLOCK_SIZE) != BLOCK_SIZE) + return -1; + + } + } + + return h; + +} + +static int CheckInit(void) +{ + static int initialised = 0; + int h; + int i; + + + off_t fSize; + off_t requiredSize; + int written; + int blk; + + yflash_Page p; + + if(initialised) + { + return YAFFS_OK; + } + + initialised = 1; + + memset(dummyBuffer,0xff,sizeof(dummyBuffer)); + + + filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB; + + for(i = 0; i < MAX_HANDLES; i++) + filedisk.handle[i] = -1; + + for(i = 0,blk = 0; blk < filedisk.nBlocks; blk+=BLOCKS_PER_HANDLE,i++) + filedisk.handle[i] = GetBlockFileHandle(i); + + + return 1; +} + + +int yflash_GetNumberOfBlocks(void) +{ + CheckInit(); + + return filedisk.nBlocks; +} + +int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags) +{ + int written; + int pos; + int h; + int i; + int nRead; + int error; + + T(YAFFS_TRACE_MTD,(TSTR("write chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags)); + + CheckInit(); + + + + if(data) + { + pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE; + h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))]; + + lseek(h,pos,SEEK_SET); + nRead = read(h, localBuffer,dev->nDataBytesPerChunk); + for(i = error = 0; i < dev->nDataBytesPerChunk && !error; i++){ + if(localBuffer[i] != 0xFF){ + printf("nand simulation: chunk %d data byte %d was %0x2\n", + chunkInNAND,i,localBuffer[i]); + error = 1; + } + } + + for(i = 0; i < dev->nDataBytesPerChunk; i++) + localBuffer[i] &= data[i]; + + if(memcmp(localBuffer,data,dev->nDataBytesPerChunk)) + printf("nand simulator: data does not match\n"); + + lseek(h,pos,SEEK_SET); + written = write(h,localBuffer,dev->nDataBytesPerChunk); + + if(yaffs_testPartialWrite){ + close(h); + exit(1); + } + +#ifdef SIMULATE_FAILURES + if((chunkInNAND >> 6) == 100) + written = 0; + + if((chunkInNAND >> 6) == 110) + written = 0; +#endif + + + if(written != dev->nDataBytesPerChunk) return YAFFS_FAIL; + } + + if(tags) + { + pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ; + h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))]; + + lseek(h,pos,SEEK_SET); + + if( 0 && dev->isYaffs2) + { + + written = write(h,tags,sizeof(yaffs_ExtendedTags)); + if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL; + } + else + { + yaffs_PackedTags2 pt; + yaffs_PackTags2(&pt,tags); + __u8 * ptab = (__u8 *)&pt; + + nRead = read(h,localBuffer,sizeof(pt)); + for(i = error = 0; i < sizeof(pt) && !error; i++){ + if(localBuffer[i] != 0xFF){ + printf("nand simulation: chunk %d oob byte %d was %0x2\n", + chunkInNAND,i,localBuffer[i]); + error = 1; + } + } + + for(i = 0; i < sizeof(pt); i++) + localBuffer[i] &= ptab[i]; + + if(memcmp(localBuffer,&pt,sizeof(pt))) + printf("nand sim: tags corruption\n"); + + lseek(h,pos,SEEK_SET); + + written = write(h,localBuffer,sizeof(pt)); + if(written != sizeof(pt)) return YAFFS_FAIL; + } + } + + + return YAFFS_OK; + +} + +int yaffs_CheckAllFF(const __u8 *ptr, int n) +{ + while(n) + { + n--; + if(*ptr!=0xFF) return 0; + ptr++; + } + return 1; +} + + +static int fail300 = 1; +static int fail320 = 1; + +static int failRead10 = 2; + +int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags) +{ + int nread; + int pos; + int h; + + T(YAFFS_TRACE_MTD,(TSTR("read chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags)); + + CheckInit(); + + + + if(data) + { + + pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE; + h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))]; + lseek(h,pos,SEEK_SET); + nread = read(h,data,dev->nDataBytesPerChunk); + + + if(nread != dev->nDataBytesPerChunk) return YAFFS_FAIL; + } + + if(tags) + { + pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE; + h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))]; + lseek(h,pos,SEEK_SET); + + if(0 && dev->isYaffs2) + { + nread= read(h,tags,sizeof(yaffs_ExtendedTags)); + if(nread != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL; + if(yaffs_CheckAllFF((__u8 *)tags,sizeof(yaffs_ExtendedTags))) + { + yaffs_InitialiseTags(tags); + } + else + { + tags->chunkUsed = 1; + } + } + else + { + yaffs_PackedTags2 pt; + nread= read(h,&pt,sizeof(pt)); + yaffs_UnpackTags2(tags,&pt); +#ifdef SIMULATE_FAILURES + if((chunkInNAND >> 6) == 100) { + if(fail300 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){ + tags->eccResult = YAFFS_ECC_RESULT_FIXED; + fail300 = 0; + } + + } + if((chunkInNAND >> 6) == 110) { + if(fail320 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){ + tags->eccResult = YAFFS_ECC_RESULT_FIXED; + fail320 = 0; + } + } +#endif + if(failRead10>0 && chunkInNAND == 10){ + failRead10--; + nread = 0; + } + + if(nread != sizeof(pt)) return YAFFS_FAIL; + } + } + + + return YAFFS_OK; + +} + + +int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) +{ + int written; + int h; + + yaffs_PackedTags2 pt; + + CheckInit(); + + memset(&pt,0,sizeof(pt)); + h = filedisk.handle[(blockNo / ( BLOCKS_PER_HANDLE))]; + lseek(h,((blockNo % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET); + written = write(h,&pt,sizeof(pt)); + + if(written != sizeof(pt)) return YAFFS_FAIL; + + + return YAFFS_OK; + +} + +int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) +{ + + int i; + int h; + + CheckInit(); + + printf("erase block %d\n",blockNumber); + + if(blockNumber == 320) + fail320 = 1; + + if(blockNumber < 0 || blockNumber >= filedisk.nBlocks) + { + T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); + return YAFFS_FAIL; + } + else + { + + __u8 pg[PAGE_SIZE]; + int syz = PAGE_SIZE; + int pos; + + memset(pg,0xff,syz); + + + h = filedisk.handle[(blockNumber / ( BLOCKS_PER_HANDLE))]; + lseek(h,((blockNumber % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE,SEEK_SET); + for(i = 0; i < dev->nChunksPerBlock; i++) + { + write(h,pg,PAGE_SIZE); + } + pos = lseek(h, 0,SEEK_CUR); + + return YAFFS_OK; + } + +} + +int yflash_InitialiseNAND(yaffs_Device *dev) +{ + CheckInit(); + + return YAFFS_OK; +} + + + + +int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber) +{ + yaffs_ExtendedTags tags; + int chunkNo; + + *sequenceNumber = 0; + + chunkNo = blockNo * dev->nChunksPerBlock; + + yflash_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags); + if(tags.blockBad) + { + *state = YAFFS_BLOCK_STATE_DEAD; + } + else if(!tags.chunkUsed) + { + *state = YAFFS_BLOCK_STATE_EMPTY; + } + else if(tags.chunkUsed) + { + *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; + *sequenceNumber = tags.sequenceNumber; + } + return YAFFS_OK; +} + diff --git a/fs/yaffs2/direct/yaffs_fileem2k.h b/fs/yaffs2/direct/yaffs_fileem2k.h new file mode 100644 index 0000000000..e694c9258f --- /dev/null +++ b/fs/yaffs2/direct/yaffs_fileem2k.h @@ -0,0 +1,50 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __FILEEM2K_H__ +#define __FILEEM2K_H__ + +#if 1 + +#define SIZE_IN_MB 128 +//#define SIZE_IN_MB 8000 +#define PAGE_DATA_SIZE (2048) +#define PAGE_SPARE_SIZE (64) +#define PAGE_SIZE (PAGE_DATA_SIZE + PAGE_SPARE_SIZE) +#define PAGES_PER_BLOCK (64) +#define BLOCK_DATA_SIZE (PAGE_DATA_SIZE * PAGES_PER_BLOCK) +#define BLOCK_SIZE (PAGES_PER_BLOCK * (PAGE_SIZE)) +#define BLOCKS_PER_MB ((1024*1024)/BLOCK_DATA_SIZE) +#define SIZE_IN_BLOCKS (BLOCKS_PER_MB * SIZE_IN_MB) + +#else + +#define SIZE_IN_MB 128 +#define PAGE_DATA_SIZE (512) +#define SPARE_SIZE (16) +#define PAGE_SIZE (PAGE_DATA_SIZE + SPARE_SIZE) +#define PAGES_PER_BLOCK (32) +#define BLOCK_DATA_SIZE (PAGE_SIZE * PAGES_PER_BLOCK) +#define BLOCK_SIZE (PAGES_PER_BLOCK * (PAGE_SIZE)) +#define BLOCKS_PER_MB ((1024*1024)/BLOCK_DATA_SIZE) +#define SIZE_IN_BLOCKS (BLOCKS_PER_MB * SIZE_IN_MB) + +#endif + + +int yflash_GetNumberOfBlocks(void); + +#endif + diff --git a/fs/yaffs2/direct/yaffs_flashif.c b/fs/yaffs2/direct/yaffs_flashif.c new file mode 100644 index 0000000000..5178cb2ac3 --- /dev/null +++ b/fs/yaffs2/direct/yaffs_flashif.c @@ -0,0 +1,229 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + +const char *yaffs_flashif_c_version = "$Id: yaffs_flashif.c,v 1.3 2007/02/14 01:09:06 wookey Exp $"; + + +#include "yportenv.h" + +#include "yaffs_flashif.h" +#include "yaffs_guts.h" +#include "devextras.h" + + +#define SIZE_IN_MB 16 + +#define BLOCK_SIZE (32 * 528) +#define BLOCKS_PER_MEG ((1024*1024)/(32 * 512)) + + + +typedef struct +{ + __u8 data[528]; // Data + spare +} yflash_Page; + +typedef struct +{ + yflash_Page page[32]; // The pages in the block + +} yflash_Block; + + + +typedef struct +{ + yflash_Block **block; + int nBlocks; +} yflash_Device; + +static yflash_Device ramdisk; + +static int CheckInit(yaffs_Device *dev) +{ + static int initialised = 0; + + int i; + int fail = 0; + int nAllocated = 0; + + if(initialised) + { + return YAFFS_OK; + } + + initialised = 1; + + + ramdisk.nBlocks = (SIZE_IN_MB * 1024 * 1024)/(16 * 1024); + + ramdisk.block = YMALLOC(sizeof(yflash_Block *) * ramdisk.nBlocks); + + if(!ramdisk.block) return 0; + + for(i=0; i <ramdisk.nBlocks; i++) + { + ramdisk.block[i] = NULL; + } + + for(i=0; i <ramdisk.nBlocks && !fail; i++) + { + if((ramdisk.block[i] = YMALLOC(sizeof(yflash_Block))) == 0) + { + fail = 1; + } + else + { + yflash_EraseBlockInNAND(dev,i); + nAllocated++; + } + } + + if(fail) + { + for(i = 0; i < nAllocated; i++) + { + YFREE(ramdisk.block[i]); + } + YFREE(ramdisk.block); + + T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n", + nAllocated/64,ramdisk.nBlocks * YAFFS_BYTES_PER_BLOCK)); + return 0; + } + + + + return 1; +} + +int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags) +{ + int blk; + int pg; + + + CheckInit(dev); + + blk = chunkInNAND/32; + pg = chunkInNAND%32; + + + if(data) + { + memcpy(ramdisk.block[blk]->page[pg].data,data,512); + } + + + if(tags) + { + yaffs_PackedTags pt; + yaffs_PackTags(&pt,tags); + memcpy(&ramdisk.block[blk]->page[pg].data[512],&pt,sizeof(pt)); + } + + return YAFFS_OK; + +} + + +int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Tags *tags) +{ + int blk; + int pg; + + + CheckInit(dev); + + blk = chunkInNAND/32; + pg = chunkInNAND%32; + + + if(data) + { + memcpy(data,ramdisk.block[blk]->page[pg].data,512); + } + + + if(tags) + { + yaffs_PackedTags pt; + memcpy(&pt,&ramdisk.block[blk]->page[pg].data[512],sizeof(yaffs_PackedTags)); + yaffs_UnpackTags(tags,&pt); + } + + return YAFFS_OK; +} + + +int yflash_CheckChunkErased(yaffs_Device *dev,int chunkInNAND) +{ + int blk; + int pg; + int i; + + + CheckInit(dev); + + blk = chunkInNAND/32; + pg = chunkInNAND%32; + + + for(i = 0; i < 528; i++) + { + if(ramdisk.block[blk]->page[pg].data[i] != 0xFF) + { + return YAFFS_FAIL; + } + } + + return YAFFS_OK; + +} + +int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) +{ + + CheckInit(dev); + + if(blockNumber < 0 || blockNumber >= ramdisk.nBlocks) + { + T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); + return YAFFS_FAIL; + } + else + { + memset(ramdisk.block[blockNumber],0xFF,sizeof(yflash_Block)); + return YAFFS_OK; + } + +} + +int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) +{ + return YAFFS_OK; + +} +int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber) +{ + *state = YAFFS_BLOCK_STATE_EMPTY; + *sequenceNumber = 0; +} + + +int yflash_InitialiseNAND(yaffs_Device *dev) +{ + return YAFFS_OK; +} + diff --git a/fs/yaffs2/direct/yaffs_flashif.h b/fs/yaffs2/direct/yaffs_flashif.h new file mode 100644 index 0000000000..f7f4e4227d --- /dev/null +++ b/fs/yaffs2/direct/yaffs_flashif.h @@ -0,0 +1,31 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_FLASH_H__ +#define __YAFFS_FLASH_H__ + + +#include "yaffs_guts.h" +int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); +int yflash_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare); +int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags); +int yflash_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare); +int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags); +int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); +int yflash_InitialiseNAND(yaffs_Device *dev); +int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); +int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber); + +#endif diff --git a/fs/yaffs2/direct/yaffs_malloc.h b/fs/yaffs2/direct/yaffs_malloc.h new file mode 100644 index 0000000000..245f9c9634 --- /dev/null +++ b/fs/yaffs2/direct/yaffs_malloc.h @@ -0,0 +1,23 @@ +#ifndef __YAFFS_MALLOC_H__ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#include <stdlib.h> + +void *yaffs_malloc(size_t size); +void yaffs_free(void *ptr); + +#endif + diff --git a/fs/yaffs2/direct/yaffs_ramdisk.c b/fs/yaffs2/direct/yaffs_ramdisk.c new file mode 100644 index 0000000000..6afee81f4c --- /dev/null +++ b/fs/yaffs2/direct/yaffs_ramdisk.c @@ -0,0 +1,234 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * yaffs_ramdisk.c: yaffs ram disk component + * This provides a ram disk under yaffs. + * NB this is not intended for NAND emulation. + * Use this with dev->useNANDECC enabled, then ECC overheads are not required. + */ + +const char *yaffs_ramdisk_c_version = "$Id: yaffs_ramdisk.c,v 1.4 2007/02/14 01:09:06 wookey Exp $"; + + +#include "yportenv.h" + +#include "yaffs_ramdisk.h" +#include "yaffs_guts.h" +#include "devextras.h" +#include "yaffs_packedtags1.h" + + + +#define SIZE_IN_MB 2 + +#define BLOCK_SIZE (32 * 528) +#define BLOCKS_PER_MEG ((1024*1024)/(32 * 512)) + + + + + +typedef struct +{ + __u8 data[528]; // Data + spare +} yramdisk_Page; + +typedef struct +{ + yramdisk_Page page[32]; // The pages in the block + +} yramdisk_Block; + + + +typedef struct +{ + yramdisk_Block **block; + int nBlocks; +} yramdisk_Device; + +static yramdisk_Device ramdisk; + +static int CheckInit(yaffs_Device *dev) +{ + static int initialised = 0; + + int i; + int fail = 0; + //int nBlocks; + int nAllocated = 0; + + if(initialised) + { + return YAFFS_OK; + } + + initialised = 1; + + + ramdisk.nBlocks = (SIZE_IN_MB * 1024 * 1024)/(16 * 1024); + + ramdisk.block = YMALLOC(sizeof(yramdisk_Block *) * ramdisk.nBlocks); + + if(!ramdisk.block) return 0; + + for(i=0; i <ramdisk.nBlocks; i++) + { + ramdisk.block[i] = NULL; + } + + for(i=0; i <ramdisk.nBlocks && !fail; i++) + { + if((ramdisk.block[i] = YMALLOC(sizeof(yramdisk_Block))) == 0) + { + fail = 1; + } + else + { + yramdisk_EraseBlockInNAND(dev,i); + nAllocated++; + } + } + + if(fail) + { + for(i = 0; i < nAllocated; i++) + { + YFREE(ramdisk.block[i]); + } + YFREE(ramdisk.block); + + T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n", + nAllocated/64,ramdisk.nBlocks * 528)); + return 0; + } + + + return 1; +} + +int yramdisk_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags) +{ + int blk; + int pg; + + + CheckInit(dev); + + blk = chunkInNAND/32; + pg = chunkInNAND%32; + + + if(data) + { + memcpy(ramdisk.block[blk]->page[pg].data,data,512); + } + + + if(tags) + { + yaffs_PackedTags1 pt; + + yaffs_PackTags1(&pt,tags); + memcpy(&ramdisk.block[blk]->page[pg].data[512],&pt,sizeof(pt)); + } + + return YAFFS_OK; + +} + + +int yramdisk_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags) +{ + int blk; + int pg; + + + CheckInit(dev); + + blk = chunkInNAND/32; + pg = chunkInNAND%32; + + + if(data) + { + memcpy(data,ramdisk.block[blk]->page[pg].data,512); + } + + + if(tags) + { + yaffs_PackedTags1 pt; + + memcpy(&pt,&ramdisk.block[blk]->page[pg].data[512],sizeof(pt)); + yaffs_UnpackTags1(tags,&pt); + + } + + return YAFFS_OK; +} + + +int yramdisk_CheckChunkErased(yaffs_Device *dev,int chunkInNAND) +{ + int blk; + int pg; + int i; + + + CheckInit(dev); + + blk = chunkInNAND/32; + pg = chunkInNAND%32; + + + for(i = 0; i < 528; i++) + { + if(ramdisk.block[blk]->page[pg].data[i] != 0xFF) + { + return YAFFS_FAIL; + } + } + + return YAFFS_OK; + +} + +int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) +{ + + CheckInit(dev); + + if(blockNumber < 0 || blockNumber >= ramdisk.nBlocks) + { + T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); + return YAFFS_FAIL; + } + else + { + memset(ramdisk.block[blockNumber],0xFF,sizeof(yramdisk_Block)); + return YAFFS_OK; + } + +} + +int yramdisk_InitialiseNAND(yaffs_Device *dev) +{ + //dev->useNANDECC = 1; // force on useNANDECC which gets faked. + // This saves us doing ECC checks. + + return YAFFS_OK; +} + + diff --git a/fs/yaffs2/direct/yaffs_ramdisk.h b/fs/yaffs2/direct/yaffs_ramdisk.h new file mode 100644 index 0000000000..045ab42db5 --- /dev/null +++ b/fs/yaffs2/direct/yaffs_ramdisk.h @@ -0,0 +1,32 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * yaffs_ramdisk.h: yaffs ram disk component + */ + +#ifndef __YAFFS_RAMDISK_H__ +#define __YAFFS_RAMDISK_H__ + + +#include "yaffs_guts.h" +int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); +int yramdisk_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags); +int yramdisk_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags); +int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); +int yramdisk_InitialiseNAND(yaffs_Device *dev); +int yramdisk_MarkNANDBlockBad(yaffs_Device *dev,int blockNumber); +int yramdisk_QueryNANDBlock(yaffs_Device *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber); +#endif diff --git a/fs/yaffs2/direct/yaffs_ramem2k.c b/fs/yaffs2/direct/yaffs_ramem2k.c new file mode 100644 index 0000000000..1ab053c467 --- /dev/null +++ b/fs/yaffs2/direct/yaffs_ramem2k.c @@ -0,0 +1,363 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * yaffs_ramem2k.c: RAM emulation in-kernel for 2K pages (YAFFS2) + */ + + +const char *yaffs_ramem2k_c_version = "$Id: yaffs_ramem2k.c,v 1.3 2007/02/14 01:09:06 wookey Exp $"; + +#ifndef __KERNEL__ +#define CONFIG_YAFFS_RAM_ENABLED +#else +#include <linux/config.h> +#endif + +#ifdef CONFIG_YAFFS_RAM_ENABLED + +#include "yportenv.h" + +#include "yaffs_nandemul2k.h" +#include "yaffs_guts.h" +#include "yaffsinterface.h" +#include "devextras.h" +#include "yaffs_packedtags2.h" + + + +#define EM_SIZE_IN_MEG (32) +#define PAGE_DATA_SIZE (2048) +#define PAGE_SPARE_SIZE (64) +#define PAGES_PER_BLOCK (64) + + + +#define EM_SIZE_IN_BYTES (EM_SIZE_IN_MEG * (1<<20)) + +#define PAGE_TOTAL_SIZE (PAGE_DATA_SIZE+PAGE_SPARE_SIZE) + +#define BLOCK_TOTAL_SIZE (PAGES_PER_BLOCK * PAGE_TOTAL_SIZE) + +#define BLOCKS_PER_MEG ((1<<20)/(PAGES_PER_BLOCK * PAGE_DATA_SIZE)) + + +typedef struct +{ + __u8 data[PAGE_TOTAL_SIZE]; // Data + spare + int empty; // is this empty? +} nandemul_Page; + + +typedef struct +{ + nandemul_Page *page[PAGES_PER_BLOCK]; + int damaged; +} nandemul_Block; + + + +typedef struct +{ + nandemul_Block**block; + int nBlocks; +} nandemul_Device; + +static nandemul_Device ned; + +static int sizeInMB = EM_SIZE_IN_MEG; + + +static void nandemul_yield(int n) +{ +#ifdef __KERNEL__ + if(n > 0) schedule_timeout(n); +#endif + +} + + +static void nandemul_ReallyEraseBlock(int blockNumber) +{ + int i; + + nandemul_Block *blk; + + if(blockNumber < 0 || blockNumber >= ned.nBlocks) + { + return; + } + + blk = ned.block[blockNumber]; + + for(i = 0; i < PAGES_PER_BLOCK; i++) + { + memset(blk->page[i],0xff,sizeof(nandemul_Page)); + blk->page[i]->empty = 1; + } + nandemul_yield(2); +} + + +static int nandemul2k_CalcNBlocks(void) +{ + return EM_SIZE_IN_MEG * BLOCKS_PER_MEG; +} + + + +static int CheckInit(void) +{ + static int initialised = 0; + + int i,j; + + int fail = 0; + int nBlocks; + + int nAllocated = 0; + + if(initialised) + { + return YAFFS_OK; + } + + + ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks(); + + + ned.block = YMALLOC(sizeof(nandemul_Block*) * nBlocks ); + + if(!ned.block) return YAFFS_FAIL; + + + + + + for(i=fail=0; i <nBlocks; i++) + { + + nandemul_Block *blk; + + if(!(blk = ned.block[i] = YMALLOC(sizeof(nandemul_Block)))) + { + fail = 1; + } + else + { + for(j = 0; j < PAGES_PER_BLOCK; j++) + { + if((blk->page[j] = YMALLOC(sizeof(nandemul_Page))) == 0) + { + fail = 1; + } + } + nandemul_ReallyEraseBlock(i); + ned.block[i]->damaged = 0; + nAllocated++; + } + } + + if(fail) + { + //Todo thump pages + + for(i = 0; i < nAllocated; i++) + { + YFREE(ned.block[i]); + } + YFREE(ned.block); + + T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n", + nAllocated/64,sizeInMB)); + return 0; + } + + ned.nBlocks = nBlocks; + + initialised = 1; + + return 1; +} + +int nandemul2k_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags) +{ + int blk; + int pg; + int i; + + __u8 *x; + + + blk = chunkInNAND/PAGES_PER_BLOCK; + pg = chunkInNAND%PAGES_PER_BLOCK; + + + if(data) + { + x = ned.block[blk]->page[pg]->data; + + for(i = 0; i < PAGE_DATA_SIZE; i++) + { + x[i] &=data[i]; + } + + ned.block[blk]->page[pg]->empty = 0; + } + + + if(tags) + { + x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE]; + + yaffs_PackTags2((yaffs_PackedTags2 *)x,tags); + + } + + if(tags || data) + { + nandemul_yield(1); + } + + return YAFFS_OK; +} + + +int nandemul2k_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags) +{ + int blk; + int pg; + + __u8 *x; + + + + blk = chunkInNAND/PAGES_PER_BLOCK; + pg = chunkInNAND%PAGES_PER_BLOCK; + + + if(data) + { + memcpy(data,ned.block[blk]->page[pg]->data,PAGE_DATA_SIZE); + } + + + if(tags) + { + x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE]; + + yaffs_UnpackTags2(tags,(yaffs_PackedTags2 *)x); + } + + return YAFFS_OK; +} + + +static int nandemul2k_CheckChunkErased(yaffs_Device *dev,int chunkInNAND) +{ + int blk; + int pg; + int i; + + + + blk = chunkInNAND/PAGES_PER_BLOCK; + pg = chunkInNAND%PAGES_PER_BLOCK; + + + for(i = 0; i < PAGE_TOTAL_SIZE; i++) + { + if(ned.block[blk]->page[pg]->data[i] != 0xFF) + { + return YAFFS_FAIL; + } + } + + return YAFFS_OK; + +} + +int nandemul2k_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) +{ + + + if(blockNumber < 0 || blockNumber >= ned.nBlocks) + { + T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); + } + else if(ned.block[blockNumber]->damaged) + { + T(YAFFS_TRACE_ALWAYS,("Attempt to erase damaged block %d\n",blockNumber)); + } + else + { + nandemul_ReallyEraseBlock(blockNumber); + } + + return YAFFS_OK; +} + +int nandemul2k_InitialiseNAND(yaffs_Device *dev) +{ + CheckInit(); + return YAFFS_OK; +} + +int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) +{ + + __u8 *x; + + x = &ned.block[blockNo]->page[0]->data[PAGE_DATA_SIZE]; + + memset(x,0,sizeof(yaffs_PackedTags2)); + + + return YAFFS_OK; + +} + +int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber) +{ + yaffs_ExtendedTags tags; + int chunkNo; + + *sequenceNumber = 0; + + chunkNo = blockNo * dev->nChunksPerBlock; + + nandemul2k_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags); + if(tags.blockBad) + { + *state = YAFFS_BLOCK_STATE_DEAD; + } + else if(!tags.chunkUsed) + { + *state = YAFFS_BLOCK_STATE_EMPTY; + } + else if(tags.chunkUsed) + { + *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; + *sequenceNumber = tags.sequenceNumber; + } + return YAFFS_OK; +} + +int nandemul2k_GetBytesPerChunk(void) { return PAGE_DATA_SIZE;} + +int nandemul2k_GetChunksPerBlock(void) { return PAGES_PER_BLOCK; } +int nandemul2k_GetNumberOfBlocks(void) {return nandemul2k_CalcNBlocks();} + + +#endif //YAFFS_RAM_ENABLED + diff --git a/fs/yaffs2/direct/yaffscfg.c b/fs/yaffs2/direct/yaffscfg.c new file mode 100644 index 0000000000..b1d311e569 --- /dev/null +++ b/fs/yaffs2/direct/yaffscfg.c @@ -0,0 +1,144 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * yaffscfg.c The configuration for the "direct" use of yaffs. + * + * This file is intended to be modified to your requirements. + * There is no need to redistribute this file. + */ + +#include "yaffscfg.h" +#include "yaffsfs.h" +#include <errno.h> + +unsigned yaffs_traceMask = 0xFFFFFFFF; + + +void yaffsfs_SetError(int err) +{ + //Do whatever to set error + errno = err; +} + +void yaffsfs_Lock(void) +{ +} + +void yaffsfs_Unlock(void) +{ +} + +__u32 yaffsfs_CurrentTime(void) +{ + return 0; +} + +void *yaffs_malloc(size_t size) +{ + return malloc(size); +} + +void yaffs_free(void *ptr) +{ + free(ptr); +} + +void yaffsfs_LocalInitialisation(void) +{ + // Define locking semaphore. +} + +// Configuration for: +// /ram 2MB ramdisk +// /boot 2MB boot disk (flash) +// /flash 14MB flash disk (flash) +// NB Though /boot and /flash occupy the same physical device they +// are still disticnt "yaffs_Devices. You may think of these as "partitions" +// using non-overlapping areas in the same device. +// + +#include "yaffs_ramdisk.h" +#include "yaffs_flashif.h" + +static yaffs_Device ramDev; +static yaffs_Device bootDev; +static yaffs_Device flashDev; + +static yaffsfs_DeviceConfiguration yaffsfs_config[] = { + + { "/ram", &ramDev}, + { "/boot", &bootDev}, + { "/flash", &flashDev}, + {(void *)0,(void *)0} +}; + + +int yaffs_StartUp(void) +{ + // Stuff to configure YAFFS + // Stuff to initialise anything special (eg lock semaphore). + yaffsfs_LocalInitialisation(); + + // Set up devices + + // /ram + ramDev.nBytesPerChunk = 512; + ramDev.nChunksPerBlock = 32; + ramDev.nReservedBlocks = 2; // Set this smaller for RAM + ramDev.startBlock = 1; // Can't use block 0 + ramDev.endBlock = 127; // Last block in 2MB. + ramDev.useNANDECC = 1; + ramDev.nShortOpCaches = 0; // Disable caching on this device. + ramDev.genericDevice = (void *) 0; // Used to identify the device in fstat. + ramDev.writeChunkWithTagsToNAND = yramdisk_WriteChunkWithTagsToNAND; + ramDev.readChunkWithTagsFromNAND = yramdisk_ReadChunkWithTagsFromNAND; + ramDev.eraseBlockInNAND = yramdisk_EraseBlockInNAND; + ramDev.initialiseNAND = yramdisk_InitialiseNAND; + + // /boot + bootDev.nBytesPerChunk = 612; + bootDev.nChunksPerBlock = 32; + bootDev.nReservedBlocks = 5; + bootDev.startBlock = 1; // Can't use block 0 + bootDev.endBlock = 127; // Last block in 2MB. + bootDev.useNANDECC = 0; // use YAFFS's ECC + bootDev.nShortOpCaches = 10; // Use caches + bootDev.genericDevice = (void *) 1; // Used to identify the device in fstat. + bootDev.writeChunkToNAND = yflash_WriteChunkToNAND; + bootDev.readChunkFromNAND = yflash_ReadChunkFromNAND; + bootDev.eraseBlockInNAND = yflash_EraseBlockInNAND; + bootDev.initialiseNAND = yflash_InitialiseNAND; + + // /flash + flashDev.nBytesPerChunk = 512; + flashDev.nChunksPerBlock = 32; + flashDev.nReservedBlocks = 5; + flashDev.startBlock = 128; // First block after 2MB + flashDev.endBlock = 1023; // Last block in 16MB + flashDev.useNANDECC = 0; // use YAFFS's ECC + flashDev.nShortOpCaches = 10; // Use caches + flashDev.genericDevice = (void *) 2; // Used to identify the device in fstat. + flashDev.writeChunkToNAND = yflash_WriteChunkToNAND; + flashDev.readChunkFromNAND = yflash_ReadChunkFromNAND; + flashDev.eraseBlockInNAND = yflash_EraseBlockInNAND; + flashDev.initialiseNAND = yflash_InitialiseNAND; + + yaffs_initialise(yaffsfs_config); + + return 0; +} + + + + diff --git a/fs/yaffs2/direct/yaffscfg.h b/fs/yaffs2/direct/yaffscfg.h new file mode 100644 index 0000000000..2a60dc132c --- /dev/null +++ b/fs/yaffs2/direct/yaffscfg.h @@ -0,0 +1,45 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * Header file for using yaffs in an application via + * a direct interface. + */ + + +#ifndef __YAFFSCFG_H__ +#define __YAFFSCFG_H__ + + +#include "devextras.h" + +#define YAFFSFS_N_HANDLES 200 + + +typedef struct { + const char *prefix; + struct yaffs_DeviceStruct *dev; +} yaffsfs_DeviceConfiguration; + + +void yaffsfs_Lock(void); +void yaffsfs_Unlock(void); + +__u32 yaffsfs_CurrentTime(void); + +void yaffsfs_SetError(int err); + +#endif + diff --git a/fs/yaffs2/direct/yaffscfg2k.c b/fs/yaffs2/direct/yaffscfg2k.c new file mode 100644 index 0000000000..6d5f542fc4 --- /dev/null +++ b/fs/yaffs2/direct/yaffscfg2k.c @@ -0,0 +1,229 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * yaffscfg2k.c The configuration for the "direct" use of yaffs. + * + * This file is intended to be modified to your requirements. + * There is no need to redistribute this file. + */ + +#include "yaffscfg.h" +#include "yaffsfs.h" +#include "yaffs_fileem2k.h" +#include "yaffs_nandemul2k.h" + +#include <errno.h> + +unsigned yaffs_traceMask = + + YAFFS_TRACE_SCAN | + YAFFS_TRACE_GC | YAFFS_TRACE_GC_DETAIL | + YAFFS_TRACE_ERASE | + YAFFS_TRACE_TRACING | + YAFFS_TRACE_ALLOCATE | + YAFFS_TRACE_CHECKPOINT | + YAFFS_TRACE_BAD_BLOCKS | + YAFFS_TRACE_VERIFY | + YAFFS_TRACE_VERIFY_NAND | + YAFFS_TRACE_VERIFY_FULL | +// (~0) | + + 0; + + + +void yaffsfs_SetError(int err) +{ + //Do whatever to set error + errno = err; +} + +void yaffsfs_Lock(void) +{ +} + +void yaffsfs_Unlock(void) +{ +} + +__u32 yaffsfs_CurrentTime(void) +{ + return 0; +} + + +static int yaffs_kill_alloc = 0; +static size_t total_malloced = 0; +static size_t malloc_limit = 0 & 6000000; + +void *yaffs_malloc(size_t size) +{ + size_t this; + if(yaffs_kill_alloc) + return NULL; + if(malloc_limit && malloc_limit <(total_malloced + size) ) + return NULL; + + this = malloc(size); + if(this) + total_malloced += size; + return this; +} + +void yaffs_free(void *ptr) +{ + free(ptr); +} + +void yaffsfs_LocalInitialisation(void) +{ + // Define locking semaphore. +} + +// Configuration for: +// /ram 2MB ramdisk +// /boot 2MB boot disk (flash) +// /flash 14MB flash disk (flash) +// NB Though /boot and /flash occupy the same physical device they +// are still disticnt "yaffs_Devices. You may think of these as "partitions" +// using non-overlapping areas in the same device. +// + +#include "yaffs_ramdisk.h" +#include "yaffs_flashif.h" +#include "yaffs_nandemul2k.h" + +static yaffs_Device ramDev; +static yaffs_Device bootDev; +static yaffs_Device flashDev; +static yaffs_Device ram2kDev; + +static yaffsfs_DeviceConfiguration yaffsfs_config[] = { +#if 0 + { "/ram", &ramDev}, + { "/boot", &bootDev}, + { "/flash/", &flashDev}, + { "/ram2k", &ram2kDev}, + {(void *)0,(void *)0} +#else + { "/", &ramDev}, + { "/flash/boot", &bootDev}, + { "/flash/flash", &flashDev}, + { "/ram2k", &ram2kDev}, + {(void *)0,(void *)0} /* Null entry to terminate list */ +#endif +}; + + +int yaffs_StartUp(void) +{ + // Stuff to configure YAFFS + // Stuff to initialise anything special (eg lock semaphore). + yaffsfs_LocalInitialisation(); + + // Set up devices + // /ram + memset(&ramDev,0,sizeof(ramDev)); + ramDev.nDataBytesPerChunk = 512; + ramDev.nChunksPerBlock = 32; + ramDev.nReservedBlocks = 2; // Set this smaller for RAM + ramDev.startBlock = 0; // Can use block 0 + ramDev.endBlock = 127; // Last block in 2MB. + //ramDev.useNANDECC = 1; + ramDev.nShortOpCaches = 0; // Disable caching on this device. + ramDev.genericDevice = (void *) 0; // Used to identify the device in fstat. + ramDev.writeChunkWithTagsToNAND = yramdisk_WriteChunkWithTagsToNAND; + ramDev.readChunkWithTagsFromNAND = yramdisk_ReadChunkWithTagsFromNAND; + ramDev.eraseBlockInNAND = yramdisk_EraseBlockInNAND; + ramDev.initialiseNAND = yramdisk_InitialiseNAND; + + // /boot + memset(&bootDev,0,sizeof(bootDev)); + bootDev.nDataBytesPerChunk = 512; + bootDev.nChunksPerBlock = 32; + bootDev.nReservedBlocks = 5; + bootDev.startBlock = 0; // Can use block 0 + bootDev.endBlock = 63; // Last block + //bootDev.useNANDECC = 0; // use YAFFS's ECC + bootDev.nShortOpCaches = 10; // Use caches + bootDev.genericDevice = (void *) 1; // Used to identify the device in fstat. + bootDev.writeChunkWithTagsToNAND = yflash_WriteChunkWithTagsToNAND; + bootDev.readChunkWithTagsFromNAND = yflash_ReadChunkWithTagsFromNAND; + bootDev.eraseBlockInNAND = yflash_EraseBlockInNAND; + bootDev.initialiseNAND = yflash_InitialiseNAND; + bootDev.markNANDBlockBad = yflash_MarkNANDBlockBad; + bootDev.queryNANDBlock = yflash_QueryNANDBlock; + + + + // /flash + // Set this puppy up to use + // the file emulation space as + // 2kpage/64chunk per block/128MB device + memset(&flashDev,0,sizeof(flashDev)); + + flashDev.nDataBytesPerChunk = 2048; + flashDev.nChunksPerBlock = 64; + flashDev.nReservedBlocks = 5; + flashDev.nCheckpointReservedBlocks = 5; + //flashDev.checkpointStartBlock = 1; + //flashDev.checkpointEndBlock = 20; + flashDev.startBlock = 0; + flashDev.endBlock = 200; // Make it smaller + //flashDev.endBlock = yflash_GetNumberOfBlocks()-1; + flashDev.isYaffs2 = 1; + flashDev.wideTnodesDisabled=0; + flashDev.nShortOpCaches = 10; // Use caches + flashDev.genericDevice = (void *) 2; // Used to identify the device in fstat. + flashDev.writeChunkWithTagsToNAND = yflash_WriteChunkWithTagsToNAND; + flashDev.readChunkWithTagsFromNAND = yflash_ReadChunkWithTagsFromNAND; + flashDev.eraseBlockInNAND = yflash_EraseBlockInNAND; + flashDev.initialiseNAND = yflash_InitialiseNAND; + flashDev.markNANDBlockBad = yflash_MarkNANDBlockBad; + flashDev.queryNANDBlock = yflash_QueryNANDBlock; + + // /ram2k + // Set this puppy up to use + // the file emulation space as + // 2kpage/64chunk per block/128MB device + memset(&ram2kDev,0,sizeof(ram2kDev)); + + ram2kDev.nDataBytesPerChunk = nandemul2k_GetBytesPerChunk(); + ram2kDev.nChunksPerBlock = nandemul2k_GetChunksPerBlock(); + ram2kDev.nReservedBlocks = 5; + ram2kDev.startBlock = 0; // First block after /boot + //ram2kDev.endBlock = 127; // Last block in 16MB + ram2kDev.endBlock = nandemul2k_GetNumberOfBlocks() - 1; // Last block in 512MB + ram2kDev.isYaffs2 = 1; + ram2kDev.nShortOpCaches = 10; // Use caches + ram2kDev.genericDevice = (void *) 3; // Used to identify the device in fstat. + ram2kDev.writeChunkWithTagsToNAND = nandemul2k_WriteChunkWithTagsToNAND; + ram2kDev.readChunkWithTagsFromNAND = nandemul2k_ReadChunkWithTagsFromNAND; + ram2kDev.eraseBlockInNAND = nandemul2k_EraseBlockInNAND; + ram2kDev.initialiseNAND = nandemul2k_InitialiseNAND; + ram2kDev.markNANDBlockBad = nandemul2k_MarkNANDBlockBad; + ram2kDev.queryNANDBlock = nandemul2k_QueryNANDBlock; + + yaffs_initialise(yaffsfs_config); + + return 0; +} + + + +void SetCheckpointReservedBlocks(int n) +{ + flashDev.nCheckpointReservedBlocks = n; +} + diff --git a/fs/yaffs2/direct/yaffsfs.c b/fs/yaffs2/direct/yaffsfs.c new file mode 100644 index 0000000000..a8519c28e7 --- /dev/null +++ b/fs/yaffs2/direct/yaffsfs.c @@ -0,0 +1,1505 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "yaffsfs.h" +#include "yaffs_guts.h" +#include "yaffscfg.h" +#include <string.h> // for memset +#include "yportenv.h" + +#define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5 + +#ifndef NULL +#define NULL ((void *)0) +#endif + + +const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.18 2007/07/18 19:40:38 charles Exp $"; + +// configurationList is the list of devices that are supported +static yaffsfs_DeviceConfiguration *yaffsfs_configurationList; + + +/* Some forward references */ +static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path, int symDepth); +static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj); + + +// Handle management. +// + + +unsigned int yaffs_wr_attempts; + +typedef struct +{ + __u8 inUse:1; // this handle is in use + __u8 readOnly:1; // this handle is read only + __u8 append:1; // append only + __u8 exclusive:1; // exclusive + __u32 position; // current position in file + yaffs_Object *obj; // the object +}yaffsfs_Handle; + + +static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES]; + +// yaffsfs_InitHandle +/// Inilitalise handles on start-up. +// +static int yaffsfs_InitHandles(void) +{ + int i; + for(i = 0; i < YAFFSFS_N_HANDLES; i++) + { + yaffsfs_handle[i].inUse = 0; + yaffsfs_handle[i].obj = NULL; + } + return 0; +} + +yaffsfs_Handle *yaffsfs_GetHandlePointer(int h) +{ + if(h < 0 || h >= YAFFSFS_N_HANDLES) + { + return NULL; + } + + return &yaffsfs_handle[h]; +} + +yaffs_Object *yaffsfs_GetHandleObject(int handle) +{ + yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle); + + if(h && h->inUse) + { + return h->obj; + } + + return NULL; +} + + +//yaffsfs_GetHandle +// Grab a handle (when opening a file) +// + +static int yaffsfs_GetHandle(void) +{ + int i; + yaffsfs_Handle *h; + + for(i = 0; i < YAFFSFS_N_HANDLES; i++) + { + h = yaffsfs_GetHandlePointer(i); + if(!h) + { + // todo bug: should never happen + } + if(!h->inUse) + { + memset(h,0,sizeof(yaffsfs_Handle)); + h->inUse=1; + return i; + } + } + return -1; +} + +// yaffs_PutHandle +// Let go of a handle (when closing a file) +// +static int yaffsfs_PutHandle(int handle) +{ + yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle); + + if(h) + { + h->inUse = 0; + h->obj = NULL; + } + return 0; +} + + + +// Stuff to search for a directory from a path + + +int yaffsfs_Match(char a, char b) +{ + // case sensitive + return (a == b); +} + +// yaffsfs_FindDevice +// yaffsfs_FindRoot +// Scan the configuration list to find the root. +// Curveballs: Should match paths that end in '/' too +// Curveball2 Might have "/x/ and "/x/y". Need to return the longest match +static yaffs_Device *yaffsfs_FindDevice(const char *path, char **restOfPath) +{ + yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList; + const char *leftOver; + const char *p; + yaffs_Device *retval = NULL; + int thisMatchLength; + int longestMatch = -1; + + // Check all configs, choose the one that: + // 1) Actually matches a prefix (ie /a amd /abc will not match + // 2) Matches the longest. + while(cfg && cfg->prefix && cfg->dev) + { + leftOver = path; + p = cfg->prefix; + thisMatchLength = 0; + + while(*p && //unmatched part of prefix + strcmp(p,"/") && // the rest of the prefix is not / (to catch / at end) + *leftOver && + yaffsfs_Match(*p,*leftOver)) + { + p++; + leftOver++; + thisMatchLength++; + } + if((!*p || strcmp(p,"/") == 0) && // end of prefix + (!*leftOver || *leftOver == '/') && // no more in this path name part + (thisMatchLength > longestMatch)) + { + // Matched prefix + *restOfPath = (char *)leftOver; + retval = cfg->dev; + longestMatch = thisMatchLength; + } + cfg++; + } + return retval; +} + +static yaffs_Object *yaffsfs_FindRoot(const char *path, char **restOfPath) +{ + + yaffs_Device *dev; + + dev= yaffsfs_FindDevice(path,restOfPath); + if(dev && dev->isMounted) + { + return dev->rootDir; + } + return NULL; +} + +static yaffs_Object *yaffsfs_FollowLink(yaffs_Object *obj,int symDepth) +{ + + while(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) + { + char *alias = obj->variant.symLinkVariant.alias; + + if(*alias == '/') + { + // Starts with a /, need to scan from root up + obj = yaffsfs_FindObject(NULL,alias,symDepth++); + } + else + { + // Relative to here, so use the parent of the symlink as a start + obj = yaffsfs_FindObject(obj->parent,alias,symDepth++); + } + } + return obj; +} + + +// yaffsfs_FindDirectory +// Parse a path to determine the directory and the name within the directory. +// +// eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx" +static yaffs_Object *yaffsfs_DoFindDirectory(yaffs_Object *startDir,const char *path,char **name,int symDepth) +{ + yaffs_Object *dir; + char *restOfPath; + char str[YAFFS_MAX_NAME_LENGTH+1]; + int i; + + if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES) + { + return NULL; + } + + if(startDir) + { + dir = startDir; + restOfPath = (char *)path; + } + else + { + dir = yaffsfs_FindRoot(path,&restOfPath); + } + + while(dir) + { + // parse off /. + // curve ball: also throw away surplus '/' + // eg. "/ram/x////ff" gets treated the same as "/ram/x/ff" + while(*restOfPath == '/') + { + restOfPath++; // get rid of '/' + } + + *name = restOfPath; + i = 0; + + while(*restOfPath && *restOfPath != '/') + { + if (i < YAFFS_MAX_NAME_LENGTH) + { + str[i] = *restOfPath; + str[i+1] = '\0'; + i++; + } + restOfPath++; + } + + if(!*restOfPath) + { + // got to the end of the string + return dir; + } + else + { + if(strcmp(str,".") == 0) + { + // Do nothing + } + else if(strcmp(str,"..") == 0) + { + dir = dir->parent; + } + else + { + dir = yaffs_FindObjectByName(dir,str); + + while(dir && dir->variantType == YAFFS_OBJECT_TYPE_SYMLINK) + { + + dir = yaffsfs_FollowLink(dir,symDepth); + + } + + if(dir && dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) + { + dir = NULL; + } + } + } + } + // directory did not exist. + return NULL; +} + +static yaffs_Object *yaffsfs_FindDirectory(yaffs_Object *relativeDirectory,const char *path,char **name,int symDepth) +{ + return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth); +} + +// yaffsfs_FindObject turns a path for an existing object into the object +// +static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path,int symDepth) +{ + yaffs_Object *dir; + char *name; + + dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth); + + if(dir && *name) + { + return yaffs_FindObjectByName(dir,name); + } + + return dir; +} + + + +int yaffs_open(const char *path, int oflag, int mode) +{ + yaffs_Object *obj = NULL; + yaffs_Object *dir = NULL; + char *name; + int handle = -1; + yaffsfs_Handle *h = NULL; + int alreadyOpen = 0; + int alreadyExclusive = 0; + int openDenied = 0; + int symDepth = 0; + int errorReported = 0; + + int i; + + + // todo sanity check oflag (eg. can't have O_TRUNC without WRONLY or RDWR + + + yaffsfs_Lock(); + + handle = yaffsfs_GetHandle(); + + if(handle >= 0) + { + + h = yaffsfs_GetHandlePointer(handle); + + + // try to find the exisiting object + obj = yaffsfs_FindObject(NULL,path,0); + + if(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) + { + + obj = yaffsfs_FollowLink(obj,symDepth++); + } + + if(obj) + { + // Check if the object is already in use + alreadyOpen = alreadyExclusive = 0; + + for(i = 0; i <= YAFFSFS_N_HANDLES; i++) + { + + if(i != handle && + yaffsfs_handle[i].inUse && + obj == yaffsfs_handle[i].obj) + { + alreadyOpen = 1; + if(yaffsfs_handle[i].exclusive) + { + alreadyExclusive = 1; + } + } + } + + if(((oflag & O_EXCL) && alreadyOpen) || alreadyExclusive) + { + openDenied = 1; + } + + // Open should fail if O_CREAT and O_EXCL are specified + if((oflag & O_EXCL) && (oflag & O_CREAT)) + { + openDenied = 1; + yaffsfs_SetError(-EEXIST); + errorReported = 1; + } + + // Check file permissions + if( (oflag & (O_RDWR | O_WRONLY)) == 0 && // ie O_RDONLY + !(obj->yst_mode & S_IREAD)) + { + openDenied = 1; + } + + if( (oflag & O_RDWR) && + !(obj->yst_mode & S_IREAD)) + { + openDenied = 1; + } + + if( (oflag & (O_RDWR | O_WRONLY)) && + !(obj->yst_mode & S_IWRITE)) + { + openDenied = 1; + } + + } + + else if((oflag & O_CREAT)) + { + // Let's see if we can create this file + dir = yaffsfs_FindDirectory(NULL,path,&name,0); + if(dir) + { + obj = yaffs_MknodFile(dir,name,mode,0,0); + } + else + { + yaffsfs_SetError(-ENOTDIR); + } + } + + if(obj && !openDenied) + { + h->obj = obj; + h->inUse = 1; + h->readOnly = (oflag & (O_WRONLY | O_RDWR)) ? 0 : 1; + h->append = (oflag & O_APPEND) ? 1 : 0; + h->exclusive = (oflag & O_EXCL) ? 1 : 0; + h->position = 0; + + obj->inUse++; + if((oflag & O_TRUNC) && !h->readOnly) + { + //todo truncate + yaffs_ResizeFile(obj,0); + } + + } + else + { + yaffsfs_PutHandle(handle); + if(!errorReported) + { + yaffsfs_SetError(-EACCESS); + errorReported = 1; + } + handle = -1; + } + + } + + yaffsfs_Unlock(); + + return handle; +} + +int yaffs_close(int fd) +{ + yaffsfs_Handle *h = NULL; + int retVal = 0; + + yaffsfs_Lock(); + + h = yaffsfs_GetHandlePointer(fd); + + if(h && h->inUse) + { + // clean up + yaffs_FlushFile(h->obj,1); + h->obj->inUse--; + if(h->obj->inUse <= 0 && h->obj->unlinked) + { + yaffs_DeleteFile(h->obj); + } + yaffsfs_PutHandle(fd); + retVal = 0; + } + else + { + // bad handle + yaffsfs_SetError(-EBADF); + retVal = -1; + } + + yaffsfs_Unlock(); + + return retVal; +} + +int yaffs_read(int fd, void *buf, unsigned int nbyte) +{ + yaffsfs_Handle *h = NULL; + yaffs_Object *obj = NULL; + int pos = 0; + int nRead = -1; + int maxRead; + + yaffsfs_Lock(); + h = yaffsfs_GetHandlePointer(fd); + obj = yaffsfs_GetHandleObject(fd); + + if(!h || !obj) + { + // bad handle + yaffsfs_SetError(-EBADF); + } + else if( h && obj) + { + pos= h->position; + if(yaffs_GetObjectFileLength(obj) > pos) + { + maxRead = yaffs_GetObjectFileLength(obj) - pos; + } + else + { + maxRead = 0; + } + + if(nbyte > maxRead) + { + nbyte = maxRead; + } + + + if(nbyte > 0) + { + nRead = yaffs_ReadDataFromFile(obj,buf,pos,nbyte); + if(nRead >= 0) + { + h->position = pos + nRead; + } + else + { + //todo error + } + } + else + { + nRead = 0; + } + + } + + yaffsfs_Unlock(); + + + return (nRead >= 0) ? nRead : -1; + +} + +int yaffs_write(int fd, const void *buf, unsigned int nbyte) +{ + yaffsfs_Handle *h = NULL; + yaffs_Object *obj = NULL; + int pos = 0; + int nWritten = -1; + int writeThrough = 0; + + yaffsfs_Lock(); + h = yaffsfs_GetHandlePointer(fd); + obj = yaffsfs_GetHandleObject(fd); + + if(!h || !obj) + { + // bad handle + yaffsfs_SetError(-EBADF); + } + else if( h && obj && h->readOnly) + { + // todo error + } + else if( h && obj) + { + if(h->append) + { + pos = yaffs_GetObjectFileLength(obj); + } + else + { + pos = h->position; + } + + nWritten = yaffs_WriteDataToFile(obj,buf,pos,nbyte,writeThrough); + + if(nWritten >= 0) + { + h->position = pos + nWritten; + } + else + { + //todo error + } + + } + + yaffsfs_Unlock(); + + + return (nWritten >= 0) ? nWritten : -1; + +} + +int yaffs_truncate(int fd, off_t newSize) +{ + yaffsfs_Handle *h = NULL; + yaffs_Object *obj = NULL; + int result = 0; + + yaffsfs_Lock(); + h = yaffsfs_GetHandlePointer(fd); + obj = yaffsfs_GetHandleObject(fd); + + if(!h || !obj) + { + // bad handle + yaffsfs_SetError(-EBADF); + } + else + { + // resize the file + result = yaffs_ResizeFile(obj,newSize); + } + yaffsfs_Unlock(); + + + return (result) ? 0 : -1; + +} + +off_t yaffs_lseek(int fd, off_t offset, int whence) +{ + yaffsfs_Handle *h = NULL; + yaffs_Object *obj = NULL; + int pos = -1; + int fSize = -1; + + yaffsfs_Lock(); + h = yaffsfs_GetHandlePointer(fd); + obj = yaffsfs_GetHandleObject(fd); + + if(!h || !obj) + { + // bad handle + yaffsfs_SetError(-EBADF); + } + else if(whence == SEEK_SET) + { + if(offset >= 0) + { + pos = offset; + } + } + else if(whence == SEEK_CUR) + { + if( (h->position + offset) >= 0) + { + pos = (h->position + offset); + } + } + else if(whence == SEEK_END) + { + fSize = yaffs_GetObjectFileLength(obj); + if(fSize >= 0 && (fSize + offset) >= 0) + { + pos = fSize + offset; + } + } + + if(pos >= 0) + { + h->position = pos; + } + else + { + // todo error + } + + + yaffsfs_Unlock(); + + return pos; +} + + +int yaffsfs_DoUnlink(const char *path,int isDirectory) +{ + yaffs_Object *dir = NULL; + yaffs_Object *obj = NULL; + char *name; + int result = YAFFS_FAIL; + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL,path,0); + dir = yaffsfs_FindDirectory(NULL,path,&name,0); + if(!dir) + { + yaffsfs_SetError(-ENOTDIR); + } + else if(!obj) + { + yaffsfs_SetError(-ENOENT); + } + else if(!isDirectory && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) + { + yaffsfs_SetError(-EISDIR); + } + else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) + { + yaffsfs_SetError(-ENOTDIR); + } + else + { + result = yaffs_Unlink(dir,name); + + if(result == YAFFS_FAIL && isDirectory) + { + yaffsfs_SetError(-ENOTEMPTY); + } + } + + yaffsfs_Unlock(); + + // todo error + + return (result == YAFFS_FAIL) ? -1 : 0; +} +int yaffs_rmdir(const char *path) +{ + return yaffsfs_DoUnlink(path,1); +} + +int yaffs_unlink(const char *path) +{ + return yaffsfs_DoUnlink(path,0); +} + +int yaffs_rename(const char *oldPath, const char *newPath) +{ + yaffs_Object *olddir = NULL; + yaffs_Object *newdir = NULL; + yaffs_Object *obj = NULL; + char *oldname; + char *newname; + int result= YAFFS_FAIL; + int renameAllowed = 1; + + yaffsfs_Lock(); + + olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0); + newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0); + obj = yaffsfs_FindObject(NULL,oldPath,0); + + if(!olddir || !newdir || !obj) + { + // bad file + yaffsfs_SetError(-EBADF); + renameAllowed = 0; + } + else if(olddir->myDev != newdir->myDev) + { + // oops must be on same device + // todo error + yaffsfs_SetError(-EXDEV); + renameAllowed = 0; + } + else if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) + { + // It is a directory, check that it is not being renamed to + // being its own decendent. + // Do this by tracing from the new directory back to the root, checking for obj + + yaffs_Object *xx = newdir; + + while( renameAllowed && xx) + { + if(xx == obj) + { + renameAllowed = 0; + } + xx = xx->parent; + } + if(!renameAllowed) yaffsfs_SetError(-EACCESS); + } + + if(renameAllowed) + { + result = yaffs_RenameObject(olddir,oldname,newdir,newname); + } + + yaffsfs_Unlock(); + + return (result == YAFFS_FAIL) ? -1 : 0; +} + + +static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf) +{ + int retVal = -1; + + if(obj) + { + obj = yaffs_GetEquivalentObject(obj); + } + + if(obj && buf) + { + buf->st_dev = (int)obj->myDev->genericDevice; + buf->st_ino = obj->objectId; + buf->st_mode = obj->yst_mode & ~S_IFMT; // clear out file type bits + + if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) + { + buf->st_mode |= S_IFDIR; + } + else if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) + { + buf->st_mode |= S_IFLNK; + } + else if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) + { + buf->st_mode |= S_IFREG; + } + + buf->st_nlink = yaffs_GetObjectLinkCount(obj); + buf->st_uid = 0; + buf->st_gid = 0;; + buf->st_rdev = obj->yst_rdev; + buf->st_size = yaffs_GetObjectFileLength(obj); + buf->st_blksize = obj->myDev->nDataBytesPerChunk; + buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize; + buf->yst_atime = obj->yst_atime; + buf->yst_ctime = obj->yst_ctime; + buf->yst_mtime = obj->yst_mtime; + retVal = 0; + } + return retVal; +} + +static int yaffsfs_DoStatOrLStat(const char *path, struct yaffs_stat *buf,int doLStat) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_FindObject(NULL,path,0); + + if(!doLStat && obj) + { + obj = yaffsfs_FollowLink(obj,0); + } + + if(obj) + { + retVal = yaffsfs_DoStat(obj,buf); + } + else + { + // todo error not found + yaffsfs_SetError(-ENOENT); + } + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_stat(const char *path, struct yaffs_stat *buf) +{ + return yaffsfs_DoStatOrLStat(path,buf,0); +} + +int yaffs_lstat(const char *path, struct yaffs_stat *buf) +{ + return yaffsfs_DoStatOrLStat(path,buf,1); +} + +int yaffs_fstat(int fd, struct yaffs_stat *buf) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_GetHandleObject(fd); + + if(obj) + { + retVal = yaffsfs_DoStat(obj,buf); + } + else + { + // bad handle + yaffsfs_SetError(-EBADF); + } + + yaffsfs_Unlock(); + + return retVal; +} + +static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode) +{ + int result; + + if(obj) + { + obj = yaffs_GetEquivalentObject(obj); + } + + if(obj) + { + obj->yst_mode = mode; + obj->dirty = 1; + result = yaffs_FlushFile(obj,0); + } + + return result == YAFFS_OK ? 0 : -1; +} + + +int yaffs_chmod(const char *path, mode_t mode) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_FindObject(NULL,path,0); + + if(obj) + { + retVal = yaffsfs_DoChMod(obj,mode); + } + else + { + // todo error not found + yaffsfs_SetError(-ENOENT); + } + + yaffsfs_Unlock(); + + return retVal; + +} + + +int yaffs_fchmod(int fd, mode_t mode) +{ + yaffs_Object *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_GetHandleObject(fd); + + if(obj) + { + retVal = yaffsfs_DoChMod(obj,mode); + } + else + { + // bad handle + yaffsfs_SetError(-EBADF); + } + + yaffsfs_Unlock(); + + return retVal; +} + + +int yaffs_mkdir(const char *path, mode_t mode) +{ + yaffs_Object *parent = NULL; + yaffs_Object *dir = NULL; + char *name; + int retVal= -1; + + yaffsfs_Lock(); + parent = yaffsfs_FindDirectory(NULL,path,&name,0); + if(parent) + dir = yaffs_MknodDirectory(parent,name,mode,0,0); + if(dir) + { + retVal = 0; + } + else + { + yaffsfs_SetError(-ENOSPC); // just assume no space for now + retVal = -1; + } + + yaffsfs_Unlock(); + + return retVal; +} + +int yaffs_mount(const char *path) +{ + int retVal=-1; + int result=YAFFS_FAIL; + yaffs_Device *dev=NULL; + char *dummy; + + T(YAFFS_TRACE_ALWAYS,("yaffs: Mounting %s\n",path)); + + yaffsfs_Lock(); + dev = yaffsfs_FindDevice(path,&dummy); + if(dev) + { + if(!dev->isMounted) + { + result = yaffs_GutsInitialise(dev); + if(result == YAFFS_FAIL) + { + // todo error - mount failed + yaffsfs_SetError(-ENOMEM); + } + retVal = result ? 0 : -1; + + } + else + { + //todo error - already mounted. + yaffsfs_SetError(-EBUSY); + } + } + else + { + // todo error - no device + yaffsfs_SetError(-ENODEV); + } + yaffsfs_Unlock(); + return retVal; + +} + +int yaffs_unmount(const char *path) +{ + int retVal=-1; + yaffs_Device *dev=NULL; + char *dummy; + + yaffsfs_Lock(); + dev = yaffsfs_FindDevice(path,&dummy); + if(dev) + { + if(dev->isMounted) + { + int i; + int inUse; + + yaffs_FlushEntireDeviceCache(dev); + yaffs_CheckpointSave(dev); + + for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++) + { + if(yaffsfs_handle[i].inUse && yaffsfs_handle[i].obj->myDev == dev) + { + inUse = 1; // the device is in use, can't unmount + } + } + + if(!inUse) + { + yaffs_Deinitialise(dev); + + retVal = 0; + } + else + { + // todo error can't unmount as files are open + yaffsfs_SetError(-EBUSY); + } + + } + else + { + //todo error - not mounted. + yaffsfs_SetError(-EINVAL); + + } + } + else + { + // todo error - no device + yaffsfs_SetError(-ENODEV); + } + yaffsfs_Unlock(); + return retVal; + +} + +loff_t yaffs_freespace(const char *path) +{ + loff_t retVal=-1; + yaffs_Device *dev=NULL; + char *dummy; + + yaffsfs_Lock(); + dev = yaffsfs_FindDevice(path,&dummy); + if(dev && dev->isMounted) + { + retVal = yaffs_GetNumberOfFreeChunks(dev); + retVal *= dev->nDataBytesPerChunk; + + } + else + { + yaffsfs_SetError(-EINVAL); + } + + yaffsfs_Unlock(); + return retVal; +} + + + +void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList) +{ + + yaffsfs_DeviceConfiguration *cfg; + + yaffsfs_configurationList = cfgList; + + yaffsfs_InitHandles(); + + cfg = yaffsfs_configurationList; + + while(cfg && cfg->prefix && cfg->dev) + { + cfg->dev->isMounted = 0; + cfg->dev->removeObjectCallback = yaffsfs_RemoveObjectCallback; + cfg++; + } + + +} + + +// +// Directory search stuff. + +// +// Directory search context +// +// NB this is an opaque structure. + + +typedef struct +{ + __u32 magic; + yaffs_dirent de; /* directory entry being used by this dsc */ + char name[NAME_MAX+1]; /* name of directory being searched */ + yaffs_Object *dirObj; /* ptr to directory being searched */ + yaffs_Object *nextReturn; /* obj to be returned by next readddir */ + int offset; + struct list_head others; +} yaffsfs_DirectorySearchContext; + + + +static struct list_head search_contexts; + + +static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc) +{ + if(dsc && + dsc->dirObj && + dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){ + + dsc->offset = 0; + + if( list_empty(&dsc->dirObj->variant.directoryVariant.children)){ + dsc->nextReturn = NULL; + } else { + dsc->nextReturn = list_entry(dsc->dirObj->variant.directoryVariant.children.next, + yaffs_Object,siblings); + } + } else { + /* Hey someone isn't playing nice! */ + } +} + +static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc) +{ + if(dsc && + dsc->dirObj && + dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){ + + if( dsc->nextReturn == NULL || + list_empty(&dsc->dirObj->variant.directoryVariant.children)){ + dsc->nextReturn = NULL; + } else { + struct list_head *next = dsc->nextReturn->siblings.next; + + if( next == &dsc->dirObj->variant.directoryVariant.children) + dsc->nextReturn = NULL; /* end of list */ + else + dsc->nextReturn = list_entry(next,yaffs_Object,siblings); + } + } else { + /* Hey someone isn't playing nice! */ + } +} + +static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj) +{ + + struct list_head *i; + yaffsfs_DirectorySearchContext *dsc; + + /* if search contexts not initilised then skip */ + if(!search_contexts.next) + return; + + /* Iteratethrough the directory search contexts. + * If any are the one being removed, then advance the dsc to + * the next one to prevent a hanging ptr. + */ + list_for_each(i, &search_contexts) { + if (i) { + dsc = list_entry(i, yaffsfs_DirectorySearchContext,others); + if(dsc->nextReturn == obj) + yaffsfs_DirAdvance(dsc); + } + } + +} + +yaffs_DIR *yaffs_opendir(const char *dirname) +{ + yaffs_DIR *dir = NULL; + yaffs_Object *obj = NULL; + yaffsfs_DirectorySearchContext *dsc = NULL; + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL,dirname,0); + + if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) + { + + dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext)); + dir = (yaffs_DIR *)dsc; + if(dsc) + { + memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext)); + dsc->magic = YAFFS_MAGIC; + dsc->dirObj = obj; + strncpy(dsc->name,dirname,NAME_MAX); + INIT_LIST_HEAD(&dsc->others); + + if(!search_contexts.next) + INIT_LIST_HEAD(&search_contexts); + + list_add(&dsc->others,&search_contexts); + yaffsfs_SetDirRewound(dsc); } + + } + + yaffsfs_Unlock(); + + return dir; +} + +struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) +{ + yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp; + struct yaffs_dirent *retVal = NULL; + + yaffsfs_Lock(); + + if(dsc && dsc->magic == YAFFS_MAGIC){ + yaffsfs_SetError(0); + if(dsc->nextReturn){ + dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId; + dsc->de.d_dont_use = (unsigned)dsc->nextReturn; + dsc->de.d_off = dsc->offset++; + yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX); + if(strlen(dsc->de.d_name) == 0) + { + // this should not happen! + strcpy(dsc->de.d_name,"zz"); + } + dsc->de.d_reclen = sizeof(struct yaffs_dirent); + retVal = &dsc->de; + yaffsfs_DirAdvance(dsc); + } else + retVal = NULL; + } + else + { + yaffsfs_SetError(-EBADF); + } + + yaffsfs_Unlock(); + + return retVal; + +} + + +void yaffs_rewinddir(yaffs_DIR *dirp) +{ + yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp; + + yaffsfs_Lock(); + + yaffsfs_SetDirRewound(dsc); + + yaffsfs_Unlock(); +} + + +int yaffs_closedir(yaffs_DIR *dirp) +{ + yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp; + + yaffsfs_Lock(); + dsc->magic = 0; + list_del(&dsc->others); /* unhook from list */ + YFREE(dsc); + yaffsfs_Unlock(); + return 0; +} + +// end of directory stuff + + +int yaffs_symlink(const char *oldpath, const char *newpath) +{ + yaffs_Object *parent = NULL; + yaffs_Object *obj; + char *name; + int retVal= -1; + int mode = 0; // ignore for now + + yaffsfs_Lock(); + parent = yaffsfs_FindDirectory(NULL,newpath,&name,0); + obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath); + if(obj) + { + retVal = 0; + } + else + { + yaffsfs_SetError(-ENOSPC); // just assume no space for now + retVal = -1; + } + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_readlink(const char *path, char *buf, int bufsiz) +{ + yaffs_Object *obj = NULL; + int retVal; + + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL,path,0); + + if(!obj) + { + yaffsfs_SetError(-ENOENT); + retVal = -1; + } + else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK) + { + yaffsfs_SetError(-EINVAL); + retVal = -1; + } + else + { + char *alias = obj->variant.symLinkVariant.alias; + memset(buf,0,bufsiz); + strncpy(buf,alias,bufsiz - 1); + retVal = 0; + } + yaffsfs_Unlock(); + return retVal; +} + +int yaffs_link(const char *oldpath, const char *newpath) +{ + // Creates a link called newpath to existing oldpath + yaffs_Object *obj = NULL; + yaffs_Object *target = NULL; + int retVal = 0; + + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL,oldpath,0); + target = yaffsfs_FindObject(NULL,newpath,0); + + if(!obj) + { + yaffsfs_SetError(-ENOENT); + retVal = -1; + } + else if(target) + { + yaffsfs_SetError(-EEXIST); + retVal = -1; + } + else + { + yaffs_Object *newdir = NULL; + yaffs_Object *link = NULL; + + char *newname; + + newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0); + + if(!newdir) + { + yaffsfs_SetError(-ENOTDIR); + retVal = -1; + } + else if(newdir->myDev != obj->myDev) + { + yaffsfs_SetError(-EXDEV); + retVal = -1; + } + if(newdir && strlen(newname) > 0) + { + link = yaffs_Link(newdir,newname,obj); + if(link) + retVal = 0; + else + { + yaffsfs_SetError(-ENOSPC); + retVal = -1; + } + + } + } + yaffsfs_Unlock(); + + return retVal; +} + +int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev); + +int yaffs_DumpDevStruct(const char *path) +{ + char *rest; + + yaffs_Object *obj = yaffsfs_FindRoot(path,&rest); + + if(obj) + { + yaffs_Device *dev = obj->myDev; + + printf("\n" + "nPageWrites.......... %d\n" + "nPageReads........... %d\n" + "nBlockErasures....... %d\n" + "nGCCopies............ %d\n" + "garbageCollections... %d\n" + "passiveGarbageColl'ns %d\n" + "\n", + dev->nPageWrites, + dev->nPageReads, + dev->nBlockErasures, + dev->nGCCopies, + dev->garbageCollections, + dev->passiveGarbageCollections + ); + + } + return 0; +} + diff --git a/fs/yaffs2/direct/yaffsfs.h b/fs/yaffs2/direct/yaffsfs.h new file mode 100644 index 0000000000..9afe60a1ce --- /dev/null +++ b/fs/yaffs2/direct/yaffsfs.h @@ -0,0 +1,233 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * Header file for using yaffs in an application via + * a direct interface. + */ + + +#ifndef __YAFFSFS_H__ +#define __YAFFSFS_H__ + +#include "yaffscfg.h" +#include "yportenv.h" + + +//typedef long off_t; +//typedef long dev_t; +//typedef unsigned long mode_t; + + +#ifndef NAME_MAX +#define NAME_MAX 256 +#endif + +#ifndef O_RDONLY +#define O_RDONLY 00 +#endif + +#ifndef O_WRONLY +#define O_WRONLY 01 +#endif + +#ifndef O_RDWR +#define O_RDWR 02 +#endif + +#ifndef O_CREAT +#define O_CREAT 0100 +#endif + +#ifndef O_EXCL +#define O_EXCL 0200 +#endif + +#ifndef O_TRUNC +#define O_TRUNC 01000 +#endif + +#ifndef O_APPEND +#define O_APPEND 02000 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef EBUSY +#define EBUSY 16 +#endif + +#ifndef ENODEV +#define ENODEV 19 +#endif + +#ifndef EINVAL +#define EINVAL 22 +#endif + +#ifndef EBADF +#define EBADF 9 +#endif + +#ifndef EACCESS +#define EACCESS 13 +#endif + +#ifndef EXDEV +#define EXDEV 18 +#endif + +#ifndef ENOENT +#define ENOENT 2 +#endif + +#ifndef ENOSPC +#define ENOSPC 28 +#endif + +#ifndef ENOTEMPTY +#define ENOTEMPTY 39 +#endif + +#ifndef ENOMEM +#define ENOMEM 12 +#endif + +#ifndef EEXIST +#define EEXIST 17 +#endif + +#ifndef ENOTDIR +#define ENOTDIR 20 +#endif + +#ifndef EISDIR +#define EISDIR 21 +#endif + + +// Mode flags + +#ifndef S_IFMT +#define S_IFMT 0170000 +#endif + +#ifndef S_IFLNK +#define S_IFLNK 0120000 +#endif + +#ifndef S_IFDIR +#define S_IFDIR 0040000 +#endif + +#ifndef S_IFREG +#define S_IFREG 0100000 +#endif + +#ifndef S_IREAD +#define S_IREAD 0000400 +#endif + +#ifndef S_IWRITE +#define S_IWRITE 0000200 +#endif + + + + +struct yaffs_dirent{ + long d_ino; /* inode number */ + off_t d_off; /* offset to this dirent */ + unsigned short d_reclen; /* length of this d_name */ + char d_name [NAME_MAX+1]; /* file name (null-terminated) */ + unsigned d_dont_use; /* debug pointer, not for public consumption */ +}; + +typedef struct yaffs_dirent yaffs_dirent; + + +typedef struct __opaque yaffs_DIR; + + + +struct yaffs_stat{ + int st_dev; /* device */ + int st_ino; /* inode */ + mode_t st_mode; /* protection */ + int st_nlink; /* number of hard links */ + int st_uid; /* user ID of owner */ + int st_gid; /* group ID of owner */ + unsigned st_rdev; /* device type (if inode device) */ + off_t st_size; /* total size, in bytes */ + unsigned long st_blksize; /* blocksize for filesystem I/O */ + unsigned long st_blocks; /* number of blocks allocated */ + unsigned long yst_atime; /* time of last access */ + unsigned long yst_mtime; /* time of last modification */ + unsigned long yst_ctime; /* time of last change */ +}; + +int yaffs_open(const char *path, int oflag, int mode) ; +int yaffs_read(int fd, void *buf, unsigned int nbyte) ; +int yaffs_write(int fd, const void *buf, unsigned int nbyte) ; +int yaffs_close(int fd) ; +off_t yaffs_lseek(int fd, off_t offset, int whence) ; +int yaffs_truncate(int fd, off_t newSize); + +int yaffs_unlink(const char *path) ; +int yaffs_rename(const char *oldPath, const char *newPath) ; + +int yaffs_stat(const char *path, struct yaffs_stat *buf) ; +int yaffs_lstat(const char *path, struct yaffs_stat *buf) ; +int yaffs_fstat(int fd, struct yaffs_stat *buf) ; + +int yaffs_chmod(const char *path, mode_t mode); +int yaffs_fchmod(int fd, mode_t mode); + +int yaffs_mkdir(const char *path, mode_t mode) ; +int yaffs_rmdir(const char *path) ; + +yaffs_DIR *yaffs_opendir(const char *dirname) ; +struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) ; +void yaffs_rewinddir(yaffs_DIR *dirp) ; +int yaffs_closedir(yaffs_DIR *dirp) ; + +int yaffs_mount(const char *path) ; +int yaffs_unmount(const char *path) ; + +int yaffs_symlink(const char *oldpath, const char *newpath); +int yaffs_readlink(const char *path, char *buf, int bufsiz); + +int yaffs_link(const char *oldpath, const char *newpath); +int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev); + +loff_t yaffs_freespace(const char *path); + +void yaffs_initialise(yaffsfs_DeviceConfiguration *configList); + +int yaffs_StartUp(void); + +#endif + + diff --git a/fs/yaffs2/direct/ydirectenv.h b/fs/yaffs2/direct/ydirectenv.h new file mode 100644 index 0000000000..0c2820579e --- /dev/null +++ b/fs/yaffs2/direct/ydirectenv.h @@ -0,0 +1,88 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * ydirectenv.h: Environment wrappers for YAFFS direct. + */ + +#ifndef __YDIRECTENV_H__ +#define __YDIRECTENV_H__ + +// Direct interface + +#include "devextras.h" + +#include "stdlib.h" +#include "stdio.h" +#include "string.h" +#include "yaffs_malloc.h" + +#include "assert.h" +#define YBUG() assert(1) + +#define YCHAR char +#define YUCHAR unsigned char +#define _Y(x) x +#define yaffs_strcpy(a,b) strcpy(a,b) +#define yaffs_strncpy(a,b,c) strncpy(a,b,c) +#define yaffs_strncmp(a,b,c) strncmp(a,b,c) +#define yaffs_strlen(s) strlen(s) +#define yaffs_sprintf sprintf +#define yaffs_toupper(a) toupper(a) + +#ifdef NO_Y_INLINE +#define Y_INLINE +#else +#define Y_INLINE inline +#endif + +#define YMALLOC(x) yaffs_malloc(x) +#define YFREE(x) free(x) +#define YMALLOC_ALT(x) yaffs_malloc(x) +#define YFREE_ALT(x) free(x) + +#define YMALLOC_DMA(x) yaffs_malloc(x) + +#define YYIELD() do {} while(0) + + + +//#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 Y_CURRENT_TIME yaffsfs_CurrentTime() +#define Y_TIME_CONVERT(x) x + +#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) + +#endif + + |