mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-25 13:35:21 +02:00
8843 lines
241 KiB
Diff
8843 lines
241 KiB
Diff
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 <Martin.Fouts@palmsource.com>
|
|
+ * Created by Martin Fouts <Martin.Fouts@palmsource.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
|
@@ -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 <charles@aleph1.co.uk>
|
|
+#
|
|
+# This program is free software; you can redistribute it and/or modify
|
|
+# it under the terms of the GNU General Public License version 2 as
|
|
+# published by the Free Software Foundation.
|
|
+
|
|
+## Change or override KERNELDIR to your kernel
|
|
+#KERNELDIR = /usr/src/kernel-headers-2.4.18
|
|
+#CFLAGS = -I$(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 <charles@aleph1.co.uk>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ *
|
|
+ *
|
|
+ * 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 <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <fcntl.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <dirent.h>
|
|
+#include <string.h>
|
|
+#include <unistd.h>
|
|
+#include <mtd/mtd-user.h>
|
|
+#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 <charles@aleph1.co.uk>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ *
|
|
+ *
|
|
+ * Nick Bane modifications flagged NCB
|
|
+ *
|
|
+ * Endian handling patches by James Ng.
|
|
+ *
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <fcntl.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <dirent.h>
|
|
+#include <string.h>
|
|
+#include <unistd.h>
|
|
+#include "yaffs_ecc.h"
|
|
+#include "yaffs_guts.h"
|
|
+
|
|
+
|
|
+#define MAX_OBJECTS 10000
|
|
+
|
|
+const char * mkyaffsimage_c_version = "$Id: 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 <string.h>
|
|
+
|
|
+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<<symsize))
|
|
+ goto done;
|
|
+ if(prim <= 0 || prim >= (1<<symsize))
|
|
+ goto done;
|
|
+ if(nroots < 0 || nroots >= (1<<symsize))
|
|
+ goto done;
|
|
+ if(pad < 0 || pad >= ((1<<symsize) -1 - nroots))
|
|
+ goto done;
|
|
+
|
|
+ rs = (struct rs *)malloc(sizeof(struct rs));
|
|
+// rs = (struct rs *)rs0;
|
|
+ if(rs == ((void *)0))
|
|
+ goto done;
|
|
+ rs->mm = symsize;
|
|
+ rs->nn = (1<<symsize)-1;
|
|
+ rs->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;i<rs->nn;i++){
|
|
+ rs->index_of[sr] = i;
|
|
+ rs->alpha_to[i] = sr;
|
|
+ sr <<= 1;
|
|
+ if(sr & (1<<symsize))
|
|
+ sr ^= gfpoly;
|
|
+ sr &= rs->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<<mm)-1) */
|
|
+ data_t *alpha_to; /* log lookup table */
|
|
+ data_t *index_of; /* Antilog lookup table */
|
|
+ data_t *genpoly; /* Generator polynomial */
|
|
+ int nroots; /* Number of generator roots = number of parity symbols */
|
|
+ int fcr; /* First consecutive root, index form */
|
|
+ int prim; /* Primitive element, index form */
|
|
+ int iprim; /* prim-th root of 1, index form */
|
|
+ int pad; /* Padding bytes in shortened block */
|
|
+};
|
|
+
|
|
+void encode_rs(void *p,data_t *data, unsigned short *bb);
|
|
+struct rs *init_rs_int(int symsize,int gfpoly,int fcr,int prim,int nroots,int pad);
|
|
+void free_rs_int(void *p);
|
|
+
|
|
+#endif /* __SSFDC_RS_ECC_H__ */
|
|
diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_checkptrw.c linux-2.6.24.7.new/fs/yaffs2/yaffs_checkptrw.c
|
|
--- linux-2.6.24.7/fs/yaffs2/yaffs_checkptrw.c 2009-04-21 14:57:10.000000000 +0200
|
|
+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_checkptrw.c 2009-04-21 15:01:02.000000000 +0200
|
|
@@ -12,7 +12,7 @@
|
|
*/
|
|
|
|
const char *yaffs_checkptrw_c_version =
|
|
- "$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $";
|
|
+ "$Id: yaffs_checkptrw.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $";
|
|
|
|
|
|
#include "yaffs_checkptrw.h"
|
|
@@ -22,27 +22,28 @@
|
|
{
|
|
|
|
int blocksAvailable = dev->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 <linux/rslib.h>
|
|
+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<<Symbolsize-1) - nroot - 26 = 1
|
|
+ */
|
|
+ rs_init_user = (void *) init_rs_int (5, 0x25, 1, 1, 4, 1);
|
|
+ encode_rs(rs_init_user, data5, par);
|
|
+ free_rs_int(rs_init_user);
|
|
+#endif
|
|
+}
|
|
+
|
|
+#ifdef __KERNEL__
|
|
+/*
|
|
+ * It does reed solomon ECC correction on 16 bytes of oob data
|
|
+ */
|
|
+int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
|
|
+ yaffs_ECCOther * read_ecc,
|
|
+ const yaffs_ECCOther * test_ecc)
|
|
+{
|
|
+ unsigned short *par = (unsigned short *)&read_ecc->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 <linux/version.h>
|
|
@@ -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 <asm/uaccess.h>
|
|
|
|
#include "yportenv.h"
|
|
#include "yaffs_guts.h"
|
|
|
|
+unsigned yaffs_traceMask = YAFFS_TRACE_ALWAYS |
|
|
+ YAFFS_TRACE_BAD_BLOCKS/* |
|
|
+ YAFFS_TRACE_CHECKPOINT*/
|
|
+ /* | 0xFFFFFFFF */;
|
|
+
|
|
#include <linux/mtd/mtd.h>
|
|
#include "yaffs_mtdif.h"
|
|
-#include "yaffs_mtdif1.h"
|
|
#include "yaffs_mtdif2.h"
|
|
|
|
-unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
|
|
-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 <linux/rslib.h>
|
|
+#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 <MAX_MASK_NAME_LENGTH; x++, i++, pos++)
|
|
- substring[i] = *x;
|
|
- substring[i] = '\0';
|
|
|
|
for (i = 0; mask_flags[i].mask_name != NULL; i++) {
|
|
- if(strcmp(substring,mask_flags[i].mask_name) == 0){
|
|
+ len = strlen(mask_flags[i].mask_name);
|
|
+ if (strncmp(buf + pos, mask_flags[i].mask_name, len) == 0) {
|
|
mask_name = mask_flags[i].mask_name;
|
|
mask_bitfield = mask_flags[i].mask_bitfield;
|
|
done = 0;
|
|
@@ -2171,6 +2082,7 @@
|
|
}
|
|
|
|
if (mask_name != NULL) {
|
|
+ pos += len;
|
|
done = 0;
|
|
switch(add) {
|
|
case '-':
|
|
@@ -2190,9 +2102,7 @@
|
|
}
|
|
|
|
yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
|
|
-
|
|
- printk("new trace = 0x%08X\n",yaffs_traceMask);
|
|
-
|
|
+
|
|
if (rg & YAFFS_TRACE_ALWAYS) {
|
|
for (i = 0; mask_flags[i].mask_name != NULL; i++) {
|
|
char flag;
|
|
@@ -2266,6 +2176,16 @@
|
|
}
|
|
}
|
|
|
|
+#if defined(CONFIG_YAFFS_ECC_RS)
|
|
+ /* 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
|
|
+ */
|
|
+ rs_decoder = init_rs (5, 0x25, 1, 1, 4);
|
|
+#endif
|
|
return error;
|
|
}
|
|
|
|
@@ -2289,6 +2209,9 @@
|
|
fsinst++;
|
|
}
|
|
|
|
+#if defined(CONFIG_YAFFS_ECC_RS)
|
|
+ free_rs(rs_decoder);
|
|
+#endif
|
|
}
|
|
|
|
module_init(init_yaffs_fs)
|
|
diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_guts.c linux-2.6.24.7.new/fs/yaffs2/yaffs_guts.c
|
|
--- linux-2.6.24.7/fs/yaffs2/yaffs_guts.c 2009-04-21 14:57:10.000000000 +0200
|
|
+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_guts.c 2009-04-21 15:01:02.000000000 +0200
|
|
@@ -12,7 +12,7 @@
|
|
*/
|
|
|
|
const char *yaffs_guts_c_version =
|
|
- "$Id: yaffs_guts.c,v 1.49 2007-05-15 20:07:40 charles Exp $";
|
|
+ "$Id: yaffs_guts.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $";
|
|
|
|
#include "yportenv.h"
|
|
|
|
@@ -21,7 +21,7 @@
|
|
#include "yaffs_tagsvalidity.h"
|
|
|
|
#include "yaffs_tagscompat.h"
|
|
-#ifndef CONFIG_YAFFS_USE_OWN_SORT
|
|
+#ifndef CONFIG_YAFFS_OWN_SORT
|
|
#include "yaffs_qsort.h"
|
|
#endif
|
|
#include "yaffs_nand.h"
|
|
@@ -97,8 +97,6 @@
|
|
|
|
static void yaffs_VerifyFreeChunks(yaffs_Device * dev);
|
|
|
|
-static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
|
|
-
|
|
#ifdef YAFFS_PARANOID
|
|
static int yaffs_CheckFileSanity(yaffs_Object * in);
|
|
#else
|
|
@@ -110,13 +108,6 @@
|
|
|
|
static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
|
|
|
|
-static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode,
|
|
- yaffs_ExtendedTags * tags);
|
|
-
|
|
-static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos);
|
|
-static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev,
|
|
- yaffs_FileStructure * fStruct,
|
|
- __u32 chunkId);
|
|
|
|
|
|
/* Function to calculate chunk and offset */
|
|
@@ -140,73 +131,56 @@
|
|
YBUG();
|
|
}
|
|
|
|
-/* Function to return the number of shifts for a power of 2 greater than or equal
|
|
+/* Function to return the number of shifts for a power of 2 greater than or equal
|
|
* to the given number
|
|
* Note we don't try to cater for all possible numbers and this does not have to
|
|
* be hellishly efficient.
|
|
*/
|
|
-
|
|
+
|
|
static __u32 ShiftsGE(__u32 x)
|
|
{
|
|
int extraBits;
|
|
int nShifts;
|
|
-
|
|
+
|
|
nShifts = extraBits = 0;
|
|
-
|
|
+
|
|
while(x>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<<YAFFS_TNODES_INTERNAL_BITS) + i);
|
|
- }
|
|
- }
|
|
- } else if (level == 0) {
|
|
- int i;
|
|
- yaffs_ExtendedTags tags;
|
|
- __u32 objectId = obj->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<<dev->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 <ian@brightstareng.com>)
|
|
- 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 <ian@brightstareng.com>
|
|
-To: David Goodenough <david.goodenough@linkchoose.co.uk>
|
|
-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 <alyf@alyf.net>,
|
|
- Charles Manning <manningc2@actrix.gen.nz>
|
|
-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 <linux/kernel.h>
|
|
#include <linux/mm.h>
|
|
-#include <linux/sched.h>
|
|
#include <linux/string.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/vmalloc.h>
|
|
@@ -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__))
|