diff -urN linux-2.6.24.7/fs/yaffs2/Kconfig linux-2.6.24.7.new/fs/yaffs2/Kconfig --- linux-2.6.24.7/fs/yaffs2/Kconfig 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/Kconfig 2009-04-21 15:01:02.000000000 +0200 @@ -2,6 +2,8 @@ # YAFFS file system configurations # +menu "Yaffs2 Filesystems" + config YAFFS_FS tristate "YAFFS2 file system support" default n @@ -12,8 +14,8 @@ 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. + To compile the YAFFS2 file system support as a module, choose M here: + the module will be called yaffs2. If unsure, say N. @@ -27,29 +29,11 @@ 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. - - If unsure, say N. - config YAFFS_DOES_ECC bool "Lets Yaffs do its own ECC" - depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS + depends on YAFFS_FS && YAFFS_YAFFS1 default n help This enables Yaffs to use its own ECC functions instead of using @@ -59,12 +43,12 @@ 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 + depends on YAFFS_FS && YAFFS_DOES_ECC 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. + 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. @@ -73,10 +57,39 @@ depends on YAFFS_FS default y help - Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices + Enable YAFFS2 support -- yaffs for >= 2048 byte / page larger devices If unsure, say Y. +if SOC_JZ4730 || SOC_JZ4740 + +choice + prompt "ECC type for oob area" + depends on YAFFS_YAFFS2 + default CONFIG_YAFFS_ECC_RS + help + There are 16 bytes for yaffs2 information in oob which should be checked + using some type of ECC. + +config YAFFS_ECC_RS + bool "Use soft reed solomon ECC for oob area" + select REED_SOLOMON + select REED_SOLOMON_ENC8 + select REED_SOLOMON_DEC8 + help + The reed solomon ECC could correct 2 5-bit symbols for 16 bytes in oob. + It should be selected for MLC nand. + +config YAFFS_ECC_HAMMING + bool "Use hamming ECC for oob area" + help + The hamming ECC could only correct 1 bit for 16 bytes in oob, but it's + a bit faster than reed solomon ECC. It should be selected for SLC nand. + +endchoice + +endif + config YAFFS_AUTO_YAFFS2 bool "Autoselect yaffs2 format" depends on YAFFS_YAFFS2 @@ -84,8 +97,7 @@ 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). + will be used depending on the device page size. If unsure, say Y. @@ -109,57 +121,30 @@ If unsure, say N. -config YAFFS_CHECKPOINT_RESERVED_BLOCKS - int "Reserved blocks for checkpointing" - depends on YAFFS_YAFFS2 - default 10 - help - Give the number of Blocks to reserve for checkpointing. - Checkpointing saves the state at unmount so that mounting is - much faster as a scan of all the flash to regenerate this state - is not needed. These Blocks are reserved per partition, so if - you have very small partitions the default (10) may be a mess - for you. You can set this value to 0, but that does not mean - checkpointing is disabled at all. There only won't be any - specially reserved blocks for checkpointing, so if there is - enough free space on the filesystem, it will be used for - checkpointing. - - If unsure, leave at default (10), but don't wonder if there are - always 2MB used on your large page device partition (10 x 2k - pagesize). When using small partitions or when being very small - on space, you probably want to set this to zero. - 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 + Wide tnodes are only used for large 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. + Setting this to 'y' will force tnode width to 16 bits and make + large arrays slower. If unsure, say N. -config YAFFS_ALWAYS_CHECK_CHUNK_ERASED - bool "Force chunk erase check" +config YAFFS_DISABLE_CHUNK_ERASED_CHECK + bool "Turn off debug chunk erase check" depends on YAFFS_FS - default n + default y 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. + Enabling this turns off the test that chunks are erased in flash + before writing to them. This is safe, since the write verification + will fail. Suggest enabling the test (ie. say N) + during development to help debug things. If unsure, say Y. @@ -173,3 +158,10 @@ but makes look-ups faster. If unsure, say Y. + +config YAFFS_CHECKPOINT_RESERVED_BLOCKS + int 'Reserved blocks for checkpointing' + depends on YAFFS_FS + default 10 + +endmenu diff -urN linux-2.6.24.7/fs/yaffs2/Makefile linux-2.6.24.7.new/fs/yaffs2/Makefile --- linux-2.6.24.7/fs/yaffs2/Makefile 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/Makefile 2009-04-21 15:01:02.000000000 +0200 @@ -1,11 +1,10 @@ # -# Makefile for the linux YAFFS filesystem routines. +# Makefile for the linux YAFFS2 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_packedtags2.o yaffs_nand.o yaffs_qsort.o -yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o -yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o -yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o +obj-y := yaffs2.o +obj-$(CONFIG_YAFFS_FS) := yaffs_mtdif.o yaffs_mtdif2.o +obj-$(CONFIG_YAFFS_FS) += yaffs_ecc.o yaffs_fs.o yaffs_guts.o +obj-$(CONFIG_YAFFS_FS) += yaffs_packedtags2.o yaffs_qsort.o +obj-$(CONFIG_YAFFS_FS) += yaffs_tagscompat.o yaffs_tagsvalidity.o +obj-$(CONFIG_YAFFS_FS) += yaffs_checkptrw.o yaffs_nand.o diff -urN linux-2.6.24.7/fs/yaffs2/devextras.h linux-2.6.24.7.new/fs/yaffs2/devextras.h --- linux-2.6.24.7/fs/yaffs2/devextras.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/devextras.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 @@ -15,7 +15,7 @@ /* * This file is just holds extra declarations used during development. - * Most of these are from kernel includes placed here so we can use them in + * Most of these are from kernel includes placed here so we can use them in * applications. * */ diff -urN linux-2.6.24.7/fs/yaffs2/moduleconfig.h linux-2.6.24.7.new/fs/yaffs2/moduleconfig.h --- linux-2.6.24.7/fs/yaffs2/moduleconfig.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/moduleconfig.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,10 +1,10 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 + * Created by Martin Fouts * * 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 @@ -44,21 +44,7 @@ /* 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. -*/ -/* Default: Not selected */ -/* Meaning: Use older-style on-NAND data format with pageStatus byte */ -#define CONFIG_YAFFS_9BYTE_TAGS +#define YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 #endif /* YAFFS_OUT_OF_TREE */ diff -urN linux-2.6.24.7/fs/yaffs2/utils/Makefile linux-2.6.24.7.new/fs/yaffs2/utils/Makefile --- linux-2.6.24.7/fs/yaffs2/utils/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7.new/fs/yaffs2/utils/Makefile 2009-04-21 15:01:02.000000000 +0200 @@ -0,0 +1,69 @@ +#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 +# +# 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$(KERNELDIR)/include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL + +include ../../../.config + +CFLAGS = -I../../../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 + +ifeq ($(CONFIG_YAFFS_ECC_RS), y) +CFLAGS+= -DCONFIG_YAFFS_ECC_RS +endif + +ifeq ($(CONFIG_YAFFS_ECC_HAMMING), y) +CFLAGS+= -DCONFIG_YAFFS_ECC_HAMMING +endif + + +## Change if you are using a cross-compiler +MAKETOOLS = #mipsel-linux- + +CC=$(MAKETOOLS)gcc + +COMMONLINKS = yaffs_ecc.c +COMMONOBJS = $(COMMONLINKS:.c=.o) + +ifeq ($(CONFIG_YAFFS_ECC_RS), y) +COMMONOBJS += ssfdc_rs_ecc.o +endif + +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 diff -urN linux-2.6.24.7/fs/yaffs2/utils/README linux-2.6.24.7.new/fs/yaffs2/utils/README --- linux-2.6.24.7/fs/yaffs2/utils/README 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7.new/fs/yaffs2/utils/README 2009-04-21 15:01:02.000000000 +0200 @@ -0,0 +1,11 @@ +This directory contains yaffs/yaffs2 tools to make the fs image. + +To build the tools, type 'make'. + +To make yaffs2 image, use next command: + + $ mkyaffs2image 1 /myroot myroot.yaffs2 + +To burn the yaffs2 image to the NAND, use next command: + + $ nandwrite -a -o /dev/mtd0 myroot.yaffs2 diff -urN linux-2.6.24.7/fs/yaffs2/utils/mkyaffs2image.c linux-2.6.24.7.new/fs/yaffs2/utils/mkyaffs2image.c --- linux-2.6.24.7/fs/yaffs2/utils/mkyaffs2image.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7.new/fs/yaffs2/utils/mkyaffs2image.c 2009-04-21 15:01:02.000000000 +0200 @@ -0,0 +1,738 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * + * makeyaffsimage.c + * + * Makes a YAFFS file system image that can be used to load up a file system. + * + * Copyright (C) 2002 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + * + * + * Nick Bane modifications flagged NCB + * + * Endian handling patches by James Ng. + * + * mkyaffs2image hacks by NCB + * + * Changes by Sergey Kubushin flagged KSI + * + */ + +/* KSI: + * All this nightmare should be rewritten from ground up. Why save return + * values if nobody checks them? The read/write function returns only one + * error, -1. Positive return value does NOT mean read/write operation has + * been completed successfully. If somebody opens files, he MUST close them + * when they are not longer needed. Only those brave enough can write 64 + * bytes from a yaffs_PackedTags2 structure. The list is too long, there is + * enough bugs here to write a couple of thick books on how NOT to write + * programs... + * + * And BTW, what was one supposed to do with that file that this horror + * occasionally managed to generate? + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "yaffs_ecc.h" +#include "yaffs_guts.h" + +#include "yaffs_packedtags2.h" + +unsigned yaffs_traceMask=0; + +#define MAX_OBJECTS 100000 +#define MAX_CHUNKSIZE 8192 +#define MAX_SPARESIZE 256 + +#define PT2_BYTES 25 + +const char * mkyaffsimage_c_version = "$Id: mkyaffs2image.c,v 1.1.1.1 2008-10-29 14:29:21 lhhuang Exp $"; + +static int chunkSize = 2048; +static int spareSize = 64; +static int layout_no; + +static struct nand_oobinfo oob_layout[] = { + /* KSI: + * Dummy "raw" layout - no ECC, all the bytes are free. Does NOT + * really work, only used for compatibility with CVS YAFFS2 that + * never ever worked with any stock MTD. + */ + { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 0, + .eccpos = {}, + .oobfree = { {0, 64} } + }, + /* KSI: + * Regular MTD AUTOPLACED ECC for large page NAND devices, the + * only one existing in stock MTD so far. It corresponds to layout# 1 + * in command line arguments. Any other layouts could be added to + * the list when they made their way in kernel's MTD. The structure + * is simply copied from kernel's drivers/mtd/nand/nand_base.c as-is. + */ + /* For 2KB pagesize NAND devices */ + { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 24, + .eccpos = { + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { {2, 38} } + }, + /* For 4KB pagesize NAND devices */ + { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 72, + .eccpos = { + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}, + .oobfree = { {2, 54} } + }, + /* For 4KB pagesize with 2 planes NAND devices */ + { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 72, + .eccpos = { + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}, + .oobfree = { {2, 54} } + }, + /* End-of-list marker */ + { + .useecc = -1, + } +}; + +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 = 0, nDirectories = 0, nPages = 0; + +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; +} + +/* KSI: + * No big endian for now. This is left for a later time. The existing code + * is FUBAR. + */ +#if 0 +/* 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 +} +#endif + +void nandmtd2_pt2buf(unsigned char *buf, yaffs_PackedTags2 *pt) +{ + int i, j = 0, k, n; + unsigned char pt2_byte_buf[PT2_BYTES]; + + *((unsigned int *) &pt2_byte_buf[0]) = pt->t.sequenceNumber; + *((unsigned int *) &pt2_byte_buf[4]) = pt->t.objectId; + *((unsigned int *) &pt2_byte_buf[8]) = pt->t.chunkId; + *((unsigned int *) &pt2_byte_buf[12]) = pt->t.byteCount; + pt2_byte_buf[16] = pt->ecc.colParity; + pt2_byte_buf[17] = pt->ecc.lineParity & 0xff; + pt2_byte_buf[18] = (pt->ecc.lineParity >> 8) & 0xff; + pt2_byte_buf[19] = (pt->ecc.lineParity >> 16) & 0xff; + pt2_byte_buf[20] = (pt->ecc.lineParity >> 24) & 0xff; + pt2_byte_buf[21] = pt->ecc.lineParityPrime & 0xff; + pt2_byte_buf[22] = (pt->ecc.lineParityPrime >> 8) & 0xff; + pt2_byte_buf[23] = (pt->ecc.lineParityPrime >> 16) & 0xff; + pt2_byte_buf[24] = (pt->ecc.lineParityPrime >> 24) & 0xff; + + k = oob_layout[layout_no].oobfree[j][0]; + n = oob_layout[layout_no].oobfree[j][1]; + + if (n == 0) { + fprintf(stderr, "No OOB space for tags"); + exit(-1); + } + + for (i = 0; i < PT2_BYTES; i++) { + if (n == 0) { + j++; + k = oob_layout[layout_no].oobfree[j][0]; + n = oob_layout[layout_no].oobfree[j][1]; + if (n == 0) { + fprintf(stderr, "No OOB space for tags"); + exit(-1); + } + } + buf[k++] = pt2_byte_buf[i]; + n--; + } +} + +static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes) +{ + yaffs_ExtendedTags t; + yaffs_PackedTags2 pt; + unsigned char spare_buf[MAX_SPARESIZE]; + + + 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; + +/* KSI: Broken anyway -- e.g. &t is pointer to a wrong type... */ +#if 0 + if (convert_endian) + { + little_to_big_endian(&t); + } +#endif + + nPages++; + + yaffs_PackTags2(&pt,&t); + + memset(spare_buf, 0xff, spareSize); + + if (layout_no == 0) { + memcpy(spare_buf, &pt, sizeof(yaffs_PackedTags2)); + } else { + nandmtd2_pt2buf(spare_buf, &pt); + } + + return write(outFile,spare_buf,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)) + +/* KSI: Removed for now. TBD later when the proper util (from scratch) is written */ +#if 0 +// 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 +} +#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[MAX_CHUNKSIZE]; + + + yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes; + + memset(bytes,0xff,chunkSize); + + 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); + } + +/* KSI: FUBAR. Left for a leter time. */ +#if 0 + if (convert_endian) + { + object_header_little_to_big_endian(oh); + } +#endif + + 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[MAX_CHUNKSIZE]; + int nBytes; + int chunk = 0; + + h = open(full_name,O_RDONLY); + if(h >= 0) + { + memset(bytes,0xff,chunkSize); + while((nBytes = read(h,bytes,chunkSize)) > 0) + { + chunk++; + write_chunk(bytes,newObj,chunk,nBytes); + memset(bytes,0xff,chunkSize); + } + if(nBytes < 0) + error = nBytes; + + printf("%d data chunks written\n",chunk); + close(h); + } + else + { + perror("Error opening file"); + } + + } + + } + 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"); + } + } + } + /* KSI: + * Who is supposed to close those open directories in this + * recursive function, lord Byron? Stock "ulimit -n" is 1024 + * and e.g. stock Fedora /etc directory has more that 1024 + * directories... + */ + closedir(dir); + } + + return 0; + +} + +void usage(void) +{ + /* ECC for oob should conform with CONFIG_YAFFS_ECC_XX when building linux kernel, but ecc + for oob isn't required when using BCH ECC, as oob will be corrected together with data + when using BCH ECC. */ +#if defined(CONFIG_YAFFS_ECC_RS) + printf("Reed-solomn ECC will be used for checking 16 bytes for yaffs2 information in oob area.\n" + "so, CONFIG_YAFFS_ECC_RS should be selected when building linux kernel.\n"); +#elif defined(CONFIG_YAFFS_ECC_HAMMING) + printf("Hamming ECC will be used for checking 16 bytes for yaffs2 information in oob area.\n" + "so, CONFIG_YAFFS_ECC_HAMMING should be selected when building linux kernel.\n"); +#endif + + printf("usage: mkyaffs2image layout# dir image_file [convert]\n"); + printf("\n" + " layout# NAND OOB layout:\n" + " 0 - nand_oob_raw, no used, \n" + " 1 - nand_oob_64, for 2KB pagesize, \n" + " 2 - nand_oob_128, for 2KB pagesize using multiple planes or 4KB pagesize,\n" + " 3 - nand_oob_256, for 4KB pagesize using multiple planes\n"); + printf(" dir the directory tree to be converted\n"); + printf(" image_file the output file to hold the image\n"); + printf(" 'convert' make a big-endian img on a little-endian machine. BROKEN !\n"); + printf("\n Example:\n" + " mkyaffs2image 1 /nfsroot/root26 root26.yaffs2 \n" +); + + exit(1); +} + +int main(int argc, char *argv[]) +{ + struct stat stats; + int i; + + printf("mkyaffs2image: image building tool for YAFFS2 built "__DATE__"\n"); + + if ((argc < 4) || (sscanf(argv[1], "%u", &layout_no) != 1)) + { + usage(); + } + + switch (layout_no) { + case 0: + printf("Warning: it isn't used by JZSOC!\n"); + break; + case 1: + chunkSize = 2048; + spareSize = 64; + break; + case 2: + chunkSize = 4096; + spareSize = 128; + break; + case 3: + chunkSize = 8192; + spareSize = 256; + break; + default: + usage(); + } + + i = 0; + + while (oob_layout[i].useecc != -1) + i++; + + if (layout_no >= i) + usage(); + + if ((argc == 5) && (!strncmp(argv[4], "convert", strlen("convert")))) + { + /* KSI: Broken as of now. TBD. Fail. */ + usage(); + convert_endian = 1; + } + + if(stat(argv[2],&stats) < 0) + { + printf("Could not stat %s\n",argv[2]); + exit(1); + } + + if(!S_ISDIR(stats.st_mode)) + { + printf(" %s is not a directory\n",argv[2]); + exit(1); + } + + outFile = open(argv[3],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE); + + + if(outFile < 0) + { + printf("Could not open output file %s\n",argv[3]); + exit(1); + } + + printf("Processing directory %s into image file %s\n",argv[2],argv[3]); + error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL); + + if(error) + error = process_directory(YAFFS_OBJECTID_ROOT,argv[2]); + + 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); +} + diff -urN linux-2.6.24.7/fs/yaffs2/utils/mkyaffsimage.c linux-2.6.24.7.new/fs/yaffs2/utils/mkyaffsimage.c --- linux-2.6.24.7/fs/yaffs2/utils/mkyaffsimage.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7.new/fs/yaffs2/utils/mkyaffsimage.c 2009-04-21 15:01:02.000000000 +0200 @@ -0,0 +1,593 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * + * makeyaffsimage.c + * + * Makes a YAFFS file system image that can be used to load up a file system. + * + * Copyright (C) 2002 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + * + * + * Nick Bane modifications flagged NCB + * + * Endian handling patches by James Ng. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "yaffs_ecc.h" +#include "yaffs_guts.h" + + +#define MAX_OBJECTS 10000 + +const char * mkyaffsimage_c_version = "$Id: mkyaffsimage.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $"; + + +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.byteCount = 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); +} + diff -urN linux-2.6.24.7/fs/yaffs2/utils/ssfdc_rs_ecc.c linux-2.6.24.7.new/fs/yaffs2/utils/ssfdc_rs_ecc.c --- linux-2.6.24.7/fs/yaffs2/utils/ssfdc_rs_ecc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7.new/fs/yaffs2/utils/ssfdc_rs_ecc.c 2009-04-21 15:01:02.000000000 +0200 @@ -0,0 +1,180 @@ +/* Reed-Solomon decoder + * Copyright 2002 Phil Karn, KA9Q + * May be used under the terms of the GNU Lesser General Public License (LGPL) + */ +#include "ssfdc_rs_ecc.h" + +#include + +struct CONV_DATA { + unsigned char shift0; + unsigned char mask0; + unsigned char mask1; + unsigned char merge_shift; +} ConvData [8]= { + {0x0, 0xff, 0x01, 0x8}, /* 0 */ + {0x1, 0x7f, 0x03, 0x7}, /* 1 */ + {0x2, 0x3f, 0x07, 0x6}, /* 2 */ + {0x3, 0x1f, 0x0f, 0x5}, /* 3 */ + {0x4, 0x0f, 0x1f, 0x4}, /* 4 */ + {0x5, 0x07, 0x3f, 0x3}, /* 5 */ + {0x6, 0x03, 0x7f, 0x2}, /* 6 */ + {0x7, 0x01, 0xff, 0x1}, /* 7 */ +}; + +static void kfree(void *ptr) +{ +// return 0; +} + +static int modnn(struct rs *rs,int x) +{ + while (x >= rs->nn) { + x -= rs->nn; + x = (x >> rs->mm) + (x & rs->nn); + } + return x; +} + +void encode_rs(void *p,data_t *data, unsigned short *bb) +{ + struct rs *rs = (struct rs *)p; + int i, j; + data_t feedback; + + memset(bb,0,(rs->nroots)*sizeof(unsigned short)); + + for(i=0;i<(rs->nn)-(rs->nroots)-(rs->pad);i++){ + + feedback = (rs->index_of)[data[i] ^ bb[0]]; + if(feedback != ((rs->nn))){ + for(j=1;j<(rs->nroots);j++) + bb[j] ^= (rs->alpha_to)[modnn(rs,feedback + (rs->genpoly)[(rs->nroots)-j])]; + } + + memmove(&bb[0],&bb[1],sizeof(unsigned short)*((rs->nroots)-1)); + + if(feedback != ((rs->nn))) { + bb[(rs->nroots)-1] = (rs->alpha_to)[modnn(rs,feedback + (rs->genpoly)[0])]; + } + else + bb[(rs->nroots)-1] = 0; + } + +} + +void free_rs_int(void *p) +{ + struct rs *rs = (struct rs *)p; + + free(rs->alpha_to); + free(rs->index_of); + free(rs->genpoly); + free(rs); +} + +/* + * init_rs_int - Initialize a Reed-Solomon codec + * @symsize: symbol size + * @gfpoly: Field generator polynomial coefficients + * @fcr: first root of RS code generator polynomial, index form + * @prim: primitive element to generate polynomial roots + * @nroots: RS code generator polynomial degree (number of roots) + */ +struct rs *init_rs_int(int symsize,int gfpoly,int fcr,int prim,int nroots,int pad) +{ + struct rs *rs; +#if 0 + static unsigned int rs0[64]={0}; + static data_t alpha0[512]={0}; + static data_t index0[512]={0}; + static data_t genepoly0[9]={0}; +#endif + int i, j, sr,root,iprim; + + rs = ((void *)0); + if(symsize < 0 || symsize > 8*sizeof(data_t)){ + goto done; + } + + if(fcr < 0 || fcr >= (1<= (1<= (1<= ((1<mm = symsize; + rs->nn = (1<pad = pad; + rs->alpha_to = (data_t *)malloc(sizeof(data_t)*(rs->nn+1)); +// rs->alpha_to = alpha0; + if(rs->alpha_to == ((void *)0)){ + kfree(rs); + rs = ((void *)0); + goto done; + } + rs->index_of = (data_t *)malloc(sizeof(data_t)*(rs->nn+1)); +// rs->index_of = index0; + if(rs->index_of == ((void *)0)){ + kfree(rs->alpha_to); + kfree(rs); + rs = ((void *)0); + goto done; + } + rs->index_of[0] = ((rs->nn)); + rs->alpha_to[((rs->nn))] = 0; + sr = 1; + for(i=0;inn;i++){ + rs->index_of[sr] = i; + rs->alpha_to[i] = sr; + sr <<= 1; + if(sr & (1<nn; + } + if(sr != 1){ + kfree(rs->alpha_to); + kfree(rs->index_of); + kfree(rs); + rs = ((void *)0); + goto done; + } + rs->genpoly = (data_t *)malloc(sizeof(data_t)*(nroots+1)); +// rs->genpoly = genepoly0; + if(rs->genpoly == ((void *)0)){ + kfree(rs->alpha_to); + kfree(rs->index_of); + kfree(rs); + rs = ((void *)0); + goto done; + } + rs->fcr = fcr; + rs->prim = prim; + rs->nroots = nroots; + for(iprim=1;(iprim % prim) != 0;iprim += rs->nn) + ; + rs->iprim = iprim / prim; + rs->genpoly[0] = 1; + for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) { + rs->genpoly[i+1] = 1; + for (j = i; j > 0; j--){ + if (rs->genpoly[j] != 0) + rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)]; + else + rs->genpoly[j] = rs->genpoly[j-1]; + } + rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)]; + } + for (i = 0; i <= nroots; i++) + rs->genpoly[i] = rs->index_of[rs->genpoly[i]]; + done:; + return rs; +} + diff -urN linux-2.6.24.7/fs/yaffs2/utils/ssfdc_rs_ecc.h linux-2.6.24.7.new/fs/yaffs2/utils/ssfdc_rs_ecc.h --- linux-2.6.24.7/fs/yaffs2/utils/ssfdc_rs_ecc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7.new/fs/yaffs2/utils/ssfdc_rs_ecc.h 2009-04-21 15:01:02.000000000 +0200 @@ -0,0 +1,29 @@ +#ifndef __SSFDC_RS_ECC_H__ +#define __SSFDC_RS_ECC_H__ + +/* Stuff common to all the general-purpose Reed-Solomon codecs + * Copyright 2004 Phil Karn, KA9Q + * May be used under the terms of the GNU Lesser General Public License (LGPL) + */ + +/* Reed-Solomon codec control block */ +typedef unsigned char data_t; + +struct rs { + int mm; /* Bits per symbol */ + int nn; /* Symbols per block (= (1<nErasedBlocks - dev->nReservedBlocks; - + T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpt blocks available = %d" TENDSTR), blocksAvailable)); - - + + return (blocksAvailable <= 0) ? 0 : 1; } + static int yaffs_CheckpointErase(yaffs_Device *dev) { - + int i; + - - if(!dev->eraseBlockInNAND) + if(!dev->eraseBlockInNAND) return 0; T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR), dev->internalStartBlock,dev->internalEndBlock)); - + for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){ @@ -58,9 +59,9 @@ } } } - + dev->blocksInCheckpoint = 0; - + return 1; } @@ -72,11 +73,11 @@ T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock)); - + if(dev->checkpointNextBlock >= 0 && dev->checkpointNextBlock <= dev->internalEndBlock && blocksAvailable > 0){ - + for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){ @@ -88,7 +89,7 @@ } } T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR))); - + dev->checkpointNextBlock = -1; dev->checkpointCurrentBlock = -1; } @@ -97,19 +98,19 @@ { int i; yaffs_ExtendedTags tags; - + T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR), dev->blocksInCheckpoint, dev->checkpointNextBlock)); - - if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks) + + if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks) for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){ int chunk = i * dev->nChunksPerBlock; int realignedChunk = chunk - dev->chunkOffset; dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags); - T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR), + T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR), i, tags.objectId,tags.sequenceNumber,tags.eccResult)); - + if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){ /* Right kind of block */ dev->checkpointNextBlock = tags.objectId; @@ -130,7 +131,7 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) { - + /* Got the functions we need? */ if (!dev->writeChunkWithTagsToNAND || !dev->readChunkWithTagsFromNAND || @@ -140,31 +141,29 @@ if(forWriting && !yaffs_CheckpointSpaceOk(dev)) return 0; - + if(!dev->checkpointBuffer) dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk); if(!dev->checkpointBuffer) return 0; - + dev->checkpointPageSequence = 0; - + dev->checkpointOpenForWrite = forWriting; - + dev->checkpointByteCount = 0; - dev->checkpointSum = 0; - dev->checkpointXor = 0; dev->checkpointCurrentBlock = -1; dev->checkpointCurrentChunk = -1; dev->checkpointNextBlock = dev->internalStartBlock; - + /* Erase all the blocks in the checkpoint area */ if(forWriting){ memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk); dev->checkpointByteOffset = 0; return yaffs_CheckpointErase(dev); - - + + } else { int i; /* Set to a value that will kick off a read */ @@ -177,15 +176,7 @@ for(i = 0; i < dev->checkpointMaxBlocks; i++) dev->checkpointBlockList[i] = -1; } - - return 1; -} - -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) -{ - __u32 compositeSum; - compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF); - *sum = compositeSum; + return 1; } @@ -196,15 +187,15 @@ int realignedChunk; yaffs_ExtendedTags tags; - + if(dev->checkpointCurrentBlock < 0){ yaffs_CheckpointFindNextErasedBlock(dev); dev->checkpointCurrentChunk = 0; } - + if(dev->checkpointCurrentBlock < 0) return 0; - + tags.chunkDeleted = 0; tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */ tags.chunkId = dev->checkpointPageSequence + 1; @@ -217,25 +208,25 @@ bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; dev->blocksInCheckpoint++; } - + chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; - + T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), - chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId)); - + chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId)); + realignedChunk = chunk - dev->chunkOffset; - + dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags); dev->checkpointByteOffset = 0; - dev->checkpointPageSequence++; + dev->checkpointPageSequence++; dev->checkpointCurrentChunk++; if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){ dev->checkpointCurrentChunk = 0; dev->checkpointCurrentBlock = -1; } memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk); - + return 1; } @@ -245,37 +236,31 @@ int i=0; int ok = 1; - + __u8 * dataBytes = (__u8 *)data; - - + + if(!dev->checkpointBuffer) return 0; - if(!dev->checkpointOpenForWrite) - return -1; - while(i < nBytes && ok) { + - - - dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ; - dev->checkpointSum += *dataBytes; - dev->checkpointXor ^= *dataBytes; - + + dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ; dev->checkpointByteOffset++; i++; dataBytes++; dev->checkpointByteCount++; - - + + if(dev->checkpointByteOffset < 0 || - dev->checkpointByteOffset >= dev->nDataBytesPerChunk) + dev->checkpointByteOffset >= dev->nDataBytesPerChunk) ok = yaffs_CheckpointFlushBuffer(dev); } - + return i; } @@ -285,44 +270,41 @@ int ok = 1; yaffs_ExtendedTags tags; - + int chunk; int realignedChunk; __u8 *dataBytes = (__u8 *)data; - + if(!dev->checkpointBuffer) return 0; - if(dev->checkpointOpenForWrite) - return -1; - while(i < nBytes && ok) { - - + + if(dev->checkpointByteOffset < 0 || dev->checkpointByteOffset >= dev->nDataBytesPerChunk) { - + if(dev->checkpointCurrentBlock < 0){ yaffs_CheckpointFindNextCheckpointBlock(dev); dev->checkpointCurrentChunk = 0; } - + if(dev->checkpointCurrentBlock < 0) ok = 0; else { - - chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + + + chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; realignedChunk = chunk - dev->chunkOffset; /* read in the next chunk */ /* printf("read checkpoint page %d\n",dev->checkpointPage); */ - dev->readChunkWithTagsFromNAND(dev, realignedChunk, + dev->readChunkWithTagsFromNAND(dev, realignedChunk, dev->checkpointBuffer, &tags); - + if(tags.chunkId != (dev->checkpointPageSequence + 1) || tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA) ok = 0; @@ -330,30 +312,28 @@ dev->checkpointByteOffset = 0; dev->checkpointPageSequence++; dev->checkpointCurrentChunk++; - + if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock) dev->checkpointCurrentBlock = -1; } } - + if(ok){ *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset]; - dev->checkpointSum += *dataBytes; - dev->checkpointXor ^= *dataBytes; dev->checkpointByteOffset++; i++; dataBytes++; dev->checkpointByteCount++; } } - + return i; } int yaffs_CheckpointClose(yaffs_Device *dev) { - if(dev->checkpointOpenForWrite){ + if(dev->checkpointOpenForWrite){ if(dev->checkpointByteOffset != 0) yaffs_CheckpointFlushBuffer(dev); } else { @@ -373,19 +353,19 @@ dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock; dev->nErasedBlocks -= dev->blocksInCheckpoint; - + T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR), dev->checkpointByteCount)); - + if(dev->checkpointBuffer){ - /* free the buffer */ + /* free the buffer */ YFREE(dev->checkpointBuffer); dev->checkpointBuffer = NULL; return 1; } else return 0; - + } int yaffs_CheckpointInvalidateStream(yaffs_Device *dev) diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_checkptrw.h linux-2.6.24.7.new/fs/yaffs2/yaffs_checkptrw.h --- linux-2.6.24.7/fs/yaffs2/yaffs_checkptrw.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_checkptrw.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 @@ -24,8 +24,6 @@ int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes); -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); - int yaffs_CheckpointClose(yaffs_Device *dev); int yaffs_CheckpointInvalidateStream(yaffs_Device *dev); diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_ecc.c linux-2.6.24.7.new/fs/yaffs2/yaffs_ecc.c --- linux-2.6.24.7/fs/yaffs2/yaffs_ecc.c 2009-04-21 14:57:10.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_ecc.c 2009-04-21 15:01:02.000000000 +0200 @@ -14,9 +14,9 @@ /* * This code implements the ECC algorithm used in SmartMedia. * - * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. * The two unused bit are set to 1. - * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC * blocks are used on a 512-byte NAND page. * */ @@ -29,7 +29,7 @@ */ const char *yaffs_ecc_c_version = - "$Id: yaffs_ecc.c,v 1.9 2007-02-14 01:09:06 wookey Exp $"; + "$Id: yaffs_ecc.c,v 1.2 2008-07-17 23:07:00 lhhuang Exp $"; #include "yportenv.h" @@ -83,17 +83,6 @@ return r; } -static int yaffs_CountBits32(unsigned x) -{ - int r = 0; - while (x) { - if (x & 1) - r++; - x >>= 1; - } - return r; -} - /* Calculate the ECC for a 256-byte block of data */ void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc) { @@ -228,8 +217,8 @@ return 1; /* Corrected the error */ } - if ((yaffs_CountBits(d0) + - yaffs_CountBits(d1) + + if ((yaffs_CountBits(d0) + + yaffs_CountBits(d1) + yaffs_CountBits(d2)) == 1) { /* Reccoverable error in ecc */ @@ -239,13 +228,115 @@ return 1; /* Corrected the error */ } - + /* Unrecoverable error */ return -1; } +#if defined(CONFIG_YAFFS_ECC_RS) +#ifdef __KERNEL__ +#include +struct rs_control *rs_decoder; +#else +#include "ssfdc_rs_ecc.h" +void *rs_init_user; +#endif + +/* Transfer 16 bytes to 26 5-bit symbols */ +void Data2Sym(const unsigned char *in, unsigned char *out) +{ + int i, j, shift; + + for (i = 0; i < 26; i++){ + j = (5 * i) >> 3; + shift = (5 * i) & 0x7; + if (shift > 3) + out[i] = ((in[j] >> shift) | (in[j+1] << (8 - shift))) & 0x1f; + else + out[i] = (in[j] >> shift) & 0x1f; + } + out[25] &= 0x7; /* the last symbol has only 3 bits */ +} + +/* + * It does reed solomon ECC calcs on 16 bytes of oob data + */ +void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes, + yaffs_ECCOther * eccOther) +{ + unsigned short *par = (unsigned short *)&eccOther->lineParity; + unsigned char data5[26]; + + + Data2Sym(data, data5); + memset(par, 0, 8); + +#ifdef __KERNEL__ + /* Encode 26 symbols in data5. Store parities of 4 symbols in + * buffer par whose size is 8 bytes(2 bytes per symbol) */ + encode_rs8 (rs_decoder, data5, 26, par, 0); +#else + /* init reed solomon ECC for nand oob area + * Symbolsize is 5 (bits) + * Primitive polynomial is x^5+x^2+1 + * first consecutive root is 0 + * primitive element to generate roots = 1 + * generator polynomial degree (number of roots) = 4 + * pad = (1<lineParity; + unsigned char data5[26]; + int numerr; + + Data2Sym(data, data5); + + /* Decode 26 symbols in data5. */ + numerr = decode_rs8 (rs_decoder, data5, par, 26, NULL, 0, NULL, 0, NULL); + + if (numerr == 0) + return 0; + else if (numerr > 0 && numerr < 3) + return 1; + else + return -1; +} +#else +int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, + yaffs_ECCOther * read_ecc, + const yaffs_ECCOther * test_ecc) +{ + return 0; +} +#endif + +#else + +static int yaffs_CountBits32(unsigned x) +{ + int r = 0; + while (x) { + if (x & 1) + r++; + x >>= 1; + } + return r; +} /* * ECCxxxOther does ECC calcs on arbitrary n bytes of data @@ -293,7 +384,7 @@ if ((cDelta | lDelta | lDeltaPrime) == 0) return 0; /* no error */ - if (lDelta == ~lDeltaPrime && + if (lDelta == ~lDeltaPrime && (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) { /* Single bit (recoverable) error in data */ @@ -309,7 +400,7 @@ if(lDelta >= nBytes) return -1; - + data[lDelta] ^= (1 << bit); return 1; /* corrected */ @@ -328,4 +419,4 @@ return -1; } - +#endif /* YAFFS_ECC_RS */ diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_ecc.h linux-2.6.24.7.new/fs/yaffs2/yaffs_ecc.h --- linux-2.6.24.7/fs/yaffs2/yaffs_ecc.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_ecc.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 @@ -16,9 +16,9 @@ /* * This code implements the ECC algorithm used in SmartMedia. * - * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. * The two unused bit are set to 1. - * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC * blocks are used on a 512-byte NAND page. * */ @@ -32,6 +32,10 @@ unsigned lineParityPrime; } yaffs_ECCOther; +#if defined(CONFIG_YAFFS_ECC_RS) +extern struct rs_control *rs_decoder; +#endif + void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc); int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, const unsigned char *test_ecc); diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_fs.c linux-2.6.24.7.new/fs/yaffs2/yaffs_fs.c --- linux-2.6.24.7/fs/yaffs2/yaffs_fs.c 2009-04-21 14:57:10.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_fs.c 2009-04-21 15:01:02.000000000 +0200 @@ -23,7 +23,7 @@ * This is the file system front-end to YAFFS that hooks it up to * the VFS. * - * Special notes: + * 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 @@ -32,7 +32,7 @@ */ const char *yaffs_fs_c_version = - "$Id: yaffs_fs.c,v 1.63 2007-09-19 20:35:40 imcd Exp $"; + "$Id: yaffs_fs.c,v 1.2 2008-07-17 23:59:16 lhhuang Exp $"; extern const char *yaffs_guts_c_version; #include @@ -76,34 +76,23 @@ #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 - #include #include "yportenv.h" #include "yaffs_guts.h" +unsigned yaffs_traceMask = YAFFS_TRACE_ALWAYS | + YAFFS_TRACE_BAD_BLOCKS/* | + YAFFS_TRACE_CHECKPOINT*/ + /* | 0xFFFFFFFF */; + #include #include "yaffs_mtdif.h" -#include "yaffs_mtdif1.h" #include "yaffs_mtdif2.h" -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS; -unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; - -/* Module Parameters */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) -module_param(yaffs_traceMask,uint,0644); -module_param(yaffs_wr_attempts,uint,0644); -#else -MODULE_PARM(yaffs_traceMask,"i"); -MODULE_PARM(yaffs_wr_attempts,"i"); +#if defined(CONFIG_YAFFS_ECC_RS) +#include +#include "yaffs_ecc.h" #endif /*#define T(x) printk x */ @@ -174,6 +163,8 @@ static int yaffs_write_super(struct super_block *sb); #endif +static int yaffs_remount_fs(struct super_block *, int *, char *); + #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)) @@ -213,45 +204,24 @@ .commit_write = yaffs_commit_write, }; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)) -static 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, -}; - -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) - static struct file_operations yaffs_file_operations = { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) .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 struct file_operations yaffs_file_operations = { .read = generic_file_read, .write = generic_file_write, +#endif .mmap = generic_file_mmap, .flush = yaffs_file_flush, .fsync = yaffs_sync_object, -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) .sendfile = generic_file_sendfile, #endif + }; -#endif static struct inode_operations yaffs_file_inode_operations = { .setattr = yaffs_setattr, @@ -287,6 +257,7 @@ .read_inode = yaffs_read_inode, .put_inode = yaffs_put_inode, .put_super = yaffs_put_super, + .remount_fs = yaffs_remount_fs, .delete_inode = yaffs_delete_inode, .clear_inode = yaffs_clear_inode, .sync_fs = yaffs_sync_fs, @@ -391,7 +362,7 @@ 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); @@ -429,6 +400,42 @@ } +static int yaffs_dump_dev1(yaffs_Device * dev) +{ + printk("startBlock......... %d\n", dev->startBlock); + printk("endBlock........... %d\n", dev->endBlock); + printk("chunkGroupBits..... %d\n", dev->chunkGroupBits); + printk("chunkGroupSize..... %d\n", dev->chunkGroupSize); + printk("nErasedBlocks...... %d\n", dev->nErasedBlocks); + printk("nTnodesCreated..... %d\n", dev->nTnodesCreated); + printk("nFreeTnodes........ %d\n", dev->nFreeTnodes); + printk("nObjectsCreated.... %d\n", dev->nObjectsCreated); + printk("nFreeObjects....... %d\n", dev->nFreeObjects); + printk("nFreeChunks........ %d\n", dev->nFreeChunks); + printk("nPageWrites........ %d\n", dev->nPageWrites); + printk("nPageReads......... %d\n", dev->nPageReads); + printk("nBlockErasures..... %d\n", dev->nBlockErasures); + printk("nGCCopies.......... %d\n", dev->nGCCopies); + printk("garbageCollections. %d\n", dev->garbageCollections); + + printk("passiveGCs......... %d\n", dev->passiveGarbageCollections); + printk("nRetriedWrites..... %d\n", dev->nRetriedWrites); + printk("nRetireBlocks...... %d\n", dev->nRetiredBlocks); + printk("eccFixed........... %d\n", dev->eccFixed); + printk("eccUnfixed......... %d\n", dev->eccUnfixed); + printk("tagsEccFixed....... %d\n", dev->tagsEccFixed); + printk("tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed); + printk("cacheHits.......... %d\n", dev->cacheHits); + printk("nDeletedFiles...... %d\n", dev->nDeletedFiles); + printk("nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles); + printk("nBackgroudDeletions %d\n", dev->nBackgroundDeletions); + printk("useNANDECC......... %d\n", dev->useNANDECC); + printk("isYaffs2........... %d\n", dev->isYaffs2); + + return 1; +} + + /* For now put inode is just for debugging * Put inode is called when the inode **structure** is put. */ @@ -729,21 +736,21 @@ 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 : @@ -1020,7 +1027,7 @@ int error = -ENOSPC; uid_t uid = current->fsuid; gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; - + if((dir->i_mode & S_ISGID) && S_ISDIR(mode)) mode |= S_ISGID; @@ -1075,7 +1082,7 @@ obj = NULL; /* Do we ever get here? */ break; } - + /* Can not call yaffs_get_inode() with gross lock held */ yaffs_GrossUnlock(dev); @@ -1264,13 +1271,13 @@ target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir), new_dentry->d_name.name); - - + + if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && !list_empty(&target->variant.directoryVariant.children)) { - + T(YAFFS_TRACE_OS, (KERN_DEBUG "target is non-empty dir\n")); retVal = YAFFS_FAIL; @@ -1278,7 +1285,7 @@ /* Now does unlinking internally using shadowing mechanism */ T(YAFFS_TRACE_OS, (KERN_DEBUG "calling yaffs_RenameObject\n")); - + retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir), old_dentry->d_name.name, @@ -1390,7 +1397,7 @@ if(dev) yaffs_CheckpointSave(dev); - + yaffs_GrossUnlock(dev); sb->s_dirt = 0; @@ -1421,16 +1428,16 @@ { T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n")); - + return 0; /* yaffs_do_sync_fs(sb);*/ - + } 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 + * we had to release the lock to prevent deadlocks, so * need to lock again. */ @@ -1441,7 +1448,7 @@ (KERN_DEBUG "yaffs_read_inode for %d\n", (int)inode->i_ino)); yaffs_GrossLock(dev); - + obj = yaffs_FindObjectByNumber(dev, inode->i_ino); yaffs_FillInodeFromObject(inode, obj); @@ -1451,36 +1458,34 @@ static LIST_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, (KERN_DEBUG "yaffs_remount_fs: %s: RO\n", dev->name )); yaffs_GrossLock(dev); - + yaffs_FlushEntireDeviceCache(dev); - + yaffs_CheckpointSave(dev); - + if (mtd->sync) mtd->sync(mtd); yaffs_GrossUnlock(dev); } else { - T(YAFFS_TRACE_OS, + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_remount_fs: %s: RW\n", dev->name )); } - + return 0; } -#endif static void yaffs_put_super(struct super_block *sb) { @@ -1489,7 +1494,7 @@ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_put_super\n")); yaffs_GrossLock(dev); - + yaffs_FlushEntireDeviceCache(dev); yaffs_CheckpointSave(dev); @@ -1499,12 +1504,12 @@ } yaffs_Deinitialise(dev); - + yaffs_GrossUnlock(dev); /* we assume this is protected by lock_kernel() in mount/umount */ list_del(&dev->devList); - + if(dev->spareBuffer){ YFREE(dev->spareBuffer); dev->spareBuffer = NULL; @@ -1530,61 +1535,12 @@ static void yaffs_MarkSuperBlockDirty(void *vsb) { struct super_block *sb = (struct super_block *)vsb; - + T(YAFFS_TRACE_OS, (KERN_DEBUG "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; -} yaffs_options; - -#define MAX_OPT_LEN 20 -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 != ','){ - 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,"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) @@ -1596,9 +1552,6 @@ 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; @@ -1614,19 +1567,6 @@ 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)); @@ -1670,14 +1610,18 @@ 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))); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + T(YAFFS_TRACE_OS, (" writesize %d\n", mtd->writesize)); +#else + T(YAFFS_TRACE_OS, (" oobblock %d\n", mtd->oobblock)); +#endif T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize)); T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize)); - T(YAFFS_TRACE_OS, (" size %d\n", mtd->size)); - + T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size)); + #ifdef CONFIG_YAFFS_AUTO_YAFFS2 - if (yaffsVersion == 1 && + if (yaffsVersion == 1 && #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) mtd->writesize >= 2048) { #else @@ -1685,10 +1629,10 @@ #endif T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n")); yaffsVersion = 2; - } - + } + /* Added NCB 26/5/2006 for completeness */ - if (yaffsVersion == 2 && + if (yaffsVersion == 2 && #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) mtd->writesize == 512) { #else @@ -1696,7 +1640,7 @@ #endif T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n")); yaffsVersion = 1; - } + } #endif @@ -1747,7 +1691,11 @@ return NULL; } - if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + if (mtd->writesize < YAFFS_BYTES_PER_CHUNK || +#else + if (mtd->oobblock < YAFFS_BYTES_PER_CHUNK || +#endif mtd->oobsize != YAFFS_BYTES_PER_SPARE) { T(YAFFS_TRACE_ALWAYS, ("yaffs: MTD device does not support have the " @@ -1779,17 +1727,14 @@ dev->name = mtd->name; /* Set up the memory size parameters.... */ - - nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK); - dev->startBlock = 0; - dev->endBlock = nBlocks - 1; dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK; dev->nReservedBlocks = 5; - dev->nShortOpCaches = (options.no_cache) ? 0 : 10; + dev->nShortOpCaches = 10; /* Enable short op caching */ /* ... and the functions. */ if (yaffsVersion == 2) { + int block_shift; dev->writeChunkWithTagsToNAND = nandmtd2_WriteChunkWithTagsToNAND; dev->readChunkWithTagsFromNAND = @@ -1805,24 +1750,18 @@ dev->nDataBytesPerChunk = mtd->oobblock; dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; #endif - nBlocks = mtd->size / mtd->erasesize; - + block_shift = ffs(mtd->erasesize) - 1; +// nBlocks = mtd->size / mtd->erasesize; + nBlocks = mtd->size >> block_shift; dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS; 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 + nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK); + dev->startBlock = 0; + dev->endBlock = nBlocks - 1; dev->writeChunkToNAND = nandmtd_WriteChunkToNAND; dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND; -#endif dev->isYaffs2 = 0; } /* ... and common functions */ @@ -1830,10 +1769,10 @@ dev->initialiseNAND = nandmtd_InitialiseNAND; dev->putSuperFunc = yaffs_MTDPutSuper; - + dev->superBlock = (void *)sb; dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; - + #ifndef CONFIG_YAFFS_DOES_ECC dev->useNANDECC = 1; @@ -1843,9 +1782,6 @@ 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 */ list_add_tail(&dev->devList, &yaffs_dev_list); @@ -1858,7 +1794,7 @@ 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); @@ -1869,7 +1805,6 @@ if (!inode) return NULL; - inode->i_op = &yaffs_dir_inode_operations; inode->i_fop = &yaffs_dir_operations; @@ -1884,7 +1819,6 @@ return NULL; } sb->s_root = root; - T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n")); return sb; } @@ -1990,13 +1924,9 @@ { buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock); buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); - 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, "nCheckptResBlocks.. %d\n", dev->nCheckpointReservedBlocks); - 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); @@ -2012,7 +1942,6 @@ 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); @@ -2075,7 +2004,6 @@ /** * 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 { @@ -2087,7 +2015,6 @@ {"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}, @@ -2099,27 +2026,17 @@ {"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(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]; + char *end, *mask_name; int i; int done = 0; int add, len = 0; @@ -2146,22 +2063,16 @@ 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 1){ if(x & 1) extraBits++; x>>=1; nShifts++; } - if(extraBits) + if(extraBits) nShifts++; - + return nShifts; } /* Function to return the number of shifts to get a 1 in bit 0 */ - + static __u32 ShiftDiv(__u32 x) { int nShifts; - + nShifts = 0; - + if(!x) return 0; - + while( !(x&1)){ x>>=1; nShifts++; } - + return nShifts; } -/* +/* * Temporary buffer manipulations. */ -static int yaffs_InitialiseTempBuffers(yaffs_Device *dev) -{ - int i; - __u8 *buf = (__u8 *)1; - - memset(dev->tempBuffer,0,sizeof(dev->tempBuffer)); - - for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { - dev->tempBuffer[i].line = 0; /* not in use */ - dev->tempBuffer[i].buffer = buf = - YMALLOC_DMA(dev->nDataBytesPerChunk); - } - - return buf ? YAFFS_OK : YAFFS_FAIL; - -} - static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo) { int i, j; @@ -290,8 +264,6 @@ return 0; } - - /* * Chunk bitmap manipulations */ @@ -308,16 +280,6 @@ (dev->chunkBitmapStride * (blk - dev->internalStartBlock)); } -static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk) -{ - if(blk < dev->internalStartBlock || blk > dev->internalEndBlock || - chunk < 0 || chunk >= dev->nChunksPerBlock) { - T(YAFFS_TRACE_ERROR, - (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),blk,chunk)); - YBUG(); - } -} - static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device * dev, int blk) { __u8 *blkBits = yaffs_BlockBits(dev, blk); @@ -329,8 +291,6 @@ { __u8 *blkBits = yaffs_BlockBits(dev, blk); - yaffs_VerifyChunkBitId(dev,blk,chunk); - blkBits[chunk / 8] &= ~(1 << (chunk & 7)); } @@ -338,16 +298,12 @@ { __u8 *blkBits = yaffs_BlockBits(dev, blk); - yaffs_VerifyChunkBitId(dev,blk,chunk); - blkBits[chunk / 8] |= (1 << (chunk & 7)); } static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device * dev, int blk, int chunk) { __u8 *blkBits = yaffs_BlockBits(dev, blk); - yaffs_VerifyChunkBitId(dev,blk,chunk); - return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; } @@ -363,495 +319,10 @@ return 0; } -static int yaffs_CountChunkBits(yaffs_Device * dev, int blk) -{ - __u8 *blkBits = yaffs_BlockBits(dev, blk); - int i; - int n = 0; - for (i = 0; i < dev->chunkBitmapStride; i++) { - __u8 x = *blkBits; - while(x){ - if(x & 1) - n++; - x >>=1; - } - - blkBits++; - } - return n; -} - -/* - * Verification code - */ - -static int yaffs_SkipVerification(yaffs_Device *dev) -{ - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); -} - -static int yaffs_SkipFullVerification(yaffs_Device *dev) -{ - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); -} - -static int yaffs_SkipNANDVerification(yaffs_Device *dev) -{ - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); -} - -static const char * blockStateName[] = { -"Unknown", -"Needs scanning", -"Scanning", -"Empty", -"Allocating", -"Full", -"Dirty", -"Checkpoint", -"Collecting", -"Dead" -}; - -static void yaffs_VerifyBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n) -{ - int actuallyUsed; - int inUse; - - if(yaffs_SkipVerification(dev)) - return; - - /* Report illegal runtime states */ - if(bi->blockState <0 || bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) - T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has undefined state %d"TENDSTR),n,bi->blockState)); - - switch(bi->blockState){ - case YAFFS_BLOCK_STATE_UNKNOWN: - case YAFFS_BLOCK_STATE_SCANNING: - case YAFFS_BLOCK_STATE_NEEDS_SCANNING: - T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has bad run-state %s"TENDSTR), - n,blockStateName[bi->blockState])); - } - - /* Check pages in use and soft deletions are legal */ - - actuallyUsed = bi->pagesInUse - bi->softDeletions; - - if(bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock || - bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock || - actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock) - T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR), - n,bi->pagesInUse,bi->softDeletions)); - - - /* Check chunk bitmap legal */ - inUse = yaffs_CountChunkBits(dev,n); - if(inUse != bi->pagesInUse) - T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR), - n,bi->pagesInUse,inUse)); - - /* Check that the sequence number is valid. - * Ten million is legal, but is very unlikely - */ - if(dev->isYaffs2 && - (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) && - (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000 )) - T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has suspect sequence number of %d"TENDSTR), - n,bi->sequenceNumber)); - -} - -static void yaffs_VerifyCollectedBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n) -{ - yaffs_VerifyBlock(dev,bi,n); - - /* After collection the block should be in the erased state */ - /* TODO: This will need to change if we do partial gc */ - - if(bi->blockState != YAFFS_BLOCK_STATE_EMPTY){ - T(YAFFS_TRACE_ERROR,(TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), - n,bi->blockState)); - } -} - -static void yaffs_VerifyBlocks(yaffs_Device *dev) -{ - int i; - int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; - int nIllegalBlockStates = 0; - - - if(yaffs_SkipVerification(dev)) - return; - - memset(nBlocksPerState,0,sizeof(nBlocksPerState)); - - - for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++){ - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); - yaffs_VerifyBlock(dev,bi,i); - - if(bi->blockState >=0 && bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) - nBlocksPerState[bi->blockState]++; - else - nIllegalBlockStates++; - - } - - T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR))); - T(YAFFS_TRACE_VERIFY,(TSTR("Block summary"TENDSTR))); - - T(YAFFS_TRACE_VERIFY,(TSTR("%d blocks have illegal states"TENDSTR),nIllegalBlockStates)); - if(nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) - T(YAFFS_TRACE_VERIFY,(TSTR("Too many allocating blocks"TENDSTR))); - - for(i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) - T(YAFFS_TRACE_VERIFY, - (TSTR("%s %d blocks"TENDSTR), - blockStateName[i],nBlocksPerState[i])); - - if(dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) - T(YAFFS_TRACE_VERIFY, - (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), - dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); - - if(dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) - T(YAFFS_TRACE_VERIFY, - (TSTR("Erased block count wrong dev %d count %d"TENDSTR), - dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); - - if(nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1) - T(YAFFS_TRACE_VERIFY, - (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR), - nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); - - T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR))); - -} - -/* - * Verify the object header. oh must be valid, but obj and tags may be NULL in which - * case those tests will not be performed. - */ -static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) -{ - if(yaffs_SkipVerification(obj->myDev)) - return; - - if(!(tags && obj && oh)){ - T(YAFFS_TRACE_VERIFY, - (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR), - (__u32)tags,(__u32)obj,(__u32)oh)); - return; - } - - if(oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || - oh->type > YAFFS_OBJECT_TYPE_MAX) - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), - tags->objectId, oh->type)); - - if(tags->objectId != obj->objectId) - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header mismatch objectId %d"TENDSTR), - tags->objectId, obj->objectId)); - - - /* - * Check that the object's parent ids match if parentCheck requested. - * - * Tests do not apply to the root object. - */ - - if(parentCheck && tags->objectId > 1 && !obj->parent) - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR), - tags->objectId, oh->parentObjectId)); - - - if(parentCheck && obj->parent && - oh->parentObjectId != obj->parent->objectId && - (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED || - obj->parent->objectId != YAFFS_OBJECTID_DELETED)) - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR), - tags->objectId, oh->parentObjectId, obj->parent->objectId)); - - - if(tags->objectId > 1 && oh->name[0] == 0) /* Null name */ - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header name is NULL"TENDSTR), - obj->objectId)); - - if(tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header name is 0xFF"TENDSTR), - obj->objectId)); -} - - - -static int yaffs_VerifyTnodeWorker(yaffs_Object * obj, yaffs_Tnode * tn, - __u32 level, int chunkOffset) -{ - int i; - yaffs_Device *dev = obj->myDev; - int ok = 1; - int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; - - if (tn) { - if (level > 0) { - - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){ - if (tn->internal[i]) { - ok = yaffs_VerifyTnodeWorker(obj, - tn->internal[i], - level - 1, - (chunkOffset<objectId; - - chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS; - - for(i = 0; i < YAFFS_NTNODES_LEVEL0; i++){ - __u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i); - - if(theChunk > 0){ - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */ - yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags); - if(tags.objectId != objectId || tags.chunkId != chunkOffset){ - T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), - objectId, chunkOffset, theChunk, - tags.objectId, tags.chunkId)); - } - } - chunkOffset++; - } - } - } - - return ok; - -} - - -static void yaffs_VerifyFile(yaffs_Object *obj) -{ - int requiredTallness; - int actualTallness; - __u32 lastChunk; - __u32 x; - __u32 i; - int ok; - yaffs_Device *dev; - yaffs_ExtendedTags tags; - yaffs_Tnode *tn; - __u32 objectId; - - if(obj && yaffs_SkipVerification(obj->myDev)) - return; - - dev = obj->myDev; - objectId = obj->objectId; - - /* Check file size is consistent with tnode depth */ - lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1; - x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; - requiredTallness = 0; - while (x> 0) { - x >>= YAFFS_TNODES_INTERNAL_BITS; - requiredTallness++; - } - - actualTallness = obj->variant.fileVariant.topLevel; - - if(requiredTallness > actualTallness ) - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR), - obj->objectId,actualTallness, requiredTallness)); - - - /* Check that the chunks in the tnode tree are all correct. - * We do this by scanning through the tnode tree and - * checking the tags for every chunk match. - */ - - if(yaffs_SkipNANDVerification(dev)) - return; - - for(i = 1; i <= lastChunk; i++){ - tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant,i); - - if (tn) { - __u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i); - if(theChunk > 0){ - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */ - yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags); - if(tags.objectId != objectId || tags.chunkId != i){ - T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), - objectId, i, theChunk, - tags.objectId, tags.chunkId)); - } - } - } - - } - -} - -static void yaffs_VerifyDirectory(yaffs_Object *obj) -{ - if(obj && yaffs_SkipVerification(obj->myDev)) - return; - -} - -static void yaffs_VerifyHardLink(yaffs_Object *obj) -{ - if(obj && yaffs_SkipVerification(obj->myDev)) - return; - - /* Verify sane equivalent object */ -} - -static void yaffs_VerifySymlink(yaffs_Object *obj) -{ - if(obj && yaffs_SkipVerification(obj->myDev)) - return; - - /* Verify symlink string */ -} - -static void yaffs_VerifySpecial(yaffs_Object *obj) -{ - if(obj && yaffs_SkipVerification(obj->myDev)) - return; -} - -static void yaffs_VerifyObject(yaffs_Object *obj) -{ - yaffs_Device *dev; - - __u32 chunkMin; - __u32 chunkMax; - - __u32 chunkIdOk; - __u32 chunkIsLive; - - if(!obj) - return; - - dev = obj->myDev; - - if(yaffs_SkipVerification(dev)) - return; - - /* Check sane object header chunk */ - - chunkMin = dev->internalStartBlock * dev->nChunksPerBlock; - chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1; - - chunkIdOk = (obj->chunkId >= chunkMin && obj->chunkId <= chunkMax); - chunkIsLive = chunkIdOk && - yaffs_CheckChunkBit(dev, - obj->chunkId / dev->nChunksPerBlock, - obj->chunkId % dev->nChunksPerBlock); - if(!obj->fake && - (!chunkIdOk || !chunkIsLive)) { - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), - obj->objectId,obj->chunkId, - chunkIdOk ? "" : ",out of range", - chunkIsLive || !chunkIdOk ? "" : ",marked as deleted")); - } - - if(chunkIdOk && chunkIsLive &&!yaffs_SkipNANDVerification(dev)) { - yaffs_ExtendedTags tags; - yaffs_ObjectHeader *oh; - __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__); - - oh = (yaffs_ObjectHeader *)buffer; - - yaffs_ReadChunkWithTagsFromNAND(dev, obj->chunkId,buffer, &tags); - - yaffs_VerifyObjectHeader(obj,oh,&tags,1); - - yaffs_ReleaseTempBuffer(dev,buffer,__LINE__); - } - - /* Verify it has a parent */ - if(obj && !obj->fake && - (!obj->parent || obj->parent->myDev != dev)){ - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), - obj->objectId,obj->parent)); - } - - /* Verify parent is a directory */ - if(obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY){ - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), - obj->objectId,obj->parent->variantType)); - } - - switch(obj->variantType){ - case YAFFS_OBJECT_TYPE_FILE: - yaffs_VerifyFile(obj); - break; - case YAFFS_OBJECT_TYPE_SYMLINK: - yaffs_VerifySymlink(obj); - break; - case YAFFS_OBJECT_TYPE_DIRECTORY: - yaffs_VerifyDirectory(obj); - break; - case YAFFS_OBJECT_TYPE_HARDLINK: - yaffs_VerifyHardLink(obj); - break; - case YAFFS_OBJECT_TYPE_SPECIAL: - yaffs_VerifySpecial(obj); - break; - case YAFFS_OBJECT_TYPE_UNKNOWN: - default: - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d has illegaltype %d"TENDSTR), - obj->objectId,obj->variantType)); - break; - } - - -} - -static void yaffs_VerifyObjects(yaffs_Device *dev) -{ - yaffs_Object *obj; - int i; - struct list_head *lh; - - if(yaffs_SkipVerification(dev)) - return; - - /* Iterate through the objects in each hash entry */ - - for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++){ - list_for_each(lh, &dev->objectBucket[i].list) { - if (lh) { - obj = list_entry(lh, yaffs_Object, hashLink); - yaffs_VerifyObject(obj); - } - } - } - -} - - /* * Simple hash function. Needs to have a reasonable spread */ - + static Y_INLINE int yaffs_HashFunction(int n) { n = abs(n); @@ -861,7 +332,7 @@ /* * Access functions to useful fake objects */ - + yaffs_Object *yaffs_Root(yaffs_Device * dev) { return dev->rootDir; @@ -876,7 +347,7 @@ /* * Erased NAND checking functions */ - + int yaffs_CheckFF(__u8 * buffer, int nBytes) { /* Horrible, slow implementation */ @@ -898,10 +369,10 @@ int result; result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags); - + if(tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR) retval = YAFFS_FAIL; - + if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) { T(YAFFS_TRACE_NANDACCESS, @@ -915,90 +386,91 @@ } - static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, const __u8 * data, yaffs_ExtendedTags * tags, int useReserve) { - int attempts = 0; - int writeOk = 0; int chunk; + int writeOk = 0; + int erasedOk = 1; + int attempts = 0; + yaffs_BlockInfo *bi; + yaffs_InvalidateCheckpoint(dev); do { - yaffs_BlockInfo *bi = 0; - int erasedOk = 0; + chunk = yaffs_AllocateChunk(dev, useReserve,&bi); - chunk = yaffs_AllocateChunk(dev, useReserve, &bi); - if (chunk < 0) { - /* no space */ - break; - } - - /* First check this chunk is erased, if it needs - * checking. The checking policy (unless forced - * always on) is as follows: - * - * Check the first page we try to write in a block. - * If the check passes then we don't need to check any - * more. If the check fails, we check again... - * If the block has been erased, we don't need to check. - * - * However, if the block has been prioritised for gc, - * then we think there might be something odd about - * this block and stop using it. - * - * Rationale: We should only ever see chunks that have - * not been erased if there was a partially written - * chunk due to power loss. This checking policy should - * catch that case with very few checks and thus save a - * lot of checks that are most likely not needed. - */ - if (bi->gcPrioritise) { - yaffs_DeleteChunk(dev, chunk, 1, __LINE__); - /* try another chunk */ - continue; - } + if (chunk >= 0) { + /* First check this chunk is erased, if it needs checking. + * The checking policy (unless forced always on) is as follows: + * Check the first page we try to write in a block. + * - If the check passes then we don't need to check any more. + * - If the check fails, we check again... + * If the block has been erased, we don't need to check. + * + * However, if the block has been prioritised for gc, then + * we think there might be something odd about this block + * and stop using it. + * + * Rationale: + * We should only ever see chunks that have not been erased + * if there was a partially written chunk due to power loss + * This checking policy should catch that case with very + * few checks and thus save a lot of checks that are most likely not + * needed. + */ + + if(bi->gcPrioritise){ + yaffs_DeleteChunk(dev, chunk, 1, __LINE__); + } else { +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED - /* let's give it a try */ - attempts++; + bi->skipErasedCheck = 0; -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED - bi->skipErasedCheck = 0; #endif - if (!bi->skipErasedCheck) { - erasedOk = yaffs_CheckChunkErased(dev, chunk); - if (erasedOk != YAFFS_OK) { - T(YAFFS_TRACE_ERROR, - (TSTR ("**>> yaffs chunk %d was not erased" - TENDSTR), chunk)); + if(!bi->skipErasedCheck){ + erasedOk = yaffs_CheckChunkErased(dev, chunk); + if(erasedOk && !bi->gcPrioritise) + bi->skipErasedCheck = 1; + } - /* try another chunk */ - continue; + if (!erasedOk) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>> yaffs chunk %d was not erased" + TENDSTR), chunk)); + } else { + writeOk = + yaffs_WriteChunkWithTagsToNAND(dev, chunk, + data, tags); + } + + attempts++; + + if (writeOk) { + /* + * Copy the data into the robustification buffer. + * NB We do this at the end to prevent duplicates in the case of a write error. + * Todo + */ + yaffs_HandleWriteChunkOk(dev, chunk, data, tags); + + } else { + /* The erased check or write failed */ + yaffs_HandleWriteChunkError(dev, chunk, erasedOk); + } } - bi->skipErasedCheck = 1; } - writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, - data, tags); - if (writeOk != YAFFS_OK) { - yaffs_HandleWriteChunkError(dev, chunk, erasedOk); - /* try another chunk */ - continue; - } - - /* Copy the data into the robustification buffer */ - yaffs_HandleWriteChunkOk(dev, chunk, data, tags); - - } while (writeOk != YAFFS_OK && attempts < yaffs_wr_attempts); + } while (chunk >= 0 && !writeOk); if (attempts > 1) { T(YAFFS_TRACE_ERROR, - (TSTR("**>> yaffs write required %d attempts" TENDSTR), - attempts)); - + (TSTR("**>> yaffs write required %d attempts" TENDSTR), + attempts)); dev->nRetriedWrites += (attempts - 1); } @@ -1008,13 +480,13 @@ /* * Block retiring for handling a broken block. */ - + static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND) { yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); yaffs_InvalidateCheckpoint(dev); - + yaffs_MarkBlockBad(dev, blockInNAND); bi->blockState = YAFFS_BLOCK_STATE_DEAD; @@ -1028,7 +500,7 @@ * Functions for robustisizing TODO * */ - + static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * tags) @@ -1046,13 +518,28 @@ bi->gcPrioritise = 1; dev->hasPendingPrioritisedGCs = 1; bi->chunkErrorStrikes ++; - + if(bi->chunkErrorStrikes > 3){ bi->needsRetiring = 1; /* Too many stikes, so retire this */ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR))); } + + } +} +static void yaffs_ReportOddballBlocks(yaffs_Device *dev) +{ + int i; + + for(i = dev->internalStartBlock; i <= dev->internalEndBlock && (yaffs_traceMask & YAFFS_TRACE_BAD_BLOCKS); i++){ + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); + if(bi->needsRetiring || bi->gcPrioritise) + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("yaffs block %d%s%s" TENDSTR), + i, + bi->needsRetiring ? " needs retiring" : "", + bi->gcPrioritise ? " gc prioritised" : "")); + } } @@ -1061,25 +548,22 @@ int blockInNAND = chunkInNAND / dev->nChunksPerBlock; yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); - + yaffs_HandleChunkError(dev,bi); - - + if(erasedOk ) { /* Was an actual write failure, so mark the block for retirement */ bi->needsRetiring = 1; T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND)); - - } - + /* Delete the chunk */ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); } -/*---------------- Name handling functions ------------*/ +/*---------------- Name handling functions ------------*/ static __u16 yaffs_CalcNameSum(const YCHAR * name) { @@ -1088,7 +572,7 @@ YUCHAR *bname = (YUCHAR *) name; if (bname) { - while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) { + while ((*bname) && (i <= YAFFS_MAX_NAME_LENGTH)) { #ifdef CONFIG_YAFFS_CASE_INSENSITIVE sum += yaffs_toupper(*bname) * i; @@ -1120,7 +604,7 @@ * The list is hooked together using the first pointer * in the tnode. */ - + /* yaffs_CreateTnodes creates a bunch more tnodes and * adds them to the tnode free list. * Don't use this function directly @@ -1138,7 +622,7 @@ if (nTnodes < 1) return YAFFS_OK; - + /* Calculate the tnode size in bytes for variable width tnode support. * Must be a multiple of 32-bits */ tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; @@ -1175,7 +659,7 @@ next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize]; curr->internal[0] = next; } - + curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize]; curr->internal[0] = dev->freeTnodes; dev->freeTnodes = (yaffs_Tnode *)mem; @@ -1190,13 +674,12 @@ * NB If we can't add this to the management list it isn't fatal * but it just means we can't free this bunch of tnodes later. */ - + tnl = YMALLOC(sizeof(yaffs_TnodeList)); if (!tnl) { T(YAFFS_TRACE_ERROR, (TSTR ("yaffs: Could not add tnodes to management list" TENDSTR))); - return YAFFS_FAIL; } else { tnl->tnodes = newTnodes; @@ -1239,11 +722,11 @@ static yaffs_Tnode *yaffs_GetTnode(yaffs_Device * dev) { yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev); - + if(tn) memset(tn, 0, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); - return tn; + return tn; } /* FreeTnode frees up a tnode and puts it back on the free list */ @@ -1299,19 +782,19 @@ __u32 bitInWord; __u32 wordInMap; __u32 mask; - + pos &= YAFFS_TNODES_LEVEL0_MASK; val >>= dev->chunkGroupBits; - + bitInMap = pos * dev->tnodeWidth; wordInMap = bitInMap /32; bitInWord = bitInMap & (32 -1); - + mask = dev->tnodeMask << bitInWord; - + map[wordInMap] &= ~mask; map[wordInMap] |= (mask & (val << bitInWord)); - + if(dev->tnodeWidth > (32-bitInWord)) { bitInWord = (32 - bitInWord); wordInMap++;; @@ -1321,31 +804,31 @@ } } -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos) +__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos) { __u32 *map = (__u32 *)tn; __u32 bitInMap; __u32 bitInWord; __u32 wordInMap; __u32 val; - + pos &= YAFFS_TNODES_LEVEL0_MASK; - + bitInMap = pos * dev->tnodeWidth; wordInMap = bitInMap /32; bitInWord = bitInMap & (32 -1); - + val = map[wordInMap] >> bitInWord; - + if(dev->tnodeWidth > (32-bitInWord)) { bitInWord = (32 - bitInWord); wordInMap++;; val |= (map[wordInMap] << bitInWord); } - + val &= dev->tnodeMask; val <<= dev->chunkGroupBits; - + return val; } @@ -1394,7 +877,7 @@ while (level > 0 && tn) { tn = tn-> internal[(chunkId >> - ( YAFFS_TNODES_LEVEL0_BITS + + ( YAFFS_TNODES_LEVEL0_BITS + (level - 1) * YAFFS_TNODES_INTERNAL_BITS) ) & @@ -1416,7 +899,7 @@ * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will * be plugged into the ttree. */ - + static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device * dev, yaffs_FileStructure * fStruct, __u32 chunkId, @@ -1453,7 +936,7 @@ if (requiredTallness > fStruct->topLevel) { /* Not tall enough,gotta make the tree taller */ for (i = fStruct->topLevel; i < requiredTallness; i++) { - + tn = yaffs_GetTnode(dev); if (tn) { @@ -1472,7 +955,7 @@ l = fStruct->topLevel; tn = fStruct->top; - + if(l > 0) { while (l > 0 && tn) { x = (chunkId >> @@ -1492,13 +975,13 @@ if(tn->internal[x]) yaffs_FreeTnode(dev,tn->internal[x]); tn->internal[x] = passedTn; - + } else if(!tn->internal[x]) { /* Don't have one, none passed in */ tn->internal[x] = yaffs_GetTnode(dev); } } - + tn = tn->internal[x]; l--; } @@ -1539,7 +1022,7 @@ /* DeleteWorker scans backwards through the tnode tree and deletes all the * chunks and tnodes in the file - * Returns 1 if the tree was deleted. + * Returns 1 if the tree was deleted. * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete. */ @@ -1653,7 +1136,7 @@ * of the tnode. * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted. */ - + static int yaffs_SoftDeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level, int chunkOffset) { @@ -1694,7 +1177,7 @@ theChunk = yaffs_GetChunkGroupBase(dev,tn,i); if (theChunk) { /* Note this does not find the real chunk, only the chunk group. - * We make an assumption that a chunk group is not larger than + * We make an assumption that a chunk group is not larger than * a block. */ yaffs_SoftDeleteChunk(dev, theChunk); @@ -1796,7 +1279,7 @@ /* Now we have a tree with all the non-zero branches NULL but the height * is the same as it was. * Let's see if we can trim internal tnodes to shorten the tree. - * We can do this if only the 0th element in the tnode is in use + * We can do this if only the 0th element in the tnode is in use * (ie all the non-zero are NULL) */ @@ -1839,18 +1322,13 @@ /* make these things */ newObjects = YMALLOC(nObjects * sizeof(yaffs_Object)); - list = YMALLOC(sizeof(yaffs_ObjectList)); - if (!newObjects || !list) { - if(newObjects) - YFREE(newObjects); - if(list) - YFREE(list); + if (!newObjects) { T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Could not allocate more objects" TENDSTR))); return YAFFS_FAIL; } - + /* Hook them into the free list */ for (i = 0; i < nObjects - 1; i++) { newObjects[i].siblings.next = @@ -1864,9 +1342,15 @@ /* Now add this bunch of Objects to a list for freeing up. */ - list->objects = newObjects; - list->next = dev->allocatedObjectList; - dev->allocatedObjectList = list; + list = YMALLOC(sizeof(yaffs_ObjectList)); + if (!list) { + T(YAFFS_TRACE_ALLOCATE, + (TSTR("Could not add objects to management list" TENDSTR))); + } else { + list->objects = newObjects; + list->next = dev->allocatedObjectList; + dev->allocatedObjectList = list; + } return YAFFS_OK; } @@ -2123,25 +1607,12 @@ { yaffs_Object *theObject; - yaffs_Tnode *tn; if (number < 0) { number = yaffs_CreateNewObjectNumber(dev); } theObject = yaffs_AllocateEmptyObject(dev); - if(!theObject) - return NULL; - - if(type == YAFFS_OBJECT_TYPE_FILE){ - tn = yaffs_GetTnode(dev); - if(!tn){ - yaffs_FreeObject(theObject); - return NULL; - } - } - - if (theObject) { theObject->fake = 0; @@ -2168,7 +1639,8 @@ theObject->variant.fileVariant.scannedFileSize = 0; theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */ theObject->variant.fileVariant.topLevel = 0; - theObject->variant.fileVariant.top = tn; + theObject->variant.fileVariant.top = + yaffs_GetTnode(dev); break; case YAFFS_OBJECT_TYPE_DIRECTORY: INIT_LIST_HEAD(&theObject->variant.directoryVariant. @@ -2205,7 +1677,7 @@ return theObject; } - + static YCHAR *yaffs_CloneString(const YCHAR * str) { @@ -2213,8 +1685,7 @@ if (str && *str) { newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); - if(newStr) - yaffs_strcpy(newStr, str); + yaffs_strcpy(newStr, str); } return newStr; @@ -2227,7 +1698,7 @@ * aliasString only has meaning for a sumlink. * rdev only has meaning for devices (a subset of special objects) */ - + static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, yaffs_Object * parent, const YCHAR * name, @@ -2238,7 +1709,6 @@ const YCHAR * aliasString, __u32 rdev) { yaffs_Object *in; - YCHAR *str; yaffs_Device *dev = parent->myDev; @@ -2249,16 +1719,6 @@ in = yaffs_CreateNewObject(dev, -1, type); - if(type == YAFFS_OBJECT_TYPE_SYMLINK){ - str = yaffs_CloneString(aliasString); - if(!str){ - yaffs_FreeObject(in); - return NULL; - } - } - - - if (in) { in->chunkId = -1; in->valid = 1; @@ -2289,7 +1749,8 @@ switch (type) { case YAFFS_OBJECT_TYPE_SYMLINK: - in->variant.symLinkVariant.alias = str; + in->variant.symLinkVariant.alias = + yaffs_CloneString(aliasString); break; case YAFFS_OBJECT_TYPE_HARDLINK: in->variant.hardLinkVariant.equivalentObject = @@ -2298,7 +1759,7 @@ equivalentObject->objectId; list_add(&in->hardLinks, &equivalentObject->hardLinks); break; - case YAFFS_OBJECT_TYPE_FILE: + case YAFFS_OBJECT_TYPE_FILE: case YAFFS_OBJECT_TYPE_DIRECTORY: case YAFFS_OBJECT_TYPE_SPECIAL: case YAFFS_OBJECT_TYPE_UNKNOWN: @@ -2382,7 +1843,7 @@ TENDSTR))); YBUG(); } - + /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ if (obj->myDev->isYaffs2) { unlinkOp = (newDir == obj->myDev->unlinkedDir); @@ -2395,9 +1856,9 @@ existingTarget = yaffs_FindObjectByName(newDir, newName); - /* If the object is a file going into the unlinked directory, + /* If the object is a file going into the unlinked directory, * then it is OK to just stuff it in since duplicate names are allowed. - * else only proceed if the new name does not exist and if we're putting + * else only proceed if the new name does not exist and if we're putting * it into a directory. */ if ((unlinkOp || @@ -2461,7 +1922,7 @@ /* There is a target that is a non-empty directory, so we fail */ return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */ } else if (existingTarget && existingTarget != obj) { - /* Nuke the target first, using shadowing, + /* Nuke the target first, using shadowing, * but only if it isn't the same object */ yaffs_ChangeObjectName(obj, newDir, newName, force, @@ -2479,13 +1940,10 @@ static int yaffs_InitialiseBlocks(yaffs_Device * dev) { int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; - - dev->blockInfo = NULL; - dev->chunkBits = NULL; - + dev->allocationBlock = -1; /* force it to get a new one */ - /* If the first allocation strategy fails, thry the alternate one */ + /* Todo we're assuming the malloc will pass. */ dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo)); if(!dev->blockInfo){ dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo)); @@ -2493,20 +1951,17 @@ } else dev->blockInfoAlt = 0; - - if(dev->blockInfo){ - - /* Set up dynamic blockinfo stuff. */ - dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ - dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); - if(!dev->chunkBits){ - dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); - dev->chunkBitsAlt = 1; - } - else - dev->chunkBitsAlt = 0; + + /* Set up dynamic blockinfo stuff. */ + dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ + dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); + if(!dev->chunkBits){ + dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); + dev->chunkBitsAlt = 1; } - + else + dev->chunkBitsAlt = 0; + if (dev->blockInfo && dev->chunkBits) { memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo)); memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks); @@ -2519,18 +1974,17 @@ static void yaffs_DeinitialiseBlocks(yaffs_Device * dev) { - if(dev->blockInfoAlt && dev->blockInfo) + if(dev->blockInfoAlt) YFREE_ALT(dev->blockInfo); - else if(dev->blockInfo) + else YFREE(dev->blockInfo); - dev->blockInfoAlt = 0; dev->blockInfo = NULL; - - if(dev->chunkBitsAlt && dev->chunkBits) + + if(dev->chunkBitsAlt) YFREE_ALT(dev->chunkBits); - else if(dev->chunkBits) + else YFREE(dev->chunkBits); dev->chunkBitsAlt = 0; dev->chunkBits = NULL; @@ -2587,18 +2041,17 @@ int i; int iterations; int dirtiest = -1; - int pagesInUse = 0; + int pagesInUse; int prioritised=0; yaffs_BlockInfo *bi; + static int nonAggressiveSkip = 0; int pendingPrioritisedExist = 0; - + /* First let's see if we need to grab a prioritised block */ if(dev->hasPendingPrioritisedGCs){ for(i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++){ bi = yaffs_GetBlockInfo(dev, i); - //yaffs_VerifyBlock(dev,bi,i); - if(bi->gcPrioritise) { pendingPrioritisedExist = 1; if(bi->blockState == YAFFS_BLOCK_STATE_FULL && @@ -2610,7 +2063,7 @@ } } } - + if(!pendingPrioritisedExist) /* None found, so we can clear this */ dev->hasPendingPrioritisedGCs = 0; } @@ -2621,9 +2074,9 @@ * block has only a few pages in use. */ - dev->nonAggressiveSkip--; + nonAggressiveSkip--; - if (!aggressive && (dev->nonAggressiveSkip > 0)) { + if (!aggressive && (nonAggressiveSkip > 0)) { return -1; } @@ -2662,7 +2115,7 @@ dirtiest = b; pagesInUse = 0; } - else + else #endif if (bi->blockState == YAFFS_BLOCK_STATE_FULL && @@ -2684,7 +2137,7 @@ dev->oldestDirtySequence = 0; if (dirtiest > 0) { - dev->nonAggressiveSkip = 4; + nonAggressiveSkip = 4; } return dirtiest; @@ -2699,11 +2152,11 @@ /* If the block is still healthy erase it and mark as clean. * If the block has had a data failure, then retire it. */ - + T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR), blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : "")); - + bi->blockState = YAFFS_BLOCK_STATE_DIRTY; if (!bi->needsRetiring) { @@ -2716,8 +2169,7 @@ } } - if (erasedOk && - ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) { + if (erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE)) { int i; for (i = 0; i < dev->nChunksPerBlock; i++) { if (!yaffs_CheckChunkErased @@ -2767,7 +2219,7 @@ return -1; } - + /* Find an empty block. */ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { @@ -2808,13 +2260,13 @@ int reservedChunks; int reservedBlocks = dev->nReservedBlocks; int checkpointBlocks; - + checkpointBlocks = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; if(checkpointBlocks < 0) checkpointBlocks = 0; - + reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); - + return (dev->nFreeChunks > reservedChunks); } @@ -2861,10 +2313,10 @@ if(blockUsedPtr) *blockUsedPtr = bi; - + return retVal; } - + T(YAFFS_TRACE_ERROR, (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); @@ -2895,7 +2347,6 @@ int cleanups = 0; int i; int isCheckpointBlock; - int matchingChunk; int chunksBefore = yaffs_GetErasedChunks(dev); int chunksAfter; @@ -2907,7 +2358,7 @@ yaffs_Object *object; isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT); - + bi->blockState = YAFFS_BLOCK_STATE_COLLECTING; T(YAFFS_TRACE_TRACING, @@ -2936,8 +2387,6 @@ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); - yaffs_VerifyBlock(dev,bi,block); - for (chunkInBlock = 0, oldChunk = block * dev->nChunksPerBlock; chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev, block); @@ -2963,34 +2412,18 @@ chunkInBlock, tags.objectId, tags.chunkId, tags.byteCount)); - if(object && !yaffs_SkipVerification(dev)){ - if(tags.chunkId == 0) - matchingChunk = object->chunkId; - else if(object->softDeleted) - matchingChunk = oldChunk; /* Defeat the test */ - else - matchingChunk = yaffs_FindChunkInFile(object,tags.chunkId,NULL); - - if(oldChunk != matchingChunk) - T(YAFFS_TRACE_ERROR, - (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR), - oldChunk,matchingChunk,tags.objectId, tags.chunkId)); - - } - if (!object) { T(YAFFS_TRACE_ERROR, (TSTR - ("page %d in gc has no object: %d %d %d " - TENDSTR), oldChunk, - tags.objectId, tags.chunkId, tags.byteCount)); + ("page %d in gc has no object " + TENDSTR), oldChunk)); } if (object && object->deleted && tags.chunkId != 0) { /* Data chunk in a deleted file, throw it away * It's a soft deleted data chunk, - * No need to copy this, just forget about it and + * No need to copy this, just forget about it and * fix up the object. */ @@ -3040,8 +2473,6 @@ oh->shadowsObject = -1; tags.extraShadows = 0; tags.extraIsShrinkHeader = 0; - - yaffs_VerifyObjectHeader(object,oh,&tags,1); } newChunk = @@ -3098,8 +2529,6 @@ } - yaffs_VerifyCollectedBlock(dev,bi,block); - if (chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev))) { T(YAFFS_TRACE_GC, (TSTR @@ -3127,26 +2556,26 @@ int aggressive; int gcOk = YAFFS_OK; int maxTries = 0; - + int checkpointBlockAdjust; if (dev->isDoingGC) { /* Bail out so we don't get recursive gc */ return YAFFS_OK; } - + /* This loop should pass the first time. * We'll only see looping here if the erase of the collected block fails. */ do { maxTries++; - + checkpointBlockAdjust = (dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint); if(checkpointBlockAdjust < 0) checkpointBlockAdjust = 0; - if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) { + if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust)) { /* We need a block soon...*/ aggressive = 1; } else { @@ -3326,11 +2755,11 @@ static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode, int chunkInNAND, int inScan) { - /* NB inScan is zero unless scanning. - * For forward scanning, inScan is > 0; + /* NB inScan is zero unless scanning. + * For forward scanning, inScan is > 0; * for backward scanning inScan is < 0 */ - + yaffs_Tnode *tn; yaffs_Device *dev = in->myDev; int existingChunk; @@ -3354,7 +2783,7 @@ return YAFFS_OK; } - tn = yaffs_AddOrFindLevel0Tnode(dev, + tn = yaffs_AddOrFindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode, NULL); @@ -3366,7 +2795,7 @@ if (inScan != 0) { /* If we're scanning then we need to test for duplicates - * NB This does not need to be efficient since it should only ever + * NB This does not need to be efficient since it should only ever * happen when the power fails during a write, then only one * chunk should ever be affected. * @@ -3407,7 +2836,7 @@ } - /* NB The deleted flags should be false, otherwise the chunks will + /* NB The deleted flags should be false, otherwise the chunks will * not be loaded during a scan */ @@ -3418,7 +2847,7 @@ (in->myDev->isYaffs2 || existingChunk <= 0 || ((existingSerial + 1) & 3) == newSerial)) { - /* Forward scanning. + /* Forward scanning. * Use new * Delete the old one and drop through to update the tnode */ @@ -3459,7 +2888,7 @@ (TSTR("Chunk %d not found zero instead" TENDSTR), chunkInNAND)); /* get sane (zero) data if you read a hole */ - memset(buffer, 0, in->myDev->nDataBytesPerChunk); + memset(buffer, 0, in->myDev->nDataBytesPerChunk); return 0; } @@ -3475,17 +2904,10 @@ if (chunkId <= 0) return; - dev->nDeletions++; block = chunkId / dev->nChunksPerBlock; page = chunkId % dev->nChunksPerBlock; - - if(!yaffs_CheckChunkBit(dev,block,page)) - T(YAFFS_TRACE_VERIFY, - (TSTR("Deleting invalid chunk %d"TENDSTR), - chunkId)); - bi = yaffs_GetBlockInfo(dev, block); T(YAFFS_TRACE_DELETION, @@ -3596,19 +3018,15 @@ int newChunkId; yaffs_ExtendedTags newTags; - yaffs_ExtendedTags oldTags; __u8 *buffer = NULL; YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1]; yaffs_ObjectHeader *oh = NULL; - yaffs_strcpy(oldName,"silly old name"); - if (!in->fake || force) { yaffs_CheckGarbageCollection(dev); - yaffs_CheckObjectDetailsLoaded(in); buffer = yaffs_GetTempBuffer(in->myDev, __LINE__); oh = (yaffs_ObjectHeader *) buffer; @@ -3617,10 +3035,7 @@ if (prevChunkId >= 0) { result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId, - buffer, &oldTags); - - yaffs_VerifyObjectHeader(in,oh,&oldTags,0); - + buffer, NULL); memcpy(oldName, oh->name, sizeof(oh->name)); } @@ -3654,7 +3069,7 @@ if (name && *name) { memset(oh->name, 0, sizeof(oh->name)); yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH); - } else if (prevChunkId>=0) { + } else if (prevChunkId) { memcpy(oh->name, oldName, sizeof(oh->name)); } else { memset(oh->name, 0, sizeof(oh->name)); @@ -3708,8 +3123,6 @@ newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0; newTags.extraObjectType = in->variantType; - yaffs_VerifyObjectHeader(in,oh,&newTags,1); - /* Create new chunk in NAND */ newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, @@ -3748,11 +3161,11 @@ /*------------------------ Short Operations Cache ---------------------------------------- * In many situations where there is no high level buffering (eg WinCE) a lot of - * reads might be short sequential reads, and a lot of writes may be short + * reads might be short sequential reads, and a lot of writes may be short * sequential writes. eg. scanning/writing a jpeg file. - * In these cases, a short read/write cache can provide a huge perfomance benefit + * In these cases, a short read/write cache can provide a huge perfomance benefit * with dumb-as-a-rock code. - * In Linux, the page cache provides read buffering aand the short op cache provides write + * In Linux, the page cache provides read buffering aand the short op cache provides write * buffering. * * There are a limited number (~10) of cache chunks per device so that we don't @@ -3765,14 +3178,14 @@ int i; yaffs_ChunkCache *cache; int nCaches = obj->myDev->nShortOpCaches; - + for(i = 0; i < nCaches; i++){ cache = &dev->srCache[i]; if (cache->object == obj && cache->dirty) return 1; } - + return 0; } @@ -3838,7 +3251,7 @@ yaffs_Object *obj; int nCaches = dev->nShortOpCaches; int i; - + /* Find a dirty object in the cache and flush it... * until there are no further dirty objects. */ @@ -3848,18 +3261,18 @@ if (dev->srCache[i].object && dev->srCache[i].dirty) obj = dev->srCache[i].object; - + } if(obj) yaffs_FlushFilesChunkCache(obj); - + } while(obj); - + } /* Grab us a cache chunk for use. - * First look for an empty one. + * First look for an empty one. * Then look for the least recently used non-dirty one. * Then look for the least recently used dirty one...., flush and look again. */ @@ -3871,7 +3284,7 @@ if (dev->nShortOpCaches > 0) { for (i = 0; i < dev->nShortOpCaches; i++) { - if (!dev->srCache[i].object) + if (!dev->srCache[i].object) return &dev->srCache[i]; } @@ -4032,14 +3445,11 @@ static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev,int head) { yaffs_CheckpointValidity cp; - - memset(&cp,0,sizeof(cp)); - cp.structType = sizeof(cp); cp.magic = YAFFS_MAGIC; cp.version = YAFFS_CHECKPOINT_VERSION; cp.head = (head) ? 1 : 0; - + return (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp))? 1 : 0; } @@ -4048,9 +3458,9 @@ { yaffs_CheckpointValidity cp; int ok; - + ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); - + if(ok) ok = (cp.structType == sizeof(cp)) && (cp.magic == YAFFS_MAGIC) && @@ -4059,20 +3469,20 @@ return ok ? 1 : 0; } -static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, +static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, yaffs_Device *dev) { cp->nErasedBlocks = dev->nErasedBlocks; cp->allocationBlock = dev->allocationBlock; cp->allocationPage = dev->allocationPage; cp->nFreeChunks = dev->nFreeChunks; - + cp->nDeletedFiles = dev->nDeletedFiles; cp->nUnlinkedFiles = dev->nUnlinkedFiles; cp->nBackgroundDeletions = dev->nBackgroundDeletions; cp->sequenceNumber = dev->sequenceNumber; cp->oldestDirtySequence = dev->oldestDirtySequence; - + } static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev, @@ -4082,7 +3492,7 @@ dev->allocationBlock = cp->allocationBlock; dev->allocationPage = cp->allocationPage; dev->nFreeChunks = cp->nFreeChunks; - + dev->nDeletedFiles = cp->nDeletedFiles; dev->nUnlinkedFiles = cp->nUnlinkedFiles; dev->nBackgroundDeletions = cp->nBackgroundDeletions; @@ -4098,20 +3508,20 @@ __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); int ok; - + /* Write device runtime values*/ yaffs_DeviceToCheckpointDevice(&cp,dev); cp.structType = sizeof(cp); - + ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); - + /* Write block info */ if(ok) { nBytes = nBlocks * sizeof(yaffs_BlockInfo); ok = (yaffs_CheckpointWrite(dev,dev->blockInfo,nBytes) == nBytes); } - - /* Write chunk bits */ + + /* Write chunk bits */ if(ok) { nBytes = nBlocks * dev->chunkBitmapStride; ok = (yaffs_CheckpointWrite(dev,dev->chunkBits,nBytes) == nBytes); @@ -4126,28 +3536,28 @@ __u32 nBytes; __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); - int ok; - + int ok; + ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); if(!ok) return 0; - + if(cp.structType != sizeof(cp)) return 0; - - + + yaffs_CheckpointDeviceToDevice(dev,&cp); - + nBytes = nBlocks * sizeof(yaffs_BlockInfo); - + ok = (yaffs_CheckpointRead(dev,dev->blockInfo,nBytes) == nBytes); - + if(!ok) return 0; nBytes = nBlocks * dev->chunkBitmapStride; - + ok = (yaffs_CheckpointRead(dev,dev->chunkBits,nBytes) == nBytes); - + return ok ? 1 : 0; } @@ -4158,7 +3568,7 @@ cp->objectId = obj->objectId; cp->parentId = (obj->parent) ? obj->parent->objectId : 0; cp->chunkId = obj->chunkId; - cp->variantType = obj->variantType; + cp->variantType = obj->variantType; cp->deleted = obj->deleted; cp->softDeleted = obj->softDeleted; cp->unlinked = obj->unlinked; @@ -4167,7 +3577,7 @@ cp->unlinkAllowed = obj->unlinkAllowed; cp->serial = obj->serial; cp->nDataChunks = obj->nDataChunks; - + if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize; else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) @@ -4178,9 +3588,9 @@ { yaffs_Object *parent; - + obj->objectId = cp->objectId; - + if(cp->parentId) parent = yaffs_FindOrCreateObjectByNumber( obj->myDev, @@ -4188,12 +3598,12 @@ YAFFS_OBJECT_TYPE_DIRECTORY); else parent = NULL; - + if(parent) yaffs_AddObjectToDirectory(parent, obj); - + obj->chunkId = cp->chunkId; - obj->variantType = cp->variantType; + obj->variantType = cp->variantType; obj->deleted = cp->deleted; obj->softDeleted = cp->softDeleted; obj->unlinked = cp->unlinked; @@ -4202,12 +3612,12 @@ obj->unlinkAllowed = cp->unlinkAllowed; obj->serial = cp->serial; obj->nDataChunks = cp->nDataChunks; - + if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId; else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId; - + if(obj->objectId >= YAFFS_NOBJECT_BUCKETS) obj->lazyLoaded = 1; } @@ -4250,17 +3660,17 @@ { __u32 endMarker = ~0; int ok = 1; - + if(obj->variantType == YAFFS_OBJECT_TYPE_FILE){ ok = yaffs_CheckpointTnodeWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0); if(ok) - ok = (yaffs_CheckpointWrite(obj->myDev,&endMarker,sizeof(endMarker)) == + ok = (yaffs_CheckpointWrite(obj->myDev,&endMarker,sizeof(endMarker)) == sizeof(endMarker)); } - + return ok ? 1 : 0; } @@ -4271,15 +3681,12 @@ yaffs_Device *dev = obj->myDev; yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant; yaffs_Tnode *tn; - int nread = 0; - + ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk)); - + while(ok && (~baseChunk)){ - nread++; /* Read level 0 tnode */ - - + /* printf("read tnode at %d\n",baseChunk); */ tn = yaffs_GetTnodeRaw(dev); if(tn) @@ -4287,27 +3694,22 @@ (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); else ok = 0; - + if(tn && ok){ ok = yaffs_AddOrFindLevel0Tnode(dev, fileStructPtr, baseChunk, tn) ? 1 : 0; - } - + if(ok) ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk)); - + } - T(YAFFS_TRACE_CHECKPOINT,( - TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR), - nread,baseChunk,ok)); - - return ok ? 1 : 0; + return ok ? 1 : 0; } - + static int yaffs_WriteCheckpointObjects(yaffs_Device *dev) { @@ -4317,11 +3719,11 @@ int ok = 1; struct list_head *lh; - + /* Iterate through the objects in each hash entry, * dumping them to the checkpointing stream. */ - + for(i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++){ list_for_each(lh, &dev->objectBucket[i].list) { if (lh) { @@ -4333,9 +3735,9 @@ T(YAFFS_TRACE_CHECKPOINT,( TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR), cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj)); - + ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); - + if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){ ok = yaffs_WriteCheckpointTnodes(obj); } @@ -4343,14 +3745,14 @@ } } } - + /* Dump end of list */ memset(&cp,0xFF,sizeof(yaffs_CheckpointObject)); cp.structType = sizeof(cp); - + if(ok) ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); - + return ok ? 1 : 0; } @@ -4361,22 +3763,20 @@ int ok = 1; int done = 0; yaffs_Object *hardList = NULL; - + 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)); + /* printf("structure parsing failed\n"); */ ok = 0; } - - T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR), - cp.objectId,cp.parentId,cp.variantType,cp.chunkId)); - + if(ok && cp.objectId == ~0) done = 1; else if(ok){ obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType); + T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d obj addr %x" TENDSTR), + cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj)); if(obj) { yaffs_CheckpointObjectToObject(obj,&cp); if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) { @@ -4387,93 +3787,39 @@ hardList; hardList = obj; } - + } } } - + if(ok) yaffs_HardlinkFixup(dev,hardList); - + return ok ? 1 : 0; } -static int yaffs_WriteCheckpointSum(yaffs_Device *dev) -{ - __u32 checkpointSum; - int ok; - - yaffs_GetCheckpointSum(dev,&checkpointSum); - - ok = (yaffs_CheckpointWrite(dev,&checkpointSum,sizeof(checkpointSum)) == sizeof(checkpointSum)); - - if(!ok) - return 0; - - return 1; -} - -static int yaffs_ReadCheckpointSum(yaffs_Device *dev) -{ - __u32 checkpointSum0; - __u32 checkpointSum1; - int ok; - - yaffs_GetCheckpointSum(dev,&checkpointSum0); - - ok = (yaffs_CheckpointRead(dev,&checkpointSum1,sizeof(checkpointSum1)) == sizeof(checkpointSum1)); - - if(!ok) - return 0; - - if(checkpointSum0 != checkpointSum1) - return 0; - - return 1; -} - - static int yaffs_WriteCheckpointData(yaffs_Device *dev) { - int ok = 1; - - if(dev->skipCheckpointWrite || !dev->isYaffs2){ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint write" TENDSTR))); - ok = 0; - } - + int ok; + + ok = yaffs_CheckpointOpen(dev,1); + if(ok) - ok = yaffs_CheckpointOpen(dev,1); - - if(ok){ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR))); ok = yaffs_WriteCheckpointValidityMarker(dev,1); - } - if(ok){ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint device" TENDSTR))); + if(ok) ok = yaffs_WriteCheckpointDevice(dev); - } - if(ok){ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint objects" TENDSTR))); + if(ok) ok = yaffs_WriteCheckpointObjects(dev); - } - if(ok){ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR))); + if(ok) ok = yaffs_WriteCheckpointValidityMarker(dev,0); - } - - if(ok){ - ok = yaffs_WriteCheckpointSum(dev); - } - - + if(!yaffs_CheckpointClose(dev)) ok = 0; - + if(ok) dev->isCheckpointed = 1; - else + else dev->isCheckpointed = 0; return dev->isCheckpointed; @@ -4481,44 +3827,27 @@ static int yaffs_ReadCheckpointData(yaffs_Device *dev) { - int ok = 1; - - if(dev->skipCheckpointRead || !dev->isYaffs2){ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint read" TENDSTR))); - ok = 0; - } - + int ok; + + ok = yaffs_CheckpointOpen(dev,0); /* open for read */ + if(ok) - ok = yaffs_CheckpointOpen(dev,0); /* open for read */ - - if(ok){ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR))); ok = yaffs_ReadCheckpointValidityMarker(dev,1); - } - if(ok){ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint device" TENDSTR))); + if(ok) ok = yaffs_ReadCheckpointDevice(dev); - } - if(ok){ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint objects" TENDSTR))); + if(ok) ok = yaffs_ReadCheckpointObjects(dev); - } - if(ok){ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR))); + if(ok) ok = yaffs_ReadCheckpointValidityMarker(dev,0); - } + - if(ok){ - ok = yaffs_ReadCheckpointSum(dev); - T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint checksum %d" TENDSTR),ok)); - } if(!yaffs_CheckpointClose(dev)) ok = 0; if(ok) dev->isCheckpointed = 1; - else + else dev->isCheckpointed = 0; return ok ? 1 : 0; @@ -4527,7 +3856,7 @@ static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) { - if(dev->isCheckpointed || + if(dev->isCheckpointed || dev->blocksInCheckpoint > 0){ dev->isCheckpointed = 0; yaffs_CheckpointInvalidateStream(dev); @@ -4539,19 +3868,13 @@ int yaffs_CheckpointSave(yaffs_Device *dev) { - + yaffs_ReportOddballBlocks(dev); T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); - yaffs_VerifyObjects(dev); - yaffs_VerifyBlocks(dev); - yaffs_VerifyFreeChunks(dev); - - if(!dev->isCheckpointed) { - yaffs_InvalidateCheckpoint(dev); + if(!dev->isCheckpointed) yaffs_WriteCheckpointData(dev); - } - - T(YAFFS_TRACE_ALWAYS,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); + + T(YAFFS_TRACE_CHECKPOINT,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); return dev->isCheckpointed; } @@ -4560,17 +3883,13 @@ { int retval; T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); - + retval = yaffs_ReadCheckpointData(dev); - if(dev->isCheckpointed){ - yaffs_VerifyObjects(dev); - yaffs_VerifyBlocks(dev); - yaffs_VerifyFreeChunks(dev); - } - T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); - + + yaffs_ReportOddballBlocks(dev); + return retval; } @@ -4606,7 +3925,7 @@ chunk++; /* OK now check for the curveball where the start and end are in - * the same chunk. + * the same chunk. */ if ((start + n) < dev->nDataBytesPerChunk) { nToCopy = n; @@ -4763,7 +4082,7 @@ yaffs_ChunkCache *cache; /* If we can't find the data in the cache, then load the cache */ cache = yaffs_FindChunkCache(in, chunk); - + if (!cache && yaffs_CheckSpaceForAllocation(in-> myDev)) { @@ -4776,12 +4095,12 @@ cache-> data); } - else if(cache && + else if(cache && !cache->dirty && !yaffs_CheckSpaceForAllocation(in->myDev)){ /* Drop the cache if it was a read cache item and * no space check has been made for it. - */ + */ cache = NULL; } @@ -4945,9 +4264,9 @@ int oldFileSize = in->variant.fileVariant.fileSize; int newSizeOfPartialChunk; int newFullChunks; - + yaffs_Device *dev = in->myDev; - + yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk); yaffs_FlushFilesChunkCache(in); @@ -4969,7 +4288,7 @@ if (newSizeOfPartialChunk != 0) { int lastChunk = 1 + newFullChunks; - + __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); /* Got to read and rewrite the last chunk with its new size and zero pad */ @@ -4993,8 +4312,8 @@ in->variant.fileVariant.fileSize = newSize; } - - + + /* Write a new object header. * show we've shrunk the file, if need be * Do this only if the file is not in the deleted directories. @@ -5058,7 +4377,7 @@ if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) { /* Move to the unlinked directory so we have a record that it was deleted. */ - yaffs_ChangeObjectName(in, in->myDev->deletedDir,"deleted", 0, 0); + yaffs_ChangeObjectName(in, in->myDev->deletedDir, NULL, 0, 0); } @@ -5096,7 +4415,7 @@ if (immediateDeletion) { retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir, - "deleted", 0, 0); + NULL, 0, 0); T(YAFFS_TRACE_TRACING, (TSTR("yaffs: immediate deletion of file %d" TENDSTR), in->objectId)); @@ -5109,7 +4428,7 @@ } else { retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir, - "unlinked", 0, 0); + NULL, 0, 0); } } @@ -5313,7 +4632,7 @@ { yaffs_Object *hl; yaffs_Object *in; - + while (hardList) { hl = hardList; hardList = (yaffs_Object *) (hardList->hardLinks.next); @@ -5370,6 +4689,7 @@ int deleted; yaffs_BlockState state; yaffs_Object *hardList = NULL; + yaffs_Object *hl; yaffs_BlockInfo *bi; int sequenceNumber; yaffs_ObjectHeader *oh; @@ -5377,9 +4697,6 @@ yaffs_Object *parent; int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; - int alloc_failed = 0; - - __u8 *chunkData; yaffs_BlockIndex *blockIndex = NULL; @@ -5389,9 +4706,9 @@ (TSTR("yaffs_Scan is not for YAFFS2!" TENDSTR))); return YAFFS_FAIL; } - + //TODO Throw all the yaffs2 stuuf out of yaffs_Scan since it is only for yaffs1 format. - + T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR), dev->internalStartBlock, dev->internalEndBlock)); @@ -5402,8 +4719,6 @@ if (dev->isYaffs2) { blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); - if(!blockIndex) - return YAFFS_FAIL; } /* Scan all the blocks to determine their state */ @@ -5485,7 +4800,7 @@ } /* For each block.... */ - for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; + for (blockIterator = startIterator; blockIterator <= endIterator; blockIterator++) { if (dev->isYaffs2) { @@ -5501,7 +4816,7 @@ deleted = 0; /* For each chunk in each block that needs scanning....*/ - for (c = 0; !alloc_failed && c < dev->nChunksPerBlock && + for (c = 0; c < dev->nChunksPerBlock && state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { /* Read the tags and decide what to do */ chunk = blk * dev->nChunksPerBlock + c; @@ -5520,7 +4835,7 @@ /*T((" %d %d deleted\n",blk,c)); */ } else if (!tags.chunkUsed) { /* An unassigned chunk in the block - * This means that either the block is empty or + * This means that either the block is empty or * this is the one being allocated from */ @@ -5537,9 +4852,9 @@ state = YAFFS_BLOCK_STATE_ALLOCATING; dev->allocationBlock = blk; dev->allocationPage = c; - dev->allocationBlockFinder = blk; + dev->allocationBlockFinder = blk; /* Set it to here to encourage the allocator to go forth from here. */ - + /* Yaffs2 sanity check: * This should be the one with the highest sequence number */ @@ -5569,20 +4884,12 @@ /* PutChunkIntoFile checks for a clash (two data chunks with * the same chunkId). */ - - if(!in) - alloc_failed = 1; - - if(in){ - if(!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk,1)) - alloc_failed = 1; - } - + yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, + 1); endpos = (tags.chunkId - 1) * dev->nDataBytesPerChunk + tags.byteCount; - if (in && - in->variantType == YAFFS_OBJECT_TYPE_FILE + if (in->variantType == YAFFS_OBJECT_TYPE_FILE && in->variant.fileVariant.scannedFileSize < endpos) { in->variant.fileVariant. @@ -5613,7 +4920,7 @@ tags.objectId); if (in && in->variantType != oh->type) { /* This should not happen, but somehow - * Wev'e ended up with an objectId that has been reused but not yet + * Wev'e ended up with an objectId that has been reused but not yet * deleted, and worse still it has changed type. Delete the old object. */ @@ -5627,17 +4934,14 @@ objectId, oh->type); - if(!in) - alloc_failed = 1; - - if (in && oh->shadowsObject > 0) { + if (oh->shadowsObject > 0) { yaffs_HandleShadowedObject(dev, oh-> shadowsObject, 0); } - if (in && in->valid) { + if (in->valid) { /* We have already filled this one. We have a duplicate and need to resolve it. */ unsigned existingSerial = in->serial; @@ -5658,7 +4962,7 @@ } } - if (in && !in->valid && + if (!in->valid && (tags.objectId == YAFFS_OBJECTID_ROOT || tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) { /* We only load some info, don't fiddle with directory structure */ @@ -5683,7 +4987,7 @@ #endif in->chunkId = chunk; - } else if (in && !in->valid) { + } else if (!in->valid) { /* we need to load this info */ in->valid = 1; @@ -5752,11 +5056,11 @@ * Since we might scan a hardlink before its equivalent object is scanned * we put them all in a list. * After scanning is complete, we should have all the objects, so we run through this - * list and fix up all the chains. + * list and fix up all the chains. */ switch (in->variantType) { - case YAFFS_OBJECT_TYPE_UNKNOWN: + case YAFFS_OBJECT_TYPE_UNKNOWN: /* Todo got a problem */ break; case YAFFS_OBJECT_TYPE_FILE: @@ -5791,11 +5095,10 @@ case YAFFS_OBJECT_TYPE_SPECIAL: /* Do nothing */ break; - case YAFFS_OBJECT_TYPE_SYMLINK: - in->variant.symLinkVariant.alias = + case YAFFS_OBJECT_TYPE_SYMLINK: + in->variant.symLinkVariant. + alias = yaffs_CloneString(oh->alias); - if(!in->variant.symLinkVariant.alias) - alloc_failed = 1; break; } @@ -5826,11 +5129,11 @@ if (blockIndex) { YFREE(blockIndex); } - - + + /* Ok, we've done all the scanning. * Fix up the hard link chains. - * We should now have scanned all the objects, now it's time to add these + * We should now have scanned all the objects, now it's time to add these * hardlinks. */ @@ -5857,13 +5160,8 @@ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); - if(alloc_failed){ - return YAFFS_FAIL; - } - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR))); - return YAFFS_OK; } @@ -5874,23 +5172,19 @@ yaffs_Device *dev = in->myDev; yaffs_ExtendedTags tags; int result; - int alloc_failed = 0; - - if(!in) - return; - + #if 0 T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR), in->objectId, in->lazyLoaded ? "not yet" : "already")); #endif - + if(in->lazyLoaded){ in->lazyLoaded = 0; chunkData = yaffs_GetTempBuffer(dev, __LINE__); result = yaffs_ReadChunkWithTagsFromNAND(dev,in->chunkId,chunkData,&tags); - oh = (yaffs_ObjectHeader *) chunkData; + oh = (yaffs_ObjectHeader *) chunkData; in->yst_mode = oh->yst_mode; #ifdef CONFIG_YAFFS_WINCE @@ -5907,17 +5201,14 @@ in->yst_mtime = oh->yst_mtime; in->yst_ctime = oh->yst_ctime; in->yst_rdev = oh->yst_rdev; - + #endif yaffs_SetObjectName(in, oh->name); - - if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK){ + + if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias); - if(!in->variant.symLinkVariant.alias) - alloc_failed = 1; /* Not returned to caller */ - } - + yaffs_ReleaseTempBuffer(dev,chunkData, __LINE__); } } @@ -5945,13 +5236,12 @@ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; int itsUnlinked; __u8 *chunkData; - + int fileSize; int isShrink; int foundChunksInBlock; int equivalentObjectId; - int alloc_failed = 0; - + yaffs_BlockIndex *blockIndex = NULL; int altBlockIndex = 0; @@ -5971,20 +5261,18 @@ dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); - + if(!blockIndex) { blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex)); altBlockIndex = 1; } - + if(!blockIndex) { T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR))); return YAFFS_FAIL; } - - dev->blocksInCheckpoint = 0; - + chunkData = yaffs_GetTempBuffer(dev, __LINE__); /* Scan all the blocks to determine their state */ @@ -6001,15 +5289,15 @@ if(bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT; - + T(YAFFS_TRACE_SCAN_DEBUG, (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, state, sequenceNumber)); - + if(state == YAFFS_BLOCK_STATE_CHECKPOINT){ - dev->blocksInCheckpoint++; - + /* todo .. fix free space ? */ + } else if (state == YAFFS_BLOCK_STATE_DEAD) { T(YAFFS_TRACE_BAD_BLOCKS, (TSTR("block %d is bad" TENDSTR), blk)); @@ -6053,12 +5341,14 @@ /* Sort the blocks */ #ifndef CONFIG_YAFFS_USE_OWN_SORT - yaffs_qsort(blockIndex, nBlocksToScan, - sizeof(yaffs_BlockIndex), ybicmp); + { + /* Use qsort now. */ + qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); + } #else { /* Dungy old bubble sort... */ - + yaffs_BlockIndex temp; int i; int j; @@ -6084,7 +5374,7 @@ (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); /* For each block.... backwards */ - for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator; + for (blockIterator = endIterator; blockIterator >= startIterator; blockIterator--) { /* Cooperative multitasking! This loop can run for so long that watchdog timers expire. */ @@ -6094,22 +5384,18 @@ blk = blockIndex[blockIterator].block; bi = yaffs_GetBlockInfo(dev, blk); - - state = bi->blockState; deleted = 0; /* For each chunk in each block that needs scanning.... */ foundChunksInBlock = 0; - for (c = dev->nChunksPerBlock - 1; - !alloc_failed && c >= 0 && + for (c = dev->nChunksPerBlock - 1; c >= 0 && (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { - /* Scan backwards... + /* Scan backwards... * Read the tags and decide what to do */ - chunk = blk * dev->nChunksPerBlock + c; result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, @@ -6123,14 +5409,14 @@ * it is a chunk that was skipped due to failing the erased * check. Just skip it so that it can be deleted. * But, more typically, We get here when this is an unallocated - * chunk and his means that either the block is empty or + * chunk and his means that either the block is empty or * this is the one being allocated from */ if(foundChunksInBlock) { /* This is a chunk that was skipped due to failing the erased check */ - + } else if (c == 0) { /* We're looking at the first chunk in the block so the block is unused */ state = YAFFS_BLOCK_STATE_EMPTY; @@ -6140,7 +5426,7 @@ state == YAFFS_BLOCK_STATE_ALLOCATING) { if(dev->sequenceNumber == bi->sequenceNumber) { /* this is the block being allocated from */ - + T(YAFFS_TRACE_SCAN, (TSTR (" Allocating from %d %d" @@ -6149,34 +5435,34 @@ state = YAFFS_BLOCK_STATE_ALLOCATING; dev->allocationBlock = blk; dev->allocationPage = c; - dev->allocationBlockFinder = blk; + dev->allocationBlockFinder = blk; } else { /* This is a partially written block that is not * the current allocation block. This block must have * had a write failure, so set up for retirement. */ - + bi->needsRetiring = 1; bi->gcPrioritise = 1; - + T(YAFFS_TRACE_ALWAYS, (TSTR("Partially written block %d being set for retirement" TENDSTR), blk)); } } - + } dev->nFreeChunks++; - + } else if (tags.chunkId > 0) { /* chunkId > 0 so it is a data chunk... */ unsigned int endpos; __u32 chunkBase = (tags.chunkId - 1) * dev->nDataBytesPerChunk; - + foundChunksInBlock = 1; @@ -6187,29 +5473,21 @@ tags. objectId, YAFFS_OBJECT_TYPE_FILE); - if(!in){ - /* Out of memory */ - alloc_failed = 1; - } - - if (in && - in->variantType == YAFFS_OBJECT_TYPE_FILE + if (in->variantType == YAFFS_OBJECT_TYPE_FILE && chunkBase < in->variant.fileVariant.shrinkSize) { /* This has not been invalidated by a resize */ - if(!yaffs_PutChunkIntoFile(in, tags.chunkId, - chunk, -1)){ - alloc_failed = 1; - } + yaffs_PutChunkIntoFile(in, tags.chunkId, + chunk, -1); - /* File size is calculated by looking at the data chunks if we have not + /* File size is calculated by looking at the data chunks if we have not * seen an object header yet. Stop this practice once we find an object header. */ endpos = (tags.chunkId - 1) * dev->nDataBytesPerChunk + tags.byteCount; - + if (!in->valid && /* have not got an object header yet */ in->variant.fileVariant. scannedFileSize < endpos) { @@ -6221,7 +5499,7 @@ scannedFileSize; } - } else if(in) { + } else { /* This chunk has been invalidated by a resize, so delete */ yaffs_DeleteChunk(dev, chunk, 1, __LINE__); @@ -6255,7 +5533,7 @@ ) { /* If we don't have valid info then we need to read the chunk - * TODO In future we can probably defer reading the chunk and + * TODO In future we can probably defer reading the chunk and * living with invalid data until needed. */ @@ -6283,12 +5561,12 @@ if (in->valid) { /* We have already filled this one. - * We have a duplicate that will be discarded, but + * We have a duplicate that will be discarded, but * we first have to suck out resize info if it is a file. */ - if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && - ((oh && + if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && + ((oh && oh-> type == YAFFS_OBJECT_TYPE_FILE)|| (tags.extraHeaderInfoAvailable && tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE)) @@ -6339,7 +5617,7 @@ YAFFS_OBJECTID_LOSTNFOUND)) { /* We only load some info, don't fiddle with directory structure */ in->valid = 1; - + if(oh) { in->variantType = oh->type; @@ -6358,13 +5636,13 @@ in->yst_mtime = oh->yst_mtime; in->yst_ctime = oh->yst_ctime; in->yst_rdev = oh->yst_rdev; - + #endif } else { in->variantType = tags.extraObjectType; in->lazyLoaded = 1; } - + in->chunkId = chunk; } else if (!in->valid) { @@ -6372,7 +5650,7 @@ in->valid = 1; in->chunkId = chunk; - + if(oh) { in->variantType = oh->type; @@ -6393,12 +5671,12 @@ in->yst_rdev = oh->yst_rdev; #endif - if (oh->shadowsObject > 0) + if (oh->shadowsObject > 0) yaffs_HandleShadowedObject(dev, oh-> shadowsObject, 1); - + yaffs_SetObjectName(in, oh->name); parent = @@ -6466,11 +5744,11 @@ * Since we might scan a hardlink before its equivalent object is scanned * we put them all in a list. * After scanning is complete, we should have all the objects, so we run - * through this list and fix up all the chains. + * through this list and fix up all the chains. */ switch (in->variantType) { - case YAFFS_OBJECT_TYPE_UNKNOWN: + case YAFFS_OBJECT_TYPE_UNKNOWN: /* Todo got a problem */ break; case YAFFS_OBJECT_TYPE_FILE: @@ -6479,7 +5757,7 @@ scannedFileSize < fileSize) { /* This covers the case where the file size is greater * than where the data is - * This will happen if the file is resized to be larger + * This will happen if the file is resized to be larger * than its current data extents. */ in->variant.fileVariant.fileSize = fileSize; @@ -6509,21 +5787,16 @@ /* Do nothing */ break; case YAFFS_OBJECT_TYPE_SYMLINK: - if(oh){ + if(oh) in->variant.symLinkVariant.alias = yaffs_CloneString(oh-> alias); - if(!in->variant.symLinkVariant.alias) - alloc_failed = 1; - } break; } } - } - - } /* End of scanning for each chunk */ + } if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { /* If we got this far while scanning, then the block is fully allocated. */ @@ -6541,19 +5814,19 @@ } - if (altBlockIndex) + if (altBlockIndex) YFREE_ALT(blockIndex); else YFREE(blockIndex); - + /* Ok, we've done all the scanning. * Fix up the hard link chains. - * We should now have scanned all the objects, now it's time to add these + * We should now have scanned all the objects, now it's time to add these * hardlinks. */ yaffs_HardlinkFixup(dev,hardList); - - + + /* * Sort out state of unlinked and deleted objects. */ @@ -6587,10 +5860,6 @@ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); - if(alloc_failed){ - return YAFFS_FAIL; - } - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR))); return YAFFS_OK; @@ -6601,10 +5870,10 @@ static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj) { yaffs_Device *dev = obj->myDev; - + if(dev && dev->removeObjectCallback) dev->removeObjectCallback(obj); - + list_del_init(&obj->siblings); obj->parent = NULL; } @@ -6682,7 +5951,7 @@ list_for_each(i, &directory->variant.directoryVariant.children) { if (i) { l = list_entry(i, yaffs_Object, siblings); - + yaffs_CheckObjectDetailsLoaded(l); /* Special case for lost-n-found */ @@ -6690,14 +5959,14 @@ if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) { return l; } - } else if (yaffs_SumCompare(l->sum, sum) || l->chunkId <= 0) + } else if (yaffs_SumCompare(l->sum, sum) || l->chunkId <= 0) { /* LostnFound cunk called Objxxx * Do a real check */ yaffs_GetObjectName(l, buffer, YAFFS_MAX_NAME_LENGTH); - if (yaffs_strncmp(name, buffer,YAFFS_MAX_NAME_LENGTH) == 0) { + if (yaffs_strcmp(name, buffer) == 0) { return l; } @@ -6753,7 +6022,6 @@ if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { /* We want the object id of the equivalent object, not this one */ obj = obj->variant.hardLinkVariant.equivalentObject; - yaffs_CheckObjectDetailsLoaded(obj); } return obj; @@ -6762,7 +6030,7 @@ int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize) { memset(name, 0, buffSize * sizeof(YCHAR)); - + yaffs_CheckObjectDetailsLoaded(obj); if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { @@ -6991,16 +6259,15 @@ } -static int yaffs_CreateInitialDirectories(yaffs_Device *dev) +static void yaffs_CreateInitialDirectories(yaffs_Device *dev) { /* Initialise the unlinked, deleted, root and lost and found directories */ - + dev->lostNFoundDir = dev->rootDir = NULL; dev->unlinkedDir = dev->deletedDir = NULL; dev->unlinkedDir = yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); - dev->deletedDir = yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); @@ -7010,18 +6277,11 @@ dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND, YAFFS_LOSTNFOUND_MODE | S_IFDIR); - - if(dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir){ - yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir); - return YAFFS_OK; - } - - return YAFFS_FAIL; + yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir); } int yaffs_GutsInitialise(yaffs_Device * dev) { - int init_failed = 0; unsigned x; int bits; @@ -7049,12 +6309,12 @@ /* Check geometry parameters. */ - if ((dev->isYaffs2 && dev->nDataBytesPerChunk < 1024) || - (!dev->isYaffs2 && dev->nDataBytesPerChunk != 512) || - dev->nChunksPerBlock < 2 || - dev->nReservedBlocks < 2 || - dev->internalStartBlock <= 0 || - dev->internalEndBlock <= 0 || + if ((dev->isYaffs2 && dev->nDataBytesPerChunk < 1024) || + (!dev->isYaffs2 && dev->nDataBytesPerChunk != 512) || + dev->nChunksPerBlock < 2 || + dev->nReservedBlocks < 2 || + dev->internalStartBlock <= 0 || + dev->internalEndBlock <= 0 || dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2) // otherwise it is too small ) { T(YAFFS_TRACE_ALWAYS, @@ -7100,9 +6360,9 @@ /* OK now calculate a few things for the device */ - + /* - * Calculate all the chunk size manipulation numbers: + * Calculate all the chunk size manipulation numbers: */ /* Start off assuming it is a power of 2 */ dev->chunkShift = ShiftDiv(dev->nDataBytesPerChunk); @@ -7121,7 +6381,7 @@ dev->chunkShift = 0; dev->chunkMask = 0; } - + /* * Calculate chunkGroupBits. @@ -7129,9 +6389,9 @@ */ x = dev->nChunksPerBlock * (dev->internalEndBlock + 1); - + bits = ShiftsGE(x); - + /* Set up tnode width if wide tnodes are enabled. */ if(!dev->wideTnodesDisabled){ /* bits must be even so that we end up with 32-bit words */ @@ -7144,20 +6404,20 @@ } else dev->tnodeWidth = 16; - + dev->tnodeMask = (1<tnodeWidth)-1; - + /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), * so if the bitwidth of the * chunk range we're using is greater than 16 we need * to figure out chunk shift and chunkGroupSize */ - + if (bits <= dev->tnodeWidth) dev->chunkGroupBits = 0; else dev->chunkGroupBits = bits - dev->tnodeWidth; - + dev->chunkGroupSize = 1 << dev->chunkGroupBits; @@ -7193,111 +6453,71 @@ dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */ /* Initialise temporary buffers and caches. */ - if(!yaffs_InitialiseTempBuffers(dev)) - init_failed = 1; - - dev->srCache = NULL; - dev->gcCleanupList = NULL; - - - if (!init_failed && - dev->nShortOpCaches > 0) { + { + int i; + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { + dev->tempBuffer[i].line = 0; /* not in use */ + dev->tempBuffer[i].buffer = + YMALLOC_DMA(dev->nDataBytesPerChunk); + } + } + + if (dev->nShortOpCaches > 0) { int i; - __u8 *buf; - int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache); if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) { dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; } - buf = dev->srCache = YMALLOC(srCacheBytes); + dev->srCache = + YMALLOC(dev->nShortOpCaches * sizeof(yaffs_ChunkCache)); - if(dev->srCache) - memset(dev->srCache,0,srCacheBytes); - - for (i = 0; i < dev->nShortOpCaches && buf; i++) { + for (i = 0; i < dev->nShortOpCaches; i++) { dev->srCache[i].object = NULL; dev->srCache[i].lastUse = 0; dev->srCache[i].dirty = 0; - dev->srCache[i].data = buf = YMALLOC_DMA(dev->nDataBytesPerChunk); + dev->srCache[i].data = YMALLOC_DMA(dev->nDataBytesPerChunk); } - if(!buf) - init_failed = 1; - dev->srLastUse = 0; } dev->cacheHits = 0; - - if(!init_failed){ - dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); - if(!dev->gcCleanupList) - init_failed = 1; - } + + dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); if (dev->isYaffs2) { dev->useHeaderFileSize = 1; } - if(!init_failed && !yaffs_InitialiseBlocks(dev)) - init_failed = 1; + yaffs_InitialiseBlocks(dev); yaffs_InitialiseTnodes(dev); yaffs_InitialiseObjects(dev); - if(!init_failed && !yaffs_CreateInitialDirectories(dev)) - init_failed = 1; - - - if(!init_failed){ - /* Now scan the flash. */ - if (dev->isYaffs2) { - if(yaffs_CheckpointRestore(dev)) { - T(YAFFS_TRACE_ALWAYS, - (TSTR("yaffs: restored from checkpoint" TENDSTR))); - } else { - - /* Clean up the mess caused by an aborted checkpoint load - * and scan backwards. - */ - yaffs_DeinitialiseBlocks(dev); - yaffs_DeinitialiseTnodes(dev); - yaffs_DeinitialiseObjects(dev); - - - dev->nErasedBlocks = 0; - dev->nFreeChunks = 0; - dev->allocationBlock = -1; - dev->allocationPage = -1; - dev->nDeletedFiles = 0; - dev->nUnlinkedFiles = 0; - dev->nBackgroundDeletions = 0; - dev->oldestDirtySequence = 0; + yaffs_CreateInitialDirectories(dev); - if(!init_failed && !yaffs_InitialiseBlocks(dev)) - init_failed = 1; - yaffs_InitialiseTnodes(dev); - yaffs_InitialiseObjects(dev); - - if(!init_failed && !yaffs_CreateInitialDirectories(dev)) - init_failed = 1; - - if(!init_failed && !yaffs_ScanBackwards(dev)) - init_failed = 1; - } - }else - if(!yaffs_Scan(dev)) - init_failed = 1; - } + /* Now scan the flash. */ + if (dev->isYaffs2) { + if(yaffs_CheckpointRestore(dev)) { + T(YAFFS_TRACE_ALWAYS, + (TSTR("yaffs: restored from checkpoint" TENDSTR))); + } else { - if(init_failed){ - /* Clean up the mess */ - T(YAFFS_TRACE_TRACING, - (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR))); + /* Clean up the mess caused by an aborted checkpoint load + * and scan backwards. + */ + yaffs_DeinitialiseBlocks(dev); + yaffs_DeinitialiseTnodes(dev); + yaffs_DeinitialiseObjects(dev); + yaffs_InitialiseBlocks(dev); + yaffs_InitialiseTnodes(dev); + yaffs_InitialiseObjects(dev); + yaffs_CreateInitialDirectories(dev); - yaffs_Deinitialise(dev); - return YAFFS_FAIL; - } + yaffs_ScanBackwards(dev); + } + }else + yaffs_Scan(dev); /* Zero out stats */ dev->nPageReads = 0; @@ -7309,9 +6529,6 @@ dev->nRetiredBlocks = 0; yaffs_VerifyFreeChunks(dev); - yaffs_VerifyBlocks(dev); - - T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); return YAFFS_OK; @@ -7326,17 +6543,13 @@ yaffs_DeinitialiseBlocks(dev); yaffs_DeinitialiseTnodes(dev); yaffs_DeinitialiseObjects(dev); - if (dev->nShortOpCaches > 0 && - dev->srCache) { + if (dev->nShortOpCaches > 0) { for (i = 0; i < dev->nShortOpCaches; i++) { - if(dev->srCache[i].data) - YFREE(dev->srCache[i].data); - dev->srCache[i].data = NULL; + YFREE(dev->srCache[i].data); } YFREE(dev->srCache); - dev->srCache = NULL; } YFREE(dev->gcCleanupList); @@ -7394,7 +6607,7 @@ #endif nFree += dev->nDeletedFiles; - + /* Now count the number of dirty chunks in the cache and subtract those */ { @@ -7408,12 +6621,12 @@ nFree -= nDirtyCacheChunks; nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); - + /* Now we figure out how much to reserve for the checkpoint and report that... */ blocksForCheckpoint = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; if(blocksForCheckpoint < 0) blocksForCheckpoint = 0; - + nFree -= (blocksForCheckpoint * dev->nChunksPerBlock); if (nFree < 0) @@ -7427,15 +6640,9 @@ static void yaffs_VerifyFreeChunks(yaffs_Device * dev) { - int counted; - int difference; - - if(yaffs_SkipVerification(dev)) - return; - - counted = yaffs_CountFreeChunks(dev); + int counted = yaffs_CountFreeChunks(dev); - difference = dev->nFreeChunks - counted; + int difference = dev->nFreeChunks - counted; if (difference) { T(YAFFS_TRACE_ALWAYS, diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_guts.h linux-2.6.24.7.new/fs/yaffs2/yaffs_guts.h --- linux-2.6.24.7/fs/yaffs2/yaffs_guts.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_guts.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 @@ -22,11 +22,11 @@ #define YAFFS_OK 1 #define YAFFS_FAIL 0 -/* Give us a Y=0x59, - * Give us an A=0x41, - * Give us an FF=0xFF +/* Give us a Y=0x59, + * Give us an A=0x41, + * Give us an FF=0xFF * Give us an S=0x53 - * And what have we got... + * And what have we got... */ #define YAFFS_MAGIC 0x5941FF53 @@ -63,7 +63,9 @@ #define YAFFS_OBJECT_SPACE 0x40000 -#define YAFFS_CHECKPOINT_VERSION 3 +#define YAFFS_NCHECKPOINT_OBJECTS 5000 + +#define YAFFS_CHECKPOINT_VERSION 2 #ifdef CONFIG_YAFFS_UNICODE #define YAFFS_MAX_NAME_LENGTH 127 @@ -92,17 +94,11 @@ #define YAFFS_N_TEMP_BUFFERS 4 -/* 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. - * Default to something in the order of 5 to 10 blocks worth of chunks. - */ -#define YAFFS_WR_ATTEMPTS (5*64) - /* Sequence numbers are used in YAFFS2 to determine block allocation order. * The range is limited slightly to help distinguish bad numbers from good. * This also allows us to perhaps in the future use special numbers for * special purposes. - * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years, + * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years, * and is a larger number than the lifetime of a 2GB device. */ #define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 @@ -166,8 +162,6 @@ YAFFS_OBJECT_TYPE_SPECIAL } yaffs_ObjectType; -#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL - typedef struct { unsigned validMarker0; @@ -178,7 +172,7 @@ /* The following stuff only has meaning when we read */ yaffs_ECCResult eccResult; - unsigned blockBad; + unsigned blockBad; /* YAFFS 1 stuff */ unsigned chunkDeleted; /* The chunk is marked deleted */ @@ -244,35 +238,32 @@ /* This block is empty */ YAFFS_BLOCK_STATE_ALLOCATING, - /* This block is partially allocated. + /* This block is partially allocated. * At least one page holds valid data. * This is the one currently being used for page * allocation. Should never be more than one of these */ - YAFFS_BLOCK_STATE_FULL, + YAFFS_BLOCK_STATE_FULL, /* All the pages in this block have been allocated. */ YAFFS_BLOCK_STATE_DIRTY, - /* All pages have been allocated and deleted. + /* All pages have been allocated and deleted. * Erase me, reuse me. */ - YAFFS_BLOCK_STATE_CHECKPOINT, + YAFFS_BLOCK_STATE_CHECKPOINT, /* This block is assigned to holding checkpoint data. */ - YAFFS_BLOCK_STATE_COLLECTING, + YAFFS_BLOCK_STATE_COLLECTING, /* This block is being garbage collected */ - YAFFS_BLOCK_STATE_DEAD + YAFFS_BLOCK_STATE_DEAD /* This block has failed and is not in use */ } yaffs_BlockState; -#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) - - typedef struct { int softDeletions:10; /* number of soft deleted pages */ @@ -281,7 +272,7 @@ __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */ /* and retire the block. */ __u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */ - __u32 gcPrioritise: 1; /* An ECC check or blank check has failed on this block. + __u32 gcPrioritise: 1; /* An ECC check or bank check has failed on this block. It should be prioritised for GC */ __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */ @@ -408,7 +399,7 @@ __u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */ __u8 unlinkAllowed:1; __u8 dirty:1; /* the object needs to be written to flash */ - __u8 valid:1; /* When the file system is being loaded up, this + __u8 valid:1; /* When the file system is being loaded up, this * object might be created before the data * is available (ie. file data records appear before the header). */ @@ -430,11 +421,11 @@ /* directory structure stuff */ /* also used for linking up the free list */ - struct yaffs_ObjectStruct *parent; + struct yaffs_ObjectStruct *parent; struct list_head siblings; /* Where's my object header in NAND? */ - int chunkId; + int chunkId; int nDataChunks; /* Number of data chunks attached to the file. */ @@ -490,26 +481,26 @@ } yaffs_ObjectBucket; -/* yaffs_CheckpointObject holds the definition of an object as dumped +/* yaffs_CheckpointObject holds the definition of an object as dumped * by checkpointing. */ typedef struct { int structType; - __u32 objectId; + __u32 objectId; __u32 parentId; int chunkId; - + yaffs_ObjectType variantType:3; - __u8 deleted:1; - __u8 softDeleted:1; - __u8 unlinked:1; - __u8 fake:1; + __u8 deleted:1; + __u8 softDeleted:1; + __u8 unlinked:1; + __u8 fake:1; __u8 renameAllowed:1; __u8 unlinkAllowed:1; - __u8 serial; - - int nDataChunks; + __u8 serial; + + int nDataChunks; __u32 fileSizeOrEquivalentObjectId; }yaffs_CheckpointObject; @@ -539,14 +530,17 @@ int endBlock; /* End block we're allowed to use */ int nReservedBlocks; /* We want this tuneable so that we can reduce */ /* reserved blocks on NOR and RAM. */ - - + + /* Stuff used by the partitioned checkpointing mechanism */ + int checkpointStartBlock; + int checkpointEndBlock; + /* Stuff used by the shared space checkpointing mechanism */ /* If this value is zero, then this mechanism is disabled */ - + int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */ - + int nShortOpCaches; /* If <= 0, then short op caching is disabled, else @@ -561,7 +555,7 @@ * On an mtd this holds the mtd pointer. */ void *superBlock; - + /* NAND access functions (Must be set before calling YAFFS)*/ int (*writeChunkToNAND) (struct yaffs_DeviceStruct * dev, @@ -587,57 +581,53 @@ #endif int isYaffs2; - - /* The removeObjectCallback function must be supplied by OS flavours that + + /* The removeObjectCallback function must be supplied by OS flavours that * need it. The Linux kernel does not use this, but yaffs direct does use * it to implement the faster readdir */ void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj); - + /* Callback to mark the superblock dirsty */ void (*markSuperBlockDirty)(void * superblock); - + int wideTnodesDisabled; /* Set to disable wide tnodes */ - + /* End of stuff that must be set before initialisation. */ - /* Checkpoint control. Can be set before or after initialisation */ - __u8 skipCheckpointRead; - __u8 skipCheckpointWrite; - /* Runtime parameters. Set up by YAFFS. */ __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */ __u16 chunkGroupSize; /* == 2^^chunkGroupBits */ - + /* Stuff to support wide tnodes */ __u32 tnodeWidth; __u32 tnodeMask; - + /* Stuff to support various file offses to chunk/offset translations */ /* "Crumbs" for nDataBytesPerChunk not being a power of 2 */ __u32 crumbMask; __u32 crumbShift; __u32 crumbsPerChunk; - + /* Straight shifting for nDataBytesPerChunk being a power of 2 */ __u32 chunkShift; __u32 chunkMask; - + #ifdef __KERNEL__ struct semaphore sem; /* Semaphore for waiting on erasure.*/ struct semaphore grossLock; /* Gross locking semaphore */ - __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer + __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer * at compile time so we have to allocate it. */ void (*putSuperFunc) (struct super_block * sb); #endif int isMounted; - + int isCheckpointed; @@ -646,7 +636,7 @@ int internalEndBlock; int blockOffset; int chunkOffset; - + /* Runtime checkpointing stuff */ int checkpointPageSequence; /* running sequence number of checkpoint pages */ @@ -660,15 +650,13 @@ int checkpointNextBlock; int *checkpointBlockList; int checkpointMaxBlocks; - __u32 checkpointSum; - __u32 checkpointXor; - + /* Block Info */ yaffs_BlockInfo *blockInfo; __u8 *chunkBits; /* bitmap of chunks in use */ unsigned blockInfoAlt:1; /* was allocated using alternative strategy */ unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */ - int chunkBitmapStride; /* Number of bytes of chunkBits per block. + int chunkBitmapStride; /* Number of bytes of chunkBits per block. * Must be consistent with nChunksPerBlock. */ @@ -698,7 +686,6 @@ int currentDirtyChecker; /* Used to find current dirtiest block */ __u32 *gcCleanupList; /* objects to delete at the end of a GC. */ - int nonAggressiveSkip; /* GC state/mode */ /* Statistcs */ int nPageWrites; @@ -716,7 +703,7 @@ int tagsEccUnfixed; int nDeletions; int nUnmarkedDeletions; - + int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ /* Special directories */ @@ -727,7 +714,7 @@ * __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK]; * yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK]; */ - + int bufferedBlock; /* Which block is buffered here? */ int doingBufferedBlockRewrite; @@ -768,7 +755,7 @@ int endBlock; int rfu[100]; } yaffs_SuperBlockHeader; - + /* The CheckpointDevice structure holds the device information that changes at runtime and * must be preserved over unmount/mount cycles. */ diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif.c linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif.c --- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif.c 2009-04-21 14:57:10.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif.c 2009-04-21 15:01:02.000000000 +0200 @@ -12,13 +12,10 @@ */ const char *yaffs_mtdif_c_version = - "$Id: yaffs_mtdif.c,v 1.19 2007-02-14 01:09:06 wookey Exp $"; + "$Id: yaffs_mtdif.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $"; #include "yportenv.h" - - #include "yaffs_mtdif.h" - #include "linux/mtd/mtd.h" #include "linux/types.h" #include "linux/time.h" @@ -54,6 +51,7 @@ 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]; @@ -68,6 +66,11 @@ spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff; nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */ +#if 0 + char i; + for (i=0;i<8;i++) + printk("oob %d :%x",i,oob[i]); +#endif } #endif @@ -78,10 +81,11 @@ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) struct mtd_oob_ops ops; #endif - size_t dummy; + size_mtd_t dummy; int retval = 0; - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; + loff_mtd_t addr = ((loff_mtd_t) chunkInNAND) * dev->nDataBytesPerChunk; + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) __u8 spareAsBytes[8]; /* OOB */ @@ -142,10 +146,11 @@ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) struct mtd_oob_ops ops; #endif - size_t dummy; + size_mtd_t dummy; int retval = 0; - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; + loff_mtd_t addr = ((loff_mtd_t) chunkInNAND) * dev->nDataBytesPerChunk; + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) __u8 spareAsBytes[8]; /* OOB */ @@ -164,7 +169,7 @@ ops.datbuf = data; ops.ooboffs = 0; ops.oobbuf = spareAsBytes; - retval = mtd->read_oob(mtd, addr, &ops); + retval = mtd->read_oob(mtd, addr, &ops); if (dev->useNANDECC) translate_oob2spare(spare, spareAsBytes); } @@ -172,7 +177,7 @@ __u8 *spareAsBytes = (__u8 *) spare; if (data && spare) { - if (dev->useNANDECC) { + if (dev->useNANDECC) { /* Careful, this call adds 2 ints */ /* to the end of the spare data. Calling function */ /* should allocate enough memory for spare, */ @@ -208,8 +213,8 @@ int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber) { struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); - __u32 addr = - ((loff_t) blockNumber) * dev->nDataBytesPerChunk + __u64 addr = + ((loff_mtd_t) blockNumber) * dev->nDataBytesPerChunk * dev->nChunksPerBlock; struct erase_info ei; int retval = 0; diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif.h linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif.h --- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif1-compat.c linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif1-compat.c --- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif1-compat.c 2009-04-21 14:57:10.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif1-compat.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,434 +0,0 @@ -From ian@brightstareng.com Fri May 18 15:06:49 2007 -From ian@brightstareng.com Fri May 18 15:08:21 2007 -Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com) - by apollo.linkchoose.co.uk with esmtp (Exim 4.60) - (envelope-from ) - id 1Hp380-00011e-T6 - for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100 -Received: from localhost (localhost.localdomain [127.0.0.1]) - by zebra.brightstareng.com (Postfix) with ESMTP - id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT) -Received: from zebra.brightstareng.com ([127.0.0.1]) - by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP - id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT) -Received: from pippin (unknown [192.168.1.25]) - by zebra.brightstareng.com (Postfix) with ESMTP - id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT) -From: Ian McDonnell -To: David Goodenough -Subject: Re: something tested this time -- yaffs_mtdif1-compat.c -Date: Fri, 18 May 2007 10:06:49 -0400 -User-Agent: KMail/1.9.1 -References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk> -In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk> -Cc: Andrea Conti , - Charles Manning -MIME-Version: 1.0 -Content-Type: Multipart/Mixed; - boundary="Boundary-00=_5LbTGmt62YoutxM" -Message-Id: <200705181006.49860.ian@brightstareng.com> -X-Virus-Scanned: by amavisd-new at brightstareng.com -Status: R -X-Status: NT -X-KMail-EncryptionState: -X-KMail-SignatureState: -X-KMail-MDN-Sent: - ---Boundary-00=_5LbTGmt62YoutxM -Content-Type: text/plain; - charset="iso-8859-15" -Content-Transfer-Encoding: 7bit -Content-Disposition: inline - -David, Andrea, - -On Friday 18 May 2007 08:34, you wrote: -> Yea team. With this fix in place (I put it in the wrong place -> at first) I can now mount and ls the Yaffs partition without -> an error messages! - -Good news! - -Attached is a newer yaffs_mtdif1.c with a bandaid to help the -2.6.18 and 2.6.19 versions of MTD not trip on the oob read. -See the LINUX_VERSION_CODE conditional in -nandmtd1_ReadChunkWithTagsFromNAND. - --imcd - ---Boundary-00=_5LbTGmt62YoutxM -Content-Type: text/x-csrc; - charset="iso-8859-15"; - name="yaffs_mtdif1.c" -Content-Transfer-Encoding: 7bit -Content-Disposition: attachment; - filename="yaffs_mtdif1.c" - -/* - * 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 (LINUX_VERSION_CODE > KERNEL_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 (LINUX_VERSION_CODE < KERNEL_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 - (void) deleted; /* not used */ -#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++; - 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. - */ -#ifndef CONFIG_YAFFS_9BYTE_TAGS - etags->chunkDeleted = deleted; -#else - etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7); -#endif - 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", 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", - 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, int *pSequenceNumber) -{ - struct mtd_info * mtd = dev->genericDevice; - int chunkNo = blockNo * dev->nChunksPerBlock; - 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); - if (etags.blockBad) { - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, - "block %d is marked bad", blockNo); - state = YAFFS_BLOCK_STATE_DEAD; - } - 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 /*KERNEL_VERSION*/ - ---Boundary-00=_5LbTGmt62YoutxM-- - - - diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif1.c linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif1.c --- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif1.c 2009-04-21 14:57:10.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif1.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,363 +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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - -const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $"; - -#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); - - dev->nPageWrites++; - - 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; - - dev->nPageReads++; - - 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 (LINUX_VERSION_CODE < KERNEL_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", 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, int *pSequenceNumber) -{ - struct mtd_info * mtd = dev->genericDevice; - int chunkNo = blockNo * dev->nChunksPerBlock; - 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); - if (etags.blockBad) { - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, - "block %d is marked bad", blockNo); - state = YAFFS_BLOCK_STATE_DEAD; - } - 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 /*KERNEL_VERSION*/ diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif1.h linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif1.h --- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif1.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif1.h 1970-01-01 01:00:00.000000000 +0100 @@ -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, int *sequenceNumber); - -#endif diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif2.c linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif2.c --- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif2.c 2009-04-21 14:57:10.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif2.c 2009-04-21 15:01:02.000000000 +0200 @@ -14,19 +14,152 @@ /* mtd interface for YAFFS2 */ const char *yaffs_mtdif2_c_version = - "$Id: yaffs_mtdif2.c,v 1.17 2007-02-14 01:09:06 wookey Exp $"; + "$Id: yaffs_mtdif2.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $"; #include "yportenv.h" - - #include "yaffs_mtdif2.h" - #include "linux/mtd/mtd.h" #include "linux/types.h" #include "linux/time.h" #include "yaffs_packedtags2.h" +#define PT2_BYTES 25 + +void nandmtd2_pt2buf(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 pt2_byte_buf[PT2_BYTES]; + + /* Pack buffer with 0xff */ + for (i = 0; i < mtd->oobsize; i++) + dev->spareBuffer[i] = 0xff; + + if (!is_raw) { + *((unsigned int *) &dev->spareBuffer[0]) = pt->t.sequenceNumber; + *((unsigned int *) &dev->spareBuffer[4]) = pt->t.objectId; + *((unsigned int *) &dev->spareBuffer[8]) = pt->t.chunkId; + *((unsigned int *) &dev->spareBuffer[12]) = pt->t.byteCount; + dev->spareBuffer[16] = pt->ecc.colParity; + dev->spareBuffer[17] = pt->ecc.lineParity & 0xff; + dev->spareBuffer[18] = (pt->ecc.lineParity >> 8) & 0xff; + dev->spareBuffer[19] = (pt->ecc.lineParity >> 16) & 0xff; + dev->spareBuffer[20] = (pt->ecc.lineParity >> 24) & 0xff; + dev->spareBuffer[21] = pt->ecc.lineParityPrime & 0xff; + dev->spareBuffer[22] = (pt->ecc.lineParityPrime >> 8) & 0xff; + dev->spareBuffer[23] = (pt->ecc.lineParityPrime >> 16) & 0xff; + dev->spareBuffer[24] = (pt->ecc.lineParityPrime >> 24) & 0xff; + } else { + *((unsigned int *) &pt2_byte_buf[0]) = pt->t.sequenceNumber; + *((unsigned int *) &pt2_byte_buf[4]) = pt->t.objectId; + *((unsigned int *) &pt2_byte_buf[8]) = pt->t.chunkId; + *((unsigned int *) &pt2_byte_buf[12]) = pt->t.byteCount; + pt2_byte_buf[16] = pt->ecc.colParity; + pt2_byte_buf[17] = pt->ecc.lineParity & 0xff; + pt2_byte_buf[18] = (pt->ecc.lineParity >> 8) & 0xff; + pt2_byte_buf[19] = (pt->ecc.lineParity >> 16) & 0xff; + pt2_byte_buf[20] = (pt->ecc.lineParity >> 24) & 0xff; + pt2_byte_buf[21] = pt->ecc.lineParityPrime & 0xff; + pt2_byte_buf[22] = (pt->ecc.lineParityPrime >> 8) & 0xff; + pt2_byte_buf[23] = (pt->ecc.lineParityPrime >> 16) & 0xff; + pt2_byte_buf[24] = (pt->ecc.lineParityPrime >> 24) & 0xff; + +// k = mtd->oobinfo.oobfree[j][0]; +// n = mtd->oobinfo.oobfree[j][1]; + + k = mtd->ecclayout->oobfree[j].offset; + n = mtd->ecclayout->oobfree[j].length; + if (n == 0) { + T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR))); + YBUG(); + } + + for (i = 0; i < PT2_BYTES; i++) { + if (n == 0) { + j++; +// k = mtd->oobinfo.oobfree[j][0]; +// n = mtd->oobinfo.oobfree[j][1]; + k = mtd->ecclayout->oobfree[j].offset; + n = mtd->ecclayout->oobfree[j].length; + + if (n == 0) { + T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR))); + YBUG(); + } + } + dev->spareBuffer[k++] = pt2_byte_buf[i]; + 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 pt2_byte_buf[PT2_BYTES]; + + + if (!is_raw) { + pt->t.sequenceNumber = *((unsigned int *) &dev->spareBuffer[0]); + pt->t.objectId = *((unsigned int *) &dev->spareBuffer[4]); + pt->t.chunkId = *((unsigned int *) &dev->spareBuffer[8]); + pt->t.byteCount = *((unsigned int *) &dev->spareBuffer[12]); + pt->ecc.colParity = dev->spareBuffer[16]; + pt->ecc.lineParity = (dev->spareBuffer[17] & 0x000000ff) | + ((dev->spareBuffer[18] << 8) & 0x0000ff00) | + ((dev->spareBuffer[19] << 16) & 0x00ff0000) | + ((dev->spareBuffer[20] << 24) & 0xff000000); + pt->ecc.lineParityPrime = (dev->spareBuffer[21] & 0x000000ff) | + ((dev->spareBuffer[22] << 8) & 0x0000ff00) | + ((dev->spareBuffer[23] << 16) & 0x00ff0000) | + ((dev->spareBuffer[24] << 24) & 0xff000000); + } else { +// k = mtd->oobinfo.oobfree[j][0]; +// n = mtd->oobinfo.oobfree[j][1]; + + k = mtd->ecclayout->oobfree[j].offset; + n = mtd->ecclayout->oobfree[j].length; + + if (n == 0) { + T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR))); + YBUG(); + } + + for (i = 0; i < PT2_BYTES; i++) { + if (n == 0) { + j++; +// k = mtd->oobinfo.oobfree[j][0]; +// n = mtd->oobinfo.oobfree[j][1]; + k = mtd->ecclayout->oobfree[j].offset; + n = mtd->ecclayout->oobfree[j].length; + + if (n == 0) { + T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR))); + YBUG(); + } + } + pt2_byte_buf[i] = dev->spareBuffer[k++]; + n--; + } + pt->t.sequenceNumber = *((unsigned int *) &pt2_byte_buf[0]); + pt->t.objectId = *((unsigned int *) &pt2_byte_buf[4]); + pt->t.chunkId = *((unsigned int *) &pt2_byte_buf[8]); + pt->t.byteCount = *((unsigned int *) &pt2_byte_buf[12]); + pt->ecc.colParity = pt2_byte_buf[16]; + pt->ecc.lineParity = (pt2_byte_buf[17] & 0x000000ff) | + ((pt2_byte_buf[18] << 8) & 0x0000ff00) | + ((pt2_byte_buf[19] << 16) & 0x00ff0000) | + ((pt2_byte_buf[20] << 24) & 0xff000000); + pt->ecc.lineParityPrime = (pt2_byte_buf[21] & 0x000000ff) | + ((pt2_byte_buf[22] << 8) & 0x0000ff00) | + ((pt2_byte_buf[23] << 16) & 0x00ff0000) | + ((pt2_byte_buf[24] << 24) & 0xff000000); + } +} + int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * tags) @@ -38,9 +171,7 @@ size_t dummy; #endif int retval = 0; - - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; - + loff_mtd_t addr = ((loff_mtd_t) chunkInNAND) * dev->nDataBytesPerChunk; yaffs_PackedTags2 pt; T(YAFFS_TRACE_MTD, @@ -55,12 +186,14 @@ BUG(); /* both tags and data should always be present */ if (data) { + nandmtd2_pt2buf(dev, &pt, 0); //modify ops.mode = MTD_OOB_AUTO; ops.ooblen = sizeof(pt); ops.len = dev->nDataBytesPerChunk; ops.ooboffs = 0; ops.datbuf = (__u8 *)data; - ops.oobbuf = (void *)&pt; +// ops.oobbuf = (void *)&pt; //modify + ops.oobbuf = (void *)dev->spareBuffer; //modify retval = mtd->write_oob(mtd, addr, &ops); } else BUG(); /* both tags and data should always be present */ @@ -70,24 +203,27 @@ } if (data && tags) { + nandmtd2_pt2buf(dev, &pt, 0); if (dev->useNANDECC) retval = mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, (__u8 *) & pt, NULL); + &dummy, data, dev->spareBuffer, NULL); else retval = mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, - &dummy, data, (__u8 *) & pt, NULL); + &dummy, data, dev->spareBuffer, NULL); } else { - if (data) + if (data) { retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, data); - if (tags) + } + if (tags) { + nandmtd2_pt2buf(dev, &pt, 1); retval = mtd->write_oob(mtd, addr, mtd->oobsize, &dummy, - (__u8 *) & pt); - + dev->spareBuffer); + } } #endif @@ -104,11 +240,9 @@ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) struct mtd_oob_ops ops; #endif - size_t dummy; + size_mtd_t dummy; int retval = 0; - - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; - + loff_mtd_t addr = ((loff_mtd_t) chunkInNAND) * dev->nDataBytesPerChunk; yaffs_PackedTags2 pt; T(YAFFS_TRACE_MTD, @@ -128,6 +262,7 @@ ops.datbuf = data; ops.oobbuf = dev->spareBuffer; retval = mtd->read_oob(mtd, addr, &ops); + nandmtd2_buf2pt(dev, &pt, 0); //modify by yliu } #else if (data && tags) { @@ -142,23 +277,25 @@ &dummy, data, dev->spareBuffer, NULL); } + nandmtd2_buf2pt(dev, &pt, 0); } else { - if (data) + if (data) { retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, data); - if (tags) + } + if (tags) { retval = mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, dev->spareBuffer); + nandmtd2_buf2pt(dev, &pt, 1); + } } #endif - memcpy(&pt, dev->spareBuffer, sizeof(pt)); - if (tags) yaffs_UnpackTags2(tags, &pt); - + if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; @@ -177,7 +314,7 @@ retval = mtd->block_markbad(mtd, - blockNo * dev->nChunksPerBlock * + (u64)blockNo * dev->nChunksPerBlock * dev->nDataBytesPerChunk); if (retval == 0) @@ -195,11 +332,11 @@ T(YAFFS_TRACE_MTD, (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo)); + retval = mtd->block_isbad(mtd, - blockNo * dev->nChunksPerBlock * + (u64)blockNo * dev->nChunksPerBlock * dev->nDataBytesPerChunk); - if (retval) { T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR))); diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif2.h linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif2.h --- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif2.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif2.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_nand.c linux-2.6.24.7.new/fs/yaffs2/yaffs_nand.c --- linux-2.6.24.7/fs/yaffs2/yaffs_nand.c 2009-04-21 14:57:10.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_nand.c 2009-04-21 15:01:02.000000000 +0200 @@ -10,9 +10,9 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - + const char *yaffs_nand_c_version = - "$Id: yaffs_nand.c,v 1.7 2007-02-14 01:09:06 wookey Exp $"; + "$Id: yaffs_nand.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $"; #include "yaffs_nand.h" #include "yaffs_tagscompat.h" @@ -25,9 +25,9 @@ { int result; yaffs_ExtendedTags localTags; - + int realignedChunkInNAND = chunkInNAND - dev->chunkOffset; - + /* If there are no tags provided, use local tags to get prioritised gc working */ if(!tags) tags = &localTags; @@ -39,14 +39,14 @@ result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer, - tags); - if(tags && - tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){ + tags); + if(tags && + tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock); yaffs_HandleChunkError(dev,bi); } - + return result; } @@ -57,7 +57,7 @@ { chunkInNAND -= dev->chunkOffset; - + if (tags) { tags->sequenceNumber = dev->sequenceNumber; tags->chunkUsed = 1; @@ -131,4 +131,4 @@ } - + diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_nand.h linux-2.6.24.7.new/fs/yaffs2/yaffs_nand.h --- linux-2.6.24.7/fs/yaffs2/yaffs_nand.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_nand.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_nandemul2k.h linux-2.6.24.7.new/fs/yaffs2/yaffs_nandemul2k.h --- linux-2.6.24.7/fs/yaffs2/yaffs_nandemul2k.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_nandemul2k.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_packedtags1.h linux-2.6.24.7.new/fs/yaffs2/yaffs_packedtags1.h --- linux-2.6.24.7/fs/yaffs2/yaffs_packedtags1.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_packedtags1.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_packedtags2.c linux-2.6.24.7.new/fs/yaffs2/yaffs_packedtags2.c --- linux-2.6.24.7/fs/yaffs2/yaffs_packedtags2.c 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_packedtags2.c 2009-04-21 15:01:02.000000000 +0200 @@ -40,7 +40,8 @@ static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt) { T(YAFFS_TRACE_MTD, - (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), +// T(YAFFS_TRACE_ALWAYS, + (TSTR("packed tags obj %x chunk %x byte %x seq %x" TENDSTR), pt->t.objectId, pt->t.chunkId, pt->t.byteCount, pt->t.sequenceNumber)); } @@ -48,9 +49,10 @@ static void yaffs_DumpTags2(const yaffs_ExtendedTags * t) { T(YAFFS_TRACE_MTD, +// T(YAFFS_TRACE_ALWAYS, (TSTR - ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte " - "%d del %d ser %d seq %d" + ("ext.tags eccres %x blkbad %x chused %x obj %x chunk%x byte " + "%x del %x ser %x seq %x" TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId, t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, t->sequenceNumber)); @@ -89,10 +91,10 @@ } } - yaffs_DumpPackedTags2(pt); - yaffs_DumpTags2(t); +// yaffs_DumpPackedTags2(pt); +// yaffs_DumpTags2(t); -#ifndef YAFFS_IGNORE_TAGS_ECC +#if !defined(YAFFS_IGNORE_TAGS_ECC) && !defined(CONFIG_MTD_HW_BCH_ECC) { yaffs_ECCCalculateOther((unsigned char *)&pt->t, sizeof(yaffs_PackedTags2TagsPart), @@ -103,14 +105,11 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt) { - - memset(t, 0, sizeof(yaffs_ExtendedTags)); - yaffs_InitialiseTags(t); if (pt->t.sequenceNumber != 0xFFFFFFFF) { /* Page is in use */ -#ifdef YAFFS_IGNORE_TAGS_ECC +#if defined(YAFFS_IGNORE_TAGS_ECC) || defined(CONFIG_MTD_HW_BCH_ECC) { t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; } @@ -118,20 +117,23 @@ { yaffs_ECCOther ecc; int result; +#if defined(CONFIG_YAFFS_ECC_HAMMING) yaffs_ECCCalculateOther((unsigned char *)&pt->t, sizeof (yaffs_PackedTags2TagsPart), &ecc); +#endif result = yaffs_ECCCorrectOther((unsigned char *)&pt->t, sizeof (yaffs_PackedTags2TagsPart), &pt->ecc, &ecc); + switch(result){ - case 0: - t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; + case 0: + t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; break; - case 1: + case 1: t->eccResult = YAFFS_ECC_RESULT_FIXED; break; case -1: @@ -175,8 +177,8 @@ } } } - +// printk("\n TAG %d",t->chunkUsed); yaffs_DumpPackedTags2(pt); yaffs_DumpTags2(t); - +// printk("\n TAG %d",t->chunkUsed); } diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_packedtags2.h linux-2.6.24.7.new/fs/yaffs2/yaffs_packedtags2.h --- linux-2.6.24.7/fs/yaffs2/yaffs_packedtags2.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_packedtags2.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_qsort.c linux-2.6.24.7.new/fs/yaffs2/yaffs_qsort.c --- linux-2.6.24.7/fs/yaffs2/yaffs_qsort.c 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_qsort.c 2009-04-21 15:01:02.000000000 +0200 @@ -50,7 +50,7 @@ static __inline void swapfunc(char *a, char *b, int n, int swaptype) { - if (swaptype <= 1) + if (swaptype <= 1) swapcode(long, a, b, n) else swapcode(char, a, b, n) @@ -74,13 +74,8 @@ :(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 *)) +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; @@ -137,7 +132,7 @@ } 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; + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; pl -= es) swap(pl, pl - es); return; @@ -149,12 +144,12 @@ r = min((long)(pd - pc), (long)(pn - pd - es)); vecswap(pb, pn - r, r); if ((r = pb - pa) > es) - yaffs_qsort(a, r / es, es, cmp); - if ((r = pd - pc) > es) { + qsort(a, r / es, es, cmp); + if ((r = pd - pc) > 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);*/ +/* qsort(pn - r, r / es, es, cmp);*/ } diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_qsort.h linux-2.6.24.7.new/fs/yaffs2/yaffs_qsort.h --- linux-2.6.24.7/fs/yaffs2/yaffs_qsort.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_qsort.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 @@ -17,7 +17,7 @@ #ifndef __YAFFS_QSORT_H__ #define __YAFFS_QSORT_H__ -extern void yaffs_qsort (void *const base, size_t total_elems, size_t size, +extern void qsort (void *const base, size_t total_elems, size_t size, int (*cmp)(const void *, const void *)); #endif diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_tagscompat.c linux-2.6.24.7.new/fs/yaffs2/yaffs_tagscompat.c --- linux-2.6.24.7/fs/yaffs2/yaffs_tagscompat.c 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_tagscompat.c 2009-04-21 15:01:02.000000000 +0200 @@ -45,7 +45,7 @@ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 }; -int yaffs_CountBits(__u8 x) +static int yaffs_CountBits(__u8 x) { int retVal; retVal = yaffs_countBitsTable[x]; diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_tagscompat.h linux-2.6.24.7.new/fs/yaffs2/yaffs_tagscompat.h --- linux-2.6.24.7/fs/yaffs2/yaffs_tagscompat.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_tagscompat.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 @@ -33,8 +33,4 @@ int blockNo, yaffs_BlockState * state, int *sequenceNumber); -void yaffs_CalcTagsECC(yaffs_Tags * tags); -int yaffs_CheckECCOnTags(yaffs_Tags * tags); -int yaffs_CountBits(__u8 byte); - #endif diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_tagsvalidity.h linux-2.6.24.7.new/fs/yaffs2/yaffs_tagsvalidity.h --- linux-2.6.24.7/fs/yaffs2/yaffs_tagsvalidity.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffs_tagsvalidity.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 diff -urN linux-2.6.24.7/fs/yaffs2/yaffsinterface.h linux-2.6.24.7.new/fs/yaffs2/yaffsinterface.h --- linux-2.6.24.7/fs/yaffs2/yaffsinterface.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yaffsinterface.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 diff -urN linux-2.6.24.7/fs/yaffs2/yportenv.h linux-2.6.24.7.new/fs/yaffs2/yportenv.h --- linux-2.6.24.7/fs/yaffs2/yportenv.h 2009-04-09 17:39:09.000000000 +0200 +++ linux-2.6.24.7.new/fs/yaffs2/yportenv.h 2009-04-21 15:01:02.000000000 +0200 @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * 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 @@ -32,7 +32,6 @@ #endif #include #include -#include #include #include #include @@ -42,7 +41,6 @@ #define _Y(x) x #define yaffs_strcpy(a,b) strcpy(a,b) #define yaffs_strncpy(a,b,c) strncpy(a,b,c) -#define yaffs_strncmp(a,b,c) strncmp(a,b,c) #define yaffs_strlen(s) strlen(s) #define yaffs_sprintf sprintf #define yaffs_toupper(a) toupper(a) @@ -62,7 +60,7 @@ // KR - added for use in scan so processes aren't blocked indefinitely. #define YYIELD() schedule() -#define YAFFS_ROOT_MODE 0666 +#define YAFFS_ROOT_MODE 0666 #define YAFFS_LOSTNFOUND_MODE 0666 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) @@ -80,14 +78,6 @@ #define TSTR(x) KERN_WARNING x #define TOUT(p) printk p -#define yaffs_trace(mask, fmt, args...) \ - do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \ - printk(KERN_WARNING "yaffs: " fmt, ## args); \ - } while (0) - -#define compile_time_assertion(assertion) \ - ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) - #elif defined CONFIG_YAFFS_DIRECT /* Direct interface */ @@ -142,15 +132,9 @@ #endif -/* see yaffs_fs.c */ -extern unsigned int yaffs_traceMask; -extern unsigned int yaffs_wr_attempts; - -/* - * Tracing flags. - * The flags masked in YAFFS_TRACE_ALWAYS are always traced. - */ +extern unsigned yaffs_traceMask; +#define YAFFS_TRACE_ERROR 0x00000001 #define YAFFS_TRACE_OS 0x00000002 #define YAFFS_TRACE_ALLOCATE 0x00000004 #define YAFFS_TRACE_SCAN 0x00000008 @@ -166,19 +150,10 @@ #define YAFFS_TRACE_SCAN_DEBUG 0x00002000 #define YAFFS_TRACE_MTD 0x00004000 #define YAFFS_TRACE_CHECKPOINT 0x00008000 - -#define YAFFS_TRACE_VERIFY 0x00010000 -#define YAFFS_TRACE_VERIFY_NAND 0x00020000 -#define YAFFS_TRACE_VERIFY_FULL 0x00040000 -#define YAFFS_TRACE_VERIFY_ALL 0x000F0000 - - -#define YAFFS_TRACE_ERROR 0x40000000 +#define YAFFS_TRACE_ALWAYS 0x40000000 #define YAFFS_TRACE_BUG 0x80000000 -#define YAFFS_TRACE_ALWAYS 0xF0000000 - -#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0) +#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ERROR)) TOUT(p);} while(0) #ifndef CONFIG_YAFFS_WINCE #define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))