YAFFS2 import

Direct import of yaffs as a tarball as of 20071113 from their public
CVS-web at http://www.aleph1.co.uk/cgi-bin/viewcvs.cgi/yaffs2/

The code can also be imported on the command line with:
export CVSROOT=:pserver:anonymous@cvs.aleph1.co.uk:/home/aleph1/cvs cvs logon
(Hit return when asked for a password)
cvs checkout yaffs2

Signed-off-by: William Juul <william.juul@tandberg.com>
Signed-off-by: Stig Olsen <stig.olsen@tandberg.com>
This commit is contained in:
William Juul 2007-11-15 11:13:05 +01:00 committed by Scott Wood
parent 3043c045d5
commit 0e8cc8bd92
63 changed files with 24326 additions and 0 deletions

176
fs/yaffs2/Kconfig Normal file
View file

@ -0,0 +1,176 @@
#
# YAFFS file system configurations
#
config YAFFS_FS
tristate "YAFFS2 file system support"
default n
depends on MTD
select YAFFS_YAFFS1
select YAFFS_YAFFS2
help
YAFFS2, or Yet Another Flash Filing System, is a filing system
optimised for NAND Flash chips.
To compile the YAFFS2 file system support as a module, choose M
here: the module will be called yaffs2.
If unsure, say N.
Further information on YAFFS2 is available at
<http://www.aleph1.co.uk/yaffs/>.
config YAFFS_YAFFS1
bool "512 byte / page devices"
depends on YAFFS_FS
default y
help
Enable YAFFS1 support -- yaffs for 512 byte / page devices
Not needed for 2K-page devices.
If unsure, say Y.
config YAFFS_9BYTE_TAGS
bool "Use older-style on-NAND data format with pageStatus byte"
depends on YAFFS_YAFFS1
default n
help
Older-style on-NAND data format has a "pageStatus" byte to record
chunk/page state. This byte is zero when the page is discarded.
Choose this option if you have existing on-NAND data using this
format that you need to continue to support. New data written
also uses the older-style format. Note: Use of this option
generally requires that MTD's oob layout be adjusted to use the
older-style format. See notes on tags formats and MTD versions
in yaffs_mtdif1.c.
If unsure, say N.
config YAFFS_DOES_ECC
bool "Lets Yaffs do its own ECC"
depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
default n
help
This enables Yaffs to use its own ECC functions instead of using
the ones from the generic MTD-NAND driver.
If unsure, say N.
config YAFFS_ECC_WRONG_ORDER
bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
default n
help
This makes yaffs_ecc.c use the same ecc byte order as Steven
Hill's nand_ecc.c. If not set, then you get the same ecc byte
order as SmartMedia.
If unsure, say N.
config YAFFS_YAFFS2
bool "2048 byte (or larger) / page devices"
depends on YAFFS_FS
default y
help
Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
If unsure, say Y.
config YAFFS_AUTO_YAFFS2
bool "Autoselect yaffs2 format"
depends on YAFFS_YAFFS2
default y
help
Without this, you need to explicitely use yaffs2 as the file
system type. With this, you can say "yaffs" and yaffs or yaffs2
will be used depending on the device page size (yaffs on
512-byte page devices, yaffs2 on 2K page devices).
If unsure, say Y.
config YAFFS_DISABLE_LAZY_LOAD
bool "Disable lazy loading"
depends on YAFFS_YAFFS2
default n
help
"Lazy loading" defers loading file details until they are
required. This saves mount time, but makes the first look-up
a bit longer.
Lazy loading will only happen if enabled by this option being 'n'
and if the appropriate tags are available, else yaffs2 will
automatically fall back to immediate loading and do the right
thing.
Lazy laoding will be required by checkpointing.
Setting this to 'y' will disable lazy loading.
If unsure, say N.
config YAFFS_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
searching.
Setting this to 'y' will force tnode width to 16 bits and save
memory but make large arrays slower.
If unsure, say N.
config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
bool "Force chunk erase check"
depends on YAFFS_FS
default n
help
Normally YAFFS only checks chunks before writing until an erased
chunk is found. This helps to detect any partially written
chunks that might have happened due to power loss.
Enabling this forces on the test that chunks are erased in flash
before writing to them. This takes more time but is potentially
a bit more secure.
Suggest setting Y during development and ironing out driver
issues etc. Suggest setting to N if you want faster writing.
If unsure, say Y.
config YAFFS_SHORT_NAMES_IN_RAM
bool "Cache short names in RAM"
depends on YAFFS_FS
default y
help
If this config is set, then short names are stored with the
yaffs_Object. This costs an extra 16 bytes of RAM per object,
but makes look-ups faster.
If unsure, say Y.

40
fs/yaffs2/Makefile Normal file
View file

@ -0,0 +1,40 @@
# Main Makefile for YAFFS
#
#
# YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
#
# Copyright (C) 2002-2007 Aleph One Ltd.
# for Toby Churchill Ltd and Brightstar Engineering
#
# Created by Charles Manning <charles@aleph1.co.uk>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
ifneq ($(KERNELRELEASE),)
EXTRA_CFLAGS += -DYAFFS_OUT_OF_TREE
obj-m := yaffs2.o
yaffs2-objs := yaffs_mtdif.o yaffs_mtdif2.o
yaffs2-objs += yaffs_mtdif1.o yaffs_packedtags1.o
yaffs2-objs += yaffs_ecc.o yaffs_fs.o yaffs_guts.o
yaffs2-objs += yaffs_packedtags2.o yaffs_qsort.o
yaffs2-objs += yaffs_tagscompat.o yaffs_tagsvalidity.o
yaffs2-objs += yaffs_checkptrw.o yaffs_nand.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
mi modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
endif

10
fs/yaffs2/Makefile.kernel Normal file
View file

@ -0,0 +1,10 @@
#
# Makefile for the linux YAFFS filesystem routines.
#
obj-$(CONFIG_YAFFS_FS) += yaffs.o
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o

201
fs/yaffs2/README-linux Normal file
View file

@ -0,0 +1,201 @@
Welcome to YAFFS, the first file system developed specifically for NAND flash.
It is now YAFFS2 - original YAFFS (AYFFS1) only supports 512-byte page
NAND and is now deprectated. YAFFS2 supports 512b page in 'YAFFS1
compatibility' mode (CONFIG_YAFFS_YAFFS1) and 2K or larger page NAND
in YAFFS2 mode (CONFIG_YAFFS_YAFFS2).
A note on licencing
-------------------
YAFFS is available under the GPL and via alternative licensing
arrangements with Aleph One. If you're using YAFFS as a Linux kernel
file system then it will be under the GPL. For use in other situations
you should discuss licensing issues with Aleph One.
Terminology
-----------
Page - NAND addressable unit (normally 512b or 2Kbyte size) - can
be read, written, marked bad. Has associated OOB.
Block - Eraseable unit. 64 Pages. (128K on 2K NAND, 32K on 512b NAND)
OOB - 'spare area' of each page for ECC, bad block marked and YAFFS
tags. 16 bytes per 512b - 64 bytes for 2K page size.
Chunk - Basic YAFFS addressable unit. Same size as Page.
Object - YAFFS Object: File, Directory, Link, Device etc.
YAFFS design
------------
YAFFS is a log-structured filesystem. It is designed particularly for
NAND (as opposed to NOR) flash, to be flash-friendly, robust due to
journalling, and to have low RAM and boot time overheads. File data is
stored in 'chunks'. Chunks are the same size as NAND pages. Each page
is marked with file id and chunk number. These marking 'tags' are
stored in the OOB (or 'spare') region of the flash. The chunk number
is determined by dividing the file position by the chunk size. Each
chunk has a number of valid bytes, which equals the page size for all
except the last chunk in a file.
File 'headers' are stored as the first page in a file, marked as a
different type to data pages. The same mechanism is used to store
directories, device files, links etc. The first page describes which
type of object it is.
YAFFS2 never re-writes a page, because the spec of NAND chips does not
allow it. (YAFFS1 used to mark a block 'deleted' in the OOB). Deletion
is managed by moving deleted objects to the special, hidden 'unlinked'
directory. These records are preserved until all the pages containing
the object have been erased (We know when this happen by keeping a
count of chunks remaining on the system for each object - when it
reaches zero the object really is gone).
When data in a file is overwritten, the relevant chunks are replaced
by writing new pages to flash containing the new data but the same
tags.
Pages are also marked with a short (2 bit) serial number that
increments each time the page at this position is incremented. The
reason for this is that if power loss/crash/other act of demonic
forces happens before the replaced page is marked as discarded, it is
possible to have two pages with the same tags. The serial number is
used to arbitrate.
A block containing only discarded pages (termed a dirty block) is an
obvious candidate for garbage collection. Otherwise valid pages can be
copied off a block thus rendering the whole block discarded and ready
for garbage collection.
In theory you don't need to hold the file structure in RAM... you
could just scan the whole flash looking for pages when you need them.
In practice though you'd want better file access times than that! The
mechanism proposed here is to have a list of __u16 page addresses
associated with each file. Since there are 2^18 pages in a 128MB NAND,
a __u16 is insufficient to uniquely identify a page but is does
identify a group of 4 pages - a small enough region to search
exhaustively. This mechanism is clearly expandable to larger NAND
devices - within reason. The RAM overhead with this approach is approx
2 bytes per page - 512kB of RAM for a whole 128MB NAND.
Boot-time scanning to build the file structure lists only requires
one pass reading NAND. If proper shutdowns happen the current RAM
summary of the filesystem status is saved to flash, called
'checkpointing'. This saves re-scanning the flash on startup, and gives
huge boot/mount time savings.
YAFFS regenerates its state by 'replaying the tape' - i.e. by
scanning the chunks in their allocation order (i.e. block sequence ID
order), which is usually different form the media block order. Each
block is still only read once - starting from the end of the media and
working back.
YAFFS tags in YAFFS1 mode:
18-bit Object ID (2^18 files, i.e. > 260,000 files). File id 0- is not
valid and indicates a deleted page. File od 0x3ffff is also not valid.
Synonymous with inode.
2-bit serial number
20-bit Chunk ID within file. Limit of 2^20 chunks/pages per file (i.e.
> 500MB max file size). Chunk ID 0 is the file header for the file.
10-bit counter of the number of bytes used in the page.
12 bit ECC on tags
YAFFS tags in YAFFS2 mode:
4 bytes 32-bit chunk ID
4 bytes 32-bit object ID
2 bytes Number of data bytes in this chunk
4 bytes Sequence number for this block
3 bytes ECC on tags
12 bytes ECC on data (3 bytes per 256 bytes of data)
Page allocation and garbage collection
Pages are allocated sequentially from the currently selected block.
When all the pages in the block are filled, another clean block is
selected for allocation. At least two or three clean blocks are
reserved for garbage collection purposes. If there are insufficient
clean blocks available, then a dirty block ( ie one containing only
discarded pages) is erased to free it up as a clean block. If no dirty
blocks are available, then the dirtiest block is selected for garbage
collection.
Garbage collection is performed by copying the valid data pages into
new data pages thus rendering all the pages in this block dirty and
freeing it up for erasure. I also like the idea of selecting a block
at random some small percentage of the time - thus reducing the chance
of wear differences.
YAFFS is single-threaded. Garbage-collection is done as a parasitic
task of writing data. So each time some data is written, a bit of
pending garbage collection is done. More pages are garbage-collected
when free space is tight.
Flash writing
YAFFS only ever writes each page once, complying with the requirements
of the most restricitve NAND devices.
Wear levelling
This comes as a side-effect of the block-allocation strategy. Data is
always written on the next free block, so they are all used equally.
Blocks containing data that is written but never erased will not get
back into the free list, so wear is levelled over only blocks which
are free or become free, not blocks which never change.
Some helpful info
-----------------
Formatting a YAFFS device is simply done by erasing it.
Making an initial filesystem can be tricky because YAFFS uses the OOB
and thus the bytes that get written depend on the YAFFS data (tags),
and the ECC bytes and bad block markers which are dictated by the
hardware and/or the MTD subsystem. The data layout also depends on the
device page size (512b or 2K). Because YAFFS is only responsible for
some of the OOB data, generating a filesystem offline requires
detailed knowledge of what the other parts (MTD and NAND
driver/hardware) are going to do.
To make a YAFFS filesystem you have 3 options:
1) Boot the system with an empty NAND device mounted as YAFFS and copy
stuff on.
2) Make a filesystem image offline, then boot the system and use
MTDutils to write an image to flash.
3) Make a filesystem image offline and use some tool like a bootloader to
write it to flash.
Option 1 avoids a lot of issues because all the parts
(YAFFS/MTD/hardware) all take care of their own bits and (if you have
put things together properly) it will 'just work'. YAFFS just needs to
know how many bytes of the OOB it can use. However sometimes it is not
practical.
Option 2 lets MTD/hardware take care of the ECC so the filesystem
image just had to know which bytes to use for YAFFS Tags.
Option 3 is hardest as the image creator needs to know exactly what
ECC bytes, endianness and algorithm to use as well as which bytes are
available to YAFFS.
mkyaffs2image creates an image suitable for option 3 for the
particular case of yaffs2 on 2K page NAND with default MTD layout.
mkyaffsimage creates an equivalent image for 512b page NAND (i.e.
yaffs1 format).
Bootloaders
-----------
A bootloader using YAFFS needs to know how MTD is laying out the OOB
so that it can skip bad blocks.
YAFFS Tracing
-------------

View file

@ -0,0 +1,20 @@
To build YAFFS in the Linux kernel tree you need to run the patch-ker.sh
script from the yaffs source directory, giving your choice as to whether
you wish to copy (c) or link (l) the code and the path to your kernel
sources, e.g:
./patch-ker.sh c /usr/src/linux
This will copy the yaffs files into fs/yaffs2 and modify the Kconfig
and Makefiles in the fs directory.
./patch-ker.sh l /usr/src/linux
This does the same as the above but makes symbolic links instead.
After you've run the script, go back to your normal kernel making procedure
and configure the yaffs settings you want.
Prolems? Contact the yaffs mailing list:
http://www.aleph1.co.uk/mailman/listinfo/yaffs

264
fs/yaffs2/devextras.h Normal file
View file

@ -0,0 +1,264 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* 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
* applications.
*
*/
#ifndef __EXTRAS_H__
#define __EXTRAS_H__
#if defined WIN32
#define __inline__ __inline
#define new newHack
#endif
#if !(defined __KERNEL__) || (defined WIN32)
/* User space defines */
typedef unsigned char __u8;
typedef unsigned short __u16;
typedef unsigned __u32;
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
#define prefetch(x) 1
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *new,
struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head *prev,
struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static __inline__ void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static __inline__ void list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
if (first != list) {
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
pos = pos->next, prefetch(pos->next))
/**
* list_for_each_safe - iterate over a list safe against removal
* of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/*
* File types
*/
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
#ifndef WIN32
#include <sys/stat.h>
#endif
/*
* Attribute flags. These should be or-ed together to figure out what
* has been changed!
*/
#define ATTR_MODE 1
#define ATTR_UID 2
#define ATTR_GID 4
#define ATTR_SIZE 8
#define ATTR_ATIME 16
#define ATTR_MTIME 32
#define ATTR_CTIME 64
#define ATTR_ATIME_SET 128
#define ATTR_MTIME_SET 256
#define ATTR_FORCE 512 /* Not a change, but a change it */
#define ATTR_ATTR_FLAG 1024
struct iattr {
unsigned int ia_valid;
unsigned ia_mode;
unsigned ia_uid;
unsigned ia_gid;
unsigned ia_size;
unsigned ia_atime;
unsigned ia_mtime;
unsigned ia_ctime;
unsigned int ia_attr_flags;
};
#define KERN_DEBUG
#else
#ifndef WIN32
#include <linux/types.h>
#include <linux/list.h>
#include <linux/fs.h>
#include <linux/stat.h>
#endif
#endif
#if defined WIN32
#undef new
#endif
#endif

66
fs/yaffs2/direct/Makefile Normal file
View file

@ -0,0 +1,66 @@
# Makefile for YAFFS direct test
#
#
# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
#
# Copyright (C) 2003 Aleph One Ltd.
#
#
# Created by Charles Manning <charles@aleph1.co.uk>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# NB Warning this Makefile does not include header dependencies.
#
# $Id: Makefile,v 1.15 2007/07/18 19:40:38 charles Exp $
#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
CFLAGS = -Wall -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -g $(EXTRA_COMPILE_FLAGS) -DNO_Y_INLINE
CFLAGS+= -fstack-check -O0
#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations
#CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline
DIRECTTESTOBJS = dtest.o yaffscfg2k.o yaffs_ecc.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \
yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \
yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \
yaffs_checkptrw.o yaffs_qsort.o \
# yaffs_checkptrwtest.o\
BOOTTESTOBJS = bootldtst.o yboot.o yaffs_fileem.o nand_ecc.o
#ALLOBJS = dtest.o nand_ecc.o yaffscfg.o yaffs_fileem.o yaffsfs.o yaffs_ramdisk.o bootldtst.o yboot.o yaffs_ramem2k.o
ALLOBJS = $(DIRECTTESTOBJS) $(BOOTTESTOBJS)
SYMLINKS = devextras.h yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h yaffsinterface.h yportenv.h yaffs_tagscompat.c yaffs_tagscompat.h \
yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h yaffs_nandemul2k.h \
yaffs_nand.c yaffs_nand.h \
yaffs_tagsvalidity.c yaffs_tagsvalidity.h yaffs_checkptrw.h yaffs_checkptrw.c \
yaffs_qsort.c yaffs_qsort.h
#all: directtest2k boottest
all: directtest2k
$(ALLOBJS): %.o: %.c
gcc -c $(CFLAGS) $< -o $@
$(SYMLINKS):
ln -s ../$@ $@
directtest2k: $(SYMLINKS) $(DIRECTTESTOBJS)
gcc -o $@ $(DIRECTTESTOBJS)
boottest: $(SYMLINKS) $(BOOTTESTOBJS)
gcc -o $@ $(BOOTTESTOBJS)
clean:
rm -f $(ALLOBJS) core

2280
fs/yaffs2/direct/dtest.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,75 @@
# Makefile for YAFFS direct test
#
#
# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
#
# Copyright (C) 2003 Aleph One Ltd.
#
#
# Created by Charles Manning <charles@aleph1.co.uk>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# NB Warning this Makefile does not include header dependencies.
#
# $Id: Makefile,v 1.1 2007/10/16 00:46:33 charles Exp $
#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
CFLAGS = -Wall -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -g $(EXTRA_COMPILE_FLAGS) -DNO_Y_INLINE
CFLAGS+= -fstack-check -O0
#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations
#CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline
FSXTESTOBJS = yaffs_fsx.o yaffscfg2k.o yaffs_ecc.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \
yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \
yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \
yaffs_checkptrw.o yaffs_qsort.o \
# yaffs_checkptrwtest.o\
BOOTTESTOBJS = bootldtst.o yboot.o yaffs_fileem.o nand_ecc.o
#ALLOBJS = dtest.o nand_ecc.o yaffscfg.o yaffs_fileem.o yaffsfs.o yaffs_ramdisk.o bootldtst.o yboot.o yaffs_ramem2k.o
ALLOBJS = $(FSXTESTOBJS) $(BOOTTESTOBJS)
YAFFSSYMLINKS = devextras.h yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h yaffsinterface.h yportenv.h yaffs_tagscompat.c yaffs_tagscompat.h \
yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h yaffs_nandemul2k.h \
yaffs_nand.c yaffs_nand.h \
yaffs_tagsvalidity.c yaffs_tagsvalidity.h yaffs_checkptrw.h yaffs_checkptrw.c \
yaffs_qsort.c yaffs_qsort.h
YAFFSDIRECTSYMLINKS = yaffscfg2k.c yaffs_fileem2k.c yaffsfs.c yaffs_flashif.h \
yaffs_fileem2k.h yaffsfs.h yaffs_malloc.h yaffs_ramdisk.h ydirectenv.h \
yaffscfg.h yaffs_fileem.c yaffs_flashif.c yaffs_ramdisk.c yaffs_ramem2k.c
#all: fsxtest boottest
all: fsxtest
$(ALLOBJS): %.o: %.c
gcc -c $(CFLAGS) $< -o $@
$(YAFFSSYMLINKS):
ln -s ../../$@ $@
$(YAFFSDIRECTSYMLINKS):
ln -s ../$@ $@
fsxtest: $(YAFFSSYMLINKS) $(YAFFSDIRECTSYMLINKS) $(FSXTESTOBJS)
gcc -o $@ $(FSXTESTOBJS)
boottest: $(SYMLINKS) $(BOOTTESTOBJS)
gcc -o $@ $(BOOTTESTOBJS)
clean:
rm -f $(ALLOBJS) core

View file

@ -0,0 +1,7 @@
NB THis directory uses a hacked version of fsx.c which is released under
Apple Public Source License.
From what I have been able to determine, it is legally OK to release a hacked
version for the purposes of testing.
If anyone knows otherwise, please contact me: manningc2@actrix.gen.nz

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,218 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This provides a YAFFS nand emulation on a file.
* This is only intended as test code to test persistence etc.
*/
const char *yaffs_flashif_c_version = "$Id: yaffs_fileem.c,v 1.3 2007/02/14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_flashif.h"
#include "yaffs_guts.h"
#include "devextras.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define SIZE_IN_MB 16
#define BLOCK_SIZE (32 * 528)
#define BLOCKS_PER_MEG ((1024*1024)/(32 * 512))
typedef struct
{
__u8 data[528]; // Data + spare
} yflash_Page;
typedef struct
{
yflash_Page page[32]; // The pages in the block
} yflash_Block;
typedef struct
{
int handle;
int nBlocks;
} yflash_Device;
static yflash_Device filedisk;
static int CheckInit(yaffs_Device *dev)
{
static int initialised = 0;
int i;
int fSize;
int written;
yflash_Page p;
if(initialised)
{
return YAFFS_OK;
}
initialised = 1;
filedisk.nBlocks = (SIZE_IN_MB * 1024 * 1024)/(16 * 1024);
filedisk.handle = open("yaffsemfile", O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
if(filedisk.handle < 0)
{
perror("Failed to open yaffs emulation file");
return YAFFS_FAIL;
}
fSize = lseek(filedisk.handle,0,SEEK_END);
if(fSize < SIZE_IN_MB * 1024 * 1024)
{
printf("Creating yaffs emulation file\n");
lseek(filedisk.handle,0,SEEK_SET);
memset(&p,0xff,sizeof(yflash_Page));
for(i = 0; i < SIZE_IN_MB * 1024 * 1024; i+= 512)
{
written = write(filedisk.handle,&p,sizeof(yflash_Page));
if(written != sizeof(yflash_Page))
{
printf("Write failed\n");
return YAFFS_FAIL;
}
}
}
return 1;
}
int yflash_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare)
{
int written;
CheckInit(dev);
if(data)
{
lseek(filedisk.handle,chunkInNAND * 528,SEEK_SET);
written = write(filedisk.handle,data,512);
if(written != 512) return YAFFS_FAIL;
}
if(spare)
{
lseek(filedisk.handle,chunkInNAND * 528 + 512,SEEK_SET);
written = write(filedisk.handle,spare,16);
if(written != 16) return YAFFS_FAIL;
}
return YAFFS_OK;
}
int yflash_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
{
int nread;
CheckInit(dev);
if(data)
{
lseek(filedisk.handle,chunkInNAND * 528,SEEK_SET);
nread = read(filedisk.handle,data,512);
if(nread != 512) return YAFFS_FAIL;
}
if(spare)
{
lseek(filedisk.handle,chunkInNAND * 528 + 512,SEEK_SET);
nread= read(filedisk.handle,spare,16);
if(nread != 16) return YAFFS_FAIL;
}
return YAFFS_OK;
}
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
{
int i;
CheckInit(dev);
if(blockNumber < 0 || blockNumber >= filedisk.nBlocks)
{
T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
return YAFFS_FAIL;
}
else
{
yflash_Page pg;
memset(&pg,0xff,sizeof(yflash_Page));
lseek(filedisk.handle, blockNumber * 32 * 528, SEEK_SET);
for(i = 0; i < 32; i++)
{
write(filedisk.handle,&pg,528);
}
return YAFFS_OK;
}
}
int yflash_InitialiseNAND(yaffs_Device *dev)
{
dev->useNANDECC = 1; // force on useNANDECC which gets faked.
// This saves us doing ECC checks.
return YAFFS_OK;
}

View file

@ -0,0 +1,441 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This provides a YAFFS nand emulation on a file for emulating 2kB pages.
* This is only intended as test code to test persistence etc.
*/
const char *yaffs_flashif_c_version = "$Id: yaffs_fileem2k.c,v 1.12 2007/02/14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_flashif.h"
#include "yaffs_guts.h"
#include "devextras.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "yaffs_fileem2k.h"
#include "yaffs_packedtags2.h"
//#define SIMULATE_FAILURES
typedef struct
{
__u8 data[PAGE_SIZE]; // Data + spare
} yflash_Page;
typedef struct
{
yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block
} yflash_Block;
#define MAX_HANDLES 20
#define BLOCKS_PER_HANDLE 8000
typedef struct
{
int handle[MAX_HANDLES];
int nBlocks;
} yflash_Device;
static yflash_Device filedisk;
int yaffs_testPartialWrite = 0;
static __u8 localBuffer[PAGE_SIZE];
static char *NToName(char *buf,int n)
{
sprintf(buf,"emfile%d",n);
return buf;
}
static char dummyBuffer[BLOCK_SIZE];
static int GetBlockFileHandle(int n)
{
int h;
int requiredSize;
char name[40];
NToName(name,n);
int fSize;
int i;
h = open(name, O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
if(h >= 0){
fSize = lseek(h,0,SEEK_END);
requiredSize = BLOCKS_PER_HANDLE * BLOCK_SIZE;
if(fSize < requiredSize){
for(i = 0; i < BLOCKS_PER_HANDLE; i++)
if(write(h,dummyBuffer,BLOCK_SIZE) != BLOCK_SIZE)
return -1;
}
}
return h;
}
static int CheckInit(void)
{
static int initialised = 0;
int h;
int i;
off_t fSize;
off_t requiredSize;
int written;
int blk;
yflash_Page p;
if(initialised)
{
return YAFFS_OK;
}
initialised = 1;
memset(dummyBuffer,0xff,sizeof(dummyBuffer));
filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB;
for(i = 0; i < MAX_HANDLES; i++)
filedisk.handle[i] = -1;
for(i = 0,blk = 0; blk < filedisk.nBlocks; blk+=BLOCKS_PER_HANDLE,i++)
filedisk.handle[i] = GetBlockFileHandle(i);
return 1;
}
int yflash_GetNumberOfBlocks(void)
{
CheckInit();
return filedisk.nBlocks;
}
int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
{
int written;
int pos;
int h;
int i;
int nRead;
int error;
T(YAFFS_TRACE_MTD,(TSTR("write chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
CheckInit();
if(data)
{
pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
lseek(h,pos,SEEK_SET);
nRead = read(h, localBuffer,dev->nDataBytesPerChunk);
for(i = error = 0; i < dev->nDataBytesPerChunk && !error; i++){
if(localBuffer[i] != 0xFF){
printf("nand simulation: chunk %d data byte %d was %0x2\n",
chunkInNAND,i,localBuffer[i]);
error = 1;
}
}
for(i = 0; i < dev->nDataBytesPerChunk; i++)
localBuffer[i] &= data[i];
if(memcmp(localBuffer,data,dev->nDataBytesPerChunk))
printf("nand simulator: data does not match\n");
lseek(h,pos,SEEK_SET);
written = write(h,localBuffer,dev->nDataBytesPerChunk);
if(yaffs_testPartialWrite){
close(h);
exit(1);
}
#ifdef SIMULATE_FAILURES
if((chunkInNAND >> 6) == 100)
written = 0;
if((chunkInNAND >> 6) == 110)
written = 0;
#endif
if(written != dev->nDataBytesPerChunk) return YAFFS_FAIL;
}
if(tags)
{
pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
lseek(h,pos,SEEK_SET);
if( 0 && dev->isYaffs2)
{
written = write(h,tags,sizeof(yaffs_ExtendedTags));
if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
}
else
{
yaffs_PackedTags2 pt;
yaffs_PackTags2(&pt,tags);
__u8 * ptab = (__u8 *)&pt;
nRead = read(h,localBuffer,sizeof(pt));
for(i = error = 0; i < sizeof(pt) && !error; i++){
if(localBuffer[i] != 0xFF){
printf("nand simulation: chunk %d oob byte %d was %0x2\n",
chunkInNAND,i,localBuffer[i]);
error = 1;
}
}
for(i = 0; i < sizeof(pt); i++)
localBuffer[i] &= ptab[i];
if(memcmp(localBuffer,&pt,sizeof(pt)))
printf("nand sim: tags corruption\n");
lseek(h,pos,SEEK_SET);
written = write(h,localBuffer,sizeof(pt));
if(written != sizeof(pt)) return YAFFS_FAIL;
}
}
return YAFFS_OK;
}
int yaffs_CheckAllFF(const __u8 *ptr, int n)
{
while(n)
{
n--;
if(*ptr!=0xFF) return 0;
ptr++;
}
return 1;
}
static int fail300 = 1;
static int fail320 = 1;
static int failRead10 = 2;
int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
{
int nread;
int pos;
int h;
T(YAFFS_TRACE_MTD,(TSTR("read chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
CheckInit();
if(data)
{
pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
lseek(h,pos,SEEK_SET);
nread = read(h,data,dev->nDataBytesPerChunk);
if(nread != dev->nDataBytesPerChunk) return YAFFS_FAIL;
}
if(tags)
{
pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE;
h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
lseek(h,pos,SEEK_SET);
if(0 && dev->isYaffs2)
{
nread= read(h,tags,sizeof(yaffs_ExtendedTags));
if(nread != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
if(yaffs_CheckAllFF((__u8 *)tags,sizeof(yaffs_ExtendedTags)))
{
yaffs_InitialiseTags(tags);
}
else
{
tags->chunkUsed = 1;
}
}
else
{
yaffs_PackedTags2 pt;
nread= read(h,&pt,sizeof(pt));
yaffs_UnpackTags2(tags,&pt);
#ifdef SIMULATE_FAILURES
if((chunkInNAND >> 6) == 100) {
if(fail300 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
tags->eccResult = YAFFS_ECC_RESULT_FIXED;
fail300 = 0;
}
}
if((chunkInNAND >> 6) == 110) {
if(fail320 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
tags->eccResult = YAFFS_ECC_RESULT_FIXED;
fail320 = 0;
}
}
#endif
if(failRead10>0 && chunkInNAND == 10){
failRead10--;
nread = 0;
}
if(nread != sizeof(pt)) return YAFFS_FAIL;
}
}
return YAFFS_OK;
}
int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
int written;
int h;
yaffs_PackedTags2 pt;
CheckInit();
memset(&pt,0,sizeof(pt));
h = filedisk.handle[(blockNo / ( BLOCKS_PER_HANDLE))];
lseek(h,((blockNo % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET);
written = write(h,&pt,sizeof(pt));
if(written != sizeof(pt)) return YAFFS_FAIL;
return YAFFS_OK;
}
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
{
int i;
int h;
CheckInit();
printf("erase block %d\n",blockNumber);
if(blockNumber == 320)
fail320 = 1;
if(blockNumber < 0 || blockNumber >= filedisk.nBlocks)
{
T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
return YAFFS_FAIL;
}
else
{
__u8 pg[PAGE_SIZE];
int syz = PAGE_SIZE;
int pos;
memset(pg,0xff,syz);
h = filedisk.handle[(blockNumber / ( BLOCKS_PER_HANDLE))];
lseek(h,((blockNumber % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE,SEEK_SET);
for(i = 0; i < dev->nChunksPerBlock; i++)
{
write(h,pg,PAGE_SIZE);
}
pos = lseek(h, 0,SEEK_CUR);
return YAFFS_OK;
}
}
int yflash_InitialiseNAND(yaffs_Device *dev)
{
CheckInit();
return YAFFS_OK;
}
int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
{
yaffs_ExtendedTags tags;
int chunkNo;
*sequenceNumber = 0;
chunkNo = blockNo * dev->nChunksPerBlock;
yflash_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
if(tags.blockBad)
{
*state = YAFFS_BLOCK_STATE_DEAD;
}
else if(!tags.chunkUsed)
{
*state = YAFFS_BLOCK_STATE_EMPTY;
}
else if(tags.chunkUsed)
{
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
*sequenceNumber = tags.sequenceNumber;
}
return YAFFS_OK;
}

View file

@ -0,0 +1,50 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __FILEEM2K_H__
#define __FILEEM2K_H__
#if 1
#define SIZE_IN_MB 128
//#define SIZE_IN_MB 8000
#define PAGE_DATA_SIZE (2048)
#define PAGE_SPARE_SIZE (64)
#define PAGE_SIZE (PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
#define PAGES_PER_BLOCK (64)
#define BLOCK_DATA_SIZE (PAGE_DATA_SIZE * PAGES_PER_BLOCK)
#define BLOCK_SIZE (PAGES_PER_BLOCK * (PAGE_SIZE))
#define BLOCKS_PER_MB ((1024*1024)/BLOCK_DATA_SIZE)
#define SIZE_IN_BLOCKS (BLOCKS_PER_MB * SIZE_IN_MB)
#else
#define SIZE_IN_MB 128
#define PAGE_DATA_SIZE (512)
#define SPARE_SIZE (16)
#define PAGE_SIZE (PAGE_DATA_SIZE + SPARE_SIZE)
#define PAGES_PER_BLOCK (32)
#define BLOCK_DATA_SIZE (PAGE_SIZE * PAGES_PER_BLOCK)
#define BLOCK_SIZE (PAGES_PER_BLOCK * (PAGE_SIZE))
#define BLOCKS_PER_MB ((1024*1024)/BLOCK_DATA_SIZE)
#define SIZE_IN_BLOCKS (BLOCKS_PER_MB * SIZE_IN_MB)
#endif
int yflash_GetNumberOfBlocks(void);
#endif

View file

@ -0,0 +1,229 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
const char *yaffs_flashif_c_version = "$Id: yaffs_flashif.c,v 1.3 2007/02/14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_flashif.h"
#include "yaffs_guts.h"
#include "devextras.h"
#define SIZE_IN_MB 16
#define BLOCK_SIZE (32 * 528)
#define BLOCKS_PER_MEG ((1024*1024)/(32 * 512))
typedef struct
{
__u8 data[528]; // Data + spare
} yflash_Page;
typedef struct
{
yflash_Page page[32]; // The pages in the block
} yflash_Block;
typedef struct
{
yflash_Block **block;
int nBlocks;
} yflash_Device;
static yflash_Device ramdisk;
static int CheckInit(yaffs_Device *dev)
{
static int initialised = 0;
int i;
int fail = 0;
int nAllocated = 0;
if(initialised)
{
return YAFFS_OK;
}
initialised = 1;
ramdisk.nBlocks = (SIZE_IN_MB * 1024 * 1024)/(16 * 1024);
ramdisk.block = YMALLOC(sizeof(yflash_Block *) * ramdisk.nBlocks);
if(!ramdisk.block) return 0;
for(i=0; i <ramdisk.nBlocks; i++)
{
ramdisk.block[i] = NULL;
}
for(i=0; i <ramdisk.nBlocks && !fail; i++)
{
if((ramdisk.block[i] = YMALLOC(sizeof(yflash_Block))) == 0)
{
fail = 1;
}
else
{
yflash_EraseBlockInNAND(dev,i);
nAllocated++;
}
}
if(fail)
{
for(i = 0; i < nAllocated; i++)
{
YFREE(ramdisk.block[i]);
}
YFREE(ramdisk.block);
T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n",
nAllocated/64,ramdisk.nBlocks * YAFFS_BYTES_PER_BLOCK));
return 0;
}
return 1;
}
int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
{
int blk;
int pg;
CheckInit(dev);
blk = chunkInNAND/32;
pg = chunkInNAND%32;
if(data)
{
memcpy(ramdisk.block[blk]->page[pg].data,data,512);
}
if(tags)
{
yaffs_PackedTags pt;
yaffs_PackTags(&pt,tags);
memcpy(&ramdisk.block[blk]->page[pg].data[512],&pt,sizeof(pt));
}
return YAFFS_OK;
}
int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Tags *tags)
{
int blk;
int pg;
CheckInit(dev);
blk = chunkInNAND/32;
pg = chunkInNAND%32;
if(data)
{
memcpy(data,ramdisk.block[blk]->page[pg].data,512);
}
if(tags)
{
yaffs_PackedTags pt;
memcpy(&pt,&ramdisk.block[blk]->page[pg].data[512],sizeof(yaffs_PackedTags));
yaffs_UnpackTags(tags,&pt);
}
return YAFFS_OK;
}
int yflash_CheckChunkErased(yaffs_Device *dev,int chunkInNAND)
{
int blk;
int pg;
int i;
CheckInit(dev);
blk = chunkInNAND/32;
pg = chunkInNAND%32;
for(i = 0; i < 528; i++)
{
if(ramdisk.block[blk]->page[pg].data[i] != 0xFF)
{
return YAFFS_FAIL;
}
}
return YAFFS_OK;
}
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
{
CheckInit(dev);
if(blockNumber < 0 || blockNumber >= ramdisk.nBlocks)
{
T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
return YAFFS_FAIL;
}
else
{
memset(ramdisk.block[blockNumber],0xFF,sizeof(yflash_Block));
return YAFFS_OK;
}
}
int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
return YAFFS_OK;
}
int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
{
*state = YAFFS_BLOCK_STATE_EMPTY;
*sequenceNumber = 0;
}
int yflash_InitialiseNAND(yaffs_Device *dev)
{
return YAFFS_OK;
}

View file

@ -0,0 +1,31 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_FLASH_H__
#define __YAFFS_FLASH_H__
#include "yaffs_guts.h"
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
int yflash_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare);
int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags);
int yflash_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);
int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
int yflash_InitialiseNAND(yaffs_Device *dev);
int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
#endif

View file

@ -0,0 +1,23 @@
#ifndef __YAFFS_MALLOC_H__
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#include <stdlib.h>
void *yaffs_malloc(size_t size);
void yaffs_free(void *ptr);
#endif

View file

@ -0,0 +1,234 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* yaffs_ramdisk.c: yaffs ram disk component
* This provides a ram disk under yaffs.
* NB this is not intended for NAND emulation.
* Use this with dev->useNANDECC enabled, then ECC overheads are not required.
*/
const char *yaffs_ramdisk_c_version = "$Id: yaffs_ramdisk.c,v 1.4 2007/02/14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_ramdisk.h"
#include "yaffs_guts.h"
#include "devextras.h"
#include "yaffs_packedtags1.h"
#define SIZE_IN_MB 2
#define BLOCK_SIZE (32 * 528)
#define BLOCKS_PER_MEG ((1024*1024)/(32 * 512))
typedef struct
{
__u8 data[528]; // Data + spare
} yramdisk_Page;
typedef struct
{
yramdisk_Page page[32]; // The pages in the block
} yramdisk_Block;
typedef struct
{
yramdisk_Block **block;
int nBlocks;
} yramdisk_Device;
static yramdisk_Device ramdisk;
static int CheckInit(yaffs_Device *dev)
{
static int initialised = 0;
int i;
int fail = 0;
//int nBlocks;
int nAllocated = 0;
if(initialised)
{
return YAFFS_OK;
}
initialised = 1;
ramdisk.nBlocks = (SIZE_IN_MB * 1024 * 1024)/(16 * 1024);
ramdisk.block = YMALLOC(sizeof(yramdisk_Block *) * ramdisk.nBlocks);
if(!ramdisk.block) return 0;
for(i=0; i <ramdisk.nBlocks; i++)
{
ramdisk.block[i] = NULL;
}
for(i=0; i <ramdisk.nBlocks && !fail; i++)
{
if((ramdisk.block[i] = YMALLOC(sizeof(yramdisk_Block))) == 0)
{
fail = 1;
}
else
{
yramdisk_EraseBlockInNAND(dev,i);
nAllocated++;
}
}
if(fail)
{
for(i = 0; i < nAllocated; i++)
{
YFREE(ramdisk.block[i]);
}
YFREE(ramdisk.block);
T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n",
nAllocated/64,ramdisk.nBlocks * 528));
return 0;
}
return 1;
}
int yramdisk_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
{
int blk;
int pg;
CheckInit(dev);
blk = chunkInNAND/32;
pg = chunkInNAND%32;
if(data)
{
memcpy(ramdisk.block[blk]->page[pg].data,data,512);
}
if(tags)
{
yaffs_PackedTags1 pt;
yaffs_PackTags1(&pt,tags);
memcpy(&ramdisk.block[blk]->page[pg].data[512],&pt,sizeof(pt));
}
return YAFFS_OK;
}
int yramdisk_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
{
int blk;
int pg;
CheckInit(dev);
blk = chunkInNAND/32;
pg = chunkInNAND%32;
if(data)
{
memcpy(data,ramdisk.block[blk]->page[pg].data,512);
}
if(tags)
{
yaffs_PackedTags1 pt;
memcpy(&pt,&ramdisk.block[blk]->page[pg].data[512],sizeof(pt));
yaffs_UnpackTags1(tags,&pt);
}
return YAFFS_OK;
}
int yramdisk_CheckChunkErased(yaffs_Device *dev,int chunkInNAND)
{
int blk;
int pg;
int i;
CheckInit(dev);
blk = chunkInNAND/32;
pg = chunkInNAND%32;
for(i = 0; i < 528; i++)
{
if(ramdisk.block[blk]->page[pg].data[i] != 0xFF)
{
return YAFFS_FAIL;
}
}
return YAFFS_OK;
}
int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
{
CheckInit(dev);
if(blockNumber < 0 || blockNumber >= ramdisk.nBlocks)
{
T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
return YAFFS_FAIL;
}
else
{
memset(ramdisk.block[blockNumber],0xFF,sizeof(yramdisk_Block));
return YAFFS_OK;
}
}
int yramdisk_InitialiseNAND(yaffs_Device *dev)
{
//dev->useNANDECC = 1; // force on useNANDECC which gets faked.
// This saves us doing ECC checks.
return YAFFS_OK;
}

View file

@ -0,0 +1,32 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* yaffs_ramdisk.h: yaffs ram disk component
*/
#ifndef __YAFFS_RAMDISK_H__
#define __YAFFS_RAMDISK_H__
#include "yaffs_guts.h"
int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
int yramdisk_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags);
int yramdisk_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
int yramdisk_InitialiseNAND(yaffs_Device *dev);
int yramdisk_MarkNANDBlockBad(yaffs_Device *dev,int blockNumber);
int yramdisk_QueryNANDBlock(yaffs_Device *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
#endif

View file

@ -0,0 +1,363 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* yaffs_ramem2k.c: RAM emulation in-kernel for 2K pages (YAFFS2)
*/
const char *yaffs_ramem2k_c_version = "$Id: yaffs_ramem2k.c,v 1.3 2007/02/14 01:09:06 wookey Exp $";
#ifndef __KERNEL__
#define CONFIG_YAFFS_RAM_ENABLED
#else
#include <linux/config.h>
#endif
#ifdef CONFIG_YAFFS_RAM_ENABLED
#include "yportenv.h"
#include "yaffs_nandemul2k.h"
#include "yaffs_guts.h"
#include "yaffsinterface.h"
#include "devextras.h"
#include "yaffs_packedtags2.h"
#define EM_SIZE_IN_MEG (32)
#define PAGE_DATA_SIZE (2048)
#define PAGE_SPARE_SIZE (64)
#define PAGES_PER_BLOCK (64)
#define EM_SIZE_IN_BYTES (EM_SIZE_IN_MEG * (1<<20))
#define PAGE_TOTAL_SIZE (PAGE_DATA_SIZE+PAGE_SPARE_SIZE)
#define BLOCK_TOTAL_SIZE (PAGES_PER_BLOCK * PAGE_TOTAL_SIZE)
#define BLOCKS_PER_MEG ((1<<20)/(PAGES_PER_BLOCK * PAGE_DATA_SIZE))
typedef struct
{
__u8 data[PAGE_TOTAL_SIZE]; // Data + spare
int empty; // is this empty?
} nandemul_Page;
typedef struct
{
nandemul_Page *page[PAGES_PER_BLOCK];
int damaged;
} nandemul_Block;
typedef struct
{
nandemul_Block**block;
int nBlocks;
} nandemul_Device;
static nandemul_Device ned;
static int sizeInMB = EM_SIZE_IN_MEG;
static void nandemul_yield(int n)
{
#ifdef __KERNEL__
if(n > 0) schedule_timeout(n);
#endif
}
static void nandemul_ReallyEraseBlock(int blockNumber)
{
int i;
nandemul_Block *blk;
if(blockNumber < 0 || blockNumber >= ned.nBlocks)
{
return;
}
blk = ned.block[blockNumber];
for(i = 0; i < PAGES_PER_BLOCK; i++)
{
memset(blk->page[i],0xff,sizeof(nandemul_Page));
blk->page[i]->empty = 1;
}
nandemul_yield(2);
}
static int nandemul2k_CalcNBlocks(void)
{
return EM_SIZE_IN_MEG * BLOCKS_PER_MEG;
}
static int CheckInit(void)
{
static int initialised = 0;
int i,j;
int fail = 0;
int nBlocks;
int nAllocated = 0;
if(initialised)
{
return YAFFS_OK;
}
ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks();
ned.block = YMALLOC(sizeof(nandemul_Block*) * nBlocks );
if(!ned.block) return YAFFS_FAIL;
for(i=fail=0; i <nBlocks; i++)
{
nandemul_Block *blk;
if(!(blk = ned.block[i] = YMALLOC(sizeof(nandemul_Block))))
{
fail = 1;
}
else
{
for(j = 0; j < PAGES_PER_BLOCK; j++)
{
if((blk->page[j] = YMALLOC(sizeof(nandemul_Page))) == 0)
{
fail = 1;
}
}
nandemul_ReallyEraseBlock(i);
ned.block[i]->damaged = 0;
nAllocated++;
}
}
if(fail)
{
//Todo thump pages
for(i = 0; i < nAllocated; i++)
{
YFREE(ned.block[i]);
}
YFREE(ned.block);
T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n",
nAllocated/64,sizeInMB));
return 0;
}
ned.nBlocks = nBlocks;
initialised = 1;
return 1;
}
int nandemul2k_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
{
int blk;
int pg;
int i;
__u8 *x;
blk = chunkInNAND/PAGES_PER_BLOCK;
pg = chunkInNAND%PAGES_PER_BLOCK;
if(data)
{
x = ned.block[blk]->page[pg]->data;
for(i = 0; i < PAGE_DATA_SIZE; i++)
{
x[i] &=data[i];
}
ned.block[blk]->page[pg]->empty = 0;
}
if(tags)
{
x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE];
yaffs_PackTags2((yaffs_PackedTags2 *)x,tags);
}
if(tags || data)
{
nandemul_yield(1);
}
return YAFFS_OK;
}
int nandemul2k_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
{
int blk;
int pg;
__u8 *x;
blk = chunkInNAND/PAGES_PER_BLOCK;
pg = chunkInNAND%PAGES_PER_BLOCK;
if(data)
{
memcpy(data,ned.block[blk]->page[pg]->data,PAGE_DATA_SIZE);
}
if(tags)
{
x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE];
yaffs_UnpackTags2(tags,(yaffs_PackedTags2 *)x);
}
return YAFFS_OK;
}
static int nandemul2k_CheckChunkErased(yaffs_Device *dev,int chunkInNAND)
{
int blk;
int pg;
int i;
blk = chunkInNAND/PAGES_PER_BLOCK;
pg = chunkInNAND%PAGES_PER_BLOCK;
for(i = 0; i < PAGE_TOTAL_SIZE; i++)
{
if(ned.block[blk]->page[pg]->data[i] != 0xFF)
{
return YAFFS_FAIL;
}
}
return YAFFS_OK;
}
int nandemul2k_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
{
if(blockNumber < 0 || blockNumber >= ned.nBlocks)
{
T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
}
else if(ned.block[blockNumber]->damaged)
{
T(YAFFS_TRACE_ALWAYS,("Attempt to erase damaged block %d\n",blockNumber));
}
else
{
nandemul_ReallyEraseBlock(blockNumber);
}
return YAFFS_OK;
}
int nandemul2k_InitialiseNAND(yaffs_Device *dev)
{
CheckInit();
return YAFFS_OK;
}
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
__u8 *x;
x = &ned.block[blockNo]->page[0]->data[PAGE_DATA_SIZE];
memset(x,0,sizeof(yaffs_PackedTags2));
return YAFFS_OK;
}
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
{
yaffs_ExtendedTags tags;
int chunkNo;
*sequenceNumber = 0;
chunkNo = blockNo * dev->nChunksPerBlock;
nandemul2k_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
if(tags.blockBad)
{
*state = YAFFS_BLOCK_STATE_DEAD;
}
else if(!tags.chunkUsed)
{
*state = YAFFS_BLOCK_STATE_EMPTY;
}
else if(tags.chunkUsed)
{
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
*sequenceNumber = tags.sequenceNumber;
}
return YAFFS_OK;
}
int nandemul2k_GetBytesPerChunk(void) { return PAGE_DATA_SIZE;}
int nandemul2k_GetChunksPerBlock(void) { return PAGES_PER_BLOCK; }
int nandemul2k_GetNumberOfBlocks(void) {return nandemul2k_CalcNBlocks();}
#endif //YAFFS_RAM_ENABLED

144
fs/yaffs2/direct/yaffscfg.c Normal file
View file

@ -0,0 +1,144 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* yaffscfg.c The configuration for the "direct" use of yaffs.
*
* This file is intended to be modified to your requirements.
* There is no need to redistribute this file.
*/
#include "yaffscfg.h"
#include "yaffsfs.h"
#include <errno.h>
unsigned yaffs_traceMask = 0xFFFFFFFF;
void yaffsfs_SetError(int err)
{
//Do whatever to set error
errno = err;
}
void yaffsfs_Lock(void)
{
}
void yaffsfs_Unlock(void)
{
}
__u32 yaffsfs_CurrentTime(void)
{
return 0;
}
void *yaffs_malloc(size_t size)
{
return malloc(size);
}
void yaffs_free(void *ptr)
{
free(ptr);
}
void yaffsfs_LocalInitialisation(void)
{
// Define locking semaphore.
}
// Configuration for:
// /ram 2MB ramdisk
// /boot 2MB boot disk (flash)
// /flash 14MB flash disk (flash)
// NB Though /boot and /flash occupy the same physical device they
// are still disticnt "yaffs_Devices. You may think of these as "partitions"
// using non-overlapping areas in the same device.
//
#include "yaffs_ramdisk.h"
#include "yaffs_flashif.h"
static yaffs_Device ramDev;
static yaffs_Device bootDev;
static yaffs_Device flashDev;
static yaffsfs_DeviceConfiguration yaffsfs_config[] = {
{ "/ram", &ramDev},
{ "/boot", &bootDev},
{ "/flash", &flashDev},
{(void *)0,(void *)0}
};
int yaffs_StartUp(void)
{
// Stuff to configure YAFFS
// Stuff to initialise anything special (eg lock semaphore).
yaffsfs_LocalInitialisation();
// Set up devices
// /ram
ramDev.nBytesPerChunk = 512;
ramDev.nChunksPerBlock = 32;
ramDev.nReservedBlocks = 2; // Set this smaller for RAM
ramDev.startBlock = 1; // Can't use block 0
ramDev.endBlock = 127; // Last block in 2MB.
ramDev.useNANDECC = 1;
ramDev.nShortOpCaches = 0; // Disable caching on this device.
ramDev.genericDevice = (void *) 0; // Used to identify the device in fstat.
ramDev.writeChunkWithTagsToNAND = yramdisk_WriteChunkWithTagsToNAND;
ramDev.readChunkWithTagsFromNAND = yramdisk_ReadChunkWithTagsFromNAND;
ramDev.eraseBlockInNAND = yramdisk_EraseBlockInNAND;
ramDev.initialiseNAND = yramdisk_InitialiseNAND;
// /boot
bootDev.nBytesPerChunk = 612;
bootDev.nChunksPerBlock = 32;
bootDev.nReservedBlocks = 5;
bootDev.startBlock = 1; // Can't use block 0
bootDev.endBlock = 127; // Last block in 2MB.
bootDev.useNANDECC = 0; // use YAFFS's ECC
bootDev.nShortOpCaches = 10; // Use caches
bootDev.genericDevice = (void *) 1; // Used to identify the device in fstat.
bootDev.writeChunkToNAND = yflash_WriteChunkToNAND;
bootDev.readChunkFromNAND = yflash_ReadChunkFromNAND;
bootDev.eraseBlockInNAND = yflash_EraseBlockInNAND;
bootDev.initialiseNAND = yflash_InitialiseNAND;
// /flash
flashDev.nBytesPerChunk = 512;
flashDev.nChunksPerBlock = 32;
flashDev.nReservedBlocks = 5;
flashDev.startBlock = 128; // First block after 2MB
flashDev.endBlock = 1023; // Last block in 16MB
flashDev.useNANDECC = 0; // use YAFFS's ECC
flashDev.nShortOpCaches = 10; // Use caches
flashDev.genericDevice = (void *) 2; // Used to identify the device in fstat.
flashDev.writeChunkToNAND = yflash_WriteChunkToNAND;
flashDev.readChunkFromNAND = yflash_ReadChunkFromNAND;
flashDev.eraseBlockInNAND = yflash_EraseBlockInNAND;
flashDev.initialiseNAND = yflash_InitialiseNAND;
yaffs_initialise(yaffsfs_config);
return 0;
}

View file

@ -0,0 +1,45 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* Header file for using yaffs in an application via
* a direct interface.
*/
#ifndef __YAFFSCFG_H__
#define __YAFFSCFG_H__
#include "devextras.h"
#define YAFFSFS_N_HANDLES 200
typedef struct {
const char *prefix;
struct yaffs_DeviceStruct *dev;
} yaffsfs_DeviceConfiguration;
void yaffsfs_Lock(void);
void yaffsfs_Unlock(void);
__u32 yaffsfs_CurrentTime(void);
void yaffsfs_SetError(int err);
#endif

View file

@ -0,0 +1,229 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* yaffscfg2k.c The configuration for the "direct" use of yaffs.
*
* This file is intended to be modified to your requirements.
* There is no need to redistribute this file.
*/
#include "yaffscfg.h"
#include "yaffsfs.h"
#include "yaffs_fileem2k.h"
#include "yaffs_nandemul2k.h"
#include <errno.h>
unsigned yaffs_traceMask =
YAFFS_TRACE_SCAN |
YAFFS_TRACE_GC | YAFFS_TRACE_GC_DETAIL |
YAFFS_TRACE_ERASE |
YAFFS_TRACE_TRACING |
YAFFS_TRACE_ALLOCATE |
YAFFS_TRACE_CHECKPOINT |
YAFFS_TRACE_BAD_BLOCKS |
YAFFS_TRACE_VERIFY |
YAFFS_TRACE_VERIFY_NAND |
YAFFS_TRACE_VERIFY_FULL |
// (~0) |
0;
void yaffsfs_SetError(int err)
{
//Do whatever to set error
errno = err;
}
void yaffsfs_Lock(void)
{
}
void yaffsfs_Unlock(void)
{
}
__u32 yaffsfs_CurrentTime(void)
{
return 0;
}
static int yaffs_kill_alloc = 0;
static size_t total_malloced = 0;
static size_t malloc_limit = 0 & 6000000;
void *yaffs_malloc(size_t size)
{
size_t this;
if(yaffs_kill_alloc)
return NULL;
if(malloc_limit && malloc_limit <(total_malloced + size) )
return NULL;
this = malloc(size);
if(this)
total_malloced += size;
return this;
}
void yaffs_free(void *ptr)
{
free(ptr);
}
void yaffsfs_LocalInitialisation(void)
{
// Define locking semaphore.
}
// Configuration for:
// /ram 2MB ramdisk
// /boot 2MB boot disk (flash)
// /flash 14MB flash disk (flash)
// NB Though /boot and /flash occupy the same physical device they
// are still disticnt "yaffs_Devices. You may think of these as "partitions"
// using non-overlapping areas in the same device.
//
#include "yaffs_ramdisk.h"
#include "yaffs_flashif.h"
#include "yaffs_nandemul2k.h"
static yaffs_Device ramDev;
static yaffs_Device bootDev;
static yaffs_Device flashDev;
static yaffs_Device ram2kDev;
static yaffsfs_DeviceConfiguration yaffsfs_config[] = {
#if 0
{ "/ram", &ramDev},
{ "/boot", &bootDev},
{ "/flash/", &flashDev},
{ "/ram2k", &ram2kDev},
{(void *)0,(void *)0}
#else
{ "/", &ramDev},
{ "/flash/boot", &bootDev},
{ "/flash/flash", &flashDev},
{ "/ram2k", &ram2kDev},
{(void *)0,(void *)0} /* Null entry to terminate list */
#endif
};
int yaffs_StartUp(void)
{
// Stuff to configure YAFFS
// Stuff to initialise anything special (eg lock semaphore).
yaffsfs_LocalInitialisation();
// Set up devices
// /ram
memset(&ramDev,0,sizeof(ramDev));
ramDev.nDataBytesPerChunk = 512;
ramDev.nChunksPerBlock = 32;
ramDev.nReservedBlocks = 2; // Set this smaller for RAM
ramDev.startBlock = 0; // Can use block 0
ramDev.endBlock = 127; // Last block in 2MB.
//ramDev.useNANDECC = 1;
ramDev.nShortOpCaches = 0; // Disable caching on this device.
ramDev.genericDevice = (void *) 0; // Used to identify the device in fstat.
ramDev.writeChunkWithTagsToNAND = yramdisk_WriteChunkWithTagsToNAND;
ramDev.readChunkWithTagsFromNAND = yramdisk_ReadChunkWithTagsFromNAND;
ramDev.eraseBlockInNAND = yramdisk_EraseBlockInNAND;
ramDev.initialiseNAND = yramdisk_InitialiseNAND;
// /boot
memset(&bootDev,0,sizeof(bootDev));
bootDev.nDataBytesPerChunk = 512;
bootDev.nChunksPerBlock = 32;
bootDev.nReservedBlocks = 5;
bootDev.startBlock = 0; // Can use block 0
bootDev.endBlock = 63; // Last block
//bootDev.useNANDECC = 0; // use YAFFS's ECC
bootDev.nShortOpCaches = 10; // Use caches
bootDev.genericDevice = (void *) 1; // Used to identify the device in fstat.
bootDev.writeChunkWithTagsToNAND = yflash_WriteChunkWithTagsToNAND;
bootDev.readChunkWithTagsFromNAND = yflash_ReadChunkWithTagsFromNAND;
bootDev.eraseBlockInNAND = yflash_EraseBlockInNAND;
bootDev.initialiseNAND = yflash_InitialiseNAND;
bootDev.markNANDBlockBad = yflash_MarkNANDBlockBad;
bootDev.queryNANDBlock = yflash_QueryNANDBlock;
// /flash
// Set this puppy up to use
// the file emulation space as
// 2kpage/64chunk per block/128MB device
memset(&flashDev,0,sizeof(flashDev));
flashDev.nDataBytesPerChunk = 2048;
flashDev.nChunksPerBlock = 64;
flashDev.nReservedBlocks = 5;
flashDev.nCheckpointReservedBlocks = 5;
//flashDev.checkpointStartBlock = 1;
//flashDev.checkpointEndBlock = 20;
flashDev.startBlock = 0;
flashDev.endBlock = 200; // Make it smaller
//flashDev.endBlock = yflash_GetNumberOfBlocks()-1;
flashDev.isYaffs2 = 1;
flashDev.wideTnodesDisabled=0;
flashDev.nShortOpCaches = 10; // Use caches
flashDev.genericDevice = (void *) 2; // Used to identify the device in fstat.
flashDev.writeChunkWithTagsToNAND = yflash_WriteChunkWithTagsToNAND;
flashDev.readChunkWithTagsFromNAND = yflash_ReadChunkWithTagsFromNAND;
flashDev.eraseBlockInNAND = yflash_EraseBlockInNAND;
flashDev.initialiseNAND = yflash_InitialiseNAND;
flashDev.markNANDBlockBad = yflash_MarkNANDBlockBad;
flashDev.queryNANDBlock = yflash_QueryNANDBlock;
// /ram2k
// Set this puppy up to use
// the file emulation space as
// 2kpage/64chunk per block/128MB device
memset(&ram2kDev,0,sizeof(ram2kDev));
ram2kDev.nDataBytesPerChunk = nandemul2k_GetBytesPerChunk();
ram2kDev.nChunksPerBlock = nandemul2k_GetChunksPerBlock();
ram2kDev.nReservedBlocks = 5;
ram2kDev.startBlock = 0; // First block after /boot
//ram2kDev.endBlock = 127; // Last block in 16MB
ram2kDev.endBlock = nandemul2k_GetNumberOfBlocks() - 1; // Last block in 512MB
ram2kDev.isYaffs2 = 1;
ram2kDev.nShortOpCaches = 10; // Use caches
ram2kDev.genericDevice = (void *) 3; // Used to identify the device in fstat.
ram2kDev.writeChunkWithTagsToNAND = nandemul2k_WriteChunkWithTagsToNAND;
ram2kDev.readChunkWithTagsFromNAND = nandemul2k_ReadChunkWithTagsFromNAND;
ram2kDev.eraseBlockInNAND = nandemul2k_EraseBlockInNAND;
ram2kDev.initialiseNAND = nandemul2k_InitialiseNAND;
ram2kDev.markNANDBlockBad = nandemul2k_MarkNANDBlockBad;
ram2kDev.queryNANDBlock = nandemul2k_QueryNANDBlock;
yaffs_initialise(yaffsfs_config);
return 0;
}
void SetCheckpointReservedBlocks(int n)
{
flashDev.nCheckpointReservedBlocks = n;
}

1505
fs/yaffs2/direct/yaffsfs.c Normal file

File diff suppressed because it is too large Load diff

233
fs/yaffs2/direct/yaffsfs.h Normal file
View file

@ -0,0 +1,233 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* Header file for using yaffs in an application via
* a direct interface.
*/
#ifndef __YAFFSFS_H__
#define __YAFFSFS_H__
#include "yaffscfg.h"
#include "yportenv.h"
//typedef long off_t;
//typedef long dev_t;
//typedef unsigned long mode_t;
#ifndef NAME_MAX
#define NAME_MAX 256
#endif
#ifndef O_RDONLY
#define O_RDONLY 00
#endif
#ifndef O_WRONLY
#define O_WRONLY 01
#endif
#ifndef O_RDWR
#define O_RDWR 02
#endif
#ifndef O_CREAT
#define O_CREAT 0100
#endif
#ifndef O_EXCL
#define O_EXCL 0200
#endif
#ifndef O_TRUNC
#define O_TRUNC 01000
#endif
#ifndef O_APPEND
#define O_APPEND 02000
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
#ifndef EBUSY
#define EBUSY 16
#endif
#ifndef ENODEV
#define ENODEV 19
#endif
#ifndef EINVAL
#define EINVAL 22
#endif
#ifndef EBADF
#define EBADF 9
#endif
#ifndef EACCESS
#define EACCESS 13
#endif
#ifndef EXDEV
#define EXDEV 18
#endif
#ifndef ENOENT
#define ENOENT 2
#endif
#ifndef ENOSPC
#define ENOSPC 28
#endif
#ifndef ENOTEMPTY
#define ENOTEMPTY 39
#endif
#ifndef ENOMEM
#define ENOMEM 12
#endif
#ifndef EEXIST
#define EEXIST 17
#endif
#ifndef ENOTDIR
#define ENOTDIR 20
#endif
#ifndef EISDIR
#define EISDIR 21
#endif
// Mode flags
#ifndef S_IFMT
#define S_IFMT 0170000
#endif
#ifndef S_IFLNK
#define S_IFLNK 0120000
#endif
#ifndef S_IFDIR
#define S_IFDIR 0040000
#endif
#ifndef S_IFREG
#define S_IFREG 0100000
#endif
#ifndef S_IREAD
#define S_IREAD 0000400
#endif
#ifndef S_IWRITE
#define S_IWRITE 0000200
#endif
struct yaffs_dirent{
long d_ino; /* inode number */
off_t d_off; /* offset to this dirent */
unsigned short d_reclen; /* length of this d_name */
char d_name [NAME_MAX+1]; /* file name (null-terminated) */
unsigned d_dont_use; /* debug pointer, not for public consumption */
};
typedef struct yaffs_dirent yaffs_dirent;
typedef struct __opaque yaffs_DIR;
struct yaffs_stat{
int st_dev; /* device */
int st_ino; /* inode */
mode_t st_mode; /* protection */
int st_nlink; /* number of hard links */
int st_uid; /* user ID of owner */
int st_gid; /* group ID of owner */
unsigned st_rdev; /* device type (if inode device) */
off_t st_size; /* total size, in bytes */
unsigned long st_blksize; /* blocksize for filesystem I/O */
unsigned long st_blocks; /* number of blocks allocated */
unsigned long yst_atime; /* time of last access */
unsigned long yst_mtime; /* time of last modification */
unsigned long yst_ctime; /* time of last change */
};
int yaffs_open(const char *path, int oflag, int mode) ;
int yaffs_read(int fd, void *buf, unsigned int nbyte) ;
int yaffs_write(int fd, const void *buf, unsigned int nbyte) ;
int yaffs_close(int fd) ;
off_t yaffs_lseek(int fd, off_t offset, int whence) ;
int yaffs_truncate(int fd, off_t newSize);
int yaffs_unlink(const char *path) ;
int yaffs_rename(const char *oldPath, const char *newPath) ;
int yaffs_stat(const char *path, struct yaffs_stat *buf) ;
int yaffs_lstat(const char *path, struct yaffs_stat *buf) ;
int yaffs_fstat(int fd, struct yaffs_stat *buf) ;
int yaffs_chmod(const char *path, mode_t mode);
int yaffs_fchmod(int fd, mode_t mode);
int yaffs_mkdir(const char *path, mode_t mode) ;
int yaffs_rmdir(const char *path) ;
yaffs_DIR *yaffs_opendir(const char *dirname) ;
struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) ;
void yaffs_rewinddir(yaffs_DIR *dirp) ;
int yaffs_closedir(yaffs_DIR *dirp) ;
int yaffs_mount(const char *path) ;
int yaffs_unmount(const char *path) ;
int yaffs_symlink(const char *oldpath, const char *newpath);
int yaffs_readlink(const char *path, char *buf, int bufsiz);
int yaffs_link(const char *oldpath, const char *newpath);
int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev);
loff_t yaffs_freespace(const char *path);
void yaffs_initialise(yaffsfs_DeviceConfiguration *configList);
int yaffs_StartUp(void);
#endif

View file

@ -0,0 +1,88 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* ydirectenv.h: Environment wrappers for YAFFS direct.
*/
#ifndef __YDIRECTENV_H__
#define __YDIRECTENV_H__
// Direct interface
#include "devextras.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "yaffs_malloc.h"
#include "assert.h"
#define YBUG() assert(1)
#define YCHAR char
#define YUCHAR unsigned char
#define _Y(x) x
#define yaffs_strcpy(a,b) strcpy(a,b)
#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
#define yaffs_strncmp(a,b,c) strncmp(a,b,c)
#define yaffs_strlen(s) strlen(s)
#define yaffs_sprintf sprintf
#define yaffs_toupper(a) toupper(a)
#ifdef NO_Y_INLINE
#define Y_INLINE
#else
#define Y_INLINE inline
#endif
#define YMALLOC(x) yaffs_malloc(x)
#define YFREE(x) free(x)
#define YMALLOC_ALT(x) yaffs_malloc(x)
#define YFREE_ALT(x) free(x)
#define YMALLOC_DMA(x) yaffs_malloc(x)
#define YYIELD() do {} while(0)
//#define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s))
//#define YALERT(s) YINFO(s)
#define TENDSTR "\n"
#define TSTR(x) x
#define TOUT(p) printf p
#define YAFFS_LOSTNFOUND_NAME "lost+found"
#define YAFFS_LOSTNFOUND_PREFIX "obj"
//#define YPRINTF(x) printf x
#include "yaffscfg.h"
#define Y_CURRENT_TIME yaffsfs_CurrentTime()
#define Y_TIME_CONVERT(x) x
#define YAFFS_ROOT_MODE 0666
#define YAFFS_LOSTNFOUND_MODE 0666
#define yaffs_SumCompare(x,y) ((x) == (y))
#define yaffs_strcmp(a,b) strcmp(a,b)
#endif

65
fs/yaffs2/moduleconfig.h Normal file
View file

@ -0,0 +1,65 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Martin Fouts <Martin.Fouts@palmsource.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_CONFIG_H__
#define __YAFFS_CONFIG_H__
#ifdef YAFFS_OUT_OF_TREE
/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */
#define CONFIG_YAFFS_FS
#define CONFIG_YAFFS_YAFFS1
#define CONFIG_YAFFS_YAFFS2
/* These options are independent of each other. Select those that matter. */
/* Default: Not selected */
/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
//#define CONFIG_YAFFS_DOES_ECC
/* Default: Not selected */
/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
/* CONFIG_YAFFS_DOES_ECC is set */
//#define CONFIG_YAFFS_ECC_WRONG_ORDER
/* Default: Selected */
/* Meaning: Disables testing whether chunks are erased before writing to them*/
#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
/* Default: Selected */
/* Meaning: Cache short names, taking more RAM, but faster look-ups */
#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
/* Default: 10 */
/* Meaning: set the count of blocks to reserve for checkpointing */
#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
/*
Older-style on-NAND data format has a "pageStatus" byte to record
chunk/page state. This byte is zeroed when the page is discarded.
Choose this option if you have existing on-NAND data in this format
that you need to continue to support. New data written also uses the
older-style format.
Note: Use of this option generally requires that MTD's oob layout be
adjusted to use the older-style format. See notes on tags formats and
MTD versions in yaffs_mtdif1.c.
*/
/* Default: Not selected */
/* Meaning: Use older-style on-NAND data format with pageStatus byte */
//#define CONFIG_YAFFS_9BYTE_TAGS
#endif /* YAFFS_OUT_OF_TREE */
#endif /* __YAFFS_CONFIG_H__ */

View file

@ -0,0 +1,33 @@
#Makefile for NANDemul MTD
#
# NB this is not yet suitable for putting into the kernel tree.
# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
#
# Copyright (C) 2002 Aleph One Ltd.
# for Toby Churchill Ltd and Brightstar Engineering
#
# Created by Charles Manning <charles@aleph1.co.uk>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
## Change or override KERNELDIR to your kernel
## comment out USE_xxxx if you don't want these features.
KERNELDIR = /usr/src/kernel-headers-2.4.27
CFLAGS = -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -O2 -Wall -g
TARGET = nandemul2k.o
default: $(TARGET)
clean:
rm -f $(TARGET)
$(TARGET): %.o: %.c
gcc -c $(CFLAGS) $< -o $@

View file

@ -0,0 +1,714 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This version hacked for emulating 2kpage NAND for YAFFS2 testing.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
#include <linux/string.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
#include <linux/locks.h>
#endif
#include <asm/uaccess.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include "../yaffs_nandemul2k.h"
#define ALLOCATE(x) kmalloc(x,GFP_KERNEL)
#define FREE(x) kfree(x)
#define NAND_SHIFT (11) // Shifter for 2k
#define PAGE_DATA_SIZE (1 << NAND_SHIFT)
#define PAGE_SPARE_SIZE (64)
#define BLK_SHIFT 6
#define PAGES_PER_BLOCK (1 << BLK_SHIFT) // = 64
#define EM_SIZE_IN_MEG 4
#define EM_SIZE_IN_BYTES (EM_SIZE_IN_MEG * (1<<20))
#define PAGE_TOTAL_SIZE (PAGE_DATA_SIZE+PAGE_SPARE_SIZE)
#define BLOCK_TOTAL_SIZE (PAGES_PER_BLOCK * PAGE_TOTAL_SIZE)
#define BLOCKS_PER_MEG ((1<<20)/(PAGES_PER_BLOCK * PAGE_DATA_SIZE))
static struct mtd_info nandemul2k_mtd;
typedef struct
{
__u8 data[PAGE_TOTAL_SIZE]; // Data + spare
int empty; // is this empty?
} nandemul_Page;
typedef struct
{
nandemul_Page *page[PAGES_PER_BLOCK];
int damaged;
} nandemul_Block;
typedef struct
{
nandemul_Block**block;
int nBlocks;
} nandemul_Device;
static nandemul_Device ned;
static int sizeInMB = EM_SIZE_IN_MEG;
static void nandemul_yield(int n)
{
#ifdef __KERNEL__
if(n > 0) schedule_timeout(n);
#endif
}
static void nandemul2k_Read(void *buffer, int page, int start, int nBytes)
{
int pg = page%PAGES_PER_BLOCK;
int blk = page/PAGES_PER_BLOCK;
if(buffer && nBytes > 0)
{
memcpy(buffer,&ned.block[blk]->page[pg]->data[start],nBytes);
}
}
static void nandemul2k_Program(const void *buffer, int page, int start, int nBytes)
{
int pg = page%PAGES_PER_BLOCK;
int blk = page/PAGES_PER_BLOCK;
__u8 *p;
__u8 *b = (__u8 *)buffer;
p = &ned.block[blk]->page[pg]->data[start];
while(buffer && nBytes>0)
{
*p = *p & *b;
p++;
b++;
nBytes--;
}
}
static void nandemul2k_DoErase(int blockNumber)
{
int i;
nandemul_Block *blk;
if(blockNumber < 0 || blockNumber >= ned.nBlocks)
{
return;
}
blk = ned.block[blockNumber];
for(i = 0; i < PAGES_PER_BLOCK; i++)
{
memset(blk->page[i],0xff,sizeof(nandemul_Page));
blk->page[i]->empty = 1;
}
nandemul_yield(2);
}
static int nandemul2k_CalcNBlocks(void)
{
return EM_SIZE_IN_MEG * BLOCKS_PER_MEG;
}
static int CheckInit(void)
{
static int initialised = 0;
int i,j;
int fail = 0;
int nBlocks;
int nAllocated = 0;
if(initialised)
{
return 0;
}
ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks();
ned.block = ALLOCATE(sizeof(nandemul_Block*) * nBlocks );
if(!ned.block) return ENOMEM;
for(i=fail=0; i <nBlocks; i++)
{
nandemul_Block *blk;
if(!(blk = ned.block[i] = ALLOCATE(sizeof(nandemul_Block))))
{
fail = 1;
}
else
{
for(j = 0; j < PAGES_PER_BLOCK; j++)
{
if((blk->page[j] = ALLOCATE(sizeof(nandemul_Page))) == 0)
{
fail = 1;
}
}
nandemul2k_DoErase(i);
ned.block[i]->damaged = 0;
nAllocated++;
}
}
if(fail)
{
//Todo thump pages
for(i = 0; i < nAllocated; i++)
{
FREE(ned.block[i]);
}
FREE(ned.block);
return ENOMEM;
}
ned.nBlocks = nBlocks;
initialised = 1;
return 1;
}
static void nandemul2k_CleanUp(void)
{
int i,j;
for(i = 0; i < ned.nBlocks; i++)
{
for(j = 0; j < PAGES_PER_BLOCK; j++)
{
FREE(ned.block[i]->page[j]);
}
FREE(ned.block[i]);
}
FREE(ned.block);
ned.block = 0;
}
int nandemul2k_GetBytesPerChunk(void) { return PAGE_DATA_SIZE;}
int nandemul2k_GetChunksPerBlock(void) { return PAGES_PER_BLOCK; }
int nandemul2k_GetNumberOfBlocks(void) {return nandemul2k_CalcNBlocks();}
static int nandemul2k_ReadId(__u8 *vendorId, __u8 *deviceId)
{
*vendorId = 'Y';
*deviceId = '2';
return 1;
}
static int nandemul2k_ReadStatus(__u8 *status)
{
*status = 0;
return 1;
}
#ifdef CONFIG_MTD_NAND_ECC
#include <linux/mtd/nand_ecc.h>
#endif
/*
* NAND low-level MTD interface functions
*/
static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *dummy);
static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf);
static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf,
u_char *oob_buf, struct nand_oobinfo *dummy);
static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7))
static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen);
#else
static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
unsigned long count, loff_t to, size_t *retlen);
#endif
static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
static void nand_sync (struct mtd_info *mtd);
/*
* NAND read
*/
static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
return nand_read_ecc (mtd, from, len, retlen, buf, NULL,NULL);
}
/*
* NAND read with ECC
*/
static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *oob_buf,struct nand_oobinfo *oobsel)
{
int start, page;
int n = len;
int nToCopy;
/* Do not allow reads past end of device */
if ((from + len) > mtd->size) {
*retlen = 0;
return -EINVAL;
}
/* Initialize return value */
*retlen = 0;
while(n > 0)
{
/* First we calculate the starting page */
page = from >> NAND_SHIFT;
/* Get raw starting column */
start = from & (mtd->oobblock-1);
// OK now check for the curveball where the start and end are in
// the same page
if((start + n) < mtd->oobblock)
{
nToCopy = n;
}
else
{
nToCopy = mtd->oobblock - start;
}
nandemul2k_Read(buf, page, start, nToCopy);
nandemul2k_Read(oob_buf,page,PAGE_DATA_SIZE,PAGE_SPARE_SIZE);
n -= nToCopy;
from += nToCopy;
buf += nToCopy;
if(oob_buf) oob_buf += PAGE_SPARE_SIZE;
*retlen += nToCopy;
}
return 0;
}
/*
* NAND read out-of-band
*/
static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
int col, page;
T(0,("nand_read_oob: from = 0x%08x, buf = 0x%08x, len = %i\n", (unsigned int) from, (unsigned int) buf,
(int) len));
/* Shift to get page */
page = ((int) from) >> NAND_SHIFT;
/* Mask to get column */
col = from & 0x0f;
/* Initialize return length value */
*retlen = 0;
/* Do not allow reads past end of device */
if ((from + len) > mtd->size) {
T(0,
("nand_read_oob: Attempt read beyond end of device\n"));
*retlen = 0;
return -EINVAL;
}
nandemul2k_Read(buf,page,PAGE_DATA_SIZE + col,len);
/* Return happy */
*retlen = len;
return 0;
}
/*
* NAND write
*/
static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
return nand_write_ecc (mtd, to, len, retlen, buf, NULL,NULL);
}
/*
* NAND write with ECC
*/
static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf,
u_char *oob_buf, struct nand_oobinfo *dummy)
{
int start, page;
int n = len;
int nToCopy;
/* Do not allow reads past end of device */
if ((to + len) > mtd->size) {
*retlen = 0;
return -EINVAL;
}
/* Initialize return value */
*retlen = 0;
while(n > 0)
{
/* First we calculate the starting page */
page = to >> NAND_SHIFT;
/* Get raw starting column */
start = to & (mtd->oobblock - 1);
// OK now check for the curveball where the start and end are in
// the same page
if((start + n) < mtd->oobblock)
{
nToCopy = n;
}
else
{
nToCopy = mtd->oobblock - start;
}
nandemul2k_Program(buf, page, start, nToCopy);
nandemul2k_Program(oob_buf, page, PAGE_DATA_SIZE, PAGE_SPARE_SIZE);
n -= nToCopy;
to += nToCopy;
buf += nToCopy;
if(oob_buf) oob_buf += PAGE_SPARE_SIZE;
*retlen += nToCopy;
}
return 0;
}
/*
* NAND write out-of-band
*/
static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
int col, page;
T(0,(
"nand_read_oob: to = 0x%08x, len = %i\n", (unsigned int) to,
(int) len));
/* Shift to get page */
page = ((int) to) >> NAND_SHIFT;
/* Mask to get column */
col = to & 0x0f;
/* Initialize return length value */
*retlen = 0;
/* Do not allow reads past end of device */
if ((to + len) > mtd->size) {
T(0,(
"nand_read_oob: Attempt read beyond end of device\n"));
*retlen = 0;
return -EINVAL;
}
nandemul2k_Program(buf,page,512 + col,len);
/* Return happy */
*retlen = len;
return 0;
}
/*
* NAND write with iovec
*/
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7))
static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen)
#else
static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
unsigned long count, loff_t to, size_t *retlen)
#endif
{
return -EINVAL;
}
/*
* NAND erase a block
*/
static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
{
int i, nBlocks,block;
T(0,(
"nand_erase: start = 0x%08x, len = %i\n",
(unsigned int) instr->addr, (unsigned int) instr->len));
/* Start address must align on block boundary */
if (instr->addr & (mtd->erasesize - 1)) {
T(0,(
"nand_erase: Unaligned address\n"));
return -EINVAL;
}
/* Length must align on block boundary */
if (instr->len & (mtd->erasesize - 1)) {
T(0,(
"nand_erase: Length not block aligned\n"));
return -EINVAL;
}
/* Do not allow erase past end of device */
if ((instr->len + instr->addr) > mtd->size) {
T(0,(
"nand_erase: Erase past end of device\n"));
return -EINVAL;
}
nBlocks = instr->len >> (NAND_SHIFT + BLK_SHIFT);
block = instr->addr >> (NAND_SHIFT + BLK_SHIFT);
for(i = 0; i < nBlocks; i++)
{
nandemul2k_DoErase(block);
block++;
}
instr->state = MTD_ERASE_DONE;  * change state to ERASE_DONE */
instr->callback(instr);  * wake up */
return 0;
}
static int nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
{
return 0;
}
static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
return 0;
}
/*
* NAND sync
*/
static void nand_sync (struct mtd_info *mtd)
{
T(0,("nand_sync: called\n"));
}
/*
* Scan for the NAND device
*/
static int nandemul2k_scan (struct mtd_info *mtd,int nchips)
{
mtd->oobblock = PAGE_DATA_SIZE;
mtd->oobsize = PAGE_SPARE_SIZE;
mtd->erasesize = PAGE_DATA_SIZE * PAGES_PER_BLOCK;
mtd->size = sizeInMB * 1024*1024;
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->owner = THIS_MODULE;
mtd->ecctype = MTD_ECC_NONE;
mtd->erase = nand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
mtd->read = nand_read;
mtd->write = nand_write;
mtd->read_ecc = nand_read_ecc;
mtd->write_ecc = nand_write_ecc;
mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob;
mtd->block_isbad = nand_block_isbad;
mtd->block_markbad = nand_block_markbad;
mtd->readv = NULL;
mtd->writev = nand_writev;
mtd->sync = nand_sync;
mtd->lock = NULL;
mtd->unlock = NULL;
mtd->suspend = NULL;
mtd->resume = NULL;
mtd->name = "NANDemul2k";
/* Return happy */
return 0;
}
#if 0
#ifdef MODULE
MODULE_PARM(sizeInMB, "i");
__setup("sizeInMB=",sizeInMB);
#endif
#endif
/*
* Define partitions for flash devices
*/
static struct mtd_partition nandemul2k_partition[] =
{
{ .name = "NANDemul partition 1",
.offset = 0,
.size = 0 },
};
static int nPartitions = sizeof(nandemul2k_partition)/sizeof(nandemul2k_partition[0]);
/*
* Main initialization routine
*/
int __init nandemul2k_init (void)
{
// Do the nand init
CheckInit();
nandemul2k_scan(&nandemul2k_mtd,1);
// Build the partition table
nandemul2k_partition[0].size = sizeInMB * 1024 * 1024;
// Register the partition
add_mtd_partitions(&nandemul2k_mtd,nandemul2k_partition,nPartitions);
return 0;
}
module_init(nandemul2k_init);
/*
* Clean up routine
*/
#ifdef MODULE
static void __exit nandemul2k_cleanup (void)
{
nandemul2k_CleanUp();
/* Unregister partitions */
del_mtd_partitions(&nandemul2k_mtd);
/* Unregister the device */
del_mtd_device (&nandemul2k_mtd);
}
module_exit(nandemul2k_cleanup);
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Charles Manning <manningc@aleph1.co.uk>");
MODULE_DESCRIPTION("2k Page/128k Block NAND emulated in RAM");

121
fs/yaffs2/patch-ker.sh Executable file
View file

@ -0,0 +1,121 @@
#!/bin/sh
#
# YAFFS: Yet another FFS. A NAND-flash specific file system.
#
# Copyright (C) 2002-2006 Aleph One Ltd.
#
# Created by Charles Manning <charles@aleph1.co.uk>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# Patch YAFFS into the kernel
#
# args: kpath : Full path to kernel sources to be patched
#
# Somewhat "inspired by" the mtd patchin script
#
# $Id: patch-ker.sh,v 1.3 2007/07/25 01:04:38 charles Exp $
VERSION=0
PATCHLEVEL=0
SUBLEVEL=0
COPYORLINK=$1
LINUXDIR=$2
# To be a Linux directory, it must have a Makefile
# Display usage of this script
usage () {
echo "usage: $0 c/l kernelpath"
echo " if c/l is c, then copy. If l then link"
exit 1
}
if [ -z $LINUXDIR ]
then
usage;
fi
if [ $COPYORLINK = l ]; then
CPY="ln -s"
elif [ $COPYORLINK = c ]; then
CPY="cp"
else
echo "unknown copy or link type"
usage;
fi
# Check if kerneldir contains a Makefile
if [ ! -f $LINUXDIR/Makefile ]
then
echo "Directory $LINUXDIR does not exist or is not a kernel source directory";
exit 1;
fi
# Get kernel version
VERSION=`grep -s VERSION <$LINUXDIR/Makefile | head -n 1 | sed s/'VERSION = '//`
PATCHLEVEL=`grep -s PATCHLEVEL <$LINUXDIR/Makefile | head -n 1 | sed s/'PATCHLEVEL = '//`
SUBLEVEL=`grep -s SUBLEVEL <$LINUXDIR/Makefile | head -n 1 | sed s/'SUBLEVEL = '//`
# Can we handle this version?
if [ $VERSION -ne 2 -o $PATCHLEVEL -lt 6 ]
then
echo "Cannot patch kernel version $VERSION.$PATCHLEVEL.$SUBLEVEL, must be 2.6.x or higher"
exit 1;
fi
KCONFIG=$LINUXDIR/fs/Kconfig
KCONFIGOLD=$LINUXDIR/fs/Kconfig.pre.yaffs
YAFFS_PATCHED_STRING=`grep -s yaffs <$KCONFIG | head -n 1`
MAKEFILE=$LINUXDIR/fs/Makefile
MAKEFILEOLD=$LINUXDIR/fs/Makefile.pre.yaffs
if [ ! -z "$YAFFS_PATCHED_STRING" ]
then
YAFFS_PATCHED=0
echo "$KCONFIG already mentions YAFFS, so we will not change it"
else
# Change the fs/Kconfig file
# Save the old Kconfig
# Copy all stuff up to JFFS
# Insert some YAFFS stuff
# Copy all the rest of the stuff
YAFFS_PATCHED=1
echo "Updating $KCONFIG"
mv -f $KCONFIG $KCONFIGOLD
sed -n -e "/JFFS/,99999 ! p" $KCONFIGOLD >$KCONFIG
echo "">>$KCONFIG
echo "# Patched by YAFFS" >>$KCONFIG
echo "source \"fs/yaffs2/Kconfig\"">>$KCONFIG
echo "">>$KCONFIG
sed -n -e "/JFFS/,99999 p" $KCONFIGOLD >>$KCONFIG
# now do fs/Makefile -- simply add the target at the end
echo "Updating $MAKEFILE"
cp -f $MAKEFILE $MAKEFILEOLD
echo "">>$MAKEFILE
echo "# Patched by YAFFS" >>$MAKEFILE
echo "obj-\$(CONFIG_YAFFS_FS) += yaffs2/" >>$MAKEFILE
fi
YAFFSDIR=$LINUXDIR/fs/yaffs2
if [ -e $YAFFSDIR ]
then
echo "$YAFFSDIR exists, not patching"
else
mkdir $LINUXDIR/fs/yaffs2
$CPY $PWD/Makefile.kernel $LINUXDIR/fs/yaffs2/Makefile
$CPY $PWD/Kconfig $LINUXDIR/fs/yaffs2
$CPY $PWD/*.c $PWD/*.h $LINUXDIR/fs/yaffs2
fi

View file

@ -0,0 +1,6 @@
This directory holds patches that are useful for Linux integration.
Right now there is only one patched file, yaffs_mtdif2.c. This has been
patched with a tweaked version of "Sergey's patch" and typically makes a
stock mtd work properly.

View file

@ -0,0 +1,258 @@
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
*
* Copyright (C) 2002 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* mtd interface for YAFFS2 */
const char *yaffs_mtdif2_c_version =
"$Id: yaffs_mtdif2.c,v 1.2 2007/03/07 08:05:58 colin 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"
void nandmtd2_pt2buf(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
__u8 *ptab = (__u8 *)pt; /* packed tags as bytes */
int i, j = 0, k, n;
/* Pack buffer with 0xff */
for (i = 0; i < mtd->oobsize; i++)
dev->spareBuffer[i] = 0xff;
if(!is_raw){
memcpy(dev->spareBuffer,pt,sizeof(yaffs_PackedTags2));
} else {
j = 0;
k = mtd->oobinfo.oobfree[j][0];
n = mtd->oobinfo.oobfree[j][1];
if (n == 0) {
T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR)));
YBUG();
}
for (i = 0; i < sizeof(yaffs_PackedTags2); i++) {
if (n == 0) {
j++;
k = mtd->oobinfo.oobfree[j][0];
n = mtd->oobinfo.oobfree[j][1];
if (n == 0) {
T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR)));
YBUG();
}
}
dev->spareBuffer[k] = ptab[i];
k++;
n--;
}
}
}
void nandmtd2_buf2pt(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
int i, j = 0, k, n;
__u8 *ptab = (__u8 *)pt; /* packed tags as bytes */
if (!is_raw) {
memcpy(pt,dev->spareBuffer,sizeof(yaffs_PackedTags2));
} else {
j = 0;
k = mtd->oobinfo.oobfree[j][0];
n = mtd->oobinfo.oobfree[j][1];
if (n == 0) {
T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR)));
YBUG();
}
for (i = 0; i < sizeof(yaffs_PackedTags2); i++) {
if (n == 0) {
j++;
k = mtd->oobinfo.oobfree[j][0];
n = mtd->oobinfo.oobfree[j][1];
if (n == 0) {
T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR)));
YBUG();
}
}
ptab[i] = dev->spareBuffer[k];
k++;
n--;
}
}
}
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags * tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
yaffs_PackedTags2 pt;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
if (tags) {
yaffs_PackTags2(&pt, tags);
}
if (data && tags) {
nandmtd2_pt2buf(dev, &pt, 0);
retval =
mtd->write_ecc(mtd, addr, dev->nBytesPerChunk,
&dummy, data, dev->spareBuffer,
NULL);
} else {
T(YAFFS_TRACE_ALWAYS,
(TSTR
("Write chunk with null tags or data!" TENDSTR)));
YBUG();
}
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
yaffs_PackedTags2 pt;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_ReadChunkWithTagsToNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
if (0 && data && tags) {
retval =
mtd->read_ecc(mtd, addr, dev->nBytesPerChunk,
&dummy, data, dev->spareBuffer,
NULL);
nandmtd2_buf2pt(dev, &pt, 0);
} else {
if (data)
retval =
mtd->read(mtd, addr, dev->nBytesPerChunk, &dummy,
data);
if (tags) {
retval =
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
dev->spareBuffer);
nandmtd2_buf2pt(dev, &pt, 1);
}
}
if (tags)
yaffs_UnpackTags2(tags, &pt);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
retval =
mtd->block_markbad(mtd,
blockNo * dev->nChunksPerBlock *
dev->nBytesPerChunk);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
retval =
mtd->block_isbad(mtd,
blockNo * dev->nChunksPerBlock *
dev->nBytesPerChunk);
if (retval) {
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
*state = YAFFS_BLOCK_STATE_DEAD;
*sequenceNumber = 0;
} else {
yaffs_ExtendedTags t;
nandmtd2_ReadChunkWithTagsFromNAND(dev,
blockNo *
dev->nChunksPerBlock, NULL,
&t);
if (t.chunkUsed) {
*sequenceNumber = t.sequenceNumber;
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
} else {
*sequenceNumber = 0;
*state = YAFFS_BLOCK_STATE_EMPTY;
}
T(YAFFS_TRACE_MTD,
(TSTR("block is OK seq %d state %d" TENDSTR), *sequenceNumber,
*state));
}
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}

54
fs/yaffs2/utils/Makefile Normal file
View file

@ -0,0 +1,54 @@
#Makefile for mkyaffs
#
# NB this is not yet suitable for putting into the kernel tree.
# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
#
# Copyright (C) 2002 Aleph One Ltd.
# for Toby Churchill Ltd and Brightstar Engineering
#
# Created by Charles Manning <charles@aleph1.co.uk>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
## Change or override KERNELDIR to your kernel
#KERNELDIR = /usr/src/kernel-headers-2.4.18
CFLAGS = -I/usr/include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL
CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations
CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline
## Change if you are using a cross-compiler
MAKETOOLS =
CC=$(MAKETOOLS)gcc
COMMONLINKS = yaffs_ecc.c
COMMONOBJS = $(COMMONLINKS:.c=.o)
MKYAFFSSOURCES = mkyaffsimage.c
MKYAFFSIMAGEOBJS = $(MKYAFFSSOURCES:.c=.o)
MKYAFFS2SOURCES = mkyaffs2image.c
MKYAFFS2LINKS = yaffs_packedtags2.c yaffs_tagsvalidity.c
MKYAFFS2IMAGEOBJS = $(MKYAFFS2SOURCES:.c=.o) $(MKYAFFS2LINKS:.c=.o)
all: mkyaffsimage mkyaffs2image
$(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS):
ln -s ../$@ $@
$(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) : %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
mkyaffsimage: $(COMMONOBJS) $(MKYAFFSIMAGEOBJS)
$(CC) -o $@ $(COMMONOBJS) $(MKYAFFSIMAGEOBJS)
mkyaffs2image: $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS)
$(CC) -o $@ $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS)
clean:
rm -f $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) $(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS) mkyaffsimage mkyaffs2image core

View file

@ -0,0 +1,520 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
* Nick Bane modifications flagged NCB
* Endian handling patches by James Ng.
* mkyaffs2image hacks by NCB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* makeyaffs2image.c
*
* Makes a YAFFS2 file system image that can be used to load up a file system.
* Uses default Linux MTD layout - change if you need something different.
*/
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include "yaffs_ecc.h"
#include "yaffs_guts.h"
#include "yaffs_tagsvalidity.h"
#include "yaffs_packedtags2.h"
unsigned yaffs_traceMask=0;
#define MAX_OBJECTS 10000
#define chunkSize 2048
#define spareSize 64
const char * mkyaffsimage_c_version = "$Id: mkyaffs2image.c,v 1.4 2007/02/14 01:09:06 wookey 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;
}
/* This little function converts a little endian tag to a big endian tag.
* NOTE: The tag is not usable after this other than calculating the CRC
* with.
*/
static void little_to_big_endian(yaffs_Tags *tagsPtr)
{
#if 0 // FIXME NCB
yaffs_TagsUnion * tags = (yaffs_TagsUnion* )tagsPtr; // Work in bytes.
yaffs_TagsUnion temp;
memset(&temp, 0, sizeof(temp));
// Ick, I hate magic numbers.
temp.asBytes[0] = ((tags->asBytes[2] & 0x0F) << 4) | ((tags->asBytes[1] & 0xF0) >> 4);
temp.asBytes[1] = ((tags->asBytes[1] & 0x0F) << 4) | ((tags->asBytes[0] & 0xF0) >> 4);
temp.asBytes[2] = ((tags->asBytes[0] & 0x0F) << 4) | ((tags->asBytes[2] & 0x30) >> 2) | ((tags->asBytes[3] & 0xC0) >> 6);
temp.asBytes[3] = ((tags->asBytes[3] & 0x3F) << 2) | ((tags->asBytes[2] & 0xC0) >> 6);
temp.asBytes[4] = ((tags->asBytes[6] & 0x03) << 6) | ((tags->asBytes[5] & 0xFC) >> 2);
temp.asBytes[5] = ((tags->asBytes[5] & 0x03) << 6) | ((tags->asBytes[4] & 0xFC) >> 2);
temp.asBytes[6] = ((tags->asBytes[4] & 0x03) << 6) | (tags->asBytes[7] & 0x3F);
temp.asBytes[7] = (tags->asBytes[6] & 0xFC) | ((tags->asBytes[7] & 0xC0) >> 6);
// Now copy it back.
tags->asBytes[0] = temp.asBytes[0];
tags->asBytes[1] = temp.asBytes[1];
tags->asBytes[2] = temp.asBytes[2];
tags->asBytes[3] = temp.asBytes[3];
tags->asBytes[4] = temp.asBytes[4];
tags->asBytes[5] = temp.asBytes[5];
tags->asBytes[6] = temp.asBytes[6];
tags->asBytes[7] = temp.asBytes[7];
#endif
}
static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
{
yaffs_ExtendedTags t;
yaffs_PackedTags2 pt;
error = write(outFile,data,chunkSize);
if(error < 0) return error;
yaffs_InitialiseTags(&t);
t.chunkId = chunkId;
// t.serialNumber = 0;
t.serialNumber = 1; // **CHECK**
t.byteCount = nBytes;
t.objectId = objId;
t.sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
// added NCB **CHECK**
t.chunkUsed = 1;
if (convert_endian)
{
little_to_big_endian(&t);
}
nPages++;
yaffs_PackTags2(&pt,&t);
// return write(outFile,&pt,sizeof(yaffs_PackedTags2));
return write(outFile,&pt,spareSize);
}
#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \
(((x) & 0x0000FF00) << 8 ) | \
(((x) & 0x00FF0000) >> 8 ) | \
(((x) & 0xFF000000) >> 24))
#define SWAP16(x) ((((x) & 0x00FF) << 8) | \
(((x) & 0xFF00) >> 8))
// This one is easier, since the types are more standard. No funky shifts here.
static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh)
{
oh->type = SWAP32(oh->type); // GCC makes enums 32 bits.
oh->parentObjectId = SWAP32(oh->parentObjectId); // int
oh->sum__NoLongerUsed = SWAP16(oh->sum__NoLongerUsed); // __u16 - Not used, but done for completeness.
// name = skip. Char array. Not swapped.
oh->yst_mode = SWAP32(oh->yst_mode);
#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case.
// In fact, WinCE would be *THE* place where this would be an issue!
oh->notForWinCE[0] = SWAP32(oh->notForWinCE[0]);
oh->notForWinCE[1] = SWAP32(oh->notForWinCE[1]);
oh->notForWinCE[2] = SWAP32(oh->notForWinCE[2]);
oh->notForWinCE[3] = SWAP32(oh->notForWinCE[3]);
oh->notForWinCE[4] = SWAP32(oh->notForWinCE[4]);
#else
// Regular POSIX.
oh->yst_uid = SWAP32(oh->yst_uid);
oh->yst_gid = SWAP32(oh->yst_gid);
oh->yst_atime = SWAP32(oh->yst_atime);
oh->yst_mtime = SWAP32(oh->yst_mtime);
oh->yst_ctime = SWAP32(oh->yst_ctime);
#endif
oh->fileSize = SWAP32(oh->fileSize); // Aiee. An int... signed, at that!
oh->equivalentObjectId = SWAP32(oh->equivalentObjectId);
// alias - char array.
oh->yst_rdev = SWAP32(oh->yst_rdev);
#ifdef CONFIG_YAFFS_WINCE
oh->win_ctime[0] = SWAP32(oh->win_ctime[0]);
oh->win_ctime[1] = SWAP32(oh->win_ctime[1]);
oh->win_atime[0] = SWAP32(oh->win_atime[0]);
oh->win_atime[1] = SWAP32(oh->win_atime[1]);
oh->win_mtime[0] = SWAP32(oh->win_mtime[0]);
oh->win_mtime[1] = SWAP32(oh->win_mtime[1]);
oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]);
oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]);
oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]);
oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]);
oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]);
oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]);
#else
oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]);
oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]);
oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]);
oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]);
oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]);
oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]);
oh->roomToGrow[6] = SWAP32(oh->roomToGrow[6]);
oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]);
oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]);
oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]);
oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]);
oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]);
#endif
}
static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias)
{
__u8 bytes[chunkSize];
yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes;
memset(bytes,0xff,sizeof(bytes));
oh->type = t;
oh->parentObjectId = parent;
strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
if(t != YAFFS_OBJECT_TYPE_HARDLINK)
{
oh->yst_mode = s->st_mode;
oh->yst_uid = s->st_uid;
// NCB 12/9/02 oh->yst_gid = s->yst_uid;
oh->yst_gid = s->st_gid;
oh->yst_atime = s->st_atime;
oh->yst_mtime = s->st_mtime;
oh->yst_ctime = s->st_ctime;
oh->yst_rdev = s->st_rdev;
}
if(t == YAFFS_OBJECT_TYPE_FILE)
{
oh->fileSize = s->st_size;
}
if(t == YAFFS_OBJECT_TYPE_HARDLINK)
{
oh->equivalentObjectId = equivalentObj;
}
if(t == YAFFS_OBJECT_TYPE_SYMLINK)
{
strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH);
}
if (convert_endian)
{
object_header_little_to_big_endian(oh);
}
return write_chunk(bytes,objId,0,0xffff);
}
static int process_directory(int parent, const char *path)
{
DIR *dir;
struct dirent *entry;
nDirectories++;
dir = opendir(path);
if(dir)
{
while((entry = readdir(dir)) != NULL)
{
/* Ignore . and .. */
if(strcmp(entry->d_name,".") &&
strcmp(entry->d_name,".."))
{
char full_name[500];
struct stat stats;
int equivalentObj;
int newObj;
sprintf(full_name,"%s/%s",path,entry->d_name);
lstat(full_name,&stats);
if(S_ISLNK(stats.st_mode) ||
S_ISREG(stats.st_mode) ||
S_ISDIR(stats.st_mode) ||
S_ISFIFO(stats.st_mode) ||
S_ISBLK(stats.st_mode) ||
S_ISCHR(stats.st_mode) ||
S_ISSOCK(stats.st_mode))
{
newObj = obj_id++;
nObjects++;
printf("Object %d, %s is a ",newObj,full_name);
/* We're going to create an object for it */
if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0)
{
/* we need to make a hard link */
printf("hard link to object %d\n",equivalentObj);
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL);
}
else
{
add_obj_to_list(stats.st_dev,stats.st_ino,newObj);
if(S_ISLNK(stats.st_mode))
{
char symname[500];
memset(symname,0, sizeof(symname));
readlink(full_name,symname,sizeof(symname) -1);
printf("symlink to \"%s\"\n",symname);
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname);
}
else if(S_ISREG(stats.st_mode))
{
printf("file, ");
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL);
if(error >= 0)
{
int h;
__u8 bytes[chunkSize];
int nBytes;
int chunk = 0;
h = open(full_name,O_RDONLY);
if(h >= 0)
{
memset(bytes,0xff,sizeof(bytes));
while((nBytes = read(h,bytes,sizeof(bytes))) > 0)
{
chunk++;
write_chunk(bytes,newObj,chunk,nBytes);
memset(bytes,0xff,sizeof(bytes));
}
if(nBytes < 0)
error = nBytes;
printf("%d data chunks written\n",chunk);
}
else
{
perror("Error opening file");
}
close(h);
}
}
else if(S_ISSOCK(stats.st_mode))
{
printf("socket\n");
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
}
else if(S_ISFIFO(stats.st_mode))
{
printf("fifo\n");
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
}
else if(S_ISCHR(stats.st_mode))
{
printf("character device\n");
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
}
else if(S_ISBLK(stats.st_mode))
{
printf("block device\n");
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
}
else if(S_ISDIR(stats.st_mode))
{
printf("directory\n");
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL);
// NCB modified 10/9/2001 process_directory(1,full_name);
process_directory(newObj,full_name);
}
}
}
else
{
printf(" we don't handle this type\n");
}
}
}
}
return 0;
}
int main(int argc, char *argv[])
{
struct stat stats;
printf("mkyaffs2image: image building tool for YAFFS2 built "__DATE__"\n");
if(argc < 3)
{
printf("usage: mkyaffs2image dir image_file [convert]\n");
printf(" dir the directory tree to be converted\n");
printf(" image_file the output file to hold the image\n");
printf(" 'convert' produce a big-endian image from a little-endian machine\n");
exit(1);
}
if ((argc == 4) && (!strncmp(argv[3], "convert", strlen("convert"))))
{
convert_endian = 1;
}
if(stat(argv[1],&stats) < 0)
{
printf("Could not stat %s\n",argv[1]);
exit(1);
}
if(!S_ISDIR(stats.st_mode))
{
printf(" %s is not a directory\n",argv[1]);
exit(1);
}
outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE);
if(outFile < 0)
{
printf("Could not open output file %s\n",argv[2]);
exit(1);
}
printf("Processing directory %s into image file %s\n",argv[1],argv[2]);
error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL);
if(error)
error = process_directory(YAFFS_OBJECTID_ROOT,argv[1]);
close(outFile);
if(error < 0)
{
perror("operation incomplete");
exit(1);
}
else
{
printf("Operation complete.\n"
"%d objects in %d directories\n"
"%d NAND pages\n",nObjects, nDirectories, nPages);
}
close(outFile);
exit(0);
}

View file

@ -0,0 +1,590 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
* Nick Bane modifications flagged NCB
* Endian handling patches by James Ng
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* makeyaffsimage.c
*
* Makes a YAFFS file system image that can be used to load up a file system.
*/
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include "yaffs_ecc.h"
#include "yaffs_guts.h"
#define MAX_OBJECTS 10000
const char * mkyaffsimage_c_version = "$Id: mkyaffsimage.c,v 1.7 2003/07/16 03:00:48 charles 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);
}

404
fs/yaffs2/yaffs_checkptrw.c Normal file
View file

@ -0,0 +1,404 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
const char *yaffs_checkptrw_c_version =
"$Id: yaffs_checkptrw.c,v 1.14 2007/05/15 20:07:40 charles Exp $";
#include "yaffs_checkptrw.h"
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
{
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)
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){
T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){
bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
dev->nErasedBlocks++;
dev->nFreeChunks += dev->nChunksPerBlock;
}
else {
dev->markNANDBlockBad(dev,i);
bi->blockState = YAFFS_BLOCK_STATE_DEAD;
}
}
}
dev->blocksInCheckpoint = 0;
return 1;
}
static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
{
int i;
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
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){
dev->checkpointNextBlock = i + 1;
dev->checkpointCurrentBlock = i;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i));
return;
}
}
}
T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
dev->checkpointNextBlock = -1;
dev->checkpointCurrentBlock = -1;
}
static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
{
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)
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),
i, tags.objectId,tags.sequenceNumber,tags.eccResult));
if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
/* Right kind of block */
dev->checkpointNextBlock = tags.objectId;
dev->checkpointCurrentBlock = i;
dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
dev->blocksInCheckpoint++;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
return;
}
}
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
dev->checkpointNextBlock = -1;
dev->checkpointCurrentBlock = -1;
}
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
{
/* Got the functions we need? */
if (!dev->writeChunkWithTagsToNAND ||
!dev->readChunkWithTagsFromNAND ||
!dev->eraseBlockInNAND ||
!dev->markNANDBlockBad)
return 0;
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 */
dev->checkpointByteOffset = dev->nDataBytesPerChunk;
/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
* going to be way more than we need */
dev->blocksInCheckpoint = 0;
dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
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;
}
static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
{
int chunk;
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;
tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
tags.byteCount = dev->nDataBytesPerChunk;
if(dev->checkpointCurrentChunk == 0){
/* First chunk we write for the block? Set block state to
checkpoint */
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock);
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));
realignedChunk = chunk - dev->chunkOffset;
dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags);
dev->checkpointByteOffset = 0;
dev->checkpointPageSequence++;
dev->checkpointCurrentChunk++;
if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
dev->checkpointCurrentChunk = 0;
dev->checkpointCurrentBlock = -1;
}
memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
return 1;
}
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
{
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->checkpointByteOffset++;
i++;
dataBytes++;
dev->checkpointByteCount++;
if(dev->checkpointByteOffset < 0 ||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
ok = yaffs_CheckpointFlushBuffer(dev);
}
return i;
}
int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
{
int i=0;
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 +
dev->checkpointCurrentChunk;
realignedChunk = chunk - dev->chunkOffset;
/* read in the next chunk */
/* printf("read checkpoint page %d\n",dev->checkpointPage); */
dev->readChunkWithTagsFromNAND(dev, realignedChunk,
dev->checkpointBuffer,
&tags);
if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
ok = 0;
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->checkpointByteOffset != 0)
yaffs_CheckpointFlushBuffer(dev);
} else {
int i;
for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]);
if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
else {
// Todo this looks odd...
}
}
YFREE(dev->checkpointBlockList);
dev->checkpointBlockList = NULL;
}
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 */
YFREE(dev->checkpointBuffer);
dev->checkpointBuffer = NULL;
return 1;
}
else
return 0;
}
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
{
/* Erase the first checksum block */
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
if(!yaffs_CheckpointSpaceOk(dev))
return 0;
return yaffs_CheckpointErase(dev);
}

View file

@ -0,0 +1,35 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_CHECKPTRW_H__
#define __YAFFS_CHECKPTRW_H__
#include "yaffs_guts.h"
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes);
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);
#endif

331
fs/yaffs2/yaffs_ecc.c Normal file
View file

@ -0,0 +1,331 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This code implements the ECC algorithm used in SmartMedia.
*
* 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
* blocks are used on a 512-byte NAND page.
*
*/
/* Table generated by gen-ecc.c
* Using a table means we do not have to calculate p1..p4 and p1'..p4'
* for each byte of data. These are instead provided in a table in bits7..2.
* Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
* this bytes influence on the line parity.
*/
const char *yaffs_ecc_c_version =
"$Id: yaffs_ecc.c,v 1.9 2007/02/14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_ecc.h"
static const unsigned char column_parity_table[] = {
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
};
/* Count the bits in an unsigned char or a U32 */
static int yaffs_CountBits(unsigned char x)
{
int r = 0;
while (x) {
if (x & 1)
r++;
x >>= 1;
}
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)
{
unsigned int i;
unsigned char col_parity = 0;
unsigned char line_parity = 0;
unsigned char line_parity_prime = 0;
unsigned char t;
unsigned char b;
for (i = 0; i < 256; i++) {
b = column_parity_table[*data++];
col_parity ^= b;
if (b & 0x01) // odd number of bits in the byte
{
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
ecc[2] = (~col_parity) | 0x03;
t = 0;
if (line_parity & 0x80)
t |= 0x80;
if (line_parity_prime & 0x80)
t |= 0x40;
if (line_parity & 0x40)
t |= 0x20;
if (line_parity_prime & 0x40)
t |= 0x10;
if (line_parity & 0x20)
t |= 0x08;
if (line_parity_prime & 0x20)
t |= 0x04;
if (line_parity & 0x10)
t |= 0x02;
if (line_parity_prime & 0x10)
t |= 0x01;
ecc[1] = ~t;
t = 0;
if (line_parity & 0x08)
t |= 0x80;
if (line_parity_prime & 0x08)
t |= 0x40;
if (line_parity & 0x04)
t |= 0x20;
if (line_parity_prime & 0x04)
t |= 0x10;
if (line_parity & 0x02)
t |= 0x08;
if (line_parity_prime & 0x02)
t |= 0x04;
if (line_parity & 0x01)
t |= 0x02;
if (line_parity_prime & 0x01)
t |= 0x01;
ecc[0] = ~t;
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
// Swap the bytes into the wrong order
t = ecc[0];
ecc[0] = ecc[1];
ecc[1] = t;
#endif
}
/* Correct the ECC on a 256 byte block of data */
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc)
{
unsigned char d0, d1, d2; /* deltas */
d0 = read_ecc[0] ^ test_ecc[0];
d1 = read_ecc[1] ^ test_ecc[1];
d2 = read_ecc[2] ^ test_ecc[2];
if ((d0 | d1 | d2) == 0)
return 0; /* no error */
if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
/* Single bit (recoverable) error in data */
unsigned byte;
unsigned bit;
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
// swap the bytes to correct for the wrong order
unsigned char t;
t = d0;
d0 = d1;
d1 = t;
#endif
bit = byte = 0;
if (d1 & 0x80)
byte |= 0x80;
if (d1 & 0x20)
byte |= 0x40;
if (d1 & 0x08)
byte |= 0x20;
if (d1 & 0x02)
byte |= 0x10;
if (d0 & 0x80)
byte |= 0x08;
if (d0 & 0x20)
byte |= 0x04;
if (d0 & 0x08)
byte |= 0x02;
if (d0 & 0x02)
byte |= 0x01;
if (d2 & 0x80)
bit |= 0x04;
if (d2 & 0x20)
bit |= 0x02;
if (d2 & 0x08)
bit |= 0x01;
data[byte] ^= (1 << bit);
return 1; /* Corrected the error */
}
if ((yaffs_CountBits(d0) +
yaffs_CountBits(d1) +
yaffs_CountBits(d2)) == 1) {
/* Reccoverable error in ecc */
read_ecc[0] = test_ecc[0];
read_ecc[1] = test_ecc[1];
read_ecc[2] = test_ecc[2];
return 1; /* Corrected the error */
}
/* Unrecoverable error */
return -1;
}
/*
* ECCxxxOther does ECC calcs on arbitrary n bytes of data
*/
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
yaffs_ECCOther * eccOther)
{
unsigned int i;
unsigned char col_parity = 0;
unsigned line_parity = 0;
unsigned line_parity_prime = 0;
unsigned char b;
for (i = 0; i < nBytes; i++) {
b = column_parity_table[*data++];
col_parity ^= b;
if (b & 0x01) {
/* odd number of bits in the byte */
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
eccOther->colParity = (col_parity >> 2) & 0x3f;
eccOther->lineParity = line_parity;
eccOther->lineParityPrime = line_parity_prime;
}
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
yaffs_ECCOther * read_ecc,
const yaffs_ECCOther * test_ecc)
{
unsigned char cDelta; /* column parity delta */
unsigned lDelta; /* line parity delta */
unsigned lDeltaPrime; /* line parity delta */
unsigned bit;
cDelta = read_ecc->colParity ^ test_ecc->colParity;
lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
if ((cDelta | lDelta | lDeltaPrime) == 0)
return 0; /* no error */
if (lDelta == ~lDeltaPrime &&
(((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15))
{
/* Single bit (recoverable) error in data */
bit = 0;
if (cDelta & 0x20)
bit |= 0x04;
if (cDelta & 0x08)
bit |= 0x02;
if (cDelta & 0x02)
bit |= 0x01;
if(lDelta >= nBytes)
return -1;
data[lDelta] ^= (1 << bit);
return 1; /* corrected */
}
if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
yaffs_CountBits(cDelta)) == 1) {
/* Reccoverable error in ecc */
*read_ecc = *test_ecc;
return 1; /* corrected */
}
/* Unrecoverable error */
return -1;
}

44
fs/yaffs2/yaffs_ecc.h Normal file
View file

@ -0,0 +1,44 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* This code implements the ECC algorithm used in SmartMedia.
*
* 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
* blocks are used on a 512-byte NAND page.
*
*/
#ifndef __YAFFS_ECC_H__
#define __YAFFS_ECC_H__
typedef struct {
unsigned char colParity;
unsigned lineParity;
unsigned lineParityPrime;
} yaffs_ECCOther;
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);
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
yaffs_ECCOther * ecc);
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
yaffs_ECCOther * read_ecc,
const yaffs_ECCOther * test_ecc);
#endif

2299
fs/yaffs2/yaffs_fs.c Normal file

File diff suppressed because it is too large Load diff

7474
fs/yaffs2/yaffs_guts.c Normal file

File diff suppressed because it is too large Load diff

902
fs/yaffs2/yaffs_guts.h Normal file
View file

@ -0,0 +1,902 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_GUTS_H__
#define __YAFFS_GUTS_H__
#include "devextras.h"
#include "yportenv.h"
#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 an S=0x53
* And what have we got...
*/
#define YAFFS_MAGIC 0x5941FF53
#define YAFFS_NTNODES_LEVEL0 16
#define YAFFS_TNODES_LEVEL0_BITS 4
#define YAFFS_TNODES_LEVEL0_MASK 0xf
#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
#define YAFFS_TNODES_INTERNAL_MASK 0x7
#define YAFFS_TNODES_MAX_LEVEL 6
#ifndef CONFIG_YAFFS_NO_YAFFS1
#define YAFFS_BYTES_PER_SPARE 16
#define YAFFS_BYTES_PER_CHUNK 512
#define YAFFS_CHUNK_SIZE_SHIFT 9
#define YAFFS_CHUNKS_PER_BLOCK 32
#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
#endif
#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
#define YAFFS_MAX_CHUNK_ID 0x000FFFFF
#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
#define YAFFS_ALLOCATION_NOBJECTS 100
#define YAFFS_ALLOCATION_NTNODES 100
#define YAFFS_ALLOCATION_NLINKS 100
#define YAFFS_NOBJECT_BUCKETS 256
#define YAFFS_OBJECT_SPACE 0x40000
#define YAFFS_CHECKPOINT_VERSION 3
#ifdef CONFIG_YAFFS_UNICODE
#define YAFFS_MAX_NAME_LENGTH 127
#define YAFFS_MAX_ALIAS_LENGTH 79
#else
#define YAFFS_MAX_NAME_LENGTH 255
#define YAFFS_MAX_ALIAS_LENGTH 159
#endif
#define YAFFS_SHORT_NAME_LENGTH 15
/* Some special object ids for pseudo objects */
#define YAFFS_OBJECTID_ROOT 1
#define YAFFS_OBJECTID_LOSTNFOUND 2
#define YAFFS_OBJECTID_UNLINKED 3
#define YAFFS_OBJECTID_DELETED 4
/* Sseudo object ids for checkpointing */
#define YAFFS_OBJECTID_SB_HEADER 0x10
#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
/* */
#define YAFFS_MAX_SHORT_OP_CACHES 20
#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,
* and is a larger number than the lifetime of a 2GB device.
*/
#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00
/* ChunkCache is used for short read/write operations.*/
typedef struct {
struct yaffs_ObjectStruct *object;
int chunkId;
int lastUse;
int dirty;
int nBytes; /* Only valid if the cache is dirty */
int locked; /* Can't push out or flush while locked. */
#ifdef CONFIG_YAFFS_YAFFS2
__u8 *data;
#else
__u8 data[YAFFS_BYTES_PER_CHUNK];
#endif
} yaffs_ChunkCache;
/* Tags structures in RAM
* NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
* the structure size will get blown out.
*/
#ifndef CONFIG_YAFFS_NO_YAFFS1
typedef struct {
unsigned chunkId:20;
unsigned serialNumber:2;
unsigned byteCount:10;
unsigned objectId:18;
unsigned ecc:12;
unsigned unusedStuff:2;
} yaffs_Tags;
typedef union {
yaffs_Tags asTags;
__u8 asBytes[8];
} yaffs_TagsUnion;
#endif
/* Stuff used for extended tags in YAFFS2 */
typedef enum {
YAFFS_ECC_RESULT_UNKNOWN,
YAFFS_ECC_RESULT_NO_ERROR,
YAFFS_ECC_RESULT_FIXED,
YAFFS_ECC_RESULT_UNFIXED
} yaffs_ECCResult;
typedef enum {
YAFFS_OBJECT_TYPE_UNKNOWN,
YAFFS_OBJECT_TYPE_FILE,
YAFFS_OBJECT_TYPE_SYMLINK,
YAFFS_OBJECT_TYPE_DIRECTORY,
YAFFS_OBJECT_TYPE_HARDLINK,
YAFFS_OBJECT_TYPE_SPECIAL
} yaffs_ObjectType;
#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
typedef struct {
unsigned validMarker0;
unsigned chunkUsed; /* Status of the chunk: used or unused */
unsigned objectId; /* If 0 then this is not part of an object (unused) */
unsigned chunkId; /* If 0 then this is a header, else a data chunk */
unsigned byteCount; /* Only valid for data chunks */
/* The following stuff only has meaning when we read */
yaffs_ECCResult eccResult;
unsigned blockBad;
/* YAFFS 1 stuff */
unsigned chunkDeleted; /* The chunk is marked deleted */
unsigned serialNumber; /* Yaffs1 2-bit serial number */
/* YAFFS2 stuff */
unsigned sequenceNumber; /* The sequence number of this block */
/* Extra info if this is an object header (YAFFS2 only) */
unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */
unsigned extraParentObjectId; /* The parent object */
unsigned extraIsShrinkHeader; /* Is it a shrink header? */
unsigned extraShadows; /* Does this shadow another object? */
yaffs_ObjectType extraObjectType; /* What object type? */
unsigned extraFileLength; /* Length if it is a file */
unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */
unsigned validMarker1;
} yaffs_ExtendedTags;
/* Spare structure for YAFFS1 */
typedef struct {
__u8 tagByte0;
__u8 tagByte1;
__u8 tagByte2;
__u8 tagByte3;
__u8 pageStatus; /* set to 0 to delete the chunk */
__u8 blockStatus;
__u8 tagByte4;
__u8 tagByte5;
__u8 ecc1[3];
__u8 tagByte6;
__u8 tagByte7;
__u8 ecc2[3];
} yaffs_Spare;
/*Special structure for passing through to mtd */
struct yaffs_NANDSpare {
yaffs_Spare spare;
int eccres1;
int eccres2;
};
/* Block data in RAM */
typedef enum {
YAFFS_BLOCK_STATE_UNKNOWN = 0,
YAFFS_BLOCK_STATE_SCANNING,
YAFFS_BLOCK_STATE_NEEDS_SCANNING,
/* The block might have something on it (ie it is allocating or full, perhaps empty)
* but it needs to be scanned to determine its true state.
* This state is only valid during yaffs_Scan.
* NB We tolerate empty because the pre-scanner might be incapable of deciding
* However, if this state is returned on a YAFFS2 device, then we expect a sequence number
*/
YAFFS_BLOCK_STATE_EMPTY,
/* This block is empty */
YAFFS_BLOCK_STATE_ALLOCATING,
/* 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,
/* All the pages in this block have been allocated.
*/
YAFFS_BLOCK_STATE_DIRTY,
/* All pages have been allocated and deleted.
* Erase me, reuse me.
*/
YAFFS_BLOCK_STATE_CHECKPOINT,
/* This block is assigned to holding checkpoint data.
*/
YAFFS_BLOCK_STATE_COLLECTING,
/* This block is being garbage collected */
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 */
int pagesInUse:10; /* number of pages in use */
unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
__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.
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 */
#ifdef CONFIG_YAFFS_YAFFS2
__u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
__u32 sequenceNumber; /* block sequence number for yaffs2 */
#endif
} yaffs_BlockInfo;
/* -------------------------- Object structure -------------------------------*/
/* This is the object structure as stored on NAND */
typedef struct {
yaffs_ObjectType type;
/* Apply to everything */
int parentObjectId;
__u16 sum__NoLongerUsed; /* checksum of name. No longer used */
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
/* Thes following apply to directories, files, symlinks - not hard links */
__u32 yst_mode; /* protection */
#ifdef CONFIG_YAFFS_WINCE
__u32 notForWinCE[5];
#else
__u32 yst_uid;
__u32 yst_gid;
__u32 yst_atime;
__u32 yst_mtime;
__u32 yst_ctime;
#endif
/* File size applies to files only */
int fileSize;
/* Equivalent object id applies to hard links only. */
int equivalentObjectId;
/* Alias is for symlinks only. */
YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
__u32 yst_rdev; /* device stuff for block and char devices (major/min) */
#ifdef CONFIG_YAFFS_WINCE
__u32 win_ctime[2];
__u32 win_atime[2];
__u32 win_mtime[2];
__u32 roomToGrow[4];
#else
__u32 roomToGrow[10];
#endif
int shadowsObject; /* This object header shadows the specified object if > 0 */
/* isShrink applies to object headers written when we shrink the file (ie resize) */
__u32 isShrink;
} yaffs_ObjectHeader;
/*--------------------------- Tnode -------------------------- */
union yaffs_Tnode_union {
#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
#else
union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
#endif
/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
};
typedef union yaffs_Tnode_union yaffs_Tnode;
struct yaffs_TnodeList_struct {
struct yaffs_TnodeList_struct *next;
yaffs_Tnode *tnodes;
};
typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
/*------------------------ Object -----------------------------*/
/* An object can be one of:
* - a directory (no data, has children links
* - a regular file (data.... not prunes :->).
* - a symlink [symbolic link] (the alias).
* - a hard link
*/
typedef struct {
__u32 fileSize;
__u32 scannedFileSize;
__u32 shrinkSize;
int topLevel;
yaffs_Tnode *top;
} yaffs_FileStructure;
typedef struct {
struct list_head children; /* list of child links */
} yaffs_DirectoryStructure;
typedef struct {
YCHAR *alias;
} yaffs_SymLinkStructure;
typedef struct {
struct yaffs_ObjectStruct *equivalentObject;
__u32 equivalentObjectId;
} yaffs_HardLinkStructure;
typedef union {
yaffs_FileStructure fileVariant;
yaffs_DirectoryStructure directoryVariant;
yaffs_SymLinkStructure symLinkVariant;
yaffs_HardLinkStructure hardLinkVariant;
} yaffs_ObjectVariant;
struct yaffs_ObjectStruct {
__u8 deleted:1; /* This should only apply to unlinked files. */
__u8 softDeleted:1; /* it has also been soft deleted */
__u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/
__u8 fake:1; /* A fake object has no presence on NAND. */
__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
* object might be created before the data
* is available (ie. file data records appear before the header).
*/
__u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */
__u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is
* still in the inode cache. Free of object is defered.
* until the inode is released.
*/
__u8 serial; /* serial number of chunk in NAND. Cached here */
__u16 sum; /* sum of the name to speed searching */
struct yaffs_DeviceStruct *myDev; /* The device I'm on */
struct list_head hashLink; /* list of objects in this hash bucket */
struct list_head hardLinks; /* all the equivalent hard linked objects */
/* directory structure stuff */
/* also used for linking up the free list */
struct yaffs_ObjectStruct *parent;
struct list_head siblings;
/* Where's my object header in NAND? */
int chunkId;
int nDataChunks; /* Number of data chunks attached to the file. */
__u32 objectId; /* the object id value */
__u32 yst_mode;
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
#endif
#ifndef __KERNEL__
__u32 inUse;
#endif
#ifdef CONFIG_YAFFS_WINCE
__u32 win_ctime[2];
__u32 win_mtime[2];
__u32 win_atime[2];
#else
__u32 yst_uid;
__u32 yst_gid;
__u32 yst_atime;
__u32 yst_mtime;
__u32 yst_ctime;
#endif
__u32 yst_rdev;
#ifdef __KERNEL__
struct inode *myInode;
#endif
yaffs_ObjectType variantType;
yaffs_ObjectVariant variant;
};
typedef struct yaffs_ObjectStruct yaffs_Object;
struct yaffs_ObjectList_struct {
yaffs_Object *objects;
struct yaffs_ObjectList_struct *next;
};
typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
typedef struct {
struct list_head list;
int count;
} yaffs_ObjectBucket;
/* yaffs_CheckpointObject holds the definition of an object as dumped
* by checkpointing.
*/
typedef struct {
int structType;
__u32 objectId;
__u32 parentId;
int chunkId;
yaffs_ObjectType variantType:3;
__u8 deleted:1;
__u8 softDeleted:1;
__u8 unlinked:1;
__u8 fake:1;
__u8 renameAllowed:1;
__u8 unlinkAllowed:1;
__u8 serial;
int nDataChunks;
__u32 fileSizeOrEquivalentObjectId;
}yaffs_CheckpointObject;
/*--------------------- Temporary buffers ----------------
*
* These are chunk-sized working buffers. Each device has a few
*/
typedef struct {
__u8 *buffer;
int line; /* track from whence this buffer was allocated */
int maxLine;
} yaffs_TempBuffer;
/*----------------- Device ---------------------------------*/
struct yaffs_DeviceStruct {
struct list_head devList;
const char *name;
/* Entry parameters set up way early. Yaffs sets up the rest.*/
int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
int nChunksPerBlock; /* does not need to be a power of 2 */
int nBytesPerSpare; /* spare area size */
int startBlock; /* Start block we're allowed to use */
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 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
* the number of short op caches (don't use too many)
*/
int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
int useNANDECC; /* Flag to decide whether or not to use NANDECC */
void *genericDevice; /* Pointer to device context
* 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,
int chunkInNAND, const __u8 * data,
const yaffs_Spare * spare);
int (*readChunkFromNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, __u8 * data,
yaffs_Spare * spare);
int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev,
int blockInNAND);
int (*initialiseNAND) (struct yaffs_DeviceStruct * dev);
#ifdef CONFIG_YAFFS_YAFFS2
int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, const __u8 * data,
const yaffs_ExtendedTags * tags);
int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, __u8 * data,
yaffs_ExtendedTags * tags);
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber);
#endif
int isYaffs2;
/* 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
* at compile time so we have to allocate it.
*/
void (*putSuperFunc) (struct super_block * sb);
#endif
int isMounted;
int isCheckpointed;
/* Stuff to support block offsetting to support start block zero */
int internalStartBlock;
int internalEndBlock;
int blockOffset;
int chunkOffset;
/* Runtime checkpointing stuff */
int checkpointPageSequence; /* running sequence number of checkpoint pages */
int checkpointByteCount;
int checkpointByteOffset;
__u8 *checkpointBuffer;
int checkpointOpenForWrite;
int blocksInCheckpoint;
int checkpointCurrentChunk;
int checkpointCurrentBlock;
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.
* Must be consistent with nChunksPerBlock.
*/
int nErasedBlocks;
int allocationBlock; /* Current block being allocated off */
__u32 allocationPage;
int allocationBlockFinder; /* Used to search for next allocation block */
/* Runtime state */
int nTnodesCreated;
yaffs_Tnode *freeTnodes;
int nFreeTnodes;
yaffs_TnodeList *allocatedTnodeList;
int isDoingGC;
int nObjectsCreated;
yaffs_Object *freeObjects;
int nFreeObjects;
yaffs_ObjectList *allocatedObjectList;
yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
int nFreeChunks;
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;
int nPageReads;
int nBlockErasures;
int nErasureFailures;
int nGCCopies;
int garbageCollections;
int passiveGarbageCollections;
int nRetriedWrites;
int nRetiredBlocks;
int eccFixed;
int eccUnfixed;
int tagsEccFixed;
int tagsEccUnfixed;
int nDeletions;
int nUnmarkedDeletions;
int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
/* Special directories */
yaffs_Object *rootDir;
yaffs_Object *lostNFoundDir;
/* Buffer areas for storing data to recover from write failures TODO
* __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;
yaffs_ChunkCache *srCache;
int srLastUse;
int cacheHits;
/* Stuff for background deletion and unlinked files.*/
yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/
int nDeletedFiles; /* Count of files awaiting deletion;*/
int nUnlinkedFiles; /* Count of unlinked files. */
int nBackgroundDeletions; /* Count of background deletions. */
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
int maxTemp;
int unmanagedTempAllocations;
int unmanagedTempDeallocations;
/* yaffs2 runtime stuff */
unsigned sequenceNumber; /* Sequence number of currently allocating block */
unsigned oldestDirtySequence;
};
typedef struct yaffs_DeviceStruct yaffs_Device;
/* The static layout of bllock usage etc is stored in the super block header */
typedef struct {
int StructType;
int version;
int checkpointStartBlock;
int checkpointEndBlock;
int startBlock;
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.
*/
typedef struct {
int structType;
int nErasedBlocks;
int allocationBlock; /* Current block being allocated off */
__u32 allocationPage;
int nFreeChunks;
int nDeletedFiles; /* Count of files awaiting deletion;*/
int nUnlinkedFiles; /* Count of unlinked files. */
int nBackgroundDeletions; /* Count of background deletions. */
/* yaffs2 runtime stuff */
unsigned sequenceNumber; /* Sequence number of currently allocating block */
unsigned oldestDirtySequence;
} yaffs_CheckpointDevice;
typedef struct {
int structType;
__u32 magic;
__u32 version;
__u32 head;
} yaffs_CheckpointValidity;
/* Function to manipulate block info */
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
{
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
blk));
YBUG();
}
return &dev->blockInfo[blk - dev->internalStartBlock];
}
/*----------------------- YAFFS Functions -----------------------*/
int yaffs_GutsInitialise(yaffs_Device * dev);
void yaffs_Deinitialise(yaffs_Device * dev);
int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev);
int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName,
yaffs_Object * newDir, const YCHAR * newName);
int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name);
int yaffs_DeleteFile(yaffs_Object * obj);
int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize);
int yaffs_GetObjectFileLength(yaffs_Object * obj);
int yaffs_GetObjectInode(yaffs_Object * obj);
unsigned yaffs_GetObjectType(yaffs_Object * obj);
int yaffs_GetObjectLinkCount(yaffs_Object * obj);
int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr);
int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr);
/* File operations */
int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, loff_t offset,
int nBytes);
int yaffs_WriteDataToFile(yaffs_Object * obj, const __u8 * buffer, loff_t offset,
int nBytes, int writeThrough);
int yaffs_ResizeFile(yaffs_Object * obj, loff_t newSize);
yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name,
__u32 mode, __u32 uid, __u32 gid);
int yaffs_FlushFile(yaffs_Object * obj, int updateTime);
/* Flushing and checkpointing */
void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
int yaffs_CheckpointSave(yaffs_Device *dev);
int yaffs_CheckpointRestore(yaffs_Device *dev);
/* Directory operations */
yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name,
__u32 mode, __u32 uid, __u32 gid);
yaffs_Object *yaffs_FindObjectByName(yaffs_Object * theDir, const YCHAR * name);
int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir,
int (*fn) (yaffs_Object *));
yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number);
/* Link operations */
yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name,
yaffs_Object * equivalentObject);
yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj);
/* Symlink operations */
yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name,
__u32 mode, __u32 uid, __u32 gid,
const YCHAR * alias);
YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj);
/* Special inodes (fifos, sockets and devices) */
yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name,
__u32 mode, __u32 uid, __u32 gid, __u32 rdev);
/* Special directories */
yaffs_Object *yaffs_Root(yaffs_Device * dev);
yaffs_Object *yaffs_LostNFound(yaffs_Device * dev);
#ifdef CONFIG_YAFFS_WINCE
/* CONFIG_YAFFS_WINCE special stuff */
void yfsd_WinFileTimeNow(__u32 target[2]);
#endif
#ifdef __KERNEL__
void yaffs_HandleDeferedFree(yaffs_Object * obj);
#endif
/* Debug dump */
int yaffs_DumpObject(yaffs_Object * obj);
void yaffs_GutsTest(yaffs_Device * dev);
/* A few useful functions */
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn);
int yaffs_CheckFF(__u8 * buffer, int nBytes);
void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
#endif

241
fs/yaffs2/yaffs_mtdif.c Normal file
View file

@ -0,0 +1,241 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
const char *yaffs_mtdif_c_version =
"$Id: yaffs_mtdif.c,v 1.19 2007/02/14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_mtdif.h"
#include "linux/mtd/mtd.h"
#include "linux/types.h"
#include "linux/time.h"
#include "linux/mtd/nand.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
static struct nand_oobinfo yaffs_oobinfo = {
.useecc = 1,
.eccbytes = 6,
.eccpos = {8, 9, 10, 13, 14, 15}
};
static struct nand_oobinfo yaffs_noeccinfo = {
.useecc = 0,
};
#endif
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
{
oob[0] = spare->tagByte0;
oob[1] = spare->tagByte1;
oob[2] = spare->tagByte2;
oob[3] = spare->tagByte3;
oob[4] = spare->tagByte4;
oob[5] = spare->tagByte5 & 0x3f;
oob[5] |= spare->blockStatus == 'Y' ? 0: 0x80;
oob[5] |= spare->pageStatus == 0 ? 0: 0x40;
oob[6] = spare->tagByte6;
oob[7] = spare->tagByte7;
}
static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
{
struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
spare->tagByte0 = oob[0];
spare->tagByte1 = oob[1];
spare->tagByte2 = oob[2];
spare->tagByte3 = oob[3];
spare->tagByte4 = oob[4];
spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
spare->tagByte6 = oob[6];
spare->tagByte7 = oob[7];
spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
}
#endif
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
__u8 spareAsBytes[8]; /* OOB */
if (data && !spare)
retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data);
else if (spare) {
if (dev->useNANDECC) {
translate_spare2oob(spare, spareAsBytes);
ops.mode = MTD_OOB_AUTO;
ops.ooblen = 8; /* temp hack */
} else {
ops.mode = MTD_OOB_RAW;
ops.ooblen = YAFFS_BYTES_PER_SPARE;
}
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
ops.datbuf = (u8 *)data;
ops.ooboffs = 0;
ops.oobbuf = spareAsBytes;
retval = mtd->write_oob(mtd, addr, &ops);
}
#else
__u8 *spareAsBytes = (__u8 *) spare;
if (data && spare) {
if (dev->useNANDECC)
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_oobinfo);
else
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_noeccinfo);
} else {
if (data)
retval =
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (spare)
retval =
mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
&dummy, spareAsBytes);
}
#endif
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
yaffs_Spare * spare)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
__u8 spareAsBytes[8]; /* OOB */
if (data && !spare)
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data);
else if (spare) {
if (dev->useNANDECC) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = 8; /* temp hack */
} else {
ops.mode = MTD_OOB_RAW;
ops.ooblen = YAFFS_BYTES_PER_SPARE;
}
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
ops.datbuf = data;
ops.ooboffs = 0;
ops.oobbuf = spareAsBytes;
retval = mtd->read_oob(mtd, addr, &ops);
if (dev->useNANDECC)
translate_oob2spare(spare, spareAsBytes);
}
#else
__u8 *spareAsBytes = (__u8 *) spare;
if (data && spare) {
if (dev->useNANDECC) {
/* Careful, this call adds 2 ints */
/* to the end of the spare data. Calling function */
/* should allocate enough memory for spare, */
/* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_oobinfo);
} else {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_noeccinfo);
}
} else {
if (data)
retval =
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (spare)
retval =
mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
&dummy, spareAsBytes);
}
#endif
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
__u32 addr =
((loff_t) blockNumber) * dev->nDataBytesPerChunk
* dev->nChunksPerBlock;
struct erase_info ei;
int retval = 0;
ei.mtd = mtd;
ei.addr = addr;
ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
ei.time = 1000;
ei.retries = 2;
ei.callback = NULL;
ei.priv = (u_long) dev;
/* Todo finish off the ei if required */
sema_init(&dev->sem, 0);
retval = mtd->erase(mtd, &ei);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd_InitialiseNAND(yaffs_Device * dev)
{
return YAFFS_OK;
}

27
fs/yaffs2/yaffs_mtdif.h Normal file
View file

@ -0,0 +1,27 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_MTDIF_H__
#define __YAFFS_MTDIF_H__
#include "yaffs_guts.h"
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare);
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
yaffs_Spare * spare);
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber);
int nandmtd_InitialiseNAND(yaffs_Device * dev);
#endif

369
fs/yaffs2/yaffs_mtdif1.c Normal file
View file

@ -0,0 +1,369 @@
/*
* 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.5 2007/10/29 14:59:57 imcd 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\n", blockNo);
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
/* Check any MTD prerequists.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
{
/* 2.6.18 has mtd->ecclayout->oobavail */
/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
int oobavail = mtd->ecclayout->oobavail;
if (oobavail < YTAG1_SIZE) {
yaffs_trace(YAFFS_TRACE_ERROR,
"mtd device has only %d bytes for tags, need %d\n",
oobavail, YTAG1_SIZE);
return YAFFS_FAIL;
}
return YAFFS_OK;
}
/* Query for the current state of a specific block.
*
* Examine the tags of the first chunk of the block and return the state:
* - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
* - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
* - YAFFS_BLOCK_STATE_EMPTY, the block is clean
*
* Always returns YAFFS_OK.
*/
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * pState, int *pSequenceNumber)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkNo = blockNo * dev->nChunksPerBlock;
loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
yaffs_ExtendedTags etags;
int state = YAFFS_BLOCK_STATE_DEAD;
int seqnum = 0;
int retval;
/* We don't yet have a good place to test for MTD config prerequists.
* Do it here as we are called during the initial scan.
*/
if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
return YAFFS_FAIL;
}
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
etags.blockBad = (mtd->block_isbad)(mtd, addr);
if (etags.blockBad) {
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
"block %d is marked bad\n", blockNo);
state = YAFFS_BLOCK_STATE_DEAD;
}
else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
/* bad tags, need to look more closely */
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
}
else if (etags.chunkUsed) {
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
seqnum = etags.sequenceNumber;
}
else {
state = YAFFS_BLOCK_STATE_EMPTY;
}
*pState = state;
*pSequenceNumber = seqnum;
/* query always succeeds */
return YAFFS_OK;
}
#endif /*KERNEL_VERSION*/

28
fs/yaffs2/yaffs_mtdif1.h Normal file
View file

@ -0,0 +1,28 @@
/*
* 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

232
fs/yaffs2/yaffs_mtdif2.c Normal file
View file

@ -0,0 +1,232 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* mtd interface for YAFFS2 */
const char *yaffs_mtdif2_c_version =
"$Id: yaffs_mtdif2.c,v 1.17 2007/02/14 01:09:06 wookey 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"
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags * tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_oob_ops ops;
#else
size_t dummy;
#endif
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
yaffs_PackedTags2 pt;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
if (tags)
yaffs_PackTags2(&pt, tags);
else
BUG(); /* both tags and data should always be present */
if (data) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = sizeof(pt);
ops.len = dev->nDataBytesPerChunk;
ops.ooboffs = 0;
ops.datbuf = (__u8 *)data;
ops.oobbuf = (void *)&pt;
retval = mtd->write_oob(mtd, addr, &ops);
} else
BUG(); /* both tags and data should always be present */
#else
if (tags) {
yaffs_PackTags2(&pt, tags);
}
if (data && tags) {
if (dev->useNANDECC)
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) & pt, NULL);
else
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) & pt, NULL);
} else {
if (data)
retval =
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (tags)
retval =
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
(__u8 *) & pt);
}
#endif
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
yaffs_PackedTags2 pt;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
if (data && !tags)
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data);
else if (tags) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = sizeof(pt);
ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
ops.ooboffs = 0;
ops.datbuf = data;
ops.oobbuf = dev->spareBuffer;
retval = mtd->read_oob(mtd, addr, &ops);
}
#else
if (data && tags) {
if (dev->useNANDECC) {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, dev->spareBuffer,
NULL);
} else {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, dev->spareBuffer,
NULL);
}
} else {
if (data)
retval =
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (tags)
retval =
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
dev->spareBuffer);
}
#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;
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
retval =
mtd->block_markbad(mtd,
blockNo * dev->nChunksPerBlock *
dev->nDataBytesPerChunk);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
retval =
mtd->block_isbad(mtd,
blockNo * dev->nChunksPerBlock *
dev->nDataBytesPerChunk);
if (retval) {
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
*state = YAFFS_BLOCK_STATE_DEAD;
*sequenceNumber = 0;
} else {
yaffs_ExtendedTags t;
nandmtd2_ReadChunkWithTagsFromNAND(dev,
blockNo *
dev->nChunksPerBlock, NULL,
&t);
if (t.chunkUsed) {
*sequenceNumber = t.sequenceNumber;
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
} else {
*sequenceNumber = 0;
*state = YAFFS_BLOCK_STATE_EMPTY;
}
}
T(YAFFS_TRACE_MTD,
(TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
*state));
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}

29
fs/yaffs2/yaffs_mtdif2.h Normal file
View file

@ -0,0 +1,29 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_MTDIF2_H__
#define __YAFFS_MTDIF2_H__
#include "yaffs_guts.h"
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags * tags);
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags);
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber);
#endif

134
fs/yaffs2/yaffs_nand.c Normal file
View file

@ -0,0 +1,134 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
const char *yaffs_nand_c_version =
"$Id: yaffs_nand.c,v 1.7 2007/02/14 01:09:06 wookey Exp $";
#include "yaffs_nand.h"
#include "yaffs_tagscompat.h"
#include "yaffs_tagsvalidity.h"
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer,
yaffs_ExtendedTags * tags)
{
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;
if (dev->readChunkWithTagsFromNAND)
result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
tags);
else
result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
realignedChunkInNAND,
buffer,
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;
}
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * buffer,
yaffs_ExtendedTags * tags)
{
chunkInNAND -= dev->chunkOffset;
if (tags) {
tags->sequenceNumber = dev->sequenceNumber;
tags->chunkUsed = 1;
if (!yaffs_ValidateTags(tags)) {
T(YAFFS_TRACE_ERROR,
(TSTR("Writing uninitialised tags" TENDSTR)));
YBUG();
}
T(YAFFS_TRACE_WRITE,
(TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
tags->objectId, tags->chunkId));
} else {
T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
YBUG();
}
if (dev->writeChunkWithTagsToNAND)
return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
tags);
else
return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
chunkInNAND,
buffer,
tags);
}
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
{
blockNo -= dev->blockOffset;
;
if (dev->markNANDBlockBad)
return dev->markNANDBlockBad(dev, blockNo);
else
return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
}
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo,
yaffs_BlockState * state,
unsigned *sequenceNumber)
{
blockNo -= dev->blockOffset;
if (dev->queryNANDBlock)
return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
else
return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
state,
sequenceNumber);
}
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND)
{
int result;
blockInNAND -= dev->blockOffset;
dev->nBlockErasures++;
result = dev->eraseBlockInNAND(dev, blockInNAND);
return result;
}
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
{
return dev->initialiseNAND(dev);
}

44
fs/yaffs2/yaffs_nand.h Normal file
View file

@ -0,0 +1,44 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_NAND_H__
#define __YAFFS_NAND_H__
#include "yaffs_guts.h"
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer,
yaffs_ExtendedTags * tags);
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * buffer,
yaffs_ExtendedTags * tags);
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo);
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo,
yaffs_BlockState * state,
unsigned *sequenceNumber);
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND);
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
#endif

View file

@ -0,0 +1,39 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/* Interface to emulated NAND functions (2k page size) */
#ifndef __YAFFS_NANDEMUL2K_H__
#define __YAFFS_NANDEMUL2K_H__
#include "yaffs_guts.h"
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, const __u8 * data,
yaffs_ExtendedTags * tags);
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, __u8 * data,
yaffs_ExtendedTags * tags);
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber);
int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND);
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
int nandemul2k_GetBytesPerChunk(void);
int nandemul2k_GetChunksPerBlock(void);
int nandemul2k_GetNumberOfBlocks(void);
#endif

View file

@ -0,0 +1,52 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_packedtags1.h"
#include "yportenv.h"
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t)
{
pt->chunkId = t->chunkId;
pt->serialNumber = t->serialNumber;
pt->byteCount = t->byteCount;
pt->objectId = t->objectId;
pt->ecc = 0;
pt->deleted = (t->chunkDeleted) ? 0 : 1;
pt->unusedStuff = 0;
pt->shouldBeFF = 0xFFFFFFFF;
}
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt)
{
static const __u8 allFF[] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff };
if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
t->blockBad = 0;
if (pt->shouldBeFF != 0xFFFFFFFF) {
t->blockBad = 1;
}
t->chunkUsed = 1;
t->objectId = pt->objectId;
t->chunkId = pt->chunkId;
t->byteCount = pt->byteCount;
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
t->chunkDeleted = (pt->deleted) ? 0 : 1;
t->serialNumber = pt->serialNumber;
} else {
memset(t, 0, sizeof(yaffs_ExtendedTags));
}
}

View file

@ -0,0 +1,37 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
#ifndef __YAFFS_PACKEDTAGS1_H__
#define __YAFFS_PACKEDTAGS1_H__
#include "yaffs_guts.h"
typedef struct {
unsigned chunkId:20;
unsigned serialNumber:2;
unsigned byteCount:10;
unsigned objectId:18;
unsigned ecc:12;
unsigned deleted:1;
unsigned unusedStuff:1;
unsigned shouldBeFF;
} yaffs_PackedTags1;
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t);
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt);
#endif

View file

@ -0,0 +1,182 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_packedtags2.h"
#include "yportenv.h"
#include "yaffs_tagsvalidity.h"
/* This code packs a set of extended tags into a binary structure for
* NAND storage
*/
/* Some of the information is "extra" struff which can be packed in to
* speed scanning
* This is defined by having the EXTRA_HEADER_INFO_FLAG set.
*/
/* Extra flags applied to chunkId */
#define EXTRA_HEADER_INFO_FLAG 0x80000000
#define EXTRA_SHRINK_FLAG 0x40000000
#define EXTRA_SHADOWS_FLAG 0x20000000
#define EXTRA_SPARE_FLAGS 0x10000000
#define ALL_EXTRA_FLAGS 0xF0000000
/* Also, the top 4 bits of the object Id are set to the object type. */
#define EXTRA_OBJECT_TYPE_SHIFT (28)
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
{
T(YAFFS_TRACE_MTD,
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
pt->t.objectId, pt->t.chunkId, pt->t.byteCount,
pt->t.sequenceNumber));
}
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
{
T(YAFFS_TRACE_MTD,
(TSTR
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte "
"%d del %d ser %d seq %d"
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
t->sequenceNumber));
}
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
{
pt->t.chunkId = t->chunkId;
pt->t.sequenceNumber = t->sequenceNumber;
pt->t.byteCount = t->byteCount;
pt->t.objectId = t->objectId;
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
/* Store the extra header info instead */
/* We save the parent object in the chunkId */
pt->t.chunkId = EXTRA_HEADER_INFO_FLAG
| t->extraParentObjectId;
if (t->extraIsShrinkHeader) {
pt->t.chunkId |= EXTRA_SHRINK_FLAG;
}
if (t->extraShadows) {
pt->t.chunkId |= EXTRA_SHADOWS_FLAG;
}
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
pt->t.objectId |=
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
pt->t.byteCount = t->extraEquivalentObjectId;
} else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
pt->t.byteCount = t->extraFileLength;
} else {
pt->t.byteCount = 0;
}
}
yaffs_DumpPackedTags2(pt);
yaffs_DumpTags2(t);
#ifndef YAFFS_IGNORE_TAGS_ECC
{
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
sizeof(yaffs_PackedTags2TagsPart),
&pt->ecc);
}
#endif
}
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
{
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
}
#else
{
yaffs_ECCOther ecc;
int result;
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
sizeof
(yaffs_PackedTags2TagsPart),
&ecc);
result =
yaffs_ECCCorrectOther((unsigned char *)&pt->t,
sizeof
(yaffs_PackedTags2TagsPart),
&pt->ecc, &ecc);
switch(result){
case 0:
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
break;
case 1:
t->eccResult = YAFFS_ECC_RESULT_FIXED;
break;
case -1:
t->eccResult = YAFFS_ECC_RESULT_UNFIXED;
break;
default:
t->eccResult = YAFFS_ECC_RESULT_UNKNOWN;
}
}
#endif
t->blockBad = 0;
t->chunkUsed = 1;
t->objectId = pt->t.objectId;
t->chunkId = pt->t.chunkId;
t->byteCount = pt->t.byteCount;
t->chunkDeleted = 0;
t->serialNumber = 0;
t->sequenceNumber = pt->t.sequenceNumber;
/* Do extra header info stuff */
if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) {
t->chunkId = 0;
t->byteCount = 0;
t->extraHeaderInfoAvailable = 1;
t->extraParentObjectId =
pt->t.chunkId & (~(ALL_EXTRA_FLAGS));
t->extraIsShrinkHeader =
(pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
t->extraShadows =
(pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
t->extraObjectType =
pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT;
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
t->extraEquivalentObjectId = pt->t.byteCount;
} else {
t->extraFileLength = pt->t.byteCount;
}
}
}
yaffs_DumpPackedTags2(pt);
yaffs_DumpTags2(t);
}

View file

@ -0,0 +1,38 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
#ifndef __YAFFS_PACKEDTAGS2_H__
#define __YAFFS_PACKEDTAGS2_H__
#include "yaffs_guts.h"
#include "yaffs_ecc.h"
typedef struct {
unsigned sequenceNumber;
unsigned objectId;
unsigned chunkId;
unsigned byteCount;
} yaffs_PackedTags2TagsPart;
typedef struct {
yaffs_PackedTags2TagsPart t;
yaffs_ECCOther ecc;
} yaffs_PackedTags2;
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt);
#endif

160
fs/yaffs2/yaffs_qsort.c Normal file
View file

@ -0,0 +1,160 @@
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "yportenv.h"
//#include <linux/string.h>
/*
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*/
#define swapcode(TYPE, parmi, parmj, n) { \
long i = (n) / sizeof (TYPE); \
register TYPE *pi = (TYPE *) (parmi); \
register TYPE *pj = (TYPE *) (parmj); \
do { \
register TYPE t = *pi; \
*pi++ = *pj; \
*pj++ = t; \
} while (--i > 0); \
}
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
static __inline void
swapfunc(char *a, char *b, int n, int swaptype)
{
if (swaptype <= 1)
swapcode(long, a, b, n)
else
swapcode(char, a, b, n)
}
#define swap(a, b) \
if (swaptype == 0) { \
long t = *(long *)(a); \
*(long *)(a) = *(long *)(b); \
*(long *)(b) = t; \
} else \
swapfunc(a, b, es, swaptype)
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
static __inline char *
med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
{
return cmp(a, b) < 0 ?
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
:(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
}
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
void
yaffs_qsort(void *aa, size_t n, size_t es,
int (*cmp)(const void *, const void *))
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
int d, r, swaptype, swap_cnt;
register char *a = aa;
loop: SWAPINIT(a, es);
swap_cnt = 0;
if (n < 7) {
for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
pm = (char *)a + (n / 2) * es;
if (n > 7) {
pl = (char *)a;
pn = (char *)a + (n - 1) * es;
if (n > 40) {
d = (n / 8) * es;
pl = med3(pl, pl + d, pl + 2 * d, cmp);
pm = med3(pm - d, pm, pm + d, cmp);
pn = med3(pn - 2 * d, pn - d, pn, cmp);
}
pm = med3(pl, pm, pn, cmp);
}
swap(a, pm);
pa = pb = (char *)a + es;
pc = pd = (char *)a + (n - 1) * es;
for (;;) {
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pa, pb);
pa += es;
}
pb += es;
}
while (pb <= pc && (r = cmp(pc, a)) >= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pc, pd);
pd -= es;
}
pc -= es;
}
if (pb > pc)
break;
swap(pb, pc);
swap_cnt = 1;
pb += es;
pc -= es;
}
if (swap_cnt == 0) { /* Switch to insertion sort */
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
pn = (char *)a + n * es;
r = min(pa - (char *)a, pb - pa);
vecswap(a, pb - r, r);
r = min((long)(pd - pc), (long)(pn - pd - es));
vecswap(pb, pn - r, r);
if ((r = pb - pa) > es)
yaffs_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);*/
}

23
fs/yaffs2/yaffs_qsort.h Normal file
View file

@ -0,0 +1,23 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_QSORT_H__
#define __YAFFS_QSORT_H__
extern void yaffs_qsort (void *const base, size_t total_elems, size_t size,
int (*cmp)(const void *, const void *));
#endif

View file

@ -0,0 +1,530 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_guts.h"
#include "yaffs_tagscompat.h"
#include "yaffs_ecc.h"
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
#ifdef NOTYET
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND);
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_Spare * spare);
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
const yaffs_Spare * spare);
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);
#endif
static const char yaffs_countBitsTable[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
int yaffs_CountBits(__u8 x)
{
int retVal;
retVal = yaffs_countBitsTable[x];
return retVal;
}
/********** Tags ECC calculations *********/
void yaffs_CalcECC(const __u8 * data, yaffs_Spare * spare)
{
yaffs_ECCCalculate(data, spare->ecc1);
yaffs_ECCCalculate(&data[256], spare->ecc2);
}
void yaffs_CalcTagsECC(yaffs_Tags * tags)
{
/* Calculate an ecc */
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
unsigned i, j;
unsigned ecc = 0;
unsigned bit = 0;
tags->ecc = 0;
for (i = 0; i < 8; i++) {
for (j = 1; j & 0xff; j <<= 1) {
bit++;
if (b[i] & j) {
ecc ^= bit;
}
}
}
tags->ecc = ecc;
}
int yaffs_CheckECCOnTags(yaffs_Tags * tags)
{
unsigned ecc = tags->ecc;
yaffs_CalcTagsECC(tags);
ecc ^= tags->ecc;
if (ecc && ecc <= 64) {
/* TODO: Handle the failure better. Retire? */
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
ecc--;
b[ecc / 8] ^= (1 << (ecc & 7));
/* Now recvalc the ecc */
yaffs_CalcTagsECC(tags);
return 1; /* recovered error */
} else if (ecc) {
/* Wierd ecc failure value */
/* TODO Need to do somethiong here */
return -1; /* unrecovered error */
}
return 0;
}
/********** Tags **********/
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];
}
static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr,
yaffs_Tags * tagsPtr)
{
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
int result;
tu->asBytes[0] = sparePtr->tagByte0;
tu->asBytes[1] = sparePtr->tagByte1;
tu->asBytes[2] = sparePtr->tagByte2;
tu->asBytes[3] = sparePtr->tagByte3;
tu->asBytes[4] = sparePtr->tagByte4;
tu->asBytes[5] = sparePtr->tagByte5;
tu->asBytes[6] = sparePtr->tagByte6;
tu->asBytes[7] = sparePtr->tagByte7;
result = yaffs_CheckECCOnTags(tagsPtr);
if (result > 0) {
dev->tagsEccFixed++;
} else if (result < 0) {
dev->tagsEccUnfixed++;
}
}
static void yaffs_SpareInitialise(yaffs_Spare * spare)
{
memset(spare, 0xFF, sizeof(yaffs_Spare));
}
static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, const __u8 * data,
yaffs_Spare * spare)
{
if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
T(YAFFS_TRACE_ERROR,
(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
chunkInNAND));
return YAFFS_FAIL;
}
dev->nPageWrites++;
return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
}
static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND,
__u8 * data,
yaffs_Spare * spare,
yaffs_ECCResult * eccResult,
int doErrorCorrection)
{
int retVal;
yaffs_Spare localSpare;
dev->nPageReads++;
if (!spare && data) {
/* If we don't have a real spare, then we use a local one. */
/* Need this for the calculation of the ecc */
spare = &localSpare;
}
if (!dev->useNANDECC) {
retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
if (data && doErrorCorrection) {
/* Do ECC correction */
/* Todo handle any errors */
int eccResult1, eccResult2;
__u8 calcEcc[3];
yaffs_ECCCalculate(data, calcEcc);
eccResult1 =
yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
yaffs_ECCCalculate(&data[256], calcEcc);
eccResult2 =
yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
if (eccResult1 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error fix performed on chunk %d:0"
TENDSTR), chunkInNAND));
dev->eccFixed++;
} else if (eccResult1 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error unfixed on chunk %d:0"
TENDSTR), chunkInNAND));
dev->eccUnfixed++;
}
if (eccResult2 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error fix performed on chunk %d:1"
TENDSTR), chunkInNAND));
dev->eccFixed++;
} else if (eccResult2 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error unfixed on chunk %d:1"
TENDSTR), chunkInNAND));
dev->eccUnfixed++;
}
if (eccResult1 || eccResult2) {
/* We had a data problem on this page */
yaffs_HandleReadDataError(dev, chunkInNAND);
}
if (eccResult1 < 0 || eccResult2 < 0)
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
else if (eccResult1 > 0 || eccResult2 > 0)
*eccResult = YAFFS_ECC_RESULT_FIXED;
else
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
}
} else {
/* Must allocate enough memory for spare+2*sizeof(int) */
/* for ecc results from device. */
struct yaffs_NANDSpare nspare;
retVal =
dev->readChunkFromNAND(dev, chunkInNAND, data,
(yaffs_Spare *) & nspare);
memcpy(spare, &nspare, sizeof(yaffs_Spare));
if (data && doErrorCorrection) {
if (nspare.eccres1 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error fix performed on chunk %d:0"
TENDSTR), chunkInNAND));
} else if (nspare.eccres1 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error unfixed on chunk %d:0"
TENDSTR), chunkInNAND));
}
if (nspare.eccres2 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error fix performed on chunk %d:1"
TENDSTR), chunkInNAND));
} else if (nspare.eccres2 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error unfixed on chunk %d:1"
TENDSTR), chunkInNAND));
}
if (nspare.eccres1 || nspare.eccres2) {
/* We had a data problem on this page */
yaffs_HandleReadDataError(dev, chunkInNAND);
}
if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
*eccResult = YAFFS_ECC_RESULT_FIXED;
else
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
}
}
return retVal;
}
#ifdef NOTYET
static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
int chunkInNAND)
{
static int init = 0;
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
static __u8 data[YAFFS_BYTES_PER_CHUNK];
/* Might as well always allocate the larger size for */
/* dev->useNANDECC == true; */
static __u8 spare[sizeof(struct yaffs_NANDSpare)];
dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
if (!init) {
memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
init = 1;
}
if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
return YAFFS_FAIL;
if (memcmp(cmpbuf, spare, 16))
return YAFFS_FAIL;
return YAFFS_OK;
}
#endif
/*
* Functions for robustisizing
*/
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND)
{
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
/* Mark the block for retirement */
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
(TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
/* TODO:
* Just do a garbage collection on the affected block
* then retire the block
* NB recursion
*/
}
#ifdef NOTYET
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
{
}
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_Spare * spare)
{
}
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
const yaffs_Spare * spare)
{
}
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
{
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
/* Mark the block for retirement */
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
/* Delete the chunk */
yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
}
static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
const yaffs_Spare * s0, const yaffs_Spare * s1)
{
if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
s0->tagByte0 != s1->tagByte0 ||
s0->tagByte1 != s1->tagByte1 ||
s0->tagByte2 != s1->tagByte2 ||
s0->tagByte3 != s1->tagByte3 ||
s0->tagByte4 != s1->tagByte4 ||
s0->tagByte5 != s1->tagByte5 ||
s0->tagByte6 != s1->tagByte6 ||
s0->tagByte7 != s1->tagByte7 ||
s0->ecc1[0] != s1->ecc1[0] ||
s0->ecc1[1] != s1->ecc1[1] ||
s0->ecc1[2] != s1->ecc1[2] ||
s0->ecc2[0] != s1->ecc2[0] ||
s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
return 0;
}
return 1;
}
#endif /* NOTYET */
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags *
eTags)
{
yaffs_Spare spare;
yaffs_Tags tags;
yaffs_SpareInitialise(&spare);
if (eTags->chunkDeleted) {
spare.pageStatus = 0;
} else {
tags.objectId = eTags->objectId;
tags.chunkId = eTags->chunkId;
tags.byteCount = eTags->byteCount;
tags.serialNumber = eTags->serialNumber;
if (!dev->useNANDECC && data) {
yaffs_CalcECC(data, &spare);
}
yaffs_LoadTagsIntoSpare(&spare, &tags);
}
return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
}
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
int chunkInNAND,
__u8 * data,
yaffs_ExtendedTags * eTags)
{
yaffs_Spare spare;
yaffs_Tags tags;
yaffs_ECCResult eccResult;
static yaffs_Spare spareFF;
static int init;
if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF));
init = 1;
}
if (yaffs_ReadChunkFromNAND
(dev, chunkInNAND, data, &spare, &eccResult, 1)) {
/* eTags may be NULL */
if (eTags) {
int deleted =
(yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
eTags->chunkDeleted = deleted;
eTags->eccResult = eccResult;
eTags->blockBad = 0; /* We're reading it */
/* therefore it is not a bad block */
eTags->chunkUsed =
(memcmp(&spareFF, &spare, sizeof(spareFF)) !=
0) ? 1 : 0;
if (eTags->chunkUsed) {
yaffs_GetTagsFromSpare(dev, &spare, &tags);
eTags->objectId = tags.objectId;
eTags->chunkId = tags.chunkId;
eTags->byteCount = tags.byteCount;
eTags->serialNumber = tags.serialNumber;
}
}
return YAFFS_OK;
} else {
return YAFFS_FAIL;
}
}
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int blockInNAND)
{
yaffs_Spare spare;
memset(&spare, 0xff, sizeof(yaffs_Spare));
spare.blockStatus = 'Y';
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
&spare);
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
NULL, &spare);
return YAFFS_OK;
}
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState *
state,
int *sequenceNumber)
{
yaffs_Spare spare0, spare1;
static yaffs_Spare spareFF;
static int init;
yaffs_ECCResult dummy;
if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF));
init = 1;
}
*sequenceNumber = 0;
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
&spare0, &dummy, 1);
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
&spare1, &dummy, 1);
if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
*state = YAFFS_BLOCK_STATE_DEAD;
else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
*state = YAFFS_BLOCK_STATE_EMPTY;
else
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
return YAFFS_OK;
}

View file

@ -0,0 +1,40 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_TAGSCOMPAT_H__
#define __YAFFS_TAGSCOMPAT_H__
#include "yaffs_guts.h"
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags *
tags);
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
int chunkInNAND,
__u8 * data,
yaffs_ExtendedTags *
tags);
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int blockNo);
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
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

View file

@ -0,0 +1,28 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_tagsvalidity.h"
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags)
{
memset(tags, 0, sizeof(yaffs_ExtendedTags));
tags->validMarker0 = 0xAAAAAAAA;
tags->validMarker1 = 0x55555555;
}
int yaffs_ValidateTags(yaffs_ExtendedTags * tags)
{
return (tags->validMarker0 == 0xAAAAAAAA &&
tags->validMarker1 == 0x55555555);
}

View file

@ -0,0 +1,24 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_TAGS_VALIDITY_H__
#define __YAFFS_TAGS_VALIDITY_H__
#include "yaffs_guts.h"
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
int yaffs_ValidateTags(yaffs_ExtendedTags * tags);
#endif

View file

@ -0,0 +1,21 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFSINTERFACE_H__
#define __YAFFSINTERFACE_H__
int yaffs_Initialise(unsigned nBlocks);
#endif

187
fs/yaffs2/yportenv.h Normal file
View file

@ -0,0 +1,187 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YPORTENV_H__
#define __YPORTENV_H__
#if defined CONFIG_YAFFS_WINCE
#include "ywinceenv.h"
#elif defined __KERNEL__
#include "moduleconfig.h"
/* Linux kernel */
#include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
#include <linux/config.h>
#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>
#define YCHAR char
#define YUCHAR unsigned char
#define _Y(x) x
#define yaffs_strcpy(a,b) strcpy(a,b)
#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
#define yaffs_strncmp(a,b,c) strncmp(a,b,c)
#define yaffs_strlen(s) strlen(s)
#define yaffs_sprintf sprintf
#define yaffs_toupper(a) toupper(a)
#define Y_INLINE inline
#define YAFFS_LOSTNFOUND_NAME "lost+found"
#define YAFFS_LOSTNFOUND_PREFIX "obj"
/* #define YPRINTF(x) printk x */
#define YMALLOC(x) kmalloc(x,GFP_KERNEL)
#define YFREE(x) kfree(x)
#define YMALLOC_ALT(x) vmalloc(x)
#define YFREE_ALT(x) vfree(x)
#define YMALLOC_DMA(x) YMALLOC(x)
// KR - added for use in scan so processes aren't blocked indefinitely.
#define YYIELD() schedule()
#define YAFFS_ROOT_MODE 0666
#define YAFFS_LOSTNFOUND_MODE 0666
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
#define Y_TIME_CONVERT(x) (x).tv_sec
#else
#define Y_CURRENT_TIME CURRENT_TIME
#define Y_TIME_CONVERT(x) (x)
#endif
#define yaffs_SumCompare(x,y) ((x) == (y))
#define yaffs_strcmp(a,b) strcmp(a,b)
#define TENDSTR "\n"
#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 */
#include "ydirectenv.h"
#elif defined CONFIG_YAFFS_UTIL
/* Stuff for YAFFS utilities */
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "devextras.h"
#define YMALLOC(x) malloc(x)
#define YFREE(x) free(x)
#define YMALLOC_ALT(x) malloc(x)
#define YFREE_ALT(x) free(x)
#define YCHAR char
#define YUCHAR unsigned char
#define _Y(x) x
#define yaffs_strcpy(a,b) strcpy(a,b)
#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
#define yaffs_strlen(s) strlen(s)
#define yaffs_sprintf sprintf
#define yaffs_toupper(a) toupper(a)
#define Y_INLINE inline
/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */
/* #define YALERT(s) YINFO(s) */
#define TENDSTR "\n"
#define TSTR(x) x
#define TOUT(p) printf p
#define YAFFS_LOSTNFOUND_NAME "lost+found"
#define YAFFS_LOSTNFOUND_PREFIX "obj"
/* #define YPRINTF(x) printf x */
#define YAFFS_ROOT_MODE 0666
#define YAFFS_LOSTNFOUND_MODE 0666
#define yaffs_SumCompare(x,y) ((x) == (y))
#define yaffs_strcmp(a,b) strcmp(a,b)
#else
/* Should have specified a configuration type */
#error Unknown configuration
#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.
*/
#define YAFFS_TRACE_OS 0x00000002
#define YAFFS_TRACE_ALLOCATE 0x00000004
#define YAFFS_TRACE_SCAN 0x00000008
#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
#define YAFFS_TRACE_ERASE 0x00000020
#define YAFFS_TRACE_GC 0x00000040
#define YAFFS_TRACE_WRITE 0x00000080
#define YAFFS_TRACE_TRACING 0x00000100
#define YAFFS_TRACE_DELETION 0x00000200
#define YAFFS_TRACE_BUFFERS 0x00000400
#define YAFFS_TRACE_NANDACCESS 0x00000800
#define YAFFS_TRACE_GC_DETAIL 0x00001000
#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_BUG 0x80000000
#define YAFFS_TRACE_ALWAYS 0xF0000000
#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
#ifndef CONFIG_YAFFS_WINCE
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))
#endif
#endif