Mercurial > yaffs-ecoscentric
changeset 353:fa7270d25c51
Merge from upstream
| author | Ross Younger <wry@ecoscentric.com> |
|---|---|
| date | Tue, 17 Nov 2009 10:49:51 +0000 |
| parents | 73b6efce8c58 (diff) 88c898910859 (current diff) |
| children | 68aafa1d2927 |
| files | linux-tests/initnandsim linux-tests/mkdirtree packages/fs/yaffs/current/ChangeLog packages/fs/yaffs/current/src/yaffs_checkptrw.c packages/fs/yaffs/current/src/yaffs_guts.c packages/fs/yaffs/current/src/yaffs_guts.h |
| diffstat | 111 files changed, 9087 insertions(+), 17740 deletions(-) [+] |
line wrap: on
line diff
deleted file mode 100644 --- a/Kconfig +++ /dev/null @@ -1,177 +0,0 @@ -# -# YAFFS file system configurations -# - -config YAFFS_FS - tristate "YAFFS2 file system support" - default n - depends on MTD_BLOCK - select YAFFS_YAFFS1 - select YAFFS_YAFFS2 - help - YAFFS2, or Yet Another Flash Filing System, is a filing system - optimised for NAND Flash chips. - - To compile the YAFFS2 file system support as a module, choose M - here: the module will be called yaffs2. - - If unsure, say N. - - Further information on YAFFS2 is available at - <http://www.aleph1.co.uk/yaffs/>. - -config YAFFS_YAFFS1 - bool "512 byte / page devices" - depends on YAFFS_FS - default y - help - Enable YAFFS1 support -- yaffs for 512 byte / page devices - - Not needed for 2K-page devices. - - If unsure, say Y. - -config YAFFS_9BYTE_TAGS - bool "Use older-style on-NAND data format with pageStatus byte" - depends on YAFFS_YAFFS1 - default n - help - - Older-style on-NAND data format has a "pageStatus" byte to record - chunk/page state. This byte is zero when the page is discarded. - Choose this option if you have existing on-NAND data using this - format that you need to continue to support. New data written - also uses the older-style format. Note: Use of this option - generally requires that MTD's oob layout be adjusted to use the - older-style format. See notes on tags formats and MTD versions - in yaffs_mtdif1.c. - - If unsure, say N. - -config YAFFS_DOES_ECC - bool "Lets Yaffs do its own ECC" - depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS - default n - help - This enables Yaffs to use its own ECC functions instead of using - the ones from the generic MTD-NAND driver. - - If unsure, say N. - -config YAFFS_ECC_WRONG_ORDER - bool "Use the same ecc byte order as Steven Hill's nand_ecc.c" - depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS - default n - help - This makes yaffs_ecc.c use the same ecc byte order as Steven - Hill's nand_ecc.c. If not set, then you get the same ecc byte - order as SmartMedia. - - If unsure, say N. - -config YAFFS_YAFFS2 - bool "2048 byte (or larger) / page devices" - depends on YAFFS_FS - default y - help - Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices - - If unsure, say Y. - -config YAFFS_AUTO_YAFFS2 - bool "Autoselect yaffs2 format" - depends on YAFFS_YAFFS2 - default y - help - Without this, you need to explicitely use yaffs2 as the file - system type. With this, you can say "yaffs" and yaffs or yaffs2 - will be used depending on the device page size (yaffs on - 512-byte page devices, yaffs2 on 2K page devices). - - If unsure, say Y. - -config YAFFS_DISABLE_TAGS_ECC - bool "Disable YAFFS from doing ECC on tags by default" - depends on YAFFS_FS && YAFFS_YAFFS2 - default n - help - This defaults Yaffs to using its own ECC calculations on tags instead of - just relying on the MTD. - This behavior can also be overridden with tags_ecc_on and - tags_ecc_off mount options. - - If unsure, say N. - -config YAFFS_DISABLE_LAZY_LOAD - bool "Disable lazy loading" - depends on YAFFS_YAFFS2 - default n - help - "Lazy loading" defers loading file details until they are - required. This saves mount time, but makes the first look-up - a bit longer. - - Lazy loading will only happen if enabled by this option being 'n' - and if the appropriate tags are available, else yaffs2 will - automatically fall back to immediate loading and do the right - thing. - - Lazy laoding will be required by checkpointing. - - Setting this to 'y' will disable lazy loading. - - If unsure, say N. - - -config YAFFS_DISABLE_WIDE_TNODES - bool "Turn off wide tnodes" - depends on YAFFS_FS - default n - help - Wide tnodes are only used for NAND arrays >=32MB for 512-byte - page devices and >=128MB for 2k page devices. They use slightly - more RAM but are faster since they eliminate chunk group - searching. - - Setting this to 'y' will force tnode width to 16 bits and save - memory but make large arrays slower. - - If unsure, say N. - -config YAFFS_ALWAYS_CHECK_CHUNK_ERASED - bool "Force chunk erase check" - depends on YAFFS_FS - default n - help - Normally YAFFS only checks chunks before writing until an erased - chunk is found. This helps to detect any partially written - chunks that might have happened due to power loss. - - Enabling this forces on the test that chunks are erased in flash - before writing to them. This takes more time but is potentially - a bit more secure. - - Suggest setting Y during development and ironing out driver - issues etc. Suggest setting to N if you want faster writing. - - If unsure, say Y. - -config YAFFS_SHORT_NAMES_IN_RAM - bool "Cache short names in RAM" - depends on YAFFS_FS - default y - help - If this config is set, then short names are stored with the - yaffs_Object. This costs an extra 16 bytes of RAM per object, - but makes look-ups faster. - - If unsure, say Y. - -config YAFFS_EMPTY_LOST_AND_FOUND - bool "Empty lost and found on boot" - depends on YAFFS_FS - default n - help - If this is enabled then the contents of lost and found is - automatically dumped at mount. -
deleted file mode 100644 --- a/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# Main Makefile for YAFFS -# -# -# 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. - - -ifneq ($(KERNELRELEASE),) - EXTRA_CFLAGS += -DYAFFS_OUT_OF_TREE - - obj-m := yaffs2.o - - yaffs2-objs := yaffs_mtdif.o yaffs_mtdif2.o - yaffs2-objs += yaffs_mtdif1.o yaffs_packedtags1.o - yaffs2-objs += yaffs_ecc.o yaffs_fs.o yaffs_guts.o - yaffs2-objs += yaffs_packedtags2.o yaffs_qsort.o - yaffs2-objs += yaffs_tagscompat.o yaffs_tagsvalidity.o - yaffs2-objs += yaffs_checkptrw.o yaffs_nand.o - -else - KERNELDIR ?= /lib/modules/$(shell uname -r)/build - PWD := $(shell pwd) - -modules default: - $(MAKE) -C $(KERNELDIR) M=$(PWD) modules - -mi modules_install: - $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install - -clean: - $(MAKE) -C $(KERNELDIR) M=$(PWD) clean -endif
deleted file mode 100644 --- a/Makefile.kernel +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for the linux YAFFS filesystem routines. -# - -obj-$(CONFIG_YAFFS_FS) += yaffs.o - -yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o -yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o -yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o -yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
deleted file mode 100644 --- a/README-linux +++ /dev/null @@ -1,201 +0,0 @@ -Welcome to YAFFS, the first file system developed specifically for NAND flash. - -It is now YAFFS2 - original YAFFS (AYFFS1) only supports 512-byte page -NAND and is now deprecated. YAFFS2 supports 512b page in 'YAFFS1 -compatibility' mode (CONFIG_YAFFS_YAFFS1) and 2K or larger page NAND -in YAFFS2 mode (CONFIG_YAFFS_YAFFS2). - - -A note on licencing -------------------- -YAFFS is available under the GPL and via alternative licensing -arrangements with Aleph One. If you're using YAFFS as a Linux kernel -file system then it will be under the GPL. For use in other situations -you should discuss licensing issues with Aleph One. - - -Terminology ------------ -Page - NAND addressable unit (normally 512b or 2Kbyte size) - can - be read, written, marked bad. Has associated OOB. -Block - Eraseable unit. 64 Pages. (128K on 2K NAND, 32K on 512b NAND) -OOB - 'spare area' of each page for ECC, bad block marked and YAFFS - tags. 16 bytes per 512b - 64 bytes for 2K page size. -Chunk - Basic YAFFS addressable unit. Same size as Page. -Object - YAFFS Object: File, Directory, Link, Device etc. - -YAFFS design ------------- - -YAFFS is a log-structured filesystem. It is designed particularly for -NAND (as opposed to NOR) flash, to be flash-friendly, robust due to -journalling, and to have low RAM and boot time overheads. File data is -stored in 'chunks'. Chunks are the same size as NAND pages. Each page -is marked with file id and chunk number. These marking 'tags' are -stored in the OOB (or 'spare') region of the flash. The chunk number -is determined by dividing the file position by the chunk size. Each -chunk has a number of valid bytes, which equals the page size for all -except the last chunk in a file. - -File 'headers' are stored as the first page in a file, marked as a -different type to data pages. The same mechanism is used to store -directories, device files, links etc. The first page describes which -type of object it is. - -YAFFS2 never re-writes a page, because the spec of NAND chips does not -allow it. (YAFFS1 used to mark a block 'deleted' in the OOB). Deletion -is managed by moving deleted objects to the special, hidden 'unlinked' -directory. These records are preserved until all the pages containing -the object have been erased (We know when this happen by keeping a -count of chunks remaining on the system for each object - when it -reaches zero the object really is gone). - -When data in a file is overwritten, the relevant chunks are replaced -by writing new pages to flash containing the new data but the same -tags. - -Pages are also marked with a short (2 bit) serial number that -increments each time the page at this position is incremented. The -reason for this is that if power loss/crash/other act of demonic -forces happens before the replaced page is marked as discarded, it is -possible to have two pages with the same tags. The serial number is -used to arbitrate. - -A block containing only discarded pages (termed a dirty block) is an -obvious candidate for garbage collection. Otherwise valid pages can be -copied off a block thus rendering the whole block discarded and ready -for garbage collection. - -In theory you don't need to hold the file structure in RAM... you -could just scan the whole flash looking for pages when you need them. -In practice though you'd want better file access times than that! The -mechanism proposed here is to have a list of __u16 page addresses -associated with each file. Since there are 2^18 pages in a 128MB NAND, -a __u16 is insufficient to uniquely identify a page but is does -identify a group of 4 pages - a small enough region to search -exhaustively. This mechanism is clearly expandable to larger NAND -devices - within reason. The RAM overhead with this approach is approx -2 bytes per page - 512kB of RAM for a whole 128MB NAND. - -Boot-time scanning to build the file structure lists only requires -one pass reading NAND. If proper shutdowns happen the current RAM -summary of the filesystem status is saved to flash, called -'checkpointing'. This saves re-scanning the flash on startup, and gives -huge boot/mount time savings. - -YAFFS regenerates its state by 'replaying the tape' - i.e. by -scanning the chunks in their allocation order (i.e. block sequence ID -order), which is usually different form the media block order. Each -block is still only read once - starting from the end of the media and -working back. - -YAFFS tags in YAFFS1 mode: - -18-bit Object ID (2^18 files, i.e. > 260,000 files). File id 0- is not - valid and indicates a deleted page. File od 0x3ffff is also not valid. - Synonymous with inode. -2-bit serial number -20-bit Chunk ID within file. Limit of 2^20 chunks/pages per file (i.e. - > 500MB max file size). Chunk ID 0 is the file header for the file. -10-bit counter of the number of bytes used in the page. -12 bit ECC on tags - -YAFFS tags in YAFFS2 mode: - 4 bytes 32-bit chunk ID - 4 bytes 32-bit object ID - 2 bytes Number of data bytes in this chunk - 4 bytes Sequence number for this block - 3 bytes ECC on tags - 12 bytes ECC on data (3 bytes per 256 bytes of data) - - -Page allocation and garbage collection - -Pages are allocated sequentially from the currently selected block. -When all the pages in the block are filled, another clean block is -selected for allocation. At least two or three clean blocks are -reserved for garbage collection purposes. If there are insufficient -clean blocks available, then a dirty block ( ie one containing only -discarded pages) is erased to free it up as a clean block. If no dirty -blocks are available, then the dirtiest block is selected for garbage -collection. - -Garbage collection is performed by copying the valid data pages into -new data pages thus rendering all the pages in this block dirty and -freeing it up for erasure. I also like the idea of selecting a block -at random some small percentage of the time - thus reducing the chance -of wear differences. - -YAFFS is single-threaded. Garbage-collection is done as a parasitic -task of writing data. So each time some data is written, a bit of -pending garbage collection is done. More pages are garbage-collected -when free space is tight. - - -Flash writing - -YAFFS only ever writes each page once, complying with the requirements -of the most restricitve NAND devices. - -Wear levelling - -This comes as a side-effect of the block-allocation strategy. Data is -always written on the next free block, so they are all used equally. -Blocks containing data that is written but never erased will not get -back into the free list, so wear is levelled over only blocks which -are free or become free, not blocks which never change. - - - -Some helpful info ------------------ - -Formatting a YAFFS device is simply done by erasing it. - -Making an initial filesystem can be tricky because YAFFS uses the OOB -and thus the bytes that get written depend on the YAFFS data (tags), -and the ECC bytes and bad block markers which are dictated by the -hardware and/or the MTD subsystem. The data layout also depends on the -device page size (512b or 2K). Because YAFFS is only responsible for -some of the OOB data, generating a filesystem offline requires -detailed knowledge of what the other parts (MTD and NAND -driver/hardware) are going to do. - -To make a YAFFS filesystem you have 3 options: - -1) Boot the system with an empty NAND device mounted as YAFFS and copy - stuff on. - -2) Make a filesystem image offline, then boot the system and use - MTDutils to write an image to flash. - -3) Make a filesystem image offline and use some tool like a bootloader to - write it to flash. - -Option 1 avoids a lot of issues because all the parts -(YAFFS/MTD/hardware) all take care of their own bits and (if you have -put things together properly) it will 'just work'. YAFFS just needs to -know how many bytes of the OOB it can use. However sometimes it is not -practical. - -Option 2 lets MTD/hardware take care of the ECC so the filesystem -image just had to know which bytes to use for YAFFS Tags. - -Option 3 is hardest as the image creator needs to know exactly what -ECC bytes, endianness and algorithm to use as well as which bytes are -available to YAFFS. - -mkyaffs2image creates an image suitable for option 3 for the -particular case of yaffs2 on 2K page NAND with default MTD layout. - -mkyaffsimage creates an equivalent image for 512b page NAND (i.e. -yaffs1 format). - -Bootloaders ------------ - -A bootloader using YAFFS needs to know how MTD is laying out the OOB -so that it can skip bad blocks. - -YAFFS Tracing --------------
deleted file mode 100644 --- a/README-linux-patch +++ /dev/null @@ -1,20 +0,0 @@ -To build YAFFS in the Linux kernel tree you need to run the patch-ker.sh -script from the yaffs source directory, giving your choice as to whether -you wish to copy (c) or link (l) the code and the path to your kernel -sources, e.g: - -./patch-ker.sh c /usr/src/linux - -This will copy the yaffs files into fs/yaffs2 and modify the Kconfig -and Makefiles in the fs directory. - -./patch-ker.sh l /usr/src/linux - -This does the same as the above but makes symbolic links instead. - -After you've run the script, go back to your normal kernel making procedure -and configure the yaffs settings you want. - -Prolems? Contact the yaffs mailing list: - -http://www.aleph1.co.uk/mailman/listinfo/yaffs
deleted file mode 100644 --- a/direct/Makefile +++ /dev/null @@ -1,75 +0,0 @@ -# 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$ - -#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC - -CFLAGS = -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -CFLAGS += -DCONFIG_YAFFS_PROVIDE_DEFS -DCONFIG_YAFFSFS_PROVIDE_VALUES -DNO_Y_INLINE -CFLAGS += -Wall -g $(EXTRA_COMPILE_FLAGS) -Wstrict-aliasing -#CFLAGS += -fno-strict-aliasing -CFLAGS += -O0 -#CFLAGS += -DVALGRIND_TEST - -#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations -#CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline - - -COMMONTESTOBJS = yaffscfg2k.o yaffs_ecc.o yaffs_fileem.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \ - yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \ - yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \ - yaffs_checkptrw.o yaffs_qsort.o\ - yaffs_norif1.o ynorsim.o -# yaffs_checkptrwtest.o\ - -DIRECTTESTOBJS = $(COMMONTESTOBJS) dtest.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 = $(sort $(DIRECTTESTOBJS) $(YAFFSTESTOBJS)) - -SYMLINKS = devextras.h yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h yaffsinterface.h yportenv.h yaffs_tagscompat.c yaffs_tagscompat.h \ - yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h yaffs_nandemul2k.h \ - yaffs_nand.c yaffs_nand.h yaffs_getblockinfo.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) - -yaffs_test: $(SYMLINKS) $(YAFFSTESTOBJS) - gcc -o $@ $(YAFFSTESTOBJS) - - -boottest: $(SYMLINKS) $(BOOTTESTOBJS) - gcc -o $@ $(BOOTTESTOBJS) - - -clean: - rm -f $(ALLOBJS) core
deleted file mode 100644 --- a/direct/dtest.c +++ /dev/null @@ -1,2449 +0,0 @@ -/* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * - * Copyright (C) 2002 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning <charles@aleph1.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - - - - -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> - -#include "yaffsfs.h" - - -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 i = 0; - 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; - int result; - - 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); - n = strlen(xx); - result = yaffs_write(h,xx,n); - if(result != n) - printf("Wrote %d, should have been %d\n",result,n); - iterations--; - } - yaffs_close (h); -} - -void verify_file_of_size(const char *fn,int syze) -{ - int h; - int result; - - 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); - - result = yaffs_read(h,yy,l); - yy[l] = 0; - - if(strcmp(xx,yy)){ - printf("=====>>>>> verification of file %s failed near position %lld\n",fn,(long long)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 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_ftruncate(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(const 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(const 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); - - 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 ino %d length %d mode %X ",de->d_name,(int)s.st_ino,(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 total = 0; - int lastTotal = 0; - - char str[100]; - - - 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) -{ - return 0; -} - - -void rename_over_test(const char *mountpt) -{ - int i; - char a[100]; - char b[100]; - char c[100]; - - sprintf(a,"%s/a",mountpt); - sprintf(b,"%s/b",mountpt); - sprintf(c,"%s/c",mountpt); - - yaffs_StartUp(); - - yaffs_mount(mountpt); - - printf("Existing files\n"); - dumpDirFollow(mountpt); - - - - i = yaffs_open(c,O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); - printf("File c handle is %d\n",i); - yaffs_close(i); - i = yaffs_open(a,O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); - yaffs_close(i); - i = yaffs_open(b,O_CREAT | O_TRUNC | O_RDWR, S_IREAD | S_IWRITE); - 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_ftruncate(a,syz); - - } - else - { - //expand - r = yaffs_lseek(a,i * 500,SEEK_SET); - r = yaffs_write(a,abuffer,1000); - } - x++; - - } - } - - return 0; - -} - -int root_perm_remount(const char *path) -{ - struct yaffs_stat s; - - yaffs_StartUp(); - - yaffs_mount(path); - - yaffs_stat(path,&s); - printf("root perms after mount %x\n",s.st_mode); - - yaffs_chmod(path, 0777); - - yaffs_stat(path,&s); - printf("root perms after setting to 0777 is %x\n",s.st_mode); - - yaffs_unmount(path); - - 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_ftruncate(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 %lld\n",(long long)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_ftruncate(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 %lld\n",(long long)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; - 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_ftruncate(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 fill_files_test(const char *mountpt) -{ - int i; - yaffs_StartUp(); - - for(i = 0; i < 5; i++) - { - yaffs_mount(mountpt); - fill_files(mountpt,2,3,100); - yaffs_unmount(mountpt); - } - -} - -void fill_empty_files_test(const char *mountpt) -{ - int i; - yaffs_StartUp(); - char name[100]; - int result = 0; - - int d,f; - - for(i = 0; i < 5; i++) - { - yaffs_mount(mountpt); - for(d = 0; result >= 0 && d < 1000; d++){ - sprintf(name,"%s/%d",mountpt,d); - result= yaffs_mkdir(name,0); - printf("creating directory %s result %d\n",name,result); - - for(f = 0; result >= 0 && f < 100; f++){ - sprintf(name,"%s/%d/%d",mountpt,d,f); - result= yaffs_open(name,O_CREAT, 0); - yaffs_close(result); - printf("creating file %s result %d\n",name,result); - } - } - yaffs_unmount(mountpt); - } - -} - -void long_name_test(const char *mountpt) -{ - int i; - yaffs_StartUp(); - char fullName[1000]; - char name[300]; - int result = 0; - - int d,f; - - // Make a 256 byte name - memset(name,0,sizeof(name)); - for(i = 0; i < 256; i++) - name[i] = '0' + i % 10; - - sprintf(fullName,"%s/%s",mountpt,name); - - for(i = 0; i < 1; i++) - { - yaffs_mount(mountpt); - - printf("Files at start\n"); - dumpDir(mountpt); - - printf("Creating file %s\n",fullName); - - f = yaffs_open(fullName,O_CREAT | O_RDWR,0); - yaffs_close(f); - - printf("Result %d\n",f); - - printf("Files\n"); - dumpDir(mountpt); - - printf("Deleting %s\n",fullName); - result = yaffs_unlink(fullName); - printf("Result %d\n",result); - - printf("Files\n"); - - dumpDir(mountpt); - - yaffs_unmount(mountpt); - } - -} - - - -void lookup_test(const char *mountpt) -{ - int i; - int h; - char a[100]; - - - yaffs_DIR *d; - yaffs_dirent *de; - - 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]; - - 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]; - - 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]; - - 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); - -#if 0 - for(j = 0; j < 200; j++){ - yaffs_write(h0,xx,1000); - yaffs_write(h1,xx,1000); - } -#else - while(yaffs_write(h0,xx,1000) > 0){ - - yaffs_write(h1,xx,1000); - } -#endif - 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]; - - 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]; - int i; - int j; - - int h0; - int h1; - - - 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_ftruncate(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 seek_overwrite_test(const char *mountpt,int nmounts) -{ - - char a[30]; - - int i; - int j; - - int h0; - - - sprintf(a,"%s/f",mountpt); - - yaffs_StartUp(); - - yaffs_mount(mountpt); - - - for(i = 0; i < nmounts; i++){ - - h0 = yaffs_open(a, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); - - for(j = 0; j < 100000; j++){ - yaffs_lseek(h0,0,SEEK_SET); - yaffs_write(h0,xx,5000); - yaffs_lseek(h0,0x100000,SEEK_SET); - yaffs_write(h0,xx,5000); - - if(early_exit) - exit(0); - } - - yaffs_close(h0); - - } -} - - -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); - return 0; -} - - -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 j; - - 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 space; - - 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((space = yaffs_freespace(mountpt)) > 25000000){ - sprintf(a,"%s/file%d",mountpt,fnum); - fnum++; - printf("create file %s, free space %d\n",a,space); - 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_ftruncate(h,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 h[NSMALLFILES]; - int r; - - - 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[i],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); -} - -void rmdir_test(const char *mountpt) -{ - char name[100]; - yaffs_StartUp(); - - yaffs_mount(mountpt); - - strcpy(name,mountpt); - strcat(name,"/"); - strcat(name,"hello"); - yaffs_mkdir(name,0666); - yaffs_rmdir(name); - yaffs_unmount(mountpt); -} - - -int random_seed; -int simulate_power_failure; - -int main(int argc, char *argv[]) -{ - random_seed = time(NULL); - //return long_test(argc,argv); - - //return cache_read_test(); - - // resize_stress_test_no_grow("/flash/flash",20); - //root_perm_remount("/flash/flash"); - - //huge_directory_test_on_path("/ram2k"); - - //yaffs_backward_scan_test("/flash/flash"); - // yaffs_device_flush_test("/flash/flash"); - - //rename_over_test("//////////////////flash///////////////////yaffs1///////////"); - - //fill_empty_files_test("/yaffs2/"); - long_name_test("/yaffs2"); - - //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); - //seek_overwrite_test("/flash/flash",1000); - //checkpoint_fill_test("/flash/flash",20); - //checkpoint_upgrade_test("/flash/flash",20); - //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; - -}
deleted file mode 100644 --- a/direct/fsx_test/Makefile +++ /dev/null @@ -1,79 +0,0 @@ -# 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$ - -#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC - -CFLAGS = -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -DNO_Y_INLINE -CFLAGS+= -DCONFIG_YAFFS_PROVIDE_DEFS -DCONFIG_YAFFSFS_PROVIDE_VALUES -CFLAGS+= -Wall -g $(EXTRA_COMPILE_FLAGS) -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 yaffs_fileem.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_norif1.o ynorsim.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 yaffs_getblockinfo.h - -YAFFSDIRECTSYMLINKS = yaffscfg2k.c yaffs_fileem2k.c yaffsfs.c yaffs_flashif.h yaffs_flashif2.h\ - yaffs_fileem2k.h yaffsfs.h yaffs_malloc.h yaffs_ramdisk.h ydirectenv.h \ - yaffscfg.h yaffs_fileem.c yaffs_flashif.c yaffs_ramdisk.c yaffs_ramem2k.c\ - yaffs_norif1.c yaffs_norif1.h ynorsim.c ynorsim.h - - - -#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
deleted file mode 100644 --- a/direct/fsx_test/README +++ /dev/null @@ -1,7 +0,0 @@ -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
deleted file mode 100644 --- a/direct/fsx_test/yaffs_fsx.c +++ /dev/null @@ -1,1013 +0,0 @@ -/* - * 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 <time.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 */ 10000000; /* -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_ftruncate(fd, (off_t)0); - yaffs_ftruncate(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_ftruncate(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_ftruncate(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_ftruncate(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); -} - - -#define BASE_NAME "/M18-1" - -int random_seed = 999; -int simulate_power_failure = 0; - -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(BASE_NAME); - - fname = BASE_NAME "/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(BASE_NAME); - prt("All operations completed A-OK!\n"); - - exit(0); - return 0; -} -
deleted file mode 100644 --- a/direct/python/Makefile +++ /dev/null @@ -1,82 +0,0 @@ -# Makefile for YAFFS direct stress tests -# -# -# 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$ - -#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC - -CFLAGS = -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -CFLAGS += -DCONFIG_YAFFS_PROVIDE_DEFS -DCONFIG_YAFFSFS_PROVIDE_VALUES -DNO_Y_INLINE -CFLAGS += -Wall -g $(EXTRA_COMPILE_FLAGS) -Wstrict-aliasing -#CFLAGS += -fno-strict-aliasing -CFLAGS += -O0 -#CFLAGS += -DVALGRIND_TEST - -#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations -#CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline - - -COMMONTESTOBJS = yaffscfg2k.o yaffs_ecc.o yaffs_fileem.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \ - yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \ - yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \ - yaffs_checkptrw.o yaffs_qsort.o\ - yaffs_norif1.o ynorsim.o - - -YAFFSLIBOBJS = $(COMMONTESTOBJS) yaffs_python_helper.o - - - -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_getblockinfo.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_flashif2.h\ - yaffs_fileem2k.h yaffsfs.h yaffs_malloc.h yaffs_ramdisk.h ydirectenv.h \ - yaffscfg.h yaffs_fileem.c yaffs_flashif.c yaffs_ramdisk.c yaffs_ramem2k.c\ - yaffs_norif1.c yaffs_norif1.h ynorsim.c ynorsim.h \ - yaffs_nandif.c yaffs_nandif.h - - -SYMLINKS = $(YAFFSSYMLINKS) $(YAFFSDIRECTSYMLINKS) - -all: libyaffsfs.so - - -$(YAFFSLIBOBJS): %.o: %.c - gcc -c $(CFLAGS) -o $@ $< - - -$(YAFFSSYMLINKS): - ln -s ../../$@ $@ - -$(YAFFSDIRECTSYMLINKS): - ln -s ../$@ $@ - - - -libyaffsfs.so: $(SYMLINKS) $(YAFFSLIBOBJS) - gcc -shared $(YAFFSLIBOBJS) -o $@ - - - - -clean: - rm -f $(YAFFSLIBOBJS) core $(YAFFSSYMLINKS) $(YAFFSDIRECTSYMLINKS) - rm -f libyaffsfs.so -
deleted file mode 100644 --- a/direct/python/README.txt +++ /dev/null @@ -1,57 +0,0 @@ -Using python with yaffsfs -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Herewith a brief session showing yaffs direct being accessed from python. - -I tried SWIG first, but ctypes turned out to be way, way easier... - -Thanks to the people on NZPUG mailing list that helped with the exercise. - -Build libyaffsfs.so with the accompanying Makefile. - -$ make libyaffsfs.so - -$ python -Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) -[GCC 4.3.3] on linux2 -Type "help", "copyright", "credits" or "license" for more information. ->>> from yaffsfs import * ->>> yaffs_StartUp() -0 ->>> yaffs_mount("/yaffs2") -yaffs: Mounting /yaffs2 -yaffs: yaffs_GutsInitialise() -yaffs_ScanBackwards starts intstartblk 1 intendblk 256... -0 blocks to be sorted... -...done -yaffs_ScanBackwards ends - -Block summary -0 blocks have illegal states -Unknown 0 blocks -Needs scanning 0 blocks -Scanning 0 blocks -Empty 256 blocks -Allocating 0 blocks -Full 0 blocks -Dirty 0 blocks -Checkpoint 0 blocks -Collecting 0 blocks -Dead 0 blocks - -yaffs: yaffs_GutsInitialise() done. - -0 ->>> yaffs_open("/yaffs2/xx",66,0666) -yaffs: Tnodes added -Allocated block 1, seq 4097, 255 left -0 ->>> yaffs_write(0,"abcdefg",5) -5 ->>> b = create_string_buffer("",100) ->>> yaffs_lseek(0,0,0) -0 ->>> yaffs_read(0,b,100) -5 ->>> print b.value -abcde
deleted file mode 100644 --- a/direct/python/examples.py +++ /dev/null @@ -1,57 +0,0 @@ -from yaffsfs import * - -def yaffs_ls(dname): - if dname[-1] != "/": dname = dname + "/" - dc = yaffs_opendir(dname) - if dc != 0 : - sep = yaffs_readdir(dc) - while bool(sep): - se = sep.contents - fullname = dname + se.d_name - #print fullname, " ", se.d_ino," ",ord(se.d_type) - st = yaffs_stat_struct() - result = yaffs_stat(fullname,byref(st)) - perms = st.st_mode & 0777 - isFile = True if st.st_mode & 0x8000 else False - isDir = True if st.st_mode & 0x4000 else False - - if isFile : - print "File ",se.d_ino, hex(perms), st.st_size, fullname - if isDir : - print "Dir ",se.d_ino, hex(perms), fullname - yaffs_ls(fullname) - - sep = yaffs_readdir(dc) - yaffs_closedir(dc) - return 0 - else: - print "Could not open directory" - return -1 - -def yaffs_mkfile(fname,fsize): - fd = yaffs_open(fname,66, 0666) - if fd >= 0: - b = create_string_buffer("",1024) - totalwrite=0 - while fsize > 0: - thiswrite = 1024 if fsize > 1024 else fsize - result = yaffs_write(fd,b,thiswrite) - totalwrite += result - fsize -= result - if result != thiswrite: - fsize= 0 - - return totalwrite - else : - return -1 - -root = "/yaffs2" - -yaffs_StartUp() -yaffs_mount(root) - -yaffs_mkdir(root+"/dd",0666) - -yaffs_open(root+"/dd/111",66,0666) - -yaffs_ls(root)
deleted file mode 100644 --- a/direct/python/yaffs_python_helper.c +++ /dev/null @@ -1,48 +0,0 @@ - -/* - * 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. - * - */ - -/* - * These are some dangly bits that need to be built to wrap up the rest of the yaffs test harness. - * - * - * This is also the place where extra debugging stuff might end up. - * - */ - -#include "yaffsfs.h" - -int simulate_power_failure; -int random_seed; - -int yaffs_print_constants(void) -{ - printf( "O_CREAT........%d\n",O_CREAT); - printf( "O_RDONLY.......%d\n",O_RDONLY); - printf( "O_WRONLY.......%d\n",O_WRONLY); - printf( "O_RDWR.........%d\n",O_RDWR); - printf( "O_TRUNC........%d\n",O_TRUNC); - - printf( "sizeof(off_t)..%d\n",sizeof(off_t)); - return 0; -} - -int yaffs_O_CREAT(void) { return O_CREAT;} -int yaffs_O_RDONLY(void) { return O_RDONLY;} -int yaffs_O_WRONLY(void) { return O_WRONLY;} -int yaffs_O_RDWR(void) { return O_RDWR;} -int yaffs_O_TRUNC(void) { return O_TRUNC;} - -int yaffs_set_trace(unsigned int tm) { return yaffs_traceMask=tm; } -int yaffs_get_trace(void) { return yaffs_traceMask; }
deleted file mode 100644 --- a/direct/python/yaffsfs.py +++ /dev/null @@ -1,222 +0,0 @@ -from ctypes import * -cdll.LoadLibrary("./libyaffsfs.so") -ylib = CDLL("./libyaffsfs.so") - -#int yaffs_open(const YCHAR *path, int oflag, int mode) ; -yaffs_open = ylib.yaffs_open -yaffs_open.argtypes = [ c_char_p, c_int, c_int] -yaffs_open.restype = c_int - -#int yaffs_close(int fd) ; -yaffs_close = ylib.yaffs_close -yaffs_close.argtypes = [ c_int] -yaffs_close.restype = c_int - -#int yaffs_fsync(int fd) ; -yaffs_fsync = ylib.yaffs_fsync -yaffs_fsync.argtypes = [c_int] -yaffs_fsync.restype = c_int - -#int yaffs_fdatasync(int fd) ; -yaffs_fdatasync = ylib.yaffs_fdatasync -yaffs_fdatasync.argtypes = [c_int] -yaffs_fdatasync.restype = c_int - -#int yaffs_flush(int fd) ; /* same as yaffs_fsync() */ -yaffs_flush = ylib.yaffs_flush -yaffs_flush.argtypes = [c_int] -yaffs_flush.restype = c_int - -#int yaffs_access(const YCHAR *path, int amode); -yaffs_access=ylib.yaffs_access -yaffs_access.argtypes= [c_char_p,c_int] -yaffs_access.restype = c_int - -#int yaffs_dup(int fd); -yaffs_dup = ylib.yaffs_dup -yaffs_dup.argtypes = [c_int] -yaffs_dup.restype = c_int - -#int yaffs_read(int fd, void *buf, unsigned int nbyte) ; -yaffs_read=ylib.yaffs_read -yaffs_read.argtypes=[c_int,c_char_p,c_int] -yaffs_read.restype = c_int - -#int yaffs_write(int fd, const void *buf, unsigned int nbyte) ; -yaffs_write=ylib.yaffs_write -yaffs_write.argtypes=[c_int,c_char_p,c_int] -yaffs_write.restype = c_int - -#int yaffs_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset); -yaffs_pread=ylib.yaffs_pread -yaffs_pread.argtypes=[c_int,c_char_p,c_int,c_int] -yaffs_pread.restype = c_int - -#int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset); -yaffs_pwrite=ylib.yaffs_pwrite -yaffs_pwrite.argtypes=[c_int,c_char_p,c_int,c_int] -yaffs_pwrite.restype = c_int - -# off_t = 4 byte int -#off_t yaffs_lseek(int fd, off_t offset, int whence) ; -yaffs_lseek=ylib.yaffs_lseek -yaffs_lseek.argtypes= [c_int, c_int, c_int] -yaffs_lseek.restype= c_int - -#int yaffs_truncate(const YCHAR *path, off_t newSize); -yaffs_truncate=ylib.yaffs_truncate -yaffs_truncate.argtypes = [c_char_p,c_int] -yaffs_truncate.restype = c_int - -#int yaffs_ftruncate(int fd, off_t newSize); -yaffs_ftruncate = ylib.yaffs_ftruncate -yaffs_truncate.argtypes = [c_int,c_int] -yaffs_truncate.restype = c_int - -#int yaffs_unlink(const YCHAR *path) ; -yaffs_unlink=ylib.yaffs_unlink -yaffs_unlink.argtypes = [c_char_p] -yaffs_unlink.restype = c_int - -#int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath) ; -yaffs_rename= ylib.yaffs_rename -yaffs_rename.argtypes=[c_char_p, c_char_p] -yaffs_rename.restype = c_int - -class yaffs_stat_struct(Structure): - _fields_ = [ - ("st_dev", c_int), - ("st_ino", c_int), - ("st_mode", c_int), - ("st_nlink", c_int), - ("st_uid", c_int), - ("st_gid", c_int), - ("st_rdev", c_int), - ("st_size", c_int), - ("st_blksize", c_int), - ("st_blocks", c_int), - ("yst_atime", c_int), - ("yst_mtime", c_int), - ("yst_ctime", c_int)] - -#int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf) ; -yaffs_stat = ylib.yaffs_stat -yaffs_stat.argtypes=[c_char_p,POINTER(yaffs_stat_struct)] -yaffs_stat.restype=c_int - -#int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf) ; -yaffs_lstat = ylib.yaffs_lstat -yaffs_lstat.argtypes=[c_char_p,POINTER(yaffs_stat_struct)] -yaffs_lstat.restype=c_int - -#int yaffs_fstat(int fd, struct yaffs_stat *buf) ; -yaffs_fstat = ylib.yaffs_fstat -yaffs_fstat.argtypes=[c_int,POINTER(yaffs_stat_struct)] -yaffs_fstat.restype=c_int - - -#int yaffs_chmod(const YCHAR *path, mode_t mode); -yaffs_chmod = ylib.yaffs_chmod -yaffs_chmod.argtypes = [c_char_p, c_int] -yaffs_chmod.restype = c_int - -#int yaffs_fchmod(int fd, mode_t mode); -yaffs_fchmod = ylib.yaffs_fchmod -yaffs_fchmod.argtypes = [c_int, c_int] -yaffs_fchmod.restype = c_int - -#int yaffs_mkdir(const YCHAR *path, mode_t mode) ; -yaffs_mkdir = ylib.yaffs_mkdir -yaffs_mkdir.argtypes = [c_char_p, c_int] -yaffs_mkdir.restype = c_int - -#int yaffs_rmdir(const YCHAR *path) ; -yaffs_rmdir = ylib.yaffs_rmdir -yaffs_rmdir.argtypes = [c_char_p] -yaffs_rmdir.restype = c_int - -class yaffs_dirent_struct(Structure): - _fields_ = [ - ("d_ino", c_int), - ("d_off", c_int), - ("d_reclen", c_short), - ("d_type", c_char), - ("d_name", c_char * 257), - ("d_dont_use", c_int)] - -#yaffs_DIR *yaffs_opendir(const YCHAR *dirname) ; -yaffs_opendir = ylib.yaffs_opendir -yaffs_opendir.argtypes = [c_char_p] -yaffs_opendir.restype = c_int - -#struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) ; -yaffs_readdir= ylib.yaffs_readdir -yaffs_readdir.argtypes=[c_int] -yaffs_readdir.restype=POINTER(yaffs_dirent_struct) - -#void yaffs_rewinddir(yaffs_DIR *dirp) ; -yaffs_rewinddir = ylib.yaffs_rewinddir -yaffs_rewinddir.argtypes = [c_int] -yaffs_rewinddir.restype = c_int ###### Should be void - -#int yaffs_closedir(yaffs_DIR *dirp) ; -yaffs_closedir = ylib.yaffs_closedir -yaffs_closedir.argtypes = [c_int] -yaffs_closedir.restype = c_int - - -#int yaffs_mount(const YCHAR *path) ; -yaffs_mount = ylib.yaffs_mount -yaffs_mount.argtypes = [c_char_p] -yaffs_mount.restype = c_int - -#int yaffs_unmount(const YCHAR *path) ; -yaffs_unmount = ylib.yaffs_unmount -yaffs_unmount.argtypes = [c_char_p] -yaffs_unmount.restype = c_int - -#int yaffs_sync(const YCHAR *path) ; -yaffs_sync = ylib.yaffs_sync -yaffs_sync.argtypes = [c_char_p] -yaffs_sync.restype = c_int - -#int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath); -yaffs_symlink= ylib.yaffs_symlink -yaffs_symlink.argtypes= [c_char_p, c_char_p] -yaffs_symlink.restype = c_int - -#int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz); -yaffs_readlink = ylib.yaffs_readlink -yaffs_readlink.argtypes = [c_char_p, c_char_p, c_int] -yaffs_readlink.restype = c_int - -#int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath); -yaffs_link = ylib.yaffs_link -yaffs_link.argtypes = [c_char_p, c_char_p] -yaffs_link.restype = c_int - -#int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev); -yaffs_mknod = ylib.yaffs_mknod -yaffs_mknod.argtypes = [c_char_p, c_int, c_int] -yaffs_mknod.restype = c_int - -#loff_t yaffs_freespace(const YCHAR *path); -yaffs_freespace = ylib.yaffs_freespace -yaffs_freespace.argtypes = [c_char_p] -yaffs_freespace.restype = c_longlong - -#loff_t yaffs_totalspace(const YCHAR *path); -yaffs_totalspace = ylib.yaffs_totalspace -yaffs_totalspace.argtypes = [c_char_p] -yaffs_totalspace.restype = c_longlong - -#int yaffs_inodecount(const YCHAR *path); -yaffs_inodecount = ylib.yaffs_inodecount -yaffs_inodecount.argtypes = [c_char_p] -yaffs_inodecount.restype = c_int - -#int yaffs_StartUp(void) -yaffs_StartUp = ylib.yaffs_StartUp -yaffs_StartUp.argtypes = [] -yaffs_StartUp.restype = c_int -
deleted file mode 100644 --- a/direct/tests/Makefile +++ /dev/null @@ -1,83 +0,0 @@ -# Makefile for YAFFS direct stress tests -# -# -# 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$ - -#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC - -CFLAGS = -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -CFLAGS += -DCONFIG_YAFFS_PROVIDE_DEFS -DCONFIG_YAFFSFS_PROVIDE_VALUES -DNO_Y_INLINE -CFLAGS += -Wall -g $(EXTRA_COMPILE_FLAGS) -Wstrict-aliasing -#CFLAGS += -fno-strict-aliasing -CFLAGS += -O0 -#CFLAGS += -DCONFIG_YAFFS_VALGRIND_TEST - -#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations -#CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline - - -COMMONTESTOBJS = yaffscfg2k.o yaffs_ecc.o yaffs_fileem.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \ - yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \ - yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \ - yaffs_checkptrw.o yaffs_qsort.o\ - yaffs_norif1.o ynorsim.o nor_stress.o yaffs_fsx.o - -# yaffs_checkptrwtest.o\ - -YAFFSTESTOBJS = $(COMMONTESTOBJS) yaffs_test.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 = $(sort $(YAFFSTESTOBJS)) - -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_getblockinfo.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_flashif2.h\ - yaffs_fileem2k.h yaffsfs.h yaffs_malloc.h yaffs_ramdisk.h ydirectenv.h \ - yaffscfg.h yaffs_fileem.c yaffs_flashif.c yaffs_ramdisk.c yaffs_ramem2k.c\ - yaffs_norif1.c yaffs_norif1.h ynorsim.c ynorsim.h \ - yaffs_nandif.c yaffs_nandif.h - - -SYMLINKS = $(YAFFSSYMLINKS) $(YAFFSDIRECTSYMLINKS) -#all: directtest2k boottest - -all: yaffs_test - -$(ALLOBJS): %.o: %.c - gcc -c $(CFLAGS) -o $@ $< - - -$(YAFFSSYMLINKS): - ln -s ../../$@ $@ - -$(YAFFSDIRECTSYMLINKS): - ln -s ../$@ $@ - - -yaffs_test: $(SYMLINKS) $(YAFFSTESTOBJS) - gcc -o $@ $(YAFFSTESTOBJS) - - - - -clean: - rm -f yaffs_test $(ALLOBJS) core $(YAFFSSYMLINKS) $(YAFFSDIRECTSYMLINKS)
deleted file mode 100644 --- a/direct/tests/README +++ /dev/null @@ -1,7 +0,0 @@ -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
deleted file mode 100755 --- a/direct/tests/init_fw_update_test_nand.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -# Run this to initialise the file system for the test runs. - rm seed-nand-* - rm emfile-2k-0* - ./yaffs_test -u -i yaffs2 -
deleted file mode 100755 --- a/direct/tests/init_fw_update_test_nor.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -# Run this to initialise the file system for the test runs. - ./yaffs_test -u -i M18-1
deleted file mode 100644 --- a/direct/tests/nor_stress.c +++ /dev/null @@ -1,419 +0,0 @@ -#include "nor_stress.h" - - -#include "yaffsfs.h" -#include "yaffs_fsx.h" - -#include <stdio.h> - - - -#if 1 -#define FSX_INIT(mount_pt) do{ if(interleave_fsx) yaffs_fsx_init(mount_pt); } while(0) -#define FSX_COMPLETE() do { if(interleave_fsx) yaffs_fsx_complete(); } while (0) - -#define FSX() \ -do { \ - if((myrand() & 0x1) == 0){\ - if(interleave_fsx) \ - yaffs_fsx_do_op(); \ - } \ -} while(0) - -#else -#define FSX_INIT(mount_point) do { } while(0) -#define FSX_COMPLETE() do { } while(0) -#define FSX() do { } while(0) -#endif - - -void (*ext_fatal)(void) = NULL; - -static unsigned powerUps; -static unsigned cycleStarts; -static unsigned cycleEnds; - -static int interleave_fsx; - -char fullPathName[100]; -char fullPowerUpName[100]; -char fullStartName[100]; -char fullEndName[100]; -char fullMainName[100]; -char fullTempMainName[100]; -char fullTempCounterName[100]; - - -extern int random_seed; - -int myrand(void) { - random_seed = random_seed * 1103515245 + 12345; - return((unsigned)(random_seed/65536) % 32768); -} - -void MakeName(char *fullName,const char *prefix, const char *name) -{ - strcpy(fullName,prefix); - strcat(fullName,"/"); - strcat(fullName,name); -} - - -void MakeFullNames(const char *prefix) -{ - MakeName(fullPathName,prefix,""); - MakeName(fullPowerUpName,prefix,"powerUps"); - MakeName(fullStartName,prefix,"starts"); - MakeName(fullEndName,prefix,"ends"); - MakeName(fullMainName,prefix,"main"); - MakeName(fullTempCounterName,prefix,"tmp-counter"); - MakeName(fullTempMainName,prefix,"tmp-main"); -} - -static void FatalError(int lineNo) -{ - printf("Integrity error %d\n",lineNo); - if(ext_fatal) - ext_fatal(); - - while(1){ - sleep(1); - } -} -void print_stat(const char *str, struct yaffs_stat *st) -{ - printf("%s inode %d\n",str,st->st_ino); -} - -static void UpdateCounter(const char *name, unsigned *val, int initialise) -{ - int inh=-1; - int outh=-1; - unsigned x[2]; - int nread = 0; - int nwritten = 0; - - x[0] = x[1] = 0; - - if(initialise){ - x[0] = 0; - x[1] = 1; - } else { - inh = yaffs_open(name,O_RDONLY, S_IREAD | S_IWRITE); - if(inh >= 0){ - nread = yaffs_read(inh,x,sizeof(x)); - yaffs_close(inh); - } - - if(nread != sizeof(x) || - x[0] + 1 != x[1]){ - printf("Error reading counter %s handle %d, x[0] %u x[1] %u last error %d\n", - name, inh, x[0], x[1],yaffsfs_GetLastError()); - FatalError(__LINE__); - - } - x[0]++; - x[1]++; - } - - FSX(); - outh = yaffs_open(fullTempCounterName, O_RDWR | O_TRUNC | O_CREAT, S_IREAD | S_IWRITE); - if(outh >= 0){ - struct yaffs_stat tmpstat, oldstat, tmpfstat; - FSX(); - nwritten = yaffs_write(outh,x,sizeof(x)); - FSX(); - yaffs_fstat(outh,&tmpfstat); - yaffs_close(outh); - FSX(); - - printf("About to rename %s to %s\n",fullTempCounterName,name); - yaffs_stat(fullTempCounterName,&tmpstat); - yaffs_stat(name,&oldstat); - print_stat("old stat",&oldstat); - print_stat("new stat",&tmpstat); - print_stat("new fstat",&tmpfstat); - yaffs_rename(fullTempCounterName,name); - FSX(); - } - - if(nwritten != sizeof(x)){ - printf("Error writing counter %s handle %d, x[0] %u x[1] %u\n", - name, inh, x[0], x[1]); - FatalError(__LINE__); - } - - *val = x[0]; - - printf("##\n" - "## Set counter %s to %u\n" - "##\n", name,x[0]); -} - - -static void dump_directory_tree_worker(const char *dname,int recursive) -{ - yaffs_DIR *d; - yaffs_dirent *de; - struct yaffs_stat s; - char str[1000]; - - d = yaffs_opendir(dname); - - if(!d) - { - printf("opendir failed\n"); - } - else - { - while((de = yaffs_readdir(d)) != NULL) - { - strcpy(str,dname); - strcat(str,"/"); - strcat(str,de->d_name); - - yaffs_lstat(str,&s); - - printf("%s inode %ld %d obj %x length %d mode %X ",str, de->d_ino, s.st_ino,de->d_dont_use,(int)s.st_size,s.st_mode);\ - if(de->d_ino != s.st_ino){ - printf(" \n\n!!!! HEY inode mismatch\n\n"); - FatalError(__LINE__); - } - - 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); - - if(s.st_ino > 10000) - FatalError(__LINE__); - - } - - yaffs_closedir(d); - } - -} - -static void dump_directory_tree(const char *dname) -{ - dump_directory_tree_worker(dname,1); - printf("\n"); - printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname)); -} - - - - -#define XX_SIZE 500 - -static unsigned xx[XX_SIZE]; - -static int yWriteFile(const char *fname, unsigned sz32) -{ - int h; - int r; - int i; - struct yaffs_stat st; - unsigned checksum = 0; - - - FSX(); - h = yaffs_open(fname,O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); - yaffs_fstat(h,&st); - printf("Writing file %s inode %d\n",fname, st.st_ino); - - FSX(); - - if(h < 0){ - printf("could not open file %s\n",fname); - return h; - } - - xx[0] = sz32; - checksum ^= xx[0]; - - if((r = yaffs_write(h,xx,sizeof(unsigned))) != sizeof(unsigned)){ - goto WRITE_ERROR; - } - FSX(); - while(sz32> 0){ - for(i = 0; i < XX_SIZE; i++){ - xx[i] = sz32 + i; - checksum ^= xx[i]; - } - - FSX(); - if((r = yaffs_write(h,xx,sizeof(xx))) != sizeof(xx)){ - goto WRITE_ERROR; - } - sz32--; - } - - xx[0] = checksum; - FSX(); - if((r = yaffs_write(h,xx,sizeof(unsigned))) != sizeof(unsigned)){ - goto WRITE_ERROR; - } - - FSX(); - yaffs_close(h); - return 0; - -WRITE_ERROR: - printf("ywrite error at position %d\n",(int)yaffs_lseek(h,0,SEEK_END)); - yaffs_close(h); - return -1; - -} - -static int yVerifyFile(const char *fName) -{ - unsigned checksum = 0; - unsigned totalSize; - unsigned sz32; - unsigned recordedSize = 0; - int r; - int h; - int i; - int retval = 0; - - - printf("Verifying file %s\n",fName); - - h = yaffs_open(fName, O_RDONLY,S_IREAD | S_IWRITE); - - if(h < 0){ - printf("could not open file %s\n",fName); - return -1; - } - - totalSize = yaffs_lseek(h,0,SEEK_END); - yaffs_lseek(h,0,SEEK_SET); - - r = yaffs_read(h,&sz32,sizeof(sz32)); - - if(r != sizeof(sz32)){ - printf("reading size failed ... returned %d\n",r); - yaffs_close(h); - return -1; - } - - recordedSize = sz32 * sizeof(xx) + 8; - - printf("verify %s: file size is %d, recorded size is %d\n", fName, totalSize, recordedSize); - if(totalSize != recordedSize){ - printf("!!!!!!!!!!!!!!!!!!!!!!!!file size is wrong, should be %d, is %d\n", recordedSize,totalSize); - yaffs_close(h); - return -1; - } - - checksum ^= sz32; - - - while(sz32 > 0){ - r = yaffs_read(h,xx,sizeof(xx)); - if(r != sizeof(xx)){ - printf("!!!!!!!!!!!!!!!!!!!!!!!!!!reading data failed ... returned %d\n",r); - yaffs_close(h); - return -1; - } - for(i = 0; i < XX_SIZE; i++) - checksum ^= xx[i]; - sz32--; - } - r = yaffs_read(h,xx,sizeof(xx[0])); - if(r != sizeof(xx[0])){ - printf("!!!!!!!!!!!!!!!!!!!!!!!!!!reading data failed ... returned %d\n",r); - yaffs_close(h); - return -1; - } - - checksum ^= xx[0]; - - if(checksum != 0){ - printf("!!!!!!!!!!!!!!!!!!!!! checksum failed\n"); - retval = -1; - } else - printf("verified ok\n"); - yaffs_close(h); - - return retval; -} - - -static void DoUpdateMainFile(void) -{ - int result; - int sz32; - sz32 = (myrand() % 1000) + 20; - - result = yWriteFile(fullTempMainName,sz32); - FSX(); - if(result) - FatalError(__LINE__); - yaffs_rename(fullTempMainName,fullMainName); - FSX(); -} - -static void DoVerifyMainFile(void) -{ - int result; - result = yVerifyFile(fullMainName); - if(result) - FatalError(__LINE__); - -} - - -void NorStressTestInitialise(const char *prefix) -{ - MakeFullNames(prefix); - - UpdateCounter(fullPowerUpName,&powerUps,1); - UpdateCounter(fullStartName,&cycleStarts,1); - UpdateCounter(fullEndName,&cycleEnds,1); - UpdateCounter(fullPowerUpName,&powerUps,1); - DoUpdateMainFile(); - DoVerifyMainFile(); -} - - -void NorStressTestRun(const char *prefix, int n_cycles, int do_fsx) -{ - interleave_fsx = do_fsx; - MakeFullNames(prefix); - FSX_INIT(prefix); - - dump_directory_tree(fullPathName); - - UpdateCounter(fullPowerUpName,&powerUps,0); - dump_directory_tree(fullPathName); - - while(n_cycles < 0 || n_cycles > 0){ - if(n_cycles > 0) - n_cycles--; - UpdateCounter(fullStartName, &cycleStarts,0); - dump_directory_tree(fullPathName); - DoVerifyMainFile(); - DoUpdateMainFile(); - dump_directory_tree(fullPathName); - - UpdateCounter(fullEndName,&cycleEnds,0); - dump_directory_tree(fullPathName); - } - FSX_COMPLETE(); -}
deleted file mode 100644 --- a/direct/tests/nor_stress.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __NOR_STRESS_H__ -#define __NOR_STRESS_H__ - -void NorStressTestInitialise(const char *path); -void NorStressTestRun(const char *path, int n_cycles, int do_fsx); - -#endif -
deleted file mode 100755 --- a/direct/tests/run_fw_update_test_nand.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -iterations=100000 - -[ -z $1 ] || iterations=$1 - - -rm iteration-max-* -touch iteration-max-$iterations - -echo " Running $iterations iterations" -sleep 2 - -for ((i=0; i < $iterations; i++)) -do - - seed=$RANDOM - j=$(( $i % 10 )) - rm seed-nand-*$j - echo $seed>seed-nand-for-run-$i - rm emfile-2k-0-*$j - cp emfile-2k-0 emfile-2k-0-$i - echo "#########" - echo "#########" - echo "#########" - echo "######### Run $i of $iterations with seed $seed" - echo "#########" - echo "#########" - echo "#########" - ./yaffs_test -u -f -p -s$seed yaffs2 -done
deleted file mode 100755 --- a/direct/tests/run_fw_update_test_nor.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - - -for ((i=0; i < 100000; i++)) -do - - seed=$RANDOM - j=$(( $i % 10 )) - rm seed-nor-*$j - echo $seed>seed-nor-for-run-$i - rm data*$j - cp emfile-nor data-for-run-$i - echo "######### Run $i with seed $seed" - ./yaffs_test -f -u -p -s$seed M18-1 -done
deleted file mode 100644 --- a/direct/tests/yaffs_fsx.c +++ /dev/null @@ -1,918 +0,0 @@ -/* - * 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 "yaffs_fsx.h" - -#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 <time.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[200]; /* name of our test file */ -char mount_name[200]; - -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 */ -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 EXIT(int x) -{ - printf("fsx wanted to exit with %d\n",x); - while(x){} -} - -char goodfile[1024]; -char logfile[1024]; - - -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_ftruncate(fd, (off_t)0); - yaffs_ftruncate(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_ftruncate(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_ftruncate(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_ftruncate(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 -yaffs_fsx_do_op(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); -} - - - -extern int random_seed; -extern int simulate_power_failure; - - -int mounted_by_fsx = 0; - -int -yaffs_fsx_init(const char *mount_pt) -{ - int i; - - goodfile[0] = 0; - logfile[0] = 0; - - page_size = getpagesize(); - page_mask = page_size - 1; - - setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */ - - strcpy(mount_name,mount_pt); - strcpy(fname,mount_name); - strcat(fname,"/fsxdata"); - -#if 0 - 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); -#endif - - 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(); - - printf("yaffs_fsx_init done\n"); - - return 0; -} - - -int yaffs_fsx_complete(void) -{ - if (yaffs_close(fd)) { - prterr("close"); - report_failure(99); - } - - yaffs_close(fsxgoodfd); - - prt("All operations completed A-OK!\n"); - - EXIT(0); - return 0; -} - -int -yaffs_fsx_main(const char *mount_pt, int numops) -{ - yaffs_fsx_init(mount_pt); - while (numops == -1 || numops--) - yaffs_fsx_do_op(); - yaffs_fsx_complete(); - - return 0; -}
deleted file mode 100644 --- a/direct/tests/yaffs_fsx.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __YAFFS_FSX_H__ -#define __YAFFS_FSX_H__ - -int yaffs_fsx_main(const char *mountpt,int n_cycles); -int yaffs_fsx_init(const char *mountpt); -int yaffs_fsx_complete(void); -void yaffs_fsx_do_op(void); - -#endif -
deleted file mode 100644 --- a/direct/tests/yaffs_test.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * - * Copyright (C) 2002 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning <charles@aleph1.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - - - - -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <signal.h> -#include <stdlib.h> - -#include "yaffsfs.h" - -#include "nor_stress.h" -#include "yaffs_fsx.h" - -void (*ext_fatal)(void); - - -int random_seed; -int simulate_power_failure = 0; - - -int do_fsx; -int do_bash_around; - -int init_test; -int do_upgrade; -int n_cycles = -1; -int yaffs_test_maxMallocs; - -extern int ops_multiplier; - -char mount_point[200]; - -#define BASH_HANDLES 20 -void yaffs_bash_around(const char *mountpt, int n_cycles) -{ - char name[200]; - char name1[200]; - int h[BASH_HANDLES]; - int i; - int op; - int pos; - int n; - int n1; - int start_op; - int op_max = 99; - - int cycle = 0; - - sprintf(name,"%s/bashdir",mountpt); - - yaffs_mkdir(name,0666); - - for(i = 0; i < BASH_HANDLES; i++) - h[i] = -1; - - while(n_cycles){ - if(cycle % 100 == 0){ - printf("CYCLE %8d mo %2d inodes %d space %d ",cycle,op_max, - yaffs_inodecount(mountpt),yaffs_freespace(mountpt)); - for(i = 0; i < BASH_HANDLES; i++) - printf("%2d ",h[i]); - printf("\n"); - } - cycle++; - - if(n_cycles > 0) - n_cycles--; - i = rand() % BASH_HANDLES; - op = rand() % op_max; - pos = rand() & 20000000; - n = rand() % 100; - n1 = rand() % 100; - - sprintf(name,"%s/bashdir/xx%d",mountpt,n); - sprintf(name1,"%s/bashdir/xx%d",mountpt,n1); - - start_op = op; - - op-=1; - if(op < 0){ - if(h[i]>= 0){ - yaffs_close(h[i]); - h[i] = -1; - } - continue; - } - op-=1; - if(op < 0){ - if(h[i] < 0) - h[i] = yaffs_open(name,O_CREAT| O_RDWR, 0666); - continue; - } - - op-=5; - if(op< 0){ - yaffs_lseek(h[i],pos,SEEK_SET); - yaffs_write(h[i],name,n); - continue; - } - op-=1; - if(op < 0){ - yaffs_unlink(name); - continue; - } - op-=1; - if(op < 0){ - yaffs_rename(name,name1); - continue; - } - op-=1; - if(op < 0){ - yaffs_mkdir(name,0666); - continue; - } - op-=1; - if(op < 0){ - yaffs_rmdir(name); - continue; - } - - op_max = start_op-op; - } - - -} - -void BadUsage(void) -{ - printf("Usage: yaffs_test [options] mountpoint\n"); - printf("options\n"); - printf(" f: do fsx testing\n"); - printf(" i: initialise for upgrade testing\n"); - printf(" l: multiply number of operations by 5\n"); - printf(" m: random max number of mallocs\n"); - printf(" n nnn: number of cycles\n"); - printf(" p: simulate power fail testing\n"); - printf(" s sss: set seed\n"); - printf(" u: do upgrade test\n"); - printf(" b: bash-about test\n"); - exit(2); -} - -int sleep_exit = 0; -int sleep_time = 0; -void test_fatal(void) -{ - printf("fatal yaffs test pid %d sleeping\n",getpid()); - while(!sleep_exit){ - sleep(1); - sleep_time++; - } - - signal(SIGSEGV,SIG_IGN); - signal(SIGBUS,SIG_IGN); - signal(SIGABRT,SIG_IGN); - sleep_exit = 0; - -} - -void bad_ptr_handler(int sig) -{ - printf("signal %d received\n",sig); - test_fatal(); -} - -int main(int argc, char **argv) -{ - int ch; - int random_mallocs=0; - ext_fatal = test_fatal; - -#if 1 - signal(SIGSEGV,bad_ptr_handler); - signal(SIGBUS,bad_ptr_handler); - signal(SIGABRT,bad_ptr_handler); -#endif - while ((ch = getopt(argc,argv, "bfilmn:ps:u")) - != EOF) - switch (ch) { - case 's': - random_seed = atoi(optarg); - break; - case 'p': - simulate_power_failure =1; - break; - case 'i': - init_test = 1; - break; - case 'b': - do_bash_around = 1; - break; - case 'f': - do_fsx = 1; - break; - case 'l': - ops_multiplier *= 5; - break; - case 'u': - do_upgrade = 1; - break; - case 'm': - random_mallocs=1; - break; - case 'n': - n_cycles = atoi(optarg); - break; - default: - BadUsage(); - /* NOTREACHED */ - } - argc -= optind; - argv += optind; - - if(random_mallocs){ - yaffs_test_maxMallocs = 0xFFF & random_seed; - } - - if(argc == 1) { - strcpy(mount_point,argv[0]); - - if(simulate_power_failure) - n_cycles = -1; - printf("Running test %s %s %s %s seed %d cycles %d\n", - do_upgrade ? "fw_upgrade" : "", - init_test ? "initialise":"", - do_fsx ? "fsx" :"", - simulate_power_failure ? "power_fail" : "", - random_seed, n_cycles); - - yaffs_StartUp(); - yaffs_mount(mount_point); - printf("Mount complete\n"); - - if(do_upgrade && init_test){ - simulate_power_failure = 0; - NorStressTestInitialise(mount_point); - } else if(do_upgrade){ - printf("Running stress on %s with seed %d\n",mount_point,random_seed); - NorStressTestRun(mount_point,n_cycles,do_fsx); - } else if(do_fsx){ - yaffs_fsx_main(mount_point,n_cycles); - } else if(do_bash_around){ - yaffs_bash_around(mount_point,n_cycles); - }else { - printf("No test to run!\n"); - BadUsage(); - } - yaffs_unmount(mount_point); - - printf("Test run completed!\n"); - } - else - BadUsage(); - return 0; -} - -
deleted file mode 100644 --- a/direct/yaffs_fileem.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * 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$"; - - -#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("emfile-512-0", 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; -} - -
deleted file mode 100644 --- a/direct/yaffs_fileem2k.c +++ /dev/null @@ -1,607 +0,0 @@ -/* - * 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_flashif2_c_version = "$Id$"; - - -#include "yportenv.h" - -#include "yaffs_flashif2.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 REPORT_ERROR 0 - -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 (32*8) - -typedef struct -{ - int handle[MAX_HANDLES]; - int nBlocks; -} yflash_Device; - -static yflash_Device filedisk; - -int yaffs_testPartialWrite = 0; - -extern int random_seed; -extern int simulate_power_failure; -static int initialised = 0; -static int remaining_ops; -static int nops_so_far; - -int ops_multiplier; - - -static void yflash2_MaybePowerFail(unsigned int chunkInNAND, int failPoint) -{ - - nops_so_far++; - - - remaining_ops--; - if(simulate_power_failure && - remaining_ops < 1){ - printf("Simulated power failure after %d operations\n",nops_so_far); - printf(" power failed on chunkInNAND %d, at fail point %d\n", - chunkInNAND, failPoint); - exit(0); - } -} - - - - - -static __u8 localBuffer[PAGE_SIZE]; - -static char *NToName(char *buf,int n) -{ - sprintf(buf,"emfile-2k-%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 i; - - int blk; - - - if(initialised) - { - return YAFFS_OK; - } - - initialised = 1; - - - srand(random_seed); - remaining_ops = (rand() % 1000) * 5; - 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 yflash2_GetNumberOfBlocks(void) -{ - CheckInit(); - - return filedisk.nBlocks; -} - -int yflash2_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const 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(dev->inbandTags){ - - yaffs_PackedTags2TagsPart * pt2tp; - pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; - yaffs_PackTags2TagsPart(pt2tp,tags); - - 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); - written = write(h,data,dev->totalBytesPerChunk); - - - if(yaffs_testPartialWrite){ - close(h); - exit(1); - } - - if(written != dev->totalBytesPerChunk) return YAFFS_FAIL; - - - } - - else { - /* First do a write of a partial page */ - int n_partials; - int bpos; - - if(data) - { - pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE; - h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))]; - - - memcpy(localBuffer,data, dev->nDataBytesPerChunk); - - n_partials = rand()%20; - - for(i = 0; i < n_partials; i++){ - bpos = rand() % dev->nDataBytesPerChunk; - - localBuffer[bpos] |= (1 << (rand() & 7)); - } - - if(REPORT_ERROR && 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); - } - - - if(written != dev->nDataBytesPerChunk) return YAFFS_FAIL; - } - // yflash2_MaybePowerFail(chunkInNAND,1); - - 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(dev,&pt,tags); - __u8 * ptab = (__u8 *)&pt; - - nRead = read(h,localBuffer,sizeof(pt)); - for(i = error = 0; REPORT_ERROR && 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]; - - n_partials = rand()% sizeof(pt); - - for(i = 0; i < n_partials; i++){ - bpos = rand() % sizeof(pt); - - localBuffer[bpos] |= (1 << (rand() & 7)); - } - - if(REPORT_ERROR && 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; - } - } - - //yflash2_MaybePowerFail(chunkInNAND,2); - - /* Next do the whole write */ - if(data) - { - pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE; - h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))]; - - - memset(localBuffer,0xFF, PAGE_SIZE); - for(i = 0; i < dev->nDataBytesPerChunk; i++){ - localBuffer[i] &= data[i]; - } - - if(REPORT_ERROR && 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); - } - - - 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(dev,&pt,tags); - __u8 * ptab = (__u8 *)&pt; - - nRead = read(h,localBuffer,sizeof(pt)); - for(i = error = 0; REPORT_ERROR && 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(REPORT_ERROR && 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; - } - } - - yflash2_MaybePowerFail(chunkInNAND,3); - - } - 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 yflash2_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags) -{ - int nread; - int pos; - int h; - int localData = 0; - int retval = YAFFS_OK; - int nRead; - - T(YAFFS_TRACE_MTD,(TSTR("read chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags)); - - CheckInit(); - - - - - if(dev->inbandTags){ - /* Got to suck the tags out of the data area */ - if(!data) { - localData=1; - data = yaffs_GetTempBuffer(dev,__LINE__); - } - - - yaffs_PackedTags2TagsPart * pt2tp; - pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; - - - 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->totalBytesPerChunk); - - yaffs_UnpackTags2TagsPart(tags,pt2tp); - - if(nread != dev->totalBytesPerChunk) - retval = YAFFS_FAIL; - - if(localData) - yaffs_ReleaseTempBuffer(dev,data,__LINE__); - - - - } - - else { - - 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) - retval = 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)) - retval = 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(dev,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)) - retval = YAFFS_FAIL; - } - } - } - - - - return retval; - -} - - -int yflash2_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 yflash2_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 yflash2_InitialiseNAND(yaffs_Device *dev) -{ - CheckInit(); - - return YAFFS_OK; -} - - - - -int yflash2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, __u32 *sequenceNumber) -{ - yaffs_ExtendedTags tags; - int chunkNo; - - *sequenceNumber = 0; - - chunkNo = blockNo * dev->nChunksPerBlock; - - yflash2_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; -} -
deleted file mode 100644 --- a/direct/yaffs_fileem2k.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 32 -//#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 yflash2_GetNumberOfBlocks(void); - -#endif -
deleted file mode 100644 --- a/direct/yaffs_flashif.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * 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$"; - - -#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; -} -
deleted file mode 100644 --- a/direct/yaffs_flashif.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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, const 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, __u32 *sequenceNumber); - -#endif
deleted file mode 100644 --- a/direct/yaffs_flashif2.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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_FLASH2_H__ -#define __YAFFS_FLASH2_H__ - - -#include "yaffs_guts.h" -int yflash2_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); -int yflash2_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare); -int yflash2_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags); -int yflash2_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare); -int yflash2_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags); -int yflash2_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); -int yflash2_InitialiseNAND(yaffs_Device *dev); -int yflash2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); -int yflash2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, __u32 *sequenceNumber); - -#endif
deleted file mode 100644 --- a/direct/yaffs_malloc.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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_MALLOC_H__ -#define __YAFFS_MALLOC_H__ - -#include <stdlib.h> - -void *yaffs_malloc(size_t size); -void yaffs_free(void *ptr); - -#endif -
deleted file mode 100644 --- a/direct/yaffs_nandif.c +++ /dev/null @@ -1,245 +0,0 @@ - -/* - * 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 "yportenv.h" -#include "yaffs_guts.h" -#include "devextras.h" - - -#include "yaffs_nandif.h" -#include "yaffs_packedtags2.h" - - -#if 0 - - -static unsigned char *DevBufferIn(yaffs_Device *dev) -{ - yfsd_WinCEDevice *cedev = (yfsd_WinCEDevice *)(dev->genericDevice); - return cedev->bufferIn; -} -static unsigned char *DevBufferOut(yaffs_Device *dev) -{ - yfsd_WinCEDevice *cedev = (yfsd_WinCEDevice *)(dev->genericDevice); - return cedev->bufferOut; -} - -static unsigned DevBufferSize(yaffs_Device *dev) -{ - yfsd_WinCEDevice *cedev = (yfsd_WinCEDevice *)(dev->genericDevice); - return cedev->bufferSize; -} - -#endif - -/* NB For use with inband tags.... - * We assume that the data buffer is of size totalBytersPerChunk so that we can also - * use it to load the tags. - */ -int ynandif_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, - const __u8 * data, - const yaffs_ExtendedTags * tags) -{ - - int retval = 0; - yaffs_PackedTags2 pt; - void *spare; - unsigned spareSize = 0; - - unsigned char *bufferIn = DevBufferIn(dev); - unsigned char *bufferOut = DevBufferOut(dev); - unsigned bufferSize = DevBufferSize(dev); - - T(YAFFS_TRACE_MTD, - (TSTR - ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" - TENDSTR), chunkInNAND, data, tags)); - - - /* For yaffs2 writing there must be both data and tags. - * If we're using inband tags, then the tags are stuffed into - * the end of the data buffer. - */ - - if(dev->inbandTags){ - yaffs_PackedTags2TagsPart *pt2tp; - pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); - yaffs_PackTags2TagsPart(pt2tp,tags); - spare = NULL; - spareSize = 0; - } - else{ - yaffs_PackTags2(&pt, tags); - spare = &pt; - spareSize = sizeof(yaffs_PackedTags2); - } - - yramsim_WritePage(chunkInNAND, - data, dev->totalBytesPerChunk, spare, spareSize); - - return YAFFS_OK; -} - -int ynandif_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, - __u8 * data, yaffs_ExtendedTags * tags) -{ - yaffs_PackedTags2 pt; - int localData = 0; - void *spare = NULL; - unsigned spareSize; - int eccStatus; //0 = ok, 1 = fixed, -1 = unfixed - - unsigned char *bufferIn = DevBufferIn(dev); - unsigned char *bufferOut = DevBufferOut(dev); - unsigned bufferSize = DevBufferSize(dev); - - T(YAFFS_TRACE_MTD, - (TSTR - ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p" - TENDSTR), chunkInNAND, data, tags)); - - if(!tags){ - spare = NULL; - spareSize = 0; - }else if(dev->inbandTags){ - - if(!data) { - localData = 1; - data = yaffs_GetTempBuffer(dev,__LINE__); - } - spare = NULL; - spareSize = 0; - } - else { - spare = &pt; - spareSize = sizeof(yaffs_PackedTags2); - } - - yramsim_ReadPage(chunkInNAND, - data,data ? dev->totalBytesPerChunk : 0, - spare,spareSize, - &eccStatus); - - - - if(dev->inbandTags){ - if(tags){ - yaffs_PackedTags2TagsPart * pt2tp; - pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; - yaffs_UnpackTags2TagsPart(tags,pt2tp); - } - } - else { - if (tags){ - yaffs_UnpackTags2(tags, &pt); - } - } - - if(tags && tags->chunkUsed){ - if(eccStatus == 0) - tags->eccResult = YAFFS_ECC_RESULT_NO_ERROR; - else if(eccStatus < 0) - tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; - else - tags->eccResult = YAFFS_ECC_RESULT_FIXED; - } - - if(localData) - yaffs_ReleaseTempBuffer(dev,data,__LINE__); - - return YAFFS_OK; -} - -int ynandif_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockId) -{ - - yramsim_MarkBlockBad(blockId); - - return YAFFS_OK; -} - -int ynandif_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, int blockId) -{ - - yramsim_EraseBlock(blockId); - - return YAFFS_OK; -} - - -static int ynandif_IsBlockOk(struct yaffs_DeviceStruct *dev, int blockId) -{ - return yramsim_CheckBlockOk(blockId); -} - -int ynandif_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockId, yaffs_BlockState *state, __u32 *sequenceNumber) -{ - unsigned chunkNo; - yaffs_ExtendedTags tags; - - *sequenceNumber = 0; - - chunkNo = blockId * dev->nChunksPerBlock; - - if(!ynandif_IsBlockOk(dev,blockId)){ - *state = YAFFS_BLOCK_STATE_DEAD; - } - else - { - ynandif_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags); - - if(!tags.chunkUsed) - { - *state = YAFFS_BLOCK_STATE_EMPTY; - } - else - { - *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; - *sequenceNumber = tags.sequenceNumber; - } - } - - return YAFFS_OK; -} - - -int ynandif_GetGeometry(yaffs_Device *dev, ynandif_Geometry *geometry) -{ - - yramsim_Geometry g; - - yramsim_GetGeometry(&g); - geometry->startBlock = g.startBlock; - geometry->endBlock = g.endBlock; - geometry->dataSize = g.dataSize; - geometry->spareSize = g.spareSize; - geometry->pagesPerBlock = g.pagesPerBlock; - geometry->hasECC = g.hasECC; - geometry->inbandTags = g.inbandTags; - geometry->useYaffs2 = g.useYaffs2; - - return YAFFS_OK; - -} - -int ynandif_InitialiseNAND(yaffs_Device *dev) -{ - - yramsim_Initialise(); - - return YAFFS_OK; -}
deleted file mode 100644 --- a/direct/yaffs_nandif.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 __YNANDIF_H__ -#define __YNANDIF_H__ - -#include "yaffs_guts.h" - -typedef struct { - unsigned startBlock; - unsigned endBlock; - unsigned dataSize; // Number of data bytes per page - unsigned spareSize; // Number of spare bytes per chunk - unsigned pagesPerBlock; - unsigned hasECC; - unsigned inbandTags; // Use inband tags on this device - unsigned useYaffs2; -} ynandif_Geometry; - -int ynandif_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags); -int ynandif_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags); -int ynandif_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); -int ynandif_InitialiseNAND(yaffs_Device *dev); -int ynandif_MarkNANDBlockBad(yaffs_Device *dev,int blockNumber); -int ynandif_QueryNANDBlock(yaffs_Device *dev, int blockNo, yaffs_BlockState *state, __u32 *sequenceNumber); -int ynandif_GetGeometry(yaffs_Device *dev, ynandif_Geometry *geometry); -#endif
deleted file mode 100644 --- a/direct/yaffs_norif1.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning <charles@aleph1.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * This is an interface module for handling NOR in yaffs1 mode. - */ - -/* First set up for M18 with 1k chunks and 16-byte spares. - * - * NB We're using the oddball M18 modes of operation here - * The chip is 64MB based at 0x0000, but YAFFS only going to use the top half - * ie. YAFFS will be from 32MB to 64MB. - * - * The M18 has two ways of writing data. Every Programming Region (1kbytes) - * can be programmed in two modes: - * * Object Mode 1024 bytes of write once data. - * * Control Mode: 512bytes of bit-writeable data. - * This is arranged as 32 * (16 bytes of bit-writable followed by 16 bytes of "dont touch") - * - * The block size is 256kB, making 128 blocks in the 32MB YAFFS area. - * Each block comprises: - * Offset 0k: 248 x 1k data pages - * Offset 248k: 248 x 32-byte spare areas implemented as 16 bytes of spare followed by 16 bytes untouched) - * Offset 248k + (248 * 32): Format marker - * - */ - -const char *yaffs_norif1_c_version = "$Id$"; - -#include "yaffs_norif1.h" - -#include "yportenv.h" - -#include "yaffs_flashif.h" -#include "yaffs_guts.h" - -#include "devextras.h" - -#define SPARE_BYTES_PER_CHUNK 16 -#define M18_SKIP 16 -#define PROG_REGION_SIZE 1024 -#define BLOCK_SIZE_IN_BYTES (256*1024) -#define CHUNKS_PER_BLOCK 248 -#define SPARE_AREA_OFFSET (CHUNKS_PER_BLOCK * PROG_REGION_SIZE) - -#define FORMAT_OFFSET (SPARE_AREA_OFFSET + CHUNKS_PER_BLOCK * (SPARE_BYTES_PER_CHUNK + M18_SKIP)) - -#define FORMAT_VALUE 0x1234 - -#define DATA_BYTES_PER_CHUNK 1024 -#define BLOCKS_IN_DEVICE (8*1024/256) - - -#define YNOR_PREMARKER (0xF6) -#define YNOR_POSTMARKER (0xF0) - - -#if 1 - -/* Compile this for a simulation */ -#include "ynorsim.h" -#define ynorif1_FlashInit() ynorsim_Initialise() -#define ynorif1_FlashDeinit() ynorsim_Shutdown() -#define ynorif1_FlashWrite32(addr,buf,nwords) ynorsim_Write32(addr,buf,nwords) -#define ynorif1_FlashRead32(addr,buf,nwords) ynorsim_Read32(addr,buf,nwords) -#define ynorif1_FlashEraseBlock(addr) ynorsim_EraseBlock(addr) -#define DEVICE_BASE ynorsim_GetBase() -#else - -/* Compile this for running on blob, hacked for yaffs access */ -#include "../blob/yflashrw.h" -#define ynorif1_FlashInit() do{} while(0) -#define ynorif1_FlashDeinit() do {} while(0) -#define ynorif1_FlashWrite32(addr,buf,nwords) Y_FlashWrite(addr,buf,nwords) -#define ynorif1_FlashRead32(addr,buf,nwords) Y_FlashRead(addr,buf,nwords) -#define ynorif1_FlashEraseBlock(addr) Y_FlashErase(addr,BLOCK_SIZE_IN_BYTES) -#define DEVICE_BASE (32 * 1024 * 1024) -#endif - -__u32 *Block2Addr(yaffs_Device *dev, int blockNumber) -{ - __u32 addr; - - addr = (__u32) DEVICE_BASE; - addr += blockNumber * BLOCK_SIZE_IN_BYTES; - - return (__u32 *) addr; -} - -__u32 *Block2FormatAddr(yaffs_Device *dev,int blockNumber) -{ - __u32 addr; - - addr = (__u32) Block2Addr(dev,blockNumber); - addr += FORMAT_OFFSET; - - return (__u32 *)addr; -} -__u32 *Chunk2DataAddr(yaffs_Device *dev,int chunkId) -{ - unsigned block; - unsigned chunkInBlock; - __u32 addr; - - block = chunkId/dev->nChunksPerBlock; - chunkInBlock = chunkId % dev->nChunksPerBlock; - - addr = (__u32) Block2Addr(dev,block); - addr += chunkInBlock * DATA_BYTES_PER_CHUNK; - - return (__u32 *)addr; -} - -__u32 *Chunk2SpareAddr(yaffs_Device *dev,int chunkId) -{ - unsigned block; - unsigned chunkInBlock; - __u32 addr; - - block = chunkId/dev->nChunksPerBlock; - chunkInBlock = chunkId % dev->nChunksPerBlock; - - addr = (__u32) Block2Addr(dev,block); - addr += SPARE_AREA_OFFSET; - addr += chunkInBlock * (SPARE_BYTES_PER_CHUNK + M18_SKIP); - return (__u32 *)addr; -} - - -void ynorif1_AndBytes(__u8*target, const __u8 *src, int nbytes) -{ - while(nbytes > 0){ - *target &= *src; - target++; - src++; - nbytes--; - } -} - -int ynorif1_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare) -{ - __u32 *dataAddr = Chunk2DataAddr(dev,chunkInNAND); - __u32 *spareAddr = Chunk2SpareAddr(dev,chunkInNAND); - - yaffs_Spare tmpSpare; - - /* We should only be getting called for one of 3 reasons: - * Writing a chunk: data and spare will not be NULL - * Writing a deletion marker: data will be NULL, spare not NULL - * Writing a bad block marker: data will be NULL, spare not NULL - */ - - if(sizeof(yaffs_Spare) != 16) - YBUG(); - - if(data && spare) - { - if(spare->pageStatus != 0xff) - YBUG(); - /* Write a pre-marker */ - memset(&tmpSpare,0xff,sizeof(tmpSpare)); - tmpSpare.pageStatus = YNOR_PREMARKER; - ynorif1_FlashWrite32(spareAddr,(__u32 *)&tmpSpare,sizeof(yaffs_Spare)/4); - - /* Write the data */ - ynorif1_FlashWrite32(dataAddr,(__u32 *)data,dev->totalBytesPerChunk / 4); - - - memcpy(&tmpSpare,spare,sizeof(yaffs_Spare)); - - /* Write the real tags, but override the premarker*/ - tmpSpare.pageStatus = YNOR_PREMARKER; - ynorif1_FlashWrite32(spareAddr,(__u32 *)&tmpSpare,sizeof(yaffs_Spare)/4); - - /* Write a post-marker */ - tmpSpare.pageStatus = YNOR_POSTMARKER; - ynorif1_FlashWrite32(spareAddr,(__u32 *)&tmpSpare,sizeof(tmpSpare)/4); - - } else if(spare){ - /* This has to be a read-modify-write operation to handle NOR-ness */ - - ynorif1_FlashRead32(spareAddr,(__u32 *)&tmpSpare,16/ 4); - - ynorif1_AndBytes((__u8 *)&tmpSpare,(__u8 *)spare,sizeof(yaffs_Spare)); - - ynorif1_FlashWrite32(spareAddr,(__u32 *)&tmpSpare,16/ 4); - } - else { - YBUG(); - } - - - return YAFFS_OK; - -} - -int ynorif1_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare) -{ - - __u32 *dataAddr = Chunk2DataAddr(dev,chunkInNAND); - __u32 *spareAddr = Chunk2SpareAddr(dev,chunkInNAND); - - if(data) - { - ynorif1_FlashRead32(dataAddr,(__u32 *)data,dev->totalBytesPerChunk / 4); - } - - if(spare) - { - ynorif1_FlashRead32(spareAddr,(__u32 *)spare,16/ 4); - - /* If the page status is YNOR_POSTMARKER then it was written properly - * so change that to 0xFF so that the rest of yaffs is happy. - */ - if(spare->pageStatus == YNOR_POSTMARKER) - spare->pageStatus = 0xFF; - else if(spare->pageStatus != 0xff && - (spare->pageStatus | YNOR_PREMARKER) != 0xff) - spare->pageStatus = YNOR_PREMARKER; - } - - - return YAFFS_OK; - -} - -static int ynorif1_FormatBlock(yaffs_Device *dev, int blockNumber) -{ - __u32 *blockAddr = Block2Addr(dev,blockNumber); - __u32 *formatAddr = Block2FormatAddr(dev,blockNumber); - __u32 formatValue = FORMAT_VALUE; - - ynorif1_FlashEraseBlock(blockAddr); - ynorif1_FlashWrite32(formatAddr,&formatValue,1); - - return YAFFS_OK; -} - -static int ynorif1_UnformatBlock(yaffs_Device *dev, int blockNumber) -{ - __u32 *formatAddr = Block2FormatAddr(dev,blockNumber); - __u32 formatValue = 0; - - ynorif1_FlashWrite32(formatAddr,&formatValue,1); - - return YAFFS_OK; -} - -static int ynorif1_IsBlockFormatted(yaffs_Device *dev, int blockNumber) -{ - __u32 *formatAddr = Block2FormatAddr(dev,blockNumber); - __u32 formatValue; - - - ynorif1_FlashRead32(formatAddr,&formatValue,1); - - return (formatValue == FORMAT_VALUE); -} - -int ynorif1_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) -{ - - if(blockNumber < 0 || blockNumber >= BLOCKS_IN_DEVICE) - { - T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); - return YAFFS_FAIL; - } - else - { - ynorif1_UnformatBlock(dev,blockNumber); - ynorif1_FormatBlock(dev,blockNumber); - return YAFFS_OK; - } - -} - -int ynorif1_InitialiseNAND(yaffs_Device *dev) -{ - int i; - - ynorif1_FlashInit(); - /* Go through the blocks formatting them if they are not formatted */ - for(i = dev->startBlock; i <= dev->endBlock; i++){ - if(!ynorif1_IsBlockFormatted(dev,i)){ - ynorif1_FormatBlock(dev,i); - } - } - return YAFFS_OK; -} - -int ynorif1_DeinitialiseNAND(yaffs_Device *dev) -{ - - ynorif1_FlashDeinit(); - - return YAFFS_OK; -} - -
deleted file mode 100644 --- a/direct/yaffs_norif1.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning <charles@aleph1.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2.1 as - * published by the Free Software Foundation. - * - * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. - */ - - -#ifndef __YAFFS_NOR_IF1_H__ -#define __YAFFS_NOR_IF1_H__ - -#include "yaffs_guts.h" - -int ynorif1_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare); -int ynorif1_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare); -int ynorif1_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); -int ynorif1_InitialiseNAND(yaffs_Device *dev); -int ynorif1_DeinitialiseNAND(yaffs_Device *dev); - -#endif - -
deleted file mode 100644 --- a/direct/yaffs_ramdisk.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * 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$"; - - -#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, const 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; -} - -
deleted file mode 100644 --- a/direct/yaffs_ramdisk.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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, const 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
deleted file mode 100644 --- a/direct/yaffs_ramem2k.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * 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$"; - -#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, const 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(dev,(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(dev,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, __u32 *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 -
deleted file mode 100644 --- a/direct/yaffscfg.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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.nDataBytesPerChunk = 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.nDataBytesPerChunk = 512; - 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.nDataBytesPerChunk = 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; -} - - - -
deleted file mode 100644 --- a/direct/yaffscfg.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 "yportenv.h" - -#define YAFFSFS_N_HANDLES 200 - - -typedef struct { - const YCHAR *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 -
deleted file mode 100644 --- a/direct/yaffscfg2k.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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 "yaffs_norif1.h" - -#include <errno.h> - -unsigned yaffs_traceMask = - - YAFFS_TRACE_SCAN | - YAFFS_TRACE_GC | - YAFFS_TRACE_ERASE | - YAFFS_TRACE_ERROR | - YAFFS_TRACE_TRACING | - YAFFS_TRACE_ALLOCATE | - YAFFS_TRACE_BAD_BLOCKS | - YAFFS_TRACE_VERIFY | - - 0; - - -static int yaffsfs_lastError; - -void yaffsfs_SetError(int err) -{ - //Do whatever to set error - yaffsfs_lastError = err; -} - - -int yaffsfs_GetLastError(void) -{ - return yaffsfs_lastError; -} - -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) -{ - void * 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_flashif2.h" -#include "yaffs_nandemul2k.h" - -static yaffs_Device ram1Dev; -static yaffs_Device nand2; -static yaffs_Device flashDev; -static yaffs_Device ram2kDev; -static yaffs_Device m18_1Dev; - -static yaffsfs_DeviceConfiguration yaffsfs_config[] = { - - { "/ram1", &ram1Dev}, - { "/M18-1", &m18_1Dev}, - { "/yaffs2", &flashDev}, - { "/ram2k", &ram2kDev}, - {(void *)0,(void *)0} /* Null entry to terminate list */ -}; - - -int yaffs_StartUp(void) -{ - // Stuff to configure YAFFS - // Stuff to initialise anything special (eg lock semaphore). - yaffsfs_LocalInitialisation(); - - // Set up devices - // /ram1 ram, yaffs1 - memset(&ram1Dev,0,sizeof(ram1Dev)); - ram1Dev.totalBytesPerChunk = 512; - ram1Dev.nChunksPerBlock = 32; - ram1Dev.nReservedBlocks = 2; // Set this smaller for RAM - ram1Dev.startBlock = 0; // Can use block 0 - ram1Dev.endBlock = 127; // Last block in 2MB. - //ram1Dev.useNANDECC = 1; - ram1Dev.nShortOpCaches = 0; // Disable caching on this device. - ram1Dev.genericDevice = (void *) 0; // Used to identify the device in fstat. - ram1Dev.writeChunkWithTagsToNAND = yramdisk_WriteChunkWithTagsToNAND; - ram1Dev.readChunkWithTagsFromNAND = yramdisk_ReadChunkWithTagsFromNAND; - ram1Dev.eraseBlockInNAND = yramdisk_EraseBlockInNAND; - ram1Dev.initialiseNAND = yramdisk_InitialiseNAND; - - // /M18-1 yaffs1 on M18 nor sim - memset(&m18_1Dev,0,sizeof(m18_1Dev)); - m18_1Dev.totalBytesPerChunk = 1024; - m18_1Dev.nChunksPerBlock =248; - m18_1Dev.nReservedBlocks = 2; - m18_1Dev.startBlock = 0; // Can use block 0 - m18_1Dev.endBlock = 31; // Last block - m18_1Dev.useNANDECC = 0; // use YAFFS's ECC - m18_1Dev.nShortOpCaches = 10; // Use caches - m18_1Dev.genericDevice = (void *) 1; // Used to identify the device in fstat. - m18_1Dev.writeChunkToNAND = ynorif1_WriteChunkToNAND; - m18_1Dev.readChunkFromNAND = ynorif1_ReadChunkFromNAND; - m18_1Dev.eraseBlockInNAND = ynorif1_EraseBlockInNAND; - m18_1Dev.initialiseNAND = ynorif1_InitialiseNAND; - m18_1Dev.deinitialiseNAND = ynorif1_DeinitialiseNAND; - - - // /yaffs2 - // Set this puppy up to use - // the file emulation space as - // 2kpage/64chunk per block - // - memset(&flashDev,0,sizeof(flashDev)); - - flashDev.totalBytesPerChunk = 2048; - flashDev.nChunksPerBlock = 64; - flashDev.nReservedBlocks = 5; - flashDev.inbandTags = 0; - flashDev.startBlock = 0; - flashDev.endBlock = yflash2_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 = yflash2_WriteChunkWithTagsToNAND; - flashDev.readChunkWithTagsFromNAND = yflash2_ReadChunkWithTagsFromNAND; - flashDev.eraseBlockInNAND = yflash2_EraseBlockInNAND; - flashDev.initialiseNAND = yflash2_InitialiseNAND; - flashDev.markNANDBlockBad = yflash2_MarkNANDBlockBad; - flashDev.queryNANDBlock = yflash2_QueryNANDBlock; - - - yaffs_initialise(yaffsfs_config); - - return 0; -} - - - -void SetCheckpointReservedBlocks(int n) -{ -// flashDev.nCheckpointReservedBlocks = n; -} -
deleted file mode 100644 --- a/direct/yaffsfs.c +++ /dev/null @@ -1,1736 +0,0 @@ -/* - * 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$"; - -// 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 YCHAR *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(YCHAR a, YCHAR b) -{ - // case sensitive - return (a == b); -} - -int yaffsfs_IsPathDivider(YCHAR ch) -{ - YCHAR *str = YAFFS_PATH_DIVIDERS; - - while(*str){ - if(*str == ch) - return 1; - str++; - } - - return 0; -} - -// 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 YCHAR *path, YCHAR **restOfPath) -{ - yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList; - const YCHAR *leftOver; - const YCHAR *p; - yaffs_Device *retval = NULL; - int thisMatchLength; - int longestMatch = -1; - int matching; - - // 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; - matching = 1; - - - while(matching && *p && *leftOver){ - // Skip over any /s - while(yaffsfs_IsPathDivider(*p)) - p++; - - // Skip over any /s - while(yaffsfs_IsPathDivider(*leftOver)) - leftOver++; - - // Now match the text part - while(matching && - *p && !yaffsfs_IsPathDivider(*p) && - *leftOver && !yaffsfs_IsPathDivider(*leftOver)){ - if(yaffsfs_Match(*p,*leftOver)){ - p++; - leftOver++; - thisMatchLength++; - } else { - matching = 0; - } - } - } - - // Skip over any /s in leftOver - while(yaffsfs_IsPathDivider(*leftOver)) - leftOver++; - - - if( matching && (thisMatchLength > longestMatch)){ - // Matched prefix - *restOfPath = (YCHAR *)leftOver; - retval = cfg->dev; - longestMatch = thisMatchLength; - } - - cfg++; - } - return retval; -} - -#if 0 -static yaffs_Device *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath) -{ - yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList; - const YCHAR *leftOver; - const YCHAR *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 - !(yaffsfs_IsPathDivider(*p) && (p[1] == 0)) && // the rest of the prefix is not / (to catch / at end) - *leftOver && - yaffsfs_Match(*p,*leftOver)){ - p++; - leftOver++; - thisMatchLength++; - } - - - if((!*p || (yaffsfs_IsPathDivider(*p) && (p[1] == 0))) && // end of prefix - (!*leftOver || yaffsfs_IsPathDivider(*leftOver)) && // no more in this path name part - (thisMatchLength > longestMatch)){ - // Matched prefix - *restOfPath = (YCHAR *)leftOver; - retval = cfg->dev; - longestMatch = thisMatchLength; - } - cfg++; - } - return retval; -} -#endif - -static yaffs_Object *yaffsfs_FindRoot(const YCHAR *path, YCHAR **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){ - YCHAR *alias = obj->variant.symLinkVariant.alias; - - if(yaffsfs_IsPathDivider(*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 YCHAR *path,YCHAR **name,int symDepth) -{ - yaffs_Object *dir; - YCHAR *restOfPath; - YCHAR str[YAFFS_MAX_NAME_LENGTH+1]; - int i; - - if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES) - return NULL; - - if(startDir){ - dir = startDir; - restOfPath = (YCHAR *)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(yaffsfs_IsPathDivider(*restOfPath)) - restOfPath++; // get rid of '/' - - *name = restOfPath; - i = 0; - - while(*restOfPath && !yaffsfs_IsPathDivider(*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(yaffs_strcmp(str,_Y(".")) == 0) - { - // Do nothing - } - else if(yaffs_strcmp(str,_Y("..")) == 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 YCHAR *path,YCHAR **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 YCHAR *path,int symDepth) -{ - yaffs_Object *dir; - YCHAR *name; - - dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth); - - if(dir && *name) - return yaffs_FindObjectByName(dir,name); - - return dir; -} - - -int yaffs_dup(int fd) -{ - int newHandle = -1; - yaffsfs_Handle *oldPtr = NULL; - yaffsfs_Handle *newPtr = NULL; - - yaffsfs_Lock(); - - oldPtr = yaffsfs_GetHandlePointer(fd); - if(oldPtr && oldPtr->inUse) - newHandle = yaffsfs_GetHandle(); - if(newHandle >= 0) - newPtr = yaffsfs_GetHandlePointer(newHandle); - - if(newPtr){ - *newPtr = *oldPtr; - return newHandle; - } - - if(!oldPtr) - yaffsfs_SetError(-EBADF); - else - yaffsfs_SetError(-ENOMEM); - - return -1; - -} - -int yaffs_open(const YCHAR *path, int oflag, int mode) -{ - yaffs_Object *obj = NULL; - yaffs_Object *dir = NULL; - YCHAR *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 && obj->variantType != YAFFS_OBJECT_TYPE_FILE) - obj = NULL; - - 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); - errorReported = 1; - } - } - - 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) - yaffs_ResizeFile(obj,0); - } else { - yaffsfs_PutHandle(handle); - if(!errorReported) { - yaffsfs_SetError(-EACCES); - errorReported = 1; - } - handle = -1; - } - } - - yaffsfs_Unlock(); - - return handle; -} - -int yaffs_Dofsync(int fd,int datasync) -{ - yaffsfs_Handle *h = NULL; - int retVal = 0; - - yaffsfs_Lock(); - - h = yaffsfs_GetHandlePointer(fd); - - if(h && h->inUse) - // flush the file - yaffs_FlushFile(h->obj,1,datasync); - else { - // bad handle - yaffsfs_SetError(-EBADF); - retVal = -1; - } - - yaffsfs_Unlock(); - - return retVal; -} - -int yaffs_fsync(int fd) -{ - return yaffs_Dofsync(fd,0); -} - -int yaffs_flush(int fd) -{ - return yaffs_fsync(fd); -} - -int yaffs_fdatasync(int fd) -{ - return yaffs_Dofsync(fd,1); -} - -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,0); - h->obj->inUse--; - if(h->obj->inUse <= 0 && h->obj->unlinked) - yaffs_DeleteObject(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; - unsigned 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_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset) -{ - yaffsfs_Handle *h = NULL; - yaffs_Object *obj = NULL; - int pos = 0; - int nRead = -1; - unsigned 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= offset; - 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); - 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_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset) -{ - 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){ - pos = offset; - - nWritten = yaffs_WriteDataToFile(obj,buf,pos,nbyte,writeThrough); - - if(nWritten < 0 || ((unsigned int)nWritten) < nbyte) - yaffsfs_SetError(-ENOSPC); - - } - - yaffsfs_Unlock(); - - - return (nWritten >= 0) ? nWritten : -1; - -} - - -int yaffs_truncate(const YCHAR *path,off_t newSize) -{ - yaffs_Object *obj = NULL; - int result = YAFFS_FAIL; - - yaffsfs_Lock(); - - obj = yaffsfs_FindObject(NULL,path,0); - if(obj) - obj = yaffs_GetEquivalentObject(obj); - - if(!obj) - yaffsfs_SetError(-ENOENT); - else if(obj->variantType != YAFFS_OBJECT_TYPE_FILE) - yaffsfs_SetError(-EISDIR); - else - result = yaffs_ResizeFile(obj,newSize); - - yaffsfs_Unlock(); - - - return (result) ? 0 : -1; -} - -int yaffs_ftruncate(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 YCHAR *path,int isDirectory) -{ - yaffs_Object *dir = NULL; - yaffs_Object *obj = NULL; - YCHAR *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 YCHAR *path) -{ - return yaffsfs_DoUnlink(path,1); -} - -int yaffs_unlink(const YCHAR *path) -{ - return yaffsfs_DoUnlink(path,0); -} - -int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath) -{ - yaffs_Object *olddir = NULL; - yaffs_Object *newdir = NULL; - yaffs_Object *obj = NULL; - YCHAR *oldname; - YCHAR *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(-EACCES); - } - - 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; -#if CONFIG_YAFFS_WINCE - buf->yst_wince_atime[0] = obj->win_atime[0]; - buf->yst_wince_atime[1] = obj->win_atime[1]; - buf->yst_wince_ctime[0] = obj->win_ctime[0]; - buf->yst_wince_ctime[1] = obj->win_ctime[1]; - buf->yst_wince_mtime[0] = obj->win_mtime[0]; - buf->yst_wince_mtime[1] = obj->win_mtime[1]; -#else - buf->yst_atime = obj->yst_atime; - buf->yst_ctime = obj->yst_ctime; - buf->yst_mtime = obj->yst_mtime; -#endif - retVal = 0; - } - return retVal; -} - -static int yaffsfs_DoStatOrLStat(const YCHAR *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 YCHAR *path, struct yaffs_stat *buf) -{ - return yaffsfs_DoStatOrLStat(path,buf,0); -} - -int yaffs_lstat(const YCHAR *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; -} - -#ifdef CONFIG_YAFFS_WINCE -int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime) -{ - yaffs_Object *obj; - - int retVal = -1; - - yaffsfs_Lock(); - obj = yaffsfs_GetHandleObject(fd); - - if(obj){ - - if(wctime){ - wctime[0] = obj->win_ctime[0]; - wctime[1] = obj->win_ctime[1]; - } - if(watime){ - watime[0] = obj->win_atime[0]; - watime[1] = obj->win_atime[1]; - } - if(wmtime){ - wmtime[0] = obj->win_mtime[0]; - wmtime[1] = obj->win_mtime[1]; - } - - - retVal = 0; - } else - // bad handle - yaffsfs_SetError(-EBADF); - - yaffsfs_Unlock(); - - return retVal; -} - - -int yaffs_set_wince_times(int fd, - const unsigned *wctime, - const unsigned *watime, - const unsigned *wmtime) -{ - yaffs_Object *obj; - int result; - int retVal = -1; - - yaffsfs_Lock(); - obj = yaffsfs_GetHandleObject(fd); - - if(obj){ - - if(wctime){ - obj->win_ctime[0] = wctime[0]; - obj->win_ctime[1] = wctime[1]; - } - if(watime){ - obj->win_atime[0] = watime[0]; - obj->win_atime[1] = watime[1]; - } - if(wmtime){ - obj->win_mtime[0] = wmtime[0]; - obj->win_mtime[1] = wmtime[1]; - } - - obj->dirty = 1; - result = yaffs_FlushFile(obj,0,0); - retVal = 0; - } else - // bad handle - yaffsfs_SetError(-EBADF); - - yaffsfs_Unlock(); - - return retVal; -} - -#endif - - -static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode) -{ - int result = -1; - - if(obj) - obj = yaffs_GetEquivalentObject(obj); - - if(obj) { - obj->yst_mode = mode; - obj->dirty = 1; - result = yaffs_FlushFile(obj,0,0); - } - - return result == YAFFS_OK ? 0 : -1; -} - - -int yaffs_access(const YCHAR *path, int amode) -{ - yaffs_Object *obj; - - int retval = 0; - - yaffsfs_Lock(); - obj = yaffsfs_FindObject(NULL,path,0); - - if(obj) { - int access_ok = 1; - - if((amode & R_OK) && !(obj->yst_mode & S_IREAD)) - access_ok = 0; - if((amode & W_OK) && !(obj->yst_mode & S_IWRITE)) - access_ok = 0; - if((amode & X_OK) && !(obj->yst_mode & S_IEXEC)) - access_ok = 0; - - if(!access_ok) { - yaffsfs_SetError(-EACCES); - retval = -1; - } - } else { - // todo error not found - yaffsfs_SetError(-ENOENT); - retval = -1; - } - - yaffsfs_Unlock(); - - return retval; - -} - - -int yaffs_chmod(const YCHAR *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 YCHAR *path, mode_t mode) -{ - yaffs_Object *parent = NULL; - yaffs_Object *dir = NULL; - YCHAR *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 { - if(!parent) - yaffsfs_SetError(-ENOENT); // missing path - else if (yaffs_FindObjectByName(parent,name)) - yaffsfs_SetError(-EEXIST); // the name already exists - else - yaffsfs_SetError(-ENOSPC); // just assume no space - retVal = -1; - } - - yaffsfs_Unlock(); - - return retVal; -} - -int yaffs_mount(const YCHAR *path) -{ - int retVal=-1; - int result=YAFFS_FAIL; - yaffs_Device *dev=NULL; - YCHAR *dummy; - - T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Mounting %s" TENDSTR),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_sync(const YCHAR *path) -{ - int retVal=-1; - yaffs_Device *dev=NULL; - YCHAR *dummy; - - yaffsfs_Lock(); - dev = yaffsfs_FindDevice(path,&dummy); - if(dev){ - if(dev->isMounted){ - - yaffs_FlushEntireDeviceCache(dev); - yaffs_CheckpointSave(dev); - - - } else - //todo error - not mounted. - yaffsfs_SetError(-EINVAL); - - }else - // todo error - no device - yaffsfs_SetError(-ENODEV); - - yaffsfs_Unlock(); - return retVal; -} - - -int yaffs_unmount(const YCHAR *path) -{ - int retVal=-1; - yaffs_Device *dev=NULL; - YCHAR *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 YCHAR *path) -{ - loff_t retVal=-1; - yaffs_Device *dev=NULL; - YCHAR *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; -} - -loff_t yaffs_totalspace(const YCHAR *path) -{ - loff_t retVal=-1; - yaffs_Device *dev=NULL; - YCHAR *dummy; - - yaffsfs_Lock(); - dev = yaffsfs_FindDevice(path,&dummy); - if(dev && dev->isMounted){ - retVal = (dev->endBlock - dev->startBlock + 1) - dev->nReservedBlocks; - retVal *= dev->nChunksPerBlock; - retVal *= dev->nDataBytesPerChunk; - - } else - yaffsfs_SetError(-EINVAL); - - yaffsfs_Unlock(); - return retVal; -} - -int yaffs_inodecount(const YCHAR *path) -{ - loff_t retVal= -1; - yaffs_Device *dev=NULL; - YCHAR *dummy; - - yaffsfs_Lock(); - dev = yaffsfs_FindDevice(path,&dummy); - if(dev && dev->isMounted) { - int nObjects = dev->nObjectsCreated - dev->nFreeObjects; - if(nObjects > dev->nHardLinks) - retVal = nObjects - dev->nHardLinks; - } - - if(retVal < 0) - 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 */ - YCHAR 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 ylist_head others; -} yaffsfs_DirectorySearchContext; - - - -static struct ylist_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( ylist_empty(&dsc->dirObj->variant.directoryVariant.children)) - dsc->nextReturn = NULL; - else - dsc->nextReturn = ylist_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 || - ylist_empty(&dsc->dirObj->variant.directoryVariant.children)) - dsc->nextReturn = NULL; - else { - struct ylist_head *next = dsc->nextReturn->siblings.next; - - if( next == &dsc->dirObj->variant.directoryVariant.children) - dsc->nextReturn = NULL; /* end of list */ - else - dsc->nextReturn = ylist_entry(next,yaffs_Object,siblings); - } - } else { - /* Hey someone isn't playing nice! */ - } -} - -static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj) -{ - - struct ylist_head *i; - yaffsfs_DirectorySearchContext *dsc; - - /* if search contexts not initilised then skip */ - if(!search_contexts.next) - return; - - /* Iterate through the directory search contexts. - * If any are the one being removed, then advance the dsc to - * the next one to prevent a hanging ptr. - */ - ylist_for_each(i, &search_contexts) { - if (i) { - dsc = ylist_entry(i, yaffsfs_DirectorySearchContext,others); - if(dsc->nextReturn == obj) - yaffsfs_DirAdvance(dsc); - } - } - -} - -yaffs_DIR *yaffs_opendir(const YCHAR *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; - yaffs_strncpy(dsc->name,dirname,NAME_MAX); - YINIT_LIST_HEAD(&dsc->others); - - if(!search_contexts.next) - YINIT_LIST_HEAD(&search_contexts); - - ylist_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(yaffs_strlen(dsc->de.d_name) == 0) - { - // this should not happen! - yaffs_strcpy(dsc->de.d_name,_Y("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; - ylist_del(&dsc->others); /* unhook from list */ - YFREE(dsc); - yaffsfs_Unlock(); - return 0; -} - -// end of directory stuff - - -int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath) -{ - yaffs_Object *parent = NULL; - yaffs_Object *obj; - YCHAR *name; - int retVal= -1; - int mode = 0; // ignore for now - - yaffsfs_Lock(); - parent = yaffsfs_FindDirectory(NULL,newpath,&name,0); - if(parent){ - 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; - } - } else { - yaffsfs_SetError(-EINVAL); - retVal = -1; - } - - yaffsfs_Unlock(); - - return retVal; - -} - -int yaffs_readlink(const YCHAR *path, YCHAR *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 { - YCHAR *alias = obj->variant.symLinkVariant.alias; - memset(buf,0,bufsiz); - yaffs_strncpy(buf,alias,bufsiz - 1); - retVal = 0; - } - yaffsfs_Unlock(); - return retVal; -} - -int yaffs_link(const YCHAR *oldpath, const YCHAR *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; - - YCHAR *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 && yaffs_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 YCHAR *pathname, mode_t mode, dev_t dev) -{ - return -1; -} - -int yaffs_DumpDevStruct(const YCHAR *path) -{ -#if 0 - YCHAR *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 - ); - - } - -#endif - return 0; -} -
deleted file mode 100644 --- a/direct/yaffsfs.h +++ /dev/null @@ -1,286 +0,0 @@ -/* - * 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 - - -#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES - -#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 EACCES -#define EACCES 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 - -#ifndef S_IEXEC -#define S_IEXEC 0000100 -#endif - -#ifndef R_OK -#define R_OK 4 -#define W_OK 2 -#define X_OK 1 -#define F_OK 0 -#endif - -#else -#include <errno.h> -#include <sys/stat.h> -#include <fcntl.h> -#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 */ - YUCHAR d_type; /* type of this record */ - YCHAR 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 */ - unsigned 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 */ -#ifdef CONFIG_YAFFS_WINCE - /* Special 64-bit times for WinCE */ - unsigned long yst_wince_atime[2]; - unsigned long yst_wince_mtime[2]; - unsigned long yst_wince_ctime[2]; -#else - unsigned long yst_atime; /* time of last access */ - unsigned long yst_mtime; /* time of last modification */ - unsigned long yst_ctime; /* time of last change */ -#endif -}; - -int yaffs_open(const YCHAR *path, int oflag, int mode) ; -int yaffs_close(int fd) ; -int yaffs_fsync(int fd) ; -int yaffs_fdatasync(int fd) ; -int yaffs_flush(int fd) ; /* same as yaffs_fsync() */ - -int yaffs_access(const YCHAR *path, int amode); - -int yaffs_dup(int fd); - -int yaffs_read(int fd, void *buf, unsigned int nbyte) ; -int yaffs_write(int fd, const void *buf, unsigned int nbyte) ; - -int yaffs_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset); -int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset); - -off_t yaffs_lseek(int fd, off_t offset, int whence) ; - -int yaffs_truncate(const YCHAR *path, off_t newSize); -int yaffs_ftruncate(int fd, off_t newSize); - -int yaffs_unlink(const YCHAR *path) ; -int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath) ; - -int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf) ; -int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf) ; -int yaffs_fstat(int fd, struct yaffs_stat *buf) ; - -#ifdef CONFIG_YAFFS_WINCE - -int yaffs_set_wince_times(int fd, const unsigned *wctime, const unsigned *watime, const unsigned *wmtime); -int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime); - -#endif - -int yaffs_chmod(const YCHAR *path, mode_t mode); -int yaffs_fchmod(int fd, mode_t mode); - -int yaffs_mkdir(const YCHAR *path, mode_t mode) ; -int yaffs_rmdir(const YCHAR *path) ; - -yaffs_DIR *yaffs_opendir(const YCHAR *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 YCHAR *path) ; -int yaffs_unmount(const YCHAR *path) ; - -int yaffs_sync(const YCHAR *path) ; - -int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath); -int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz); - -int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath); -int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev); - -loff_t yaffs_freespace(const YCHAR *path); -loff_t yaffs_totalspace(const YCHAR *path); - -int yaffs_inodecount(const YCHAR *path); - - -void yaffs_initialise(yaffsfs_DeviceConfiguration *configList); - -int yaffs_StartUp(void); - -#endif - -
deleted file mode 100644 --- a/direct/ydirectenv.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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(0) -//#define YBUG() do { *((int *)0) =1;} while(0) - - -#define YCHAR char -#define YUCHAR unsigned char -#define _Y(x) x -#define yaffs_strcat(a,b) strcat(a,b) -#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) - -#define YAFFS_PATH_DIVIDERS "/" - -#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 TCONT(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 - -
deleted file mode 100644 --- a/direct/ynorsim.c +++ /dev/null @@ -1,170 +0,0 @@ - - -#include "ynorsim.h" - - - -#include <stdio.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <unistd.h> -#include <time.h> - -#define YNORSIM_FNAME "emfile-nor" - -/* Set YNORSIM_BIT_CHANGES to a a value from 1..30 to - *simulate bit flipping as the programming happens. - * A low value results in faster simulation with less chance of encountering a partially programmed - * word. - */ - -//#define YNORSIM_BIT_CHANGES 15 -#define YNORSIM_BIT_CHANGES 2 - -#if 0 -/* Simulate 32MB of flash in 256k byte blocks. - * This stuff is x32. - */ - -#define YNORSIM_BLOCK_SIZE_U32 (256*1024/4) -#define YNORSIM_DEV_SIZE_U32 (32*1024 * 1024/4) -#else -/* Simulate 8MB of flash in 256k byte blocks. - * This stuff is x32. - */ - -#define YNORSIM_BLOCK_SIZE_U32 (256*1024/4) -#define YNORSIM_DEV_SIZE_U32 (8*1024 * 1024/4) -#endif - -static __u32 word[YNORSIM_DEV_SIZE_U32]; - -extern int random_seed; -extern int simulate_power_failure; - -static void NorError(void) -{ - printf("Nor error\n"); - while(1){} -} - -static void ynorsim_SaveImage(void) -{ - int h = open(YNORSIM_FNAME, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); - write(h,word,sizeof(word)); - close(h); -} - -static void ynorsim_RestoreImage(void) -{ - int h = open(YNORSIM_FNAME, O_RDONLY, S_IREAD | S_IWRITE); - memset(word,0xFF,sizeof(word)); - read(h,word,sizeof(word)); - close(h); -} - - -static void ynorsim_PowerFail(void) -{ - ynorsim_SaveImage(); - exit(1); -} - -static int initialised = 0; -static int remaining_ops; -static int nops_so_far; - -int ops_multiplier = 500; - -static void ynorsim_MaybePowerFail(void) -{ - - nops_so_far++; - - - remaining_ops--; - if(simulate_power_failure && - remaining_ops < 1){ - printf("Simulated power failure after %d operations\n",nops_so_far); - ynorsim_PowerFail(); - } -} - -static void ynorsim_Ready(void) -{ - if(initialised) - return; - srand(random_seed); - remaining_ops = 1000000000; - remaining_ops = (rand() % 10000) * ops_multiplier * YNORSIM_BIT_CHANGES; - ynorsim_RestoreImage(); -} - -void ynorsim_Read32(__u32 *addr,__u32 *buf, int nwords) -{ - while(nwords > 0){ - *buf = *addr; - buf++; - addr++; - nwords--; - } -} - -void ynorsim_WriteOneWord32(__u32 *addr,__u32 val) -{ - __u32 tmp; - __u32 m; - int i; - - tmp = *addr; - if(val & ~tmp){ - // Fail due to trying to change a zero into a 1 - printf("attempt to set a zero to one (%x)->(%x)\n",tmp,val); - NorError(); - } - - for(i = 0; i < YNORSIM_BIT_CHANGES; i++){ - m = 1 << (rand() & 31); - if(!(m & val)){ - tmp &= ~m; - *addr = tmp; - ynorsim_MaybePowerFail(); - } - - } - - *addr = tmp & val; - ynorsim_MaybePowerFail(); -} - -void ynorsim_Write32(__u32 *addr, __u32 *buf, int nwords) -{ - while(nwords >0){ - ynorsim_WriteOneWord32(addr,*buf); - addr++; - buf++; - nwords--; - } -} - -void ynorsim_EraseBlock(__u32 *addr) -{ - /* Todo... bit flipping */ - memset(addr,0xFF,YNORSIM_BLOCK_SIZE_U32 * 4); -} - -void ynorsim_Initialise(void) -{ - ynorsim_Ready(); -} - -void ynorsim_Shutdown(void) -{ - ynorsim_SaveImage(); - initialised=0; -} - -__u32 *ynorsim_GetBase(void) -{ - return word; -}
deleted file mode 100644 --- a/direct/ynorsim.h +++ /dev/null @@ -1,14 +0,0 @@ - -#ifndef __Y_NORSIM_H__ -#define __Y_NORSIM_H__ - -#include "yaffs_guts.h" - -void ynorsim_Read32(__u32 *addr, __u32 *data, int nwords); -void ynorsim_Write32(__u32 *addr, __u32 *data, int nwords); -void ynorsim_EraseBlock(__u32 *addr); -void ynorsim_Shutdown(void); -void ynorsim_Initialise(void); -__u32 * ynorsim_GetBase(void); - -#endif
deleted file mode 100755 --- a/linux-tests/initnandsim +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -modprobe mtd -modprobe mtdblock -modprobe nandsim first_id_byte=0x20 second_id_byte=0xa2 third_id_byte=00 fourth_id_byte=0x15 -cat /proc/mtd -
deleted file mode 100755 --- a/linux-tests/mkdirtree +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -TREE_BASE=/mnt/dirtree - -for (( d=0; d<50; d++ )) -do - mkdir -p $TREE_BASE/dir$d - - for (( f=0; f<50; f++ )) - do - ls > $TREE_BASE/dir$d/file$f - done -done - - -echo "Foo bar file" > $TREE_BASE/foo_file - -ln $TREE_BASE/foo_file $TREE_BASE/../foo_link - - - - -
deleted file mode 100644 --- a/moduleconfig.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 Martin Fouts <Martin.Fouts@palmsource.com> - * - * 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_CONFIG_H__ -#define __YAFFS_CONFIG_H__ - -#ifdef YAFFS_OUT_OF_TREE - -/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */ -#define CONFIG_YAFFS_FS -#define CONFIG_YAFFS_YAFFS1 -#define CONFIG_YAFFS_YAFFS2 - -/* These options are independent of each other. Select those that matter. */ - -/* Default: Not selected */ -/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */ -/* #define CONFIG_YAFFS_DOES_ECC */ - -/* Default: Selected */ -/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */ -#define CONFIG_YAFFS_DOES_TAGS_ECC - -/* Default: Not selected */ -/* Meaning: ECC byte order is 'wrong'. Only meaningful if */ -/* CONFIG_YAFFS_DOES_ECC is set */ -/* #define CONFIG_YAFFS_ECC_WRONG_ORDER */ - -/* Default: Selected */ -/* Meaning: Disables testing whether chunks are erased before writing to them*/ -#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK - -/* Default: Not Selected */ -/* Meaning: At mount automatically empty all files from lost and found. */ -/* This is done to fix an old problem where rmdir was not checking for an */ -/* empty directory. This can also be achieved with a mount option. */ -/* #define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND */ - -/* Default: Selected */ -/* Meaning: Cache short names, taking more RAM, but faster look-ups */ -#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM - -/* Default: 10 */ -/* Meaning: set the count of blocks to reserve for checkpointing */ -#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 - -/* -Older-style on-NAND data format has a "pageStatus" byte to record -chunk/page state. This byte is zeroed when the page is discarded. -Choose this option if you have existing on-NAND data in this format -that you need to continue to support. New data written also uses the -older-style format. -Note: Use of this option generally requires that MTD's oob layout be -adjusted to use the older-style format. See notes on tags formats and -MTD versions in yaffs_mtdif1.c. -*/ -/* Default: Not selected */ -/* Meaning: Use older-style on-NAND data format with pageStatus byte */ -/* #define CONFIG_YAFFS_9BYTE_TAGS */ - -#endif /* YAFFS_OUT_OF_TREE */ - -#endif /* __YAFFS_CONFIG_H__ */
deleted file mode 100644 --- a/mtdemul/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -#Makefile for NANDemul MTD -# -# NB this is not yet suitable for putting into the kernel tree. -# YAFFS: Yet another Flash File System. A NAND-flash specific file system. -# -# Copyright (C) 2002 Aleph One Ltd. -# for Toby Churchill Ltd and Brightstar Engineering -# -# Created by Charles Manning <charles@aleph1.co.uk> -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. - -## Change or override KERNELDIR to your kernel -## comment out USE_xxxx if you don't want these features. - -KERNELDIR = /opt/linux-source-2.6.24 - -#CFLAGS = -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -O2 -Wall -g -CFLAGS = -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -O2 -Wall -g - - - -TARGET = nandemul2k.o - -default: $(TARGET) - -clean: - rm -f $(TARGET) - -$(TARGET): %.o: %.c - gcc -c $(CFLAGS) $< -o $@ -
deleted file mode 100644 --- a/mtdemul/nandemul2k.c +++ /dev/null @@ -1,708 +0,0 @@ -/* - * 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 version hacked for emulating 2kpage NAND for YAFFS2 testing. - */ - -//#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/version.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/fs.h> -#include <linux/proc_fs.h> -#include <linux/pagemap.h> -#include <linux/mtd/mtd.h> -#include <linux/interrupt.h> -#include <linux/string.h> -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) -#include <linux/locks.h> -#endif - -#include <asm/uaccess.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/nand.h> -#include "../yaffs_nandemul2k.h" - -#define ALLOCATE(x) kmalloc(x,GFP_KERNEL) -#define FREE(x) kfree(x) - - - - - -#define NAND_SHIFT (11) // Shifter for 2k -#define PAGE_DATA_SIZE (1 << NAND_SHIFT) -#define PAGE_SPARE_SIZE (64) -#define BLK_SHIFT 6 -#define PAGES_PER_BLOCK (1 << BLK_SHIFT) // = 64 - - -#define EM_SIZE_IN_MEG 4 -#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)) - - -static struct mtd_info nandemul2k_mtd; - -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 nandemul2k_Read(void *buffer, int page, int start, int nBytes) -{ - int pg = page%PAGES_PER_BLOCK; - int blk = page/PAGES_PER_BLOCK; - if(buffer && nBytes > 0) - { - memcpy(buffer,&ned.block[blk]->page[pg]->data[start],nBytes); - } - -} - -static void nandemul2k_Program(const void *buffer, int page, int start, int nBytes) -{ - int pg = page%PAGES_PER_BLOCK; - int blk = page/PAGES_PER_BLOCK; - __u8 *p; - __u8 *b = (__u8 *)buffer; - - p = &ned.block[blk]->page[pg]->data[start]; - - while(buffer && nBytes>0) - { - *p = *p & *b; - p++; - b++; - nBytes--; - } -} - -static void nandemul2k_DoErase(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 0; - } - - - ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks(); - - - ned.block = ALLOCATE(sizeof(nandemul_Block*) * nBlocks ); - - if(!ned.block) return ENOMEM; - - - - - - for(i=fail=0; i <nBlocks; i++) - { - - nandemul_Block *blk; - - if(!(blk = ned.block[i] = ALLOCATE(sizeof(nandemul_Block)))) - { - fail = 1; - } - else - { - for(j = 0; j < PAGES_PER_BLOCK; j++) - { - if((blk->page[j] = ALLOCATE(sizeof(nandemul_Page))) == 0) - { - fail = 1; - } - } - nandemul2k_DoErase(i); - ned.block[i]->damaged = 0; - nAllocated++; - } - } - - if(fail) - { - //Todo thump pages - - for(i = 0; i < nAllocated; i++) - { - FREE(ned.block[i]); - } - FREE(ned.block); - - return ENOMEM; - } - - ned.nBlocks = nBlocks; - - initialised = 1; - - return 1; -} - - - -static void nandemul2k_CleanUp(void) -{ - int i,j; - - for(i = 0; i < ned.nBlocks; i++) - { - for(j = 0; j < PAGES_PER_BLOCK; j++) - { - FREE(ned.block[i]->page[j]); - } - FREE(ned.block[i]); - - } - FREE(ned.block); - ned.block = 0; -} - -int nandemul2k_GetBytesPerChunk(void) { return PAGE_DATA_SIZE;} - -int nandemul2k_GetChunksPerBlock(void) { return PAGES_PER_BLOCK; } -int nandemul2k_GetNumberOfBlocks(void) {return nandemul2k_CalcNBlocks();} - - - -static int nandemul2k_ReadId(__u8 *vendorId, __u8 *deviceId) -{ - *vendorId = 'Y'; - *deviceId = '2'; - - return 1; -} - - -static int nandemul2k_ReadStatus(__u8 *status) -{ - *status = 0; - return 1; -} - - -#ifdef CONFIG_MTD_NAND_ECC -#include <linux/mtd/nand_ecc.h> -#endif - -/* - * NAND low-level MTD interface functions - */ -static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf); -static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf); -static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf); -static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7)) -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen); -#else -static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, - unsigned long count, loff_t to, size_t *retlen); -#endif -static int nand_erase (struct mtd_info *mtd, struct erase_info *instr); -static void nand_sync (struct mtd_info *mtd); - - - -/* - * NAND read - */ -static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) -{ - return nand_read_ecc (mtd, from, len, retlen, buf, NULL,NULL); -} - - -/* - * NAND read with ECC - */ -static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf, u_char *oob_buf,struct nand_oobinfo *oobsel) -{ - int start, page; - int n = len; - int nToCopy; - - - - /* Do not allow reads past end of device */ - if ((from + len) > mtd->size) { - *retlen = 0; - return -EINVAL; - } - - - /* Initialize return value */ - *retlen = 0; - - while(n > 0) - { - - /* First we calculate the starting page */ - page = from >> NAND_SHIFT; - - /* Get raw starting column */ - - start = from & (PAGE_DATA_SIZE - 1); - - // OK now check for the curveball where the start and end are in - // the same page - if((start + n) < PAGE_DATA_SIZE) - { - nToCopy = n; - } - else - { - nToCopy = PAGE_DATA_SIZE - start; - } - - nandemul2k_Read(buf, page, start, nToCopy); - nandemul2k_Read(oob_buf,page,PAGE_DATA_SIZE,PAGE_SPARE_SIZE); - - n -= nToCopy; - from += nToCopy; - buf += nToCopy; - if(oob_buf) oob_buf += PAGE_SPARE_SIZE; - *retlen += nToCopy; - - } - - - return 0; -} - -/* - * NAND read out-of-band - */ -static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) -{ - int col, page; - - T(0,("nand_read_oob: from = 0x%08x, buf = 0x%08x, len = %i\n", (unsigned int) from, (unsigned int) buf, - (int) len)); - - /* Shift to get page */ - page = ((int) from) >> NAND_SHIFT; - - /* Mask to get column */ - col = from & (PAGE_SPARE_SIZE-1) - - /* Initialize return length value */ - *retlen = 0; - - /* Do not allow reads past end of device */ - if ((from + len) > mtd->size) { - T(0, - ("nand_read_oob: Attempt read beyond end of device\n")); - *retlen = 0; - return -EINVAL; - } - - nandemul2k_Read(buf,page,PAGE_DATA_SIZE + col,len); - - /* Return happy */ - *retlen = len; - return 0; -} - -/* - * NAND write - */ -static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - return nand_write_ecc (mtd, to, len, retlen, buf, NULL,NULL); -} - -/* - * NAND write with ECC - */ -static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, - u_char *oob_buf, struct nand_oobinfo *dummy) -{ - - int start, page; - int n = len; - int nToCopy; - - - - /* Do not allow reads past end of device */ - if ((to + len) > mtd->size) { - *retlen = 0; - return -EINVAL; - } - - - /* Initialize return value */ - *retlen = 0; - - while(n > 0) - { - - /* First we calculate the starting page */ - page = to >> NAND_SHIFT; - - /* Get raw starting column */ - - start = to & (PAGE_DATA_SIZE - 1); - - // OK now check for the curveball where the start and end are in - // the same page - if((start + n) < PAGE_DATA_SIZE) - { - nToCopy = n; - } - else - { - nToCopy = PAGE_DATA_SIZE - start; - } - - nandemul2k_Program(buf, page, start, nToCopy); - nandemul2k_Program(oob_buf, page, PAGE_DATA_SIZE, PAGE_SPARE_SIZE); - - n -= nToCopy; - to += nToCopy; - buf += nToCopy; - if(oob_buf) oob_buf += PAGE_SPARE_SIZE; - *retlen += nToCopy; - - } - - - return 0; -} - -/* - * NAND write out-of-band - */ -static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - int col, page; - - - T(0,( - "nand_read_oob: to = 0x%08x, len = %i\n", (unsigned int) to, - (int) len)); - - /* Shift to get page */ - page = ((int) to) >> NAND_SHIFT; - - /* Mask to get column */ - col = to & PAGE_SPARE_SIZE; - - /* Initialize return length value */ - *retlen = 0; - - /* Do not allow reads past end of device */ - if ((to + len) > mtd->size) { - T(0,( - "nand_read_oob: Attempt read beyond end of device\n")); - *retlen = 0; - return -EINVAL; - } - - nandemul2k_Program(buf,page,512 + col,len); - - /* Return happy */ - *retlen = len; - return 0; - -} - -/* - * NAND write with iovec - */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7)) -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen) -#else -static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, - unsigned long count, loff_t to, size_t *retlen) -#endif -{ - return -EINVAL; -} - -/* - * NAND erase a block - */ -static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) -{ - int i, nBlocks,block; - - T(0,( - "nand_erase: start = 0x%08x, len = %i\n", - (unsigned int) instr->addr, (unsigned int) instr->len)); - - /* Start address must align on block boundary */ - if (instr->addr & (mtd->erasesize - 1)) { - T(0,( - "nand_erase: Unaligned address\n")); - return -EINVAL; - } - - /* Length must align on block boundary */ - if (instr->len & (mtd->erasesize - 1)) { - T(0,( - "nand_erase: Length not block aligned\n")); - return -EINVAL; - } - - /* Do not allow erase past end of device */ - if ((instr->len + instr->addr) > mtd->size) { - T(0,( - "nand_erase: Erase past end of device\n")); - return -EINVAL; - } - - nBlocks = instr->len >> (NAND_SHIFT + BLK_SHIFT); - block = instr->addr >> (NAND_SHIFT + BLK_SHIFT); - - for(i = 0; i < nBlocks; i++) - { - nandemul2k_DoErase(block); - block++; - } - - instr->state = MTD_ERASE_DONE; /* Changed state to done */ - instr->callback(instr); /* ... and wake up */ - - return 0; - - -} - - -static int nand_block_isbad(struct mtd_info *mtd, loff_t ofs) -{ - return 0; -} - -static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) -{ - return 0; -} - - -/* - * NAND sync - */ -static void nand_sync (struct mtd_info *mtd) -{ - T(0,("nand_sync: called\n")); - -} - -/* - * Scan for the NAND device - */ -static int nandemul2k_scan (struct mtd_info *mtd,int nchips) -{ - mtd->writesize = PAGE_DATA_SIZE; - mtd->oobsize = PAGE_SPARE_SIZE; - mtd->oobavail = PAGE_SPARE_SIZE/2; /* Simulate using up some for other uses */ - mtd->erasesize = PAGE_DATA_SIZE * PAGES_PER_BLOCK; - mtd->size = sizeInMB * 1024*1024; - - - - /* Fill in remaining MTD driver data */ - mtd->type = MTD_NANDFLASH; - mtd->flags = MTD_CAP_NANDFLASH; - mtd->owner = THIS_MODULE; - mtd->erase = nand_erase; - mtd->point = NULL; - mtd->unpoint = NULL; - mtd->read = nand_read; - mtd->write = nand_write; - mtd->read_oob = nand_read_oob; - mtd->write_oob = nand_write_oob; - mtd->read_oob = nand_read_oob; - mtd->write_oob = nand_write_oob; - mtd->block_isbad = nand_block_isbad; - mtd->block_markbad = nand_block_markbad; - mtd->readv = NULL; - mtd->writev = nand_writev; - mtd->sync = nand_sync; - mtd->lock = NULL; - mtd->unlock = NULL; - mtd->suspend = NULL; - mtd->resume = NULL; - - mtd->name = "NANDemul2k"; - - /* Return happy */ - return 0; -} - -#if 0 -#ifdef MODULE -MODULE_PARM(sizeInMB, "i"); - -__setup("sizeInMB=",sizeInMB); -#endif -#endif - -/* - * Define partitions for flash devices - */ - -static struct mtd_partition nandemul2k_partition[] = -{ - { .name = "NANDemul partition 1", - .offset = 0, - .size = 0 }, -}; - -static int nPartitions = sizeof(nandemul2k_partition)/sizeof(nandemul2k_partition[0]); - -/* - * Main initialization routine - */ -int __init nandemul2k_init (void) -{ - - // Do the nand init - - CheckInit(); - - nandemul2k_scan(&nandemul2k_mtd,1); - - // Build the partition table - - nandemul2k_partition[0].size = sizeInMB * 1024 * 1024; - - // Register the partition - add_mtd_partitions(&nandemul2k_mtd,nandemul2k_partition,nPartitions); - - return 0; - -} - -module_init(nandemul2k_init); - -/* - * Clean up routine - */ -#ifdef MODULE -static void __exit nandemul2k_cleanup (void) -{ - - nandemul2k_CleanUp(); - - /* Unregister partitions */ - del_mtd_partitions(&nandemul2k_mtd); - - /* Unregister the device */ - del_mtd_device (&nandemul2k_mtd); - -} -module_exit(nandemul2k_cleanup); -#endif - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Charles Manning <manningc@aleph1.co.uk>"); -MODULE_DESCRIPTION("2k Page/128k Block NAND emulated in RAM"); - - - -
new file mode 100644 --- /dev/null +++ b/packages/ecos.db @@ -0,0 +1,16 @@ +# ecos.db for ecos-anon-yaffs +# +# NB. This repo isn't expected to form part of the ordinary eCos +# repository, because of the special licensing of its contents. +# Nevertheless an ecos.db is useful so we can test-build against it easily. + +package CYGPKG_FS_YAFFS { + alias { "YAFFS filesystem" fs_yaffs yaffs } + directory fs/yaffs + script yaffs.cdl + description " + This package provides the YAFFS filesystem. + This software is covered by the full GNU GPL; see + the file GPL-2 for details." +} +
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/ChangeLog @@ -0,0 +1,88 @@ +2009-11-13 Ross Younger <wry@ecoscentric.com> + + * tests: yaffs1-6 NA unless CYGPKG_KERNEL is present. + * Update upstream: (pulled up to 2009-11-11 02:11:13 +0000) + - mostly bugfixes + +2009-11-09 Ross Younger <wry@ecoscentric.com> + + * ecos-yaffs-nand.c: Update for changes to NAND interface. + +2009-11-03 Ross Younger <wry@ecoscentric.com> + + * tests: Import from eCosPro: mounttime, yaffs1, yaffs2, + yaffs4, yaffs5, yaffs6. Patch for codebase differences. + +2009-11-02 Ross Younger <wry@ecoscentric.com> + + * Update to latest snapshot from Aleph One CVS (mostly + tidyups): last upstream change is dated "2009-10-30 02:32:32 +0000" + +2009-10-29 Ross Younger <wry@ecoscentric.com> + + * yaffs_guts.c: Fix low-memory assert bug. + +2009-10-09 Ross Younger <wry@ecoscentric.com> + + * tests/fops.c: Don't make unreasonable use of stack. + * Update for latest upstream snapshot (yaffs_FlushFile) + +2009-09-24 Ross Younger <wry@ecoscentric.com> + + * doc/yaffs.sgml: Various fixups. + * ecos-yaffs-nand.h, ecos-yaffs.c, yaffs_guts.c: Build fixes for + older gcc + +2009-09-16 Ross Younger <wry@ecoscentric.com> + + * ecos-yaffs-nand.c: Correctly use ECC on YAFFS tags in yaffs2 + filesystems when not in inbandTags mode (ref: 1000821) + * ecos-yaffs.c: Improve spare area size sanity checking on mount + * yaffs_packedtags2.c: Add framework (usually conditioned out) + to count ECC corrections within the spare area. + +2009-08-28 Ross Younger <wry@ecoscentric.com> + + * doc/yaffs.sgml: Bring explanations of CDL options up-to-date. + * yaffs.cdl: Add CYGNUM_FS_YAFFS_TEMP_BUFFERS tuning parameter. + +2009-08-26 Ross Younger <wry@ecoscentric.com> + + * Added support for small-page chips: incorporates and builds on work + by Simon Kallweit. Small page devices can operate either in YAFFS1 + mode, or YAFFS2 mode with inbandTags. + * Updated #defines to omit unneeded YAFFS code. + +2009-08-18 Ross Younger <wry@ecoscentric.com> + + * yaffs-guts.c: Update from Aleph One CVS (1.85 -> 1.88) + +2009-07-20 Ross Younger <wry@ecoscentric.com> + + * ecos-yaffs.c: Compute free-space from nErasedBlocks (recommended by + Charles Manning) - not yaffs_GetNumberOfFreeChunks. + +2009-07-03 Ross Younger <wry@eCosCentric.com> + + * Add detailed RAM use estimate and worked example. + +2009-06-18 Ross Younger <wry@eCosCentric.com> + + * General enhancements and bugfixes. + * Add mount-time mallinfo check/warning in debug builds. + * Replace unconditional diag_printfs with calls to TOUT macro. + * TOUT (trace output) macro now uses configable cdl function, + may be disabled. + * Improve our definition of YBUG. + * Upstream: Merge from cvs datestamp "2009-05-16 00:00" + * Retab eCos-specific files, for consistency. + * Pare down use of libextras. + * doc: linewrap for consistency. + * Elide unneeded YAFFS1 code. + * Use eCos qsort, not yaffs's own. + +2009-05-01 Ross Younger <wry@eCosCentric.com> + + * New package. YAFFS filesystem. Beware license terms; this + package is not covered by the standard eCos license! +
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/GPL-2 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License.
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/cdl/yaffs.cdl @@ -0,0 +1,289 @@ +# ==================================================================== +# +# yaffs.cdl +# +# YAFFS (Yet Another Flash File System) port to eCos +# +# ==================================================================== +# ####ECOSGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of eCos, the Embedded Configurable Operating System. +# Copyright (C) 2009 eCosCentric Limited. +# +# eCos is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 or (at your option) any later +# version. +# +# eCos is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with eCos; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception, if other files instantiate templates or use +# macros or inline functions from this file, or you compile this file +# and link it with other works to produce a work based on this file, +# this file does not by itself cause the resulting work to be covered by +# the GNU General Public License. However the source code for this file +# must still be made available in accordance with section (3) of the GNU +# General Public License v2. +# +# This exception does not invalidate any other reasons why a work based +# on this file might be covered by the GNU General Public License. +# ------------------------------------------- +# ####ECOSGPLCOPYRIGHTEND#### +# ==================================================================== +######DESCRIPTIONBEGIN#### +# +# Author(s): wry +# Date: 2009-05-01 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_FS_YAFFS { + display "YAFFS flash filesystem" + parent CYGPKG_FS + include_files + # there's nothing to include as we patch in to the fstab. + + requires CYGPKG_IO_FILEIO + requires CYGPKG_IO_NAND + requires CYGPKG_ISOINFRA + requires CYGINT_ISO_ERRNO + requires CYGINT_ISO_ERRNO_CODES + requires CYGINT_ISO_MALLOC + requires CYGPKG_LIBC_STDLIB + # STDLIB requires CYGINT_ISO_CTYPE, which is provided by CYGPKG_LIBC_I18N + requires CYGPKG_LIBC_STRING + + requires { CYGPKG_REDBOOT implies (CYGMEM_REDBOOT_WORKSPACE_HEAP_SIZE >= 0x00014000) } + + implements CYGINT_IO_FILEIO_FS + + compile -library=libextras.a ecos-yaffs.c + compile yaffs_checkptrw.c \ + yaffs_guts.c \ + yaffs_nand.c \ + yaffs_ecc.c \ + yaffs_packedtags1.c \ + yaffs_packedtags2.c \ + yaffs_tagscompat.c \ + yaffs_tagsvalidity.c \ + ecos-yaffs-nand.c \ + ecos-yaffs-diriter.c + + #doc ref/yaffs.html + description " + This package provides the YAFFS filesystem which is intended for + NAND flash devices." + + cdl_component CYGPKG_FS_YAFFS_OPTIONS { + display "YAFFS build options" + flavor none + description " + Package specific build options including control over + compiler flags used only in building the YAFFS code." + + cdl_option CYGPKG_FS_YAFFS_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "-Werror" } + description " + This option modifies the set of compiler flags for + building the YAFFS filesystem. These flags + are used in addition to the set of global flags." + } + cdl_option CYGPKG_FS_YAFFS_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the YAFFS filesystem. These flags + are removed from the set of global flags if present." + } + } + + cdl_option CYGSEM_FS_YAFFS_SMALLPAGE_MODE { + display "YAFFS mode for small page devices" + flavor data + default_value { "YAFFS2" } + legal_values { "YAFFS1" "YAFFS2" } + description " + Small page devices - those with 512 bytes/page - may operate + in either YAFFS1 mode, or YAFFS2 with the inband tags option. + This option selects the mode to use. Note that some chips + cannot support YAFFS1 mode, so this option may not be + relevant to you." + } + + cdl_option CYGSEM_FS_YAFFS_CACHE_SHORT_NAMES { + display "Cache short filenames in RAM" + default_value 1 + description " + If set, short names are cached in memory. + This consumes more RAM, but allows faster file look-ups." + } + + cdl_option CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE { + display "Omit YAFFS2-specific code" + default_value 1 + active_if { CYGSEM_FS_YAFFS_SMALLPAGE_MODE == "YAFFS1" } + active_if CYGNUM_NAND_PAGEBUFFER <= 512 + description " + This option causes some of the YAFFS2-specific code + to be omitted from the build, in order to reduce code + size. Obviously, this can only ever work if all your devices + are small-page, and you have configured YAFFS to run them in + YAFFS1 mode." + } + + cdl_option CYGPKG_FS_YAFFS_RET_DIRENT_DTYPE { + display "Support for fileio's struct dirent d_type field" + flavor bool + default_value 0 + active_if CYGPKG_FILEIO_DIRENT_DTYPE + description "This option controls whether the YAFFS filesystem + supports setting fileio's struct dirent d_type field. + If this option is enabled, d_type will be set." + } + + cdl_option CYGNUM_FS_YAFFS_RESERVED_BLOCKS { + display "Number of reserved blocks" + flavor data + default_value 5 + legal_values 2 to 0x7fffffff + description " + The number of eraseblocks YAFFS should keep in reserve to allow + for garbage collection and for block failures. A + minimum value of 5 is recommended if you are using real + (non-synthetic) NAND devices; wizards may wish to tune it to + improve performance. Note that this setting is a global + default and may be tuned per-device by a mount-time option." + } + + cdl_option CYGNUM_FS_YAFFS_SHORTOP_CACHES { + display "Number of cache entries" + flavor data + default_value 10 + legal_values 0 to 0x7fffffff + description " + The number of page cache entries to use. Values from 10 to 20 + are recommended; set to 0 to disable cacheing. + Wizards may wish to tune this value to improve performance. + Note that this setting is a global default and may be + configured per-device by a mount-time option. There is also + an upper limit hard-wired into the code as + YAFFS_MAX_SHORT_OP_CACHES; numbers in excess of this ceiling + will be ignored." + } + + cdl_option CYGNUM_FS_YAFFS_TEMP_BUFFERS { + display "Number of preallocated temporary page buffers" + flavor data + default_value 6 + legal_values 0 to 0x7fffffff + description " + At mount time, YAFFS preallocates a number of temporary + buffers, which are used in many places throughout the code. + This setting controls how many. + If YAFFS ever runs out of temporary buffers, it calls malloc to + dynamically allocate further buffers as needed. + Most users will not need to change this setting, but it may + prove a useful tuning parameter." + } + + cdl_option CYGNUM_FS_YAFFS_TRACEMASK { + display "Output trace mask" + flavor data + default_value 0 + legal_values 0 to 0xffffffff + description " + The YAFFS filesystem has a number of categories in which it can + emit diagnostic output. They are controlled by this setting, + which is a bitfield; set bits enable various categories. + For the definition of the bits used, see yportenv.h + (\"Tracing flags\"). They tend only to be useful for debugging. + " + } + + cdl_option CYGSEM_FS_YAFFS_TRACEFN { + display "Enable debug tracing" + flavor booldata + default_value { "diag_printf" } + description " + If enabled, diagnostic output from YAFFS will be sent to + this function." + } + + cdl_option CYGPKG_FS_YAFFS_TESTS { + display "YAFFS filesystem tests" + flavor data + no_define + calculated { "tests/fops tests/mounttime" + . " tests/yaffs1 tests/yaffs2 tests/yaffs4" + . " tests/yaffs5 tests/yaffs6" + } + description " + This special option specifies the set of tests to build for YAFFS." + } + + cdl_component CYGPKG_FS_YAFFS_TESTING { + display "Testing configuration" + default_value 1 + + define_proc { + puts $::cdl_system_header "/***** Synthdisk driver proc output start *****/" + puts $::cdl_system_header "#define CYGDAT_DEVS_DISK_CFG <pkgconf/fs_yaffs.h>" + puts $::cdl_system_header "/***** Synthdisk driver proc output end *****/" + } + + + cdl_option CYGDAT_DEVS_DISK_TEST_DEVICE { + display "Test device driver" + flavor data + default_value { CYGPKG_DEVS_NAND_SYNTH?"\"synth/0\"":"\"onboard/0\"" } + } + + cdl_option CYGDAT_DEVS_DISK_TEST_MOUNTPOINT { + display "Test filesystem mountpoint" + flavor data + default_value {"\"/nand\"" } + } + + cdl_option CYGDAT_DEVS_DISK_TEST_DIRECTORY { + display "Test directory on test device" + flavor data + default_value {"\"/test\"" } + } + + + cdl_option CYGDAT_DEVS_DISK_TEST_DEVICE2 { + display "Second Test device driver" + flavor data + default_value { CYGPKG_DEVS_NAND_SYNTH?"\"synth/1\"":"\"onboard/1\"" } + } + + cdl_option CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 { + display "Second Test filesystem mountpoint" + flavor data + default_value {"\"/nand2\"" } + } + + cdl_option CYGDAT_DEVS_DISK_TEST_DIRECTORY2 { + display "Test directory on second test device" + flavor data + default_value {"\"/test\"" } + } + + } + +}
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/doc/.gitignore @@ -0,0 +1,6 @@ +*.html +*.aux +*.log +*.out +*.pdf +*.tex
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/doc/makefile @@ -0,0 +1,8 @@ +TOPLEVEL := ../../../.. +MAIN_SGML := yaffs.sgml +MAIN_HTML := fs-yaffs.html +MAIN_PDF := fs-yaffs.pdf +OTHER_SGML := +PICTURES := + +include $(TOPLEVEL)/pkgconf/rules.doc
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/doc/yaffs.sgml @@ -0,0 +1,685 @@ +<!-- {{{ Banner --> + +<!-- =============================================================== --> +<!-- --> +<!-- yaffs.sgml --> +<!-- --> +<!-- Documentation for the eCos port of the YAFFS filesystem. --> +<!-- --> +<!-- =============================================================== --> +<!-- ####ECOSDOCCOPYRIGHTBEGIN#### --> +<!-- =============================================================== --> +<!-- Copyright (C) 2009 eCosCentric Ltd. --> +<!-- This material may be distributed only subject to the terms --> +<!-- and conditions set forth in the Open Publication License, v1.0 --> +<!-- or later (the latest version is presently available at --> +<!-- http://www.opencontent.org/openpub/) --> +<!-- Distribution of the work or derivative of the work in any --> +<!-- standard (paper) book form is prohibited unless prior --> +<!-- permission obtained from the copyright holder --> +<!-- =============================================================== --> +<!-- ####ECOSDOCCOPYRIGHTEND#### --> +<!-- =============================================================== --> +<!-- #####DESCRIPTIONBEGIN#### --> +<!-- --> +<!-- Author(s): wry --> +<!-- Date: 2009-05-28 --> +<!-- --> +<!-- ####DESCRIPTIONEND#### --> +<!-- =============================================================== --> + +<!-- }}} --> + +<!-- ### Uncomment to make a standalone book: +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"> +<book id="fs-yaffs-book"> + <bookinfo> + <title>The YAFFS filesystem for eCos</title> + <copyright><year>2009</year><holder>eCosCentric Limited</holder></copyright> + <legalnotice> + <title>Documentation licensing terms</title> + <para>This material may be distributed only subject to the terms + and conditions set forth in the Open Publication License, v1.0 + or later (the latest version is presently available at + <ulink url="http://www.opencontent.org/openpub/">http://www.opencontent.org/openpub/</ulink>). + </para> + <para> + Distribution of the work or derivative of the work in any + standard (paper) book form is prohibited unless prior + permission is obtained from the copyright holder. + </para> + </legalnotice> + </bookinfo> + ! /### --> + +<part id="fs-yaffs"> +<title>The YAFFS filesystem</title> + +<chapter id="yaffs-overview-c"> +<title>What is YAFFS?</title> + +<para> +YAFFS is a filesystem for NAND flash chips. +</para> + +<para> +YAFFS is accessed through the FILEIO package which presents a standard +POSIX compatible IO interface through which applications use standard +open(), read(), write() and close() calls. +</para> + +<para> +YAFFS is a <emphasis>journalling</emphasis> filesystem +with <emphasis>wear-levelling</emphasis>. It is +particularly suited to NAND flash parts, having been +designed with their unique properties in mind. +The use of traditional filesystems (FAT, ext2, etc) which do not have +these features is not recommended on such chips because their design +requires the use of fixed address on the underlying hardware. +Such behaviour causes flash sectors to wear out, the consequence of +which would typically be to cause the whole device to become unbootable. +</para> + +<para> +YAFFS also provides a high degree of robustness, which is usually +a requirement of embedded devices. +A power failure or other crash can leave a traditional filesystem +in an inconsistent state which is often difficult to repair, +especially in the field. +</para> + +<para> +YAFFS can also be built into RedBoot, which allows you to store +application images on NAND flash and boot them with +RedBoot's usual flexible scripting system. +</para> + +<para> +For more information about NAND flash chips, +how they differ from NOR flash parts +and other ways to access them, refer to the documentation for the +<xref linkend="io-nand-overview" endterm="io-nand-short">. +</para> + +<para> +For more information about YAFFS itself, refer to +<ulink url="http://www.yaffs.net/">yaffs.net</ulink>. +</para> +</chapter> + +<chapter id="yaffs-getstarted"><title>Getting started with YAFFS</title> + +<sect1 id="yaffs-licensing"><title>Licensing considerations</title> +<para> +Before you can use YAFFS, you must accept its license. +<emphasis>YAFFS is not covered by the standard eCos license.</emphasis> +You will be reminded of your license to use YAFFS when you install it. +</para> + +<para> +Most users will only have access to YAFFS under the GNU GPL. +This costs nothing to license. However this usually means that if you ever +distribute your application, +you must do so under the GPL. +This requires you to publish or otherwise make all of your application, +eCos and everything else you link with it available as source code. +For full details refer to the text of the +<ulink url="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GPL +(v2)</ulink>. +</para> + +<para> +If you cannot accept the restrictions and obligations of the GPL, +YAFFS for eCos is available under a proprietary license, for a fee. +Details are available on request from +<ulink url="http://www.ecoscentric.com/">eCosCentric</ulink> or +<ulink url="http://www.yaffs.net/yaffs-licences">Aleph One</ulink>. +</para> +</sect1> + +<sect1 id="yaffs-install"><title>Installation</title> +<para> +YAFFS is supplied as an EPK (eCos Package) file. +</para> + +<sect2 id="yaffs-install-configtool"><title>Installation via the eCos +Configuration Tool</title> +<para> +<orderedlist> +<listitem><para>Open up the eCos Configuration Tool.</para></listitem> +<listitem><para>Open up the <emphasis>Administration</emphasis> dialog, +from the <emphasis>Tools</emphasis> menu.</para></listitem> +<listitem><para>Press the <emphasis>Add</emphasis> button.</para></listitem> +<listitem><para>A file browser windows opens. Navigate to the YAFFS EPK file.</para></listitem> +<listitem><para>The License screen shows. You must accept the license +in order to install the package. Press Yes if you do.</para></listitem> +</orderedlist> +</para> +</sect2> + +<sect2 id="yaffs-install-commandline"><title>Installing from the +command-line</title> +<para> Advanced users may alternatively use the +<filename>ecosadmin.tcl</filename> tool from the command line. You +will be prompted to accept the license at the appropriate time during +the procedure. +</para> + +<programlisting> +tclsh $ECOS_REPOSITORY/ecosadmin.tcl add yaffs-v1_2_3.epk +</programlisting> +</sect2> +</sect1> + +<sect1 id="yaffs-config-build"><title>Configuration and Building</title> +<para> +After installing the EPK, YAFFS is added to your eCos repository +and is configured and built in the normal way. +</para> + +<sect2 id="yaffs-pkg-deps"><title>Package dependencies</title> +<para> +To link YAFFS into your application, +add <filename>CYGPKG_FS_YAFFS</filename> to your eCos +configuration in the normal way, either using the eCos Configuration Tool +(<emphasis>Packages</emphasis> dialog on the <emphasis>Build</emphasis> +menu), or the <filename>ecosconfig</filename> command-line tool.</para> + +<para> +You will also need to add <filename>CYGPKG_IO_NAND</filename> and +<filename>CYGPKG_IO_FILEIO</filename> to your configuration if they +are not already present. +Your platform HAL should supply packages for all NAND device(s) present. +</para> + +<para> +If you started with a smaller template than <emphasis>default</emphasis>, +you may also need to add some of the following:</para> +<itemizedlist> +<listitem><para><filename>CYGPKG_LIBC_STDLIB</filename></para></listitem> +<listitem><para><filename>CYGPKG_LIBC_STRING</filename> </para></listitem> +<listitem><para><filename>CYGPKG_MEMALLOC</filename> or something else +which provides <filename>CYGINT_ISO_MALLOC</filename></para></listitem> +<listitem><para><filename>CYGPKG_LIBC_I18N</filename> or something else +which provides <filename>CYGINT_ISO_CTYPE</filename></para></listitem> +</itemizedlist> +</sect2> + +<sect2 id="yaffs-pkg-options"><title>Configuration options</title> +<para> +YAFFS provides a number of package options, including tuning parameters. +</para> + +<variablelist> +<varlistentry><term><constant>CYGSEM_FS_YAFFS_CACHE_SHORT_NAMES</constant></term><listitem><para>If +set, caches files' short names in RAM. This consumes more RAM but +improves performance.</para></listitem></varlistentry> +<varlistentry><term><constant>CYGPKG_FS_YAFFS_RET_DIRENT_DTYPE</constant></term><listitem><para>Controls +whether YAFFS supports setting the <structfield>d_type</structfield> +field in a <structname>struct dirent</structname>. If you don't need +this, leave it switched off to save a little code size.</para></listitem></varlistentry> +<varlistentry><term><constant>CYGNUM_FS_YAFFS_RESERVED_BLOCKS</constant></term><listitem><para> +The number of blocks to keep in reserve to allow for garbage collection +and block failures. The recommended value is 5, but it can be tuned to suit your application: +higher numbers can reduce the delay caused by garbage collection, at the cost of removing +available space for storing files. +<emphasis>This setting is a global default and may be +changed by a mount-time option.</emphasis></para></listitem></varlistentry> +<varlistentry><term><constant>CYGNUM_FS_YAFFS_SHORTOP_CACHES</constant></term><listitem><para> +The number of page cache entries to use. Values of 10 to 20 are +recommended as a good compromise; increasing the number consumes more RAM but may +improve performance. +Set to 0 to disable these caches altogether. +<emphasis>This setting is a global default and may be +changed by a mount-time option.</emphasis></para></listitem></varlistentry> +<varlistentry><term><constant>CYGNUM_FS_YAFFS_TEMP_BUFFERS</constant></term> +<listitem><para> +YAFFS requires temporary buffers in many places throughout the code. +To avoid the overhead of a dynamic malloc every time, a number of +buffers are preallocated at mount time. This setting controls how many; +should it not prove enough, YAFFS will call maloc on demand as required. +The default setting is 6; most users will not need to change it. +</para></listitem></varlistentry> +<varlistentry><term><constant>CYGNUM_FS_YAFFS_TRACEMASK</constant></term><listitem><para>This +is a 32-bit bitfield which controls diagnostic output. The bit definitions +are found in <filename>yportenv.h</filename>; changing this setting tends to only be useful +if you wish to debug YAFFS itself.</para></listitem></varlistentry> +<varlistentry><term><constant>CYGPKG_FS_YAFFS_CFLAGS_ADD</constant></term> +<term><constant>CYGPKG_FS_YAFFS_CFLAGS_REMOVE</constant></term><listitem><para> +These settings allow specific build options to be added to or removed from the CFLAGS +list when building YAFFS.</para></listitem></varlistentry> +<varlistentry><term><constant>CYGSEM_FS_YAFFS_SMALLPAGE_MODE</constant></term> +<listitem><para>This option only affects behaviour on so-called "small page" NAND devices +(those whose pages are 512 bytes long). +Such devices do not have enough space in their Out Of Band area to +store a full set of YAFFS metadata tags. There are two ways to work +around this: <itemizedlist><listitem><para><constant>YAFFS2</constant> mode - +the default - uses regular tags, but at +a price: it steals 16 bytes from the available space per page to store +them. <emphasis>This reduces the apparent available +size of your filesystem by 1/32!</emphasis></para></listitem> +<listitem><para><constant>YAFFS1</constant> mode places a smaller tagset +in the OOB area, but with a different side-effect: whenever a page is +deleted, one byte of the tags area has to be rewritten. Some devices +forbid rewrite-without-erase in this way, so it may not be safe for you +to use this option. <emphasis>You must refer to the spec sheet for the chip on +your board before selecting this option!</emphasis></para></listitem></itemizedlist> +</para></listitem></varlistentry> +<varlistentry><term><constant>CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE</constant></term><listitem><para> +This causes all YAFFS2 code to be omitted from the build. This option only makes sense when +all the devices on which YAFFS is to be used are small-page and operating in YAFFS1 mode. +<note><para>There is no corresponding option to omit YAFFS1 code, because that code is only +compiled when <constant>CYGSEM_FS_YAFFS_SMALLPAGE_MODE</constant> is set to YAFFS1. </para></note> +</para></listitem></varlistentry> +</variablelist> +</sect2> +</sect1> + +<sect1 id="yaffs-using"><title>Using YAFFS</title> +<para> +YAFFS appears in the eCos filesystem table. +This means that you can mount a filesystem in the standard Unix-like way, +then interact with it with calls to open, read, etc. +</para> + +<sect2 id="yaffs-mounting"><title>Mounting a filesystem</title> + +<para> +Before you can use a filesystem, it must be <emphasis>mounted</emphasis>. +</para> + +<para> +A NAND device is logically organised as one or more +<emphasis>partitions</emphasis>, which are +usually set up by the relevant platform HAL. +You need to tell the mount command +which device and partition you wish to access. In the following example, +we are mounting partition 0 of the <emphasis>onboard</emphasis> NAND device. +</para> +<!-- FIXME: Update if partition naming is changed. --> + +<programlisting> +rv = mount("onboard/0", "/nand", "yaffs"); +</programlisting> + +<note><para>The <emphasis>device</emphasis> argument to the +<function>mount</function> call is a NAND-specific device name, not +an entry in /dev. +Refer to the documentation for your platform HAL for details of how +the NAND device(s) are named, and to the NAND library documentation +for details of how partitions are addressed. +</para></note> + +<para> +You can, if you wish, make the filesystem mounting automatic at +static constructor time with the MTAB_ENTRY macro. (Your platform +HAL may already do this; check it carefully.) +</para> + +<programlisting> +MTAB_ENTRY(my_nand, "/nand", "yaffs", "onboard/0", "", 0); +</programlisting> + +<note><para>This example is for eCosPro. In eCos, the MTAB_ENTRY macro +takes only four arguments.</para></note> + +<sect3 id="yaffs-mount-options"><title>Mount-time options</title> +<para> +eCosPro allows various options to be passed to a filesystem at mount time, +by combining them with the filesystem argument in a particular format. +YAFFS understands the following options: +</para> + +<itemizedlist> +<listitem><para><constant>reserved</constant>=<int> The number of +physical NAND blocks to reserve for garbage collection and block failures +(minimum 2). The default is set in CDL as +<constant>CYGNUM_FS_YAFFS_RESERVED_BLOCKS</constant>.</para></listitem> +<listitem><para><constant>caches</constant>=<int> The number of +page cache entries to use. +Values of 10 to 20 are recommended. +The default is set in CDL as +<constant>CYGNUM_FS_YAFFS_SHORTOP_CACHES</constant>.</para></listitem> +<listitem><para><constant>skip-checkpoint-read</constant> Instructs YAFFS +to not attempt to reload the filesystem from a checkpoint, if one exists. +In other words, this option forces a full filesystem scan whether or not +one is necessary.</para></listitem> +</itemizedlist> +</sect3> +</sect2> + +<sect2 id="yaffs-sync"><title>Data flushing</title> +<para> +YAFFS operates a cacheing layer in order to save undue wear on the +NAND chip if many small writes are performed. Because of this, +if you wish to ensure that any data written to a still-open file has +been fully flushed, you must make a synchronisation request. This is +done with the <function>fsync</function> function, which takes as its +argument the file descriptor of the file you wish to synchronise.</para> +</sect2> + +<sect2 id="yaffs-checkpointing"><title>Checkpointing</title> +<para> +When mounting a filesystem, YAFFS has to scan the NAND chip to recreate +its internal state. This can be a slow process, but is made much +faster if there is a valid <emphasis>checkpoint</emphasis>. +</para> + +<para> +A checkpoint is written out automatically when you unmount the filesystem. +At any other time, you can manually force a checkpoint to be written +with one of the following functions: +</para> + +<itemizedlist> +<listitem><para><function>cyg_fs_fssync(mountpoint)</function> +synchronises a filesystem (automatically called on umount)</para></listitem> +<listitem><para><function>sync</function> synchronises all mounted +filesystems.</para></listitem> +</itemizedlist> + +<note><para> +A checkpoint becomes invalid as soon as there have been any other writes +to the filesystem. Finding a good place to sync is necessarily dependent +on your application logic.</para> +</note> +</sect2> + +<sect2 id="yaffs-limitations"><title>Limitations</title> +<para> +Although YAFFS is a Unix-compatible filesystem, the eCos port does not +provide support for the full range of Unix attributes. +</para> +<itemizedlist> +<listitem><para> eCos does not check file or directory permissions; +everything it creates is given fixed user and group IDs of zero and +standard permissions (files rw-r--r--, directories rwxr-xr-x).</para></listitem> +<listitem><para> It is not currently possible to change file ownership +or permissions.</para></listitem> +<listitem><para> It is not currently possible to create symbolic links, +FIFOs (named pipes), sockets or device nodes.</para></listitem> +<listitem><para> Hard links to files work in the expected way. Hard +links to directories are forbidden.</para></listitem> +<listitem><para> It is not possible to unlink the '.', '..' or +'lost+found' special directories.</para></listitem> +</itemizedlist> + +<note><para> +If you will be sharing a YAFFS filesystem between eCos and some other +operating system, you are advised to carefully check the other system's +definitions of mode (permission) bits and whether any translation may be +required.</para> +</note> +</sect2> +</sect1> + +<sect1 id="yaffs-mem-reqs"><title>Memory requirements</title> +<para> +The amount of RAM required by YAFFS to hold its in-memory data structures +grows with the number of objects (files and directories) in your +filesystem. +You are recommended to test your application thoroughly to ensure +that sufficient memory exists for YAFFS to operate with the +most complicated filesystem it is likely to encounter.</para> + +<para> +If you wish to estimate your RAM usage, the YAFFS author provides the +following calculation:</para> + +<itemizedlist> +<listitem><para> The partition itself requires a yaffs_DeviceStruct of 3608 +bytes.</para></listitem> +<listitem><para> If CYGNUM_FS_YAFFS_SHORTOP_CACHES is enabled, each +is the size of a NAND page plus 28 bytes.</para></listitem> +<listitem><para> Every object (file, directory or hardlink) in the +filesystem takes a yaffs_Object struct, which is 124 bytes.</para></listitem> +<listitem><para> Every page of every file requires a Tnode entry, but +they are always allocated in groups of 16 at a time.</para> + <itemizedlist> + <listitem><para>The size of a single Tnode entry is the + number of <emphasis>bits</emphasis> required to number all the + pages in the NAND partition YAFFS is using, numbering from + <emphasis>one</emphasis>; this is rounded up to a multiple of 2, + and has an absolute minimum of sixteen bits.</para></listitem> + <listitem><para>For example: on a partition with 65536 pages, + seventeen bits are required for the numbering, which round up to + 18. Therefore each file takes 288 bits (36 bytes) per group of Tnodes, + and one group of Tnodes will cover up to sixteen pages of data.</para></listitem> + </itemizedlist> + </listitem> +</itemizedlist> + +<note><para><emphasis>Actual memory consumption will be slightly +higher than suggested by the above.</emphasis> This arises from the +tree structure holding the Tnodes, overheads from the heap itself, +and so on.</para></note> + +<para> +YAFFS calls the standard <function>malloc</function> function to allocate +memory and <function>free</function> to release it. Normally, the eCos +heap occupies all spare RAM not needed for the program, its static +data or the stacks. Therefore, most applications will not need to do +anything special beyond ensuring there is enough spare RAM available on +the platform.</para> + +<tip><para> +If you wish to experiment with restricted-size heaps to determine +much memory your application actually uses under YAFFS, +you may find the option +<constant>CYGSEM_MEMALLOC_INVOKE_OUT_OF_MEMORY</constant> of use. +</para></tip> + +<sect2 id="yaffs-mem-reqs-example"><title>Worked example</title> +<para> +Consider a YAFFS filesystem hosted by a NAND partition with 65536 pages, +each of size 2k, using the default setting of ten short-op caches. +On this filesystem we shall store 10000 files each of +size 10240 bytes, hence each requires a single group of Tnodes. +</para> + +<table frame=all pgwide=0><title>YAFFS RAM use worked example</title> +<tgroup cols=2> +<colspec colname=c1> +<colspec colname=c2> +<thead><row> +<entry>Consumer</entry> +<entry>RAM used (bytes)</entry> +</row></thead> +<tfoot><row> +<entry>Total</entry> +<entry align=right> 1,624,368 </entry> +</row></tfoot> +<tbody> +<row> +<entry> yaffs_DeviceStruct </entry> +<entry align=right> 3,608 </entry> +</row> +<row> +<entry> Short-op caches @ 10 x (2048+28)</entry> +<entry align=right> 20,760 </entry> +</row> +<row> +<entry> yaffs_Objects @ 10,000 x 124 </entry> +<entry align=right> 1,240,000 </entry> +</row> +<row> +<entry> Tnode groups @ 10,000 x 36 <emphasis>(see above)</emphasis></entry> +<entry align=right> 360,000 </entry> +</row> +</tbody> +</tgroup> +</table> + +<para> +This example is a close match to the actual consumption measured by +eCosCentric during testing. (The measured consumption as reported +by <function>mallinfo</function> was 1,681,112 bytes, which includes +the heap's own overheads.) +</para> +</sect2> +</sect1> + +<sect1 id="yaffs-testing"><title>Testing</title> +<para> +YAFFS is supplied with a number of test programs, some of which are have been +adapted from tests for other filesystems in eCos. +</para> + +<glosslist> +<glossentry><glossterm>fops</glossterm><glossdef><para> +This was the first basic test created for the port of the filesystem. +It is believed to exercise all of the code paths (filesystem operations, +file operations and directory operations) within the eCos-YAFFS +adaptation layer. </para> <para> +This test was originally intended to run on a synthetic NAND filesystem. +On real NAND chips, it deliberately omits the more stressful routines to +avoid undue wear on the hardware. +</para></glossdef></glossentry> +<glossentry><glossterm>yaffs1</glossterm><glossdef><para> +A number of filesystem edge-case semantic tests, including +file and directory creation and deletion, +invalid open and rename operations, and +removing nonexistent files and directories. +</para></glossdef></glossentry> +<glossentry><glossterm>yaffs2</glossterm><glossdef><para> +Concurrent multi-threaded filesystem access and consistency checks. +</para></glossdef></glossentry> +<glossentry><glossterm>yaffs4</glossterm><glossdef><para> +Semantic and edge-case testing - like yaffs1 - but with long file names. +</para></glossdef></glossentry> +<glossentry><glossterm>yaffs5</glossterm><glossdef><para> +Tests that file reading and writing works over reasonably large files +(up to 1Mbyte) with different I/O chunk sizes. Some operation timings +are collected and reported, as is the data rate on large files. +</para></glossdef></glossentry> +<glossentry><glossterm>yaffs6</glossterm><glossdef><para> +Semantic and edge-case testing - like yaffs1 - but with Cyrillic filenames +in order to test UTF-8 correctness. +</para></glossdef></glossentry> +<glossentry><glossterm>mounttime</glossterm><glossdef><para> +A simple benchmark which repeatedly mounts and unmounts the filesystem +and measures how long this takes. +You can optionally use the <filename>mkfiles</filename> routine - also +present in the tests directory - to create many short files so you can +test performance on a loaded filesystem. +</para></glossdef></glossentry> +<glossentry><glossterm>hammer</glossterm><glossdef><para> +A stress test designed to shake out corner cases. +Repeatedly creates many files of varying sizes from multiple threads +until the filesystem fills up, then verifies their contents and removes +them. From time to time, all threads pause and the filesystem is +unmounted and remounted. </para><para>This test is particularly useful when +combined with the bad block injection functionality provided by +the synthetic NAND device. It has been used in this way by eCosCentric to +thoroughly test this package's stability under error conditions. +<note><para>This test runs forever, until interrupted.</para></note> +</para></glossdef></glossentry> +</glosslist> +</sect1> +</chapter> + +<chapter id="yaffs-redboot"><title>Using YAFFS with RedBoot</title> +<para> +It is possible to link YAFFS into RedBoot and use it to boot an +executable image stored on a NAND array. +</para> + +<para> +This is done by configuring and building RedBoot largely in the normal way. +You will need to add <filename>CYGPKG_FS_YAFFS</filename> and +<filename>CYGPKG_IO_FILEIO</filename> to your configuration, plus their +attendant dependencies. +</para> + +<para> +The presence of CYGPKG_IO_FILEIO activates the <filename>fs</filename> series +of RedBoot commands. The following (edited) transcript illustrates how +they might +be used in concert with other RedBoot commands to store an ELF image on +a NAND partition, load it back and execute: +</para> + +<programlisting> +RedBoot> fs mount -d onboard/0 -t yaffs /nand +yaffs: restored from checkpoint +RedBoot> load -r -h my.tftp.ip.address -b %{freememlo} my.image +Using default protocol (TFTP) +Raw file loaded 0xa013f000-0xa01554b3, assumed entry at 0xa013f000 +RedBoot> fs write /nand/myimg.elf +RedBoot> fs list /nand + 1 drwxr-xr-x 0 size 0 . + 1 drwxr-xr-x 0 size 0 .. + 262 -rw-r--r-- 0 size 91316 myimg.elf + 2 drwxr-xr-x 0 size 0 lost+found +RedBoot> load -m file /nand/myimg.elf +RedBoot> go +Hello, NAND world! +</programlisting> + +<note><para>When you command RedBoot to execute an image, it +first synchronises all mounted filesystems. Therefore, +provided these filesystems support the synchronisation operation +(which YAFFS does), it is not always necessary to unmount them before +invoking an image. +</para> +</note> + +<sect1 id="yaffs-rb-mem"><title>Memory considerations under RedBoot</title> +<para> +RedBoot traditionally has very limited requirements for memory management; +the main need is for there to be free space in RAM at the correct +(physical) address to load an image before jumping to it. +</para> + +<para> +Introducing YAFFS brings with it not just the need to have dynamically +allocatable RAM (<filename>CYGPKG_MEMALLOC</filename>), but enough +to replay the filesystem journal. This must be balanced against the need +for RAM to load images into. +</para> + +<para> +When the <filename>CYGPKG_MEMALLOC</filename> package is present in +RedBoot, by default a small (64k) heap is set up so that the maximum RAM +possible is available for loading images. This is not enough to +support YAFFS in any circumstances, so the following definition has +been included in the <filename>yaffs.cdl</filename> file: +</para> + +<programlisting> +requires { CYGPKG_REDBOOT implies (CYGMEM_REDBOOT_WORKSPACE_HEAP_SIZE >= 0x00014000) } +</programlisting> + +<caution><para> +This declaration only provideds the bare minimum heap required to mount a +trivial YAFFS filesystem. More will be required for all but the simplest +of cases and it is recommended that you test for typical use in your +environment. Refer also to <xref linkend="yaffs-mem-reqs">. +</para></caution> + +<para> +It is recommended that, should you wish to make a filesystem usable by +RedBoot, your platform HAL should make a similar +declaration in its CDL to establish an appropriate heap size. + +For example, the platform HAL for the EA LPC2468 OEM board - which has +a 128MB NAND chip on-board - contains the following declaration: +</para> + +<programlisting> +requires { (CYGPKG_REDBOOT && CYGPKG_FS_YAFFS) implies (CYGMEM_REDBOOT_WORKSPACE_HEAP_SIZE >= 0x20000) } +</programlisting> + +<tip><para> +If you wish to experiment with restricted heaps to determine +much memory your application actually uses under YAFFS, +you may find the option +<constant>CYGSEM_MEMALLOC_INVOKE_OUT_OF_MEMORY</constant> of use. +</para></tip> +</sect1> +</chapter> +</part> + +<!-- ### Uncomment to make a standalone book: +</book> + /### -->
rename from devextras.h rename to packages/fs/yaffs/current/src/devextras.h --- a/devextras.h +++ b/packages/fs/yaffs/current/src/devextras.h @@ -20,6 +20,8 @@ * */ +#include "ecos-yaffs.h" + #ifndef __EXTRAS_H__ #define __EXTRAS_H__
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yaffs-diriter.c @@ -0,0 +1,89 @@ +/* + * 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. + */ + +//============================================================================= +// +// ecos-yaffs-diriter.c +// +// Directory Iterator support for the eCos-YAFFS adaptation layer +// +//============================================================================= +// +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-07 +// Note: This file is a derivative work of direct/yaffsfs.c and so +// should be taken as inheriting its license terms - hence the +// copyright banner above. +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include "ecos-yaffs-diriter.h" +#include <cyg/infra/cyg_ass.h> + +// Directory operations -------------------------------------------------- + +struct ylist_head eyaffs_all_diriters; + +void eyaffs_diriter_advance(eyaffs_diriter *ctx) +{ + CYG_ASSERT(ctx && ctx->node && ctx->node->variantType == YAFFS_OBJECT_TYPE_DIRECTORY, "node not a directory"); + if ( !ctx->nextret ) return; // already finished, nothing to do + + struct ylist_head * top = &ctx->node->variant.directoryVariant.children; + + if (ylist_empty(top)) { + ctx->nextret = NULL; + return; + } + + struct ylist_head *next = ctx->nextret->siblings.next; + + if( next == top ) // finished + ctx->nextret = NULL; + else + ctx->nextret = ylist_entry(next,yaffs_Object,siblings); // works backwards from 'next' to its containing y_Object +} + +void eyaffs_diriter_rewind(eyaffs_diriter *ctx) +{ + CYG_ASSERT(ctx && ctx->node && ctx->node->variantType == YAFFS_OBJECT_TYPE_DIRECTORY, "node not a directory"); + + struct ylist_head * top = &ctx->node->variant.directoryVariant.children; + if (ylist_empty(top)) + ctx->nextret = NULL; + else + ctx->nextret = ylist_entry(top->next, yaffs_Object, siblings); +} + +void eyaffs_diriter_objremove_callback(yaffs_Object *obj) +{ + struct ylist_head *i; + eyaffs_diriter *cur; + + if(!eyaffs_all_diriters.next) return; // nothing to do + + ylist_for_each(i, &eyaffs_all_diriters) { // foreach ($i) @eyaffs_all_diriters + if (i) { + // 'i' points to the 'iterlist' member of an eyaffs_diriter, sort out cur to point to it + cur = ylist_entry(i, eyaffs_diriter, iterlist); + + if(cur->nextret == obj) // then fix it up + eyaffs_diriter_advance(cur); + } + } +} +
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yaffs-diriter.h @@ -0,0 +1,71 @@ +#ifndef CYGONCE_ECOS_YAFFS_DIRITER_H +#define CYGONCE_ECOS_YAFFS_DIRITER_H +//============================================================================= +// +// ecos-yaffs-diriter.h +// +// Directory Iterator support for the eCos-YAFFS adaptation layer +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-07 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include "yaffs_guts.h" + +// Directory operations -------------------------------------------------- + +/* Directory iterator used by readdir(). + * We need to keep track of all live diriters so as to avoid jumping off + * to Fishkill in the event that our next-object-to-return is deleted. + * Thankfully, yaffs provides a callback mechanism so we can detect + * this case. */ +typedef struct eyaffs_diriter { + struct ylist_head iterlist; // doubly linked list, impl by devextras.h + yaffs_Object * node; + yaffs_Object * nextret; // next one to return +} eyaffs_diriter; + +extern struct ylist_head eyaffs_all_diriters; + +void eyaffs_diriter_advance(eyaffs_diriter *ctx); +void eyaffs_diriter_rewind(eyaffs_diriter *ctx); +void eyaffs_diriter_objremove_callback(yaffs_Object *obj); + +#endif //CYGONCE_ECOS_YAFFS_DIRITER_H
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yaffs-nand.c @@ -0,0 +1,282 @@ +//============================================================================= +// +// ecos-yaffs-nand.c +// +// Glue for YAFFS to the eCos NAND library +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-07 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include "ecos-yaffs.h" +#include "ecos-yaffs-nand.h" +#include "yaffs_packedtags1.h" +#include "yaffs_packedtags2.h" +#include "yaffs_tagscompat.h" +#include <cyg/nand/util.h> // for BLOCK2PAGEADDR + +int eyaffs_initialiseNAND (struct yaffs_DeviceStruct * dev) +{ + // Nothing to do - we've already inited it in mount(). + //cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; + return YAFFS_OK; +} + +int eyaffs_deinitialiseNAND (struct yaffs_DeviceStruct * dev) +{ + // Nothing to do + //cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; + return YAFFS_OK; +} + +int eyaffs_eraseBlockInNAND (struct yaffs_DeviceStruct * dev, int blockInNAND) +{ + cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; + int rv = cyg_nand_erase_block(part, blockInNAND); + return rv==0 ? YAFFS_OK : YAFFS_FAIL; +} + +int eyaffs_writeChunkWithTagsToNAND (struct yaffs_DeviceStruct * dev, + int chunkInNAND, const __u8 * data, + const yaffs_ExtendedTags * tags) +{ + cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; + int rv; + + if (!dev->isYaffs2) { +#ifdef CONFIG_YAFFS_NO_YAFFS1 + rv = 1; +#else + yaffs_PackedTags1 pt1; + + if (tags->chunkDeleted) { + memset(&pt1, 0xff, sizeof(pt1)); + pt1.deleted = 0; + //((CYG_BYTE*)&pt1)[8] = 0; // TODO: support 9BYTE_TAGS, if there is a demand to (requires corresponding fixup in the ECC check below) + } else { + yaffs_PackTags1(&pt1, tags); + yaffs_CalcTagsECC((yaffs_Tags *)&pt1); + } + rv = cyg_nand_write_page(part, chunkInNAND, data, &pt1, PACKEDTAGS1_OOBSIZE); +#endif + } else { +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE + return YAFFS_FAIL; +#else + // YAFFS2 mode. + // N.B. We are not doing ECC - the NAND layer does that - so don't + // need to bother with the whole tags struct, just the bit that matters. + + if (!data || !tags) { + T(YAFFS_TRACE_ERROR, + (TSTR("**>> yaffs2: both data and tags must be present" TENDSTR))); + YBUG(); + return YAFFS_FAIL; + } + + if (dev->inbandTags) { + yaffs_PackedTags2TagsPart *pt2tp; + pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); + yaffs_PackTags2TagsPart(pt2tp, tags); + rv = cyg_nand_write_page(part, chunkInNAND, data, 0, 0); + } else { + yaffs_PackedTags2 pt; + void *packed_tags_ptr = dev->noTagsECC ? (void*) &pt.t : (void*) &pt; + yaffs_PackTags2(dev, &pt, tags); + rv = cyg_nand_write_page(part, chunkInNAND, data, packed_tags_ptr, PACKEDTAGS2_OOBSIZE(dev)); + } +#endif + } + + // all done: + return rv==0 ? YAFFS_OK : YAFFS_FAIL; +} + +int eyaffs_readChunkWithTagsFromNAND (struct yaffs_DeviceStruct * dev, + int chunkInNAND, __u8 * data, + yaffs_ExtendedTags * tags) +{ + cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; + int localData = 0; + int rv; + + if (!dev->isYaffs2) { +#ifdef CONFIG_YAFFS_NO_YAFFS1 + rv = 1; +#else + yaffs_PackedTags1 pt1; + memset(&pt1, 0xff, sizeof(yaffs_PackedTags1)); + + rv = cyg_nand_read_page(part, chunkInNAND, data, &pt1, PACKEDTAGS1_OOBSIZE); + + if (rv == 0) { + if (yaffs_CheckFF((CYG_BYTE*)&pt1, 8)) { + // block is empty + if (tags) { + memset(tags, 0, sizeof(*tags)); + tags->eccResult = YAFFS_ECC_RESULT_NO_ERROR; + } + } else { + // must check and correct tags' mini-ecc. + int deleted = !pt1.deleted; // this would break the tags ECC. + pt1.deleted = 1; + // TODO: support 9BYTE_TAGS if there is a demand. + int rv2 = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1); + if (rv2 < 0) { + T(YAFFS_TRACE_ERROR, + (TSTR ("**>>yaffs ecc error unfixed on chunk %d:0" + TENDSTR), chunkInNAND)); + dev->eccUnfixed++; + rv = EIO; + } else { + if (tags) { + yaffs_UnpackTags1(tags, &pt1); + tags->chunkDeleted = deleted; + tags->eccResult = YAFFS_ECC_RESULT_NO_ERROR; + } + + if (rv2 > 0) { + T(YAFFS_TRACE_ERROR, + (TSTR ("**>>yaffs ecc tags error fix performed on chunk %d:0" + TENDSTR), chunkInNAND)); + dev->eccFixed++; + if (tags) + tags->eccResult = YAFFS_ECC_RESULT_FIXED; + } + } + } + } // else reading the NAND failed; drop out +#endif + + } else { // YAFFS2 mode +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE + return YAFFS_FAIL; +#else + if (dev->inbandTags) { + if (!data) { + localData = 1; + data = yaffs_GetTempBuffer(dev, __LINE__); + } + + rv = cyg_nand_read_page(part, chunkInNAND, data, 0, 0); + if (tags) { + yaffs_PackedTags2TagsPart *pt2tp; + pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; + yaffs_UnpackTags2TagsPart(tags, pt2tp); + } + } else { + yaffs_PackedTags2 pt; + void *packed_tags_ptr = dev->noTagsECC ? (void*) &pt.t : (void*) &pt; + rv = cyg_nand_read_page(part, chunkInNAND, data, packed_tags_ptr, tags ? PACKEDTAGS2_OOBSIZE(dev) : 0); + if (tags) + yaffs_UnpackTags2(dev, tags, &pt); + } +#endif + } + + // all done: + if (localData) + yaffs_ReleaseTempBuffer(dev, data, __LINE__); + + if (rv != 0) { + if (tags) { + // mark the tags as clearly useless + memset(tags, 0, sizeof(yaffs_ExtendedTags)); + tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; + tags->blockBad = 1; + } + return YAFFS_FAIL; + } + return YAFFS_OK; + // TODO: go through yaffs_guts and ensure that all calls to ReadChunksWithTagsFromNAND DTRT on FAIL or if the read tags aren't valid. +} + +int eyaffs_markNANDBlockBad (struct yaffs_DeviceStruct * dev, int blockNo) +{ + cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; + int rv = cyg_nand_bbt_markbad(part, blockNo); + return rv==0 ? YAFFS_OK : YAFFS_FAIL; +} + +int eyaffs_queryNANDBlock (struct yaffs_DeviceStruct * dev, int blockNo, + yaffs_BlockState * state, __u32 *sequenceNumber) +{ + yaffs_ExtendedTags tags; + cyg_nand_page_addr pg; + cyg_nand_partition *part = (cyg_nand_partition*) dev->genericDevice; + + int rv = cyg_nand_bbt_query(part, blockNo); + if (rv < 0) return YAFFS_FAIL; + + switch(rv) { + case CYG_NAND_BBT_OK: + // Now we need to read the tags from the OOB area of the first page + pg = CYG_NAND_BLOCK2PAGEADDR(part->dev, blockNo); + // TODO: This is quite inefficient on small page devices in + // YAFFS2 mode with inbandTags enabled, as the whole page has + // to be read. Some day, it would be nice to implement part-page + // reads in the NAND layer where this can be efficiently done. + int rv2 = eyaffs_readChunkWithTagsFromNAND(dev, pg, 0, &tags); + if (rv2 == YAFFS_FAIL) { + (void) cyg_nand_bbt_markbad(part, blockNo); + goto deadblock; + } + if (tags.chunkUsed) { + *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; + *sequenceNumber = tags.sequenceNumber; + return YAFFS_OK; + } + *state = YAFFS_BLOCK_STATE_EMPTY; + *sequenceNumber = 0; + return YAFFS_OK; + + case CYG_NAND_BBT_WORNBAD: + case CYG_NAND_BBT_RESERVED: + case CYG_NAND_BBT_FACTORY_BAD: + deadblock: + *state = YAFFS_BLOCK_STATE_DEAD; + *sequenceNumber = 0; + return YAFFS_OK; + default: + YBUG(); // can't happen + return YAFFS_FAIL; + } +} +
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yaffs-nand.h @@ -0,0 +1,84 @@ +#ifndef CYGONCE_ECOS_YAFFS_NAND_H +#define CYGONCE_ECOS_YAFFS_NAND_H +//============================================================================= +// +// ecos-yaffs-nand.h +// +// Glue for YAFFS to the eCos NAND library +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-07 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/nand/nand.h> +#include "yaffs_guts.h" // extendedTags +#include "devextras.h" // __u8 and __u32 + +// If writing a yaffs_PackedTags1, we store only its eight meaningful bytes +#define PACKEDTAGS1_OOBSIZE 8 +#define PACKEDTAGS2_OOBSIZE(dev) (dev->noTagsECC ? \ + (unsigned)sizeof(yaffs_PackedTags2TagsPart) : \ + (unsigned)sizeof(yaffs_PackedTags2)) + +int eyaffs_eraseBlockInNAND (struct yaffs_DeviceStruct * dev, int blockInNAND); +int eyaffs_initialiseNAND (struct yaffs_DeviceStruct * dev); +// not mandatory: +int eyaffs_deinitialiseNAND (struct yaffs_DeviceStruct * dev); + +#ifdef CYGSEM_FS_YAFFS_SMALLPAGE_MODE_YAFFS1 +int eyaffs_writeChunkToNAND(struct yaffs_DeviceStruct *dev, + int chunkInNAND, const __u8 *data, + const yaffs_Spare *spare); +int eyaffs_readChunkFromNAND(struct yaffs_DeviceStruct *dev, + int chunkInNAND, __u8 *data, + yaffs_Spare *spare); +#endif + +int eyaffs_writeChunkWithTagsToNAND (struct yaffs_DeviceStruct * dev, + int chunkInNAND, const __u8 * data, + const yaffs_ExtendedTags * tags); +int eyaffs_readChunkWithTagsFromNAND (struct yaffs_DeviceStruct * dev, + int chunkInNAND, __u8 * data, + yaffs_ExtendedTags * tags); +int eyaffs_markNANDBlockBad (struct yaffs_DeviceStruct * dev, int blockNo); +int eyaffs_queryNANDBlock (struct yaffs_DeviceStruct * dev, int blockNo, + yaffs_BlockState * state, __u32 *sequenceNumber); + +#endif //CYGONCE_ECOS_YAFFS_NAND_H
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yaffs.c @@ -0,0 +1,1032 @@ +//============================================================================= +// +// ecos-eyaffs.c +// +// eyaffs interface to the eCos filesystem layer +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-05 +// +//####DESCRIPTIONEND#### +//============================================================================= + +/* Major TODO: + * At the moment we tend to look files up by name(dirsearch), perform + * our own sanity checks, then pass on to YAFFS fns which then go and + * repeat the last step of the lookup. IWBNI we exposed corresponding + * YAFFS functions which took yaffs_Object* instead of name. */ + +#include "yportenv.h" +#include "yaffs_guts.h" +#include "yaffs_packedtags2.h" +#include "ecos-yaffs.h" +#include "ecos-yaffs-nand.h" +#include "ecos-yaffs-diriter.h" + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> +#include <cyg/fileio/fileio.h> +#include <cyg/fileio/dirent.h> +#include <cyg/infra/cyg_ass.h> +#include <cyg/nand/nand.h> +#include <cyg/nand/util.h> + +// convenience error test macros. x should be an ecos error code. +#define ER(x) do { int _x = (x); if (_x != 0) return _x; } while(0) +#define EG(x) do { _err = (x); if (_err != 0) goto err_exit; } while(0) +// ... variants which take a negative ecos error code +#define ERm(x) ER(-(x)) +#define EGm(x) EG(-(x)) +// ... variants for YAFFS ops, which return YAFFS_OK or YAFFS_FAIL +#define YER(x) do { int _x = (x); if (_x == YAFFS_FAIL) return EIO; } while(0) + +// sneaky grab from fileio misc.cxx: +__externC cyg_mtab_entry cyg_mtab[]; +__externC cyg_mtab_entry cyg_mtab_end; + +// For yaffs_guts: +unsigned int yaffs_traceMask = CYGNUM_FS_YAFFS_TRACEMASK; + +// How many attempts do we make to write a page before giving up? +// This could easily be added to CDL. +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; + +// eCos doesn't support file permissions or user IDs at all. +// We hard-code sensible values in case anybody makes decisions on +// the output from stat() et al. +// (Update: As of March 2009 there is now limited support for chmod in both +// anoncvs and eCosPro.) +#define FIXED_UID 0 +#define FIXED_GID 0 +#define DIRECTORY_FIXED_PERMS (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) +#define FILE_FIXED_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) +// TODO: We could make uid/gid/fixedperms configurable. + +// Helper functions and forward defs ------------------------------------- +static int eyaffs_count_links(yaffs_Object * node) +{ + int links = 0; + struct ylist_head *tmp; + ylist_for_each(tmp, &(node->hardLinks)) { + ++links; + } + return links; +} + +static int eyaffs_stat_object(yaffs_Object *node, struct stat *buf); + +// Directory search / traversal ------------------------------------------ +typedef struct ey_dirsearch +{ + yaffs_Object *dir; // directory to search + const char *path; // path to follow + yaffs_Object *node; // Node found + const char *name; // last name used + int namelen;// name fragment length + cyg_bool last; // last name in path? +} ey_dirsearch; + +static void init_dirsearch(ey_dirsearch *ds, yaffs_Object *dir, const char *name) +{ + ds->dir = dir; + ds->path = name; + ds->node = dir; + ds->name = name; + ds->namelen = 0; + ds->last = false; +} + +// Search a single directory for the next name in a path +static int find_entry(ey_dirsearch *ds) +{ + yaffs_Object *dir = ds->dir; + const char *name = ds->path; + const char *n = name; + char namelen = 0; + + yaffs_Object *d; + + // check that we really have a directory + switch (yaffs_GetObjectType(dir)) { + case DT_DIR: break; + + case DT_LNK: // TODO: symlink support + default: return ENOTDIR; + } + + // Isolate the next element of the path name. + while( *n != '\0' && *n != '/' ) + n++, namelen++; + + // Check if this is the last path element. + while( *n == '/') n++; + if( *n == '\0' ) + ds->last = true; + + // update name in dirsearch object + ds->name = name; + ds->namelen = namelen; + + // First, special case "." and "..": + if (name[0] == '.') { + if (namelen == 1) { // "." + ds->node = dir; + return ENOERR; + } else if (name[1] == '.' && namelen == 2) { // ".." + ds->node = dir->parent; + if (!ds->node) ds->node = dir; // ".." at the root stays in the root + return ENOERR; + } + } + + // Otherwise, search the directory for a matching entry + YCHAR namebuf[YAFFS_MAX_NAME_LENGTH+1]; + memcpy(namebuf, name, namelen); + namebuf[(int)namelen]=0; + + d = yaffs_FindObjectByName(dir, namebuf); + // TODO: Create a variant of y_FindObjectByName which takes dir, name and len. Indeed, that would be beneficial for a lot of its functions. + if( d == NULL ) return ENOENT; + d = yaffs_GetEquivalentObject(d); // traverse hardlinks + + // pass back the node we have found + ds->node = d; + + return ENOERR; +} + +/* Main directory search code. Use init_dirsearch() to init the struct. + * If we return with d->last set, d->name _might_ be null-terminated. + * (It will iff no trailing slashes were passed in.) + * Code that acts on the output name MUST use d->namelen and not assume + * null-termination without testing first. + */ +static int eyaffs_find(ey_dirsearch *d) +{ + if ( *(d->path) == 0 ) + return ENOERR; + for (;;) { + ER(find_entry(d)); + if (d->last) return ENOERR; + // Not done yet? Next one down... + d->dir = d->node; + d->path += d->namelen; + // While we could check file perms here, eCos doesn't support them. + while ( *(d->path) == '/' ) ++d->path; // skip separators + } +} + +// File operations -------------------------------------------------------- + +static int eyaffs_pathconf(yaffs_Object *node, struct cyg_pathconf_info *info) +{ + switch(info->name) { + case _PC_LINK_MAX: + info->value = LINK_MAX; + return ENOERR; + + case _PC_NAME_MAX: + info->value = YAFFS_MAX_NAME_LENGTH; + return ENOERR; + + case _PC_PATH_MAX: + info->value = PATH_MAX; + return ENOERR; + + case _PC_PRIO_IO: + case _PC_SYNC_IO: + info->value=0; + return ENOERR; + + case _PC_NO_TRUNC: + info->value=1; + return ENOERR; + + case _PC_MAX_CANON: // terminals only + case _PC_MAX_INPUT: // terminals + case _PC_PIPE_BUF: // pipes + case _PC_ASYNC_IO: // not supported + case _PC_CHOWN_RESTRICTED: // we don't track owners + case _PC_VDISABLE: // terminals + default: + info->value = -1; + return EINVAL; + } +} + +static int eyaffs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + int i; + off_t pos = fp->f_offset; + ssize_t resid = uio->uio_resid; + + for (i=0; i < uio->uio_iovcnt; i++) { + cyg_iovec *iov = &uio->uio_iov[i]; + unsigned char *buf = iov->iov_base; + off_t len = iov->iov_len; + + if (pos + len > node->variant.fileVariant.fileSize) + len = node->variant.fileVariant.fileSize - pos; + + while (len > 0 && pos < node->variant.fileVariant.fileSize) { + off_t l = yaffs_ReadDataFromFile(node, buf, pos, len); + len -= l; + pos += l; + buf += l; + resid -= l; + } + } + uio->uio_resid = resid; + fp->f_offset = pos; + return ENOERR; +} + +static int eyaffs_fo_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + int i; + off_t pos = fp->f_offset; + ssize_t resid = uio->uio_resid; + + if (fp->f_flag & CYG_FAPPEND) + pos = fp->f_offset = node->variant.fileVariant.fileSize; + + CYG_ASSERT(pos >= 0, "pos became negative"); + + for (i=0; i < uio->uio_iovcnt; i++) { + cyg_iovec *iov = &uio->uio_iov[i]; + unsigned char *buf = iov->iov_base; + off_t len = iov->iov_len; + + while (len > 0) { + off_t l = yaffs_WriteDataToFile(node, buf, pos, len, 0); + len -= l; + buf += l; + pos += l; + resid -= l; + + if (l==0) goto stop; // urgh, how does this cope with dire errors? + } + } + + // Timestamps are updated on yaffs_FlushFile() +stop: + uio->uio_resid = resid; + fp->f_offset = pos; + return ENOERR; +} + + +static int eyaffs_fo_lseek (struct CYG_FILE_TAG *fp, off_t *apos, int whence ) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + off_t pos = *apos; + + switch (whence) + { + case SEEK_SET: + // Pos is already where we want to be + break; + case SEEK_CUR: + // Add pos to current offset + pos += fp->f_offset; + break; + case SEEK_END: + // Add pos to file size + pos += node->variant.fileVariant.fileSize; + break; + default: + return EINVAL; + } + + // Check that pos is still within current file size, + // or at the very end + if (pos < 0 || pos > node->variant.fileVariant.fileSize) + return EINVAL; + + *apos = fp->f_offset = pos; + return ENOERR; +} + +static int eyaffs_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, + CYG_ADDRWORD data) +{ + return EINVAL; // No ioctls defined +} + +static int eyaffs_fo_fsync (struct CYG_FILE_TAG *fp, int mode ) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + int ymode = (mode == CYG_FDATASYNC) ? 1 : 0; + YER(yaffs_FlushFile(node,1,ymode)); + return ENOERR; +} + +static int eyaffs_fo_close (struct CYG_FILE_TAG *fp) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + + if (node->inUse) { + YER(yaffs_FlushFile(node,1,0)); + node->inUse--; + if (node->inUse <= 0 && node->unlinked) { + YER(yaffs_DeleteObject(node)); + } + } + fp->f_data = 0; + return ENOERR; +} + +static int eyaffs_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf ) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + + return eyaffs_stat_object(node, buf); +} + +static int eyaffs_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len ) +{ + yaffs_Object *node = (yaffs_Object*) fp->f_data; + + switch(key) { + case FS_INFO_CONF: + return eyaffs_pathconf(node, (struct cyg_pathconf_info *)buf ); + } + return EINVAL; +} +static int eyaffs_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len ) +{ + return EINVAL; // None defined +} + +static cyg_fileops eyaffs_fileops = +{ + eyaffs_fo_read, eyaffs_fo_write, + eyaffs_fo_lseek, eyaffs_fo_ioctl, + cyg_fileio_seltrue, + eyaffs_fo_fsync, eyaffs_fo_close, + eyaffs_fo_fstat, + eyaffs_fo_getinfo, eyaffs_fo_setinfo +}; + +// Directory entrypoints -------------- + +static int eyaffs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) +{ + eyaffs_diriter *diriter = (eyaffs_diriter*) fp->f_data; + struct dirent *ent = (struct dirent *)uio->uio_iov[0].iov_base; + unsigned offset = fp->f_offset; + off_t len = uio->uio_iov[0].iov_len; + + if( len < sizeof(struct dirent) ) + return EINVAL; + + if (offset == 0) { + strcpy(ent->d_name, "."); +#ifdef CYGPKG_FS_YAFFS_RET_DIRENT_DTYPE + ent->d_type = __stat_mode_DIR; +#endif + goto done; + } + if (offset == 1) { + strcpy(ent->d_name, ".."); +#ifdef CYGPKG_FS_YAFFS_RET_DIRENT_DTYPE + ent->d_type = __stat_mode_DIR; +#endif + goto done; + } + + // else use the iter: + yaffs_Object * node = diriter->nextret; + + if (!node) goto done_eof; + + yaffs_GetObjectName(node, ent->d_name, sizeof(ent->d_name)); +#ifdef CYGPKG_FS_YAFFS_RET_DIRENT_DTYPE + ent->d_type = yaffs_GetObjectType(node); +#endif + eyaffs_diriter_advance(diriter); + +done: + uio->uio_resid -= sizeof(struct dirent); + fp->f_offset++; +done_eof: + return ENOERR; +} + +static int eyaffs_fo_dirlseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence ) +{ + // This is easy, we only allow a full rewind. + if (whence != SEEK_SET || *pos != 0) + return EINVAL; + // get and rewind the diriter + eyaffs_diriter *diriter = (eyaffs_diriter*) fp->f_data; + eyaffs_diriter_rewind(diriter); + fp->f_offset = 0; + return ENOERR; +} + +static int eyaffs_fo_dirclose (struct CYG_FILE_TAG *fp) +{ + eyaffs_diriter *diriter = (eyaffs_diriter*) fp->f_data; + + diriter->node->inUse--; + ylist_del(&diriter->iterlist); + memset(diriter, 0xbb, sizeof(eyaffs_diriter)); + fp->f_data = 0; + YFREE(diriter); + return ENOERR; +} + + +static cyg_fileops eyaffs_dirops = +{ + eyaffs_fo_dirread, + (cyg_fileop_write *)cyg_fileio_enosys, + eyaffs_fo_dirlseek, + (cyg_fileop_ioctl *)cyg_fileio_enosys, + cyg_fileio_seltrue, + (cyg_fileop_fsync *)cyg_fileio_enosys, + eyaffs_fo_dirclose, + (cyg_fileop_fstat *)cyg_fileio_enosys, + (cyg_fileop_getinfo *)cyg_fileio_enosys, + (cyg_fileop_setinfo *)cyg_fileio_enosys +}; + +// Filesystem operations ------------------------------------------------- +// N.B. Function names are prefixed with 'e' to distinguish them from +// those internal to yaffs. + + +static int eyaffs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte ) +{ + int _err = ENOERR; + + cyg_nand_device *nand = 0; + cyg_nand_partition *part = 0; + ERm(cyg_nand_resolve_device(mte->devname, &nand, &part)); + + if (!part || !part->dev || (part->last <= part->first) ) { + TOUT(("eyaffs_mount: Invalid partition\n")); + ER(EINVAL); + } + + // Is this partition already mounted? + cyg_mtab_entry *m = cyg_mtab; + while (m != &cyg_mtab_end) { + if (m->valid + && (0==strcmp(m->fsname,"yaffs")) + && (((yaffs_Device *)m->data)->genericDevice == part) ) { + ER(EBUSY); + /* TODO: Set up a refcount to allow a yaffs/nand fs + * to be mounted multiple times. In that case, + * re-use the existing yaffs device struct. */ + } + m++; + } + + // Option handling. Defaults come from CDL. + int o_nReserved = CYGNUM_FS_YAFFS_RESERVED_BLOCKS; + int o_nShortOpCaches = CYGNUM_FS_YAFFS_SHORTOP_CACHES; + int o_skipCheckpointRead = 0; + // (eCosPro can change these at mount time.) + +#if 0 // Applicable only to eCosPro + if (mte->options) { + int t; + char buf[10]; + // reserved=<int>: Number of blocks to reserve (minimum 2) + if (0==cyg_fs_get_option(mte->options, "reserved", buf, sizeof buf)) { + t = atoi(buf); + if (t>=2 && t <= (part->last - part->first)) + o_nReserved = t; + else + TOUT(("eyaffs_mount: ignoring invalid value `reserved=%d'", t)); + } + // caches=<int>: Number of cache entries to use (10-20 recommended) + if (0==cyg_fs_get_option(mte->options, "caches", buf, sizeof buf)) { + t = atoi(buf); + if (t>=0) + o_nShortOpCaches = t; + else + TOUT(("eyaffs_mount: ignoring invalid value `caches=%d'", t)); + } + // skip-checkpoint-read: Ignore the checkpoint restore and instead + // do a full filesystem scan. + if (0==cyg_fs_get_option(mte->options, "skip-checkpoint-read", buf, sizeof buf)) { + o_skipCheckpointRead = 1; + } + // TODO: readonly option, runtime and/or CDL? + } +#endif + +#ifdef CYGPKG_INFRA_DEBUG + // Best-efforts sanity check that there's enough heap. + // The rule of thumb is 2 bytes per page. + struct mallinfo mi = mallinfo(); + unsigned want = ( 1 << (nand->block_page_bits + 1) ) * (1 + part->last - part->first); + if ( mi.fordblks < want) { + TOUT(("eyaffs_mount: warning: arena reports %u bytes free; %u recommended for this device\n", mi.fordblks, want)); + } + +#endif + + yaffs_Device *y = YMALLOC(sizeof(yaffs_Device)); // ^^^^^^^^^^^^^^^^ + if (!y) EG(ENOMEM); + memset(y, 0, sizeof(yaffs_Device)); + y->name = mte->devname; + y->genericDevice = (void*) part; + + y->nDataBytesPerChunk = + y->totalBytesPerChunk = NAND_BYTES_PER_PAGE(nand); + y->inbandTags = 0; + + y->nChunksPerBlock = NAND_PAGES_PER_BLOCK(nand); + y->nReservedBlocks = o_nReserved; + y->startBlock = part->first; + y->endBlock = part->last; + y->useNANDECC = 1; + y->nShortOpCaches = o_nShortOpCaches; + + if (NAND_BYTES_PER_PAGE(nand) == 512) { +#ifdef CYGSEM_FS_YAFFS_SMALLPAGE_MODE_YAFFS1 + y->isYaffs2 = 0; + if (NAND_APPSPARE_PER_PAGE(nand) < PACKEDTAGS1_OOBSIZE) { + NAND_ERROR(nand, + "Device has %d spare per page but YAFFS1 needs %d\n", + NAND_APPSPARE_PER_PAGE(nand), PACKEDTAGS1_OOBSIZE); + EG(EINVAL); + } +#else // CYGSEM_FS_YAFFS_SMALLPAGE_MODE_YAFFS2 + y->isYaffs2 = 1; + // 512-byte page devices normally have 8-byte spare areas. + // This isn't big enough for YAFFS2 tags, which need 25. + y->inbandTags = 1; +#endif + } else { + y->isYaffs2 = 1; + if (NAND_APPSPARE_PER_PAGE(nand) < PACKEDTAGS2_OOBSIZE(y)) { + NAND_ERROR(nand, + "Device has %d spare per page but YAFFS2 needs %u\n", + NAND_APPSPARE_PER_PAGE(nand), PACKEDTAGS2_OOBSIZE(y)); + EG(EINVAL); + } + } + +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE + if (y->isYaffs2) { + NAND_ERROR(nand, "Device is set to run with yaffs2 code, which is compiled out.\n"); + EG(ENODEV); + } +#endif + + y->eraseBlockInNAND = eyaffs_eraseBlockInNAND; + y->initialiseNAND = eyaffs_initialiseNAND; + y->deinitialiseNAND = eyaffs_deinitialiseNAND; + + y->writeChunkWithTagsToNAND = eyaffs_writeChunkWithTagsToNAND; + y->readChunkWithTagsFromNAND = eyaffs_readChunkWithTagsFromNAND; + y->markNANDBlockBad = eyaffs_markNANDBlockBad; + y->queryNANDBlock = eyaffs_queryNANDBlock; + + y->isMounted = 0; + y->removeObjectCallback = eyaffs_diriter_objremove_callback; + + if (o_skipCheckpointRead) { + NAND_CHATTER(1, nand, "mounting with skip-checkpoint-read\n"); + y->skipCheckpointRead = 1; + } + + int yerr = yaffs_GutsInitialise(y); + if (yerr == YAFFS_FAIL) { + NAND_CHATTER(1, nand, "yaffs_GutsInitialise failed!\n"); + EG(EIO); + } + + yaffs_Object * root = yaffs_Root(y); + mte->root = (cyg_dir) root; + mte->data = (CYG_ADDRWORD) y; + CYG_ASSERT(_err == ENOERR, "Unhandled error in initialisation"); + // At this point we could use the device struct's devList to link it + // into a global devList. (We don't currently need to, so won't.) + return ENOERR; +err_exit: + if (y) YFREE(y); + return _err; +} + +static int eyaffs_umount ( cyg_mtab_entry *mte ) +{ + yaffs_Device *y = (yaffs_Device*) mte->data; + + yaffs_FlushEntireDeviceCache(y); + yaffs_CheckpointSave(y); + yaffs_Deinitialise(y); + + YFREE(y); + return ENOERR; +} + +static int eyaffs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name, + int mode, cyg_file *file ) +{ + int _err; + ey_dirsearch ds; + yaffs_Object *node = 0; + + // 'mode' is the open options (flags), not the permissions. + // (eCos doesn't support file perms.) + + // fileio gives us either the root, or the current wd, to start at + init_dirsearch(&ds, (yaffs_Object*) dir, name); + _err = eyaffs_find(&ds); + + if (_err == ENOENT) { + // It's not there. Are we creat()ing? + if (ds.last && (mode & O_CREAT) ) { + // A trailing slash implies directory, which makes no sense here + if (ds.name[ds.namelen] == '/') return EISDIR; + CYG_ASSERT(ds.name[ds.namelen]==0, "Length fencepost failed"); + node = yaffs_MknodFile(ds.dir, ds.name, FILE_FIXED_PERMS, FIXED_UID, FIXED_GID); + if (!node || (node==YAFFS_FAIL)) return ENOMEM; + _err = ENOERR; + } + // else we return ENOENT + } else if (_err == ENOERR) { + // The node exists. If the O_CREAT and O_EXCL bits are set, we + // must fail the open. + if( (mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) ) + _err = EEXIST; + else node = ds.node; + } + + if( _err != ENOERR ) return _err; + + if (yaffs_GetObjectType(node) == DT_LNK) { + // TODO: symlink support + return ENOSYS; + } + + if(yaffs_GetObjectType(node) == DT_DIR) return EISDIR; + + // Could check perms here (and on the dir tree too) + + if( mode & O_TRUNC ) + YER(yaffs_ResizeFile(node, 0)); + + node->inUse++; + + file->f_flag |= mode & CYG_FILE_MODE_MASK; + file->f_type = CYG_FILE_TYPE_FILE; + file->f_ops = &eyaffs_fileops; + file->f_offset = (mode & O_APPEND) ? yaffs_GetObjectFileLength(node) : 0; + file->f_data = (CYG_ADDRWORD) node; + file->f_xops = 0; + + return ENOERR; +} + +static int eyaffs_unlink ( cyg_mtab_entry *mte, cyg_dir dir, const char *name ) +{ + int _err; + ey_dirsearch ds; + + init_dirsearch(&ds, (yaffs_Object*) dir, name); + _err = eyaffs_find(&ds); + if (_err != ENOERR) return _err; + + if(yaffs_GetObjectType(ds.node) == DT_DIR) return EISDIR; + if (ds.name[ds.namelen] == '/') return EISDIR; // cannot unlink dirs + YER(yaffs_Unlink(ds.dir,ds.name)); // this appears to DTRT wrt 0-linked still-open files + return ENOERR; +} + +static int eyaffs_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name ) +{ + ey_dirsearch ds; + + init_dirsearch(&ds, (yaffs_Object*) dir, name); + int _err = eyaffs_find(&ds); + if (_err == ENOENT) { + if (ds.last) { + char dirname[ds.namelen+1]; + memcpy(dirname, ds.name, ds.namelen); + dirname[ds.namelen] = 0; + // OK, create it! + yaffs_Object * node = yaffs_MknodDirectory(ds.dir, dirname, DIRECTORY_FIXED_PERMS, FIXED_UID, FIXED_GID); + _err = (node == NULL) ? EIO : ENOERR; + } else { + // Intermediate directory doesn't exist - ENOENT + } + } else { + // something there already + if (_err == ENOERR) _err = EEXIST; + } + return _err; +} + +static int eyaffs_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name ) +{ + ey_dirsearch ds; + + init_dirsearch(&ds, (yaffs_Object*) dir, name); + int _err = eyaffs_find(&ds); + if (_err != ENOERR) return _err; + + if(yaffs_GetObjectType(ds.node) != DT_DIR) return ENOTDIR; + if (0==strcmp(ds.name,".")) return EINVAL; + if (0==ds.namelen) return EINVAL; + + char dirname[ds.namelen+1]; + memcpy(dirname, ds.name, ds.namelen); + dirname[ds.namelen] = 0; + + if (YAFFS_FAIL == yaffs_Unlink(ds.dir,dirname)) return ENOTEMPTY; + return ENOERR; +} + +static int eyaffs_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1, + cyg_dir dir2, const char *name2 ) +{ + ey_dirsearch ds1, ds2; + + init_dirsearch(&ds1, (yaffs_Object*) dir1, name1); + int _err = eyaffs_find(&ds1); + if (_err != ENOERR) return _err; + + init_dirsearch(&ds2, (yaffs_Object*) dir2, name2); + _err = eyaffs_find(&ds2); + + if (ds2.last && _err == ENOENT) + ds2.node = NULL, _err = ENOERR; // through-rename + + if (_err != ENOERR) return _err; + + if (ds1.node == ds2.node) return ENOERR; // identity op + + if (ds2.node) { + int type1 = yaffs_GetObjectType(ds1.node), + type2 = yaffs_GetObjectType(ds2.node); + if ( (type1 != DT_DIR) && (type2 == DT_DIR) ) + return EISDIR; + if ( (type1 == DT_DIR) && (type2 != DT_DIR) ) + return ENOTDIR; + // YAFFS will delete the target + } + // Alas, if this is a directory rename, there may be trailing / involved, + // so we have to strip them. + char xname1[ds1.namelen+1]; + memcpy(xname1, ds1.name, ds1.namelen); + xname1[ds1.namelen] = 0; + char xname2[ds2.namelen+1]; + memcpy(xname2, ds2.name, ds2.namelen); + xname2[ds2.namelen] = 0; + + YER(yaffs_RenameObject(ds1.dir, xname1, ds2.dir, xname2)); + return ENOERR; +} + +static int eyaffs_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1, + cyg_dir dir2, const char *name2, int type ) +{ + ey_dirsearch ds1, ds2; + + // Only do hard links for now + if (type != CYG_FSLINK_HARD) return EINVAL; + + init_dirsearch(&ds1, (yaffs_Object*) dir1, name1); + int _err = eyaffs_find(&ds1); + if (_err != ENOERR) return _err; + + init_dirsearch(&ds2, (yaffs_Object*) dir2, name2); + _err = eyaffs_find(&ds2); + if (_err == ENOERR) return EEXIST; // Can't rename-over + + if (ds2.last && _err == ENOENT) + ds2.node = 0, _err = ENOERR; // link-through + + ER(_err); + + // Forbid hard links to directories + if (ds1.node->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) + return EPERM; + + if (ds2.name[ds2.namelen] == '/') return EISDIR; // eh? makes no sense. + yaffs_Object * newnode = yaffs_Link(ds2.dir, ds2.name, ds1.node); + if (newnode) return ENOERR; + else return EIO; +} + +static int eyaffs_opendir( cyg_mtab_entry *mte, cyg_dir dir, const char *name, + cyg_file *file ) +{ + int _err; + ey_dirsearch ds; + + init_dirsearch(&ds, (yaffs_Object*) dir, name); + _err = eyaffs_find(&ds); + if (_err != ENOERR) return _err; + + if(yaffs_GetObjectType(ds.node) != DT_DIR) return ENOTDIR; + + eyaffs_diriter *diriter = YMALLOC(sizeof(eyaffs_diriter)); + if (!diriter) return ENOMEM; + + ds.node->inUse++; + + YINIT_LIST_HEAD(&diriter->iterlist); + diriter->node = ds.node; + + if (!eyaffs_all_diriters.next) YINIT_LIST_HEAD(&eyaffs_all_diriters); + ylist_add(&diriter->iterlist, &eyaffs_all_diriters); + eyaffs_diriter_rewind(diriter); + + file->f_type = CYG_FILE_TYPE_FILE; + file->f_ops = &eyaffs_dirops; + file->f_offset = 0; + file->f_data = (CYG_ADDRWORD) diriter; + file->f_xops = 0; + return ENOERR; +} + +static int eyaffs_chdir ( cyg_mtab_entry *mte, cyg_dir xdir, const char *name, + cyg_dir *dir_out ) +{ + yaffs_Object *dir = (yaffs_Object*) xdir; + if (dir_out) { + ey_dirsearch ds; + init_dirsearch(&ds, dir, name); + int _err = eyaffs_find(&ds); + if (_err != ENOERR) return _err; + if (yaffs_GetObjectType(ds.node) != DT_DIR) + return ENOTDIR; + *dir_out = (cyg_dir)ds.node; + } else { + // the "dec-refcount" case: nothing to do + } + return ENOERR; +} + +static int eyaffs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name, + struct stat *buf) +{ + int _err; + ey_dirsearch ds; + + init_dirsearch(&ds, (yaffs_Object*) dir, name); + _err = eyaffs_find(&ds); + if (_err != ENOERR) return _err; + + return eyaffs_stat_object(ds.node, buf); +} + +static int eyaffs_stat_object(yaffs_Object *node, struct stat *buf) +{ + switch (yaffs_GetObjectType(node)) { + case DT_REG: + buf->st_mode = __stat_mode_REG; + buf->st_size = node->variant.fileVariant.fileSize; + break; + case DT_DIR: + buf->st_mode = __stat_mode_DIR; + buf->st_size = 0; + break; + default: + return ENOSYS; // Don't support anything else yet + } + + buf->st_mode |= node->yst_mode &~ S_IFMT; + + buf->st_ino = node->objectId; + buf->st_dev = 0; + buf->st_nlink = eyaffs_count_links(node); + buf->st_uid = node->yst_uid; + buf->st_gid = node->yst_gid; + + buf->st_atime = node->yst_atime; + buf->st_mtime = node->yst_mtime; + buf->st_ctime = node->yst_ctime; + + return ENOERR; +} + +static int eyaffs_getinfo( cyg_mtab_entry *mte, cyg_dir dir, const char *name, + int key, void *buf, int len ) +{ + int _err; + ey_dirsearch ds; + yaffs_Device *y = (yaffs_Device*) mte->data; + + switch(key) { + case FS_INFO_CONF: + break; + +#ifdef CYGSEM_FILEIO_INFO_DISK_USAGE + case FS_INFO_DISK_USAGE: + { + struct cyg_fs_disk_usage *usage = (struct cyg_fs_disk_usage *) buf; + CYG_CHECK_DATA_PTR(buf, "getinfo buf"); + if (len < sizeof(struct cyg_fs_disk_usage)) return EINVAL; + usage->total_blocks = y->endBlock - y->startBlock + 1; + usage->free_blocks = y->nErasedBlocks; + usage->block_size = y->nDataBytesPerChunk * y->nChunksPerBlock; + return ENOERR; + } +#else + (void)y; +#endif + + case FS_INFO_GETCWD: + // yaffs doesn't provide anything special, we'd only end up duplicating the fallback ".." method. + default: // others not supported + return ENOSYS; + } + + init_dirsearch(&ds, (yaffs_Object*) dir, name); + _err = eyaffs_find(&ds); + if (_err != ENOERR) return _err; + + switch(key) { + case FS_INFO_CONF: + if (len < sizeof (struct cyg_pathconf_info)) return EINVAL; + return eyaffs_pathconf(ds.node, (struct cyg_pathconf_info *) buf); + + default: + return ENOSYS; + } +} + +static int eyaffs_do_sync_fs(yaffs_Device * y) +{ + yaffs_FlushEntireDeviceCache(y); + // TODO: If there were a convenient way to enumerate all the open + // files in a filesystem, we could fsync them all here. + // This might involve code similar to cyg_fd_filesys_close(). + yaffs_CheckpointSave(y); + return ENOERR; +} + +static int eyaffs_setinfo( cyg_mtab_entry *mte, cyg_dir dir, const char *name, + int key, void *buf, int len ) +{ + switch (key) { + case FS_INFO_SYNC: + return eyaffs_do_sync_fs( (yaffs_Device*) mte->data ); + } + return EINVAL; +} + +FSTAB_ENTRY(eyaffs_fste, "yaffs", 0, CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM, + eyaffs_mount, + eyaffs_umount, + eyaffs_open, + eyaffs_unlink, + eyaffs_mkdir, + eyaffs_rmdir, + eyaffs_rename, + eyaffs_link, + eyaffs_opendir, + eyaffs_chdir, + eyaffs_stat, + eyaffs_getinfo, + eyaffs_setinfo); + +// -----------------------------------------------------------------------
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yaffs.h @@ -0,0 +1,89 @@ +#ifndef CYGONCE_FS_ECOS_YAFFS_H +#define CYGONCE_FS_ECOS_YAFFS_H +//============================================================================= +// +// ecos-yaffs.h +// +// Options for the eCos interface to the YAFFS filesystem +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-05 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <pkgconf/system.h> +#include <pkgconf/fs_yaffs.h> + +/* Options from yaffs moduleconfig.h */ +#define CONFIG_YAFFS_FS + +#ifdef CYGSEM_FS_YAFFS_SMALLPAGE_MODE_YAFFS1 +# define CONFIG_YAFFS_YAFFS1 +# define CONFIG_YAFFS_YAFFS2 +#else // CYGSEM_FS_YAFFS_SMALLPAGE_MODE_YAFFS2 +# define CONFIG_YAFFS_NO_YAFFS1 +# define CONFIG_YAFFS_YAFFS2 +#endif + +/* eCos does not currently supply DT_REG &c. and ATTR_MODE &c., so we'll + * use YAFFS's: */ +#define CONFIG_YAFFS_PROVIDE_DEFS + +/* Our NAND layer does ECC, so we won't use YAFFS's - but we do need + * to use its internal ECC on the tags */ +//#define YAFFS_IGNORE_TAGS_ECC +//#define CONFIG_YAFFS_DOES_ECC +//#define CONFIG_YAFFS_ECC_WRONG_ORDER + +/* Do not test whether chunks are erased before writing to them */ +#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK + +/* Cache short names, taking more RAM, but faster look-ups */ +#ifdef CYGSEM_FS_YAFFS_CACHE_SHORT_NAMES +#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM +#endif + +/* The count of blocks to reserve for checkpointing */ +#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 + +/* Use older-style on-NAND data format with pageStatus byte? + * This probably requires work in the NAND layer in order to support. */ +//#define CONFIG_YAFFS_9BYTE_TAGS + +#endif /* CYGONCE_FS_ECOS_YAFFS_H */
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/src/ecos-yport.h @@ -0,0 +1,135 @@ +#ifndef CYGONCE_FS_ECOS_YPORT_H +#define CYGONCE_FS_ECOS_YPORT_H +//============================================================================= +// +// ecos-yport.h +// +// eCos porting layer for YAFFS +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-05 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include "ecos-yaffs.h" + +#include "devextras.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/diag.h> +#include <cyg/infra/cyg_type.h> + +#define YCHAR char +#define YUCHAR unsigned char +#define _Y(x) x +#define yaffs_strcat(a,b) strcat(a,b) +#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) + +#define YAFFS_PATH_DIVIDERS "/" + +#define Y_INLINE inline + +#define YMALLOC(x) malloc(x) +#define YFREE(x) free(x) +#define YMALLOC_ALT(x) malloc(x) +#define YFREE_ALT(x) free(x) + +#define YMALLOC_DMA(x) YMALLOC(x) + +#ifdef CYGFUN_KERNEL_API_C +#include <cyg/kernel/kapi.h> +#define YYIELD() do { cyg_thread_yield(); } while(0) +#else +#define YYIELD() do {} while(0) +#endif + + +//#define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) +//#define YALERT(s) YINFO(s) +#define YBUG() do { cyg_assert_fail(__PRETTY_FUNCTION__, __FILE__, __LINE__, "==>> yaffs bug detected"); } while(0) + +#define TENDSTR "\n" +#define TSTR(x) x +#define TCONT(x) x +#ifdef CYGSEM_FS_YAFFS_TRACEFN +externC int CYGSEM_FS_YAFFS_TRACEFN (const char *fmt, ...) CYGBLD_ATTRIB_PRINTF_FORMAT(1,2); +#define TOUT(p) CYGSEM_FS_YAFFS_TRACEFN p +#else +static inline int _yaffs_trace_ignore (const char *fmt, ...) CYGBLD_ATTRIB_PRINTF_FORMAT(1,2); +static inline int _yaffs_trace_ignore (const char *fmt, ...) { return 0; } +#define TOUT(p) _yaffs_trace_ignore p +#endif + + +#define YAFFS_LOSTNFOUND_NAME "lost+found" +#define YAFFS_LOSTNFOUND_PREFIX "obj" +//#define YPRINTF(x) printf x + +#ifdef CYGPKG_LIBC_TIME +#define Y_CURRENT_TIME time(NULL) +#else +#define Y_CURRENT_TIME ((time_t)-1) +#endif +#define Y_TIME_CONVERT(x) (x) + +// eCos defines mode bits differently to POSIX. +#define YAFFS_ROOT_MODE ( S_IRUSR | S_IWUSR | S_IXUSR | \ + S_IRGRP | S_IXGRP | \ + S_IROTH | S_IXOTH ) +#define YAFFS_LOSTNFOUND_MODE YAFFS_ROOT_MODE + +#define yaffs_SumCompare(x,y) ((x) == (y)) +#define yaffs_strcmp(a,b) strcmp(a,b) + +typedef off_t loff_t; /* This will break and should probably be removed + if/when we add 64-bit file support generally. */ + +#define yaffs_qsort qsort /* provided by eCos stdlib */ + +#endif /* CYGONCE_FS_ECOS_YPORT_H */
rename from yaffs_checkptrw.c rename to packages/fs/yaffs/current/src/yaffs_checkptrw.c --- a/yaffs_checkptrw.c +++ b/packages/fs/yaffs/current/src/yaffs_checkptrw.c @@ -170,7 +170,7 @@ int yaffs_CheckpointOpen(yaffs_Device *d * going to be way more than we need */ dev->blocksInCheckpoint = 0; dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2; - dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks); + dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks); if(!dev->checkpointBlockList) return 0;
rename from yaffs_guts.c rename to packages/fs/yaffs/current/src/yaffs_guts.c --- a/yaffs_guts.c +++ b/packages/fs/yaffs/current/src/yaffs_guts.c @@ -39,6 +39,10 @@ const char *yaffs_guts_c_version = /* Robustification (if it ever comes about...) */ +/* eCos note: I have discussed the existence of robustification hooks + * with Charles Manning. He put them in as stubs, but then concluded + * that there was no value in filling them in. + * - wry, 2009-06-19 */ static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND); static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, int erasedOk); @@ -2890,9 +2894,12 @@ static int yaffs_CheckSpaceForAllocation int checkpointBlocks; if (dev->isYaffs2) { +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; if (checkpointBlocks < 0) +#endif checkpointBlocks = 0; } else { checkpointBlocks = 0; @@ -4123,7 +4130,8 @@ static void yaffs_InvalidateWholeChunkCa /*--------------------- Checkpointing --------------------*/ - +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head) { yaffs_CheckpointValidity cp; @@ -4480,8 +4488,8 @@ static int yaffs_ReadCheckpointObjects(y while (ok && !done) { ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); if (cp.structType != sizeof(cp)) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR), - cp.structType, sizeof(cp), ok)); + T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %u ok %d"TENDSTR), + cp.structType, (unsigned)(sizeof(cp)), ok)); ok = 0; } @@ -4548,7 +4556,6 @@ static int yaffs_ReadCheckpointSum(yaffs return 1; } - static int yaffs_WriteCheckpointData(yaffs_Device *dev) { int ok = 1; @@ -4557,7 +4564,6 @@ static int yaffs_WriteCheckpointData(yaf T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR))); ok = 0; } - if (ok) ok = yaffs_CheckpointOpen(dev, 1); @@ -4637,6 +4643,7 @@ static int yaffs_ReadCheckpointData(yaff return ok ? 1 : 0; } +#endif // !OMIT_YAFFS2_CODE static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) { @@ -4652,7 +4659,6 @@ static void yaffs_InvalidateCheckpoint(y int yaffs_CheckpointSave(yaffs_Device *dev) { - T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); yaffs_VerifyObjects(dev); @@ -4661,7 +4667,10 @@ int yaffs_CheckpointSave(yaffs_Device *d if (!dev->isCheckpointed) { yaffs_InvalidateCheckpoint(dev); +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else yaffs_WriteCheckpointData(dev); +#endif } T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); @@ -4669,6 +4678,8 @@ int yaffs_CheckpointSave(yaffs_Device *d return dev->isCheckpointed; } +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else int yaffs_CheckpointRestore(yaffs_Device *dev) { int retval; @@ -4686,6 +4697,7 @@ int yaffs_CheckpointRestore(yaffs_Device return retval; } +#endif /*--------------------- File read/write ------------------------ * Read and write have very similar structures. @@ -5373,6 +5385,8 @@ int yaffs_Unlink(yaffs_Object *dir, cons /*----------------------- Initialisation Scanning ---------------------- */ +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, int backwardScanning) { @@ -5406,6 +5420,7 @@ static void yaffs_HandleShadowedObject(y obj->valid = 1; /* So that we don't read any other info for this file */ } +#endif typedef struct { int seq; @@ -5445,6 +5460,8 @@ static void yaffs_HardlinkFixup(yaffs_De +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else static int ybicmp(const void *a, const void *b) { register int aseq = ((yaffs_BlockIndex *)a)->seq; @@ -5456,7 +5473,7 @@ static int ybicmp(const void *a, const v else return aseq - bseq; } - +#endif struct yaffs_ShadowFixerStruct { int objectId; @@ -5465,6 +5482,7 @@ struct yaffs_ShadowFixerStruct { }; +#ifndef CONFIG_YAFFS_NO_YAFFS1 static void yaffs_StripDeletedObjects(yaffs_Device *dev) { /* @@ -6050,6 +6068,8 @@ static int yaffs_Scan(yaffs_Device *dev) return YAFFS_OK; } +#endif //CONFIG_YAFFS_NO_YAFFS1 + static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) { @@ -6108,6 +6128,8 @@ static void yaffs_CheckObjectDetailsLoad } } +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE +#else static int yaffs_ScanBackwards(yaffs_Device *dev) { yaffs_ExtendedTags tags; @@ -6770,6 +6792,7 @@ static int yaffs_ScanBackwards(yaffs_Dev return YAFFS_OK; } +#endif // !CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE /*------------------------------ Directory Functions ----------------------------- */ @@ -7534,6 +7557,9 @@ int yaffs_GutsInitialise(yaffs_Device *d if (!init_failed) { /* Now scan the flash. */ if (dev->isYaffs2) { +#ifdef CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE + init_failed = 1; +#else if (yaffs_CheckpointRestore(dev)) { yaffs_CheckObjectDetailsLoaded(dev->rootDir); T(YAFFS_TRACE_ALWAYS, @@ -7569,13 +7595,19 @@ int yaffs_GutsInitialise(yaffs_Device *d if (!init_failed && !yaffs_ScanBackwards(dev)) init_failed = 1; } - } else if (!yaffs_Scan(dev)) - init_failed = 1; - - yaffs_StripDeletedObjects(dev); +#endif // !CYGSEM_FS_YAFFS_OMIT_YAFFS2_CODE + } else /* !dev->isYaffs2 */ { +#ifdef CONFIG_YAFFS_NO_YAFFS1 + init_failed = 1; +#else + if (!yaffs_Scan(dev)) + init_failed = 1; + + yaffs_StripDeletedObjects(dev); yaffs_FixHangingObjects(dev); if(dev->emptyLostAndFound) yaffs_EmptyLostAndFound(dev); +#endif } if (init_failed) { @@ -7739,8 +7771,8 @@ static void yaffs_VerifyFreeChunks(yaffs #define yaffs_CheckStruct(structure, syze, name) \ do { \ if (sizeof(structure) != syze) { \ - T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\ - name, syze, sizeof(structure))); \ + T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %u\n" TENDSTR),\ + name, syze, (unsigned)sizeof(structure))); \ return YAFFS_FAIL; \ } \ } while (0) @@ -7757,4 +7789,6 @@ static int yaffs_CheckStructures(void) yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader"); #endif return YAFFS_OK; -} + (void) yaffs_DeleteWorker; + (void) yaffs_VerifyTnodeWorker; +}
rename from yaffs_guts.h rename to packages/fs/yaffs/current/src/yaffs_guts.h --- a/yaffs_guts.h +++ b/packages/fs/yaffs/current/src/yaffs_guts.h @@ -90,7 +90,7 @@ #define YAFFS_MAX_SHORT_OP_CACHES 20 -#define YAFFS_N_TEMP_BUFFERS 6 +#define YAFFS_N_TEMP_BUFFERS CYGNUM_FS_YAFFS_TEMP_BUFFERS /* We limit the number attempts at sucessfully saving a chunk of data. * Small-page devices have 32 pages per block; large-page devices have 64.
rename from yaffs_nand.c rename to packages/fs/yaffs/current/src/yaffs_nand.c --- a/yaffs_nand.c +++ b/packages/fs/yaffs/current/src/yaffs_nand.c @@ -20,6 +20,39 @@ const char *yaffs_nand_c_version = #include "yaffs_getblockinfo.h" +#ifdef CONFIG_YAFFS_NO_YAFFS1 +// Trap to let us compile the source largely unmodified but to elide the +// YAFFS1 code unless we really need it +static inline int noyaffs1(void) { + T(YAFFS_TRACE_ERROR, (TSTR("YAFFS1 support compiled out" TENDSTR))); + YBUG(); + return YAFFS_FAIL; +} + +static inline +int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, + int chunkInNAND, + const __u8 *data, + const yaffs_ExtendedTags *tags) +{ return noyaffs1(); } +static inline +int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev, + int chunkInNAND, + __u8 *data, + yaffs_ExtendedTags *tags) +{ return noyaffs1(); } +static inline +int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, + int blockNo) +{ return noyaffs1(); } +static inline +int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, + int blockNo, + yaffs_BlockState *state, + __u32 *sequenceNumber) +{ return noyaffs1(); } +#endif + int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags)
rename from yaffs_packedtags2.c rename to packages/fs/yaffs/current/src/yaffs_packedtags2.c --- a/yaffs_packedtags2.c +++ b/packages/fs/yaffs/current/src/yaffs_packedtags2.c @@ -15,6 +15,13 @@ #include "yportenv.h" #include "yaffs_tagsvalidity.h" +#if 0 +// Used in conjunction with RANDOMLY_LOSE mode on the synth nand driver to +// demonstrate that it is behaving as intended. +#define COUNT_ECC_TAG_FIXES +unsigned yaffs_tag_ecc_fixes = 0; +#endif + /* This code packs a set of extended tags into a binary structure for * NAND storage */ @@ -154,7 +161,6 @@ void yaffs_UnpackTags2TagsPart(yaffs_Ext } - void yaffs_UnpackTags2(yaffs_Device *dev, yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt) { @@ -178,6 +184,9 @@ void yaffs_UnpackTags2(yaffs_Device *dev break; case 1: eccResult = YAFFS_ECC_RESULT_FIXED; +#ifdef COUNT_ECC_TAG_FIXES + ++yaffs_tag_ecc_fixes; +#endif break; case -1: eccResult = YAFFS_ECC_RESULT_UNFIXED;
rename from yaffs_tagscompat.c rename to packages/fs/yaffs/current/src/yaffs_tagscompat.c --- a/yaffs_tagscompat.c +++ b/packages/fs/yaffs/current/src/yaffs_tagscompat.c @@ -16,7 +16,9 @@ #include "yaffs_ecc.h" #include "yaffs_getblockinfo.h" +#ifndef CONFIG_YAFFS_NO_YAFFS1 static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND); +#endif // ! NO_YAFFS1, i.e. only when YAFFS1 is needed #ifdef NOTYET static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND); static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, @@ -56,11 +58,16 @@ int yaffs_CountBits(__u8 x) /********** Tags ECC calculations *********/ void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) -{ +{ +#if 1 + YBUG(); // Should never get here if configured out.. +#else yaffs_ECCCalculate(data, spare->ecc1); yaffs_ECCCalculate(&data[256], spare->ecc2); +#endif } +#ifndef CONFIG_YAFFS_NO_YAFFS1 void yaffs_CalcTagsECC(yaffs_Tags *tags) { /* Calculate an ecc */ @@ -112,9 +119,11 @@ int yaffs_CheckECCOnTags(yaffs_Tags *tag return 0; } +#endif /********** Tags **********/ +#ifndef CONFIG_YAFFS_NO_YAFFS1 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr) { @@ -190,6 +199,9 @@ static int yaffs_ReadChunkFromNAND(struc } if (!dev->useNANDECC) { +#if 1 + YBUG(); +#else retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare); if (data && doErrorCorrection) { /* Do ECC correction */ @@ -244,6 +256,7 @@ static int yaffs_ReadChunkFromNAND(struc else *eccResult = YAFFS_ECC_RESULT_NO_ERROR; } +#endif } else { /* Must allocate enough memory for spare+2*sizeof(int) */ /* for ecc results from device. */ @@ -295,6 +308,7 @@ static int yaffs_ReadChunkFromNAND(struc } return retVal; } +#endif // ! NO_YAFFS1, i.e. only when YAFFS1 is present #ifdef NOTYET static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, @@ -328,6 +342,7 @@ static int yaffs_CheckChunkErased(struct * Functions for robustisizing */ +#ifndef CONFIG_YAFFS_NO_YAFFS1 static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND) { int blockInNAND = chunkInNAND / dev->nChunksPerBlock; @@ -343,6 +358,7 @@ static void yaffs_HandleReadDataError(ya * NB recursion */ } +#endif // ! NO_YAFFS1, i.e. only when YAFFS1 is needed #ifdef NOTYET static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND) @@ -395,6 +411,7 @@ static int yaffs_VerifyCompare(const __u } #endif /* NOTYET */ +#ifndef CONFIG_YAFFS_NO_YAFFS1 int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, const __u8 *data, @@ -536,3 +553,5 @@ int yaffs_TagsCompatabilityQueryNANDBloc return YAFFS_OK; } +#endif // ! NO_YAFFS1, i.e. only when YAFFS1 is needed +
rename from yaffs_tagscompat.h rename to packages/fs/yaffs/current/src/yaffs_tagscompat.h --- a/yaffs_tagscompat.h +++ b/packages/fs/yaffs/current/src/yaffs_tagscompat.h @@ -17,6 +17,8 @@ #define __YAFFS_TAGSCOMPAT_H__ #include "yaffs_guts.h" + +#ifndef CONFIG_YAFFS_NO_YAFFS1 int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, const __u8 *data, @@ -34,6 +36,7 @@ int yaffs_TagsCompatabilityQueryNANDBloc void yaffs_CalcTagsECC(yaffs_Tags *tags); int yaffs_CheckECCOnTags(yaffs_Tags *tags); +#endif int yaffs_CountBits(__u8 byte); #endif
rename from yportenv.h rename to packages/fs/yaffs/current/src/yportenv.h --- a/yportenv.h +++ b/packages/fs/yaffs/current/src/yportenv.h @@ -17,6 +17,8 @@ #ifndef __YPORTENV_H__ #define __YPORTENV_H__ +#include "ecos-yaffs.h" + /* * Define the MTD version in terms of Linux Kernel versions * This allows yaffs to be used independantly of the kernel @@ -152,6 +154,10 @@ #define yaffs_SumCompare(x, y) ((x) == (y)) #define yaffs_strcmp(a, b) strcmp(a, b) +#elif defined CYGPKG_FS_YAFFS + +#include "ecos-yport.h" + #else /* Should have specified a configuration type */ #error Unknown configuration
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/ar4prng.inl @@ -0,0 +1,98 @@ +//============================================================================= +// +// ar4prng.inl +// +// Inline providing ARC4-based PRNG +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 eCosCentric Limited. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-04-06 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#define _SWAP(_a,_b) do { int tmp = (_a); (_a) = (_b); (_b) = tmp; } while(0) + +typedef struct { + unsigned char S[256]; + int i,j; +} ar4ctx; + +void ar4prng_init(ar4ctx *c, unsigned char *seed, unsigned seedlen) +{ + int i,j=0; + for (i=0; i<256; i++) c->S[i] = i; + for (i=0; i<256; i++) { + j = (j + c->S[i] + seed[i%seedlen]) %256; + _SWAP(c->S[i], c->S[j]); + } + c->i = c->j = 0; +} + +unsigned char ar4prng_next(ar4ctx *c) +{ + c->i = (c->i + 1) %256; + c->j = (c->j + c->S[c->i]) %256; + _SWAP(c->S[c->i], c->S[c->j]); + return c->S[(c->S[c->i] + c->S[c->j])%256]; +} + +void ar4prng_many(ar4ctx *c, unsigned char *optr, unsigned len) +{ + while (len--) *(optr++) = ar4prng_next(c); +} + +#include <cyg/infra/cyg_type.h> + +/* If you care about systematic sampling bias, do not naively + * reduce a u32 mod some limit. */ +cyg_uint32 ar4prng_u32(ar4ctx *c) +{ + cyg_uint32 rv = 0; + ar4prng_many(c, (void*)&rv, sizeof(rv)); + return rv; +} + +cyg_int32 ar4prng_s32(ar4ctx *c) +{ + cyg_int32 rv = 0; + ar4prng_many(c, (void*)&rv, sizeof(rv)); + return rv; +} + +#undef _SWAP +
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/fops.c @@ -0,0 +1,777 @@ +//============================================================================= +// +// ops.c +// +// Filesystem, file and directory operation tests for YAFFS on eCos +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-05-11 +// Description: A good (read/write) shakedown of the filesystem ops. +// On the SYNTH device, includes a long test which fills up +// the filesystem. +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/testcase.h> +#include <pkgconf/system.h> + +#if !defined(CYGPKG_LIBC_TIME) || !defined(CYGPKG_ERROR) || !defined(CYGPKG_LIBC_STDIO) + +void cyg_user_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_LIBC_TIME, CYGPKG_ERROR and CYGPKG_LIBC_STDIO"); +} + +#else + + +#include <cyg/infra/diag.h> +#include <cyg/fileio/fileio.h> +#include <dirent.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0) + +#define MUSTOS(what) do { \ + if (0 != what) { \ + perror(#what); \ + CYG_TEST_FAIL(#what); \ + cyg_test_exit(); \ + } \ +} while(0) + +#define EXPECT(what,val) do { CYG_TEST_CHECK((what) == (val), #what "==" #val); } while(0) + +#ifdef CYGPKG_DEVS_NAND_SYNTH +#define DEVICE "synth/0" +#else +#define DEVICE "onboard/0" +#endif +#define MOUNTPOINT "/nand" +#define FSTYPE "yaffs" + +MTAB_ENTRY(my_auto, MOUNTPOINT, FSTYPE, DEVICE, 0/*priv set up by mount*/); + +void list_dir_contents(const char *dir) +{ + DIR *d = opendir(dir); + if (!d) { + diag_printf("opendir %s: %s (%d)\n", dir, strerror(errno), errno); + return; + } + diag_printf("Directory %s contains:\n", dir); + + struct dirent *de; + int n = 0; + while ((de=readdir(d))) { + diag_printf("\t%s\n", de->d_name); + ++n; + } + diag_printf("(ends)\n"); + + // Rewind and try again + int m = 0; + rewinddir(d); + while ((de=readdir(d))) + ++m; + if (n != m) + CYG_TEST_FAIL_EXIT("dir reread check failed - rewinddir broken?"); + + closedir(d); +} + +#if 0 +void MKDIR(const char *dir) +{ + MUSTOS(mkdir(dir,0777)); +} +#else +#define MKDIR(d) MUSTOS(mkdir(d,0777)) +#endif + +#if 0 +void RMDIR(const char *dir) +{ + MUSTOS(rmdir(dir)); +} +#else +#define RMDIR(d) MUSTOS(rmdir(d)) +#endif + +#define RENAME(d,d2) MUSTOS(rename(d,d2)) +#define UNLINK(p) MUSTOS(unlink(p)) +#define LINK(p1,p2) MUSTOS(link(p1,p2)) + +void CHDIR(const char *dir) +{ + MUSTOS(chdir(dir)); +} + +void WANTDIR(const char *d) +{ + struct stat st; + MUSTOS(stat(d,&st)); + EXPECT(S_ISDIR(st.st_mode),1); +} + +void DONOTWANT(const char *f) +{ + struct stat st; + if (stat(f,&st) != -1) { + diag_printf("Do not want %s, but it is there\n",f); + CYG_TEST_FAIL_EXIT("Unexpected entity present"); + } + EXPECT(errno,ENOENT); +} + +void RM_RF_work(const char *f, int recurse) +{ + //diag_printf("chdir %s <r=%d>\n",f,recurse); + MUSTOS(chdir(f)); + DIR *d = opendir("."); + if (!d) { + diag_printf("opendir %s: %s\n", f, strerror(errno)); + return; + } + //diag_printf("opened dir %s\n",f); + struct dirent de_stack; + struct dirent *de_res; + while (0==readdir_r(d, &de_stack, &de_res) && de_res) { + struct stat st; + if (0==strcmp(de_res->d_name,".")) continue; + if (0==strcmp(de_res->d_name,"..")) continue; + MUSTOS(stat(de_res->d_name,&st)); + if (S_ISDIR(st.st_mode)) { + RM_RF_work(de_res->d_name, recurse+1); + //diag_printf("rmdir %s\n", de_res->d_name); + if (rmdir(de_res->d_name)) + perror("rmdir"); + } else { + // diag_printf("unlink %s\n", de_res->d_name); + MUSTOS(unlink(de_res->d_name)); + } + // N.B. We have just unlinked a file or deleted a subdir + // during a live opendir/readdir cycle. What we get from readdir + // isn't (strictly) well-defined, but we expect to not crash. + // In fact what we get from YAFFS is probably the best + // possible behaviour: there's no explosion, and when we + // next say readdir() we get the next entry! + } + //diag_printf("rm -rf closes %s\n",f); + closedir(d); + MUSTOS(chdir("..")); + //diag_printf("chdir ..\n"); +} + +void RM_RF(const char *p) +{ + //diag_printf("chdir /\n"); + //MUSTOS(chdir(MOUNTPOINT)); + diag_printf("rm -rf %s\n",p); + RM_RF_work(p,0); + //diag_printf("rmdir %s\n",p); + RMDIR(p); +} + +void checklen(const char *f, off_t size) +{ + struct stat st; + MUSTOS(stat(f, &st)); + if (st.st_size != size) { + diag_printf("!! file %s size by stat is %lu, expect %lu\n", f, st.st_size, size); + CYG_TEST_FAIL_EXIT("file size readback mismatch"); + } +} + +// -------------------------------------------------------------- + +// Function inspiration borrowed from fileio1.c and just about +// every other filesystem in eCos... Only this time, we're +// sufficiently paranoid to want to use arc4 to generate our file data. + +#define SHOW_RESULT(fn,res) do { \ + diag_printf("%s returned %d, errno %d (%s)\n", #fn, (int)res, errno, strerror(errno)); \ + CYG_TEST_FAIL("Unexpected result from "#fn); \ + cyg_test_exit(); \ +} while(0) + +#define IOSIZE 100 + +#include "ar4prng.inl" + +#define SEEDLEN (sizeof(time_t)) +unsigned char seed[SEEDLEN]; + +ar4ctx prng; + +static void reinit_prng(void) +{ + static int seed_inited = 0; + + if (!seed_inited) { + // This is a bit cruddy, but will introduce sufficient variation to make it interesting. + *(time_t*)seed = time(0); + seed_inited=1; + } + + ar4prng_init(&prng, seed, SEEDLEN); +} + +unsigned char buf[IOSIZE], testbuf[IOSIZE]; + +static void createfile( char *name, size_t size ) +{ + int fd; + ssize_t wrote; + int err; + size_t savesize = size; + + diag_printf("<INFO>: create file %s size %zd\n",name,size); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + reinit_prng(); + + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + while( size > 0 ) + { + ssize_t len = size; + if ( len > IOSIZE ) len = IOSIZE; + + ar4prng_many(&prng, buf, len); + wrote = write( fd, buf, len ); + if( wrote != len ) SHOW_RESULT( write, wrote ); + + size -= wrote; + } + + err = fsync(fd); + if (err < 0) SHOW_RESULT(fsync, err); + + struct stat st; + err = fstat(fd, &st); + if (err < 0) SHOW_RESULT(fstat, err); + if (st.st_size != savesize) + CYG_TEST_FAIL_EXIT("fstat size mismatched"); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +static void checkfile( char *name ) +{ + int fd; + ssize_t done, pos=0, lastread=-1; + int i; + int err; + + diag_printf("<INFO>: check file %s\n",name); + + reinit_prng(); + + err = access( name, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd = open( name, O_RDONLY ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + for(;;) + { + done = read( fd, buf, IOSIZE ); + pos += done; + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + lastread = done; + + ar4prng_many(&prng, testbuf, done); + + for( i = 0; i < done; i++ ) + if( buf[i] != testbuf[i] ) + { + diag_printf("buf[%d](%02x) != %02x\n",i,buf[i],testbuf[i]); + CYG_TEST_FAIL_EXIT("Data read not equal to data written"); + } + } + + // While we're here, let's have a play with lseek. +#define LSEEK(f, o, w, expect) do { \ + err = lseek(f, o, w); \ + if (err != expect) SHOW_RESULT(fseek, err); \ +} while(0) + + LSEEK(fd, -lastread, SEEK_END, pos-lastread); + done = read(fd, buf, IOSIZE); + CYG_ASSERT(done == lastread, "reread last chunk size mismatch - lseek broken?"); + for (i=0; i<IOSIZE; i++) { + if (buf[i] != testbuf[i]) { + diag_printf("buf[%d](%02x) != %02x\n",i,buf[i],testbuf[i]); + CYG_TEST_FAIL_EXIT("Data mismatch - lseek broken?"); + } + } + + reinit_prng(); + ar4prng_many(&prng, testbuf, IOSIZE); + + LSEEK(fd, 10, SEEK_SET, 10); + done = read(fd, &buf[10], IOSIZE-10); + CYG_ASSERT(done == IOSIZE-10, "reading after fseek"); + LSEEK(fd, -IOSIZE, SEEK_CUR, 0); // i.e. to beginning of file + done = read(fd, buf, 10); + CYG_ASSERT(done == 10, "reading after 2nd fseek"); + for (i=0; i<IOSIZE; i++) { + if (buf[i] != testbuf[i]) { + diag_printf("buf[%d](%02x) != %02x\n",i,buf[i],testbuf[i]); + CYG_TEST_FAIL_EXIT("Data mismatch - lseek broken?"); + } + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +static void copyfile( char *name2, char *name1 ) +{ + int err; + int fd1, fd2; + ssize_t done, wrote; + + diag_printf("<INFO>: copy file %s -> %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + err = access( name2, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_WRONLY|O_CREAT ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done = read( fd2, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + wrote = write( fd1, buf, done ); + if( wrote != done ) SHOW_RESULT( write, wrote ); + + if( wrote != done ) break; + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +static void comparefiles( char *name2, char *name1 ) +{ + int err; + int fd1, fd2; + ssize_t done1, done2; + int i; + + diag_printf("<INFO>: compare files %s == %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_RDONLY ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done1 = read( fd1, buf, IOSIZE ); + if( done1 < 0 ) SHOW_RESULT( read, done1 ); + + done2 = read( fd2, testbuf, IOSIZE ); + if( done2 < 0 ) SHOW_RESULT( read, done2 ); + + if( done1 != done2 ) + diag_printf("Files different sizes\n"); + + if( done1 == 0 ) break; + + for( i = 0; i < done1; i++ ) + if( buf[i] != testbuf[i] ) + { + diag_printf("buf[%d](%02x) != buf[%d](%02x)\n",i,buf[i],i,testbuf[i]); + CYG_TEST_FAIL("Data in files not equal\n"); + } + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +#ifdef CYGPKG_DEVS_NAND_SYNTH + +#include <pkgconf/devs_nand_synth.h> + +static void maxfile( char *name ) +{ + int fd; + ssize_t wrote; + int err; + size_t size = 0; + + diag_printf("<INFO>: create maximal file %s\n",name); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + reinit_prng(); + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + do + { + ar4prng_many(&prng, buf, IOSIZE); + wrote = write( fd, buf, IOSIZE ); + if( wrote < 0 ) SHOW_RESULT( write, wrote ); + + CYG_ASSERT(size <= (CYGNUM_NAND_SYNTH_CHIPSIZE*1024), "filesystem overfull"); + size += wrote; + + } while( wrote == IOSIZE ); + + diag_printf("<INFO>: file size == %zd\n",size); + + err = close( fd ); + cyg_fs_setinfo(MOUNTPOINT, FS_INFO_SYNC, NULL, 0); // sync(); + if( err < 0 ) SHOW_RESULT( close, err ); +} +#endif // CYGPKG_DEVS_NAND_SYNTH + +// -------------------------------------------------------------- + +void cyg_user_start(void) +{ + CYG_TEST_INIT(); + + // 1. Mounting and unmounting. We should already be mounted + // by the time we get here (MTAB_ENTRY). + struct stat st; + MUSTOS(stat(MOUNTPOINT, &st)); + diag_printf("got mountpoint ino %08x\n",st.st_ino); + + EXPECT(mount(DEVICE, MOUNTPOINT, FSTYPE), -1); + MUSTOS(umount(MOUNTPOINT)); + EXPECT(umount(MOUNTPOINT),-1); + MUSTOS(mount(DEVICE, MOUNTPOINT, FSTYPE)); + EXPECT(mount(DEVICE, MOUNTPOINT, FSTYPE), -1); + CYG_TEST_INFO("mount, umount OK"); + + // 2. Directory creation, deletion and rename + // In fact we start by deleting if our test dir was already there... +#define DIR1 MOUNTPOINT"/testdir" +#define DIR2 MOUNTPOINT"/testdir2" + if (0==stat(DIR1, &st)) { + CYG_TEST_INFO("dir " DIR1 " already present - attempting to nuke"); + RM_RF(DIR1); + } + if (0==stat(DIR2, &st)) { + CYG_TEST_INFO("dir " DIR2 " already present - attempting to nuke"); + RM_RF(DIR2); + } + EXPECT(rmdir(DIR1),-1); + MKDIR(DIR1); + RMDIR(DIR1); + EXPECT(rmdir(DIR1),-1); + MKDIR(DIR1); + EXPECT(mkdir(DIR1,0777),-1); + + MKDIR(DIR1"/foo////"); + EXPECT(rmdir(DIR1),-1); + EXPECT(rmdir(DIR1"/."),-1); + EXPECT(rmdir(DIR1"/foo/.."),-1); + EXPECT(rmdir(DIR1"/./foo/."),-1); // Linux doesn't allow this either. + RMDIR(DIR1"/./foo/"); // Trailing slash on a dir op shouldn't catch us out + + RENAME(DIR1"/", MOUNTPOINT"/newdir/"); + WANTDIR(MOUNTPOINT"/newdir"); + WANTDIR(MOUNTPOINT"/newdir/////"); + DONOTWANT(DIR1); + RMDIR(MOUNTPOINT"/newdir"); + + EXPECT(rmdir(MOUNTPOINT"/"),-1); + EXPECT(rmdir(MOUNTPOINT),-1); + + CYG_TEST_INFO("directory creation, deletion OK"); + + // 3. chdir. We'll make a simple hierarchy: + // DIR1 + // DIR1/1 + // DIR1/1a + // DIR1/foo/1foo + // DIR2 + // DIR2/2 + // DIR2/bar/2bar + // DIR2/bar/2baz + // .. then chdir into each in turn and confirm that the contents are as expected. + MKDIR(DIR1); + MKDIR(DIR1"/1"); + MKDIR(DIR1"/1a"); + MKDIR(DIR1"/foo"); + MKDIR(DIR1"/foo/1foo"); + MKDIR(DIR2); + MKDIR(DIR2"/2"); + MKDIR(DIR2"/bar"); + MKDIR(DIR2"/bar/2bar"); + MKDIR(DIR2"/bar/2baz"); + + CHDIR(DIR1); + WANTDIR("1"); + WANTDIR("1a"); + WANTDIR("foo"); + DONOTWANT("2"); + DONOTWANT("1foo"); + DONOTWANT("bar"); + DONOTWANT("2bar"); + DONOTWANT("2baz"); + + CHDIR("foo"); + WANTDIR("1foo"); + DONOTWANT("1"); + DONOTWANT("1a"); + DONOTWANT("foo"); + + CHDIR(".."); + WANTDIR("1"); + WANTDIR("1a"); + WANTDIR("foo"); + DONOTWANT("bar"); + CHDIR("."); + WANTDIR("1"); + WANTDIR("1a"); + WANTDIR("foo"); + DONOTWANT("bar"); + WANTDIR("foo/1foo"); + RMDIR("foo/1foo"); + DONOTWANT("foo/1foo"); + + CYG_TEST_INFO("chdir, opendir, readdir OK"); + + // 4. File creation, copying, renaming, deletion - throughout dirs + + CHDIR(DIR1); + createfile("floop", 202); + checklen("floop", 202); + checkfile(DIR1"/floop"); + copyfile("floop", DIR2"/fee"); + CHDIR(DIR2); + checkfile("fee"); + checklen("fee", 202); + comparefiles("fee", DIR1"/floop"); + + copyfile("fee", DIR1"/fum"); + checkfile(DIR1"/fum"); + chdir(DIR1); + checkfile("fum"); + comparefiles("floop", "fum"); + comparefiles("fum", DIR2"/fee"); + + // Rename ... + RENAME("fum", DIR2"/fum2"); + DONOTWANT("fum"); + DONOTWANT("fum2"); + DONOTWANT(DIR1"/fum"); + checkfile(DIR2"/fum2"); + CHDIR(DIR2); + checkfile("fum2"); + CHDIR(DIR1); + RENAME(DIR2"/fum2", "fum3"); + checkfile("fum3"); + checkfile(DIR1"/fum3"); + DONOTWANT(DIR2"/fum3"); + comparefiles(DIR1"/fum3", DIR1"/floop"); + CHDIR(DIR2); + comparefiles(DIR1"/fum3", DIR1"/floop"); + + // A brief diversion to check rewinddir... + list_dir_contents(DIR1); + + // Create-over, rename-over + CHDIR(DIR1); + checklen("floop", 202); + checklen(DIR2"/fee", 202); + createfile(DIR2"/fee", 4242); + checklen(DIR2"/fee", 4242); + checklen("floop", 202); + RENAME(DIR2"/fee", "floop"); + checklen("floop", 4242); + + // Unlink + CHDIR(DIR2); + UNLINK(DIR1"/fum3"); + DONOTWANT(DIR1"/fum3"); + DONOTWANT("fum3"); + CHDIR(DIR1); + DONOTWANT("fum3"); + + CYG_TEST_INFO("file create/read/write, copy, delete OK"); + + // 5. File hard links (and directory, which aren't supported) + + LINK("floop","floop2"); + checklen("floop2", 4242); + LINK("floop",DIR2"/floop3"); + CHDIR(DIR2); + LINK(DIR1"/floop", "floop4"); + LINK(DIR1"/floop", DIR1"/floop5"); + DONOTWANT("floop2"); + checkfile("floop3"); + checkfile("floop4"); + DONOTWANT("floop5"); + CHDIR(DIR1); + checkfile("floop2"); + DONOTWANT("floop3"); + DONOTWANT("floop4"); + checkfile("floop5"); + + checkfile(DIR1"/floop2"); + checkfile(DIR2"/floop3"); + checkfile(DIR2"/floop4"); + checkfile(DIR1"/floop5"); + + UNLINK("floop2"); + UNLINK(DIR2"/floop3"); + CHDIR(DIR2); + UNLINK("floop4"); + UNLINK(DIR1"/floop5"); + + DONOTWANT(DIR1"/floop2"); + DONOTWANT(DIR2"/floop3"); + DONOTWANT(DIR2"/floop4"); + DONOTWANT(DIR1"/floop5"); + + CHDIR(DIR1); + checkfile("floop"); + // we'll leave floop lying around for fpathconf() test + + EXPECT(link(DIR1, DIR2"/dir-hardlink-should-fail"), -1); + EXPECT(errno, EPERM); + + CYG_TEST_INFO("hard links OK"); + +#ifdef CYGPKG_DEVS_NAND_SYNTH + // 6. EOF-on-write (by filling the filesystem!) + CYG_TEST_INFO("bigfile test, this might take a few seconds"); + + // To speed this test up tune your synth nand device to not be so big. + maxfile(DIR1"/bigfile"); + checkfile(DIR1"/bigfile"); + { + struct stat st; + stat(DIR1"/bigfile", &st); + } + UNLINK(DIR1"/bigfile"); + CYG_TEST_INFO("EOF on write OK"); +#else + CYG_TEST_INFO("SKIPPING EOF-on-write test (only applied to synth nand)"); +#endif + + // 7. Ancillary checks - getinfo, setinfo (no ioctls supported as yet) + +#ifdef CYGSEM_FILEIO_INFO_DISK_USAGE + struct cyg_fs_disk_usage usage; + MUSTOS(cyg_fs_getinfo(MOUNTPOINT, FS_INFO_DISK_USAGE, &usage, sizeof(usage))); + diag_printf("getinfo/disk_usage says:\n\ttotal blocks %llu\n\tfree blocks %llu\n\tblock size %u\n", usage.total_blocks, usage.free_blocks, usage.block_size); +#endif + + diag_printf("pathconf says:\n\tNAME_MAX %ld\n\tPATH_MAX %ld\n\tSYNC_IO %ld\n", + pathconf(DIR1, _PC_NAME_MAX), + pathconf(DIR1, _PC_PATH_MAX), + pathconf(DIR1, _PC_SYNC_IO)); + + MUSTOS(cyg_fs_setinfo(MOUNTPOINT, FS_INFO_SYNC, 0, 0)); + + int fd = open(DIR1"/floop", O_RDONLY); + CYG_ASSERT(fd >= 0, "open"); + CYG_ASSERT(fpathconf(fd, _PC_NAME_MAX) != -1, "fpathconf PC_NAME_MAX"); + close(fd); + + CYG_TEST_INFO("getinfo, setinfo OK"); + + // Clean up. + + CHDIR(MOUNTPOINT); + RM_RF(DIR1); + RM_RF(DIR2); + DONOTWANT(DIR1); + DONOTWANT(DIR2); + CYG_TEST_INFO("recursive deletion OK"); + + MUSTOS(umount(MOUNTPOINT)); +#ifndef CYGDBG_USE_ASSERTS + CYG_TEST_INFO("WARNING: asserts disabled, test INCOMPLETE, try switching on CYGPKG_INFRA_DEBUG"); +#else + CYG_TEST_PASS_FINISH("All OK"); +#endif +} + +#endif +
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/mounttime.c @@ -0,0 +1,303 @@ +//============================================================================= +// +// mounttime.c +// +// Mount timings exerciser, use on a filesystem filled by `makefiles' +// THIS DOES NOT CURRENTLY WORK ON non-PRO eCos! +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2009 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): wry +// Date: 2009-06-29 +// Description: File system mount and unmount timing benchmark. +// Intended to be used on a complicated filesystem, e.g. +// one filled up by `makefiles'. +// Some timing code borrowed from mmfs tests. +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> +#include <cyg/infra/cyg_ass.h> +#include <pkgconf/system.h> +#include <pkgconf/hal.h> +#include <cyg/hal/hal_intr.h> + +#ifndef HAL_CLOCK_READ +# error "HAL_CLOCK_READ not defined!" +#endif + +#if !defined(CYGPKG_LIBC_TIME) || !defined(CYGPKG_ERROR) || !defined(CYGPKG_LIBC_STDIO) || !defined(CYGPKG_KERNEL) + +void cyg_user_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_KERNEL, CYGPKG_LIBC_TIME, CYGPKG_ERROR and CYGPKG_LIBC_STDIO"); +} + +#else + +#include <cyg/fileio/fileio.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <dirent.h> +#include <stdlib.h> + +#include <cyg/kernel/kapi.h> + +#ifdef CYGPKG_DEVS_NAND_SYNTH +#define DEVICE "synth/0" +#else +#define DEVICE "onboard/0" +#endif + +#define MOUNTPOINT "/n" +#define FSTYPE "yaffs" +#define _NOCACHE "skip-checkpoint-read" + +#define FS_NOCACHE FSTYPE":"_NOCACHE + +//#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0) + +#define MUST(what) do { \ + if (0 != what) { \ + perror(#what); \ + CYG_TEST_FAIL(#what); \ + cyg_test_exit(); \ + } \ +} while(0) + +#define min(a,b) ( (a) > (b) ? (b) : (a) ) + +// -------------------------------------------------------------- + +void RM_RF_work(const char *f, int recurse) +{ + MUST(chdir(f)); + DIR *d = opendir("."); + if (!d) { + diag_printf("opendir %s: %s\n", f, strerror(errno)); + return; + } + struct dirent de_stack; + struct dirent *de_res; + while (0==readdir_r(d, &de_stack, &de_res) && de_res) { + struct stat st; + if (0==strcmp(de_res->d_name,".")) continue; + if (0==strcmp(de_res->d_name,"..")) continue; + MUST(stat(de_res->d_name,&st)); + if (S_ISDIR(st.st_mode)) { + RM_RF_work(de_res->d_name, recurse+1); + if (rmdir(de_res->d_name)) + perror("rmdir"); + } else { + MUST(unlink(de_res->d_name)); + } + } + closedir(d); + MUST(chdir("..")); +} + +void RM_RF(const char *p) +{ + diag_printf("rm -rf %s\n",p); + RM_RF_work(p,0); + MUST(rmdir(p)); +} + +// -------------------------------------------------------------- +// Timing code cribbed from pvr5.c + +typedef struct +{ + cyg_int64 ticks; + cyg_uint32 halticks; +} timestamp; + +typedef struct +{ + timestamp start; + timestamp end; + cyg_int64 interval; // In HAL ticks + cyg_int64 us_interval; // Interval in microseconds +} timing; + +static cyg_int64 ticks_overhead = 0; +static cyg_int32 us_per_haltick = 0; +static cyg_int32 halticks_per_us = 0; + +static cyg_int64 rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; +static cyg_int64 rtc_period = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; + +static void wait_for_tick( void ) +{ + cyg_tick_count_t now = cyg_current_time(); + + while( cyg_current_time() == now ) + continue; +} + +static void get_timestamp( timestamp *ts ) +{ + ts->ticks = cyg_current_time(); + HAL_CLOCK_READ( &ts->halticks ); +} + +static cyg_int64 ticks_to_us( cyg_int64 ticks ) +{ + cyg_int64 us; + + if( us_per_haltick != 0 ) + us = ticks * us_per_haltick; + else + us = ticks / halticks_per_us; + + return us; +} + +static void calculate_interval( timing *t ) +{ + t->interval = t->end.halticks - t->start.halticks; + + t->interval += (t->end.ticks - t->start.ticks) * rtc_period; + + t->interval -= ticks_overhead; + + t->us_interval = ticks_to_us( t->interval ); +} + +static void init_timing( void ) +{ + timing t; + cyg_thread_delay(2); // ensure clock running - asserts if not + + us_per_haltick = 1000000/(rtc_period * rtc_resolution[1]); + halticks_per_us = (rtc_period * rtc_resolution[1])/1000000; + + wait_for_tick(); + + get_timestamp( &t.start ); + get_timestamp( &t.end ); + + calculate_interval( &t ); + + ticks_overhead = t.interval; + + diag_printf("Timing overhead %lld ticks (%lluus), this will be factored out of all other measurements\n", ticks_overhead, t.us_interval ); +} + +static timing tm; + +#define START() do { \ + wait_for_tick(); \ + get_timestamp(&tm.start); \ +} while(0) + +static void report(const char *what, timing tm) +{ + if (tm.us_interval > 1100000) + diag_printf("%30s: %2d.%03d s\n", what, (int)(tm.us_interval/1000000), (int)(tm.us_interval/1000)%1000); + else + diag_printf("%30s: %2d.%03d ms\n", what, (int)(tm.us_interval/1000), (int)(tm.us_interval%1000)); + +} + +#define STOP(what) do { \ + get_timestamp(&tm.end); \ + calculate_interval(&tm); \ + report(what, tm); \ +} while(0) + +// -------------------------------------------------------------- + +void dumpmallinfo(void) +{ + struct mallinfo mi = mallinfo(); + int total_ord = mi.uordblks + mi.fordblks; + double pct = (double)mi.uordblks / (double)total_ord; + diag_printf("! Arena: size 0x%x, small blks %u/%u, ord blks used %u/%u (%u%%)\n", + mi.arena, + mi.usmblks, mi.fsmblks, + mi.uordblks, total_ord, (int)(100.0*pct)); +} + +// -------------------------------------------------------------- + +#define WORKDIR MOUNTPOINT "/" "test" + +void mounttime_main(void) +{ +#define NTIMES 3 + int i; + for (i=0; i<NTIMES; i++) { + START(); + MUST(mount(DEVICE, MOUNTPOINT, FSTYPE)); + STOP("remount"); + //if (i==0) dumpmallinfo(); + START(); + MUST(umount(MOUNTPOINT)); + STOP("unmount"); + + START(); + MUST(mount(DEVICE, MOUNTPOINT, FS_NOCACHE)); + // plain eCos does not support mount options, this test won't work there. + STOP("remount without checkpoint"); + //if (i==0) dumpmallinfo(); + START(); + MUST(umount(MOUNTPOINT)); + STOP("unmount"); + //if (i==0) dumpmallinfo(); + } + //dumpmallinfo(); + + // then consider repeats.. + + CYG_TEST_EXIT("Run complete"); +} + +int main(void) +{ + CYG_TEST_INIT(); + init_timing(); + + mounttime_main(); + return 0; +} + +#endif +
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/yaffs1.c @@ -0,0 +1,975 @@ +//========================================================================== +// +// yaffs1.c +// +// Test fileio system +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2004, 2006, 2007 eCosCentric Limited +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg +// Contributors: nickg +// Date: 2000-05-25 +// Purpose: Test fileio system +// Description: This test uses the testfs to check out the initialization +// and basic operation of the fileio system +// +// +// +// +// +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> + +#ifdef CYGPKG_KERNEL + +#include <pkgconf/hal.h> +#include <pkgconf/kernel.h> +#include <pkgconf/io_fileio.h> + +#include CYGDAT_DEVS_DISK_CFG // testing config defines + +#include <cyg/kernel/ktypes.h> // base kernel types +#include <cyg/infra/cyg_trac.h> // tracing macros +#include <cyg/infra/cyg_ass.h> // assertion macros + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> + +#include <cyg/fileio/fileio.h> + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> // HAL polled output + +//========================================================================== +// Config options + +#define TEST_DEVICE CYGDAT_DEVS_DISK_TEST_DEVICE + +#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT + +#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY + +#define TEST_FSTYPE "yaffs" + +#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DEVICE2 CYGDAT_DEVS_DISK_TEST_DEVICE2 + +#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2 + +#define TEST_FSTYPE2 "yaffs" + +#endif + +//========================================================================== + +#define SHOW_RESULT( _fn, _res ) \ +{ \ + diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):""); \ +} + +//========================================================================== + +#define IOSIZE 100 + +#define LONGNAME1 "long_file_name_that_should_take_up_more_than_one_directory_entry_1" +#define LONGNAME2 "long_file_name_that_should_take_up_more_than_one_directory_entry_2" + + +//========================================================================== + +#ifndef CYGPKG_LIBC_STRING + +char *strcat( char *s1, const char *s2 ) +{ + char *s = s1; + while( *s1 ) s1++; + while( (*s1++ = *s2++) != 0); + return s; +} + +#endif + +__externC int +rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW; + +//========================================================================== + +static void listdir( char *name, int statp, int numexpected, int *numgot ) +{ + int err; + DIR *dirp; + int num=0; + + diag_printf("<INFO>: reading directory %s\n",name); + +// diag_printf("<INFO>: opendir(%s)\n",name); + dirp = opendir( name ); + if( dirp == NULL ) SHOW_RESULT( opendir, -1 ); + + for(;;) + { + struct dirent *entry = readdir( dirp ); + + if( entry == NULL ) + break; + num++; + diag_printf("<INFO>: entry %14s",entry->d_name); +#ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE + diag_printf(" d_type %2x", entry->d_type); +#endif + if( statp ) + { + char fullname[PATH_MAX]; + struct stat sbuf; + + if( name[0] ) + { + strcpy(fullname, name ); + if( !(name[0] == '/' && name[1] == 0 ) ) + strcat(fullname, "/" ); + } + else fullname[0] = 0; + + strcat(fullname, entry->d_name ); + + err = stat( fullname, &sbuf ); + if( err < 0 ) + { + if( errno == ENOSYS ) + diag_printf(" <no status available>"); + else SHOW_RESULT( stat, err ); + } + else + { + diag_printf(" [mode %08x ino %08x nlink %d size %ld]", + sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size); + } +#ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE + if ((entry->d_type & S_IFMT) != (sbuf.st_mode & S_IFMT)) + CYG_TEST_FAIL("File mode's don't match between dirent and stat"); +#endif + } + + diag_printf("\n"); + } + +// diag_printf("<INFO>: closedir(%s)\n",name); + err = closedir( dirp ); + if( err < 0 ) SHOW_RESULT( stat, err ); + if (numexpected >= 0 && num != numexpected) + CYG_TEST_FAIL("Wrong number of dir entries\n"); + if ( numgot != NULL ) + *numgot = num; +} + +//========================================================================== + +static void createfile( char *name, size_t size ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + + diag_printf("<INFO>: create file %s size %zd\n",name,size); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + while( size > 0 ) + { + ssize_t len = size; + if ( len > IOSIZE ) len = IOSIZE; + + wrote = write( fd, buf, len ); + if( wrote != len ) SHOW_RESULT( write, wrote ); + + size -= wrote; + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +#if 0 +static void maxfile( char *name ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + size_t size = 0; + size_t prevsize = 0; + + diag_printf("<INFO>: create maximal file %s\n",name); + diag_printf("<INFO>: This may take a few minutes\n"); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + do + { + wrote = write( fd, buf, IOSIZE ); + //if( wrote < 0 ) SHOW_RESULT( write, wrote ); + + if( wrote >= 0 ) + size += wrote; + + if( (size-prevsize) > 100000 ) + { + diag_printf("<INFO>: size = %zd\n", size); + prevsize = size; + } + + } while( wrote == IOSIZE ); + + diag_printf("<INFO>: file size == %zd\n",size); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} +#endif + +//========================================================================== + +static void checkfile( char *name ) +{ + char buf[IOSIZE]; + int fd; + ssize_t done; + int i; + int err; + off_t pos = 0; + + diag_printf("<INFO>: check file %s\n",name); + + err = access( name, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd = open( name, O_RDONLY ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + for(;;) + { + done = read( fd, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + for( i = 0; i < done; i++ ) + if( buf[i] != i%256 ) + { + diag_printf("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256); + CYG_TEST_FAIL("Data read not equal to data written\n"); + for(;;); + } + + pos += done; + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +static void copyfile( char *name2, char *name1 ) +{ + + int err; + char buf[IOSIZE]; + int fd1, fd2; + ssize_t done, wrote; + + diag_printf("<INFO>: copy file %s -> %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + err = access( name2, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_WRONLY|O_CREAT ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done = read( fd2, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + wrote = write( fd1, buf, done ); + if( wrote != done ) SHOW_RESULT( write, wrote ); + + if( wrote != done ) break; + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +static void comparefiles( char *name2, char *name1 ) +{ + int err; + char buf1[IOSIZE]; + char buf2[IOSIZE]; + int fd1, fd2; + ssize_t done1, done2; + int i; + + diag_printf("<INFO>: compare files %s == %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_RDONLY ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done1 = read( fd1, buf1, IOSIZE ); + if( done1 < 0 ) SHOW_RESULT( read, done1 ); + + done2 = read( fd2, buf2, IOSIZE ); + if( done2 < 0 ) SHOW_RESULT( read, done2 ); + + if( done1 != done2 ) + diag_printf("Files different sizes\n"); + + if( done1 == 0 ) break; + + for( i = 0; i < done1; i++ ) + if( buf1[i] != buf2[i] ) + { + diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]); + CYG_TEST_FAIL("Data in files not equal\n"); + } + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +void checkcwd( const char *cwd ) +{ + static char cwdbuf[PATH_MAX]; + char *ret; + + ret = getcwd( cwdbuf, sizeof(cwdbuf)); + if( ret == NULL ) SHOW_RESULT( getcwd, ret ); + + if( strcmp( cwdbuf, cwd ) != 0 ) + { + diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd ); + CYG_TEST_FAIL( "Current directory mismatch"); + } +} + +//========================================================================== +// main + +void fileio1_main( CYG_ADDRESS id ) +{ + int err; + int existingdirents=-1; + cyg_bool mp2 = false; + int fd; +#if defined(CYGSEM_FILEIO_BLOCK_USAGE) + struct cyg_fs_block_usage usage; +#endif + + char dirname[64]; + char filename1[64]; + char filename2[64]; + +#define NEW_FILENAME( fn, f ) \ +{ \ + fn[0]=0; \ + strcat(fn, dirname); \ + strcat(fn, "/"); \ + strcat(fn,f); \ +} + +#define NEW_FILENAME1( f ) NEW_FILENAME( filename1, f ) +#define NEW_FILENAME2( f ) NEW_FILENAME( filename2, f ) + + CYG_TEST_INIT(); + + // -------------------------------------------------------------- + + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); + if( err < 0 ) { + SHOW_RESULT( mount, err ); + CYG_TEST_FAIL_FINISH("yaffs1"); + } + + err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT TEST_DIRECTORY); + err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( TEST_MOUNTPOINT TEST_DIRECTORY, true, -1, &existingdirents ); + + // -------------------------------------------------------------- +#if defined(CYGSEM_FILEIO_BLOCK_USAGE) + err = cyg_fs_getinfo(TEST_MOUNTPOINT, FS_INFO_BLOCK_USAGE, + &usage, sizeof(usage)); + if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err ); + diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n", + usage.total_blocks, usage.total_blocks * usage.block_size); + diag_printf("<INFO>: free size: %6lld blocks, %10lld bytes\n", + usage.free_blocks, usage.free_blocks * usage.block_size); + diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size); +#endif + // -------------------------------------------------------------- + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT ); + strcat(dirname, TEST_DIRECTORY ); + + // -------------------------------------------------------------- + + createfile( "foo", 20257 ); + checkfile( "foo" ); + copyfile( "foo", "fee"); + checkfile( "fee" ); + comparefiles( "foo", "fee" ); + diag_printf("<INFO>: mkdir bar\n"); + err = mkdir( "bar", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL ); + + copyfile( "fee", "bar/fum" ); + checkfile( "bar/fum" ); + comparefiles( "fee", "bar/fum" ); + diag_printf("<INFO>: cd bar\n"); + err = chdir( "bar" ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + // Create a further subdirectory and immediately remove it + // This should make no overall change, but may expose later + // node cache reference counting issues. + diag_printf("<INFO>: mkdir delme\n"); + err = mkdir( "delme", 0); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + diag_printf("<INFO>: cd delme\n"); + err = chdir( "delme"); + if( err < 0 ) SHOW_RESULT( chdir, err ); + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + diag_printf("<INFO>: rmdir delme\n"); + err = rmdir( "delme" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + NEW_FILENAME1( "bar/delme1" ); + diag_printf("<INFO>: mkdir %s\n",filename1); + err = mkdir( filename1, 0); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + diag_printf("<INFO>: rmdir %s\n",filename1); + err = rmdir( filename1 ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + + NEW_FILENAME1( "bar" ); + checkcwd( filename1 ); + + diag_printf("<INFO>: rename ../foo bundy\n"); + err = rename( "../foo", "bundy" ); + if( err < 0 ) SHOW_RESULT( rename, err ); + + listdir( dirname, true, existingdirents+2, NULL ); + listdir( "." , true, 4, NULL ); + + checkfile( "../bar/bundy" ); + comparefiles("../fee", "bundy" ); + +#if defined(CYGSEM_FILEIO_BLOCK_USAGE) + err = cyg_fs_getinfo(TEST_MOUNTPOINT, FS_INFO_BLOCK_USAGE, + &usage, sizeof(usage)); + if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err ); + diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n", + usage.total_blocks, usage.total_blocks * usage.block_size); + diag_printf("<INFO>: free size: %6lld blocks, %10lld bytes\n", + usage.free_blocks, usage.free_blocks * usage.block_size); + diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size); +#endif + // -------------------------------------------------------------- + // Check for some common error cases + + + // First make some directories + diag_printf("<INFO>: mkdir doo\n"); + err = mkdir( "doo", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir fie\n"); + err = mkdir( "fie", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir fie/foe\n"); + err = mkdir( "fie/foe", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + + diag_printf("<INFO>: rename fum doo -- should fail\n"); + err = rename( "fum", "doo" ); + if( err < 0 && errno != EISDIR ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename doo fum -- should fail\n"); + err = rename( "doo", "fum" ); + if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename doo fie -- should fail\n"); + err = rename( "doo", "fie" ); + // FATFS returns ENOTEMPTY, since fie has foe within it + if( err < 0 && errno != EIO ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: open floop for reading -- should fail\n"); + err = open( "floop", O_RDONLY ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( open, err ); + + NEW_FILENAME1( "x/y" ) + diag_printf("<INFO>: rename fum %s -- should fail\n",filename1); + err = rename( "fum", filename1 ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename fum fum -- should succeed\n"); + err = rename( "fum", "fum" ); + if( err < 0 ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: unlink fee -- should fail\n"); + err = unlink( "fee" ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "bar" ); + diag_printf("<INFO>: rmdir %s -- should fail\n",filename1); + err = rmdir( filename1 ); + // FATFS gives EBUSY here, since bar is the current dir + if( err < 0 && errno != ENOTEMPTY ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: unlink %s -- should fail\n",filename1); + err = unlink( filename1 ); + // FATFS returns EBUSY here, also because bar is current dir + if( err < 0 && errno != EISDIR ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "bar/fum" ); + diag_printf("<INFO>: rmdir %s -- should fail\n",filename1); + err = rmdir( filename1 ); + if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: mkdir %s -- should fail\n",filename1); + err = mkdir( filename1, 0 ); + if( err < 0 && errno != EEXIST ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: open bundy exclusive -- should fail\n"); + fd = open( "bundy", O_WRONLY|O_CREAT|O_EXCL ); + if( fd < 0 && errno != EEXIST ) SHOW_RESULT( open, fd ); + + diag_printf("<INFO>: open %s -- should fail\n",dirname); + fd = open( dirname, O_WRONLY ); + if( fd < 0 && errno != EISDIR ) SHOW_RESULT( open, fd ); + + + listdir( dirname, true, existingdirents+2, NULL ); + listdir( "." , true, 6, NULL ); + + // -------------------------------------------------------------- + + diag_printf("<INFO>: rename fie doo\n"); + err = rename( "fie", "doo" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: rmdir doo/foe\n"); + err = rmdir("doo/foe"); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: rmdir doo\n"); + err = rmdir("doo"); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink ../fee\n"); + err = unlink( "../fee" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink fum\n"); + err = unlink( "fum" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink ../bar/bundy\n"); + err = unlink( "../bar/bundy" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( dirname ); + + diag_printf("<INFO>: rmdir bar\n"); + err = rmdir( "bar" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + listdir( dirname, false, existingdirents, NULL ); + + // -------------------------------------------------------------- + +#ifdef TEST_MOUNTPOINT2 + diag_printf("<INFO>: mount %s\n", TEST_MOUNTPOINT2); + err = mount( TEST_DEVICE2, TEST_MOUNTPOINT2, TEST_FSTYPE2 ); + + if( err == 0 ) + { + mp2 = true; + diag_printf("<INFO>: mount %s succeeded\n", TEST_MOUNTPOINT2); + err = access( TEST_MOUNTPOINT2 TEST_DIRECTORY2, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT2 TEST_DIRECTORY2); + err = mkdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2 ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT2 TEST_DIRECTORY2 ); + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT2 ); + strcat(dirname, TEST_DIRECTORY2 ); + + } + else + { + mp2 = false; + diag_printf("<INFO>: mount %s failed, ", TEST_MOUNTPOINT2); + diag_printf("using %s instead\n", dirname ); + } + +#endif + + listdir( dirname , true, -1, &existingdirents); + + NEW_FILENAME1( "tinky" ); + NEW_FILENAME2( "laalaa" ); + + createfile( filename1, 4567 ); + copyfile( filename1, filename2 ); + checkfile( filename1); + checkfile( filename2); + comparefiles( filename1, filename2 ); + + diag_printf("<INFO>: cd %s\n",dirname); + err = chdir( dirname ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( dirname ); + + diag_printf("<INFO>: mkdir noonoo\n"); + err = mkdir( "noonoo", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL); + + diag_printf("<INFO>: cd noonoo\n"); + err = chdir( "noonoo" ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + NEW_FILENAME1( "noonoo" ); + checkcwd( filename1 ); + + createfile( "tinky", 6789 ); + checkfile( "tinky" ); + + createfile( "dipsy", 34567 ); + checkfile( "dipsy" ); + copyfile( "dipsy", "po" ); + checkfile( "po" ); + comparefiles( "dipsy", "po" ); + + listdir( ".", true, 5, NULL ); + listdir( "..", true, existingdirents+3, NULL ); + + // -------------------------------------------------------------- + + diag_printf("<INFO>: unlink tinky\n"); + err = unlink( "tinky" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink dipsy\n"); + err = unlink( "dipsy" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink po\n"); + err = unlink( "po" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( dirname ); + + diag_printf("<INFO>: rmdir noonoo\n"); + err = rmdir( "noonoo" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + // -------------------------------------------------------------- + + diag_printf("<INFO>: mkdir x\n"); + err = mkdir( "x", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir x/y\n"); + err = mkdir( "x/y", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir x/y/z\n"); + err = mkdir( "x/y/z", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir x/y/z/w\n"); + err = mkdir( "x/y/z/w", 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + NEW_FILENAME1( "x/y/z/w" ); + diag_printf("<INFO>: cd %s\n",filename1); + err = chdir( filename1 ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( "x/y/z" ); + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( "x/y/z" ); + diag_printf("<INFO>: cd .\n"); + err = chdir( "." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( "x/y" ); + diag_printf("<INFO>: cd ../../y\n"); + err = chdir( "../../y" ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + diag_printf("<INFO>: cd ../..\n"); + err = chdir( "../.." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( dirname ); + + diag_printf("<INFO>: rmdir x/y/z/w\n"); + err = rmdir( "x/y/z/w" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir x/y/z\n"); + err = rmdir( "x/y/z" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir x/y\n"); + err = rmdir( "x/y" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir x\n"); + err = rmdir( "x" ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + // -------------------------------------------------------------- + + checkcwd( dirname ); + + diag_printf("<INFO>: unlink tinky\n"); + err = unlink( "tinky" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink laalaa\n"); + err = unlink( "laalaa" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + // -------------------------------------------------------------- + + diag_printf("<INFO>: cd %s\n", TEST_MOUNTPOINT TEST_DIRECTORY); + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( ".", true, -1, NULL ); + +#ifdef TEST_MOUNTPOINT2 + if( mp2 ) + { + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT2); + err = umount( TEST_MOUNTPOINT2 ); + if( err < 0 ) SHOW_RESULT( umount, err ); + } +#endif + + // -------------------------------------------------------------- + +#if 0 + maxfile("file.max"); + + listdir( "/", true, -1, NULL ); + + diag_printf("<INFO>: unlink file.max\n"); + err = unlink( "file.max" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + // -------------------------------------------------------------- + + diag_printf("<INFO>: cd /\n"); + err = chdir( "/" ); + if( err == 0 ) + { + checkcwd( "/" ); + + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT); + err = umount( TEST_MOUNTPOINT ); + if( err < 0 ) SHOW_RESULT( umount, err ); + } + + diag_printf("<INFO>: syncing\n"); + err = cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, 0, 0); + if (err != 0) SHOW_RESULT(sync, err); + + CYG_TEST_PASS_FINISH("yaffs1"); +} + +// ------------------------------------------------------------------------- + +#include <cyg/kernel/kapi.h> + +static cyg_handle_t thread_handle; +static cyg_thread thread; +static char stack[CYGNUM_HAL_STACK_SIZE_TYPICAL+1024]; + +externC void +cyg_start( void ) +{ + cyg_thread_create(3, // Priority - just a number + fileio1_main, // entry + 0, // index + 0, // no name + &stack[0], // Stack + sizeof(stack), // Size + &thread_handle, // Handle + &thread // Thread data structure + ); + cyg_thread_resume(thread_handle); + + cyg_scheduler_start(); +} + +#else // CYGPKG_KERNEL + +#include <cyg/infra/testcase.h> + +externC void cyg_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_KERNEL"); +} + +#endif + +// ------------------------------------------------------------------------- +// EOF yaffs1.c
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/yaffs2.c @@ -0,0 +1,826 @@ +//========================================================================== +// +// yaffs2.c +// +// Test fileio system +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2004, 2006, 2007 eCosCentric Limited +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg +// Contributors: nickg +// Date: 2000-05-25 +// Purpose: Test fileio system +// Description: This test uses the testfs to check out the initialization +// and basic operation of the fileio system +// +// +// +// +// +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> + +#ifdef CYGPKG_KERNEL + +#include <pkgconf/hal.h> +#include <pkgconf/kernel.h> +#include <pkgconf/io_fileio.h> +#include <pkgconf/io_fileio.h> + +#include CYGDAT_DEVS_DISK_CFG // testing config defines + +#include <cyg/kernel/ktypes.h> // base kernel types +#include <cyg/infra/cyg_trac.h> // tracing macros +#include <cyg/infra/cyg_ass.h> // assertion macros + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> + +#include <cyg/fileio/fileio.h> + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> // HAL polled output + +#include <cyg/kernel/instrmnt.h> + +//========================================================================== +// Config options + +#define TEST_DEVICE CYGDAT_DEVS_DISK_TEST_DEVICE + +#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT + +#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY + +#define TEST_FSTYPE "yaffs" + +#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DEVICE2 CYGDAT_DEVS_DISK_TEST_DEVICE2 + +#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2 + +#define TEST_FSTYPE2 "yaffs" + +#endif + +//========================================================================== + +#if 0 +# define X(_args_) \ +{ \ + cyg_drv_isr_lock(); \ + diag_printf("%08x: ",cyg_thread_self()); \ + diag_printf _args_; \ + cyg_drv_isr_unlock(); \ + \ +} +#else +# define X(_args_) CYG_EMPTY_STATEMENT +#endif + +#ifdef JNGPKG_USB_STACK +extern int usb_stack_init(void); +#endif + +//========================================================================== + +#define SHOW_RESULT( _fn, _res ) \ +diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):""); + +//========================================================================== + +#define IOSIZE 100 + +#define NTHREAD 6 + + +//========================================================================== + +#ifndef CYGPKG_LIBC_STRING + +char *strcat( char *s1, const char *s2 ) +{ + char *s = s1; + while( *s1 ) s1++; + while( (*s1++ = *s2++) != 0); + return s; +} + +#endif + +__externC int +rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW; + +//========================================================================== + + +static cyg_mutex_t db_lock; + +#define db_printf( args... ) \ +{ \ + cyg_mutex_lock( &db_lock ); \ + diag_printf("%d: ",id); \ + diag_printf( args ); \ + cyg_mutex_unlock( &db_lock ); \ +} + +//========================================================================== + +static void listdir( char *name, int statp, int numexpected, int *numgot, int id ) +{ + int err; + DIR *dirp; + int num=0; + + db_printf("<INFO>: reading directory %s\n",name); + + dirp = opendir( name ); + if( dirp == NULL ) SHOW_RESULT( opendir, -1 ); + + for(;;) + { + struct dirent entry_data; + struct dirent *entry; + + err = readdir_r( dirp, &entry_data, &entry ); + + if( err < 0 || entry == NULL ) + break; + num++; + + cyg_mutex_lock( &db_lock ); + diag_printf("%d: <INFO>: entry %14s",id, entry->d_name); + + if( statp ) + { + char fullname[PATH_MAX]; + struct stat sbuf; + + if( name[0] ) + { + strcpy(fullname, name ); + if( !(name[0] == '/' && name[1] == 0 ) ) + strcat(fullname, "/" ); + } + else fullname[0] = 0; + + strcat(fullname, entry->d_name ); + + err = stat( fullname, &sbuf ); + if( err < 0 ) + { + if( errno == ENOSYS ) + diag_printf(" <no status available>"); + else + { + SHOW_RESULT( stat, err ); + cyg_scheduler_lock(); + CYG_INSTRUMENT_USER(0xff,err,errno); + for(;;); + } + } + else + { + diag_printf(" [mode %08x ino %08x nlink %d size %ld]", + sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size); + } + } + + diag_printf("\n"); + cyg_mutex_unlock( &db_lock ); + } + + err = closedir( dirp ); + if( err < 0 ) SHOW_RESULT( stat, err ); + if (numexpected >= 0 && num != numexpected) + CYG_TEST_FAIL("Wrong number of dir entries\n"); + if ( numgot != NULL ) + *numgot = num; +} + +//========================================================================== + +static void createfile( char *name, size_t size, int id ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + + db_printf("<INFO>: create file %s size %ld\n",name, (long)size); + + err = access( name, F_OK ); + if( err < 0 && errno == EEXIST ) + { + err = unlink( name ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + } + else + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + while( size > 0 ) + { + ssize_t len = size; + if ( len > IOSIZE ) len = IOSIZE; + + wrote = write( fd, buf, len ); + if( wrote != len ) SHOW_RESULT( write, wrote ); + + size -= wrote; + + cyg_thread_yield(); + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +#if 0 +static void maxfile( char *name, int id ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + size_t size = 0; + size_t prevsize = 0; + + db_printf("<INFO>: create maximal file %s\n",name); + db_printf("<INFO>: This may take a few minutes\n"); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + do + { + wrote = write( fd, buf, IOSIZE ); + //if( wrote < 0 ) SHOW_RESULT( write, wrote ); + + if( wrote >= 0 ) + size += wrote; + + if( (size-prevsize) > 100000 ) + { + db_printf("<INFO>: size = %ld \n", size); + prevsize = size; + } + + } while( wrote == IOSIZE ); + + db_printf("<INFO>: file size == %ld\n",size); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} +#endif + +//========================================================================== + +static void checkfile( char *name, int id ) +{ + char buf[IOSIZE]; + int fd; + ssize_t done; + int i; + int err; + off_t pos = 0; + + db_printf("<INFO>: check file %s\n",name); + + err = access( name, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd = open( name, O_RDONLY ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + for(;;) + { + done = read( fd, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + for( i = 0; i < done; i++ ) + if( buf[i] != i%256 ) + { +// db_printf("buf[%d+%d](%02x) != %02x\n",pos,i,buf[i],i%256); +// CYG_TEST_FAIL("Data read not equal to data written\n"); + X(("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256)); + cyg_scheduler_lock(); + CYG_INSTRUMENT_USER(0xf0,err,errno); + for(;;); + } + + pos += done; + + cyg_thread_yield(); + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +static void copyfile( char *name2, char *name1, int id ) +{ + + int err; + char buf[IOSIZE]; + int fd1, fd2; + ssize_t done, wrote; + + db_printf("<INFO>: copy file %s -> %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + err = access( name2, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_WRONLY|O_CREAT ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done = read( fd2, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + wrote = write( fd1, buf, done ); + if( wrote != done ) SHOW_RESULT( write, wrote ); + + if( wrote != done ) break; + + cyg_thread_yield(); + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +static void comparefiles( char *name2, char *name1, int id ) +{ + int err; + char buf1[IOSIZE]; + char buf2[IOSIZE]; + int fd1, fd2; + ssize_t done1, done2; + int i; + + db_printf("<INFO>: compare files %s == %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_RDONLY ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done1 = read( fd1, buf1, IOSIZE ); + if( done1 < 0 ) SHOW_RESULT( read, done1 ); + + done2 = read( fd2, buf2, IOSIZE ); + if( done2 < 0 ) SHOW_RESULT( read, done2 ); + + if( done1 != done2 ) + db_printf("Files different sizes\n"); + + if( done1 == 0 ) break; + + for( i = 0; i < done1; i++ ) + if( buf1[i] != buf2[i] ) + { +// db_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]); +// CYG_TEST_FAIL("Data in files not equal\n"); + X(("%s[%d](%02x) != %s[%d](%02x)\n",name1,i,buf1[i],name2,i,buf2[i])); + cyg_scheduler_lock(); + CYG_INSTRUMENT_USER(0xf1,err,errno); + for(;;); + } + + cyg_thread_yield(); + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +void checkcwd( const char *cwd, int id ) +{ + static char cwdbuf[PATH_MAX]; + char *ret; + + ret = getcwd( cwdbuf, sizeof(cwdbuf)); + if( ret == NULL ) SHOW_RESULT( getcwd, ret ); + + if( strcmp( cwdbuf, cwd ) != 0 ) + { + db_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd ); + CYG_TEST_FAIL( "Current directory mismatch"); + } +} + +//========================================================================== +// main + +static cyg_sem_t sem; + +void fileio2_main( CYG_ADDRESS id ) +{ + int err; + int existingdirents=-1; + + char dirname[64]; + char filename1[64]; + char filename2[64]; + +#define NEW_FILENAME( fn, f ) \ +{ \ + fn[0]=0; \ + strcat(fn, dirname); \ + strcat(fn, "/"); \ + strcat(fn,f); \ +} + +#define NEW_FILENAME1( f ) NEW_FILENAME( filename1, f ) +#define NEW_FILENAME2( f ) NEW_FILENAME( filename2, f ) + + // -------------------------------------------------------------- + + if( id == 0 ) + { + int i; + +#ifdef JNGPKG_USB_STACK + err = usb_stack_init(); + cyg_thread_delay( 1000 ); +#endif + + CYG_TEST_INIT(); + + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); + if( err < 0 ) { + SHOW_RESULT( mount, err ); + CYG_TEST_FAIL_FINISH("yaffs2"); + } + + err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + db_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT TEST_DIRECTORY); + err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY, id ); + + for( i = 0; i < NTHREAD-1; i++ ) + cyg_semaphore_post( &sem ); + } + else + { + cyg_semaphore_wait( &sem ); + } + + // -------------------------------------------------------------- + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT ); + strcat(dirname, TEST_DIRECTORY ); + strcat(dirname, "/dirX"); + dirname[sizeof(TEST_MOUNTPOINT) + + sizeof(TEST_DIRECTORY) - 2 + + 4] = '0' + id; +// dirname[5] = 0; + + + db_printf("<INFO>: create %s\n",dirname); + err = mkdir( dirname, 0 ); + if( err < 0 && errno != EEXIST ) SHOW_RESULT( mkdir, err ); + + listdir( dirname, true, -1, &existingdirents, id ); + + db_printf("<INFO>: existingdirents %d\n",existingdirents); + + // -------------------------------------------------------------- + + NEW_FILENAME1( "foo" ); + createfile( filename1, 20257, id ); + checkfile( filename1, id ); + + NEW_FILENAME1( "foo" ); + NEW_FILENAME2( "fee" ); + + copyfile( filename1, filename2, id); + checkfile( filename2, id ); + comparefiles( filename1, filename2, id ); + + NEW_FILENAME1( "bar" ); + db_printf("<INFO>: mkdir bar\n"); + err = mkdir( filename1, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL, id ); + + NEW_FILENAME1( "bar/fum" ); + copyfile( filename2, filename1, id ); + checkfile( filename1, id ); + comparefiles( filename2, filename1, id ); + + NEW_FILENAME1( "foo" ); + NEW_FILENAME2( "bar/bundy" ); + db_printf("<INFO>: rename %s -> %s\n",filename1,filename2); + err = rename( filename1, filename2 ); + if( err < 0 ) SHOW_RESULT( rename, err ); + + NEW_FILENAME1( "bar" ); + + listdir( dirname, true, existingdirents+2, NULL, id ); + listdir( filename1 , true, 4, NULL, id ); + + NEW_FILENAME1( "fee" ); + checkfile( filename2, id ); + comparefiles( filename1, filename2, id ); + +// db_printf("spinning\n"); for(;;) cyg_thread_delay(10); + + + // -------------------------------------------------------------- + + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "bar/fum" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "bar/bundy" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "bar" ); + db_printf("<INFO>: rmdir %s\n",filename1); + err = rmdir( filename1 ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + +// listdir( dirname, false, existingdirents, NULL, id ); + + listdir( dirname, true, existingdirents, NULL, id ); + + // -------------------------------------------------------------- + + + listdir( dirname , true, -1, &existingdirents, id); + + NEW_FILENAME1( "tinky" ); + NEW_FILENAME2( "laalaa" ); + createfile( filename1, 4567, id ); + copyfile( filename1, filename2, id ); + checkfile( filename1, id); + checkfile( filename2, id); + comparefiles( filename1, filename2, id ); + + NEW_FILENAME1( "noonoo" ); + db_printf("<INFO>: mkdir %s\n",filename1); + err = mkdir( filename1, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL, id); + + NEW_FILENAME1( "noonoo/tinky" ); + createfile( filename1, 6789, id ); + checkfile( filename1, id ); + + NEW_FILENAME1( "noonoo/dipsy" ); + NEW_FILENAME2( "noonoo/po" ); + createfile( filename1, 34567, id ); + checkfile( filename1, id ); + copyfile( filename1, filename2, id ); + checkfile( filename2, id ); + comparefiles( filename1, filename2, id ); + + NEW_FILENAME1( "noonoo" ); + listdir( filename1, true, 5, NULL, id ); + listdir( dirname, true, existingdirents+3, NULL, id ); + + // -------------------------------------------------------------- + + NEW_FILENAME1( "noonoo/tinky" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "noonoo/dipsy" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "noonoo/po" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "noonoo" ); + db_printf("<INFO>: rmdir %s\n",filename1); + err = rmdir( filename1 ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + listdir( dirname, true, existingdirents+2, NULL, id ); + + // -------------------------------------------------------------- + + + NEW_FILENAME1( "tinky" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( "laalaa" ); + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + listdir( dirname, true, -1, NULL, id ); + +#if 0 + NEW_FILENAME1( "file.max" ); + maxfile( filename1, id ); + + listdir( dirname, true, -1, NULL, id ); + + db_printf("<INFO>: unlink %s\n",filename1); + err = unlink( filename1 ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + db_printf("<INFO>: rmdir %s\n",dirname); + err = rmdir( dirname ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + db_printf("<INFO>: syncing\n"); + err = cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, 0, 0); + if (err != 0) SHOW_RESULT(sync, err); + + if( id == 0 ) + { + int i; + db_printf("<INFO>: waiting for other threads to finish\n"); + for( i = 0; i < NTHREAD-1; i++ ) + cyg_semaphore_wait( &sem ); + + CYG_TEST_PASS_FINISH("yaffs2"); + } + else + { + db_printf("<INFO>: thread finished\n"); + cyg_semaphore_post( &sem ); + } + + cyg_thread_exit(); +} + +// ------------------------------------------------------------------------- + +#include <cyg/kernel/kapi.h> + +#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL*2) + +static char stack[NTHREAD][STACK_SIZE]; +static cyg_handle_t thread_handle[NTHREAD]; +static cyg_thread thread[NTHREAD]; + +externC void +cyg_start( void ) +{ + int i; + + CYG_INSTRUMENT_USER(0x01,0,0); + + cyg_mutex_init( &db_lock ); + + cyg_semaphore_init( &sem, 0 ); + + for( i = 0; i < NTHREAD; i++ ) + { + cyg_thread_create(3, // Priority - just a number + fileio2_main, // entry + i, // index + 0, // no name + &stack[i][0], // Stack + STACK_SIZE, // Size + &thread_handle[i], // Handle + &thread[i] // Thread data structure + ); + cyg_thread_resume(thread_handle[i]); + } + + cyg_scheduler_start(); +} + +#else // CYGPKG_KERNEL + +#include <cyg/infra/testcase.h> + +externC void cyg_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_KERNEL"); +} + +#endif + + +// ------------------------------------------------------------------------- +// EOF yaffs2.c
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/yaffs4.c @@ -0,0 +1,950 @@ +//========================================================================== +// +// yaffs4.c +// +// Test fileio system +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2004, 2005, 2006, 2007 eCosCentric Limited +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg +// Contributors: nickg +// Date: 2005-07-25 +// Purpose: Test fileio system +// Description: This test uses the testfs to check out the initialization +// and basic operation of the fileio system. +// This is essentially a copy of yaffs1 but using long +// file names. +// +// +// +// +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> + +#ifdef CYGPKG_KERNEL + +#include <pkgconf/hal.h> +#include <pkgconf/kernel.h> +#include <pkgconf/io_fileio.h> + +#include CYGDAT_DEVS_DISK_CFG // testing config defines + +#include <cyg/kernel/ktypes.h> // base kernel types +#include <cyg/infra/cyg_trac.h> // tracing macros +#include <cyg/infra/cyg_ass.h> // assertion macros + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> + +#include <cyg/fileio/fileio.h> + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> // HAL polled output + +//========================================================================== +// Config options + +#define TEST_DEVICE CYGDAT_DEVS_DISK_TEST_DEVICE + +#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT + +#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY + +#define TEST_FSTYPE "yaffs" + +#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DEVICE2 CYGDAT_DEVS_DISK_TEST_DEVICE2 + +#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2 + +#define TEST_FSTYPE2 "yaffs" + +#endif + +//========================================================================== + +#define SHOW_RESULT( _fn, _res ) \ +{ \ + diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):""); \ +} + +//========================================================================== + +#define IOSIZE 100 + +#define CLEANUP + +#define LONGNAME1 "long_file_name_that_should_take_up_more_than_one_directory_entry_1" +#define LONGNAME2 "long_file_name_that_should_take_up_more_than_one_directory_entry_2" + +// 123456789012345678901234567890 +#define FOO "foo_longer_file_x.filename" +//#define FEE "fee_.filename" +//#define BAR "bar_long_directory_name.dirname" +#define FEE "a234567890123" +#define BAR "a2345678901234" +#define BUNDY "bundy_long_file_name_ccccccccccccccccccccccccccccccc.filename" +#define FUM "bundy_long_file_name_fum.filename" +#define DOO "doo_aaaaaaaaaabbbbbbbbbbbccccccccccccc" +#define FIE "fie.rrrrrrrrrrrrllllllllllllvvvvvvvvvvvvv" +#define FOE "foe_xxxxxxxxxxllllll.xxxxxxeeeeeeeeee" + +#define TINKY "tinky_long_file_name.filename" +#define LAALAA "laalaa_long_file_name.filename" +#define NOONOO "noonoo_long_directory_name.dirname" +#define DIPSY "dipsy_long_file_name.filename" +#define PO "po_long_file_name.filename" + +#define XXXX "xxxx_long_directory_name.dirname" +#define YYYY "yyyy_long_directory_name.dirname" +#define ZZZZ "zzzz_long_directory_name.dirname" +#define WWWW "wwww_long_directory_name.dirname" + + +//========================================================================== + +#ifndef CYGPKG_LIBC_STRING + +char *strcat( char *s1, const char *s2 ) +{ + char *s = s1; + while( *s1 ) s1++; + while( (*s1++ = *s2++) != 0); + return s; +} + +#endif + +__externC int +rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW; + +//========================================================================== + +static void listdir( char *name, int statp, int numexpected, int *numgot ) +{ + int err; + DIR *dirp; + int num=0; + + diag_printf("<INFO>: reading directory %s\n",name); + +// diag_printf("<INFO>: opendir(%s)\n",name); + dirp = opendir( name ); + if( dirp == NULL ) SHOW_RESULT( opendir, -1 ); + + for(;;) + { + struct dirent *entry = readdir( dirp ); + + if( entry == NULL ) + break; + num++; + diag_printf("<INFO>: entry"); + if( statp ) + { + char fullname[PATH_MAX]; + struct stat sbuf; + + if( name[0] ) + { + strcpy(fullname, name ); + if( !(name[0] == '/' && name[1] == 0 ) ) + strcat(fullname, "/" ); + } + else fullname[0] = 0; + + strcat(fullname, entry->d_name ); + + err = stat( fullname, &sbuf ); + if( err < 0 ) + { + if( errno == ENOSYS ) + diag_printf(" <no status available>"); + else SHOW_RESULT( stat, err ); + } + else + { + diag_printf(" [mode %08x ino %08x nlink %d size %6ld]", + sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size); + } + } + + diag_printf(" %s\n",entry->d_name); + } + +// diag_printf("<INFO>: closedir(%s)\n",name); + err = closedir( dirp ); + if( err < 0 ) SHOW_RESULT( stat, err ); + if (numexpected >= 0 && num != numexpected) + CYG_TEST_FAIL("Wrong number of dir entries"); + if ( numgot != NULL ) + *numgot = num; +} + +//========================================================================== + +static void createfile( char *name, size_t size ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + + diag_printf("<INFO>: create file %s size %ld\n",name, (long)size); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + while( size > 0 ) + { + ssize_t len = size; + if ( len > IOSIZE ) len = IOSIZE; + + wrote = write( fd, buf, len ); + if( wrote != len ) SHOW_RESULT( write, wrote ); + + size -= wrote; + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +#if 0 +static void maxfile( char *name ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + size_t size = 0; + size_t prevsize = 0; + + diag_printf("<INFO>: create maximal file %s\n",name); + diag_printf("<INFO>: This may take a few minutes\n"); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + do + { + wrote = write( fd, buf, IOSIZE ); + //if( wrote < 0 ) SHOW_RESULT( write, wrote ); + + if( wrote >= 0 ) + size += wrote; + + if( (size-prevsize) > 100000 ) + { + diag_printf("<INFO>: size = %ld \n", size); + prevsize = size; + } + + } while( wrote == IOSIZE ); + + diag_printf("<INFO>: file size == %ld\n",size); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} +#endif + +//========================================================================== + +static void checkfile( char *name ) +{ + char buf[IOSIZE]; + int fd; + ssize_t done; + int i; + int err; + off_t pos = 0; + + diag_printf("<INFO>: check file %s\n",name); + + err = access( name, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd = open( name, O_RDONLY ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + for(;;) + { + done = read( fd, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + for( i = 0; i < done; i++ ) + if( buf[i] != i%256 ) + { + diag_printf("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256); + CYG_TEST_FAIL("Data read not equal to data written\n"); + for(;;); + } + + pos += done; + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +static void copyfile( char *name2, char *name1 ) +{ + + int err; + char buf[IOSIZE]; + int fd1, fd2; + ssize_t done, wrote; + + diag_printf("<INFO>: copy file %s -> %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + err = access( name2, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_WRONLY|O_CREAT ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done = read( fd2, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + wrote = write( fd1, buf, done ); + if( wrote != done ) SHOW_RESULT( write, wrote ); + + if( wrote != done ) break; + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +static void comparefiles( char *name2, char *name1 ) +{ + int err; + char buf1[IOSIZE]; + char buf2[IOSIZE]; + int fd1, fd2; + ssize_t done1, done2; + int i; + + diag_printf("<INFO>: compare files %s == %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_RDONLY ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done1 = read( fd1, buf1, IOSIZE ); + if( done1 < 0 ) SHOW_RESULT( read, done1 ); + + done2 = read( fd2, buf2, IOSIZE ); + if( done2 < 0 ) SHOW_RESULT( read, done2 ); + + if( done1 != done2 ) + diag_printf("Files different sizes\n"); + + if( done1 == 0 ) break; + + for( i = 0; i < done1; i++ ) + if( buf1[i] != buf2[i] ) + { + diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]); + CYG_TEST_FAIL("Data in files not equal\n"); + } + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +void checkcwd( const char *cwd ) +{ + static char cwdbuf[PATH_MAX]; + char *ret; + + ret = getcwd( cwdbuf, sizeof(cwdbuf)); + if( ret == NULL ) SHOW_RESULT( getcwd, ret ); + + if( strcmp( cwdbuf, cwd ) != 0 ) + { + diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd ); + CYG_TEST_FAIL( "Current directory mismatch"); + } +} + +//========================================================================== +// main + +void fileio4_main( CYG_ADDRESS id ) +{ + int err; + int existingdirents=-1; + cyg_bool mp2 = false; + int fd; + + char dirname[256]; + char filename1[256]; + char filename2[256]; + +#define NEW_FILENAME( fn, f ) \ +{ \ + fn[0]=0; \ + strcat(fn, dirname); \ + strcat(fn, "/"); \ + strcat(fn,f); \ +} + +#define NEW_FILENAME1( f ) NEW_FILENAME( filename1, f ) +#define NEW_FILENAME2( f ) NEW_FILENAME( filename2, f ) + + CYG_TEST_INIT(); + + // -------------------------------------------------------------- + + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); + if( err < 0 ) { + SHOW_RESULT( mount, err ); + CYG_TEST_FAIL_FINISH("yaffs4"); + } + + err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT TEST_DIRECTORY); + err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( TEST_MOUNTPOINT TEST_DIRECTORY, true, -1, &existingdirents ); + + // -------------------------------------------------------------- + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT ); + strcat(dirname, TEST_DIRECTORY ); + + // -------------------------------------------------------------- + + createfile( FOO, 20257 ); + checkfile( FOO ); + copyfile( FOO, FEE); + checkfile( FEE ); + comparefiles( FOO, FEE ); + diag_printf("<INFO>: mkdir " BAR "\n"); + err = mkdir( BAR, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL ); + + copyfile( FEE, BAR "/" FUM ); + checkfile( BAR "/" FUM ); + comparefiles( FEE, BAR "/" FUM ); + + diag_printf("<INFO>: cd " BAR "\n"); + err = chdir( BAR ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + NEW_FILENAME1( BAR ); + checkcwd( filename1 ); + + diag_printf("<INFO>: rename ../" FOO " " BUNDY "\n"); + err = rename( "../" FOO, BUNDY ); + if( err < 0 ) SHOW_RESULT( rename, err ); + + listdir( dirname, true, existingdirents+2, NULL ); + listdir( "." , true, 4, NULL ); + + checkfile( "../" BAR "/" BUNDY ); + comparefiles("../" FEE, BUNDY ); + + // -------------------------------------------------------------- + // Check for some common error cases + + // First make some directories + diag_printf("<INFO>: mkdir " DOO "\n"); + err = mkdir( DOO, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " FIE" \n"); + err = mkdir( FIE, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " FIE "/" FOE "\n"); + err = mkdir( FIE "/" FOE, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + + diag_printf("<INFO>: rename " FUM " " DOO " -- should fail\n"); + err = rename( FUM, DOO ); + if( err < 0 && errno != EISDIR ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename " DOO " " FUM " -- should fail\n"); + err = rename( DOO, FUM ); + if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename " DOO " " FIE " -- should fail\n"); + err = rename( DOO, FIE ); + if( err < 0 && errno != EIO ) SHOW_RESULT( rename, err ); + + NEW_FILENAME1( XXXX "/" YYYY ) + diag_printf("<INFO>: rename " FUM " %s -- should fail\n",filename1); + err = rename( FUM, filename1 ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename " FUM " " FUM " -- should fail\n"); + err = rename( FUM, FUM ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: unlink " FEE " -- should fail\n"); + err = unlink( FEE ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( BAR ); + diag_printf("<INFO>: rmdir %s -- should fail\n",filename1); + err = rmdir( filename1 ); + if( err < 0 && errno != ENOTEMPTY ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: unlink %s -- should fail\n",filename1); + err = unlink( filename1 ); + if( err < 0 && errno != EISDIR ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( BAR "/" FUM ); + diag_printf("<INFO>: rmdir %s -- should fail\n",filename1); + err = rmdir( filename1 ); + if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: mkdir %s -- should fail\n",filename1); + err = mkdir( filename1, 0 ); + if( err < 0 && errno != EEXIST ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: open " BUNDY " exclusive -- should fail\n"); + fd = open( BUNDY, O_WRONLY|O_CREAT|O_EXCL ); + if( fd < 0 && errno != EEXIST ) SHOW_RESULT( open, fd ); + + diag_printf("<INFO>: open %s -- should fail\n",dirname); + fd = open( dirname, O_WRONLY ); + if( fd < 0 && errno != EISDIR ) SHOW_RESULT( open, fd ); + + + listdir( dirname, true, existingdirents+2, NULL ); + listdir( "." , true, 6, NULL ); + + // -------------------------------------------------------------- + +#ifdef CLEANUP + + diag_printf("<INFO>: rename " FIE " " DOO "\n"); + err = rename( FIE, DOO ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: rmdir " DOO "/" FOE "\n"); + err = rmdir(DOO "/" FOE); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: rmdir " DOO "\n"); + err = rmdir(DOO); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink ../" FEE "\n"); + err = unlink( "../" FEE ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " FUM "\n"); + err = unlink( FUM ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink ../" BAR "/" BUNDY "\n"); + err = unlink( "../" BAR "/" BUNDY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( dirname ); + +#ifdef CLEANUP + diag_printf("<INFO>: rmdir " BAR "\n"); + err = rmdir( BAR ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + listdir( dirname, false, existingdirents, NULL ); +#endif + + // -------------------------------------------------------------- + +#ifdef TEST_MOUNTPOINT2 + diag_printf("<INFO>: mount %s\n", TEST_MOUNTPOINT2); + err = mount( TEST_DEVICE2, TEST_MOUNTPOINT2, TEST_FSTYPE2 ); + + if( err == 0 ) + { + mp2 = true; + diag_printf("<INFO>: mount %s succeeded\n", TEST_MOUNTPOINT2); + err = access( TEST_MOUNTPOINT2 TEST_DIRECTORY2, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT2 TEST_DIRECTORY2); + err = mkdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2 ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT2 TEST_DIRECTORY2 ); + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT2 ); + strcat(dirname, TEST_DIRECTORY2 ); + + } + else + { + mp2 = false; + diag_printf("<INFO>: mount %s failed, ", TEST_MOUNTPOINT2); + diag_printf("using %s instead\n", dirname ); + } + +#endif + + listdir( dirname , true, -1, &existingdirents); + + NEW_FILENAME1( TINKY ); + NEW_FILENAME2( LAALAA ); + + createfile( filename1, 4567 ); + copyfile( filename1, filename2 ); + checkfile( filename1); + checkfile( filename2); + comparefiles( filename1, filename2 ); + + diag_printf("<INFO>: cd %s\n",dirname); + err = chdir( dirname ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( dirname ); + + diag_printf("<INFO>: mkdir " NOONOO "\n"); + err = mkdir( NOONOO, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL); + + diag_printf("<INFO>: cd " NOONOO "\n"); + err = chdir( NOONOO ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + NEW_FILENAME1( NOONOO ); + checkcwd( filename1 ); + + createfile( TINKY, 6789 ); + checkfile( TINKY ); + + createfile( DIPSY, 34567 ); + checkfile( DIPSY ); + copyfile( DIPSY, PO ); + checkfile( PO ); + comparefiles( DIPSY, PO ); + + listdir( ".", true, 5, NULL ); + listdir( "..", true, existingdirents+3, NULL ); + + // -------------------------------------------------------------- + +#ifdef CLEANUP + diag_printf("<INFO>: unlink " TINKY "\n"); + err = unlink( TINKY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " DIPSY "\n"); + err = unlink( DIPSY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " PO "\n"); + err = unlink( PO ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( dirname ); + +#ifdef CLEANUP + diag_printf("<INFO>: rmdir " NOONOO "\n"); + err = rmdir( NOONOO ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); +#endif + + // -------------------------------------------------------------- + + diag_printf("<INFO>: mkdir " XXXX "\n"); + err = mkdir( XXXX, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " XXXX "/" YYYY "\n"); + err = mkdir( XXXX "/" YYYY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " XXXX "/" YYYY "/" ZZZZ "\n"); + err = mkdir( XXXX "/" YYYY "/" ZZZZ, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " XXXX "/" YYYY "/" ZZZZ "/" WWWW "\n"); + err = mkdir( XXXX "/" YYYY "/" ZZZZ "/" WWWW, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ "/" WWWW ); + diag_printf("<INFO>: cd %s\n",filename1); + err = chdir( filename1 ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ ); + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ ); + diag_printf("<INFO>: cd .\n"); + err = chdir( "." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( XXXX "/" YYYY ); + diag_printf("<INFO>: cd ../../" YYYY "\n"); + err = chdir( "../../" YYYY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + diag_printf("<INFO>: cd ../..\n"); + err = chdir( "../.." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( dirname ); + + diag_printf("<INFO>: rmdir " XXXX "/" YYYY "/" ZZZZ "/" WWWW "\n"); + err = rmdir( XXXX "/" YYYY "/" ZZZZ "/" WWWW ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir "XXXX "/" YYYY "/" ZZZZ "\n"); + err = rmdir( XXXX "/" YYYY "/" ZZZZ ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir " XXXX "/" YYYY "\n"); + err = rmdir( XXXX "/" YYYY ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir "XXXX "\n"); + err = rmdir( XXXX ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + // -------------------------------------------------------------- + + checkcwd( dirname ); + +#ifdef CLEANUP + diag_printf("<INFO>: unlink "TINKY "\n"); + err = unlink( TINKY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " LAALAA" \n"); + err = unlink( LAALAA ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + // -------------------------------------------------------------- + + diag_printf("<INFO>: cd %s\n", TEST_MOUNTPOINT TEST_DIRECTORY); + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( ".", true, -1, NULL ); + +#ifdef TEST_MOUNTPOINT2 + if( mp2 ) + { + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT2); + err = umount( TEST_MOUNTPOINT2 ); + if( err < 0 ) SHOW_RESULT( umount, err ); + } +#endif + + // -------------------------------------------------------------- + +#if 0 + maxfile("file.max"); + + listdir( "/", true, -1, NULL ); + + diag_printf("<INFO>: unlink file.max\n"); + err = unlink( "file.max" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + // -------------------------------------------------------------- + + diag_printf("<INFO>: cd /\n"); + err = chdir( "/" ); + if( err == 0 ) + { + checkcwd( "/" ); + + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT); + err = umount( TEST_MOUNTPOINT ); + if( err < 0 ) SHOW_RESULT( umount, err ); + } + + diag_printf("<INFO>: syncing\n"); + err = cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, 0, 0); + if (err != 0) SHOW_RESULT(sync, err); + + CYG_TEST_PASS_FINISH("yaffs4"); +} + +// ------------------------------------------------------------------------- + +#include <cyg/kernel/kapi.h> + +static cyg_handle_t thread_handle; +static cyg_thread thread; +static char stack[CYGNUM_HAL_STACK_SIZE_TYPICAL+1024*4]; + +externC void +cyg_start( void ) +{ + cyg_thread_create(3, // Priority - just a number + fileio4_main, // entry + 0, // index + 0, // no name + &stack[0], // Stack + sizeof(stack), // Size + &thread_handle, // Handle + &thread // Thread data structure + ); + cyg_thread_resume(thread_handle); + + cyg_scheduler_start(); +} + +#else // CYGPKG_KERNEL + +#include <cyg/infra/testcase.h> + +externC void cyg_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_KERNEL"); +} + +#endif + +// ------------------------------------------------------------------------- +// EOF yaffs4.c
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/yaffs5.c @@ -0,0 +1,837 @@ +//========================================================================== +// +// yaffs5.c +// +// Test FAT filesystem +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2004, 2006, 2007 eCosCentric Limited +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg +// Contributors: nickg +// Date: 2007-03-28 +// Purpose: Test FAT system +// Description: This test gets some performance figures from the +// FAT filesystem. +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> + +#ifdef CYGPKG_KERNEL + +#include <pkgconf/hal.h> +#include <pkgconf/kernel.h> +#include <pkgconf/io_fileio.h> + +#include CYGDAT_DEVS_DISK_CFG // testing config defines + +#include <cyg/kernel/ktypes.h> // base kernel types +#include <cyg/infra/cyg_trac.h> // tracing macros +#include <cyg/infra/cyg_ass.h> // assertion macros + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> +#include <stdlib.h> + +#include <cyg/fileio/fileio.h> + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> // HAL polled output + +//========================================================================== +// Config options + +#define TEST_DEVICE CYGDAT_DEVS_DISK_TEST_DEVICE + +#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT + +#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY + +#define TEST_FSTYPE "yaffs" + +#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DEVICE2 CYGDAT_DEVS_DISK_TEST_DEVICE2 + +#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2 + +#define TEST_FSTYPE2 "yaffs" + +#endif + +//========================================================================== + +#define SHOW_RESULT( _fn, _res ) \ +{ \ + diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):""); \ +} + +//========================================================================== + +typedef struct +{ + cyg_int64 ticks; + cyg_int32 halticks; +} timestamp; + +typedef struct +{ + timestamp start; + timestamp end; + cyg_int64 interval; // In HAL ticks + cyg_int64 us_interval; // Interval in microseconds +} timing; + +static cyg_int64 ticks_overhead = 0; +static cyg_int32 us_per_haltick = 0; +static cyg_int32 halticks_per_us = 0; + +static cyg_int64 rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; +static cyg_int64 rtc_period = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; +static cyg_int32 ticks_per_second; + +//========================================================================== + +static char date_string[] = __DATE__; +static char time_string[] = __TIME__; + +cyg_uint32 timehash; + +//========================================================================== + +static void wait_for_tick( void ) +{ + cyg_tick_count_t now = cyg_current_time(); + + while( cyg_current_time() == now ) + continue; +} + +static void get_timestamp( timestamp *ts ) +{ + ts->ticks = cyg_current_time(); + HAL_CLOCK_READ( (cyg_uint32 *)&ts->halticks ); +} + +static cyg_int64 ticks_to_us( cyg_int64 ticks ) +{ + cyg_int64 us; + + if( us_per_haltick != 0 ) + us = ticks * us_per_haltick; + else + us = ticks / halticks_per_us; + + return us; +} + +static void calculate_interval( timing *t ) +{ + t->interval = t->end.halticks - t->start.halticks; + + t->interval += (t->end.ticks - t->start.ticks) * rtc_period; + + t->interval -= ticks_overhead; + + t->us_interval = ticks_to_us( t->interval ); +} + +static void init_timing( void ) +{ + timing t; + + ticks_per_second = (1000000000ULL*rtc_resolution[1])/rtc_resolution[0]; + us_per_haltick = 1000000/(rtc_period * rtc_resolution[1]); + halticks_per_us = (rtc_period * rtc_resolution[1])/1000000; + + wait_for_tick(); + + get_timestamp( &t.start ); + get_timestamp( &t.end ); + + calculate_interval( &t ); + + ticks_overhead = t.interval; + + diag_printf("Timing overhead %lld ticks\n", ticks_overhead ); + +} + +//========================================================================== + +#ifndef CYGPKG_LIBC_STRING + +char *strcat( char *s1, const char *s2 ) +{ + char *s = s1; + while( *s1 ) s1++; + while( (*s1++ = *s2++) != 0); + return s; +} + +#endif + +__externC int +rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW; + +//========================================================================== + +static void listdir( char *name, int statp, int numexpected, int *numgot ) +{ + int err; + DIR *dirp; + int num=0; + + diag_printf("<INFO>: reading directory %s\n",name); + +// diag_printf("<INFO>: opendir(%s)\n",name); + dirp = opendir( name ); + if( dirp == NULL ) SHOW_RESULT( opendir, -1 ); + + for(;;) + { + struct dirent *entry = readdir( dirp ); + + if( entry == NULL ) + break; + num++; + diag_printf("<INFO>: entry %14s",entry->d_name); + if( statp ) + { + char fullname[PATH_MAX]; + struct stat sbuf; + + if( name[0] ) + { + strcpy(fullname, name ); + if( !(name[0] == '/' && name[1] == 0 ) ) + strcat(fullname, "/" ); + } + else fullname[0] = 0; + + strcat(fullname, entry->d_name ); + + err = stat( fullname, &sbuf ); + if( err < 0 ) + { + if( errno == ENOSYS ) + diag_printf(" <no status available>"); + else SHOW_RESULT( stat, err ); + } + else + { + diag_printf(" [mode %08x ino %08x nlink %d size %ld]", + sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size); + } + } + + diag_printf("\n"); + } + +// diag_printf("<INFO>: closedir(%s)\n",name); + err = closedir( dirp ); + if( err < 0 ) SHOW_RESULT( stat, err ); + if (numexpected >= 0 && num != numexpected) + CYG_TEST_FAIL("Wrong number of dir entries\n"); + if ( numgot != NULL ) + *numgot = num; +} + +//========================================================================== + +static void createfile( char *name, size_t asize, size_t block_size ) +{ + size_t size = asize; + cyg_uint8 *buf; + cyg_uint32 *b; + int fd; + ssize_t wrote; + int i; + int err; + timing opent, writet; + + diag_printf("\n--------------------------------------------------------------------\n"); + diag_printf("<INFO>: create file %s size %ld block_size %ld\n",name, (long)size, (long)block_size); + + buf = malloc( block_size ); + if( buf == NULL ) + { + SHOW_RESULT( malloc, -1 ); + return; + } + b = (cyg_uint32 *)buf; + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + i = 0; + while( i < block_size/sizeof(cyg_uint32) ) + { + b[i] = i; + i++; + b[i++] = 0; + b[i++] = timehash; + b[i++] = 0x12345678; + } + + + get_timestamp( &opent.start ); + fd = open( name, O_WRONLY|O_CREAT ); + get_timestamp( &opent.end ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + get_timestamp( &writet.start ); + while( size > 0 ) + { + ssize_t len = size; + if ( len > block_size ) len = block_size; + + b[1] = asize-size; + b[block_size/sizeof(cyg_uint32)-3] = asize-size; + wrote = write( fd, buf, len ); + if( wrote != len ) SHOW_RESULT( write, wrote ); + + size -= wrote; + } + get_timestamp( &writet.end ); + + free( buf ); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); + + calculate_interval( &opent ); + calculate_interval( &writet ); + + diag_printf("CreateFile Results: %s size %ld\n", name, (long)asize); + diag_printf(" Open %8d.%03d ms\n", (int)(opent.us_interval/1000), (int)(opent.us_interval%1000) ); + diag_printf(" Write %8d.%03d ms\n", (int)(writet.us_interval/1000), (int)(writet.us_interval%1000) ); + diag_printf(" Data Rate %10lld KiB/s\n", (1000000LL*asize)/1024/writet.us_interval); +} + +//========================================================================== + +static void checkfile( char *name, size_t block_size ) +{ + cyg_uint8 *buf; + cyg_uint32 *b; + int fd; + ssize_t done; + int err; + off_t pos = 0; + timing opent, readt; + + diag_printf("\n--------------------------------------------------------------------\n"); + diag_printf("<INFO>: check file %s\n",name); + + buf = malloc( block_size ); + if( buf == NULL ) + { + SHOW_RESULT( malloc, -1 ); + return; + } + b = (cyg_uint32 *)buf; + + err = access( name, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + get_timestamp( &opent.start ); + fd = open( name, O_RDONLY ); + get_timestamp( &opent.end ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + get_timestamp( &readt.start ); + for(;;) + { + done = read( fd, buf, block_size ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + // Check that this is the block we wrote + if( b[0] != 0 ) + diag_printf("b[%d] != %08x\n", 0, 0 ); + + if( b[1] != pos ) + diag_printf("b[%d] != %08x\n", 1, (unsigned)pos ); + + if( b[2] != timehash ) + diag_printf("b[%d] != %08x\n", 2, timehash ); + + if( b[3] != 0x12345678 ) + diag_printf("b[%d] != %08x\n", 3, 0x12345678 ); + + if( b[(block_size/sizeof(cyg_uint32))-4] != (block_size/sizeof(cyg_uint32)-4) ) + diag_printf("b[%lu](%08x) != %08x\n", (long)block_size/sizeof(cyg_uint32)-4, + b[(block_size/sizeof(cyg_uint32))-4], + (unsigned)(block_size/sizeof(cyg_uint32)-4) ); + + if( b[block_size/sizeof(cyg_uint32)-3] != pos ) + diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-3, (unsigned)pos ); + + if( b[block_size/sizeof(cyg_uint32)-2] != timehash ) + diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-2, timehash ); + + if( b[block_size/sizeof(cyg_uint32)-1] != 0x12345678 ) + diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-1, 0x12345678 ); + + pos += done; + } + get_timestamp( &readt.end ); + + free( buf ); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); + + calculate_interval( &opent ); + calculate_interval( &readt ); + + diag_printf("CheckFile Results: %s size %ld\n", name, pos); + diag_printf(" Open %8d.%03d ms\n", (int)(opent.us_interval/1000), (int)(opent.us_interval%1000) ); + diag_printf(" Read %8d.%03d ms\n", (int)(readt.us_interval/1000), (int)(readt.us_interval%1000) ); + diag_printf(" Data Rate %10lld KiB/s\n", (1000000LL*pos)/1024/readt.us_interval); +} + +//========================================================================== + +#define TIME_DATA_MAX 20 + +static void checkfile1( char *name, size_t block_size ) +{ + cyg_uint8 *buf; + cyg_uint32 *b; + int fd; + ssize_t done; + int err; + off_t pos = 0; + timing totalt; + + struct + { + int valid; + timing mountt; + timing opent; + timing seekt; + timing readt; + timing closet; + timing umountt; + } time_data[TIME_DATA_MAX]; + int td; + + for( td = 0; td < TIME_DATA_MAX; td++ ) + time_data[td].valid = 0; + td = 0; + + diag_printf("\n--------------------------------------------------------------------\n"); + diag_printf("<INFO>: check file1 %s\n",name); + + buf = malloc( block_size ); + if( buf == NULL ) + { + SHOW_RESULT( malloc, -1 ); + return; + } + b = (cyg_uint32 *)buf; + + get_timestamp( &totalt.start ); + for(;;) + { + get_timestamp( &time_data[td].mountt.start ); + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); + get_timestamp( &time_data[td].mountt.end ); + if( err < 0 ) SHOW_RESULT( mount, err ); + + get_timestamp( &time_data[td].opent.start ); + fd = open( name, O_RDONLY ); + get_timestamp( &time_data[td].opent.end ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + get_timestamp( &time_data[td].seekt.start ); + err = lseek( fd, pos, SEEK_SET ); + get_timestamp( &time_data[td].seekt.end ); + if( err < 0 ) SHOW_RESULT( lseek, err ); + + get_timestamp( &time_data[td].readt.start ); + done = read( fd, buf, block_size ); + get_timestamp( &time_data[td].readt.end ); + if( done < 0 ) SHOW_RESULT( read, done ); + + get_timestamp( &time_data[td].closet.start ); + err = close( fd ); + get_timestamp( &time_data[td].closet.end ); + if( err < 0 ) SHOW_RESULT( close, err ); + + get_timestamp( &time_data[td].umountt.start ); + err = umount( TEST_MOUNTPOINT ); + get_timestamp( &time_data[td].umountt.end ); + if( err < 0 ) SHOW_RESULT( umount, err ); + + if( done == 0 ) break; + + // Check that this is the block we wrote + if( b[0] != 0 ) + diag_printf("b[%d] != %08x\n", 0, 0 ); + + if( b[1] != pos ) + diag_printf("b[%d] != %08x\n", 1, (unsigned)pos ); + +// if( b[2] != timehash ) +// diag_printf("b[%d] != %08x\n", 2, timehash ); + + if( b[3] != 0x12345678 ) + diag_printf("b[%d] != %08x\n", 3, 0x12345678 ); + + if( b[(block_size/sizeof(cyg_uint32))-4] != (block_size/sizeof(cyg_uint32)-4) ) + diag_printf("b[%lu](%08x) != %08x\n", (long)block_size/sizeof(cyg_uint32)-4, + b[(block_size/sizeof(cyg_uint32))-4], + (unsigned)(block_size/sizeof(cyg_uint32)-4) ); + + if( b[block_size/sizeof(cyg_uint32)-3] != pos ) + diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-3, (unsigned)pos ); + +// if( b[block_size/sizeof(cyg_uint32)-2] != timehash ) +// diag_printf("b[%d] != %08x\n", block_size/sizeof(cyg_uint32)-2, timehash ); + + if( b[block_size/sizeof(cyg_uint32)-1] != 0x12345678 ) + diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-1, 0x12345678 ); + + pos += done; + + time_data[td].valid = 1; + if( td < (TIME_DATA_MAX-1) ) + td++; + } + get_timestamp( &totalt.end ); + + free( buf ); + + diag_printf("Block Mount Open Seek Read Close Umount\n"); + + for( td = 0; td < TIME_DATA_MAX; td++ ) + { + if( !time_data[td].valid ) + continue; + + calculate_interval( &time_data[td].mountt ); + calculate_interval( &time_data[td].opent ); + calculate_interval( &time_data[td].seekt ); + calculate_interval( &time_data[td].readt ); + calculate_interval( &time_data[td].closet ); + calculate_interval( &time_data[td].umountt ); + + diag_printf("%2d:", td); + diag_printf(" %8d.%03d", (int)(time_data[td].mountt.us_interval/1000), (int)(time_data[td].mountt.us_interval%1000) ); + diag_printf(" %8d.%03d", (int)(time_data[td].opent.us_interval/1000), (int)(time_data[td].opent.us_interval%1000) ); + diag_printf(" %8d.%03d", (int)(time_data[td].seekt.us_interval/1000), (int)(time_data[td].seekt.us_interval%1000) ); + diag_printf(" %8d.%03d", (int)(time_data[td].readt.us_interval/1000), (int)(time_data[td].readt.us_interval%1000) ); + diag_printf(" %8d.%03d", (int)(time_data[td].closet.us_interval/1000), (int)(time_data[td].closet.us_interval%1000) ); + diag_printf(" %8d.%03d", (int)(time_data[td].umountt.us_interval/1000), (int)(time_data[td].umountt.us_interval%1000) ); + diag_printf("\n"); + } + + calculate_interval( &totalt ); + diag_printf("CheckFile1 Results: %s size %ld\n", name, pos); + diag_printf(" Total %8d.%03d ms\n", (int)(totalt.us_interval/1000), (int)(totalt.us_interval%1000) ); + diag_printf(" Data Rate %10lld KiB/s\n", (1000000LL*pos)/1024/totalt.us_interval); + +} + +//========================================================================== + +void checkcwd( const char *cwd ) +{ + static char cwdbuf[PATH_MAX]; + char *ret; + + ret = getcwd( cwdbuf, sizeof(cwdbuf)); + if( ret == NULL ) SHOW_RESULT( getcwd, ret ); + + if( strcmp( cwdbuf, cwd ) != 0 ) + { + diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd ); + CYG_TEST_FAIL( "Current directory mismatch"); + } +} + +//========================================================================== + +void fs_callback( cyg_int32 event, CYG_ADDRWORD data ) +{ +#if 0 + diag_printf("Filesystem %sSAFE\n", + event==CYG_FS_CALLBACK_UNSAFE?"UN":""); +#endif +} + + +//========================================================================== +// main + +void yaffs5_main( CYG_ADDRESS id ) +{ + int err; + int existingdirents=-1; + int i; + timing mountt, umountt; + +#if defined(CYGSEM_FILEIO_BLOCK_USAGE) + struct cyg_fs_block_usage usage; +#endif +// struct cyg_fs_callback_info callback; + + CYG_TEST_INIT(); + + init_timing(); + + for( i = 0 ; date_string[i] != 0 ; i++ ) + timehash = (timehash<<1) ^ date_string[i]; + for( i = 0 ; time_string[i] != 0 ; i++ ) + timehash = (timehash<<1) ^ time_string[i]; + + // -------------------------------------------------------------- + +#if 1 +#define DO_UMOUNT + get_timestamp( &mountt.start ); + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); +// err = mount( TEST_DEVICE, TEST_MOUNTPOINT, "yaffs:sync=write" ); +// err = mount( TEST_DEVICE, TEST_MOUNTPOINT, "yaffs:sync=close" ); +// err = mount( TEST_DEVICE, TEST_MOUNTPOINT, "yaffs:sync=data" ); + get_timestamp( &mountt.end ); + if( err < 0 ) { + SHOW_RESULT( mount, err ); + CYG_TEST_FAIL_FINISH("yaffs5"); + } + +#if 0 + callback.callback = fs_callback; + callback.data = 0; + err = cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_CALLBACK, + &callback, sizeof(callback)); + if( err < 0 ) SHOW_RESULT( cyg_fs_setinfo, err ); +#endif + + calculate_interval( &mountt ); + diag_printf(" Mount %8d.%03d ms\n", (int)(mountt.us_interval/1000), (int)(mountt.us_interval%1000) ); + + err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT TEST_DIRECTORY); + err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( TEST_MOUNTPOINT TEST_DIRECTORY, true, -1, &existingdirents ); + + // -------------------------------------------------------------- +#if defined(CYGSEM_FILEIO_BLOCK_USAGE) + err = cyg_fs_getinfo(TEST_MOUNTPOINT, FS_INFO_BLOCK_USAGE, + &usage, sizeof(usage)); + if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err ); + diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n", + usage.total_blocks, usage.total_blocks * usage.block_size); + diag_printf("<INFO>: free size: %6lld blocks, %10lld bytes\n", + usage.free_blocks, usage.free_blocks * usage.block_size); + diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size); +#endif + // -------------------------------------------------------------- + +#endif + +#if 1 + createfile( "yaffs5.0", 1024*1024, 16*1024 ); + checkfile( "yaffs5.0",16*1024 ); + err = unlink( "yaffs5.0" ); + err = cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, 0, 0); + if (err != 0) SHOW_RESULT(sync, err); +#endif + +#if 1 + createfile( "yaffs5.0", 200*1024, 1024 ); + checkfile( "yaffs5.0", 1024 ); + err = unlink( "yaffs5.0" ); +#endif + +#if 1 + createfile( "yaffs5.1", 1024*1024, 1024 ); + createfile( "yaffs5.2", 1024*1024, 4*1024 ); + err = cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, 0, 0); + if (err != 0) SHOW_RESULT(sync, err); + createfile( "yaffs5.3", 8*1024*1024, 32*1024 ); + + checkfile( "yaffs5.1", 1024 ); + checkfile( "yaffs5.2", 4*1024 ); + checkfile( "yaffs5.3", 32*1024 ); + + diag_printf("\n--------------------------------------------------------------------\n"); + + listdir( "." , true, existingdirents+3, NULL ); + + // -------------------------------------------------------------- + + diag_printf("<INFO>: unlink yaffs5.1\n"); + err = unlink( "yaffs5.1" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink yaffs5.2\n"); + err = unlink( "yaffs5.2" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink yaffs5.3\n"); + err = unlink( "yaffs5.3" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + // -------------------------------------------------------------- + +#if 1 && defined(DO_UMOUNT) + + diag_printf("<INFO>: unlink yaffs5.4\n"); + err = unlink( "yaffs5.4" ); + + createfile( "yaffs5.4", 5*1024*1024, 32*1024 ); +#endif + + // -------------------------------------------------------------- + +#ifdef DO_UMOUNT + diag_printf("<INFO>: cd /\n"); + err = chdir( "/" ); + if( err == 0 ) + { + checkcwd( "/" ); + + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT); + get_timestamp( &umountt.start ); + err = umount( TEST_MOUNTPOINT ); + get_timestamp( &umountt.end ); + if( err < 0 ) SHOW_RESULT( umount, err ); + + calculate_interval( &umountt ); + diag_printf(" Umount %8d.%03d ms\n", (int)(umountt.us_interval/1000), (int)(umountt.us_interval%1000) ); + + } +#endif + +#if 1 + + diag_printf("<INFO>: syncing\n"); + err = cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, 0, 0); + if (err != 0) SHOW_RESULT(sync, err); + + checkfile1(TEST_MOUNTPOINT TEST_DIRECTORY "/yaffs5.4", 32*1024 ); + + // Remount just to remove yaffs5.4 + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); + if( err < 0 ) { + SHOW_RESULT( mount, err ); + CYG_TEST_FAIL_FINISH("yaffs5"); + } + err = unlink( TEST_MOUNTPOINT TEST_DIRECTORY "/yaffs5.4" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + err = umount( TEST_MOUNTPOINT ); + if( err < 0 ) SHOW_RESULT( umount, err ); + +#else + + // don't sync if not mounted + diag_printf("<INFO>: syncing\n"); + err = cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, 0, 0); + if (err != 0) SHOW_RESULT(sync, err); + +#endif + + CYG_TEST_PASS_FINISH("yaffs5"); +} + +// ------------------------------------------------------------------------- + +#include <cyg/kernel/kapi.h> + +static cyg_handle_t thread_handle; +static cyg_thread thread; +static char stack[CYGNUM_HAL_STACK_SIZE_TYPICAL+8*1024]; +//static char stack[64*1024]; + +externC void +cyg_start( void ) +{ + cyg_thread_create(3, // Priority - just a number + yaffs5_main, // entry + 0, // index + 0, // no name + &stack[0], // Stack + sizeof(stack), // Size + &thread_handle, // Handle + &thread // Thread data structure + ); + cyg_thread_resume(thread_handle); + + cyg_scheduler_start(); +} + +#else // CYGPKG_KERNEL + +#include <cyg/infra/testcase.h> + +externC void cyg_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_KERNEL"); +} + +#endif + +// ------------------------------------------------------------------------- +// EOF yaffs5.c
new file mode 100644 --- /dev/null +++ b/packages/fs/yaffs/current/tests/yaffs6.c @@ -0,0 +1,984 @@ +//========================================================================== +// +// yaffs6.c +// +// Test FAT UTF-8 support +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +// Copyright (C) 2004, 2005, 2006, 2007 eCosCentric Limited +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg +// Contributors: nickg +// Date: 2007-06-20 +// Purpose: Test fileio system +// Description: This test uses the testfs to check out the initialization +// and basic operation of the fileio system. +// This is essentially a copy of yaffs4 with UTF8 encoded +// file names. +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> + +#ifdef CYGPKG_KERNEL + +#include <pkgconf/hal.h> +#include <pkgconf/kernel.h> +#include <pkgconf/io_fileio.h> + +#include CYGDAT_DEVS_DISK_CFG // testing config defines + +#include <cyg/kernel/ktypes.h> // base kernel types +#include <cyg/infra/cyg_trac.h> // tracing macros +#include <cyg/infra/cyg_ass.h> // assertion macros + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> + +#include <cyg/fileio/fileio.h> + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> // HAL polled output + +//========================================================================== +// Config options + +#define TEST_DEVICE CYGDAT_DEVS_DISK_TEST_DEVICE + +#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT + +#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY + +#define TEST_FSTYPE "yaffs" + +#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DEVICE2 CYGDAT_DEVS_DISK_TEST_DEVICE2 + +#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 + +#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2 + +#define TEST_FSTYPE2 "yaffs" + +#endif + +//========================================================================== + +#define SHOW_RESULT( _fn, _res ) \ +{ \ + diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):""); \ +} + +//========================================================================== + +#define IOSIZE 100 + +#define CLEANUP + +//========================================================================== +// The following filenames are in Cyrillic and are UTF-8 encoded. +// +// WARNING: Only edit this file with an editor that is UTF-8 aware (I +// use EMACS on Linux, but Notepad on Windows also works). Saving this +// file from an unaware editor could cause these strings to be +// corrupted and make this test fail. If the strings below do not +// appear as clean Cyrillic characters then exit now without saving +// and look for a better editor. + +#if 1 + +#define FOO "Фоо" +#define FEE "Спутник" +#define BAR "Байконур" +#define BUNDY "СергеЬй ПаЬвлович Королёв" +#define FUM "Юрий Гагаринский" +#define DOO "Константин Эдуардович Циолковский" +//#define FIE "Федеральное космическое агентство России" +#define FIE "Федеральное космическое" +#define FOE "Валентин Петрович Глушко" + +#define TINKY "Восток" +#define LAALAA "Восход" +#define NOONOO "Салют" +#define DIPSY "Космодром" +#define PO "Лайка" + +#define XXXX "Гласность" +#define YYYY "перестройка" +#define ZZZZ "Калашникова" +#define WWWW "матрёшка" + +#else + +#define FOO "foo" +#define FEE "fee" +#define BAR "bar" +#define BUNDY "bundy" +#define FUM "fum" +#define DOO "doo" +#define FIE "fie" +#define FOE "foe" + +#define TINKY "tinky" +#define LAALAA "laalaa" +#define NOONOO "noonoo" +#define DIPSY "dipsy" +#define PO "po" + +#define XXXX "xxxx" +#define YYYY "yyyy" +#define ZZZZ "zzzz" +#define WWWW "wwww" + +#endif + + +//========================================================================== + +#ifndef CYGPKG_LIBC_STRING + +char *strcat( char *s1, const char *s2 ) +{ + char *s = s1; + while( *s1 ) s1++; + while( (*s1++ = *s2++) != 0); + return s; +} + +#endif + +__externC int +rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW; + +//========================================================================== + +static void listdir( char *name, int statp, int numexpected, int *numgot ) +{ + int err; + DIR *dirp; + int num=0; + + diag_printf("<INFO>: reading directory %s\n",name); + +// diag_printf("<INFO>: opendir(%s)\n",name); + dirp = opendir( name ); + if( dirp == NULL ) SHOW_RESULT( opendir, -1 ); + + for(;;) + { + struct dirent *entry = readdir( dirp ); + + if( entry == NULL ) + break; + num++; + + diag_printf("<INFO>: entry "); + + if( statp ) + { + char fullname[PATH_MAX]; + struct stat sbuf; + + if( name[0] ) + { + strcpy(fullname, name ); + if( !(name[0] == '/' && name[1] == 0 ) ) + strcat(fullname, "/" ); + } + else fullname[0] = 0; + + strcat(fullname, entry->d_name ); + + err = stat( fullname, &sbuf ); + if( err < 0 ) + { + if( errno == ENOSYS ) + diag_printf(" <no status available>"); + else SHOW_RESULT( stat, err ); + } + else + { + diag_printf(" [mode %08x ino %08x nlink %d size %6ld]", + sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size); + } + } + + diag_printf(" %s\n",entry->d_name); + } + +// diag_printf("<INFO>: closedir(%s)\n",name); + err = closedir( dirp ); + if( err < 0 ) SHOW_RESULT( stat, err ); + if (numexpected >= 0 && num != numexpected) + CYG_TEST_FAIL("Wrong number of dir entries"); + if ( numgot != NULL ) + *numgot = num; +} + +//========================================================================== + +static void createfile( char *name, size_t size ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + + diag_printf("<INFO>: create file %s size %ld\n",name, (long)size); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + while( size > 0 ) + { + ssize_t len = size; + if ( len > IOSIZE ) len = IOSIZE; + + wrote = write( fd, buf, len ); + if( wrote != len ) SHOW_RESULT( write, wrote ); + + size -= wrote; + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +#if 0 +static void maxfile( char *name ) +{ + char buf[IOSIZE]; + int fd; + ssize_t wrote; + int i; + int err; + size_t size = 0; + size_t prevsize = 0; + + diag_printf("<INFO>: create maximal file %s\n",name); + diag_printf("<INFO>: This may take a few minutes\n"); + + err = access( name, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; + + fd = open( name, O_WRONLY|O_CREAT ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + do + { + wrote = write( fd, buf, IOSIZE ); + //if( wrote < 0 ) SHOW_RESULT( write, wrote ); + + if( wrote >= 0 ) + size += wrote; + + if( (size-prevsize) > 100000 ) + { + diag_printf("<INFO>: size = %ld \n", size); + prevsize = size; + } + + } while( wrote == IOSIZE ); + + diag_printf("<INFO>: file size == %ld\n",size); + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} +#endif + +//========================================================================== + +static void checkfile( char *name ) +{ + char buf[IOSIZE]; + int fd; + ssize_t done; + int i; + int err; + off_t pos = 0; + + diag_printf("<INFO>: check file %s\n",name); + + err = access( name, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd = open( name, O_RDONLY ); + if( fd < 0 ) SHOW_RESULT( open, fd ); + + for(;;) + { + done = read( fd, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + for( i = 0; i < done; i++ ) + if( buf[i] != i%256 ) + { + diag_printf("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256); + CYG_TEST_FAIL("Data read not equal to data written\n"); + for(;;); + } + + pos += done; + } + + err = close( fd ); + if( err < 0 ) SHOW_RESULT( close, err ); +} + +//========================================================================== + +static void copyfile( char *name2, char *name1 ) +{ + + int err; + char buf[IOSIZE]; + int fd1, fd2; + ssize_t done, wrote; + + diag_printf("<INFO>: copy file %s -> %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + err = access( name2, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_WRONLY|O_CREAT ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done = read( fd2, buf, IOSIZE ); + if( done < 0 ) SHOW_RESULT( read, done ); + + if( done == 0 ) break; + + wrote = write( fd1, buf, done ); + if( wrote != done ) SHOW_RESULT( write, wrote ); + + if( wrote != done ) break; + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +static void comparefiles( char *name2, char *name1 ) +{ + int err; + char buf1[IOSIZE]; + char buf2[IOSIZE]; + int fd1, fd2; + ssize_t done1, done2; + int i; + + diag_printf("<INFO>: compare files %s == %s\n",name2,name1); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + err = access( name1, F_OK ); + if( err != 0 ) SHOW_RESULT( access, err ); + + fd1 = open( name1, O_RDONLY ); + if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); + + fd2 = open( name2, O_RDONLY ); + if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); + + for(;;) + { + done1 = read( fd1, buf1, IOSIZE ); + if( done1 < 0 ) SHOW_RESULT( read, done1 ); + + done2 = read( fd2, buf2, IOSIZE ); + if( done2 < 0 ) SHOW_RESULT( read, done2 ); + + if( done1 != done2 ) + diag_printf("Files different sizes\n"); + + if( done1 == 0 ) break; + + for( i = 0; i < done1; i++ ) + if( buf1[i] != buf2[i] ) + { + diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]); + CYG_TEST_FAIL("Data in files not equal\n"); + } + } + + err = close( fd1 ); + if( err < 0 ) SHOW_RESULT( close, err ); + + err = close( fd2 ); + if( err < 0 ) SHOW_RESULT( close, err ); + +} + +//========================================================================== + +void checkcwd( const char *cwd ) +{ + static char cwdbuf[PATH_MAX]; + char *ret; + + ret = getcwd( cwdbuf, sizeof(cwdbuf)); + if( ret == NULL ) SHOW_RESULT( getcwd, ret ); + + if( strcmp( cwdbuf, cwd ) != 0 ) + { + diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd ); + CYG_TEST_FAIL( "Current directory mismatch"); + } +} + +//========================================================================== +// main + +void yaffs6_main( CYG_ADDRESS id ) +{ + int err; + int existingdirents=-1; + cyg_bool mp2 = false; + int fd; + + char dirname[256]; + char filename1[256]; + char filename2[256]; + +#define NEW_FILENAME( fn, f ) \ +{ \ + fn[0]=0; \ + strcat(fn, dirname); \ + strcat(fn, "/"); \ + strcat(fn,f); \ +} + +#define NEW_FILENAME1( f ) NEW_FILENAME( filename1, f ) +#define NEW_FILENAME2( f ) NEW_FILENAME( filename2, f ) + + CYG_TEST_INIT(); + +#ifdef CYGDBG_INFRA_DIAG_CHECK_STRINGS + diag_printf("WARNING: CYGDBG_INFRA_DIAG_CHECK_STRINGS is defined, Cyrillic file names will not be printed.\n"); +#else + diag_printf("WARNING: Cyrillic file names printed in UTF-8 may not be readable in some environments.\n"); +#endif + + // -------------------------------------------------------------- + + err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE ); + if( err < 0 ) { + SHOW_RESULT( mount, err ); + CYG_TEST_FAIL_FINISH("yaffs6"); + } + + err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT TEST_DIRECTORY); + err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( TEST_MOUNTPOINT TEST_DIRECTORY, true, -1, &existingdirents ); + + // -------------------------------------------------------------- + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT ); + strcat(dirname, TEST_DIRECTORY ); + + // -------------------------------------------------------------- + + createfile( FOO, 20257 ); + checkfile( FOO ); + copyfile( FOO, FEE); + checkfile( FEE ); + comparefiles( FOO, FEE ); + + diag_printf("<INFO>: mkdir " BAR "\n"); + err = mkdir( BAR, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL ); + + copyfile( FEE, BAR "/" FUM ); + checkfile( BAR "/" FUM ); + comparefiles( FEE, BAR "/" FUM ); + + diag_printf("<INFO>: cd " BAR "\n"); + err = chdir( BAR ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + NEW_FILENAME1( BAR ); + checkcwd( filename1 ); + + diag_printf("<INFO>: rename ../" FOO " " BUNDY "\n"); + err = rename( "../" FOO, BUNDY ); + if( err < 0 ) SHOW_RESULT( rename, err ); + + listdir( dirname, true, existingdirents+2, NULL ); + listdir( "." , true, 4, NULL ); + + checkfile( "../" BAR "/" BUNDY ); + comparefiles("../" FEE, BUNDY ); + +#if 1 + + // -------------------------------------------------------------- + // Check for some common error cases + + // First make some directories + diag_printf("<INFO>: mkdir " DOO "\n"); + err = mkdir( DOO, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " FIE" \n"); + err = mkdir( FIE, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: mkdir " FIE "/" FOE "\n"); + err = mkdir( FIE "/" FOE, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + + diag_printf("<INFO>: rename " FUM " " DOO " -- should fail\n"); + err = rename( FUM, DOO ); + if( err < 0 && errno != EISDIR ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename " DOO " " FUM " -- should fail\n"); + err = rename( DOO, FUM ); + if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename " DOO " " FIE " -- should fail\n"); + err = rename( DOO, FIE ); + if( err < 0 && errno != EIO ) SHOW_RESULT( rename, err ); + + NEW_FILENAME1( XXXX "/" YYYY ) + diag_printf("<INFO>: rename " FUM " %s -- should fail\n",filename1); + err = rename( FUM, filename1 ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: rename " FUM " " FUM " -- should fail\n"); + err = rename( FUM, FUM ); + if( err < 0 ) SHOW_RESULT( rename, err ); + + diag_printf("<INFO>: unlink " FEE " -- should fail\n"); + err = unlink( FEE ); + if( err < 0 && errno != ENOENT ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( BAR ); + diag_printf("<INFO>: rmdir %s -- should fail\n",filename1); + err = rmdir( filename1 ); + if( err < 0 && errno != ENOTEMPTY ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: unlink %s -- should fail\n",filename1); + err = unlink( filename1 ); + if( err < 0 && errno != EISDIR ) SHOW_RESULT( unlink, err ); + + NEW_FILENAME1( BAR "/" FUM ); + diag_printf("<INFO>: rmdir %s -- should fail\n",filename1); + err = rmdir( filename1 ); + if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: mkdir %s -- should fail\n",filename1); + err = mkdir( filename1, 0 ); + if( err < 0 && errno != EEXIST ) SHOW_RESULT( mkdir, err ); + + diag_printf("<INFO>: open " BUNDY " exclusive -- should fail\n"); + fd = open( BUNDY, O_WRONLY|O_CREAT|O_EXCL ); + if( fd < 0 && errno != EEXIST ) SHOW_RESULT( open, fd ); + + diag_printf("<INFO>: open %s -- should fail\n",dirname); + fd = open( dirname, O_WRONLY ); + if( fd < 0 && errno != EISDIR ) SHOW_RESULT( open, fd ); + + + listdir( dirname, true, existingdirents+2, NULL ); + listdir( "." , true, 6, NULL ); + + // -------------------------------------------------------------- + +#ifdef CLEANUP + + diag_printf("<INFO>: rename " FIE " " DOO "\n"); + err = rename( FIE, DOO ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: rmdir " DOO "/" FOE "\n"); + err = rmdir(DOO "/" FOE); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: rmdir " DOO "\n"); + err = rmdir(DOO); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink ../" FEE "\n"); + err = unlink( "../" FEE ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " FUM "\n"); + err = unlink( FUM ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink ../" BAR "/" BUNDY "\n"); + err = unlink( "../" BAR "/" BUNDY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( dirname ); + +#ifdef CLEANUP + diag_printf("<INFO>: rmdir " BAR "\n"); + err = rmdir( BAR ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + listdir( dirname, false, existingdirents, NULL ); +#endif + + // -------------------------------------------------------------- + +#ifdef TEST_MOUNTPOINT2 + diag_printf("<INFO>: mount %s\n", TEST_MOUNTPOINT2); + err = mount( TEST_DEVICE2, TEST_MOUNTPOINT2, TEST_FSTYPE2 ); + + if( err == 0 ) + { + mp2 = true; + diag_printf("<INFO>: mount %s succeeded\n", TEST_MOUNTPOINT2); + err = access( TEST_MOUNTPOINT2 TEST_DIRECTORY2, F_OK ); + if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); + + if( err < 0 && errno == EACCES ) + { + diag_printf("<INFO>: create %s\n", + TEST_MOUNTPOINT2 TEST_DIRECTORY2); + err = mkdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + } + + err = chdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2 ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( TEST_MOUNTPOINT2 TEST_DIRECTORY2 ); + + dirname[0] = 0; + strcat(dirname, TEST_MOUNTPOINT2 ); + strcat(dirname, TEST_DIRECTORY2 ); + + } + else + { + mp2 = false; + diag_printf("<INFO>: mount %s failed, ", TEST_MOUNTPOINT2); + diag_printf("using %s instead\n", dirname ); + } + +#endif + + listdir( dirname , true, -1, &existingdirents); + + NEW_FILENAME1( TINKY ); + NEW_FILENAME2( LAALAA ); + + createfile( filename1, 4567 ); + copyfile( filename1, filename2 ); + checkfile( filename1); + checkfile( filename2); + comparefiles( filename1, filename2 ); + + diag_printf("<INFO>: cd %s\n",dirname); + err = chdir( dirname ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + checkcwd( dirname ); + + diag_printf("<INFO>: mkdir " NOONOO "\n"); + err = mkdir( NOONOO, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + listdir( dirname , true, existingdirents+3, NULL); + + diag_printf("<INFO>: cd " NOONOO "\n"); + err = chdir( NOONOO ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + + NEW_FILENAME1( NOONOO ); + checkcwd( filename1 ); + + createfile( TINKY, 6789 ); + checkfile( TINKY ); + + createfile( DIPSY, 34567 ); + checkfile( DIPSY ); + copyfile( DIPSY, PO ); + checkfile( PO ); + comparefiles( DIPSY, PO ); + + listdir( ".", true, 5, NULL ); + listdir( "..", true, existingdirents+3, NULL ); + + // -------------------------------------------------------------- + +#ifdef CLEANUP + diag_printf("<INFO>: unlink " TINKY "\n"); + err = unlink( TINKY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " DIPSY "\n"); + err = unlink( DIPSY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " PO "\n"); + err = unlink( PO ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( dirname ); + +#ifdef CLEANUP + diag_printf("<INFO>: rmdir " NOONOO "\n"); + err = rmdir( NOONOO ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); +#endif + + // -------------------------------------------------------------- + + err = mkdir( XXXX, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + err = mkdir( XXXX "/" YYYY, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + err = mkdir( XXXX "/" YYYY "/" ZZZZ, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + err = mkdir( XXXX "/" YYYY "/" ZZZZ "/" WWWW, 0 ); + if( err < 0 ) SHOW_RESULT( mkdir, err ); + + NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ "/" WWWW ); + diag_printf("<INFO>: cd %s\n",filename1); + err = chdir( filename1 ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ ); + diag_printf("<INFO>: cd ..\n"); + err = chdir( ".." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ ); + diag_printf("<INFO>: cd .\n"); + err = chdir( "." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + NEW_FILENAME1( XXXX "/" YYYY ); + diag_printf("<INFO>: cd ../../" YYYY "\n"); + err = chdir( "../../" YYYY ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( filename1 ); + + diag_printf("<INFO>: cd ../..\n"); + err = chdir( "../.." ); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( dirname ); + + diag_printf("<INFO>: rmdir " XXXX "/" YYYY "/" ZZZZ "/" WWWW "\n"); + err = rmdir( XXXX "/" YYYY "/" ZZZZ "/" WWWW ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir "XXXX "/" YYYY "/" ZZZZ "\n"); + err = rmdir( XXXX "/" YYYY "/" ZZZZ ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir " XXXX "/" YYYY "\n"); + err = rmdir( XXXX "/" YYYY ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + diag_printf("<INFO>: rmdir "XXXX "\n"); + err = rmdir( XXXX ); + if( err < 0 ) SHOW_RESULT( rmdir, err ); + + // -------------------------------------------------------------- + + checkcwd( dirname ); + +#ifdef CLEANUP + diag_printf("<INFO>: unlink "TINKY "\n"); + err = unlink( TINKY ); + if( err < 0 ) SHOW_RESULT( unlink, err ); + + diag_printf("<INFO>: unlink " LAALAA" \n"); + err = unlink( LAALAA ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + // -------------------------------------------------------------- + + diag_printf("<INFO>: cd %s\n", TEST_MOUNTPOINT TEST_DIRECTORY); + err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY); + if( err < 0 ) SHOW_RESULT( chdir, err ); + checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY ); + + listdir( ".", true, -1, NULL ); + +#ifdef TEST_MOUNTPOINT2 + if( mp2 ) + { + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT2); + err = umount( TEST_MOUNTPOINT2 ); + if( err < 0 ) SHOW_RESULT( umount, err ); + } +#endif + + // -------------------------------------------------------------- + +#if 0 + maxfile("file.max"); + + listdir( "/", true, -1, NULL ); + + diag_printf("<INFO>: unlink file.max\n"); + err = unlink( "file.max" ); + if( err < 0 ) SHOW_RESULT( unlink, err ); +#endif + + // -------------------------------------------------------------- + +#endif + diag_printf("<INFO>: cd /\n"); + err = chdir( "/" ); + if( err == 0 ) + { + checkcwd( "/" ); + + diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT); + err = umount( TEST_MOUNTPOINT ); + if( err < 0 ) SHOW_RESULT( umount, err ); + } + + diag_printf("<INFO>: syncing\n"); + err = cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_SYNC, 0, 0); + if (err != 0) SHOW_RESULT(sync, err); + + CYG_TEST_PASS_FINISH("yaffs6"); +} + +// ------------------------------------------------------------------------- + +#include <cyg/kernel/kapi.h> + +static cyg_handle_t thread_handle; +static cyg_thread thread; +static char stack[CYGNUM_HAL_STACK_SIZE_TYPICAL+1024*4]; + +externC void +cyg_start( void ) +{ + cyg_thread_create(3, // Priority - just a number + yaffs6_main, // entry + 0, // index + 0, // no name + &stack[0], // Stack + sizeof(stack), // Size + &thread_handle, // Handle + &thread // Thread data structure + ); + cyg_thread_resume(thread_handle); + + cyg_scheduler_start(); +} + +#else // CYGPKG_KERNEL + +#include <cyg/infra/testcase.h> + +externC void cyg_start(void) +{ + CYG_TEST_NA("Needs CYGPKG_KERNEL"); +} + +#endif + +// ------------------------------------------------------------------------- +// EOF yaffs6.c
deleted file mode 100755 --- a/patch-ker.sh +++ /dev/null @@ -1,121 +0,0 @@ -#!/bin/sh -# -# YAFFS: Yet another FFS. A NAND-flash specific file system. -# -# Copyright (C) 2002-2006 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. -# -# Patch YAFFS into the kernel -# -# args: kpath : Full path to kernel sources to be patched -# -# Somewhat "inspired by" the mtd patchin script -# -# $Id$ - -VERSION=0 -PATCHLEVEL=0 -SUBLEVEL=0 -COPYORLINK=$1 -LINUXDIR=$2 - -# To be a Linux directory, it must have a Makefile - - -# Display usage of this script -usage () { - echo "usage: $0 c/l kernelpath" - echo " if c/l is c, then copy. If l then link" - exit 1 -} - - - -if [ -z $LINUXDIR ] -then - usage; -fi - -if [ $COPYORLINK = l ]; then - CPY="ln -s" -elif [ $COPYORLINK = c ]; then - CPY="cp" -else - echo "unknown copy or link type" - usage; -fi - - -# Check if kerneldir contains a Makefile -if [ ! -f $LINUXDIR/Makefile ] -then - echo "Directory $LINUXDIR does not exist or is not a kernel source directory"; - exit 1; -fi - -# Get kernel version -VERSION=`grep -s VERSION <$LINUXDIR/Makefile | head -n 1 | sed s/'VERSION = '//` -PATCHLEVEL=`grep -s PATCHLEVEL <$LINUXDIR/Makefile | head -n 1 | sed s/'PATCHLEVEL = '//` -SUBLEVEL=`grep -s SUBLEVEL <$LINUXDIR/Makefile | head -n 1 | sed s/'SUBLEVEL = '//` - -# Can we handle this version? -if [ $VERSION -ne 2 -o $PATCHLEVEL -lt 6 ] -then - echo "Cannot patch kernel version $VERSION.$PATCHLEVEL.$SUBLEVEL, must be 2.6.x or higher" - exit 1; -fi - - -KCONFIG=$LINUXDIR/fs/Kconfig -KCONFIGOLD=$LINUXDIR/fs/Kconfig.pre.yaffs -YAFFS_PATCHED_STRING=`grep -s yaffs <$KCONFIG | head -n 1` - -MAKEFILE=$LINUXDIR/fs/Makefile -MAKEFILEOLD=$LINUXDIR/fs/Makefile.pre.yaffs - -if [ ! -z "$YAFFS_PATCHED_STRING" ] -then - YAFFS_PATCHED=0 - echo "$KCONFIG already mentions YAFFS, so we will not change it" -else - # Change the fs/Kconfig file - # Save the old Kconfig - # Copy all stuff up to JFFS - # Insert some YAFFS stuff - # Copy all the rest of the stuff - - YAFFS_PATCHED=1 - echo "Updating $KCONFIG" - mv -f $KCONFIG $KCONFIGOLD - sed -n -e "/[Jj][Ff][Ff][Ss]/,99999 ! p" $KCONFIGOLD >$KCONFIG - echo "">>$KCONFIG - echo "# Patched by YAFFS" >>$KCONFIG - echo "source \"fs/yaffs2/Kconfig\"">>$KCONFIG - echo "">>$KCONFIG - sed -n -e "/[Jj][Ff][Ff][Ss]/,99999 p" $KCONFIGOLD >>$KCONFIG - - # now do fs/Makefile -- simply add the target at the end - echo "Updating $MAKEFILE" - cp -f $MAKEFILE $MAKEFILEOLD - echo "">>$MAKEFILE - echo "# Patched by YAFFS" >>$MAKEFILE - echo "obj-\$(CONFIG_YAFFS_FS) += yaffs2/" >>$MAKEFILE - -fi - -YAFFSDIR=$LINUXDIR/fs/yaffs2 - -if [ -e $YAFFSDIR ] -then - echo "$YAFFSDIR exists, not patching" -else - mkdir $LINUXDIR/fs/yaffs2 - $CPY $PWD/Makefile.kernel $LINUXDIR/fs/yaffs2/Makefile - $CPY $PWD/Kconfig $LINUXDIR/fs/yaffs2 - $CPY $PWD/*.c $PWD/*.h $LINUXDIR/fs/yaffs2 -fi
deleted file mode 100644 --- a/patches/README.txt +++ /dev/null @@ -1,6 +0,0 @@ -This directory holds patches that are useful for Linux integration. - -Right now there is only one patched file, yaffs_mtdif2.c. This has been -patched with a tweaked version of "Sergey's patch" and typically makes a -stock mtd work properly. -
deleted file mode 100644 --- a/patches/yaffs_mtdif2.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * - * Copyright (C) 2002 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning <charles@aleph1.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* mtd interface for YAFFS2 */ - -const char *yaffs_mtdif2_c_version = - "$Id$"; - -#include "yportenv.h" - - -#include "yaffs_mtdif2.h" - -#include "linux/mtd/mtd.h" -#include "linux/types.h" -#include "linux/time.h" - -#include "yaffs_packedtags2.h" - - -void nandmtd2_pt2buf(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); - __u8 *ptab = (__u8 *)pt; /* packed tags as bytes */ - - int i, j = 0, k, n; - - /* Pack buffer with 0xff */ - for (i = 0; i < mtd->oobsize; i++) - dev->spareBuffer[i] = 0xff; - - if(!is_raw){ - memcpy(dev->spareBuffer,pt,sizeof(yaffs_PackedTags2)); - } else { - j = 0; - k = mtd->oobinfo.oobfree[j][0]; - n = mtd->oobinfo.oobfree[j][1]; - - if (n == 0) { - T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR))); - YBUG(); - } - - for (i = 0; i < sizeof(yaffs_PackedTags2); i++) { - if (n == 0) { - j++; - k = mtd->oobinfo.oobfree[j][0]; - n = mtd->oobinfo.oobfree[j][1]; - if (n == 0) { - T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR))); - YBUG(); - } - } - dev->spareBuffer[k] = ptab[i]; - k++; - n--; - } - } - -} - -void nandmtd2_buf2pt(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); - int i, j = 0, k, n; - __u8 *ptab = (__u8 *)pt; /* packed tags as bytes */ - - - if (!is_raw) { - - memcpy(pt,dev->spareBuffer,sizeof(yaffs_PackedTags2)); - } else { - j = 0; - k = mtd->oobinfo.oobfree[j][0]; - n = mtd->oobinfo.oobfree[j][1]; - - if (n == 0) { - T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR))); - YBUG(); - } - - for (i = 0; i < sizeof(yaffs_PackedTags2); i++) { - if (n == 0) { - j++; - k = mtd->oobinfo.oobfree[j][0]; - n = mtd->oobinfo.oobfree[j][1]; - if (n == 0) { - T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR))); - YBUG(); - } - } - ptab[i] = dev->spareBuffer[k]; - k++; - n--; - } - } - -} - -int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, - const __u8 * data, - const yaffs_ExtendedTags * tags) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); - size_t dummy; - int retval = 0; - - loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk; - - yaffs_PackedTags2 pt; - - T(YAFFS_TRACE_MTD, - (TSTR - ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" - TENDSTR), chunkInNAND, data, tags)); - - if (tags) { - yaffs_PackTags2(&pt, tags); - } - - if (data && tags) { - nandmtd2_pt2buf(dev, &pt, 0); - retval = - mtd->write_ecc(mtd, addr, dev->nBytesPerChunk, - &dummy, data, dev->spareBuffer, - NULL); - - } else { - - T(YAFFS_TRACE_ALWAYS, - (TSTR - ("Write chunk with null tags or data!" TENDSTR))); - YBUG(); - } - - if (retval == 0) - return YAFFS_OK; - else - return YAFFS_FAIL; -} - -int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, - __u8 * data, yaffs_ExtendedTags * tags) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); - size_t dummy; - int retval = 0; - - loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk; - - yaffs_PackedTags2 pt; - - T(YAFFS_TRACE_MTD, - (TSTR - ("nandmtd2_ReadChunkWithTagsToNAND chunk %d data %p tags %p" - TENDSTR), chunkInNAND, data, tags)); - - if (0 && data && tags) { - retval = - mtd->read_ecc(mtd, addr, dev->nBytesPerChunk, - &dummy, data, dev->spareBuffer, - NULL); - nandmtd2_buf2pt(dev, &pt, 0); - } else { - if (data) - retval = - mtd->read(mtd, addr, dev->nBytesPerChunk, &dummy, - data); - if (tags) { - retval = - mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, - dev->spareBuffer); - nandmtd2_buf2pt(dev, &pt, 1); - } - } - - if (tags) - yaffs_UnpackTags2(tags, &pt); - - if (retval == 0) - return YAFFS_OK; - else - return YAFFS_FAIL; -} - -int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); - int retval; - T(YAFFS_TRACE_MTD, - (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo)); - - retval = - mtd->block_markbad(mtd, - blockNo * dev->nChunksPerBlock * - dev->nBytesPerChunk); - - if (retval == 0) - return YAFFS_OK; - else - return YAFFS_FAIL; - -} - -int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, - yaffs_BlockState * state, int *sequenceNumber) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); - int retval; - - T(YAFFS_TRACE_MTD, - (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo)); - retval = - mtd->block_isbad(mtd, - blockNo * dev->nChunksPerBlock * - dev->nBytesPerChunk); - - if (retval) { - T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR))); - - *state = YAFFS_BLOCK_STATE_DEAD; - *sequenceNumber = 0; - } else { - yaffs_ExtendedTags t; - nandmtd2_ReadChunkWithTagsFromNAND(dev, - blockNo * - dev->nChunksPerBlock, NULL, - &t); - - if (t.chunkUsed) { - *sequenceNumber = t.sequenceNumber; - *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; - } else { - *sequenceNumber = 0; - *state = YAFFS_BLOCK_STATE_EMPTY; - } - - T(YAFFS_TRACE_MTD, - (TSTR("block is OK seq %d state %d" TENDSTR), *sequenceNumber, - *state)); - } - - if (retval == 0) - return YAFFS_OK; - else - return YAFFS_FAIL; -} -
deleted file mode 100644 --- a/utils/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -#Makefile for mkyaffs -# -# NB this is not yet suitable for putting into the kernel tree. -# YAFFS: Yet another Flash File System. A NAND-flash specific file system. -# -# Copyright (C) 2002 Aleph One Ltd. -# for Toby Churchill Ltd and Brightstar Engineering -# -# Created by Charles Manning <charles@aleph1.co.uk> -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. - -## Change or override KERNELDIR to your kernel - -#KERNELDIR = /usr/src/kernel-headers-2.4.18 - -CFLAGS = -I/usr/include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL -CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations -CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline - -## Change if you are using a cross-compiler -MAKETOOLS = - -CC=$(MAKETOOLS)gcc - -COMMONLINKS = yaffs_ecc.c -COMMONOBJS = $(COMMONLINKS:.c=.o) - -MKYAFFSSOURCES = mkyaffsimage.c -MKYAFFSIMAGEOBJS = $(MKYAFFSSOURCES:.c=.o) - -MKYAFFS2SOURCES = mkyaffs2image.c -MKYAFFS2LINKS = yaffs_packedtags2.c yaffs_tagsvalidity.c -MKYAFFS2IMAGEOBJS = $(MKYAFFS2SOURCES:.c=.o) $(MKYAFFS2LINKS:.c=.o) - -all: mkyaffsimage mkyaffs2image - -$(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS): - ln -s ../$@ $@ - -$(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) : %.o: %.c - $(CC) -c $(CFLAGS) $< -o $@ - -mkyaffsimage: $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) - $(CC) -o $@ $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) - -mkyaffs2image: $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS) - $(CC) -o $@ $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS) - - -clean: - rm -f $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) $(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS) mkyaffsimage mkyaffs2image core
deleted file mode 100644 --- a/utils/mkyaffs2image.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * 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> - * Nick Bane modifications flagged NCB - * Endian handling patches by James Ng. - * mkyaffs2image hacks by NCB - * - * 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. - */ - -/* - * makeyaffs2image.c - * - * Makes a YAFFS2 file system image that can be used to load up a file system. - * Uses default Linux MTD layout - change if you need something different. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <dirent.h> -#include <string.h> -#include <unistd.h> -#include "yaffs_ecc.h" -#include "yaffs_guts.h" - -#include "yaffs_tagsvalidity.h" -#include "yaffs_packedtags2.h" - -unsigned yaffs_traceMask=0; - -#define MAX_OBJECTS 10000 - -#define chunkSize 2048 -#define spareSize 64 - -const char * mkyaffsimage_c_version = "$Id$"; - - -typedef struct -{ - dev_t dev; - ino_t ino; - int obj; -} objItem; - - -static objItem obj_list[MAX_OBJECTS]; -static int n_obj = 0; -static int obj_id = YAFFS_NOBJECT_BUCKETS + 1; - -static int nObjects, nDirectories, nPages; - -static int outFile; - -static int error; - -static int convert_endian = 0; - -static int obj_compare(const void *a, const void * b) -{ - objItem *oa, *ob; - - oa = (objItem *)a; - ob = (objItem *)b; - - if(oa->dev < ob->dev) return -1; - if(oa->dev > ob->dev) return 1; - if(oa->ino < ob->ino) return -1; - if(oa->ino > ob->ino) return 1; - - return 0; -} - - -static void add_obj_to_list(dev_t dev, ino_t ino, int obj) -{ - if(n_obj < MAX_OBJECTS) - { - obj_list[n_obj].dev = dev; - obj_list[n_obj].ino = ino; - obj_list[n_obj].obj = obj; - n_obj++; - qsort(obj_list,n_obj,sizeof(objItem),obj_compare); - - } - else - { - // oops! not enough space in the object array - fprintf(stderr,"Not enough space in object array\n"); - exit(2); - } -} - - -static int find_obj_in_list(dev_t dev, ino_t ino) -{ - objItem *i = NULL; - objItem test; - - test.dev = dev; - test.ino = ino; - - if(n_obj > 0) - { - i = bsearch(&test,obj_list,n_obj,sizeof(objItem),obj_compare); - } - - if(i) - { - return i->obj; - } - return -1; -} - -/* This little function converts a little endian tag to a big endian tag. - * NOTE: The tag is not usable after this other than calculating the CRC - * with. - */ -static void little_to_big_endian(yaffs_Tags *tagsPtr) -{ -#if 0 // FIXME NCB - yaffs_TagsUnion * tags = (yaffs_TagsUnion* )tagsPtr; // Work in bytes. - yaffs_TagsUnion temp; - - memset(&temp, 0, sizeof(temp)); - // Ick, I hate magic numbers. - temp.asBytes[0] = ((tags->asBytes[2] & 0x0F) << 4) | ((tags->asBytes[1] & 0xF0) >> 4); - temp.asBytes[1] = ((tags->asBytes[1] & 0x0F) << 4) | ((tags->asBytes[0] & 0xF0) >> 4); - temp.asBytes[2] = ((tags->asBytes[0] & 0x0F) << 4) | ((tags->asBytes[2] & 0x30) >> 2) | ((tags->asBytes[3] & 0xC0) >> 6); - temp.asBytes[3] = ((tags->asBytes[3] & 0x3F) << 2) | ((tags->asBytes[2] & 0xC0) >> 6); - temp.asBytes[4] = ((tags->asBytes[6] & 0x03) << 6) | ((tags->asBytes[5] & 0xFC) >> 2); - temp.asBytes[5] = ((tags->asBytes[5] & 0x03) << 6) | ((tags->asBytes[4] & 0xFC) >> 2); - temp.asBytes[6] = ((tags->asBytes[4] & 0x03) << 6) | (tags->asBytes[7] & 0x3F); - temp.asBytes[7] = (tags->asBytes[6] & 0xFC) | ((tags->asBytes[7] & 0xC0) >> 6); - - // Now copy it back. - tags->asBytes[0] = temp.asBytes[0]; - tags->asBytes[1] = temp.asBytes[1]; - tags->asBytes[2] = temp.asBytes[2]; - tags->asBytes[3] = temp.asBytes[3]; - tags->asBytes[4] = temp.asBytes[4]; - tags->asBytes[5] = temp.asBytes[5]; - tags->asBytes[6] = temp.asBytes[6]; - tags->asBytes[7] = temp.asBytes[7]; -#endif -} - -static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes) -{ - yaffs_ExtendedTags t; - yaffs_PackedTags2 pt; - - error = write(outFile,data,chunkSize); - if(error < 0) return error; - - yaffs_InitialiseTags(&t); - - t.chunkId = chunkId; -// t.serialNumber = 0; - t.serialNumber = 1; // **CHECK** - t.byteCount = nBytes; - t.objectId = objId; - - t.sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; - -// added NCB **CHECK** - t.chunkUsed = 1; - - if (convert_endian) - { - little_to_big_endian(&t); - } - - nPages++; - - yaffs_PackTags2(&pt,&t); - -// return write(outFile,&pt,sizeof(yaffs_PackedTags2)); - return write(outFile,&pt,spareSize); - -} - -#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \ - (((x) & 0x0000FF00) << 8 ) | \ - (((x) & 0x00FF0000) >> 8 ) | \ - (((x) & 0xFF000000) >> 24)) - -#define SWAP16(x) ((((x) & 0x00FF) << 8) | \ - (((x) & 0xFF00) >> 8)) - -// This one is easier, since the types are more standard. No funky shifts here. -static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh) -{ - oh->type = SWAP32(oh->type); // GCC makes enums 32 bits. - oh->parentObjectId = SWAP32(oh->parentObjectId); // int - oh->sum__NoLongerUsed = SWAP16(oh->sum__NoLongerUsed); // __u16 - Not used, but done for completeness. - // name = skip. Char array. Not swapped. - oh->yst_mode = SWAP32(oh->yst_mode); -#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case. - // In fact, WinCE would be *THE* place where this would be an issue! - oh->notForWinCE[0] = SWAP32(oh->notForWinCE[0]); - oh->notForWinCE[1] = SWAP32(oh->notForWinCE[1]); - oh->notForWinCE[2] = SWAP32(oh->notForWinCE[2]); - oh->notForWinCE[3] = SWAP32(oh->notForWinCE[3]); - oh->notForWinCE[4] = SWAP32(oh->notForWinCE[4]); -#else - // Regular POSIX. - oh->yst_uid = SWAP32(oh->yst_uid); - oh->yst_gid = SWAP32(oh->yst_gid); - oh->yst_atime = SWAP32(oh->yst_atime); - oh->yst_mtime = SWAP32(oh->yst_mtime); - oh->yst_ctime = SWAP32(oh->yst_ctime); -#endif - - oh->fileSize = SWAP32(oh->fileSize); // Aiee. An int... signed, at that! - oh->equivalentObjectId = SWAP32(oh->equivalentObjectId); - // alias - char array. - oh->yst_rdev = SWAP32(oh->yst_rdev); - -#ifdef CONFIG_YAFFS_WINCE - oh->win_ctime[0] = SWAP32(oh->win_ctime[0]); - oh->win_ctime[1] = SWAP32(oh->win_ctime[1]); - oh->win_atime[0] = SWAP32(oh->win_atime[0]); - oh->win_atime[1] = SWAP32(oh->win_atime[1]); - oh->win_mtime[0] = SWAP32(oh->win_mtime[0]); - oh->win_mtime[1] = SWAP32(oh->win_mtime[1]); - oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]); - oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]); - oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]); - oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]); - oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]); - oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]); -#else - oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]); - oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]); - oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]); - oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]); - oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]); - oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]); - oh->roomToGrow[6] = SWAP32(oh->roomToGrow[6]); - oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]); - oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]); - oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]); - oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]); - oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]); -#endif -} - -static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias) -{ - __u8 bytes[chunkSize]; - - - yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes; - - memset(bytes,0xff,sizeof(bytes)); - - oh->type = t; - - oh->parentObjectId = parent; - - strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH); - - - if(t != YAFFS_OBJECT_TYPE_HARDLINK) - { - oh->yst_mode = s->st_mode; - oh->yst_uid = s->st_uid; -// NCB 12/9/02 oh->yst_gid = s->yst_uid; - oh->yst_gid = s->st_gid; - oh->yst_atime = s->st_atime; - oh->yst_mtime = s->st_mtime; - oh->yst_ctime = s->st_ctime; - oh->yst_rdev = s->st_rdev; - } - - if(t == YAFFS_OBJECT_TYPE_FILE) - { - oh->fileSize = s->st_size; - } - - if(t == YAFFS_OBJECT_TYPE_HARDLINK) - { - oh->equivalentObjectId = equivalentObj; - } - - if(t == YAFFS_OBJECT_TYPE_SYMLINK) - { - strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH); - } - - if (convert_endian) - { - object_header_little_to_big_endian(oh); - } - - return write_chunk(bytes,objId,0,0xffff); - -} - - -static int process_directory(int parent, const char *path) -{ - - DIR *dir; - struct dirent *entry; - - nDirectories++; - - dir = opendir(path); - - if(dir) - { - while((entry = readdir(dir)) != NULL) - { - - /* Ignore . and .. */ - if(strcmp(entry->d_name,".") && - strcmp(entry->d_name,"..")) - { - char full_name[500]; - struct stat stats; - int equivalentObj; - int newObj; - - sprintf(full_name,"%s/%s",path,entry->d_name); - - lstat(full_name,&stats); - - if(S_ISLNK(stats.st_mode) || - S_ISREG(stats.st_mode) || - S_ISDIR(stats.st_mode) || - S_ISFIFO(stats.st_mode) || - S_ISBLK(stats.st_mode) || - S_ISCHR(stats.st_mode) || - S_ISSOCK(stats.st_mode)) - { - - newObj = obj_id++; - nObjects++; - - printf("Object %d, %s is a ",newObj,full_name); - - /* We're going to create an object for it */ - if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0) - { - /* we need to make a hard link */ - printf("hard link to object %d\n",equivalentObj); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL); - } - else - { - - add_obj_to_list(stats.st_dev,stats.st_ino,newObj); - - if(S_ISLNK(stats.st_mode)) - { - - char symname[500]; - - memset(symname,0, sizeof(symname)); - - readlink(full_name,symname,sizeof(symname) -1); - - printf("symlink to \"%s\"\n",symname); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname); - - } - else if(S_ISREG(stats.st_mode)) - { - printf("file, "); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL); - - if(error >= 0) - { - int h; - __u8 bytes[chunkSize]; - int nBytes; - int chunk = 0; - - h = open(full_name,O_RDONLY); - if(h >= 0) - { - memset(bytes,0xff,sizeof(bytes)); - while((nBytes = read(h,bytes,sizeof(bytes))) > 0) - { - chunk++; - write_chunk(bytes,newObj,chunk,nBytes); - memset(bytes,0xff,sizeof(bytes)); - } - if(nBytes < 0) - error = nBytes; - - printf("%d data chunks written\n",chunk); - } - else - { - perror("Error opening file"); - } - close(h); - - } - - } - else if(S_ISSOCK(stats.st_mode)) - { - printf("socket\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); - } - else if(S_ISFIFO(stats.st_mode)) - { - printf("fifo\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); - } - else if(S_ISCHR(stats.st_mode)) - { - printf("character device\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); - } - else if(S_ISBLK(stats.st_mode)) - { - printf("block device\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); - } - else if(S_ISDIR(stats.st_mode)) - { - printf("directory\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL); -// NCB modified 10/9/2001 process_directory(1,full_name); - process_directory(newObj,full_name); - } - } - } - else - { - printf(" we don't handle this type\n"); - } - } - } - } - - return 0; - -} - - -int main(int argc, char *argv[]) -{ - struct stat stats; - - printf("mkyaffs2image: image building tool for YAFFS2 built "__DATE__"\n"); - - if(argc < 3) - { - printf("usage: mkyaffs2image dir image_file [convert]\n"); - printf(" dir the directory tree to be converted\n"); - printf(" image_file the output file to hold the image\n"); - printf(" 'convert' produce a big-endian image from a little-endian machine\n"); - exit(1); - } - - if ((argc == 4) && (!strncmp(argv[3], "convert", strlen("convert")))) - { - convert_endian = 1; - } - - if(stat(argv[1],&stats) < 0) - { - printf("Could not stat %s\n",argv[1]); - exit(1); - } - - if(!S_ISDIR(stats.st_mode)) - { - printf(" %s is not a directory\n",argv[1]); - exit(1); - } - - outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE); - - - if(outFile < 0) - { - printf("Could not open output file %s\n",argv[2]); - exit(1); - } - - printf("Processing directory %s into image file %s\n",argv[1],argv[2]); - error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL); - if(error) - error = process_directory(YAFFS_OBJECTID_ROOT,argv[1]); - - close(outFile); - - if(error < 0) - { - perror("operation incomplete"); - exit(1); - } - else - { - printf("Operation complete.\n" - "%d objects in %d directories\n" - "%d NAND pages\n",nObjects, nDirectories, nPages); - } - - close(outFile); - - exit(0); -} -
deleted file mode 100644 --- a/utils/mkyaffsimage.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - * 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> - * Nick Bane modifications flagged NCB - * Endian handling patches by James Ng - * - * 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. - */ - -/* - * makeyaffsimage.c - * - * Makes a YAFFS file system image that can be used to load up a file system. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <dirent.h> -#include <string.h> -#include <unistd.h> -#include "yaffs_ecc.h" -#include "yaffs_guts.h" - - -#define MAX_OBJECTS 10000 - -const char * mkyaffsimage_c_version = "$Id$"; - - -typedef struct -{ - dev_t dev; - ino_t ino; - int obj; -} objItem; - - -static objItem obj_list[MAX_OBJECTS]; -static int n_obj = 0; -static int obj_id = YAFFS_NOBJECT_BUCKETS + 1; - -static int nObjects, nDirectories, nPages; - -static int outFile; - -static int error; - -static int convert_endian = 0; - -static int obj_compare(const void *a, const void * b) -{ - objItem *oa, *ob; - - oa = (objItem *)a; - ob = (objItem *)b; - - if(oa->dev < ob->dev) return -1; - if(oa->dev > ob->dev) return 1; - if(oa->ino < ob->ino) return -1; - if(oa->ino > ob->ino) return 1; - - return 0; -} - - -static void add_obj_to_list(dev_t dev, ino_t ino, int obj) -{ - if(n_obj < MAX_OBJECTS) - { - obj_list[n_obj].dev = dev; - obj_list[n_obj].ino = ino; - obj_list[n_obj].obj = obj; - n_obj++; - qsort(obj_list,n_obj,sizeof(objItem),obj_compare); - - } - else - { - // oops! not enough space in the object array - fprintf(stderr,"Not enough space in object array\n"); - exit(2); - } -} - - -static int find_obj_in_list(dev_t dev, ino_t ino) -{ - objItem *i = NULL; - objItem test; - - test.dev = dev; - test.ino = ino; - - if(n_obj > 0) - { - i = bsearch(&test,obj_list,n_obj,sizeof(objItem),obj_compare); - } - - if(i) - { - return i->obj; - } - return -1; -} - -// NCB added 10/9/2002 -static __u16 yaffs_CalcNameSum(const char *name) -{ - __u16 sum = 0; - __u16 i = 1; - - __u8 *bname = (__u8 *)name; - - while (*bname) - { - sum += (*bname) * i; - i++; - bname++; - } - return sum; -} - - -static void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) -{ - yaffs_ECCCalculate(data , spare->ecc1); - yaffs_ECCCalculate(&data[256] , spare->ecc2); -} - -static void yaffs_CalcTagsECC(yaffs_Tags *tags) -{ - // Todo don't do anything yet. Need to calculate ecc - unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes; - unsigned i,j; - unsigned ecc = 0; - unsigned bit = 0; - - // Clear ECC fields - if (!convert_endian) - { - tags->ecc = 0; - } - else - { - // Because we're in "munged tag" mode, we have to clear it manually - b[6] &= 0xC0; - b[7] &= 0x03; - } - - for(i = 0; i < 8; i++) - { -// NCB modified 20-9-02 for(j = 1; j &0x7f; j<<=1) - for(j = 1; j &0xff; j<<=1) - { - bit++; - if(b[i] & j) - { - ecc ^= bit; - } - } - } - - // Write out ECC - if (!convert_endian) - { - tags->ecc = ecc; - } - else - { - // We have to munge the ECC again. - b[6] |= ((ecc >> 6) & 0x3F); - b[7] |= ((ecc & 0x3F) << 2); - } -} -static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr) -{ - yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr; - - //yaffs_CalcTagsECC(tagsPtr); - - sparePtr->tagByte0 = tu->asBytes[0]; - sparePtr->tagByte1 = tu->asBytes[1]; - sparePtr->tagByte2 = tu->asBytes[2]; - sparePtr->tagByte3 = tu->asBytes[3]; - sparePtr->tagByte4 = tu->asBytes[4]; - sparePtr->tagByte5 = tu->asBytes[5]; - sparePtr->tagByte6 = tu->asBytes[6]; - sparePtr->tagByte7 = tu->asBytes[7]; -} - -/* This little function converts a little endian tag to a big endian tag. - * NOTE: The tag is not usable after this other than calculating the CRC - * with. - */ -static void little_to_big_endian(yaffs_Tags *tagsPtr) -{ - yaffs_TagsUnion * tags = (yaffs_TagsUnion* )tagsPtr; // Work in bytes. - yaffs_TagsUnion temp; - - memset(&temp, 0, sizeof(temp)); - // Ick, I hate magic numbers. - temp.asBytes[0] = ((tags->asBytes[2] & 0x0F) << 4) | ((tags->asBytes[1] & 0xF0) >> 4); - temp.asBytes[1] = ((tags->asBytes[1] & 0x0F) << 4) | ((tags->asBytes[0] & 0xF0) >> 4); - temp.asBytes[2] = ((tags->asBytes[0] & 0x0F) << 4) | ((tags->asBytes[2] & 0x30) >> 2) | ((tags->asBytes[3] & 0xC0) >> 6); - temp.asBytes[3] = ((tags->asBytes[3] & 0x3F) << 2) | ((tags->asBytes[2] & 0xC0) >> 6); - temp.asBytes[4] = ((tags->asBytes[6] & 0x03) << 6) | ((tags->asBytes[5] & 0xFC) >> 2); - temp.asBytes[5] = ((tags->asBytes[5] & 0x03) << 6) | ((tags->asBytes[4] & 0xFC) >> 2); - temp.asBytes[6] = ((tags->asBytes[4] & 0x03) << 6) | (tags->asBytes[7] & 0x3F); - temp.asBytes[7] = (tags->asBytes[6] & 0xFC) | ((tags->asBytes[7] & 0xC0) >> 6); - - // Now copy it back. - tags->asBytes[0] = temp.asBytes[0]; - tags->asBytes[1] = temp.asBytes[1]; - tags->asBytes[2] = temp.asBytes[2]; - tags->asBytes[3] = temp.asBytes[3]; - tags->asBytes[4] = temp.asBytes[4]; - tags->asBytes[5] = temp.asBytes[5]; - tags->asBytes[6] = temp.asBytes[6]; - tags->asBytes[7] = temp.asBytes[7]; -} - -static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes) -{ - yaffs_Tags t; - yaffs_Spare s; - - error = write(outFile,data,512); - if(error < 0) return error; - - memset(&t,0xff,sizeof (yaffs_Tags)); - memset(&s,0xff,sizeof (yaffs_Spare)); - - t.chunkId = chunkId; - t.serialNumber = 0; - t.byteCountLSB = nBytes; - t.objectId = objId; - - if (convert_endian) - { - little_to_big_endian(&t); - } - - yaffs_CalcTagsECC(&t); - yaffs_LoadTagsIntoSpare(&s,&t); - yaffs_CalcECC(data,&s); - - nPages++; - - return write(outFile,&s,sizeof(yaffs_Spare)); - -} - -#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \ - (((x) & 0x0000FF00) << 8 ) | \ - (((x) & 0x00FF0000) >> 8 ) | \ - (((x) & 0xFF000000) >> 24)) - -#define SWAP16(x) ((((x) & 0x00FF) << 8) | \ - (((x) & 0xFF00) >> 8)) - -// This one is easier, since the types are more standard. No funky shifts here. -static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh) -{ - oh->type = SWAP32(oh->type); // GCC makes enums 32 bits. - oh->parentObjectId = SWAP32(oh->parentObjectId); // int - oh->sum__NoLongerUsed = SWAP16(oh->sum__NoLongerUsed); // __u16 - Not used, but done for completeness. - // name = skip. Char array. Not swapped. - oh->yst_mode = SWAP32(oh->yst_mode); -#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case. - // In fact, WinCE would be *THE* place where this would be an issue! - oh->notForWinCE[0] = SWAP32(oh->notForWinCE[0]); - oh->notForWinCE[1] = SWAP32(oh->notForWinCE[1]); - oh->notForWinCE[2] = SWAP32(oh->notForWinCE[2]); - oh->notForWinCE[3] = SWAP32(oh->notForWinCE[3]); - oh->notForWinCE[4] = SWAP32(oh->notForWinCE[4]); -#else - // Regular POSIX. - oh->yst_uid = SWAP32(oh->yst_uid); - oh->yst_gid = SWAP32(oh->yst_gid); - oh->yst_atime = SWAP32(oh->yst_atime); - oh->yst_mtime = SWAP32(oh->yst_mtime); - oh->yst_ctime = SWAP32(oh->yst_ctime); -#endif - - oh->fileSize = SWAP32(oh->fileSize); // Aiee. An int... signed, at that! - oh->equivalentObjectId = SWAP32(oh->equivalentObjectId); - // alias - char array. - oh->yst_rdev = SWAP32(oh->yst_rdev); - -#ifdef CONFIG_YAFFS_WINCE - oh->win_ctime[0] = SWAP32(oh->win_ctime[0]); - oh->win_ctime[1] = SWAP32(oh->win_ctime[1]); - oh->win_atime[0] = SWAP32(oh->win_atime[0]); - oh->win_atime[1] = SWAP32(oh->win_atime[1]); - oh->win_mtime[0] = SWAP32(oh->win_mtime[0]); - oh->win_mtime[1] = SWAP32(oh->win_mtime[1]); - oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]); - oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]); - oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]); - oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]); - oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]); - oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]); -#else - oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]); - oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]); - oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]); - oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]); - oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]); - oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]); - oh->roomToGrow[6] = SWAP32(oh->roomToGrow[6]); - oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]); - oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]); - oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]); - oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]); - oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]); -#endif -} - -static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias) -{ - __u8 bytes[512]; - - - yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes; - - memset(bytes,0xff,512); - - oh->type = t; - - oh->parentObjectId = parent; - - strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH); - - - if(t != YAFFS_OBJECT_TYPE_HARDLINK) - { - oh->yst_mode = s->st_mode; - oh->yst_uid = s->st_uid; -// NCB 12/9/02 oh->yst_gid = s->yst_uid; - oh->yst_gid = s->st_gid; - oh->yst_atime = s->st_atime; - oh->yst_mtime = s->st_mtime; - oh->yst_ctime = s->st_ctime; - oh->yst_rdev = s->st_rdev; - } - - if(t == YAFFS_OBJECT_TYPE_FILE) - { - oh->fileSize = s->st_size; - } - - if(t == YAFFS_OBJECT_TYPE_HARDLINK) - { - oh->equivalentObjectId = equivalentObj; - } - - if(t == YAFFS_OBJECT_TYPE_SYMLINK) - { - strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH); - } - - if (convert_endian) - { - object_header_little_to_big_endian(oh); - } - - return write_chunk(bytes,objId,0,0xffff); - -} - - -static int process_directory(int parent, const char *path) -{ - - DIR *dir; - struct dirent *entry; - - nDirectories++; - - dir = opendir(path); - - if(dir) - { - while((entry = readdir(dir)) != NULL) - { - - /* Ignore . and .. */ - if(strcmp(entry->d_name,".") && - strcmp(entry->d_name,"..")) - { - char full_name[500]; - struct stat stats; - int equivalentObj; - int newObj; - - sprintf(full_name,"%s/%s",path,entry->d_name); - - lstat(full_name,&stats); - - if(S_ISLNK(stats.st_mode) || - S_ISREG(stats.st_mode) || - S_ISDIR(stats.st_mode) || - S_ISFIFO(stats.st_mode) || - S_ISBLK(stats.st_mode) || - S_ISCHR(stats.st_mode) || - S_ISSOCK(stats.st_mode)) - { - - newObj = obj_id++; - nObjects++; - - printf("Object %d, %s is a ",newObj,full_name); - - /* We're going to create an object for it */ - if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0) - { - /* we need to make a hard link */ - printf("hard link to object %d\n",equivalentObj); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL); - } - else - { - - add_obj_to_list(stats.st_dev,stats.st_ino,newObj); - - if(S_ISLNK(stats.st_mode)) - { - - char symname[500]; - - memset(symname,0, sizeof(symname)); - - readlink(full_name,symname,sizeof(symname) -1); - - printf("symlink to \"%s\"\n",symname); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname); - - } - else if(S_ISREG(stats.st_mode)) - { - printf("file, "); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL); - - if(error >= 0) - { - int h; - __u8 bytes[512]; - int nBytes; - int chunk = 0; - - h = open(full_name,O_RDONLY); - if(h >= 0) - { - memset(bytes,0xff,512); - while((nBytes = read(h,bytes,512)) > 0) - { - chunk++; - write_chunk(bytes,newObj,chunk,nBytes); - memset(bytes,0xff,512); - } - if(nBytes < 0) - error = nBytes; - - printf("%d data chunks written\n",chunk); - } - else - { - perror("Error opening file"); - } - close(h); - - } - - } - else if(S_ISSOCK(stats.st_mode)) - { - printf("socket\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); - } - else if(S_ISFIFO(stats.st_mode)) - { - printf("fifo\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); - } - else if(S_ISCHR(stats.st_mode)) - { - printf("character device\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); - } - else if(S_ISBLK(stats.st_mode)) - { - printf("block device\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); - } - else if(S_ISDIR(stats.st_mode)) - { - printf("directory\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL); -// NCB modified 10/9/2001 process_directory(1,full_name); - process_directory(newObj,full_name); - } - } - } - else - { - printf(" we don't handle this type\n"); - } - } - } - } - - return 0; - -} - - -int main(int argc, char *argv[]) -{ - struct stat stats; - - printf("mkyaffsimage: image building tool for YAFFS built "__DATE__"\n"); - - if(argc < 3) - { - printf("usage: mkyaffsimage dir image_file [convert]\n"); - printf(" dir the directory tree to be converted\n"); - printf(" image_file the output file to hold the image\n"); - printf(" 'convert' produce a big-endian image from a little-endian machine\n"); - exit(1); - } - - if ((argc == 4) && (!strncmp(argv[3], "convert", strlen("convert")))) - { - convert_endian = 1; - } - - if(stat(argv[1],&stats) < 0) - { - printf("Could not stat %s\n",argv[1]); - exit(1); - } - - if(!S_ISDIR(stats.st_mode)) - { - printf(" %s is not a directory\n",argv[1]); - exit(1); - } - - outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE); - - - if(outFile < 0) - { - printf("Could not open output file %s\n",argv[2]); - exit(1); - } - - printf("Processing directory %s into image file %s\n",argv[1],argv[2]); - error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL); - if(error) - error = process_directory(YAFFS_OBJECTID_ROOT,argv[1]); - - close(outFile); - - if(error < 0) - { - perror("operation incomplete"); - exit(1); - } - else - { - printf("Operation complete.\n" - "%d objects in %d directories\n" - "%d NAND pages\n",nObjects, nDirectories, nPages); - } - - close(outFile); - - exit(0); -} -
deleted file mode 100644 --- a/yaffs_fs.c +++ /dev/null @@ -1,2735 +0,0 @@ -/* - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. - * - * Copyright (C) 2002-2009 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * Created by Charles Manning <charles@aleph1.co.uk> - * Acknowledgements: - * Luc van OostenRyck for numerous patches. - * Nick Bane for numerous patches. - * Nick Bane for 2.5/2.6 integration. - * Andras Toth for mknod rdev issue. - * Michael Fischer for finding the problem with inode inconsistency. - * Some code bodily lifted from JFFS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * - * This is the file system front-end to YAFFS that hooks it up to - * the VFS. - * - * Special notes: - * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with - * this superblock - * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this - * superblock - * >> inode->u.generic_ip points to the associated yaffs_Object. - */ - -const char *yaffs_fs_c_version = - "$Id$"; -extern const char *yaffs_guts_c_version; - -#include <linux/version.h> -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) -#include <linux/config.h> -#endif -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/fs.h> -#include <linux/proc_fs.h> -#include <linux/smp_lock.h> -#include <linux/pagemap.h> -#include <linux/mtd/mtd.h> -#include <linux/interrupt.h> -#include <linux/string.h> -#include <linux/ctype.h> - -#include "asm/div64.h" - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) - -#include <linux/statfs.h> /* Added NCB 15-8-2003 */ -#include <linux/statfs.h> -#define UnlockPage(p) unlock_page(p) -#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) - -/* FIXME: use sb->s_id instead ? */ -#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf) - -#else - -#include <linux/locks.h> -#define BDEVNAME_SIZE 0 -#define yaffs_devname(sb, buf) kdevname(sb->s_dev) - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)) -/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */ -#define __user -#endif - -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) -#define YPROC_ROOT (&proc_root) -#else -#define YPROC_ROOT NULL -#endif - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) -#define WRITE_SIZE_STR "writesize" -#define WRITE_SIZE(mtd) ((mtd)->writesize) -#else -#define WRITE_SIZE_STR "oobblock" -#define WRITE_SIZE(mtd) ((mtd)->oobblock) -#endif - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)) -#define YAFFS_USE_WRITE_BEGIN_END 1 -#else -#define YAFFS_USE_WRITE_BEGIN_END 0 -#endif - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)) -static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) -{ - uint64_t result = partition_size; - do_div(result, block_size); - return (uint32_t)result; -} -#else -#define YCALCBLOCKS(s, b) ((s)/(b)) -#endif - -#include <linux/uaccess.h> - -#include "yportenv.h" -#include "yaffs_guts.h" - -#include <linux/mtd/mtd.h> -#include "yaffs_mtdif.h" -#include "yaffs_mtdif1.h" -#include "yaffs_mtdif2.h" - -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS; -unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; -unsigned int yaffs_auto_checkpoint = 1; - -/* Module Parameters */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) -module_param(yaffs_traceMask, uint, 0644); -module_param(yaffs_wr_attempts, uint, 0644); -module_param(yaffs_auto_checkpoint, uint, 0644); -#else -MODULE_PARM(yaffs_traceMask, "i"); -MODULE_PARM(yaffs_wr_attempts, "i"); -MODULE_PARM(yaffs_auto_checkpoint, "i"); -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) -/* use iget and read_inode */ -#define Y_IGET(sb, inum) iget((sb), (inum)) -static void yaffs_read_inode(struct inode *inode); - -#else -/* Call local equivalent */ -#define YAFFS_USE_OWN_IGET -#define Y_IGET(sb, inum) yaffs_iget((sb), (inum)) - -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino); -#endif - -/*#define T(x) printk x */ - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) -#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private) -#else -#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip) -#endif - -#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr))) -#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode) - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info) -#else -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp) -#endif - - -#define update_dir_time(dir) do {\ - (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \ - } while(0) - -static void yaffs_put_super(struct super_block *sb); - -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, - loff_t *pos); -static ssize_t yaffs_hold_space(struct file *f); -static void yaffs_release_space(struct file *f); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) -static int yaffs_file_flush(struct file *file, fl_owner_t id); -#else -static int yaffs_file_flush(struct file *file); -#endif - -static int yaffs_sync_object(struct file *file, struct dentry *dentry, - int datasync); - -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, - struct nameidata *n); -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, - struct nameidata *n); -#else -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode); -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry); -#endif -static int yaffs_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *dentry); -static int yaffs_unlink(struct inode *dir, struct dentry *dentry); -static int yaffs_symlink(struct inode *dir, struct dentry *dentry, - const char *symname); -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, - dev_t dev); -#else -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, - int dev); -#endif -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry); -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) -static int yaffs_sync_fs(struct super_block *sb, int wait); -static void yaffs_write_super(struct super_block *sb); -#else -static int yaffs_sync_fs(struct super_block *sb); -static int yaffs_write_super(struct super_block *sb); -#endif - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf); -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf); -#else -static int yaffs_statfs(struct super_block *sb, struct statfs *buf); -#endif - -#ifdef YAFFS_HAS_PUT_INODE -static void yaffs_put_inode(struct inode *inode); -#endif - -static void yaffs_delete_inode(struct inode *); -static void yaffs_clear_inode(struct inode *); - -static int yaffs_readpage(struct file *file, struct page *page); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) -static int yaffs_writepage(struct page *page, struct writeback_control *wbc); -#else -static int yaffs_writepage(struct page *page); -#endif - - -#if (YAFFS_USE_WRITE_BEGIN_END != 0) -static int yaffs_write_begin(struct file *filp, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata); -static int yaffs_write_end(struct file *filp, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *pg, void *fsdadata); -#else -static int yaffs_prepare_write(struct file *f, struct page *pg, - unsigned offset, unsigned to); -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, - unsigned to); - -#endif - -static int yaffs_readlink(struct dentry *dentry, char __user *buffer, - int buflen); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); -#else -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); -#endif - -static struct address_space_operations yaffs_file_address_operations = { - .readpage = yaffs_readpage, - .writepage = yaffs_writepage, -#if (YAFFS_USE_WRITE_BEGIN_END > 0) - .write_begin = yaffs_write_begin, - .write_end = yaffs_write_end, -#else - .prepare_write = yaffs_prepare_write, - .commit_write = yaffs_commit_write, -#endif -}; - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) -static const struct file_operations yaffs_file_operations = { - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, - .mmap = generic_file_mmap, - .flush = yaffs_file_flush, - .fsync = yaffs_sync_object, - .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, - .llseek = generic_file_llseek, -}; - -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) - -static const struct file_operations yaffs_file_operations = { - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, - .mmap = generic_file_mmap, - .flush = yaffs_file_flush, - .fsync = yaffs_sync_object, - .sendfile = generic_file_sendfile, -}; - -#else - -static const struct file_operations yaffs_file_operations = { - .read = generic_file_read, - .write = generic_file_write, - .mmap = generic_file_mmap, - .flush = yaffs_file_flush, - .fsync = yaffs_sync_object, -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) - .sendfile = generic_file_sendfile, -#endif -}; -#endif - -static const struct inode_operations yaffs_file_inode_operations = { - .setattr = yaffs_setattr, -}; - -static const struct inode_operations yaffs_symlink_inode_operations = { - .readlink = yaffs_readlink, - .follow_link = yaffs_follow_link, - .setattr = yaffs_setattr, -}; - -static const struct inode_operations yaffs_dir_inode_operations = { - .create = yaffs_create, - .lookup = yaffs_lookup, - .link = yaffs_link, - .unlink = yaffs_unlink, - .symlink = yaffs_symlink, - .mkdir = yaffs_mkdir, - .rmdir = yaffs_unlink, - .mknod = yaffs_mknod, - .rename = yaffs_rename, - .setattr = yaffs_setattr, -}; - -static const struct file_operations yaffs_dir_operations = { - .read = generic_read_dir, - .readdir = yaffs_readdir, - .fsync = yaffs_sync_object, -}; - -static const struct super_operations yaffs_super_ops = { - .statfs = yaffs_statfs, - -#ifndef YAFFS_USE_OWN_IGET - .read_inode = yaffs_read_inode, -#endif -#ifdef YAFFS_HAS_PUT_INODE - .put_inode = yaffs_put_inode, -#endif - .put_super = yaffs_put_super, - .delete_inode = yaffs_delete_inode, - .clear_inode = yaffs_clear_inode, - .sync_fs = yaffs_sync_fs, - .write_super = yaffs_write_super, -}; - -/* YAFFS uses two locks per yaffs_Device. - * dirLock: r/w lock Must be held when accessing directory structure. - * grossLock: Lock when accessing yaffs internals. - * - * Locking rules: - * If you're going to take dirLock then you must take if before - * taking grossLock. - * ie. Don't call yaffs_DirLockxxx() while holding grossLock. - * - * Todo: - * Investigate changing to mutexes etc and improve debugging. - */ -static void yaffs_DirLockInitialise(yaffs_Device *dev) -{ - init_rwsem(&dev->dirLock); -} - -static void yaffs_DirLockRead(yaffs_Device *dev) -{ - T(YAFFS_TRACE_OS, ("yaffs locking dir read %p\n", current)); - down_read(&dev->dirLock); - T(YAFFS_TRACE_OS, ("yaffs locked dir read %p\n", current)); -} - -static void yaffs_DirUnlockRead(yaffs_Device *dev) -{ - T(YAFFS_TRACE_OS, ("yaffs unlocking dir read %p\n", current)); - up_read(&dev->dirLock); -} - -static void yaffs_DirLockWrite(yaffs_Device *dev) -{ - T(YAFFS_TRACE_OS, ("yaffs locking dir write %p\n", current)); - down_write(&dev->dirLock); - T(YAFFS_TRACE_OS, ("yaffs locked dir write %p\n", current)); -} - -static void yaffs_DirUnlockWrite(yaffs_Device *dev) -{ - T(YAFFS_TRACE_OS, ("yaffs unlocking dir write %p\n", current)); - up_write(&dev->dirLock); -} - -static void yaffs_GrossLockInitialise(yaffs_Device *dev) -{ - init_MUTEX(&dev->grossLock); -} - -static void yaffs_GrossLock(yaffs_Device *dev) -{ - T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current)); - down(&dev->grossLock); - T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current)); -} - -static void yaffs_GrossUnlock(yaffs_Device *dev) -{ - T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current)); - up(&dev->grossLock); -} - - -static int yaffs_readlink(struct dentry *dentry, char __user *buffer, - int buflen) -{ - unsigned char *alias; - int ret; - - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; - - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - - if (!alias) - return -ENOMEM; - - ret = vfs_readlink(dentry, buffer, buflen, alias); - kfree(alias); - return ret; -} - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) -#else -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) -#endif -{ - unsigned char *alias; - int ret; - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; - - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - - if (!alias) { - ret = -ENOMEM; - goto out; - } - - ret = vfs_follow_link(nd, alias); - kfree(alias); -out: -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) - return ERR_PTR(ret); -#else - return ret; -#endif -} - -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, - yaffs_Object *obj); - -/* - * Lookup is used to find objects in the fs - */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) - -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, - struct nameidata *n) -#else -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) -#endif -{ - yaffs_Object *obj; - struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */ - - yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev; - - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - T(YAFFS_TRACE_OS, - ("yaffs_lookup for %d:%s\n", - yaffs_InodeToObject(dir)->objectId, dentry->d_name.name)); - - obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir), - dentry->d_name.name); - - obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */ - - /* Can't hold gross lock when calling yaffs_get_inode() */ - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - - if (obj) { - T(YAFFS_TRACE_OS, - ("yaffs_lookup found %d\n", obj->objectId)); - - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); - - if (inode) { - T(YAFFS_TRACE_OS, - ("yaffs_loookup dentry \n")); -/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to - * d_add even if NULL inode */ -#if 0 - /*dget(dentry); // try to solve directory bug */ - d_add(dentry, inode); - - /* return dentry; */ - return NULL; -#endif - } - - } else { - T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n")); - - } - -/* added NCB for 2.5/6 compatability - forces add even if inode is - * NULL which creates dentry hash */ - d_add(dentry, inode); - - return NULL; -} - - -#ifdef YAFFS_HAS_PUT_INODE - -/* For now put inode is just for debugging - * Put inode is called when the inode **structure** is put. - */ -static void yaffs_put_inode(struct inode *inode) -{ - T(YAFFS_TRACE_OS, - ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino, - atomic_read(&inode->i_count))); - -} -#endif - -/* clear is called to tell the fs to release any per-inode data it holds */ -static void yaffs_clear_inode(struct inode *inode) -{ - yaffs_Object *obj; - yaffs_Device *dev; - - obj = yaffs_InodeToObject(inode); - - T(YAFFS_TRACE_OS, - ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino, - atomic_read(&inode->i_count), - obj ? "object exists" : "null object")); - - if (obj) { - dev = obj->myDev; - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - /* Clear the association between the inode and - * the yaffs_Object. - */ - obj->myInode = NULL; - yaffs_InodeToObjectLV(inode) = NULL; - - /* If the object freeing was deferred, then the real - * free happens now. - * This should fix the inode inconsistency problem. - */ - - yaffs_HandleDeferedFree(obj); - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - } - -} - -/* delete is called when the link count is zero and the inode - * is put (ie. nobody wants to know about it anymore, time to - * delete the file). - * NB Must call clear_inode() - */ -static void yaffs_delete_inode(struct inode *inode) -{ - yaffs_Object *obj = yaffs_InodeToObject(inode); - yaffs_Device *dev; - - T(YAFFS_TRACE_OS, - ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino, - atomic_read(&inode->i_count), - obj ? "object exists" : "null object")); - - if (obj) { - dev = obj->myDev; - yaffs_DirLockWrite(dev); - yaffs_GrossLock(dev); - yaffs_DeleteObject(obj); - yaffs_GrossUnlock(dev); - yaffs_DirUnlockWrite(dev); - } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) - truncate_inode_pages(&inode->i_data, 0); -#endif - clear_inode(inode); -} - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) -static int yaffs_file_flush(struct file *file, fl_owner_t id) -#else -static int yaffs_file_flush(struct file *file) -#endif -{ - yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry); - - yaffs_Device *dev = obj->myDev; - - T(YAFFS_TRACE_OS, - ("yaffs_file_flush object %d (%s)\n", obj->objectId, - obj->dirty ? "dirty" : "clean")); - - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - yaffs_FlushFile(obj, 1,0); - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - - return 0; -} - -static int yaffs_readpage_nolock(struct file *f, struct page *pg) -{ - /* Lifted from jffs2 */ - - yaffs_Object *obj; - unsigned char *pg_buf; - int ret; - - yaffs_Device *dev; - - T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n", - (unsigned)(pg->index << PAGE_CACHE_SHIFT), - (unsigned)PAGE_CACHE_SIZE)); - - obj = yaffs_DentryToObject(f->f_dentry); - - dev = obj->myDev; - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) - BUG_ON(!PageLocked(pg)); -#else - if (!PageLocked(pg)) - PAGE_BUG(pg); -#endif - - pg_buf = kmap(pg); - /* FIXME: Can kmap fail? */ - - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - ret = yaffs_ReadDataFromFile(obj, pg_buf, - pg->index << PAGE_CACHE_SHIFT, - PAGE_CACHE_SIZE); - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - - if (ret >= 0) - ret = 0; - - if (ret) { - ClearPageUptodate(pg); - SetPageError(pg); - } else { - SetPageUptodate(pg); - ClearPageError(pg); - } - - flush_dcache_page(pg); - kunmap(pg); - - T(YAFFS_TRACE_OS, ("yaffs_readpage done\n")); - return ret; -} - -static int yaffs_readpage_unlock(struct file *f, struct page *pg) -{ - int ret = yaffs_readpage_nolock(f, pg); - UnlockPage(pg); - return ret; -} - -static int yaffs_readpage(struct file *f, struct page *pg) -{ - return yaffs_readpage_unlock(f, pg); -} - -/* writepage inspired by/stolen from smbfs */ - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) -static int yaffs_writepage(struct page *page, struct writeback_control *wbc) -#else -static int yaffs_writepage(struct page *page) -#endif -{ - struct address_space *mapping = page->mapping; - loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT; - struct inode *inode; - unsigned long end_index; - char *buffer; - yaffs_Object *obj; - int nWritten = 0; - unsigned nBytes; - - if (!mapping) - BUG(); - inode = mapping->host; - if (!inode) - BUG(); - - if (offset > inode->i_size) { - T(YAFFS_TRACE_OS, - ("yaffs_writepage at %08x, inode size = %08x!!!\n", - (unsigned)(page->index << PAGE_CACHE_SHIFT), - (unsigned)inode->i_size)); - T(YAFFS_TRACE_OS, - (" -> don't care!!\n")); - unlock_page(page); - return 0; - } - - end_index = inode->i_size >> PAGE_CACHE_SHIFT; - - /* easy case */ - if (page->index < end_index) - nBytes = PAGE_CACHE_SIZE; - else - nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1); - - get_page(page); - - buffer = kmap(page); - - obj = yaffs_InodeToObject(inode); - yaffs_DirLockRead(obj->myDev); - yaffs_GrossLock(obj->myDev); - - T(YAFFS_TRACE_OS, - ("yaffs_writepage at %08x, size %08x\n", - (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes)); - T(YAFFS_TRACE_OS, - ("writepag0: obj = %05x, ino = %05x\n", - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); - - nWritten = yaffs_WriteDataToFile(obj, buffer, - page->index << PAGE_CACHE_SHIFT, nBytes, 0); - - T(YAFFS_TRACE_OS, - ("writepag1: obj = %05x, ino = %05x\n", - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); - - yaffs_GrossUnlock(obj->myDev); - yaffs_DirUnlockRead(obj->myDev); - - kunmap(page); - SetPageUptodate(page); - UnlockPage(page); - put_page(page); - - return (nWritten == nBytes) ? 0 : -ENOSPC; -} - - -#if (YAFFS_USE_WRITE_BEGIN_END > 0) -static int yaffs_write_begin(struct file *filp, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - struct page *pg = NULL; - pgoff_t index = pos >> PAGE_CACHE_SHIFT; - uint32_t offset = pos & (PAGE_CACHE_SIZE - 1); - uint32_t to = offset + len; - - int ret = 0; - int space_held = 0; - - T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n")); - /* Get a page */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) - pg = grab_cache_page_write_begin(mapping, index, flags); -#else - pg = __grab_cache_page(mapping, index); -#endif - - *pagep = pg; - if (!pg) { - ret = -ENOMEM; - goto out; - } - /* Get fs space */ - space_held = yaffs_hold_space(filp); - - if (!space_held) { - ret = -ENOSPC; - goto out; - } - - /* Update page if required */ - - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) - ret = yaffs_readpage_nolock(filp, pg); - - if (ret) - goto out; - - /* Happy path return */ - T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n")); - - return 0; - -out: - T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret)); - if (space_held) - yaffs_release_space(filp); - if (pg) { - unlock_page(pg); - page_cache_release(pg); - } - return ret; -} - -#else - -static int yaffs_prepare_write(struct file *f, struct page *pg, - unsigned offset, unsigned to) -{ - T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n")); - - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) - return yaffs_readpage_nolock(f, pg); - return 0; -} -#endif - -#if (YAFFS_USE_WRITE_BEGIN_END > 0) -static int yaffs_write_end(struct file *filp, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *pg, void *fsdadata) -{ - int ret = 0; - void *addr, *kva; - uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1); - - kva = kmap(pg); - addr = kva + offset_into_page; - - T(YAFFS_TRACE_OS, - ("yaffs_write_end addr %x pos %x nBytes %d\n", - (unsigned) addr, - (int)pos, copied)); - - ret = yaffs_file_write(filp, addr, copied, &pos); - - if (ret != copied) { - T(YAFFS_TRACE_OS, - ("yaffs_write_end not same size ret %d copied %d\n", - ret, copied)); - SetPageError(pg); - ClearPageUptodate(pg); - } else { - SetPageUptodate(pg); - } - - kunmap(pg); - - yaffs_release_space(filp); - unlock_page(pg); - page_cache_release(pg); - return ret; -} -#else - -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, - unsigned to) -{ - void *addr, *kva; - - loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset; - int nBytes = to - offset; - int nWritten; - - unsigned spos = pos; - unsigned saddr; - - kva = kmap(pg); - addr = kva + offset; - - saddr = (unsigned) addr; - - T(YAFFS_TRACE_OS, - ("yaffs_commit_write addr %x pos %x nBytes %d\n", - saddr, spos, nBytes)); - - nWritten = yaffs_file_write(f, addr, nBytes, &pos); - - if (nWritten != nBytes) { - T(YAFFS_TRACE_OS, - ("yaffs_commit_write not same size nWritten %d nBytes %d\n", - nWritten, nBytes)); - SetPageError(pg); - ClearPageUptodate(pg); - } else { - SetPageUptodate(pg); - } - - kunmap(pg); - - T(YAFFS_TRACE_OS, - ("yaffs_commit_write returning %d\n", - nWritten == nBytes ? 0 : nWritten)); - - return nWritten == nBytes ? 0 : nWritten; -} -#endif - - -static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj) -{ - if (inode && obj) { - - - /* Check mode against the variant type and attempt to repair if broken. */ - __u32 mode = obj->yst_mode; - switch (obj->variantType) { - case YAFFS_OBJECT_TYPE_FILE: - if (!S_ISREG(mode)) { - obj->yst_mode &= ~S_IFMT; - obj->yst_mode |= S_IFREG; - } - - break; - case YAFFS_OBJECT_TYPE_SYMLINK: - if (!S_ISLNK(mode)) { - obj->yst_mode &= ~S_IFMT; - obj->yst_mode |= S_IFLNK; - } - - break; - case YAFFS_OBJECT_TYPE_DIRECTORY: - if (!S_ISDIR(mode)) { - obj->yst_mode &= ~S_IFMT; - obj->yst_mode |= S_IFDIR; - } - - break; - case YAFFS_OBJECT_TYPE_UNKNOWN: - case YAFFS_OBJECT_TYPE_HARDLINK: - case YAFFS_OBJECT_TYPE_SPECIAL: - default: - /* TODO? */ - break; - } - - inode->i_flags |= S_NOATIME; - - inode->i_ino = obj->objectId; - inode->i_mode = obj->yst_mode; - inode->i_uid = obj->yst_uid; - inode->i_gid = obj->yst_gid; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) - inode->i_blksize = inode->i_sb->s_blocksize; -#endif -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) - - inode->i_rdev = old_decode_dev(obj->yst_rdev); - inode->i_atime.tv_sec = (time_t) (obj->yst_atime); - inode->i_atime.tv_nsec = 0; - inode->i_mtime.tv_sec = (time_t) obj->yst_mtime; - inode->i_mtime.tv_nsec = 0; - inode->i_ctime.tv_sec = (time_t) obj->yst_ctime; - inode->i_ctime.tv_nsec = 0; -#else - inode->i_rdev = obj->yst_rdev; - inode->i_atime = obj->yst_atime; - inode->i_mtime = obj->yst_mtime; - inode->i_ctime = obj->yst_ctime; -#endif - inode->i_size = yaffs_GetObjectFileLength(obj); - inode->i_blocks = (inode->i_size + 511) >> 9; - - inode->i_nlink = yaffs_GetObjectLinkCount(obj); - - T(YAFFS_TRACE_OS, - ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n", - inode->i_mode, inode->i_uid, inode->i_gid, - (int)inode->i_size, atomic_read(&inode->i_count))); - - switch (obj->yst_mode & S_IFMT) { - default: /* fifo, device or socket */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) - init_special_inode(inode, obj->yst_mode, - old_decode_dev(obj->yst_rdev)); -#else - init_special_inode(inode, obj->yst_mode, - (dev_t) (obj->yst_rdev)); -#endif - break; - case S_IFREG: /* file */ - inode->i_op = &yaffs_file_inode_operations; - inode->i_fop = &yaffs_file_operations; - inode->i_mapping->a_ops = - &yaffs_file_address_operations; - break; - case S_IFDIR: /* directory */ - inode->i_op = &yaffs_dir_inode_operations; - inode->i_fop = &yaffs_dir_operations; - break; - case S_IFLNK: /* symlink */ - inode->i_op = &yaffs_symlink_inode_operations; - break; - } - - yaffs_InodeToObjectLV(inode) = obj; - - obj->myInode = inode; - - } else { - T(YAFFS_TRACE_OS, - ("yaffs_FileInode invalid parameters\n")); - } - -} - -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, - yaffs_Object *obj) -{ - struct inode *inode; - - if (!sb) { - T(YAFFS_TRACE_OS, - ("yaffs_get_inode for NULL super_block!!\n")); - return NULL; - - } - - if (!obj) { - T(YAFFS_TRACE_OS, - ("yaffs_get_inode for NULL object!!\n")); - return NULL; - - } - - T(YAFFS_TRACE_OS, - ("yaffs_get_inode for object %d\n", obj->objectId)); - - inode = Y_IGET(sb, obj->objectId); - if (IS_ERR(inode)) - return NULL; - - /* NB Side effect: iget calls back to yaffs_read_inode(). */ - /* iget also increments the inode's i_count */ - /* NB You can't be holding grossLock or deadlock will happen! */ - - return inode; -} - -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, - loff_t *pos) -{ - yaffs_Object *obj; - int nWritten, ipos; - struct inode *inode; - yaffs_Device *dev; - - obj = yaffs_DentryToObject(f->f_dentry); - - dev = obj->myDev; - - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - inode = f->f_dentry->d_inode; - - if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) - ipos = inode->i_size; - else - ipos = *pos; - - if (!obj) - T(YAFFS_TRACE_OS, - ("yaffs_file_write: hey obj is null!\n")); - else - T(YAFFS_TRACE_OS, - ("yaffs_file_write about to write writing %zu bytes" - "to object %d at %d\n", - n, obj->objectId, ipos)); - - nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0); - - T(YAFFS_TRACE_OS, - ("yaffs_file_write writing %zu bytes, %d written at %d\n", - n, nWritten, ipos)); - - if (nWritten > 0) { - ipos += nWritten; - *pos = ipos; - if (ipos > inode->i_size) { - inode->i_size = ipos; - inode->i_blocks = (ipos + 511) >> 9; - - T(YAFFS_TRACE_OS, - ("yaffs_file_write size updated to %d bytes, " - "%d blocks\n", - ipos, (int)(inode->i_blocks))); - } - - } - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - - return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten; -} - -/* Space holding and freeing is done to ensure we have space available for write_begin/end */ -/* For now we just assume few parallel writes and check against a small number. */ -/* Todo: need to do this with a counter to handle parallel reads better */ - -static ssize_t yaffs_hold_space(struct file *f) -{ - yaffs_Object *obj; - yaffs_Device *dev; - - int nFreeChunks; - - - obj = yaffs_DentryToObject(f->f_dentry); - - dev = obj->myDev; - - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - nFreeChunks = yaffs_GetNumberOfFreeChunks(dev); - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - - return (nFreeChunks > 20) ? 1 : 0; -} - -static void yaffs_release_space(struct file *f) -{ -} - -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) -{ - yaffs_Object *obj; - yaffs_Device *dev; - struct inode *inode = f->f_dentry->d_inode; - unsigned long offset, curoffs; - struct ylist_head *i; - yaffs_Object *l; - - char name[YAFFS_MAX_NAME_LENGTH + 1]; - - obj = yaffs_DentryToObject(f->f_dentry); - dev = obj->myDev; - - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - offset = f->f_pos; - - T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset)); - - if (offset == 0) { - T(YAFFS_TRACE_OS, - ("yaffs_readdir: entry . ino %d \n", - (int)inode->i_ino)); - - yaffs_GrossUnlock(dev); - - if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) - goto out; - - yaffs_GrossLock(dev); - - offset++; - f->f_pos++; - } - if (offset == 1) { - T(YAFFS_TRACE_OS, - ("yaffs_readdir: entry .. ino %d \n", - (int)f->f_dentry->d_parent->d_inode->i_ino)); - - yaffs_GrossUnlock(dev); - - if (filldir(dirent, "..", 2, offset, - f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) - goto out; - - yaffs_GrossLock(dev); - - offset++; - f->f_pos++; - } - - curoffs = 1; - - /* If the directory has changed since the open or last call to - readdir, rewind to after the 2 canned entries. */ - - if (f->f_version != inode->i_version) { - offset = 2; - f->f_pos = offset; - f->f_version = inode->i_version; - } - - ylist_for_each(i, &obj->variant.directoryVariant.children) { - curoffs++; - if (curoffs >= offset) { - l = ylist_entry(i, yaffs_Object, siblings); - - yaffs_GetObjectName(l, name, - YAFFS_MAX_NAME_LENGTH + 1); - T(YAFFS_TRACE_OS, - ("yaffs_readdir: %s inode %d\n", name, - yaffs_GetObjectInode(l))); - - yaffs_GrossUnlock(dev); - - if (filldir(dirent, - name, - strlen(name), - offset, - yaffs_GetObjectInode(l), - yaffs_GetObjectType(l)) < 0) - goto out; - - yaffs_GrossLock(dev); - - offset++; - f->f_pos++; - } - } - - yaffs_GrossUnlock(dev); -out: - yaffs_DirUnlockRead(dev); - - return 0; -} - -/* - * File creation. Allocate an inode, and we're done.. - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) -#define YCRED(x) x -#else -#define YCRED(x) (x->cred) -#endif - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, - dev_t rdev) -#else -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, - int rdev) -#endif -{ - struct inode *inode; - - yaffs_Object *obj = NULL; - yaffs_Device *dev; - - yaffs_Object *parent = yaffs_InodeToObject(dir); - - int error = -ENOSPC; - uid_t uid = YCRED(current)->fsuid; - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; - - if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) - mode |= S_ISGID; - - if (parent) { - T(YAFFS_TRACE_OS, - ("yaffs_mknod: parent object %d type %d\n", - parent->objectId, parent->variantType)); - } else { - T(YAFFS_TRACE_OS, - ("yaffs_mknod: could not get parent object\n")); - return -EPERM; - } - - T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, " - "mode %x dev %x\n", - dentry->d_name.name, mode, rdev)); - - dev = parent->myDev; - - yaffs_DirLockWrite(dev); - yaffs_GrossLock(dev); - - switch (mode & S_IFMT) { - default: - /* Special (socket, fifo, device...) */ - T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n")); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid, - gid, old_encode_dev(rdev)); -#else - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid, - gid, rdev); -#endif - break; - case S_IFREG: /* file */ - T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n")); - obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid, - gid); - break; - case S_IFDIR: /* directory */ - T(YAFFS_TRACE_OS, - ("yaffs_mknod: making directory\n")); - obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode, - uid, gid); - break; - case S_IFLNK: /* symlink */ - T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n")); - obj = NULL; /* Do we ever get here? */ - break; - } - - /* Can not call yaffs_get_inode() with gross lock held */ - yaffs_GrossUnlock(dev); - yaffs_DirUnlockWrite(dev); - - if (obj) { - inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); - d_instantiate(dentry, inode); - update_dir_time(dir); - T(YAFFS_TRACE_OS, - ("yaffs_mknod created object %d count = %d\n", - obj->objectId, atomic_read(&inode->i_count))); - error = 0; - } else { - T(YAFFS_TRACE_OS, - ("yaffs_mknod failed making object\n")); - error = -ENOMEM; - } - - return error; -} - -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) -{ - int retVal; - T(YAFFS_TRACE_OS, ("yaffs_mkdir\n")); - retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); - return retVal; -} - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, - struct nameidata *n) -#else -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode) -#endif -{ - T(YAFFS_TRACE_OS, ("yaffs_create\n")); - return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); -} - -static int yaffs_unlink(struct inode *dir, struct dentry *dentry) -{ - int retVal; - - yaffs_Device *dev; - - T(YAFFS_TRACE_OS, - ("yaffs_unlink %d:%s\n", (int)(dir->i_ino), - dentry->d_name.name)); - - dev = yaffs_InodeToObject(dir)->myDev; - - yaffs_DirLockWrite(dev); - yaffs_GrossLock(dev); - - retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name); - - if (retVal == YAFFS_OK) { - dentry->d_inode->i_nlink--; - dir->i_version++; - } - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockWrite(dev); - - if( retVal == YAFFS_OK){ - mark_inode_dirty(dentry->d_inode); - update_dir_time(dir); - return 0; - } - - return -ENOTEMPTY; -} - -/* - * Create a link... - */ -static int yaffs_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *dentry) -{ - struct inode *inode = old_dentry->d_inode; - yaffs_Object *obj = NULL; - yaffs_Object *link = NULL; - yaffs_Device *dev; - - T(YAFFS_TRACE_OS, ("yaffs_link\n")); - - obj = yaffs_InodeToObject(inode); - dev = obj->myDev; - - yaffs_DirLockWrite(dev); - yaffs_GrossLock(dev); - - if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ - link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name, - obj); - - if (link) { - old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj); - d_instantiate(dentry, old_dentry->d_inode); - atomic_inc(&old_dentry->d_inode->i_count); - T(YAFFS_TRACE_OS, - ("yaffs_link link count %d i_count %d\n", - old_dentry->d_inode->i_nlink, - atomic_read(&old_dentry->d_inode->i_count))); - } - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockWrite(dev); - - if (link){ - update_dir_time(dir); - return 0; - } - - return -EPERM; -} - -static int yaffs_symlink(struct inode *dir, struct dentry *dentry, - const char *symname) -{ - yaffs_Object *obj; - yaffs_Device *dev; - uid_t uid = YCRED(current)->fsuid; - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; - - T(YAFFS_TRACE_OS, ("yaffs_symlink\n")); - - dev = yaffs_InodeToObject(dir)->myDev; - yaffs_DirLockWrite(dev); - yaffs_GrossLock(dev); - obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name, - S_IFLNK | S_IRWXUGO, uid, gid, symname); - yaffs_GrossUnlock(dev); - yaffs_DirUnlockWrite(dev); - - if (obj) { - struct inode *inode; - - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); - d_instantiate(dentry, inode); - update_dir_time(dir); - T(YAFFS_TRACE_OS, ("symlink created OK\n")); - return 0; - } else { - T(YAFFS_TRACE_OS, ("symlink not created\n")); - } - - return -ENOMEM; -} - -static int yaffs_sync_object(struct file *file, struct dentry *dentry, - int datasync) -{ - - yaffs_Object *obj; - yaffs_Device *dev; - - obj = yaffs_DentryToObject(dentry); - - dev = obj->myDev; - - T(YAFFS_TRACE_OS, ("yaffs_sync_object\n")); - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - yaffs_FlushFile(obj, 1, datasync); - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - return 0; -} - -/* - * The VFS layer already does all the dentry stuff for rename. - * - * NB: POSIX says you can rename an object over an old object of the same name - */ -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) -{ - yaffs_Device *dev; - int retVal = YAFFS_FAIL; - yaffs_Object *target; - - T(YAFFS_TRACE_OS, ("yaffs_rename\n")); - dev = yaffs_InodeToObject(old_dir)->myDev; - - yaffs_DirLockWrite(dev); - yaffs_GrossLock(dev); - - /* Check if the target is an existing directory that is not empty. */ - target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir), - new_dentry->d_name.name); - - - - if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && - !ylist_empty(&target->variant.directoryVariant.children)) { - - T(YAFFS_TRACE_OS, ("target is non-empty dir\n")); - - retVal = YAFFS_FAIL; - } else { - /* Now does unlinking internally using shadowing mechanism */ - T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n")); - - retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir), - old_dentry->d_name.name, - yaffs_InodeToObject(new_dir), - new_dentry->d_name.name); - } - yaffs_GrossUnlock(dev); - yaffs_DirUnlockWrite(dev); - - if (retVal == YAFFS_OK) { - if (target) { - new_dentry->d_inode->i_nlink--; - mark_inode_dirty(new_dentry->d_inode); - } - - update_dir_time(old_dir); - if(old_dir != new_dir) - update_dir_time(new_dir); - return 0; - } else { - return -ENOTEMPTY; - } -} - -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) -{ - struct inode *inode = dentry->d_inode; - int error; - yaffs_Device *dev; - - T(YAFFS_TRACE_OS, - ("yaffs_setattr of object %d\n", - yaffs_InodeToObject(inode)->objectId)); - - error = inode_change_ok(inode, attr); - if (error == 0) { - dev = yaffs_InodeToObject(inode)->myDev; - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) == - YAFFS_OK) { - error = 0; - } else { - error = -EPERM; - } - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - if (!error) - error = inode_setattr(inode, attr); - } - return error; -} - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) -{ - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; - struct super_block *sb = dentry->d_sb; -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf) -{ - yaffs_Device *dev = yaffs_SuperToDevice(sb); -#else -static int yaffs_statfs(struct super_block *sb, struct statfs *buf) -{ - yaffs_Device *dev = yaffs_SuperToDevice(sb); -#endif - - T(YAFFS_TRACE_OS, ("yaffs_statfs\n")); - - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - buf->f_type = YAFFS_MAGIC; - buf->f_bsize = sb->s_blocksize; - buf->f_namelen = 255; - - if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) { - /* Do this if chunk size is not a power of 2 */ - - uint64_t bytesInDev; - uint64_t bytesFree; - - bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) * - ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk)); - - do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */ - buf->f_blocks = bytesInDev; - - bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) * - ((uint64_t)(dev->nDataBytesPerChunk)); - - do_div(bytesFree, sb->s_blocksize); - - buf->f_bfree = bytesFree; - - } else if (sb->s_blocksize > dev->nDataBytesPerChunk) { - - buf->f_blocks = - (dev->endBlock - dev->startBlock + 1) * - dev->nChunksPerBlock / - (sb->s_blocksize / dev->nDataBytesPerChunk); - buf->f_bfree = - yaffs_GetNumberOfFreeChunks(dev) / - (sb->s_blocksize / dev->nDataBytesPerChunk); - } else { - buf->f_blocks = - (dev->endBlock - dev->startBlock + 1) * - dev->nChunksPerBlock * - (dev->nDataBytesPerChunk / sb->s_blocksize); - - buf->f_bfree = - yaffs_GetNumberOfFreeChunks(dev) * - (dev->nDataBytesPerChunk / sb->s_blocksize); - } - - buf->f_files = 0; - buf->f_ffree = 0; - buf->f_bavail = buf->f_bfree; - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - return 0; -} - - - -static void yaffs_flush_sb_inodes(struct super_block *sb) -{ - struct inode *iptr; - yaffs_Object *obj; - - list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){ - obj = yaffs_InodeToObject(iptr); - if(obj){ - T(YAFFS_TRACE_OS, ("flushing obj %d\n",obj->objectId)); - yaffs_FlushFile(obj,1,0); - } - } -} - -static int yaffs_do_sync_fs(struct super_block *sb) -{ - - yaffs_Device *dev = yaffs_SuperToDevice(sb); - T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n")); - - if (sb->s_dirt) { - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - if (dev) { - yaffs_FlushEntireDeviceCache(dev); - yaffs_flush_sb_inodes(sb); - yaffs_CheckpointSave(dev); - } - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - - sb->s_dirt = 0; - } - return 0; -} - - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) -static void yaffs_write_super(struct super_block *sb) -#else -static int yaffs_write_super(struct super_block *sb) -#endif -{ - - T(YAFFS_TRACE_OS, ("yaffs_write_super\n")); - if (yaffs_auto_checkpoint >= 2) - yaffs_do_sync_fs(sb); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) - return 0; -#endif -} - - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) -static int yaffs_sync_fs(struct super_block *sb, int wait) -#else -static int yaffs_sync_fs(struct super_block *sb) -#endif -{ - T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n")); - - if (yaffs_auto_checkpoint >= 1) - yaffs_do_sync_fs(sb); - - return 0; -} - -#ifdef YAFFS_USE_OWN_IGET - -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) -{ - struct inode *inode; - yaffs_Object *obj; - yaffs_Device *dev = yaffs_SuperToDevice(sb); - - T(YAFFS_TRACE_OS, - ("yaffs_iget for %lu\n", ino)); - - inode = iget_locked(sb, ino); - if (!inode) - return ERR_PTR(-ENOMEM); - if (!(inode->i_state & I_NEW)) - return inode; - - /* NB This is called as a side effect of other functions, but - * we had to release the lock to prevent deadlocks, so - * need to lock again. - */ - - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - obj = yaffs_FindObjectByNumber(dev, inode->i_ino); - - yaffs_FillInodeFromObject(inode, obj); - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); - - unlock_new_inode(inode); - return inode; -} - -#else - -static void yaffs_read_inode(struct inode *inode) -{ - /* NB This is called as a side effect of other functions, but - * we had to release the lock to prevent deadlocks, so - * need to lock again. - */ - - yaffs_Object *obj; - yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb); - - T(YAFFS_TRACE_OS, - ("yaffs_read_inode for %d\n", (int)inode->i_ino)); - - yaffs_DirLockRead(dev); - yaffs_GrossLock(dev); - - obj = yaffs_FindObjectByNumber(dev, inode->i_ino); - - yaffs_FillInodeFromObject(inode, obj); - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockRead(dev); -} - -#endif - -static YLIST_HEAD(yaffs_dev_list); - -#if 0 /* not used */ -static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) -{ - yaffs_Device *dev = yaffs_SuperToDevice(sb); - - if (*flags & MS_RDONLY) { - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; - - T(YAFFS_TRACE_OS, - ("yaffs_remount_fs: %s: RO\n", dev->name)); - yaffs_DirLockWrite(dev); - yaffs_GrossLock(dev); - - yaffs_FlushEntireDeviceCache(dev); - - yaffs_CheckpointSave(dev); - - if (mtd->sync) - mtd->sync(mtd); - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockWrite(dev); - } else { - T(YAFFS_TRACE_OS, - ("yaffs_remount_fs: %s: RW\n", dev->name)); - } - - return 0; -} -#endif - -static void yaffs_put_super(struct super_block *sb) -{ - yaffs_Device *dev = yaffs_SuperToDevice(sb); - - T(YAFFS_TRACE_OS, ("yaffs_put_super\n")); - - yaffs_DirLockWrite(dev); - yaffs_GrossLock(dev); - - yaffs_FlushEntireDeviceCache(dev); - - yaffs_CheckpointSave(dev); - - if (dev->putSuperFunc) - dev->putSuperFunc(sb); - - yaffs_Deinitialise(dev); - - yaffs_GrossUnlock(dev); - yaffs_DirUnlockWrite(dev); - - /* we assume this is protected by lock_kernel() in mount/umount */ - ylist_del(&dev->devList); - - if (dev->spareBuffer) { - YFREE(dev->spareBuffer); - dev->spareBuffer = NULL; - } - - kfree(dev); -} - - -static void yaffs_MTDPutSuper(struct super_block *sb) -{ - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; - - if (mtd->sync) - mtd->sync(mtd); - - put_mtd_device(mtd); -} - - -static void yaffs_MarkSuperBlockDirty(void *vsb) -{ - struct super_block *sb = (struct super_block *)vsb; - - T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb)); - if (sb) - sb->s_dirt = 1; -} - -typedef struct { - int inband_tags; - int skip_checkpoint_read; - int skip_checkpoint_write; - int no_cache; - int tags_ecc_on; - int tags_ecc_overridden; - int lazy_loading_enabled; - int lazy_loading_overridden; - int empty_lost_and_found; - int empty_lost_and_found_overridden; -} yaffs_options; - -#define MAX_OPT_LEN 30 -static int yaffs_parse_options(yaffs_options *options, const char *options_str) -{ - char cur_opt[MAX_OPT_LEN + 1]; - int p; - int error = 0; - - /* Parse through the options which is a comma seperated list */ - - while (options_str && *options_str && !error) { - memset(cur_opt, 0, MAX_OPT_LEN + 1); - p = 0; - - while(*options_str == ',') - options_str++; - - while (*options_str && *options_str != ',') { - if (p < MAX_OPT_LEN) { - cur_opt[p] = *options_str; - p++; - } - options_str++; - } - - if (!strcmp(cur_opt, "inband-tags")) - options->inband_tags = 1; - else if (!strcmp(cur_opt, "tags-ecc-off")){ - options->tags_ecc_on = 0; - options->tags_ecc_overridden=1; - } else if (!strcmp(cur_opt, "tags-ecc-on")){ - options->tags_ecc_on = 1; - options->tags_ecc_overridden = 1; - } else if (!strcmp(cur_opt, "lazy-loading-off")){ - options->lazy_loading_enabled = 0; - options->lazy_loading_overridden=1; - } else if (!strcmp(cur_opt, "lazy-loading-on")){ - options->lazy_loading_enabled = 1; - options->lazy_loading_overridden = 1; - } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){ - options->empty_lost_and_found = 0; - options->empty_lost_and_found_overridden=1; - } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){ - options->empty_lost_and_found = 1; - options->empty_lost_and_found_overridden=1; - } else if (!strcmp(cur_opt, "no-cache")) - options->no_cache = 1; - else if (!strcmp(cur_opt, "no-checkpoint-read")) - options->skip_checkpoint_read = 1; - else if (!strcmp(cur_opt, "no-checkpoint-write")) - options->skip_checkpoint_write = 1; - else if (!strcmp(cur_opt, "no-checkpoint")) { - options->skip_checkpoint_read = 1; - options->skip_checkpoint_write = 1; - } else { - printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n", - cur_opt); - error = 1; - } - } - - return error; -} - -static struct super_block *yaffs_internal_read_super(int yaffsVersion, - struct super_block *sb, - void *data, int silent) -{ - int nBlocks; - struct inode *inode = NULL; - struct dentry *root; - yaffs_Device *dev = 0; - char devname_buf[BDEVNAME_SIZE + 1]; - struct mtd_info *mtd; - int err; - char *data_str = (char *)data; - - yaffs_options options; - - sb->s_magic = YAFFS_MAGIC; - sb->s_op = &yaffs_super_ops; - sb->s_flags |= MS_NOATIME; - - if (!sb) - printk(KERN_INFO "yaffs: sb is NULL\n"); - else if (!sb->s_dev) - printk(KERN_INFO "yaffs: sb->s_dev is NULL\n"); - else if (!yaffs_devname(sb, devname_buf)) - printk(KERN_INFO "yaffs: devname is NULL\n"); - else - printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n", - sb->s_dev, - yaffs_devname(sb, devname_buf)); - - if (!data_str) - data_str = ""; - - printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str); - - memset(&options, 0, sizeof(options)); - - if (yaffs_parse_options(&options, data_str)) { - /* Option parsing failed */ - return NULL; - } - - - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion)); - T(YAFFS_TRACE_OS, - ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize))); - -#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY - T(YAFFS_TRACE_OS, - ("yaffs: Write verification disabled. All guarantees " - "null and void\n")); -#endif - - T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, " - "\"%s\"\n", - MAJOR(sb->s_dev), MINOR(sb->s_dev), - yaffs_devname(sb, devname_buf))); - - /* Check it's an mtd device..... */ - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) - return NULL; /* This isn't an mtd device */ - - /* Get the device */ - mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); - if (!mtd) { - T(YAFFS_TRACE_ALWAYS, - ("yaffs: MTD device #%u doesn't appear to exist\n", - MINOR(sb->s_dev))); - return NULL; - } - /* Check it's NAND */ - if (mtd->type != MTD_NANDFLASH) { - T(YAFFS_TRACE_ALWAYS, - ("yaffs: MTD device is not NAND it's type %d\n", mtd->type)); - return NULL; - } - - T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase)); - T(YAFFS_TRACE_OS, (" read %p\n", mtd->read)); - T(YAFFS_TRACE_OS, (" write %p\n", mtd->write)); - T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob)); - T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob)); - T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad)); - T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad)); - T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd))); - T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize)); - T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize)); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) - T(YAFFS_TRACE_OS, (" size %u\n", mtd->size)); -#else - T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size)); -#endif - -#ifdef CONFIG_YAFFS_AUTO_YAFFS2 - - if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) { - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n")); - yaffsVersion = 2; - } - - /* Added NCB 26/5/2006 for completeness */ - if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) { - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n")); - yaffsVersion = 1; - } - -#endif - - if (yaffsVersion == 2) { - /* Check for version 2 style functions */ - if (!mtd->erase || - !mtd->block_isbad || - !mtd->block_markbad || - !mtd->read || - !mtd->write || -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) - !mtd->read_oob || !mtd->write_oob) { -#else - !mtd->write_ecc || - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { -#endif - T(YAFFS_TRACE_ALWAYS, - ("yaffs: MTD device does not support required " - "functions\n"));; - return NULL; - } - - if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || - mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && - !options.inband_tags) { - T(YAFFS_TRACE_ALWAYS, - ("yaffs: MTD device does not have the " - "right page sizes\n")); - return NULL; - } - } else { - /* Check for V1 style functions */ - if (!mtd->erase || - !mtd->read || - !mtd->write || -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) - !mtd->read_oob || !mtd->write_oob) { -#else - !mtd->write_ecc || - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { -#endif - T(YAFFS_TRACE_ALWAYS, - ("yaffs: MTD device does not support required " - "functions\n"));; - return NULL; - } - - if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || - mtd->oobsize != YAFFS_BYTES_PER_SPARE) { - T(YAFFS_TRACE_ALWAYS, - ("yaffs: MTD device does not support have the " - "right page sizes\n")); - return NULL; - } - } - - /* OK, so if we got here, we have an MTD that's NAND and looks - * like it has the right capabilities - * Set the yaffs_Device up for mtd - */ - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) - sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); -#else - sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); -#endif - if (!dev) { - /* Deep shit could not allocate device structure */ - T(YAFFS_TRACE_ALWAYS, - ("yaffs_read_super: Failed trying to allocate " - "yaffs_Device. \n")); - return NULL; - } - - memset(dev, 0, sizeof(yaffs_Device)); - dev->genericDevice = mtd; - dev->name = mtd->name; - - /* Set up the memory size parameters.... */ - - nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK)); - - dev->startBlock = 0; - dev->endBlock = nBlocks - 1; - dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; - dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK; - dev->nReservedBlocks = 5; - dev->nShortOpCaches = (options.no_cache) ? 0 : 10; - dev->inbandTags = options.inband_tags; - -#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD - dev->disableLazyLoad = 1; -#endif - if(options.lazy_loading_overridden) - dev->disableLazyLoad = !options.lazy_loading_enabled; - -#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC - dev->noTagsECC = 1; -#endif - if(options.tags_ecc_overridden) - dev->noTagsECC = !options.tags_ecc_on; - -#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND - dev->emptyLostAndFound = 1; -#endif - if(options.empty_lost_and_found_overridden) - dev->emptyLostAndFound = options.empty_lost_and_found; - - /* ... and the functions. */ - if (yaffsVersion == 2) { - dev->writeChunkWithTagsToNAND = - nandmtd2_WriteChunkWithTagsToNAND; - dev->readChunkWithTagsFromNAND = - nandmtd2_ReadChunkWithTagsFromNAND; - dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad; - dev->queryNANDBlock = nandmtd2_QueryNANDBlock; - dev->spareBuffer = YMALLOC(mtd->oobsize); - dev->isYaffs2 = 1; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) - dev->totalBytesPerChunk = mtd->writesize; - dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; -#else - dev->totalBytesPerChunk = mtd->oobblock; - dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; -#endif - nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize); - - dev->startBlock = 0; - dev->endBlock = nBlocks - 1; - } else { -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) - /* use the MTD interface in yaffs_mtdif1.c */ - dev->writeChunkWithTagsToNAND = - nandmtd1_WriteChunkWithTagsToNAND; - dev->readChunkWithTagsFromNAND = - nandmtd1_ReadChunkWithTagsFromNAND; - dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad; - dev->queryNANDBlock = nandmtd1_QueryNANDBlock; -#else - dev->writeChunkToNAND = nandmtd_WriteChunkToNAND; - dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND; -#endif - dev->isYaffs2 = 0; - } - /* ... and common functions */ - dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND; - dev->initialiseNAND = nandmtd_InitialiseNAND; - - dev->putSuperFunc = yaffs_MTDPutSuper; - - dev->superBlock = (void *)sb; - dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; - - -#ifndef CONFIG_YAFFS_DOES_ECC - dev->useNANDECC = 1; -#endif - -#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES - dev->wideTnodesDisabled = 1; -#endif - - dev->skipCheckpointRead = options.skip_checkpoint_read; - dev->skipCheckpointWrite = options.skip_checkpoint_write; - - /* we assume this is protected by lock_kernel() in mount/umount */ - ylist_add_tail(&dev->devList, &yaffs_dev_list); - - yaffs_DirLockInitialise(dev); - yaffs_GrossLockInitialise(dev); - - yaffs_DirLockWrite(dev); - yaffs_GrossLock(dev); - - err = yaffs_GutsInitialise(dev); - - T(YAFFS_TRACE_OS, - ("yaffs_read_super: guts initialised %s\n", - (err == YAFFS_OK) ? "OK" : "FAILED")); - - /* Release lock before yaffs_get_inode() */ - yaffs_GrossUnlock(dev); - yaffs_DirUnlockWrite(dev); - - /* Create root inode */ - if (err == YAFFS_OK) - inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, - yaffs_Root(dev)); - - if (!inode) - return NULL; - - inode->i_op = &yaffs_dir_inode_operations; - inode->i_fop = &yaffs_dir_operations; - - T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n")); - - root = d_alloc_root(inode); - - T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n")); - - if (!root) { - iput(inode); - return NULL; - } - sb->s_root = root; - sb->s_dirt = !dev->isCheckpointed; - T(YAFFS_TRACE_ALWAYS, - ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed)); - - T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n")); - return sb; -} - - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) -static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data, - int silent) -{ - return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL; -} - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) -static int yaffs_read_super(struct file_system_type *fs, - int flags, const char *dev_name, - void *data, struct vfsmount *mnt) -{ - - return get_sb_bdev(fs, flags, dev_name, data, - yaffs_internal_read_super_mtd, mnt); -} -#else -static struct super_block *yaffs_read_super(struct file_system_type *fs, - int flags, const char *dev_name, - void *data) -{ - - return get_sb_bdev(fs, flags, dev_name, data, - yaffs_internal_read_super_mtd); -} -#endif - -static struct file_system_type yaffs_fs_type = { - .owner = THIS_MODULE, - .name = "yaffs", - .get_sb = yaffs_read_super, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; -#else -static struct super_block *yaffs_read_super(struct super_block *sb, void *data, - int silent) -{ - return yaffs_internal_read_super(1, sb, data, silent); -} - -static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, - FS_REQUIRES_DEV); -#endif - - -#ifdef CONFIG_YAFFS_YAFFS2 - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) -static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, - int silent) -{ - return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL; -} - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) -static int yaffs2_read_super(struct file_system_type *fs, - int flags, const char *dev_name, void *data, - struct vfsmount *mnt) -{ - return get_sb_bdev(fs, flags, dev_name, data, - yaffs2_internal_read_super_mtd, mnt); -} -#else -static struct super_block *yaffs2_read_super(struct file_system_type *fs, - int flags, const char *dev_name, - void *data) -{ - - return get_sb_bdev(fs, flags, dev_name, data, - yaffs2_internal_read_super_mtd); -} -#endif - -static struct file_system_type yaffs2_fs_type = { - .owner = THIS_MODULE, - .name = "yaffs2", - .get_sb = yaffs2_read_super, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; -#else -static struct super_block *yaffs2_read_super(struct super_block *sb, - void *data, int silent) -{ - return yaffs_internal_read_super(2, sb, data, silent); -} - -static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, - FS_REQUIRES_DEV); -#endif - -#endif /* CONFIG_YAFFS_YAFFS2 */ - -static struct proc_dir_entry *my_proc_entry; - -static char *yaffs_dump_dev_part0(char *buf, yaffs_Device * dev) -{ - buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock); - buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); - buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk); - buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk); - buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits); - buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize); - buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks); - buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks); - buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint); - buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated); - buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes); - buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated); - buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects); - buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks); - buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites); - buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads); - buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures); - buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies); - buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections); - buf += sprintf(buf, "passiveGCs......... %d\n", - dev->passiveGarbageCollections); - buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites); - buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches); - buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks); - buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed); - buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed); - buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed); - buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed); - buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits); - buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles); - buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles); - buf += - sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions); - - return buf; -} - - -static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev) -{ - buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC); - buf += sprintf(buf, "noTagsECC.......... %d\n", dev->noTagsECC); - buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2); - buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags); - buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->emptyLostAndFound); - buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->disableLazyLoad); - - return buf; -} - -static int yaffs_proc_read(char *page, - char **start, - off_t offset, int count, int *eof, void *data) -{ - struct ylist_head *item; - char *buf = page; - int step = offset; - int n = 0; - - /* Get proc_file_read() to step 'offset' by one on each sucessive call. - * We use 'offset' (*ppos) to indicate where we are in devList. - * This also assumes the user has posted a read buffer large - * enough to hold the complete output; but that's life in /proc. - */ - - *(int *)start = 1; - - /* Print header first */ - if (step == 0) - buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__ - "\n%s\n%s\n", yaffs_fs_c_version, - yaffs_guts_c_version); - else if (step == 1) - buf += sprintf(buf,"\n"); - else { - step-=2; - - /* hold lock_kernel while traversing yaffs_dev_list */ - lock_kernel(); - - /* Locate and print the Nth entry. Order N-squared but N is small. */ - ylist_for_each(item, &yaffs_dev_list) { - yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList); - if (n < (step & ~1)) { - n+=2; - continue; - } - if((step & 1)==0){ - buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name); - buf = yaffs_dump_dev_part0(buf, dev); - } else - buf = yaffs_dump_dev_part1(buf, dev); - - break; - } - unlock_kernel(); - } - - return buf - page < count ? buf - page : count; -} - -/** - * Set the verbosity of the warnings and error messages. - * - * Note that the names can only be a..z or _ with the current code. - */ - -static struct { - char *mask_name; - unsigned mask_bitfield; -} mask_flags[] = { - {"allocate", YAFFS_TRACE_ALLOCATE}, - {"always", YAFFS_TRACE_ALWAYS}, - {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, - {"buffers", YAFFS_TRACE_BUFFERS}, - {"bug", YAFFS_TRACE_BUG}, - {"checkpt", YAFFS_TRACE_CHECKPOINT}, - {"deletion", YAFFS_TRACE_DELETION}, - {"erase", YAFFS_TRACE_ERASE}, - {"error", YAFFS_TRACE_ERROR}, - {"gc_detail", YAFFS_TRACE_GC_DETAIL}, - {"gc", YAFFS_TRACE_GC}, - {"mtd", YAFFS_TRACE_MTD}, - {"nandaccess", YAFFS_TRACE_NANDACCESS}, - {"os", YAFFS_TRACE_OS}, - {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, - {"scan", YAFFS_TRACE_SCAN}, - {"tracing", YAFFS_TRACE_TRACING}, - - {"verify", YAFFS_TRACE_VERIFY}, - {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, - {"verify_full", YAFFS_TRACE_VERIFY_FULL}, - {"verify_all", YAFFS_TRACE_VERIFY_ALL}, - - {"write", YAFFS_TRACE_WRITE}, - {"all", 0xffffffff}, - {"none", 0}, - {NULL, 0}, -}; - -#define MAX_MASK_NAME_LENGTH 40 -static int yaffs_proc_write_trace_options(struct file *file, const char *buf, - unsigned long count, void *data) -{ - unsigned rg = 0, mask_bitfield; - char *end; - char *mask_name; - const char *x; - char substring[MAX_MASK_NAME_LENGTH + 1]; - int i; - int done = 0; - int add, len = 0; - int pos = 0; - - rg = yaffs_traceMask; - - while (!done && (pos < count)) { - done = 1; - while ((pos < count) && isspace(buf[pos])) - pos++; - - switch (buf[pos]) { - case '+': - case '-': - case '=': - add = buf[pos]; - pos++; - break; - - default: - add = ' '; - break; - } - mask_name = NULL; - - mask_bitfield = simple_strtoul(buf + pos, &end, 0); - - if (end > buf + pos) { - mask_name = "numeral"; - len = end - (buf + pos); - pos += len; - done = 0; - } else { - for (x = buf + pos, i = 0; - (*x == '_' || (*x >= 'a' && *x <= 'z')) && - i < MAX_MASK_NAME_LENGTH; x++, i++, pos++) - substring[i] = *x; - substring[i] = '\0'; - - for (i = 0; mask_flags[i].mask_name != NULL; i++) { - if (strcmp(substring, mask_flags[i].mask_name) == 0) { - mask_name = mask_flags[i].mask_name; - mask_bitfield = mask_flags[i].mask_bitfield; - done = 0; - break; - } - } - } - - if (mask_name != NULL) { - done = 0; - switch (add) { - case '-': - rg &= ~mask_bitfield; - break; - case '+': - rg |= mask_bitfield; - break; - case '=': - rg = mask_bitfield; - break; - default: - rg |= mask_bitfield; - break; - } - } - } - - yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS; - - printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask); - - if (rg & YAFFS_TRACE_ALWAYS) { - for (i = 0; mask_flags[i].mask_name != NULL; i++) { - char flag; - flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-'; - printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name); - } - } - - return count; -} - - -static int yaffs_proc_write(struct file *file, const char *buf, - unsigned long count, void *data) -{ - return yaffs_proc_write_trace_options(file, buf, count, data); -} - -/* Stuff to handle installation of file systems */ -struct file_system_to_install { - struct file_system_type *fst; - int installed; -}; - -static struct file_system_to_install fs_to_install[] = { - {&yaffs_fs_type, 0}, - {&yaffs2_fs_type, 0}, - {NULL, 0} -}; - -static int __init init_yaffs_fs(void) -{ - int error = 0; - struct file_system_to_install *fsinst; - - T(YAFFS_TRACE_ALWAYS, - ("yaffs " __DATE__ " " __TIME__ " Installing. \n")); - - /* Install the proc_fs entry */ - my_proc_entry = create_proc_entry("yaffs", - S_IRUGO | S_IFREG, - YPROC_ROOT); - - if (my_proc_entry) { - my_proc_entry->write_proc = yaffs_proc_write; - my_proc_entry->read_proc = yaffs_proc_read; - my_proc_entry->data = NULL; - } else - return -ENOMEM; - - /* Now add the file system entries */ - - fsinst = fs_to_install; - - while (fsinst->fst && !error) { - error = register_filesystem(fsinst->fst); - if (!error) - fsinst->installed = 1; - fsinst++; - } - - /* Any errors? uninstall */ - if (error) { - fsinst = fs_to_install; - - while (fsinst->fst) { - if (fsinst->installed) { - unregister_filesystem(fsinst->fst); - fsinst->installed = 0; - } - fsinst++; - } - } - - return error; -} - -static void __exit exit_yaffs_fs(void) -{ - - struct file_system_to_install *fsinst; - - T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__ - " removing. \n")); - - remove_proc_entry("yaffs", YPROC_ROOT); - - fsinst = fs_to_install; - - while (fsinst->fst) { - if (fsinst->installed) { - unregister_filesystem(fsinst->fst); - fsinst->installed = 0; - } - fsinst++; - } -} - -module_init(init_yaffs_fs) -module_exit(exit_yaffs_fs) - -MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); -MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006"); -MODULE_LICENSE("GPL");
deleted file mode 100644 --- a/yaffs_mtdif.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * 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_mtdif_c_version = - "$Id$"; - -#include "yportenv.h" - - -#include "yaffs_mtdif.h" - -#include "linux/mtd/mtd.h" -#include "linux/types.h" -#include "linux/time.h" -#include "linux/mtd/nand.h" - -#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18)) -static struct nand_oobinfo yaffs_oobinfo = { - .useecc = 1, - .eccbytes = 6, - .eccpos = {8, 9, 10, 13, 14, 15} -}; - -static struct nand_oobinfo yaffs_noeccinfo = { - .useecc = 0, -}; -#endif - -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) -static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob) -{ - oob[0] = spare->tagByte0; - oob[1] = spare->tagByte1; - oob[2] = spare->tagByte2; - oob[3] = spare->tagByte3; - oob[4] = spare->tagByte4; - oob[5] = spare->tagByte5 & 0x3f; - oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80; - oob[5] |= spare->pageStatus == 0 ? 0 : 0x40; - oob[6] = spare->tagByte6; - oob[7] = spare->tagByte7; -} - -static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob) -{ - struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare; - spare->tagByte0 = oob[0]; - spare->tagByte1 = oob[1]; - spare->tagByte2 = oob[2]; - spare->tagByte3 = oob[3]; - spare->tagByte4 = oob[4]; - spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f; - spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y'; - spare->pageStatus = oob[5] & 0x40 ? 0xff : 0; - spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff; - spare->tagByte6 = oob[6]; - spare->tagByte7 = oob[7]; - spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff; - - nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */ -} -#endif - -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND, - const __u8 *data, const yaffs_Spare *spare) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) - struct mtd_oob_ops ops; -#endif - size_t dummy; - int retval = 0; - - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) - __u8 spareAsBytes[8]; /* OOB */ - - if (data && !spare) - retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data); - else if (spare) { - if (dev->useNANDECC) { - translate_spare2oob(spare, spareAsBytes); - ops.mode = MTD_OOB_AUTO; - ops.ooblen = 8; /* temp hack */ - } else { - ops.mode = MTD_OOB_RAW; - ops.ooblen = YAFFS_BYTES_PER_SPARE; - } - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen; - ops.datbuf = (u8 *)data; - ops.ooboffs = 0; - ops.oobbuf = spareAsBytes; - retval = mtd->write_oob(mtd, addr, &ops); - } -#else - __u8 *spareAsBytes = (__u8 *) spare; - - if (data && spare) { - if (dev->useNANDECC) - retval = - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, spareAsBytes, - &yaffs_oobinfo); - else - retval = - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, spareAsBytes, - &yaffs_noeccinfo); - } else { - if (data) - retval = - mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, - data); - if (spare) - retval = - mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE, - &dummy, spareAsBytes); - } -#endif - - if (retval == 0) - return YAFFS_OK; - else - return YAFFS_FAIL; -} - -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, - yaffs_Spare *spare) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) - struct mtd_oob_ops ops; -#endif - size_t dummy; - int retval = 0; - - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) - __u8 spareAsBytes[8]; /* OOB */ - - if (data && !spare) - retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data); - else if (spare) { - if (dev->useNANDECC) { - ops.mode = MTD_OOB_AUTO; - ops.ooblen = 8; /* temp hack */ - } else { - ops.mode = MTD_OOB_RAW; - ops.ooblen = YAFFS_BYTES_PER_SPARE; - } - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen; - ops.datbuf = data; - ops.ooboffs = 0; - ops.oobbuf = spareAsBytes; - retval = mtd->read_oob(mtd, addr, &ops); - if (dev->useNANDECC) - translate_oob2spare(spare, spareAsBytes); - } -#else - __u8 *spareAsBytes = (__u8 *) spare; - - if (data && spare) { - if (dev->useNANDECC) { - /* Careful, this call adds 2 ints */ - /* to the end of the spare data. Calling function */ - /* should allocate enough memory for spare, */ - /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */ - retval = - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, spareAsBytes, - &yaffs_oobinfo); - } else { - retval = - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, spareAsBytes, - &yaffs_noeccinfo); - } - } else { - if (data) - retval = - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, - data); - if (spare) - retval = - mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE, - &dummy, spareAsBytes); - } -#endif - - if (retval == 0) - return YAFFS_OK; - else - return YAFFS_FAIL; -} - -int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); - __u32 addr = - ((loff_t) blockNumber) * dev->nDataBytesPerChunk - * dev->nChunksPerBlock; - struct erase_info ei; - int retval = 0; - - ei.mtd = mtd; - ei.addr = addr; - ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock; - ei.time = 1000; - ei.retries = 2; - ei.callback = NULL; - ei.priv = (u_long) dev; - - /* Todo finish off the ei if required */ - - sema_init(&dev->sem, 0); - - retval = mtd->erase(mtd, &ei); - - if (retval == 0) - return YAFFS_OK; - else - return YAFFS_FAIL; -} - -int nandmtd_InitialiseNAND(yaffs_Device *dev) -{ - return YAFFS_OK; -} -
deleted file mode 100644 --- a/yaffs_mtdif.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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_MTDIF_H__ -#define __YAFFS_MTDIF_H__ - -#include "yaffs_guts.h" - -#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18)) -extern struct nand_oobinfo yaffs_oobinfo; -extern struct nand_oobinfo yaffs_noeccinfo; -#endif - -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND, - const __u8 *data, const yaffs_Spare *spare); -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, - yaffs_Spare *spare); -int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); -int nandmtd_InitialiseNAND(yaffs_Device *dev); -#endif
deleted file mode 100644 --- a/yaffs_mtdif1.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND. - * - * Copyright (C) 2002 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * - * 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 module provides the interface between yaffs_nand.c and the - * MTD API. This version is used when the MTD interface supports the - * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17, - * and we have small-page NAND device. - * - * These functions are invoked via function pointers in yaffs_nand.c. - * This replaces functionality provided by functions in yaffs_mtdif.c - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are - * called in yaffs_mtdif.c when the function pointers are NULL. - * We assume the MTD layer is performing ECC (useNANDECC is true). - */ - -#include "yportenv.h" -#include "yaffs_guts.h" -#include "yaffs_packedtags1.h" -#include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */ - -#include "linux/kernel.h" -#include "linux/version.h" -#include "linux/types.h" -#include "linux/mtd/mtd.h" - -/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) - -const char *yaffs_mtdif1_c_version = "$Id$"; - -#ifndef CONFIG_YAFFS_9BYTE_TAGS -# define YTAG1_SIZE 8 -#else -# define YTAG1_SIZE 9 -#endif - -#if 0 -/* Use the following nand_ecclayout with MTD when using - * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout. - * If you have existing Yaffs images and the byte order differs from this, - * adjust 'oobfree' to match your existing Yaffs data. - * - * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to - * the 9th byte. - * - * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5 - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus - * byte and B is the small-page bad-block indicator byte. - */ -static struct nand_ecclayout nand_oob_16 = { - .eccbytes = 6, - .eccpos = { 8, 9, 10, 13, 14, 15 }, - .oobavail = 9, - .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } } -}; -#endif - -/* Write a chunk (page) of data to NAND. - * - * Caller always provides ExtendedTags data which are converted to a more - * compact (packed) form for storage in NAND. A mini-ECC runs over the - * contents of the tags meta-data; used to valid the tags when read. - * - * - Pack ExtendedTags to PackedTags1 form - * - Compute mini-ECC for PackedTags1 - * - Write data and packed tags to NAND. - * - * Note: Due to the use of the PackedTags1 meta-data which does not include - * a full sequence number (as found in the larger PackedTags2 form) it is - * necessary for Yaffs to re-write a chunk/page (just once) to mark it as - * discarded and dirty. This is not ideal: newer NAND parts are supposed - * to be written just once. When Yaffs performs this operation, this - * function is called with a NULL data pointer -- calling MTD write_oob - * without data is valid usage (2.6.17). - * - * Any underlying MTD error results in YAFFS_FAIL. - * Returns YAFFS_OK or YAFFS_FAIL. - */ -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, - int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags) -{ - struct mtd_info *mtd = dev->genericDevice; - int chunkBytes = dev->nDataBytesPerChunk; - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; - struct mtd_oob_ops ops; - yaffs_PackedTags1 pt1; - int retval; - - /* we assume that PackedTags1 and yaffs_Tags are compatible */ - compile_time_assertion(sizeof(yaffs_PackedTags1) == 12); - compile_time_assertion(sizeof(yaffs_Tags) == 8); - - yaffs_PackTags1(&pt1, etags); - yaffs_CalcTagsECC((yaffs_Tags *)&pt1); - - /* When deleting a chunk, the upper layer provides only skeletal - * etags, one with chunkDeleted set. However, we need to update the - * tags, not erase them completely. So we use the NAND write property - * that only zeroed-bits stick and set tag bytes to all-ones and - * zero just the (not) deleted bit. - */ -#ifndef CONFIG_YAFFS_9BYTE_TAGS - if (etags->chunkDeleted) { - memset(&pt1, 0xff, 8); - /* clear delete status bit to indicate deleted */ - pt1.deleted = 0; - } -#else - ((__u8 *)&pt1)[8] = 0xff; - if (etags->chunkDeleted) { - memset(&pt1, 0xff, 8); - /* zero pageStatus byte to indicate deleted */ - ((__u8 *)&pt1)[8] = 0; - } -#endif - - memset(&ops, 0, sizeof(ops)); - ops.mode = MTD_OOB_AUTO; - ops.len = (data) ? chunkBytes : 0; - ops.ooblen = YTAG1_SIZE; - ops.datbuf = (__u8 *)data; - ops.oobbuf = (__u8 *)&pt1; - - retval = mtd->write_oob(mtd, addr, &ops); - if (retval) { - yaffs_trace(YAFFS_TRACE_MTD, - "write_oob failed, chunk %d, mtd error %d\n", - chunkInNAND, retval); - } - return retval ? YAFFS_FAIL : YAFFS_OK; -} - -/* Return with empty ExtendedTags but add eccResult. - */ -static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval) -{ - if (etags) { - memset(etags, 0, sizeof(*etags)); - etags->eccResult = eccResult; - } - return retval; -} - -/* Read a chunk (page) from NAND. - * - * Caller expects ExtendedTags data to be usable even on error; that is, - * all members except eccResult and blockBad are zeroed. - * - * - Check ECC results for data (if applicable) - * - Check for blank/erased block (return empty ExtendedTags if blank) - * - Check the PackedTags1 mini-ECC (correct if necessary/possible) - * - Convert PackedTags1 to ExtendedTags - * - Update eccResult and blockBad members to refect state. - * - * Returns YAFFS_OK or YAFFS_FAIL. - */ -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, - int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags) -{ - struct mtd_info *mtd = dev->genericDevice; - int chunkBytes = dev->nDataBytesPerChunk; - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; - int eccres = YAFFS_ECC_RESULT_NO_ERROR; - struct mtd_oob_ops ops; - yaffs_PackedTags1 pt1; - int retval; - int deleted; - - memset(&ops, 0, sizeof(ops)); - ops.mode = MTD_OOB_AUTO; - ops.len = (data) ? chunkBytes : 0; - ops.ooblen = YTAG1_SIZE; - ops.datbuf = data; - ops.oobbuf = (__u8 *)&pt1; - -#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20)) - /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; - * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. - */ - ops.len = (ops.datbuf) ? ops.len : ops.ooblen; -#endif - /* Read page and oob using MTD. - * Check status and determine ECC result. - */ - retval = mtd->read_oob(mtd, addr, &ops); - if (retval) { - yaffs_trace(YAFFS_TRACE_MTD, - "read_oob failed, chunk %d, mtd error %d\n", - chunkInNAND, retval); - } - - switch (retval) { - case 0: - /* no error */ - break; - - case -EUCLEAN: - /* MTD's ECC fixed the data */ - eccres = YAFFS_ECC_RESULT_FIXED; - dev->eccFixed++; - break; - - case -EBADMSG: - /* MTD's ECC could not fix the data */ - dev->eccUnfixed++; - /* fall into... */ - default: - rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0); - etags->blockBad = (mtd->block_isbad)(mtd, addr); - return YAFFS_FAIL; - } - - /* Check for a blank/erased chunk. - */ - if (yaffs_CheckFF((__u8 *)&pt1, 8)) { - /* when blank, upper layers want eccResult to be <= NO_ERROR */ - return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK); - } - -#ifndef CONFIG_YAFFS_9BYTE_TAGS - /* Read deleted status (bit) then return it to it's non-deleted - * state before performing tags mini-ECC check. pt1.deleted is - * inverted. - */ - deleted = !pt1.deleted; - pt1.deleted = 1; -#else - deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7); -#endif - - /* Check the packed tags mini-ECC and correct if necessary/possible. - */ - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1); - switch (retval) { - case 0: - /* no tags error, use MTD result */ - break; - case 1: - /* recovered tags-ECC error */ - dev->tagsEccFixed++; - if (eccres == YAFFS_ECC_RESULT_NO_ERROR) - eccres = YAFFS_ECC_RESULT_FIXED; - break; - default: - /* unrecovered tags-ECC error */ - dev->tagsEccUnfixed++; - return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL); - } - - /* Unpack the tags to extended form and set ECC result. - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy] - */ - pt1.shouldBeFF = 0xFFFFFFFF; - yaffs_UnpackTags1(etags, &pt1); - etags->eccResult = eccres; - - /* Set deleted state */ - etags->chunkDeleted = deleted; - return YAFFS_OK; -} - -/* Mark a block bad. - * - * This is a persistant state. - * Use of this function should be rare. - * - * Returns YAFFS_OK or YAFFS_FAIL. - */ -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) -{ - struct mtd_info *mtd = dev->genericDevice; - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; - int retval; - - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo); - - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo); - return (retval) ? YAFFS_FAIL : YAFFS_OK; -} - -/* Check any MTD prerequists. - * - * Returns YAFFS_OK or YAFFS_FAIL. - */ -static int nandmtd1_TestPrerequists(struct mtd_info *mtd) -{ - /* 2.6.18 has mtd->ecclayout->oobavail */ - /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */ - int oobavail = mtd->ecclayout->oobavail; - - if (oobavail < YTAG1_SIZE) { - yaffs_trace(YAFFS_TRACE_ERROR, - "mtd device has only %d bytes for tags, need %d\n", - oobavail, YTAG1_SIZE); - return YAFFS_FAIL; - } - return YAFFS_OK; -} - -/* Query for the current state of a specific block. - * - * Examine the tags of the first chunk of the block and return the state: - * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad - * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use - * - YAFFS_BLOCK_STATE_EMPTY, the block is clean - * - * Always returns YAFFS_OK. - */ -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, - yaffs_BlockState *pState, __u32 *pSequenceNumber) -{ - struct mtd_info *mtd = dev->genericDevice; - int chunkNo = blockNo * dev->nChunksPerBlock; - loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk; - yaffs_ExtendedTags etags; - int state = YAFFS_BLOCK_STATE_DEAD; - int seqnum = 0; - int retval; - - /* We don't yet have a good place to test for MTD config prerequists. - * Do it here as we are called during the initial scan. - */ - if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) - return YAFFS_FAIL; - - retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); - etags.blockBad = (mtd->block_isbad)(mtd, addr); - if (etags.blockBad) { - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, - "block %d is marked bad\n", blockNo); - state = YAFFS_BLOCK_STATE_DEAD; - } else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) { - /* bad tags, need to look more closely */ - state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; - } else if (etags.chunkUsed) { - state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; - seqnum = etags.sequenceNumber; - } else { - state = YAFFS_BLOCK_STATE_EMPTY; - } - - *pState = state; - *pSequenceNumber = seqnum; - - /* query always succeeds */ - return YAFFS_OK; -} - -#endif /*MTD_VERSION*/
deleted file mode 100644 --- a/yaffs_mtdif1.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 - * - * 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_MTDIF1_H__ -#define __YAFFS_MTDIF1_H__ - -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, - const __u8 *data, const yaffs_ExtendedTags *tags); - -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, - __u8 *data, yaffs_ExtendedTags *tags); - -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); - -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, - yaffs_BlockState *state, __u32 *sequenceNumber); - -#endif
deleted file mode 100644 --- a/yaffs_mtdif2.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * 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. - */ - -/* mtd interface for YAFFS2 */ - -const char *yaffs_mtdif2_c_version = - "$Id$"; - -#include "yportenv.h" - - -#include "yaffs_mtdif2.h" - -#include "linux/mtd/mtd.h" -#include "linux/types.h" -#include "linux/time.h" - -#include "yaffs_packedtags2.h" - -/* NB For use with inband tags.... - * We assume that the data buffer is of size totalBytersPerChunk so that we can also - * use it to load the tags. - */ -int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, - const __u8 *data, - const yaffs_ExtendedTags *tags) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) - struct mtd_oob_ops ops; -#else - size_t dummy; -#endif - int retval = 0; - - loff_t addr; - - yaffs_PackedTags2 pt; - - int packed_tags_size = dev->noTagsECC ? sizeof(pt.t) : sizeof(pt); - void * packed_tags_ptr = dev->noTagsECC ? (void *) &pt.t : (void *)&pt; - - T(YAFFS_TRACE_MTD, - (TSTR - ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" - TENDSTR), chunkInNAND, data, tags)); - - - addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; - - /* For yaffs2 writing there must be both data and tags. - * If we're using inband tags, then the tags are stuffed into - * the end of the data buffer. - */ - if (!data || !tags) - BUG(); - else if (dev->inbandTags) { - yaffs_PackedTags2TagsPart *pt2tp; - pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); - yaffs_PackTags2TagsPart(pt2tp, tags); - } else - yaffs_PackTags2(dev, &pt, tags); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) - ops.mode = MTD_OOB_AUTO; - ops.ooblen = (dev->inbandTags) ? 0 : packed_tags_size; - ops.len = dev->totalBytesPerChunk; - ops.ooboffs = 0; - ops.datbuf = (__u8 *)data; - ops.oobbuf = (dev->inbandTags) ? NULL : packed_tags_ptr; - retval = mtd->write_oob(mtd, addr, &ops); - -#else - if (!dev->inbandTags) { - retval = - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, (__u8 *) packed_tags_ptr, NULL); - } else { - retval = - mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy, - data); - } -#endif - - if (retval == 0) - return YAFFS_OK; - else - return YAFFS_FAIL; -} - -int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, - __u8 *data, yaffs_ExtendedTags *tags) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) - struct mtd_oob_ops ops; -#endif - size_t dummy; - int retval = 0; - int localData = 0; - - loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; - - yaffs_PackedTags2 pt; - - int packed_tags_size = dev->noTagsECC ? sizeof(pt.t) : sizeof(pt); - void * packed_tags_ptr = dev->noTagsECC ? (void *) &pt.t: (void *)&pt; - - T(YAFFS_TRACE_MTD, - (TSTR - ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p" - TENDSTR), chunkInNAND, data, tags)); - - if (dev->inbandTags) { - - if (!data) { - localData = 1; - data = yaffs_GetTempBuffer(dev, __LINE__); - } - - - } - - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) - if (dev->inbandTags || (data && !tags)) - retval = mtd->read(mtd, addr, dev->totalBytesPerChunk, - &dummy, data); - else if (tags) { - ops.mode = MTD_OOB_AUTO; - ops.ooblen = packed_tags_size; - ops.len = data ? dev->nDataBytesPerChunk : packed_tags_size; - ops.ooboffs = 0; - ops.datbuf = data; - ops.oobbuf = dev->spareBuffer; - retval = mtd->read_oob(mtd, addr, &ops); - } -#else - if (!dev->inbandTags && data && tags) { - - retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, dev->spareBuffer, - NULL); - } else { - if (data) - retval = - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, - data); - if (!dev->inbandTags && tags) - retval = - mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, - dev->spareBuffer); - } -#endif - - - if (dev->inbandTags) { - if (tags) { - yaffs_PackedTags2TagsPart *pt2tp; - pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; - yaffs_UnpackTags2TagsPart(tags, pt2tp); - } - } else { - if (tags) { - memcpy(packed_tags_ptr, dev->spareBuffer, packed_tags_size); - yaffs_UnpackTags2(dev, tags, &pt); - } - } - - if (localData) - yaffs_ReleaseTempBuffer(dev, data, __LINE__); - - if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) - tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; - if (retval == 0) - return YAFFS_OK; - else - return YAFFS_FAIL; -} - -int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); - int retval; - T(YAFFS_TRACE_MTD, - (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo)); - - retval = - mtd->block_markbad(mtd, - blockNo * dev->nChunksPerBlock * - dev->totalBytesPerChunk); - - if (retval == 0) - return YAFFS_OK; - else - return YAFFS_FAIL; - -} - -int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, - yaffs_BlockState *state, __u32 *sequenceNumber) -{ - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); - int retval; - - T(YAFFS_TRACE_MTD, - (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo)); - retval = - mtd->block_isbad(mtd, - blockNo * dev->nChunksPerBlock * - dev->totalBytesPerChunk); - - if (retval) { - T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR))); - - *state = YAFFS_BLOCK_STATE_DEAD; - *sequenceNumber = 0; - } else { - yaffs_ExtendedTags t; - nandmtd2_ReadChunkWithTagsFromNAND(dev, - blockNo * - dev->nChunksPerBlock, NULL, - &t); - - if (t.chunkUsed) { - *sequenceNumber = t.sequenceNumber; - *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; - } else { - *sequenceNumber = 0; - *state = YAFFS_BLOCK_STATE_EMPTY; - } - } - T(YAFFS_TRACE_MTD, - (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber, - *state)); - - if (retval == 0) - return YAFFS_OK; - else - return YAFFS_FAIL; -} -
deleted file mode 100644 --- a/yaffs_mtdif2.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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_MTDIF2_H__ -#define __YAFFS_MTDIF2_H__ - -#include "yaffs_guts.h" -int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, - const __u8 *data, - const yaffs_ExtendedTags *tags); -int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, - __u8 *data, yaffs_ExtendedTags *tags); -int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); -int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, - yaffs_BlockState *state, __u32 *sequenceNumber); - -#endif
deleted file mode 100644 --- a/yaffs_nandemul2k.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -/* Interface to emulated NAND functions (2k page size) */ - -#ifndef __YAFFS_NANDEMUL2K_H__ -#define __YAFFS_NANDEMUL2K_H__ - -#include "yaffs_guts.h" - -int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, - int chunkInNAND, const __u8 *data, - const yaffs_ExtendedTags *tags); -int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev, - int chunkInNAND, __u8 *data, - yaffs_ExtendedTags *tags); -int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); -int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, - yaffs_BlockState *state, __u32 *sequenceNumber); -int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, - int blockInNAND); -int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev); -int nandemul2k_GetBytesPerChunk(void); -int nandemul2k_GetChunksPerBlock(void); -int nandemul2k_GetNumberOfBlocks(void); - -#endif
deleted file mode 100644 --- a/yaffs_qsort.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "yportenv.h" -/* #include <linux/string.h> */ - -/* - * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". - */ -#define swapcode(TYPE, parmi, parmj, n) do { \ - long i = (n) / sizeof (TYPE); \ - register TYPE *pi = (TYPE *) (parmi); \ - register TYPE *pj = (TYPE *) (parmj); \ - do { \ - register TYPE t = *pi; \ - *pi++ = *pj; \ - *pj++ = t; \ - } while (--i > 0); \ -} while (0) - -#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ - es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1; - -static __inline void -swapfunc(char *a, char *b, int n, int swaptype) -{ - if (swaptype <= 1) - swapcode(long, a, b, n); - else - swapcode(char, a, b, n); -} - -#define yswap(a, b) do { \ - if (swaptype == 0) { \ - long t = *(long *)(a); \ - *(long *)(a) = *(long *)(b); \ - *(long *)(b) = t; \ - } else \ - swapfunc(a, b, es, swaptype); \ -} while (0) - -#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) - -static __inline char * -med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *)) -{ - return cmp(a, b) < 0 ? - (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a)) - : (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c)); -} - -#ifndef min -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -void -yaffs_qsort(void *aa, size_t n, size_t es, - int (*cmp)(const void *, const void *)) -{ - char *pa, *pb, *pc, *pd, *pl, *pm, *pn; - int d, r, swaptype, swap_cnt; - register char *a = aa; - -loop: SWAPINIT(a, es); - swap_cnt = 0; - if (n < 7) { - for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) - for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; - pl -= es) - yswap(pl, pl - es); - return; - } - pm = (char *)a + (n / 2) * es; - if (n > 7) { - pl = (char *)a; - pn = (char *)a + (n - 1) * es; - if (n > 40) { - d = (n / 8) * es; - pl = med3(pl, pl + d, pl + 2 * d, cmp); - pm = med3(pm - d, pm, pm + d, cmp); - pn = med3(pn - 2 * d, pn - d, pn, cmp); - } - pm = med3(pl, pm, pn, cmp); - } - yswap(a, pm); - pa = pb = (char *)a + es; - - pc = pd = (char *)a + (n - 1) * es; - for (;;) { - while (pb <= pc && (r = cmp(pb, a)) <= 0) { - if (r == 0) { - swap_cnt = 1; - yswap(pa, pb); - pa += es; - } - pb += es; - } - while (pb <= pc && (r = cmp(pc, a)) >= 0) { - if (r == 0) { - swap_cnt = 1; - yswap(pc, pd); - pd -= es; - } - pc -= es; - } - if (pb > pc) - break; - yswap(pb, pc); - swap_cnt = 1; - pb += es; - pc -= es; - } - if (swap_cnt == 0) { /* Switch to insertion sort */ - for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) - for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; - pl -= es) - yswap(pl, pl - es); - return; - } - - pn = (char *)a + n * es; - r = min(pa - (char *)a, pb - pa); - vecswap(a, pb - r, r); - r = min((long)(pd - pc), (long)(pn - pd - es)); - vecswap(pb, pn - r, r); - r = pb - pa; - if (r > es) - yaffs_qsort(a, r / es, es, cmp); - r = pd - pc; - if (r > es) { - /* Iterate rather than recurse to save stack space */ - a = pn - r; - n = r / es; - goto loop; - } -/* yaffs_qsort(pn - r, r / es, es, cmp);*/ -}
