1
0
Fork 0

u-boot: Update yaffs2 file system

This patch updates the yaffs2 in u-boot to correspond to
git://www.aleph1.co.uk/yaffs2
commit id 9ee5d0643e559568dbe62215f76e0a7bd5a63d93

Signed-off-by: Charles Manning <cdhmanning@gmail.com>
utp
Charles Manning 2012-05-09 16:55:17 +00:00 committed by Wolfgang Denk
parent 3874a37745
commit 753ac61088
63 changed files with 13893 additions and 10420 deletions

View File

@ -1,18 +1,37 @@
/* Yaffs commands.
* Modified by Charles Manning by adding ydevconfig command.
*
* Use ydevconfig to configure a mountpoint before use.
* For example:
* # Configure mountpt xxx using nand device 0 using blocks 100-500
* ydevconfig xxx 0 100 500
* # Mount it
* ymount xxx
* # yls, yrdm etc
* yls -l xxx
* yrdm xxx/boot-image 82000000
* ...
*/
#include <common.h>
#include <config.h>
#include <command.h>
#ifdef YAFFS2_DEBUG
#define PRINTF(fmt,args...) printf (fmt ,##args)
#ifdef YAFFS2_DEBUG
#define PRINTF(fmt, args...) printf(fmt, ##args)
#else
#define PRINTF(fmt,args...)
#define PRINTF(fmt, args...) do { } while (0)
#endif
extern void cmd_yaffs_dev_ls(void);
extern void cmd_yaffs_tracemask(unsigned set, unsigned mask);
extern void cmd_yaffs_devconfig(char *mp, int flash_dev,
int start_block, int end_block);
extern void cmd_yaffs_mount(char *mp);
extern void cmd_yaffs_umount(char *mp);
extern void cmd_yaffs_read_file(char *fn);
extern void cmd_yaffs_write_file(char *fn,char bval,int sizeOfFile);
extern void cmd_yaffs_write_file(char *fn, char bval, int sizeOfFile);
extern void cmd_yaffs_ls(const char *mountpt, int longlist);
extern void cmd_yaffs_mwrite_file(char *fn, char *addr, int size);
extern void cmd_yaffs_mread_file(char *fn, char *addr);
@ -21,193 +40,287 @@ extern void cmd_yaffs_rmdir(const char *dir);
extern void cmd_yaffs_rm(const char *path);
extern void cmd_yaffs_mv(const char *oldPath, const char *newPath);
extern int yaffs_DumpDevStruct(const char *path);
extern int yaffs_dump_dev(const char *path);
int do_ymount (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
/* ytrace - show/set yaffs trace mask */
int do_ytrace(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *mtpoint = argv[1];
cmd_yaffs_mount(mtpoint);
if (argc > 1)
cmd_yaffs_tracemask(1, simple_strtol(argv[1], NULL, 16));
else
cmd_yaffs_tracemask(0, 0);
return(0);
return 0;
}
int do_yumount (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
/* ydevls - lists yaffs mount points. */
int do_ydevls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *mtpoint = argv[1];
cmd_yaffs_umount(mtpoint);
cmd_yaffs_dev_ls();
return(0);
return 0;
}
int do_yls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
/* ydevconfig mount_pt mtd_dev_num start_block end_block */
int do_ydevconfig(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *dirname = argv[argc-1];
char *mtpoint;
int mtd_dev;
int start_block;
int end_block;
cmd_yaffs_ls(dirname, (argc>2)?1:0);
if (argc != 5) {
printf
("Bad arguments: ydevconfig mount_pt mtd_dev start_block end_block\n");
return -1;
}
return(0);
mtpoint = argv[1];
mtd_dev = simple_strtol(argv[2], NULL, 16);
start_block = simple_strtol(argv[3], NULL, 16);
end_block = simple_strtol(argv[4], NULL, 16);
cmd_yaffs_devconfig(mtpoint, mtd_dev, start_block, end_block);
return 0;
}
int do_yrd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_ymount(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *filename = argv[1];
printf ("Reading file %s ", filename);
char *mtpoint;
cmd_yaffs_read_file(filename);
if (argc != 2) {
printf("Bad arguments: ymount mount_pt\n");
return -1;
}
printf ("done\n");
return(0);
mtpoint = argv[1];
printf("Mounting yaffs2 mount point %s\n", mtpoint);
cmd_yaffs_mount(mtpoint);
return 0;
}
int do_ywr (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_yumount(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *filename = argv[1];
ulong value = simple_strtoul(argv[2], NULL, 16);
ulong numValues = simple_strtoul(argv[3], NULL, 16);
char *mtpoint;
printf ("Writing value (%lx) %lx times to %s... ", value, numValues, filename);
if (argc != 2) {
printf("Bad arguments: yumount mount_pt\n");
return -1;
}
cmd_yaffs_write_file(filename,value,numValues);
mtpoint = argv[1];
printf("Unmounting yaffs2 mount point %s\n", mtpoint);
cmd_yaffs_umount(mtpoint);
printf ("done\n");
return(0);
return 0;
}
int do_yrdm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_yls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *filename = argv[1];
ulong addr = simple_strtoul(argv[2], NULL, 16);
char *dirname;
cmd_yaffs_mread_file(filename, (char *)addr);
if (argc < 2 || argc > 3 || (argc == 3 && strcmp(argv[1], "-l"))) {
printf("Bad arguments: yls [-l] dir\n");
return -1;
}
return(0);
dirname = argv[argc - 1];
cmd_yaffs_ls(dirname, (argc > 2) ? 1 : 0);
return 0;
}
int do_ywrm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_yrd(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *filename = argv[1];
ulong addr = simple_strtoul(argv[2], NULL, 16);
ulong size = simple_strtoul(argv[3], NULL, 16);
char *filename;
cmd_yaffs_mwrite_file(filename, (char *)addr, size);
if (argc != 2) {
printf("Bad arguments: yrd file_name\n");
return -1;
}
return(0);
filename = argv[1];
printf("Reading file %s ", filename);
cmd_yaffs_read_file(filename);
printf("done\n");
return 0;
}
int do_ymkdir (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_ywr(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *dirname = argv[1];
char *filename;
ulong value;
ulong numValues;
cmd_yaffs_mkdir(dirname);
if (argc != 4) {
printf("Bad arguments: ywr file_name value n_values\n");
return -1;
}
return(0);
filename = argv[1];
value = simple_strtoul(argv[2], NULL, 16);
numValues = simple_strtoul(argv[3], NULL, 16);
printf("Writing value (%lx) %lx times to %s... ", value, numValues,
filename);
cmd_yaffs_write_file(filename, value, numValues);
printf("done\n");
return 0;
}
int do_yrmdir (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_yrdm(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *dirname = argv[1];
char *filename;
ulong addr;
cmd_yaffs_rmdir(dirname);
if (argc != 3) {
printf("Bad arguments: yrdm file_name addr\n");
return -1;
}
return(0);
filename = argv[1];
addr = simple_strtoul(argv[2], NULL, 16);
cmd_yaffs_mread_file(filename, (char *)addr);
return 0;
}
int do_yrm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_ywrm(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *path = argv[1];
char *filename;
ulong addr;
ulong size;
cmd_yaffs_rm(path);
if (argc != 4) {
printf("Bad arguments: ywrm file_name addr size\n");
return -1;
}
return(0);
filename = argv[1];
addr = simple_strtoul(argv[2], NULL, 16);
size = simple_strtoul(argv[3], NULL, 16);
cmd_yaffs_mwrite_file(filename, (char *)addr, size);
return 0;
}
int do_ymv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_ymkdir(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *oldPath = argv[1];
char *newPath = argv[2];
char *dirname;
cmd_yaffs_mv(newPath, oldPath);
if (argc != 2) {
printf("Bad arguments: ymkdir dir_name\n");
return -1;
}
return(0);
dirname = argv[1];
cmd_yaffs_mkdir(dirname);
return 0;
}
int do_ydump (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_yrmdir(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *dirname = argv[1];
if (yaffs_DumpDevStruct(dirname) != 0)
printf("yaffs_DumpDevStruct returning error when dumping path: , %s\n", dirname);
return 0;
char *dirname;
if (argc != 2) {
printf("Bad arguments: yrmdir dir_name\n");
return -1;
}
dirname = argv[1];
cmd_yaffs_rmdir(dirname);
return 0;
}
U_BOOT_CMD(
ymount, 3, 0, do_ymount,
"mount yaffs",
""
);
int do_yrm(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *name;
U_BOOT_CMD(
yumount, 3, 0, do_yumount,
"unmount yaffs",
""
);
if (argc != 2) {
printf("Bad arguments: yrm name\n");
return -1;
}
U_BOOT_CMD(
yls, 4, 0, do_yls,
"yaffs ls",
"[-l] name"
);
name = argv[1];
U_BOOT_CMD(
yrd, 2, 0, do_yrd,
"read file from yaffs",
"filename"
);
cmd_yaffs_rm(name);
U_BOOT_CMD(
ywr, 4, 0, do_ywr,
"write file to yaffs",
"filename value num_vlues"
);
return 0;
}
U_BOOT_CMD(
yrdm, 3, 0, do_yrdm,
"read file to memory from yaffs",
"filename offset"
);
int do_ymv(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *oldPath;
char *newPath;
U_BOOT_CMD(
ywrm, 4, 0, do_ywrm,
"write file from memory to yaffs",
"filename offset size"
);
if (argc != 3) {
printf("Bad arguments: ymv old_path new_path\n");
return -1;
}
U_BOOT_CMD(
ymkdir, 2, 0, do_ymkdir,
"YAFFS mkdir",
"dirname"
);
oldPath = argv[1];
newPath = argv[2];
U_BOOT_CMD(
yrmdir, 2, 0, do_yrmdir,
"YAFFS rmdir",
"dirname"
);
cmd_yaffs_mv(newPath, oldPath);
U_BOOT_CMD(
yrm, 2, 0, do_yrm,
"YAFFS rm",
"path"
);
return 0;
}
U_BOOT_CMD(
ymv, 4, 0, do_ymv,
"YAFFS mv",
"oldPath newPath"
);
U_BOOT_CMD(ytrace, 2, 0, do_ytrace,
"show/set yaffs trace mask",
"ytrace [new_mask] show/set yaffs trace mask");
U_BOOT_CMD(
ydump, 2, 0, do_ydump,
"YAFFS device struct",
"dirname"
);
U_BOOT_CMD(ydevls, 1, 0, do_ydevls,
"list yaffs mount points", "list yaffs mount points");
U_BOOT_CMD(ydevconfig, 5, 0, do_ydevconfig,
"configure yaffs mount point",
"ydevconfig mtpoint mtd_id start_block end_block configures a yaffs2 mount point");
U_BOOT_CMD(ymount, 2, 0, do_ymount,
"mount yaffs", "ymount mtpoint mounts a yaffs2 mount point");
U_BOOT_CMD(yumount, 2, 0, do_yumount,
"unmount yaffs", "yunmount mtpoint unmounts a yaffs2 mount point");
U_BOOT_CMD(yls, 3, 0, do_yls, "yaffs ls", "yls [-l] dirname");
U_BOOT_CMD(yrd, 2, 0, do_yrd,
"read file from yaffs", "yrd path read file from yaffs");
U_BOOT_CMD(ywr, 4, 0, do_ywr,
"write file to yaffs",
"ywr filename value num_vlues write values to yaffs file");
U_BOOT_CMD(yrdm, 3, 0, do_yrdm,
"read file to memory from yaffs",
"yrdm filename offset reads yaffs file into memory");
U_BOOT_CMD(ywrm, 4, 0, do_ywrm,
"write file from memory to yaffs",
"ywrm filename offset size writes memory to yaffs file");
U_BOOT_CMD(ymkdir, 2, 0, do_ymkdir,
"YAFFS mkdir", "ymkdir dir create a yaffs directory");
U_BOOT_CMD(yrmdir, 2, 0, do_yrmdir,
"YAFFS rmdir", "yrmdir dirname removes a yaffs directory");
U_BOOT_CMD(yrm, 2, 0, do_yrm, "YAFFS rm", "yrm path removes a yaffs file");
U_BOOT_CMD(ymv, 4, 0, do_ymv,
"YAFFS mv",
"ymv old_path new_path moves/rename files within a yaffs mount point");

View File

@ -16,28 +16,43 @@
#
# $Id: Makefile,v 1.15 2007/07/18 19:40:38 charles Exp $
#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
include $(TOPDIR)/config.mk
LIB = $(obj)libyaffs2.o
COBJS-$(CONFIG_YAFFS2) := \
yaffscfg.o yaffs_ecc.o yaffsfs.o yaffs_guts.o yaffs_packedtags1.o \
yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o \
yaffs_nand.o yaffs_checkptrw.o yaffs_qsort.o yaffs_mtdif.o \
yaffs_mtdif2.o
yaffs_allocator.o yaffs_attribs.o yaffs_bitmap.o yaffs_uboot_glue.o\
yaffs_checkptrw.o yaffs_ecc.o yaffs_error.o \
yaffsfs.o yaffs_guts.o yaffs_hweight.o yaffs_nameval.o yaffs_nand.o\
yaffs_packedtags1.o yaffs_packedtags2.o yaffs_qsort.o \
yaffs_summary.o yaffs_tagscompat.o yaffs_verify.o yaffs_yaffs1.o \
yaffs_yaffs2.o yaffs_mtdif.o yaffs_mtdif2.o
SRCS := $(COBJS-y:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS-y))
# -DCONFIG_YAFFS_NO_YAFFS1
CFLAGS += -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -DLINUX_VERSION_CODE=0x20622
YCFLAGS = -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM
YCFLAGS += -DCONFIG_YAFFS_YAFFS2 -DNO_Y_INLINE
YCFLAGS += -DCONFIG_YAFFS_PROVIDE_DEFS -DCONFIG_YAFFSFS_PROVIDE_VALUES
CFLAGS += $(YCFLAGS)
CPPFLAGS += $(YCFLAGS)
all: $(LIB)
$(LIB): $(obj).depend $(OBJS)
$(obj)libyaffs2.a: $(obj).depend $(OBJS)
$(AR) $(ARFLAGS) $@ $(OBJS)
$(obj)libyaffs2.o: $(obj).depend $(OBJS)
$(call cmd_link_o_target, $(OBJS))
.PHONY: clean distclean
clean:
rm -f $(OBJS)
distclean: clean
rm -f $(LIB) core *.bak .depend
#########################################################################
# defines $(obj).depend target

View File

@ -1,201 +0,0 @@
Welcome to YAFFS, the first file system developed specifically for NAND flash.
It is now YAFFS2 - original YAFFS (AYFFS1) only supports 512-byte page
NAND and is now 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

@ -1,275 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* 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
/* XXX U-BOOT XXX */
#if 1 /* !(defined __KERNEL__) || (defined WIN32) */
/* User space defines */
/* XXX U-BOOT XXX */
#if 0
typedef unsigned char __u8;
typedef unsigned short __u16;
typedef unsigned __u32;
#endif
#include <asm/types.h>
/*
* 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
/* XXX U-BOOT XXX */
#if 0
#include <sys/stat.h>
#else
#include "common.h"
#endif
#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

View File

@ -0,0 +1 @@
/* Dummy header for u-boot */

View File

@ -0,0 +1 @@
/* Dummy header for u-boot */

View File

@ -0,0 +1,4 @@
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <common.h>

View File

@ -0,0 +1,356 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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_allocator.h"
#include "yaffs_guts.h"
#include "yaffs_trace.h"
#include "yportenv.h"
/*
* Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
* of approx 100 objects that are themn allocated singly.
* This is basically a simplified slab allocator.
*
* We don't use the Linux slab allocator because slab does not allow
* us to dump all the objects in one hit when we do a umount and tear
* down all the tnodes and objects. slab requires that we first free
* the individual objects.
*
* Once yaffs has been mainlined I shall try to motivate for a change
* to slab to provide the extra features we need here.
*/
struct yaffs_tnode_list {
struct yaffs_tnode_list *next;
struct yaffs_tnode *tnodes;
};
struct yaffs_obj_list {
struct yaffs_obj_list *next;
struct yaffs_obj *objects;
};
struct yaffs_allocator {
int n_tnodes_created;
struct yaffs_tnode *free_tnodes;
int n_free_tnodes;
struct yaffs_tnode_list *alloc_tnode_list;
int n_obj_created;
struct list_head free_objs;
int n_free_objects;
struct yaffs_obj_list *allocated_obj_list;
};
static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator =
(struct yaffs_allocator *)dev->allocator;
struct yaffs_tnode_list *tmp;
if (!allocator) {
BUG();
return;
}
while (allocator->alloc_tnode_list) {
tmp = allocator->alloc_tnode_list->next;
kfree(allocator->alloc_tnode_list->tnodes);
kfree(allocator->alloc_tnode_list);
allocator->alloc_tnode_list = tmp;
}
allocator->free_tnodes = NULL;
allocator->n_free_tnodes = 0;
allocator->n_tnodes_created = 0;
}
static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator = dev->allocator;
if (!allocator) {
BUG();
return;
}
allocator->alloc_tnode_list = NULL;
allocator->free_tnodes = NULL;
allocator->n_free_tnodes = 0;
allocator->n_tnodes_created = 0;
}
static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
{
struct yaffs_allocator *allocator =
(struct yaffs_allocator *)dev->allocator;
int i;
struct yaffs_tnode *new_tnodes;
u8 *mem;
struct yaffs_tnode *curr;
struct yaffs_tnode *next;
struct yaffs_tnode_list *tnl;
if (!allocator) {
BUG();
return YAFFS_FAIL;
}
if (n_tnodes < 1)
return YAFFS_OK;
/* make these things */
new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
mem = (u8 *) new_tnodes;
if (!new_tnodes) {
yaffs_trace(YAFFS_TRACE_ERROR,
"yaffs: Could not allocate Tnodes");
return YAFFS_FAIL;
}
/* New hookup for wide tnodes */
for (i = 0; i < n_tnodes - 1; i++) {
curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
curr->internal[0] = next;
}
curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
curr->internal[0] = allocator->free_tnodes;
allocator->free_tnodes = (struct yaffs_tnode *)mem;
allocator->n_free_tnodes += n_tnodes;
allocator->n_tnodes_created += n_tnodes;
/* Now add this bunch of tnodes to a list for freeing up.
* NB If we can't add this to the management list it isn't fatal
* but it just means we can't free this bunch of tnodes later.
*/
tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
if (!tnl) {
yaffs_trace(YAFFS_TRACE_ERROR,
"Could not add tnodes to management list");
return YAFFS_FAIL;
} else {
tnl->tnodes = new_tnodes;
tnl->next = allocator->alloc_tnode_list;
allocator->alloc_tnode_list = tnl;
}
yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
return YAFFS_OK;
}
struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator =
(struct yaffs_allocator *)dev->allocator;
struct yaffs_tnode *tn = NULL;
if (!allocator) {
BUG();
return NULL;
}
/* If there are none left make more */
if (!allocator->free_tnodes)
yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
if (allocator->free_tnodes) {
tn = allocator->free_tnodes;
allocator->free_tnodes = allocator->free_tnodes->internal[0];
allocator->n_free_tnodes--;
}
return tn;
}
/* FreeTnode frees up a tnode and puts it back on the free list */
void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
{
struct yaffs_allocator *allocator = dev->allocator;
if (!allocator) {
BUG();
return;
}
if (tn) {
tn->internal[0] = allocator->free_tnodes;
allocator->free_tnodes = tn;
allocator->n_free_tnodes++;
}
dev->checkpoint_blocks_required = 0; /* force recalculation */
}
/*--------------- yaffs_obj alloaction ------------------------
*
* Free yaffs_objs are stored in a list using obj->siblings.
* The blocks of allocated objects are stored in a linked list.
*/
static void yaffs_init_raw_objs(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator = dev->allocator;
if (!allocator) {
BUG();
return;
}
allocator->allocated_obj_list = NULL;
INIT_LIST_HEAD(&allocator->free_objs);
allocator->n_free_objects = 0;
}
static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator = dev->allocator;
struct yaffs_obj_list *tmp;
if (!allocator) {
BUG();
return;
}
while (allocator->allocated_obj_list) {
tmp = allocator->allocated_obj_list->next;
kfree(allocator->allocated_obj_list->objects);
kfree(allocator->allocated_obj_list);
allocator->allocated_obj_list = tmp;
}
INIT_LIST_HEAD(&allocator->free_objs);
allocator->n_free_objects = 0;
allocator->n_obj_created = 0;
}
static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
{
struct yaffs_allocator *allocator = dev->allocator;
int i;
struct yaffs_obj *new_objs;
struct yaffs_obj_list *list;
if (!allocator) {
BUG();
return YAFFS_FAIL;
}
if (n_obj < 1)
return YAFFS_OK;
/* make these things */
new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
if (!new_objs || !list) {
kfree(new_objs);
new_objs = NULL;
kfree(list);
list = NULL;
yaffs_trace(YAFFS_TRACE_ALLOCATE,
"Could not allocate more objects");
return YAFFS_FAIL;
}
/* Hook them into the free list */
for (i = 0; i < n_obj; i++)
list_add(&new_objs[i].siblings, &allocator->free_objs);
allocator->n_free_objects += n_obj;
allocator->n_obj_created += n_obj;
/* Now add this bunch of Objects to a list for freeing up. */
list->objects = new_objs;
list->next = allocator->allocated_obj_list;
allocator->allocated_obj_list = list;
return YAFFS_OK;
}
struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
{
struct yaffs_obj *obj = NULL;
struct list_head *lh;
struct yaffs_allocator *allocator = dev->allocator;
if (!allocator) {
BUG();
return obj;
}
/* If there are none left make more */
if (list_empty(&allocator->free_objs))
yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
if (!list_empty(&allocator->free_objs)) {
lh = allocator->free_objs.next;
obj = list_entry(lh, struct yaffs_obj, siblings);
list_del_init(lh);
allocator->n_free_objects--;
}
return obj;
}
void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
{
struct yaffs_allocator *allocator = dev->allocator;
if (!allocator) {
BUG();
return;
}
/* Link into the free list. */
list_add(&obj->siblings, &allocator->free_objs);
allocator->n_free_objects++;
}
void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
{
if (!dev->allocator) {
BUG();
return;
}
yaffs_deinit_raw_tnodes(dev);
yaffs_deinit_raw_objs(dev);
kfree(dev->allocator);
dev->allocator = NULL;
}
void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator;
if (dev->allocator) {
BUG();
return;
}
allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
if (allocator) {
dev->allocator = allocator;
yaffs_init_raw_tnodes(dev);
yaffs_init_raw_objs(dev);
}
}

View File

@ -0,0 +1,30 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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_ALLOCATOR_H__
#define __YAFFS_ALLOCATOR_H__
#include "yaffs_guts.h"
void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
#endif

View File

@ -0,0 +1,152 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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_attribs.h"
void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
{
obj->yst_uid = oh->yst_uid;
obj->yst_gid = oh->yst_gid;
obj->yst_atime = oh->yst_atime;
obj->yst_mtime = oh->yst_mtime;
obj->yst_ctime = oh->yst_ctime;
obj->yst_rdev = oh->yst_rdev;
}
void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
{
#ifdef CONFIG_YAFFS_WINCE
oh->win_atime[0] = obj->win_atime[0];
oh->win_ctime[0] = obj->win_ctime[0];
oh->win_mtime[0] = obj->win_mtime[0];
oh->win_atime[1] = obj->win_atime[1];
oh->win_ctime[1] = obj->win_ctime[1];
oh->win_mtime[1] = obj->win_mtime[1];
#else
oh->yst_uid = obj->yst_uid;
oh->yst_gid = obj->yst_gid;
oh->yst_atime = obj->yst_atime;
oh->yst_mtime = obj->yst_mtime;
oh->yst_ctime = obj->yst_ctime;
oh->yst_rdev = obj->yst_rdev;
#endif
}
void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
{
#ifdef CONFIG_YAFFS_WINCE
yfsd_win_file_time_now(obj->win_atime);
obj->win_ctime[0] = obj->win_mtime[0] = obj->win_atime[0];
obj->win_ctime[1] = obj->win_mtime[1] = obj->win_atime[1];
#else
yaffs_load_current_time(obj, 1, 1);
obj->yst_rdev = rdev;
obj->yst_uid = uid;
obj->yst_gid = gid;
#endif
}
void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
{
#ifdef CONFIG_YAFFS_WINCE
yfsd_win_file_time_now(the_obj->win_atime);
the_obj->win_ctime[0] = the_obj->win_mtime[0] =
the_obj->win_atime[0];
the_obj->win_ctime[1] = the_obj->win_mtime[1] =
the_obj->win_atime[1];
#else
obj->yst_mtime = Y_CURRENT_TIME;
if (do_a)
obj->yst_atime = obj->yst_atime;
if (do_c)
obj->yst_ctime = obj->yst_atime;
#endif
}
loff_t yaffs_get_file_size(struct yaffs_obj *obj)
{
YCHAR *alias = NULL;
obj = yaffs_get_equivalent_obj(obj);
switch (obj->variant_type) {
case YAFFS_OBJECT_TYPE_FILE:
return obj->variant.file_variant.file_size;
case YAFFS_OBJECT_TYPE_SYMLINK:
alias = obj->variant.symlink_variant.alias;
if (!alias)
return 0;
return yaffs_strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
default:
return 0;
}
}
int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
{
unsigned int valid = attr->ia_valid;
if (valid & ATTR_MODE)
obj->yst_mode = attr->ia_mode;
if (valid & ATTR_UID)
obj->yst_uid = attr->ia_uid;
if (valid & ATTR_GID)
obj->yst_gid = attr->ia_gid;
if (valid & ATTR_ATIME)
obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
if (valid & ATTR_CTIME)
obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
if (valid & ATTR_MTIME)
obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
if (valid & ATTR_SIZE)
yaffs_resize_file(obj, attr->ia_size);
yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
return YAFFS_OK;
}
int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
{
unsigned int valid = 0;
attr->ia_mode = obj->yst_mode;
valid |= ATTR_MODE;
attr->ia_uid = obj->yst_uid;
valid |= ATTR_UID;
attr->ia_gid = obj->yst_gid;
valid |= ATTR_GID;
Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
valid |= ATTR_ATIME;
Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
valid |= ATTR_CTIME;
Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
valid |= ATTR_MTIME;
attr->ia_size = yaffs_get_file_size(obj);
valid |= ATTR_SIZE;
attr->ia_valid = valid;
return YAFFS_OK;
}

View File

@ -0,0 +1,28 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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_ATTRIBS_H__
#define __YAFFS_ATTRIBS_H__
#include "yaffs_guts.h"
void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
#endif

View File

@ -0,0 +1,97 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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_bitmap.h"
#include "yaffs_trace.h"
/*
* Chunk bitmap manipulations
*/
static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
{
if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
yaffs_trace(YAFFS_TRACE_ERROR,
"BlockBits block %d is not valid",
blk);
BUG();
}
return dev->chunk_bits +
(dev->chunk_bit_stride * (blk - dev->internal_start_block));
}
void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
{
if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
chunk < 0 || chunk >= dev->param.chunks_per_block) {
yaffs_trace(YAFFS_TRACE_ERROR,
"Chunk Id (%d:%d) invalid",
blk, chunk);
BUG();
}
}
void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
memset(blk_bits, 0, dev->chunk_bit_stride);
}
void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk);
blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
}
void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk);
blk_bits[chunk / 8] |= (1 << (chunk & 7));
}
int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk);
return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
}
int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
int i;
for (i = 0; i < dev->chunk_bit_stride; i++) {
if (*blk_bits)
return 1;
blk_bits++;
}
return 0;
}
int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
int i;
int n = 0;
for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
n += hweight8(*blk_bits);
return n;
}

View File

@ -0,0 +1,33 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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.
*/
/*
* Chunk bitmap manipulations
*/
#ifndef __YAFFS_BITMAP_H__
#define __YAFFS_BITMAP_H__
#include "yaffs_guts.h"
void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
#endif

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -11,395 +11,398 @@
* published by the Free Software Foundation.
*/
/* XXX U-BOOT XXX */
#include <common.h>
#include <malloc.h>
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"
#include "yaffs_getblockinfo.h"
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
{
int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"checkpt blocks_avail = %d", blocks_avail);
T(YAFFS_TRACE_CHECKPOINT,
(TSTR("checkpt blocks available = %d" TENDSTR),
blocksAvailable));
return (blocksAvailable <= 0) ? 0 : 1;
return (blocks_avail <= 0) ? 0 : 1;
}
static int yaffs_CheckpointErase(yaffs_Device *dev)
static int yaffs_checkpt_erase(struct yaffs_dev *dev)
{
int i;
if(!dev->eraseBlockInNAND)
if (!dev->param.erase_fn)
return 0;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
dev->internalStartBlock,dev->internalEndBlock));
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"checking blocks %d to %d",
dev->internal_start_block, dev->internal_end_block);
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;
for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"erasing checkpt block %d", i);
dev->n_erasures++;
if (dev->param.
erase_fn(dev,
i - dev->block_offset /* realign */)) {
bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
dev->n_erased_blocks++;
dev->n_free_chunks +=
dev->param.chunks_per_block;
} else {
dev->param.bad_block_fn(dev, i);
bi->block_state = YAFFS_BLOCK_STATE_DEAD;
}
}
}
dev->blocksInCheckpoint = 0;
dev->blocks_in_checkpt = 0;
return 1;
}
static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *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));
int i;
int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
if(dev->checkpointNextBlock >= 0 &&
dev->checkpointNextBlock <= dev->internalEndBlock &&
blocksAvailable > 0){
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"allocating checkpt block: erased %d reserved %d avail %d next %d ",
dev->n_erased_blocks, dev->param.n_reserved_blocks,
blocks_avail, dev->checkpt_next_block);
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));
if (dev->checkpt_next_block >= 0 &&
dev->checkpt_next_block <= dev->internal_end_block &&
blocks_avail > 0) {
for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
i++) {
struct yaffs_block_info *bi =
yaffs_get_block_info(dev, i);
if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
dev->checkpt_next_block = i + 1;
dev->checkpt_cur_block = i;
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"allocating checkpt block %d", i);
return;
}
}
}
T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
dev->checkpointNextBlock = -1;
dev->checkpointCurrentBlock = -1;
dev->checkpt_next_block = -1;
dev->checkpt_cur_block = -1;
}
static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
{
int i;
yaffs_ExtendedTags tags;
int i;
struct yaffs_ext_tags tags;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
dev->blocksInCheckpoint, dev->checkpointNextBlock));
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"find next checkpt block: start: blocks %d next %d",
dev->blocks_in_checkpt, dev->checkpt_next_block);
if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
int chunk = i * dev->nChunksPerBlock;
int realignedChunk = chunk - dev->chunkOffset;
if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
i++) {
int chunk = i * dev->param.chunks_per_block;
int realigned_chunk = chunk - dev->chunk_offset;
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));
dev->param.read_chunk_tags_fn(dev, realigned_chunk,
NULL, &tags);
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"find next checkpt block: search: block %d oid %d seq %d eccr %d",
i, tags.obj_id, tags.seq_number,
tags.ecc_result);
if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
if (tags.seq_number == 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));
dev->checkpt_next_block = tags.obj_id;
dev->checkpt_cur_block = i;
dev->checkpt_block_list[dev->
blocks_in_checkpt] = i;
dev->blocks_in_checkpt++;
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"found checkpt block %d", i);
return;
}
}
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
dev->checkpointNextBlock = -1;
dev->checkpointCurrentBlock = -1;
dev->checkpt_next_block = -1;
dev->checkpt_cur_block = -1;
}
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
{
int i;
dev->checkpt_open_write = writing;
/* Got the functions we need? */
if (!dev->writeChunkWithTagsToNAND ||
!dev->readChunkWithTagsFromNAND ||
!dev->eraseBlockInNAND ||
!dev->markNANDBlockBad)
if (!dev->param.write_chunk_tags_fn ||
!dev->param.read_chunk_tags_fn ||
!dev->param.erase_fn || !dev->param.bad_block_fn)
return 0;
if(forWriting && !yaffs_CheckpointSpaceOk(dev))
if (writing && !yaffs2_checkpt_space_ok(dev))
return 0;
if(!dev->checkpointBuffer)
dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
if(!dev->checkpointBuffer)
if (!dev->checkpt_buffer)
dev->checkpt_buffer =
kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
if (!dev->checkpt_buffer)
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;
dev->checkpt_page_seq = 0;
dev->checkpt_byte_count = 0;
dev->checkpt_sum = 0;
dev->checkpt_xor = 0;
dev->checkpt_cur_block = -1;
dev->checkpt_cur_chunk = -1;
dev->checkpt_next_block = dev->internal_start_block;
/* 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;
if (writing) {
memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
dev->checkpt_byte_offs = 0;
return yaffs_checkpt_erase(dev);
}
return 1;
}
/* Set to a value that will kick off a read */
dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
/* A checkpoint block list of 1 checkpoint block per 16 block is
* (hopefully) going to be way more than we need */
dev->blocks_in_checkpt = 0;
dev->checkpt_max_blocks =
(dev->internal_end_block - dev->internal_start_block) / 16 + 2;
dev->checkpt_block_list =
kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
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)
if (!dev->checkpt_block_list)
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){
for (i = 0; i < dev->checkpt_max_blocks; i++)
dev->checkpt_block_list[i] = -1;
return 1;
}
int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
{
u32 composite_sum;
composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
*sum = composite_sum;
return 1;
}
static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
{
int chunk;
int realigned_chunk;
struct yaffs_ext_tags tags;
if (dev->checkpt_cur_block < 0) {
yaffs2_checkpt_find_erased_block(dev);
dev->checkpt_cur_chunk = 0;
}
if (dev->checkpt_cur_block < 0)
return 0;
tags.is_deleted = 0;
tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
tags.chunk_id = dev->checkpt_page_seq + 1;
tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
tags.n_bytes = dev->data_bytes_per_chunk;
if (dev->checkpt_cur_chunk == 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++;
struct yaffs_block_info *bi =
yaffs_get_block_info(dev, dev->checkpt_cur_block);
bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
dev->blocks_in_checkpt++;
}
chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
chunk =
dev->checkpt_cur_block * dev->param.chunks_per_block +
dev->checkpt_cur_chunk;
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
tags.obj_id, tags.chunk_id);
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));
realigned_chunk = chunk - dev->chunk_offset;
realignedChunk = chunk - dev->chunkOffset;
dev->n_page_writes++;
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;
dev->param.write_chunk_tags_fn(dev, realigned_chunk,
dev->checkpt_buffer, &tags);
dev->checkpt_byte_offs = 0;
dev->checkpt_page_seq++;
dev->checkpt_cur_chunk++;
if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
dev->checkpt_cur_chunk = 0;
dev->checkpt_cur_block = -1;
}
memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
return 1;
}
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
{
int i=0;
int i = 0;
int ok = 1;
u8 *data_bytes = (u8 *) data;
__u8 * dataBytes = (__u8 *)data;
if(!dev->checkpointBuffer)
if (!dev->checkpt_buffer)
return 0;
if(!dev->checkpointOpenForWrite)
if (!dev->checkpt_open_write)
return -1;
while(i < nBytes && ok) {
while (i < n_bytes && ok) {
dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
dev->checkpt_sum += *data_bytes;
dev->checkpt_xor ^= *data_bytes;
dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
dev->checkpointSum += *dataBytes;
dev->checkpointXor ^= *dataBytes;
dev->checkpointByteOffset++;
dev->checkpt_byte_offs++;
i++;
dataBytes++;
dev->checkpointByteCount++;
if(dev->checkpointByteOffset < 0 ||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
ok = yaffs_CheckpointFlushBuffer(dev);
data_bytes++;
dev->checkpt_byte_count++;
if (dev->checkpt_byte_offs < 0 ||
dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
ok = yaffs2_checkpt_flush_buffer(dev);
}
return i;
return i;
}
int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
{
int i=0;
int i = 0;
int ok = 1;
yaffs_ExtendedTags tags;
struct yaffs_ext_tags tags;
int chunk;
int realignedChunk;
int realigned_chunk;
u8 *data_bytes = (u8 *) data;
__u8 *dataBytes = (__u8 *)data;
if(!dev->checkpointBuffer)
if (!dev->checkpt_buffer)
return 0;
if(dev->checkpointOpenForWrite)
if (dev->checkpt_open_write)
return -1;
while(i < nBytes && ok) {
while (i < n_bytes && ok) {
if (dev->checkpt_byte_offs < 0 ||
dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
if(dev->checkpointByteOffset < 0 ||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
if(dev->checkpointCurrentBlock < 0){
yaffs_CheckpointFindNextCheckpointBlock(dev);
dev->checkpointCurrentChunk = 0;
if (dev->checkpt_cur_block < 0) {
yaffs2_checkpt_find_block(dev);
dev->checkpt_cur_chunk = 0;
}
if(dev->checkpointCurrentBlock < 0)
if (dev->checkpt_cur_block < 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;
break;
}
chunk = dev->checkpt_cur_block *
dev->param.chunks_per_block +
dev->checkpt_cur_chunk;
realigned_chunk = chunk - dev->chunk_offset;
dev->n_page_reads++;
/* read in the next chunk */
dev->param.read_chunk_tags_fn(dev,
realigned_chunk,
dev->checkpt_buffer,
&tags);
if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {
ok = 0;
break;
}
dev->checkpt_byte_offs = 0;
dev->checkpt_page_seq++;
dev->checkpt_cur_chunk++;
if (dev->checkpt_cur_chunk >=
dev->param.chunks_per_block)
dev->checkpt_cur_block = -1;
}
if(ok){
*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
dev->checkpointSum += *dataBytes;
dev->checkpointXor ^= *dataBytes;
dev->checkpointByteOffset++;
i++;
dataBytes++;
dev->checkpointByteCount++;
}
*data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
dev->checkpt_sum += *data_bytes;
dev->checkpt_xor ^= *data_bytes;
dev->checkpt_byte_offs++;
i++;
data_bytes++;
dev->checkpt_byte_count++;
}
return i;
return i;
}
int yaffs_CheckpointClose(yaffs_Device *dev)
int yaffs_checkpt_close(struct yaffs_dev *dev)
{
int i;
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...
}
if (dev->checkpt_open_write) {
if (dev->checkpt_byte_offs != 0)
yaffs2_checkpt_flush_buffer(dev);
} else if (dev->checkpt_block_list) {
for (i = 0;
i < dev->blocks_in_checkpt &&
dev->checkpt_block_list[i] >= 0; i++) {
int blk = dev->checkpt_block_list[i];
struct yaffs_block_info *bi = NULL;
if (dev->internal_start_block <= blk &&
blk <= dev->internal_end_block)
bi = yaffs_get_block_info(dev, blk);
if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
}
YFREE(dev->checkpointBlockList);
dev->checkpointBlockList = NULL;
kfree(dev->checkpt_block_list);
dev->checkpt_block_list = NULL;
}
dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
dev->nErasedBlocks -= dev->blocksInCheckpoint;
dev->n_free_chunks -=
dev->blocks_in_checkpt * dev->param.chunks_per_block;
dev->n_erased_blocks -= dev->blocks_in_checkpt;
yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
dev->checkpt_byte_count);
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
dev->checkpointByteCount));
if(dev->checkpointBuffer){
if (dev->checkpt_buffer) {
/* free the buffer */
YFREE(dev->checkpointBuffer);
dev->checkpointBuffer = NULL;
kfree(dev->checkpt_buffer);
dev->checkpt_buffer = NULL;
return 1;
} else {
return 0;
}
else
return 0;
}
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
{
/* Erase the first checksum block */
/* Erase the checkpoint data */
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"checkpoint invalidate of %d blocks",
dev->blocks_in_checkpt);
if(!yaffs_CheckpointSpaceOk(dev))
return 0;
return yaffs_CheckpointErase(dev);
return yaffs_checkpt_erase(dev);
}

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -18,17 +18,16 @@
#include "yaffs_guts.h"
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes);
int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes);
int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
int yaffs_CheckpointClose(yaffs_Device *dev);
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
int yaffs_checkpt_close(struct yaffs_dev *dev);
int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
#endif

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -16,28 +16,22 @@
*
* 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.
* 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.
*/
/* XXX U-BOOT XXX */
#include <common.h>
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"
/* 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.
*/
static const unsigned char column_parity_table[] = {
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
@ -73,35 +67,11 @@ static const unsigned char column_parity_table[] = {
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)
void yaffs_ecc_calc(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;
@ -112,12 +82,10 @@ void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
b = column_parity_table[*data++];
col_parity ^= b;
if (b & 0x01) // odd number of bits in the byte
{
if (b & 0x01) { /* odd number of bits in the byte */
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
ecc[2] = (~col_parity) | 0x03;
@ -160,19 +128,12 @@ void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
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)
int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc)
{
unsigned char d0, d1, d2; /* deltas */
@ -181,7 +142,7 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
d2 = read_ecc[2] ^ test_ecc[2];
if ((d0 | d1 | d2) == 0)
return 0; /* no error */
return 0; /* no error */
if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
@ -191,15 +152,6 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
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)
@ -228,19 +180,17 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
data[byte] ^= (1 << bit);
return 1; /* Corrected the error */
return 1; /* Corrected the error */
}
if ((yaffs_CountBits(d0) +
yaffs_CountBits(d1) +
yaffs_CountBits(d2)) == 1) {
if ((hweight8(d0) + hweight8(d1) + hweight8(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 */
return 1; /* Corrected the error */
}
/* Unrecoverable error */
@ -249,25 +199,23 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
}
/*
* ECCxxxOther does ECC calcs on arbitrary n bytes of data
*/
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
yaffs_ECCOther * eccOther)
void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
struct yaffs_ecc_other *ecc_other)
{
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++) {
for (i = 0; i < n_bytes; i++) {
b = column_parity_table[*data++];
col_parity ^= b;
if (b & 0x01) {
if (b & 0x01) {
/* odd number of bits in the byte */
line_parity ^= i;
line_parity_prime ^= ~i;
@ -275,59 +223,59 @@ void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
}
eccOther->colParity = (col_parity >> 2) & 0x3f;
eccOther->lineParity = line_parity;
eccOther->lineParityPrime = line_parity_prime;
ecc_other->col_parity = (col_parity >> 2) & 0x3f;
ecc_other->line_parity = line_parity;
ecc_other->line_parity_prime = line_parity_prime;
}
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
yaffs_ECCOther * read_ecc,
const yaffs_ECCOther * test_ecc)
int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
struct yaffs_ecc_other *read_ecc,
const struct yaffs_ecc_other *test_ecc)
{
unsigned char cDelta; /* column parity delta */
unsigned lDelta; /* line parity delta */
unsigned lDeltaPrime; /* line parity delta */
unsigned char delta_col; /* column parity delta */
unsigned delta_line; /* line parity delta */
unsigned delta_line_prime; /* 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;
delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
delta_line_prime =
read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
if ((cDelta | lDelta | lDeltaPrime) == 0)
return 0; /* no error */
if ((delta_col | delta_line | delta_line_prime) == 0)
return 0; /* no error */
if (lDelta == ~lDeltaPrime &&
(((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15))
{
if (delta_line == ~delta_line_prime &&
(((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
/* Single bit (recoverable) error in data */
bit = 0;
if (cDelta & 0x20)
if (delta_col & 0x20)
bit |= 0x04;
if (cDelta & 0x08)
if (delta_col & 0x08)
bit |= 0x02;
if (cDelta & 0x02)
if (delta_col & 0x02)
bit |= 0x01;
if(lDelta >= nBytes)
if (delta_line >= n_bytes)
return -1;
data[lDelta] ^= (1 << bit);
data[delta_line] ^= (1 << bit);
return 1; /* corrected */
return 1; /* corrected */
}
if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
yaffs_CountBits(cDelta)) == 1) {
if ((hweight32(delta_line) +
hweight32(delta_line_prime) +
hweight8(delta_col)) == 1) {
/* Reccoverable error in ecc */
*read_ecc = *test_ecc;
return 1; /* corrected */
return 1; /* corrected */
}
/* Unrecoverable error */
return -1;
}

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -13,32 +13,32 @@
* 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.
*
*/
/*
* 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;
struct yaffs_ecc_other {
unsigned char col_parity;
unsigned line_parity;
unsigned line_parity_prime;
};
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_ecc_calc(const unsigned char *data, unsigned char *ecc);
int yaffs_ecc_correct(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);
void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
struct yaffs_ecc_other *ecc);
int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
struct yaffs_ecc_other *read_ecc,
const struct yaffs_ecc_other *test_ecc);
#endif

View File

@ -0,0 +1,58 @@
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Timothy Manning <timothy@yaffs.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffsfs.h"
struct error_entry {
int code;
const char *text;
};
static const struct error_entry error_list[] = {
{ ENOMEM , "ENOMEM" },
{ EBUSY , "EBUSY"},
{ ENODEV , "ENODEV"},
{ EINVAL , "EINVAL"},
{ EBADF , "EBADF"},
{ EACCES , "EACCES"},
{ EXDEV , "EXDEV" },
{ ENOENT , "ENOENT"},
{ ENOSPC , "ENOSPC"},
{ ERANGE , "ERANGE"},
{ ENODATA, "ENODATA"},
{ ENOTEMPTY, "ENOTEMPTY"},
{ ENAMETOOLONG, "ENAMETOOLONG"},
{ ENOMEM , "ENOMEM"},
{ EEXIST , "EEXIST"},
{ ENOTDIR , "ENOTDIR"},
{ EISDIR , "EISDIR"},
{ ENFILE, "ENFILE"},
{ EROFS, "EROFS"},
{ EFAULT, "EFAULT"},
{ 0, NULL }
};
const char *yaffs_error_to_str(int err)
{
const struct error_entry *e = error_list;
if (err < 0)
err = -err;
while (e->code && e->text) {
if (err == e->code)
return e->text;
e++;
}
return "Unknown error code";
}

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -18,14 +18,18 @@
#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);
int yflash_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber);
int yflash_WriteChunkToNAND(struct yaffs_dev *dev, int nand_chunk,
const u8 *data, const struct yaffs_spare *spare);
int yflash_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk,
const u8 *data, const struct yaffs_ext_tags *tags);
int yflash_ReadChunkFromNAND(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_spare *spare);
int yflash_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_ext_tags *tags);
int yflash_InitialiseNAND(struct yaffs_dev *dev);
int yflash_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no);
int yflash_QueryNANDBlock(struct yaffs_dev *dev, int block_no,
enum yaffs_block_state *state, u32 *seq_number);
#endif

View File

@ -0,0 +1,35 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_FLASH2_H__
#define __YAFFS_FLASH2_H__
#include "yaffs_guts.h"
int yflash2_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber);
int yflash2_WriteChunkToNAND(struct yaffs_dev *dev, int nand_chunk,
const u8 *data, const struct yaffs_spare *spare);
int yflash2_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk,
const u8 *data, const struct yaffs_ext_tags *tags);
int yflash2_ReadChunkFromNAND(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_spare *spare);
int yflash2_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_ext_tags *tags);
int yflash2_InitialiseNAND(struct yaffs_dev *dev);
int yflash2_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no);
int yflash2_QueryNANDBlock(struct yaffs_dev *dev, int block_no,
enum yaffs_block_state *state, u32 *seq_number);
#endif

View File

@ -0,0 +1,35 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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_GETBLOCKINFO_H__
#define __YAFFS_GETBLOCKINFO_H__
#include "yaffs_guts.h"
#include "yaffs_trace.h"
/* Function to manipulate block info */
static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
*dev, int blk)
{
if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>> yaffs: get_block_info block %d is not valid",
blk);
BUG();
}
return &dev->block_info[blk - dev->internal_start_block];
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* These functions have been renamed to hweightxx to match the
* equivaqlent functions in the Linux kernel.
*/
#include "yaffs_hweight.h"
static const char yaffs_count_bits_table[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_hweight8(u8 x)
{
int ret_val;
ret_val = yaffs_count_bits_table[x];
return ret_val;
}
int yaffs_hweight32(u32 x)
{
return yaffs_hweight8(x & 0xff) +
yaffs_hweight8((x >> 8) & 0xff) +
yaffs_hweight8((x >> 16) & 0xff) +
yaffs_hweight8((x >> 24) & 0xff);
}

View File

@ -1,8 +1,7 @@
#ifndef __YAFFS_MALLOC_H__
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -14,12 +13,12 @@
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/* XXX U-BOOT XXX */
#if 0
#include <stdlib.h>
#endif
#ifndef __YAFFS_HWEIGHT_H__
#define __YAFFS_HWEIGHT_H__
void *yaffs_malloc(size_t size);
void yaffs_free(void *ptr);
#include "yportenv.h"
int yaffs_hweight8(u8 x);
int yaffs_hweight32(u32 x);
#endif

View File

@ -0,0 +1,126 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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 of macros that would normally
* be providesd in the Linux kernel. These macros have been written from
* scratch but are functionally equivalent to the Linux ones.
*
*/
#ifndef __YAFFS_LIST_H__
#define __YAFFS_LIST_H__
/*
* This is a simple doubly linked list implementation that matches the
* way the Linux kernel doubly linked list implementation works.
*/
struct list_head {
struct list_head *next; /* next in chain */
struct list_head *prev; /* previous in chain */
};
/* Initialise a static list */
#define LIST_HEAD(name) \
struct list_head name = { &(name), &(name)}
/* Initialise a list head to an empty list */
#define INIT_LIST_HEAD(p) \
do { \
(p)->next = (p);\
(p)->prev = (p); \
} while (0)
/* Add an element to a list */
static inline void list_add(struct list_head *new_entry,
struct list_head *list)
{
struct list_head *list_next = list->next;
list->next = new_entry;
new_entry->prev = list;
new_entry->next = list_next;
list_next->prev = new_entry;
}
static inline void list_add_tail(struct list_head *new_entry,
struct list_head *list)
{
struct list_head *list_prev = list->prev;
list->prev = new_entry;
new_entry->next = list;
new_entry->prev = list_prev;
list_prev->next = new_entry;
}
/* Take an element out of its current list, with or without
* reinitialising the links.of the entry*/
static inline void list_del(struct list_head *entry)
{
struct list_head *list_next = entry->next;
struct list_head *list_prev = entry->prev;
list_next->prev = list_prev;
list_prev->next = list_next;
}
static inline void list_del_init(struct list_head *entry)
{
list_del(entry);
entry->next = entry->prev = entry;
}
/* Test if the list is empty */
static inline int list_empty(struct list_head *entry)
{
return (entry->next == entry);
}
/* list_entry takes a pointer to a list entry and offsets it to that
* we can find a pointer to the object it is embedded in.
*/
#define list_entry(entry, type, member) \
((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
/* list_for_each and list_for_each_safe iterate over lists.
* list_for_each_safe uses temporary storage to make the list delete safe
*/
#define list_for_each(itervar, list) \
for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
#define list_for_each_safe(itervar, save_var, list) \
for (itervar = (list)->next, save_var = (list)->next->next; \
itervar != (list); \
itervar = save_var, save_var = save_var->next)
#endif

View File

@ -14,9 +14,6 @@
/* XXX U-BOOT XXX */
#include <common.h>
const char *yaffs_mtdif_c_version =
"$Id: yaffs_mtdif.c,v 1.19 2007/02/14 01:09:06 wookey Exp $";
#include "yportenv.h"
@ -27,72 +24,56 @@ const char *yaffs_mtdif_c_version =
#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)
static inline void translate_spare2oob(const struct 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;
oob[0] = spare->tb0;
oob[1] = spare->tb1;
oob[2] = spare->tb2;
oob[3] = spare->tb3;
oob[4] = spare->tb4;
oob[5] = spare->tb5 & 0x3f;
oob[5] |= spare->block_status == 'Y' ? 0 : 0x80;
oob[5] |= spare->page_status == 0 ? 0 : 0x40;
oob[6] = spare->tb6;
oob[7] = spare->tb7;
}
static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
static inline void translate_oob2spare(struct 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;
struct yaffs_nand_spare *nspare = (struct yaffs_nand_spare *)spare;
spare->tb0 = oob[0];
spare->tb1 = oob[1];
spare->tb2 = oob[2];
spare->tb3 = oob[3];
spare->tb4 = oob[4];
spare->tb5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
spare->block_status = oob[5] & 0x80 ? 0xff : 'Y';
spare->page_status = oob[5] & 0x40 ? 0xff : 0;
spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
spare->tagByte6 = oob[6];
spare->tagByte7 = oob[7];
spare->tb6 = oob[6];
spare->tb7 = 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)
int nandmtd_WriteChunkToNAND(struct yaffs_dev *dev, int chunkInNAND,
const u8 *data, const struct yaffs_spare *spare)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
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 */
loff_t addr = ((loff_t) chunkInNAND) * dev->data_bytes_per_chunk;
u8 spareAsBytes[8]; /* OOB */
if (data && !spare)
retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
retval = mtd->write(mtd, addr, dev->data_bytes_per_chunk,
&dummy, data);
else if (spare) {
if (dev->useNANDECC) {
if (dev->param.use_nand_ecc) {
translate_spare2oob(spare, spareAsBytes);
ops.mode = MTD_OOB_AUTO;
ops.ooblen = 8; /* temp hack */
@ -100,37 +81,12 @@ int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
ops.mode = MTD_OOB_RAW;
ops.ooblen = YAFFS_BYTES_PER_SPARE;
}
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
ops.len = data ? dev->data_bytes_per_chunk : 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;
@ -138,69 +94,36 @@ int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
return YAFFS_FAIL;
}
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
yaffs_Spare * spare)
int nandmtd_ReadChunkFromNAND(struct yaffs_dev *dev, int chunkInNAND, u8 *data,
struct yaffs_spare *spare)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
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 */
loff_t addr = ((loff_t) chunkInNAND) * dev->data_bytes_per_chunk;
u8 spareAsBytes[8]; /* OOB */
if (data && !spare)
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
retval = mtd->read(mtd, addr, dev->data_bytes_per_chunk,
&dummy, data);
else if (spare) {
if (dev->useNANDECC) {
if (dev->param.use_nand_ecc) {
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.len = data ? dev->data_bytes_per_chunk : ops.ooblen;
ops.datbuf = data;
ops.ooboffs = 0;
ops.oobbuf = spareAsBytes;
retval = mtd->read_oob(mtd, addr, &ops);
if (dev->useNANDECC)
if (dev->param.use_nand_ecc)
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;
@ -208,18 +131,18 @@ int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
return YAFFS_FAIL;
}
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
int nandmtd_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
__u32 addr =
((loff_t) blockNumber) * dev->nDataBytesPerChunk
* dev->nChunksPerBlock;
((loff_t) blockNumber) * dev->data_bytes_per_chunk
* dev->param.chunks_per_block;
struct erase_info ei;
int retval = 0;
ei.mtd = mtd;
ei.addr = addr;
ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
ei.len = dev->data_bytes_per_chunk * dev->param.chunks_per_block;
ei.time = 1000;
ei.retries = 2;
ei.callback = NULL;
@ -227,10 +150,6 @@ int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
/* Todo finish off the ei if required */
/* XXX U-BOOT XXX */
#if 0
sema_init(&dev->sem, 0);
#endif
retval = mtd->erase(mtd, &ei);
@ -240,7 +159,7 @@ int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
return YAFFS_FAIL;
}
int nandmtd_InitialiseNAND(yaffs_Device * dev)
int nandmtd_InitialiseNAND(struct yaffs_dev *dev)
{
return YAFFS_OK;
}

View File

@ -18,10 +18,10 @@
#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);
int nandmtd_WriteChunkToNAND(struct yaffs_dev *dev, int chunkInNAND,
const u8 *data, const struct yaffs_spare *spare);
int nandmtd_ReadChunkFromNAND(struct yaffs_dev *dev, int chunkInNAND, u8 *data,
struct yaffs_spare *spare);
int nandmtd_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber);
int nandmtd_InitialiseNAND(struct yaffs_dev *dev);
#endif

View File

@ -17,11 +17,8 @@
#include <common.h>
#include "asm/errno.h"
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_trace.h"
#include "yaffs_mtdif2.h"
@ -29,71 +26,67 @@ const char *yaffs_mtdif2_c_version =
#include "linux/types.h"
#include "linux/time.h"
#include "yaffs_trace.h"
#include "yaffs_packedtags2.h"
#include "string.h"
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags * tags)
#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
/* NB For use with inband tags....
* We assume that the data buffer is of size total_bytes_per_chunk so
* that we can also use it to load the tags.
*/
int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
const u8 *data,
const struct yaffs_ext_tags *tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
struct mtd_oob_ops ops;
#else
size_t dummy;
#endif
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
loff_t addr;
u8 local_spare[128];
yaffs_PackedTags2 pt;
struct yaffs_packed_tags2 pt;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
int packed_tags_size =
dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
void *packed_tags_ptr =
dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
#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 */
yaffs_trace(YAFFS_TRACE_MTD,
"nandmtd2_write_chunk_tags chunk %d data %p tags %p",
nand_chunk, data, tags);
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);
}
addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
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);
/* For yaffs2 writing there must be both data and tags.
* If we're using inband tags, then the tags are stuffed into
* the end of the data buffer.
*/
if (!data || !tags)
BUG();
else if (dev->param.inband_tags) {
struct yaffs_packed_tags2_tags_only *pt2tp;
pt2tp =
(struct yaffs_packed_tags2_tags_only *)(data +
dev->
data_bytes_per_chunk);
yaffs_pack_tags2_tags_only(pt2tp, tags);
} 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);
yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
}
#endif
ops.mode = MTD_OOB_AUTO;
ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
ops.len = dev->param.total_bytes_per_chunk;
ops.ooboffs = 0;
ops.datbuf = (u8 *) data;
ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
retval = mtd->write_oob(mtd, addr, &ops);
if (retval == 0)
return YAFFS_OK;
@ -101,88 +94,97 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
return YAFFS_FAIL;
}
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags)
int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_ext_tags *tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
u8 local_spare[128];
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
int local_data = 0;
struct yaffs_packed_tags2 pt;
loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
int packed_tags_size =
dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
void *packed_tags_ptr =
dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
yaffs_trace(YAFFS_TRACE_MTD,
"nandmtd2_read_chunk_tags chunk %d data %p tags %p",
nand_chunk, data, tags);
yaffs_PackedTags2 pt;
if (dev->param.inband_tags) {
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
if (!data) {
local_data = 1;
data = yaffs_get_temp_buffer(dev);
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
if (data && !tags)
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data);
}
if (dev->param.inband_tags || (data && !tags))
retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
&dummy, data);
else if (tags) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = sizeof(pt);
ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
ops.ooblen = packed_tags_size;
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
ops.ooboffs = 0;
ops.datbuf = data;
ops.oobbuf = dev->spareBuffer;
ops.oobbuf = local_spare;
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);
if (dev->param.inband_tags) {
if (tags) {
struct yaffs_packed_tags2_tags_only *pt2tp;
pt2tp =
(struct yaffs_packed_tags2_tags_only *)
&data[dev->data_bytes_per_chunk];
yaffs_unpack_tags2_tags_only(tags, pt2tp);
}
} 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);
if (tags) {
memcpy(packed_tags_ptr,
local_spare,
packed_tags_size);
yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
}
}
#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 (local_data)
yaffs_release_temp_buffer(dev, data);
if (tags && retval == -EBADMSG
&& tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
dev->n_ecc_unfixed++;
}
if (tags && retval == -EUCLEAN
&& tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
dev->n_ecc_fixed++;
}
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
int nandmtd2_MarkNANDBlockBad(struct yaffs_dev *dev, int blockNo)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
yaffs_trace(YAFFS_TRACE_MTD,
"nandmtd2_MarkNANDBlockBad %d", blockNo);
retval =
mtd->block_markbad(mtd,
blockNo * dev->nChunksPerBlock *
dev->nDataBytesPerChunk);
blockNo * dev->param.chunks_per_block *
dev->data_bytes_per_chunk);
if (retval == 0)
return YAFFS_OK;
@ -191,42 +193,40 @@ int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
}
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber)
int nandmtd2_QueryNANDBlock(struct yaffs_dev *dev, int blockNo,
enum yaffs_block_state *state, u32 *sequenceNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_QueryNANDBlock %d", blockNo);
retval =
mtd->block_isbad(mtd,
blockNo * dev->nChunksPerBlock *
dev->nDataBytesPerChunk);
blockNo * dev->param.chunks_per_block *
dev->data_bytes_per_chunk);
if (retval) {
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
*state = YAFFS_BLOCK_STATE_DEAD;
*sequenceNumber = 0;
} else {
yaffs_ExtendedTags t;
nandmtd2_ReadChunkWithTagsFromNAND(dev,
blockNo *
dev->nChunksPerBlock, NULL,
&t);
struct yaffs_ext_tags t;
nandmtd2_read_chunk_tags(dev,
blockNo *
dev->param.chunks_per_block, NULL,
&t);
if (t.chunkUsed) {
*sequenceNumber = t.sequenceNumber;
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
if (t.chunk_used) {
*sequenceNumber = t.seq_number;
*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
} else {
*sequenceNumber = 0;
*state = YAFFS_BLOCK_STATE_EMPTY;
}
}
T(YAFFS_TRACE_MTD,
(TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
*state));
yaffs_trace(YAFFS_TRACE_MTD, "block is bad seq %d state %d",
*sequenceNumber, *state);
if (retval == 0)
return YAFFS_OK;

View File

@ -17,13 +17,14 @@
#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);
int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int chunkInNAND,
const u8 *data,
const struct yaffs_ext_tags *tags);
int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int chunkInNAND,
u8 *data, struct yaffs_ext_tags *tags);
int nandmtd2_MarkNANDBlockBad(struct yaffs_dev *dev, int blockNo);
int nandmtd2_QueryNANDBlock(struct yaffs_dev *dev, int blockNo,
enum yaffs_block_state *state, u32 *sequenceNumber);
#endif

View File

@ -0,0 +1,208 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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 simple implementation of a name-value store assumes a small number of
* values and fits into a small finite buffer.
*
* Each attribute is stored as a record:
* sizeof(int) bytes record size.
* yaffs_strnlen+1 bytes name null terminated.
* nbytes value.
* ----------
* total size stored in record size
*
* This code has not been tested with unicode yet.
*/
#include "yaffs_nameval.h"
#include "yportenv.h"
static int nval_find(const char *xb, int xb_size, const YCHAR *name,
int *exist_size)
{
int pos = 0;
int size;
memcpy(&size, xb, sizeof(int));
while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
if (!yaffs_strncmp((YCHAR *) (xb + pos + sizeof(int)),
name, size)) {
if (exist_size)
*exist_size = size;
return pos;
}
pos += size;
if (pos < xb_size - sizeof(int))
memcpy(&size, xb + pos, sizeof(int));
else
size = 0;
}
if (exist_size)
*exist_size = 0;
return -ENODATA;
}
static int nval_used(const char *xb, int xb_size)
{
int pos = 0;
int size;
memcpy(&size, xb + pos, sizeof(int));
while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
pos += size;
if (pos < xb_size - sizeof(int))
memcpy(&size, xb + pos, sizeof(int));
else
size = 0;
}
return pos;
}
int nval_del(char *xb, int xb_size, const YCHAR *name)
{
int pos = nval_find(xb, xb_size, name, NULL);
int size;
if (pos < 0 || pos >= xb_size)
return -ENODATA;
/* Find size, shift rest over this record,
* then zero out the rest of buffer */
memcpy(&size, xb + pos, sizeof(int));
memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
memset(xb + (xb_size - size), 0, size);
return 0;
}
int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
int bsize, int flags)
{
int pos;
int namelen = yaffs_strnlen(name, xb_size);
int reclen;
int size_exist = 0;
int space;
int start;
pos = nval_find(xb, xb_size, name, &size_exist);
if (flags & XATTR_CREATE && pos >= 0)
return -EEXIST;
if (flags & XATTR_REPLACE && pos < 0)
return -ENODATA;
start = nval_used(xb, xb_size);
space = xb_size - start + size_exist;
reclen = (sizeof(int) + namelen + 1 + bsize);
if (reclen > space)
return -ENOSPC;
if (pos >= 0) {
nval_del(xb, xb_size, name);
start = nval_used(xb, xb_size);
}
pos = start;
memcpy(xb + pos, &reclen, sizeof(int));
pos += sizeof(int);
yaffs_strncpy((YCHAR *) (xb + pos), name, reclen);
pos += (namelen + 1);
memcpy(xb + pos, buf, bsize);
return 0;
}
int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
int bsize)
{
int pos = nval_find(xb, xb_size, name, NULL);
int size;
if (pos >= 0 && pos < xb_size) {
memcpy(&size, xb + pos, sizeof(int));
pos += sizeof(int); /* advance past record length */
size -= sizeof(int);
/* Advance over name string */
while (xb[pos] && size > 0 && pos < xb_size) {
pos++;
size--;
}
/*Advance over NUL */
pos++;
size--;
/* If bsize is zero then this is a size query.
* Return the size, but don't copy.
*/
if (!bsize)
return size;
if (size <= bsize) {
memcpy(buf, xb + pos, size);
return size;
}
}
if (pos >= 0)
return -ERANGE;
return -ENODATA;
}
int nval_list(const char *xb, int xb_size, char *buf, int bsize)
{
int pos = 0;
int size;
int name_len;
int ncopied = 0;
int filled = 0;
memcpy(&size, xb + pos, sizeof(int));
while (size > sizeof(int) &&
size <= xb_size &&
(pos + size) < xb_size &&
!filled) {
pos += sizeof(int);
size -= sizeof(int);
name_len = yaffs_strnlen((YCHAR *) (xb + pos), size);
if (ncopied + name_len + 1 < bsize) {
memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
buf += name_len;
*buf = '\0';
buf++;
if (sizeof(YCHAR) > 1) {
*buf = '\0';
buf++;
}
ncopied += (name_len + 1);
} else {
filled = 1;
}
pos += size;
if (pos < xb_size - sizeof(int))
memcpy(&size, xb + pos, sizeof(int));
else
size = 0;
}
return ncopied;
}
int nval_hasvalues(const char *xb, int xb_size)
{
return nval_used(xb, xb_size) > 0;
}

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -13,11 +13,16 @@
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __NAMEVAL_H__
#define __NAMEVAL_H__
#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 *));
#include "yportenv.h"
int nval_del(char *xb, int xb_size, const YCHAR * name);
int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
int bsize, int flags);
int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
int bsize);
int nval_list(const char *xb, int xb_size, char *buf, int bsize);
int nval_hasvalues(const char *xb, int xb_size);
#endif

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -11,124 +11,110 @@
* published by the Free Software Foundation.
*/
/* XXX U-BOOT XXX */
#include <common.h>
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"
#include "yaffs_getblockinfo.h"
#include "yaffs_summary.h"
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer,
yaffs_ExtendedTags * tags)
int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
u8 *buffer, struct yaffs_ext_tags *tags)
{
int result;
yaffs_ExtendedTags localTags;
struct yaffs_ext_tags local_tags;
int flash_chunk = nand_chunk - dev->chunk_offset;
int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
dev->n_page_reads++;
/* If there are no tags provided, use local tags to get prioritised gc working */
if(!tags)
tags = &localTags;
/* If there are no tags provided use local tags. */
if (!tags)
tags = &local_tags;
if (dev->readChunkWithTagsFromNAND)
result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
tags);
if (dev->param.read_chunk_tags_fn)
result =
dev->param.read_chunk_tags_fn(dev, flash_chunk, buffer,
tags);
else
result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
realignedChunkInNAND,
buffer,
tags);
if(tags &&
tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){
result = yaffs_tags_compat_rd(dev,
flash_chunk, buffer, tags);
if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
yaffs_HandleChunkError(dev,bi);
struct yaffs_block_info *bi;
bi = yaffs_get_block_info(dev,
nand_chunk /
dev->param.chunks_per_block);
yaffs_handle_chunk_error(dev, bi);
}
return result;
}
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * buffer,
yaffs_ExtendedTags * tags)
int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
int nand_chunk,
const u8 *buffer, struct yaffs_ext_tags *tags)
{
chunkInNAND -= dev->chunkOffset;
int result;
int flash_chunk = nand_chunk - dev->chunk_offset;
dev->n_page_writes++;
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));
tags->seq_number = dev->seq_number;
tags->chunk_used = 1;
yaffs_trace(YAFFS_TRACE_WRITE,
"Writing chunk %d tags %d %d",
nand_chunk, tags->obj_id, tags->chunk_id);
} else {
T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
YBUG();
yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
BUG();
return YAFFS_FAIL;
}
if (dev->writeChunkWithTagsToNAND)
return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
tags);
if (dev->param.write_chunk_tags_fn)
result = dev->param.write_chunk_tags_fn(dev, flash_chunk,
buffer, tags);
else
return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
chunkInNAND,
buffer,
tags);
}
result = yaffs_tags_compat_wr(dev, flash_chunk, 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,
int *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);
yaffs_summary_add(dev, tags, nand_chunk);
return result;
}
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
{
return dev->initialiseNAND(dev);
block_no -= dev->block_offset;
if (dev->param.bad_block_fn)
return dev->param.bad_block_fn(dev, block_no);
return yaffs_tags_compat_mark_bad(dev, block_no);
}
int yaffs_query_init_block_state(struct yaffs_dev *dev,
int block_no,
enum yaffs_block_state *state,
u32 *seq_number)
{
block_no -= dev->block_offset;
if (dev->param.query_block_fn)
return dev->param.query_block_fn(dev, block_no, state,
seq_number);
return yaffs_tags_compat_query_block(dev, block_no, state, seq_number);
}
int yaffs_erase_block(struct yaffs_dev *dev, int flash_block)
{
int result;
flash_block -= dev->block_offset;
dev->n_erasures++;
result = dev->param.erase_fn(dev, flash_block);
return result;
}
int yaffs_init_nand(struct yaffs_dev *dev)
{
if (dev->param.initialise_flash_fn)
return dev->param.initialise_flash_fn(dev);
return YAFFS_OK;
}

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -17,27 +17,22 @@
#define __YAFFS_NAND_H__
#include "yaffs_guts.h"
int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
u8 *buffer, struct yaffs_ext_tags *tags);
int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
int nand_chunk,
const u8 *buffer, struct yaffs_ext_tags *tags);
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer,
yaffs_ExtendedTags * tags);
int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * buffer,
yaffs_ExtendedTags * tags);
int yaffs_query_init_block_state(struct yaffs_dev *dev,
int block_no,
enum yaffs_block_state *state,
unsigned *seq_number);
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo);
int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo,
yaffs_BlockState * state,
int *sequenceNumber);
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND);
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
int yaffs_init_nand(struct yaffs_dev *dev);
#endif

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -20,18 +20,18 @@
#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_WriteChunkWithTagsToNAND(struct yaffs_dev *dev,
int nand_chunk, const u8 *data,
const struct yaffs_ext_tags *tags);
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev,
int nand_chunk, u8 *data,
struct yaffs_ext_tags *tags);
int nandemul2k_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no);
int nandemul2k_QueryNANDBlock(struct yaffs_dev *dev, int block_no,
enum yaffs_block_state *state, u32 *seq_number);
int nandemul2k_EraseBlockInNAND(struct yaffs_dev *dev,
int flash_block);
int nandemul2k_InitialiseNAND(struct yaffs_dev *dev);
int nandemul2k_GetBytesPerChunk(void);
int nandemul2k_GetChunksPerBlock(void);
int nandemul2k_GetNumberOfBlocks(void);

View File

@ -0,0 +1,251 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yportenv.h"
#include "yaffs_guts.h"
#include "yaffs_nandif.h"
#include "yaffs_packedtags2.h"
#include "yramsim.h"
#include "yaffs_trace.h"
#include "yaffsfs.h"
/* NB For use with inband tags....
* We assume that the data buffer is of size totalBytersPerChunk so that
* we can also use it to load the tags.
*/
int ynandif_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk,
const u8 *data,
const struct yaffs_ext_tags *tags)
{
int retval = 0;
struct yaffs_packed_tags2 pt;
void *spare;
unsigned spareSize = 0;
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
yaffs_trace(YAFFS_TRACE_MTD,
"nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p",
nand_chunk, data, tags);
/* For yaffs2 writing there must be both data and tags.
* If we're using inband tags, then the tags are stuffed into
* the end of the data buffer.
*/
if (dev->param.inband_tags) {
struct yaffs_packed_tags2_tags_only *pt2tp;
pt2tp = (struct yaffs_packed_tags2_tags_only *)
(data + dev->data_bytes_per_chunk);
yaffs_pack_tags2_tags_only(pt2tp, tags);
spare = NULL;
spareSize = 0;
} else {
yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
spare = &pt;
spareSize = sizeof(struct yaffs_packed_tags2);
}
retval = geometry->writeChunk(dev, nand_chunk,
data, dev->param.total_bytes_per_chunk,
spare, spareSize);
return retval;
}
int ynandif_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_ext_tags *tags)
{
struct yaffs_packed_tags2 pt;
int localData = 0;
void *spare = NULL;
unsigned spareSize;
int retval = 0;
int eccStatus; /* 0 = ok, 1 = fixed, -1 = unfixed */
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
yaffs_trace(YAFFS_TRACE_MTD,
"nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p",
nand_chunk, data, tags);
if (!tags) {
spare = NULL;
spareSize = 0;
} else if (dev->param.inband_tags) {
if (!data) {
localData = 1;
data = yaffs_get_temp_buffer(dev);
}
spare = NULL;
spareSize = 0;
} else {
spare = &pt;
spareSize = sizeof(struct yaffs_packed_tags2);
}
retval = geometry->readChunk(dev, nand_chunk,
data,
data ? dev->param.total_bytes_per_chunk : 0,
spare, spareSize,
&eccStatus);
if (dev->param.inband_tags) {
if (tags) {
struct yaffs_packed_tags2_tags_only *pt2tp;
pt2tp = (struct yaffs_packed_tags2_tags_only *)
&data[dev->data_bytes_per_chunk];
yaffs_unpack_tags2_tags_only(tags, pt2tp);
}
} else {
if (tags)
yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
}
if (tags && tags->chunk_used) {
if (eccStatus < 0 ||
tags->ecc_result == YAFFS_ECC_RESULT_UNFIXED)
tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
else if (eccStatus > 0 ||
tags->ecc_result == YAFFS_ECC_RESULT_FIXED)
tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
else
tags->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
}
if (localData)
yaffs_release_temp_buffer(dev, data);
return retval;
}
int ynandif_MarkNANDBlockBad(struct yaffs_dev *dev, int blockId)
{
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
return geometry->markBlockBad(dev, blockId);
}
int ynandif_EraseBlockInNAND(struct yaffs_dev *dev, int blockId)
{
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
return geometry->eraseBlock(dev, blockId);
}
static int ynandif_IsBlockOk(struct yaffs_dev *dev, int blockId)
{
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
return geometry->checkBlockOk(dev, blockId);
}
int ynandif_QueryNANDBlock(struct yaffs_dev *dev, int blockId,
enum yaffs_block_state *state, u32 *seq_number)
{
unsigned chunkNo;
struct yaffs_ext_tags tags;
*seq_number = 0;
chunkNo = blockId * dev->param.chunks_per_block;
if (!ynandif_IsBlockOk(dev, blockId)) {
*state = YAFFS_BLOCK_STATE_DEAD;
} else {
ynandif_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &tags);
if (!tags.chunk_used) {
*state = YAFFS_BLOCK_STATE_EMPTY;
} else {
*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
*seq_number = tags.seq_number;
}
}
return YAFFS_OK;
}
int ynandif_InitialiseNAND(struct yaffs_dev *dev)
{
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
geometry->initialise(dev);
return YAFFS_OK;
}
int ynandif_Deinitialise_flash_fn(struct yaffs_dev *dev)
{
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
geometry->deinitialise(dev);
return YAFFS_OK;
}
struct yaffs_dev *
yaffs_add_dev_from_geometry(const YCHAR *name,
const struct ynandif_Geometry *geometry)
{
YCHAR *clonedName = malloc(sizeof(YCHAR) *
(strnlen(name, YAFFS_MAX_NAME_LENGTH)+1));
struct yaffs_dev *dev = malloc(sizeof(struct yaffs_dev));
struct yaffs_param *param;
if (dev && clonedName) {
memset(dev, 0, sizeof(struct yaffs_dev));
strcpy(clonedName, name);
param = &dev->param;
param->name = clonedName;
param->write_chunk_tags_fn = ynandif_WriteChunkWithTagsToNAND;
param->read_chunk_tags_fn = ynandif_ReadChunkWithTagsFromNAND;
param->erase_fn = ynandif_EraseBlockInNAND;
param->initialise_flash_fn = ynandif_InitialiseNAND;
param->query_block_fn = ynandif_QueryNANDBlock;
param->bad_block_fn = ynandif_MarkNANDBlockBad;
param->n_caches = 20;
param->start_block = geometry->start_block;
param->end_block = geometry->end_block;
param->total_bytes_per_chunk = geometry->dataSize;
param->spare_bytes_per_chunk = geometry->spareSize;
param->inband_tags = geometry->inband_tags;
param->chunks_per_block = geometry->pagesPerBlock;
param->use_nand_ecc = geometry->hasECC;
param->is_yaffs2 = geometry->useYaffs2;
param->n_reserved_blocks = 5;
dev->driver_context = (void *)geometry;
yaffs_add_device(dev);
return dev;
}
free(dev);
free(clonedName);
return NULL;
}

View File

@ -0,0 +1,65 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YNANDIF_H__
#define __YNANDIF_H__
#include "yaffs_guts.h"
struct ynandif_Geometry {
unsigned start_block;
unsigned end_block;
unsigned dataSize;
unsigned spareSize;
unsigned pagesPerBlock;
unsigned hasECC;
unsigned inband_tags;
unsigned useYaffs2;
int (*initialise)(struct yaffs_dev *dev);
int (*deinitialise)(struct yaffs_dev *dev);
int (*readChunk) (struct yaffs_dev *dev,
unsigned pageId,
unsigned char *data,
unsigned dataLength,
unsigned char *spare,
unsigned spareLength,
int *eccStatus);
/* ECC status is set to 0 for OK, 1 for fixed, -1 for unfixed. */
int (*writeChunk)(struct yaffs_dev *dev,
unsigned pageId,
const unsigned char *data,
unsigned dataLength,
const unsigned char *spare,
unsigned spareLength);
int (*eraseBlock)(struct yaffs_dev *dev, unsigned blockId);
int (*checkBlockOk)(struct yaffs_dev *dev, unsigned blockId);
int (*markBlockBad)(struct yaffs_dev *dev, unsigned blockId);
void *privateData;
};
struct yaffs_dev *
yaffs_add_dev_from_geometry(const YCHAR *name,
const struct ynandif_Geometry *geometry);
#endif

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -13,12 +13,29 @@
* 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 __YAFFS_TAGS_VALIDITY_H__
#define __YAFFS_TAGS_VALIDITY_H__
#include "yaffs_guts.h"
#ifndef __YAFFS_OSGLUE_H__
#define __YAFFS_OSGLUE_H__
#include "yportenv.h"
void yaffsfs_Lock(void);
void yaffsfs_Unlock(void);
u32 yaffsfs_CurrentTime(void);
void yaffsfs_SetError(int err);
void *yaffsfs_malloc(size_t size);
void yaffsfs_free(void *ptr);
void yaffsfs_OSInitialisation(void);
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
int yaffs_ValidateTags(yaffs_ExtendedTags * tags);
#endif

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -11,45 +11,46 @@
* published by the Free Software Foundation.
*/
/* XXX U-BOOT XXX */
#include <common.h>
#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;
static const u8 all_ff[20] = {
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff
};
void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
const struct yaffs_ext_tags *t)
{
pt->chunk_id = t->chunk_id;
pt->serial_number = t->serial_number;
pt->n_bytes = t->n_bytes;
pt->obj_id = t->obj_id;
pt->ecc = 0;
pt->deleted = (t->is_deleted) ? 0 : 1;
pt->unused_stuff = 0;
pt->should_be_ff = 0xffffffff;
}
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt)
void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
const struct yaffs_packed_tags1 *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;
if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
t->block_bad = 0;
if (pt->should_be_ff != 0xffffffff)
t->block_bad = 1;
t->chunk_used = 1;
t->obj_id = pt->obj_id;
t->chunk_id = pt->chunk_id;
t->n_bytes = pt->n_bytes;
t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
t->is_deleted = (pt->deleted) ? 0 : 1;
t->serial_number = pt->serial_number;
} else {
memset(t, 0, sizeof(yaffs_ExtendedTags));
memset(t, 0, sizeof(struct yaffs_ext_tags));
}
}

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -20,18 +20,20 @@
#include "yaffs_guts.h"
typedef struct {
unsigned chunkId:20;
unsigned serialNumber:2;
unsigned byteCount:10;
unsigned objectId:18;
struct yaffs_packed_tags1 {
unsigned chunk_id:20;
unsigned serial_number:2;
unsigned n_bytes:10;
unsigned obj_id:18;
unsigned ecc:12;
unsigned deleted:1;
unsigned unusedStuff:1;
unsigned shouldBeFF;
unsigned unused_stuff:1;
unsigned should_be_ff;
} yaffs_PackedTags1;
};
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t);
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt);
void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
const struct yaffs_ext_tags *t);
void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
const struct yaffs_packed_tags1 *pt);
#endif

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -11,12 +11,9 @@
* published by the Free Software Foundation.
*/
/* XXX U-BOOT XXX */
#include <common.h>
#include "yaffs_packedtags2.h"
#include "yportenv.h"
#include "yaffs_tagsvalidity.h"
#include "yaffs_trace.h"
/* This code packs a set of extended tags into a binary structure for
* NAND storage
@ -27,159 +24,174 @@
* This is defined by having the EXTRA_HEADER_INFO_FLAG set.
*/
/* Extra flags applied to chunkId */
/* Extra flags applied to chunk_id */
#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
#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)
#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
static void yaffs_dump_packed_tags2_tags_only(
const struct yaffs_packed_tags2_tags_only *ptt)
{
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));
yaffs_trace(YAFFS_TRACE_MTD,
"packed tags obj %d chunk %d byte %d seq %d",
ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
}
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
{
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));
yaffs_dump_packed_tags2_tags_only(&pt->t);
}
static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
{
yaffs_trace(YAFFS_TRACE_MTD,
"ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
t->seq_number);
}
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
{
pt->t.chunkId = t->chunkId;
pt->t.sequenceNumber = t->sequenceNumber;
pt->t.byteCount = t->byteCount;
pt->t.objectId = t->objectId;
if (t->chunk_id != 0 || !t->extra_available)
return 0;
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
/* Check if the file size is too long to store */
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
(t->extra_file_size >> 31) != 0)
return 0;
return 1;
}
void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
const struct yaffs_ext_tags *t)
{
ptt->chunk_id = t->chunk_id;
ptt->seq_number = t->seq_number;
ptt->n_bytes = t->n_bytes;
ptt->obj_id = t->obj_id;
/* Only store extra tags for object headers.
* If it is a file then only store if the file size is short\
* enough to fit.
*/
if (yaffs_check_tags_extra_packable(t)) {
/* 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;
}
/* We save the parent object in the chunk_id */
ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
if (t->extra_is_shrink)
ptt->chunk_id |= EXTRA_SHRINK_FLAG;
if (t->extra_shadows)
ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
pt->t.objectId |=
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
ptt->obj_id |= (t->extra_obj_type << 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;
}
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
ptt->n_bytes = t->extra_equiv_id;
else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
ptt->n_bytes = (unsigned) t->extra_file_size;
else
ptt->n_bytes = 0;
}
yaffs_DumpPackedTags2(pt);
yaffs_DumpTags2(t);
#ifndef YAFFS_IGNORE_TAGS_ECC
{
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
sizeof(yaffs_PackedTags2TagsPart),
&pt->ecc);
}
#endif
yaffs_dump_packed_tags2_tags_only(ptt);
yaffs_dump_tags2(t);
}
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
const struct yaffs_ext_tags *t, int tags_ecc)
{
yaffs_pack_tags2_tags_only(&pt->t, t);
memset(t, 0, sizeof(yaffs_ExtendedTags));
if (tags_ecc)
yaffs_ecc_calc_other((unsigned char *)&pt->t,
sizeof(struct yaffs_packed_tags2_tags_only),
&pt->ecc);
}
yaffs_InitialiseTags(t);
void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
struct yaffs_packed_tags2_tags_only *ptt)
{
memset(t, 0, sizeof(struct yaffs_ext_tags));
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;
if (ptt->seq_number == 0xffffffff)
return;
/* Do extra header info stuff */
t->block_bad = 0;
t->chunk_used = 1;
t->obj_id = ptt->obj_id;
t->chunk_id = ptt->chunk_id;
t->n_bytes = ptt->n_bytes;
t->is_deleted = 0;
t->serial_number = 0;
t->seq_number = ptt->seq_number;
if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) {
t->chunkId = 0;
t->byteCount = 0;
/* Do extra header info stuff */
if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
t->chunk_id = 0;
t->n_bytes = 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;
t->extra_available = 1;
t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
t->extraEquivalentObjectId = pt->t.byteCount;
} else {
t->extraFileLength = pt->t.byteCount;
}
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
t->extra_equiv_id = ptt->n_bytes;
else
t->extra_file_size = ptt->n_bytes;
}
yaffs_dump_packed_tags2_tags_only(ptt);
yaffs_dump_tags2(t);
}
void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
int tags_ecc)
{
enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
if (pt->t.seq_number != 0xffffffff && tags_ecc) {
/* Chunk is in use and we need to do ECC */
struct yaffs_ecc_other ecc;
int result;
yaffs_ecc_calc_other((unsigned char *)&pt->t,
sizeof(struct yaffs_packed_tags2_tags_only),
&ecc);
result =
yaffs_ecc_correct_other((unsigned char *)&pt->t,
sizeof(struct yaffs_packed_tags2_tags_only),
&pt->ecc, &ecc);
switch (result) {
case 0:
ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
break;
case 1:
ecc_result = YAFFS_ECC_RESULT_FIXED;
break;
case -1:
ecc_result = YAFFS_ECC_RESULT_UNFIXED;
break;
default:
ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
}
}
yaffs_unpack_tags2_tags_only(t, &pt->t);
yaffs_DumpPackedTags2(pt);
yaffs_DumpTags2(t);
t->ecc_result = ecc_result;
yaffs_dump_packed_tags2(pt);
yaffs_dump_tags2(t);
}

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -21,18 +21,27 @@
#include "yaffs_guts.h"
#include "yaffs_ecc.h"
typedef struct {
unsigned sequenceNumber;
unsigned objectId;
unsigned chunkId;
unsigned byteCount;
} yaffs_PackedTags2TagsPart;
struct yaffs_packed_tags2_tags_only {
unsigned seq_number;
unsigned obj_id;
unsigned chunk_id;
unsigned n_bytes;
};
typedef struct {
yaffs_PackedTags2TagsPart t;
yaffs_ECCOther ecc;
} yaffs_PackedTags2;
struct yaffs_packed_tags2 {
struct yaffs_packed_tags2_tags_only t;
struct yaffs_ecc_other ecc;
};
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt);
/* Full packed tags with ECC, used for oob tags */
void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
const struct yaffs_ext_tags *t, int tags_ecc);
void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
int tags_ecc);
/* Only the tags part (no ECC for use with inband tags */
void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
const struct yaffs_ext_tags *t);
void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
struct yaffs_packed_tags2_tags_only *pt);
#endif

View File

@ -27,58 +27,56 @@
* SUCH DAMAGE.
*/
/* XXX U-BOOT XXX */
#include <common.h>
#include "yportenv.h"
//#include <linux/string.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 { \
#define swapcode(TYPE, parmi, parmj, n) do { \
long i = (n) / sizeof(TYPE); \
register TYPE *pi = (TYPE *) (parmi); \
register TYPE *pj = (TYPE *) (parmj); \
do { \
register TYPE t = *pi; \
*pi++ = *pj; \
*pj++ = t; \
} while (--i > 0); \
}
} while (0)
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1;
static __inline void
static inline void
swapfunc(char *a, char *b, int n, int swaptype)
{
if (swaptype <= 1)
swapcode(long, a, b, n)
swapcode(long, a, b, n);
else
swapcode(char, a, b, n)
swapcode(char, a, b, n);
}
#define swap(a, b) \
#define yswap(a, b) do { \
if (swaptype == 0) { \
long t = *(long *)(a); \
*(long *)(a) = *(long *)(b); \
*(long *)(b) = t; \
} else \
swapfunc(a, b, es, swaptype)
swapfunc(a, b, es, swaptype); \
} while (0)
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
static __inline char *
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 ));
(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))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
void
@ -95,7 +93,7 @@ loop: SWAPINIT(a, es);
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);
yswap(pl, pl - es);
return;
}
pm = (char *)a + (n / 2) * es;
@ -110,7 +108,7 @@ loop: SWAPINIT(a, es);
}
pm = med3(pl, pm, pn, cmp);
}
swap(a, pm);
yswap(a, pm);
pa = pb = (char *)a + es;
pc = pd = (char *)a + (n - 1) * es;
@ -118,7 +116,7 @@ loop: SWAPINIT(a, es);
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pa, pb);
yswap(pa, pb);
pa += es;
}
pb += es;
@ -126,14 +124,14 @@ loop: SWAPINIT(a, es);
while (pb <= pc && (r = cmp(pc, a)) >= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pc, pd);
yswap(pc, pd);
pd -= es;
}
pc -= es;
}
if (pb > pc)
break;
swap(pb, pc);
yswap(pb, pc);
swap_cnt = 1;
pb += es;
pc -= es;
@ -142,7 +140,7 @@ loop: SWAPINIT(a, es);
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);
yswap(pl, pl - es);
return;
}
@ -151,9 +149,11 @@ loop: SWAPINIT(a, es);
vecswap(a, pb - r, r);
r = min((long)(pd - pc), (long)(pn - pd - es));
vecswap(pb, pn - r, r);
if ((r = pb - pa) > es)
r = pb - pa;
if (r > es)
yaffs_qsort(a, r / es, es, cmp);
if ((r = pd - pc) > es) {
r = pd - pc;
if (r > es) {
/* Iterate rather than recurse to save stack space */
a = pn - r;
n = r / es;

View File

@ -1,32 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* yaffs_ramdisk.h: yaffs ram disk component
*/
#ifndef __YAFFS_RAMDISK_H__
#define __YAFFS_RAMDISK_H__
#include "yaffs_guts.h"
int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
int yramdisk_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, 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,313 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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.
*/
/* Summaries write the useful part of the tags for the chunks in a block into an
* an array which is written to the last n chunks of the block.
* Reading the summaries gives all the tags for the block in one read. Much
* faster.
*
* Chunks holding summaries are marked with tags making it look like
* they are part of a fake file.
*
* The summary could also be used during gc.
*
*/
#include "yaffs_summary.h"
#include "yaffs_packedtags2.h"
#include "yaffs_nand.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_bitmap.h"
/*
* The summary is built up in an array of summary tags.
* This gets written to the last one or two (maybe more) chunks in a block.
* A summary header is written as the first part of each chunk of summary data.
* The summary header must match or the summary is rejected.
*/
/* Summary tags don't need the sequence number because that is redundant. */
struct yaffs_summary_tags {
unsigned obj_id;
unsigned chunk_id;
unsigned n_bytes;
};
/* Summary header */
struct yaffs_summary_header {
unsigned version; /* Must match current version */
unsigned block; /* Must be this block */
unsigned seq; /* Must be this sequence number */
unsigned sum; /* Just add up all the bytes in the tags */
};
static void yaffs_summary_clear(struct yaffs_dev *dev)
{
if (!dev->sum_tags)
return;
memset(dev->sum_tags, 0, dev->chunks_per_summary *
sizeof(struct yaffs_summary_tags));
}
void yaffs_summary_deinit(struct yaffs_dev *dev)
{
kfree(dev->sum_tags);
dev->sum_tags = NULL;
kfree(dev->gc_sum_tags);
dev->gc_sum_tags = NULL;
dev->chunks_per_summary = 0;
}
int yaffs_summary_init(struct yaffs_dev *dev)
{
int sum_bytes;
int chunks_used; /* Number of chunks used by summary */
int sum_tags_bytes;
sum_bytes = dev->param.chunks_per_block *
sizeof(struct yaffs_summary_tags);
chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/
(dev->data_bytes_per_chunk -
sizeof(struct yaffs_summary_header));
dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;
sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
dev->chunks_per_summary;
dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
if (!dev->sum_tags || !dev->gc_sum_tags) {
yaffs_summary_deinit(dev);
return YAFFS_FAIL;
}
yaffs_summary_clear(dev);
return YAFFS_OK;
}
static unsigned yaffs_summary_sum(struct yaffs_dev *dev)
{
u8 *sum_buffer = (u8 *)dev->sum_tags;
int i;
unsigned sum = 0;
i = sizeof(struct yaffs_summary_tags) *
dev->chunks_per_summary;
while (i > 0) {
sum += *sum_buffer;
sum_buffer++;
i--;
}
return sum;
}
static int yaffs_summary_write(struct yaffs_dev *dev, int blk)
{
struct yaffs_ext_tags tags;
u8 *buffer;
u8 *sum_buffer = (u8 *)dev->sum_tags;
int n_bytes;
int chunk_in_nand;
int chunk_in_block;
int result;
int this_tx;
struct yaffs_summary_header hdr;
int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
buffer = yaffs_get_temp_buffer(dev);
n_bytes = sizeof(struct yaffs_summary_tags) *
dev->chunks_per_summary;
memset(&tags, 0, sizeof(struct yaffs_ext_tags));
tags.obj_id = YAFFS_OBJECTID_SUMMARY;
tags.chunk_id = 1;
chunk_in_block = dev->chunks_per_summary;
chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block +
dev->chunks_per_summary;
hdr.version = YAFFS_SUMMARY_VERSION;
hdr.block = blk;
hdr.seq = bi->seq_number;
hdr.sum = yaffs_summary_sum(dev);
do {
this_tx = n_bytes;
if (this_tx > sum_bytes_per_chunk)
this_tx = sum_bytes_per_chunk;
memcpy(buffer, &hdr, sizeof(hdr));
memcpy(buffer + sizeof(hdr), sum_buffer, this_tx);
tags.n_bytes = this_tx + sizeof(hdr);
result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,
buffer, &tags);
if (result != YAFFS_OK)
break;
yaffs_set_chunk_bit(dev, blk, chunk_in_block);
bi->pages_in_use++;
dev->n_free_chunks--;
n_bytes -= this_tx;
sum_buffer += this_tx;
chunk_in_nand++;
chunk_in_block++;
tags.chunk_id++;
} while (result == YAFFS_OK && n_bytes > 0);
yaffs_release_temp_buffer(dev, buffer);
if (result == YAFFS_OK)
bi->has_summary = 1;
return result;
}
int yaffs_summary_read(struct yaffs_dev *dev,
struct yaffs_summary_tags *st,
int blk)
{
struct yaffs_ext_tags tags;
u8 *buffer;
u8 *sum_buffer = (u8 *)st;
int n_bytes;
int chunk_id;
int chunk_in_nand;
int chunk_in_block;
int result;
int this_tx;
struct yaffs_summary_header hdr;
struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
int sum_tags_bytes;
sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
dev->chunks_per_summary;
buffer = yaffs_get_temp_buffer(dev);
n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
chunk_in_block = dev->chunks_per_summary;
chunk_in_nand = blk * dev->param.chunks_per_block +
dev->chunks_per_summary;
chunk_id = 1;
do {
this_tx = n_bytes;
if (this_tx > sum_bytes_per_chunk)
this_tx = sum_bytes_per_chunk;
result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,
buffer, &tags);
if (tags.chunk_id != chunk_id ||
tags.obj_id != YAFFS_OBJECTID_SUMMARY ||
tags.chunk_used == 0 ||
tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
tags.n_bytes != (this_tx + sizeof(hdr)))
result = YAFFS_FAIL;
if (result != YAFFS_OK)
break;
if (st == dev->sum_tags) {
/* If we're scanning then update the block info */
yaffs_set_chunk_bit(dev, blk, chunk_in_block);
bi->pages_in_use++;
}
memcpy(&hdr, buffer, sizeof(hdr));
memcpy(sum_buffer, buffer + sizeof(hdr), this_tx);
n_bytes -= this_tx;
sum_buffer += this_tx;
chunk_in_nand++;
chunk_in_block++;
chunk_id++;
} while (result == YAFFS_OK && n_bytes > 0);
yaffs_release_temp_buffer(dev, buffer);
if (result == YAFFS_OK) {
/* Verify header */
if (hdr.version != YAFFS_SUMMARY_VERSION ||
hdr.block != blk ||
hdr.seq != bi->seq_number ||
hdr.sum != yaffs_summary_sum(dev))
result = YAFFS_FAIL;
}
if (st == dev->sum_tags && result == YAFFS_OK)
bi->has_summary = 1;
return result;
}
int yaffs_summary_add(struct yaffs_dev *dev,
struct yaffs_ext_tags *tags,
int chunk_in_nand)
{
struct yaffs_packed_tags2_tags_only tags_only;
struct yaffs_summary_tags *sum_tags;
int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
if (!dev->sum_tags)
return YAFFS_OK;
if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
yaffs_pack_tags2_tags_only(&tags_only, tags);
sum_tags = &dev->sum_tags[chunk_in_block];
sum_tags->chunk_id = tags_only.chunk_id;
sum_tags->n_bytes = tags_only.n_bytes;
sum_tags->obj_id = tags_only.obj_id;
if (chunk_in_block == dev->chunks_per_summary - 1) {
/* Time to write out the summary */
yaffs_summary_write(dev, block_in_nand);
yaffs_summary_clear(dev);
yaffs_skip_rest_of_block(dev);
}
}
return YAFFS_OK;
}
int yaffs_summary_fetch(struct yaffs_dev *dev,
struct yaffs_ext_tags *tags,
int chunk_in_block)
{
struct yaffs_packed_tags2_tags_only tags_only;
struct yaffs_summary_tags *sum_tags;
if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
sum_tags = &dev->sum_tags[chunk_in_block];
tags_only.chunk_id = sum_tags->chunk_id;
tags_only.n_bytes = sum_tags->n_bytes;
tags_only.obj_id = sum_tags->obj_id;
yaffs_unpack_tags2_tags_only(tags, &tags_only);
return YAFFS_OK;
}
return YAFFS_FAIL;
}
void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
{
struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
int i;
if (!bi->has_summary)
return;
for (i = dev->chunks_per_summary;
i < dev->param.chunks_per_block;
i++) {
if (yaffs_check_chunk_bit(dev, blk, i)) {
yaffs_clear_chunk_bit(dev, blk, i);
bi->pages_in_use--;
dev->n_free_chunks++;
}
}
}

View File

@ -0,0 +1,37 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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_SUMMARY_H__
#define __YAFFS_SUMMARY_H__
#include "yaffs_packedtags2.h"
int yaffs_summary_init(struct yaffs_dev *dev);
void yaffs_summary_deinit(struct yaffs_dev *dev);
int yaffs_summary_add(struct yaffs_dev *dev,
struct yaffs_ext_tags *tags,
int chunk_in_block);
int yaffs_summary_fetch(struct yaffs_dev *dev,
struct yaffs_ext_tags *tags,
int chunk_in_block);
int yaffs_summary_read(struct yaffs_dev *dev,
struct yaffs_summary_tags *st,
int blk);
void yaffs_summary_gc(struct yaffs_dev *dev, int blk);
#endif

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -11,63 +11,27 @@
* published by the Free Software Foundation.
*/
/* XXX U-BOOT XXX */
#include <common.h>
#include "yaffs_guts.h"
#include "yaffs_tagscompat.h"
#include "yaffs_ecc.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_trace.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 void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
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)
void yaffs_calc_ecc(const u8 *data, struct yaffs_spare *spare)
{
yaffs_ECCCalculate(data, spare->ecc1);
yaffs_ECCCalculate(&data[256], spare->ecc2);
yaffs_ecc_calc(data, spare->ecc1);
yaffs_ecc_calc(&data[256], spare->ecc2);
}
void yaffs_CalcTagsECC(yaffs_Tags * tags)
void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
{
/* Calculate an ecc */
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
unsigned i, j;
unsigned ecc = 0;
unsigned bit = 0;
@ -77,34 +41,31 @@ void yaffs_CalcTagsECC(yaffs_Tags * tags)
for (i = 0; i < 8; i++) {
for (j = 1; j & 0xff; j <<= 1) {
bit++;
if (b[i] & j) {
if (b[i] & j)
ecc ^= bit;
}
}
}
tags->ecc = ecc;
}
int yaffs_CheckECCOnTags(yaffs_Tags * tags)
int yaffs_check_tags_ecc(struct yaffs_tags *tags)
{
unsigned ecc = tags->ecc;
yaffs_CalcTagsECC(tags);
yaffs_calc_tags_ecc(tags);
ecc ^= tags->ecc;
if (ecc && ecc <= 64) {
/* TODO: Handle the failure better. Retire? */
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
ecc--;
b[ecc / 8] ^= (1 << (ecc & 7));
/* Now recvalc the ecc */
yaffs_CalcTagsECC(tags);
yaffs_calc_tags_ecc(tags);
return 1; /* recovered error */
} else if (ecc) {
@ -112,235 +73,202 @@ int yaffs_CheckECCOnTags(yaffs_Tags * tags)
/* TODO Need to do somethiong here */
return -1; /* unrecovered error */
}
return 0;
}
/********** Tags **********/
static void yaffs_LoadTagsIntoSpare(yaffs_Spare * sparePtr,
yaffs_Tags * tagsPtr)
static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
struct yaffs_tags *tags_ptr)
{
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
yaffs_CalcTagsECC(tagsPtr);
yaffs_calc_tags_ecc(tags_ptr);
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];
spare_ptr->tb0 = tu->as_bytes[0];
spare_ptr->tb1 = tu->as_bytes[1];
spare_ptr->tb2 = tu->as_bytes[2];
spare_ptr->tb3 = tu->as_bytes[3];
spare_ptr->tb4 = tu->as_bytes[4];
spare_ptr->tb5 = tu->as_bytes[5];
spare_ptr->tb6 = tu->as_bytes[6];
spare_ptr->tb7 = tu->as_bytes[7];
}
static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr,
yaffs_TagsUnion *tu)
static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
struct yaffs_spare *spare_ptr,
struct yaffs_tags *tags_ptr)
{
union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
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;
tu->as_bytes[0] = spare_ptr->tb0;
tu->as_bytes[1] = spare_ptr->tb1;
tu->as_bytes[2] = spare_ptr->tb2;
tu->as_bytes[3] = spare_ptr->tb3;
tu->as_bytes[4] = spare_ptr->tb4;
tu->as_bytes[5] = spare_ptr->tb5;
tu->as_bytes[6] = spare_ptr->tb6;
tu->as_bytes[7] = spare_ptr->tb7;
result = yaffs_CheckECCOnTags(&tu->asTags);
if (result > 0) {
dev->tagsEccFixed++;
} else if (result < 0) {
dev->tagsEccUnfixed++;
}
result = yaffs_check_tags_ecc(tags_ptr);
if (result > 0)
dev->n_tags_ecc_fixed++;
else if (result < 0)
dev->n_tags_ecc_unfixed++;
}
static void yaffs_SpareInitialise(yaffs_Spare * spare)
static void yaffs_spare_init(struct yaffs_spare *spare)
{
memset(spare, 0xFF, sizeof(yaffs_Spare));
memset(spare, 0xff, sizeof(struct yaffs_spare));
}
static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, const __u8 * data,
yaffs_Spare * spare)
static int yaffs_wr_nand(struct yaffs_dev *dev,
int nand_chunk, const u8 *data,
struct yaffs_spare *spare)
{
if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
T(YAFFS_TRACE_ERROR,
(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
chunkInNAND));
if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>> yaffs chunk %d is not valid",
nand_chunk);
return YAFFS_FAIL;
}
dev->nPageWrites++;
return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
}
static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND,
__u8 * data,
yaffs_Spare * spare,
yaffs_ECCResult * eccResult,
int doErrorCorrection)
static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
int nand_chunk,
u8 *data,
struct yaffs_spare *spare,
enum yaffs_ecc_result *ecc_result,
int correct_errors)
{
int retVal;
yaffs_Spare localSpare;
int ret_val;
struct yaffs_spare local_spare;
dev->nPageReads++;
if (!spare && data) {
if (!spare) {
/* If we don't have a real spare, then we use a local one. */
/* Need this for the calculation of the ecc */
spare = &localSpare;
spare = &local_spare;
}
if (!dev->useNANDECC) {
retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
if (data && doErrorCorrection) {
if (!dev->param.use_nand_ecc) {
ret_val =
dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
if (data && correct_errors) {
/* Do ECC correction */
/* Todo handle any errors */
int eccResult1, eccResult2;
__u8 calcEcc[3];
int ecc_result1, ecc_result2;
u8 calc_ecc[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);
yaffs_ecc_calc(data, calc_ecc);
ecc_result1 =
yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
yaffs_ecc_calc(&data[256], calc_ecc);
ecc_result2 =
yaffs_ecc_correct(&data[256], spare->ecc2,
calc_ecc);
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 (ecc_result1 > 0) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>yaffs ecc error fix performed on chunk %d:0",
nand_chunk);
dev->n_ecc_fixed++;
} else if (ecc_result1 < 0) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>yaffs ecc error unfixed on chunk %d:0",
nand_chunk);
dev->n_ecc_unfixed++;
}
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 (ecc_result2 > 0) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>yaffs ecc error fix performed on chunk %d:1",
nand_chunk);
dev->n_ecc_fixed++;
} else if (ecc_result2 < 0) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>yaffs ecc error unfixed on chunk %d:1",
nand_chunk);
dev->n_ecc_unfixed++;
}
if (eccResult1 || eccResult2) {
if (ecc_result1 || ecc_result2) {
/* We had a data problem on this page */
yaffs_HandleReadDataError(dev, chunkInNAND);
yaffs_handle_rd_data_error(dev, nand_chunk);
}
if (eccResult1 < 0 || eccResult2 < 0)
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
else if (eccResult1 > 0 || eccResult2 > 0)
*eccResult = YAFFS_ECC_RESULT_FIXED;
if (ecc_result1 < 0 || ecc_result2 < 0)
*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
else if (ecc_result1 > 0 || ecc_result2 > 0)
*ecc_result = YAFFS_ECC_RESULT_FIXED;
else
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
*ecc_result = 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) {
struct yaffs_nand_spare nspare;
memset(&nspare, 0, sizeof(nspare));
ret_val = dev->param.read_chunk_fn(dev, nand_chunk, data,
(struct yaffs_spare *)
&nspare);
memcpy(spare, &nspare, sizeof(struct yaffs_spare));
if (data && correct_errors) {
if (nspare.eccres1 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error fix performed on chunk %d:0"
TENDSTR), chunkInNAND));
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>mtd ecc error fix performed on chunk %d:0",
nand_chunk);
} else if (nspare.eccres1 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error unfixed on chunk %d:0"
TENDSTR), chunkInNAND));
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>mtd ecc error unfixed on chunk %d:0",
nand_chunk);
}
if (nspare.eccres2 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error fix performed on chunk %d:1"
TENDSTR), chunkInNAND));
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>mtd ecc error fix performed on chunk %d:1",
nand_chunk);
} else if (nspare.eccres2 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error unfixed on chunk %d:1"
TENDSTR), chunkInNAND));
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>mtd ecc error unfixed on chunk %d:1",
nand_chunk);
}
if (nspare.eccres1 || nspare.eccres2) {
/* We had a data problem on this page */
yaffs_HandleReadDataError(dev, chunkInNAND);
yaffs_handle_rd_data_error(dev, nand_chunk);
}
if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
*eccResult = YAFFS_ECC_RESULT_FIXED;
*ecc_result = YAFFS_ECC_RESULT_FIXED;
else
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
}
}
return retVal;
return ret_val;
}
#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)
static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
{
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
int flash_block = nand_chunk / dev->param.chunks_per_block;
/* 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));
yaffs_get_block_info(dev, flash_block + dev->block_offset)->
needs_retiring = 1;
yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
"**>>Block %d marked for retirement",
flash_block);
/* TODO:
* Just do a garbage collection on the affected block
@ -349,184 +277,131 @@ static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND)
*/
}
#ifdef NOTYET
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
int yaffs_tags_compat_wr(struct yaffs_dev *dev,
int nand_chunk,
const u8 *data, const struct yaffs_ext_tags *ext_tags)
{
}
struct yaffs_spare spare;
struct yaffs_tags tags;
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_Spare * spare)
{
}
yaffs_spare_init(&spare);
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
const yaffs_Spare * spare)
{
}
if (ext_tags->is_deleted)
spare.page_status = 0;
else {
tags.obj_id = ext_tags->obj_id;
tags.chunk_id = ext_tags->chunk_id;
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
{
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
/* Mark the block for retirement */
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
/* Delete the chunk */
yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
}
if (dev->data_bytes_per_chunk >= 1024)
tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
else
tags.n_bytes_msb = 3;
static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
const yaffs_Spare * s0, const yaffs_Spare * s1)
{
tags.serial_number = ext_tags->serial_number;
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;
if (!dev->param.use_nand_ecc && data)
yaffs_calc_ecc(data, &spare);
yaffs_load_tags_to_spare(&spare, &tags);
}
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);
return yaffs_wr_nand(dev, nand_chunk, data, &spare);
}
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
int chunkInNAND,
__u8 * data,
yaffs_ExtendedTags * eTags)
int yaffs_tags_compat_rd(struct yaffs_dev *dev,
int nand_chunk,
u8 *data, struct yaffs_ext_tags *ext_tags)
{
yaffs_Spare spare;
yaffs_TagsUnion tags;
yaffs_ECCResult eccResult;
static yaffs_Spare spareFF;
struct yaffs_spare spare;
struct yaffs_tags tags;
enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
static struct yaffs_spare spare_ff;
static int init;
int deleted;
if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF));
memset(&spare_ff, 0xff, sizeof(spare_ff));
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.asTags.objectId;
eTags->chunkId = tags.asTags.chunkId;
eTags->byteCount = tags.asTags.byteCount;
eTags->serialNumber = tags.asTags.serialNumber;
}
}
return YAFFS_OK;
} else {
if (!yaffs_rd_chunk_nand(dev, nand_chunk,
data, &spare, &ecc_result, 1))
return YAFFS_FAIL;
/* ext_tags may be NULL */
if (!ext_tags)
return YAFFS_OK;
deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
ext_tags->is_deleted = deleted;
ext_tags->ecc_result = ecc_result;
ext_tags->block_bad = 0; /* We're reading it */
/* therefore it is not a bad block */
ext_tags->chunk_used =
memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;
if (ext_tags->chunk_used) {
yaffs_get_tags_from_spare(dev, &spare, &tags);
ext_tags->obj_id = tags.obj_id;
ext_tags->chunk_id = tags.chunk_id;
ext_tags->n_bytes = tags.n_bytes_lsb;
if (dev->data_bytes_per_chunk >= 1024)
ext_tags->n_bytes |=
(((unsigned)tags.n_bytes_msb) << 10);
ext_tags->serial_number = tags.serial_number;
}
}
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)
int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
{
struct yaffs_spare spare;
yaffs_Spare spare0, spare1;
static yaffs_Spare spareFF;
memset(&spare, 0xff, sizeof(struct yaffs_spare));
spare.block_status = 'Y';
yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
&spare);
yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
NULL, &spare);
return YAFFS_OK;
}
int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
int block_no,
enum yaffs_block_state *state,
u32 *seq_number)
{
struct yaffs_spare spare0, spare1;
static struct yaffs_spare spare_ff;
static int init;
yaffs_ECCResult dummy;
enum yaffs_ecc_result dummy;
if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF));
memset(&spare_ff, 0xff, sizeof(spare_ff));
init = 1;
}
*sequenceNumber = 0;
*seq_number = 0;
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
&spare0, &dummy, 1);
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
&spare1, &dummy, 1);
yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL,
&spare0, &dummy, 1);
yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
NULL, &spare1, &dummy, 1);
if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
if (hweight8(spare0.block_status & spare1.block_status) < 7)
*state = YAFFS_BLOCK_STATE_DEAD;
else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
*state = YAFFS_BLOCK_STATE_EMPTY;
else
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
return YAFFS_OK;
}

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -17,24 +17,20 @@
#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);
int yaffs_tags_compat_wr(struct yaffs_dev *dev,
int nand_chunk,
const u8 *data, const struct yaffs_ext_tags *tags);
int yaffs_tags_compat_rd(struct yaffs_dev *dev,
int nand_chunk,
u8 *data, struct yaffs_ext_tags *tags);
int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
int block_no,
enum yaffs_block_state *state,
u32 *seq_number);
void yaffs_CalcTagsECC(yaffs_Tags * tags);
int yaffs_CheckECCOnTags(yaffs_Tags * tags);
int yaffs_CountBits(__u8 byte);
void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
int yaffs_check_tags_ecc(struct yaffs_tags *tags);
int yaffs_count_bits(u8 byte);
#endif

View File

@ -1,31 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* XXX U-BOOT XXX */
#include <common.h>
#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,57 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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 __YTRACE_H__
#define __YTRACE_H__
extern unsigned int yaffs_trace_mask;
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_SYNC 0x00100000
#define YAFFS_TRACE_BACKGROUND 0x00200000
#define YAFFS_TRACE_LOCK 0x00400000
#define YAFFS_TRACE_MOUNT 0x00800000
#define YAFFS_TRACE_ERROR 0x40000000
#define YAFFS_TRACE_BUG 0x80000000
#define YAFFS_TRACE_ALWAYS 0xf0000000
#endif

View File

@ -0,0 +1,464 @@
/*
* 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 is set up for u-boot.
*
* This version now uses the ydevconfig mechanism to set up partitions.
*/
#include <common.h>
#include <config.h>
#include "nand.h"
#include "yaffscfg.h"
#include "yaffsfs.h"
#include "yaffs_packedtags2.h"
#include "yaffs_mtdif.h"
#include "yaffs_mtdif2.h"
#if 0
#include <errno.h>
#else
#include "malloc.h"
#endif
unsigned yaffs_trace_mask = 0x0; /* Disable logging */
static int yaffs_errno;
void yaffs_bug_fn(const char *fn, int n)
{
printf("yaffs bug at %s:%d\n", fn, n);
}
void *yaffsfs_malloc(size_t x)
{
return malloc(x);
}
void yaffsfs_free(void *x)
{
free(x);
}
void yaffsfs_SetError(int err)
{
yaffs_errno = err;
}
int yaffsfs_GetLastError(void)
{
return yaffs_errno;
}
int yaffsfs_GetError(void)
{
return yaffs_errno;
}
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)
{
/* No locking used */
}
static const char *yaffs_file_type_str(struct yaffs_stat *stat)
{
switch (stat->st_mode & S_IFMT) {
case S_IFREG: return "regular file";
case S_IFDIR: return "directory";
case S_IFLNK: return "symlink";
default: return "unknown";
}
}
static const char *yaffs_error_str(void)
{
int error = yaffsfs_GetLastError();
if (error < 0)
error = -error;
switch (error) {
case EBUSY: return "Busy";
case ENODEV: return "No such device";
case EINVAL: return "Invalid parameter";
case ENFILE: return "Too many open files";
case EBADF: return "Bad handle";
case EACCES: return "Wrong permissions";
case EXDEV: return "Not on same device";
case ENOENT: return "No such entry";
case ENOSPC: return "Device full";
case EROFS: return "Read only file system";
case ERANGE: return "Range error";
case ENOTEMPTY: return "Not empty";
case ENAMETOOLONG: return "Name too long";
case ENOMEM: return "Out of memory";
case EFAULT: return "Fault";
case EEXIST: return "Name exists";
case ENOTDIR: return "Not a directory";
case EISDIR: return "Not permitted on a directory";
case ELOOP: return "Symlink loop";
case 0: return "No error";
default: return "Unknown error";
}
}
extern nand_info_t nand_info[];
void cmd_yaffs_tracemask(unsigned set, unsigned mask)
{
if (set)
yaffs_trace_mask = mask;
printf("yaffs trace mask: %08x\n", yaffs_trace_mask);
}
static int yaffs_regions_overlap(int a, int b, int x, int y)
{
return (a <= x && x <= b) ||
(a <= y && y <= b) ||
(x <= a && a <= y) ||
(x <= b && b <= y);
}
void cmd_yaffs_devconfig(char *_mp, int flash_dev,
int start_block, int end_block)
{
struct mtd_info *mtd = NULL;
struct yaffs_dev *dev = NULL;
struct yaffs_dev *chk;
char *mp = NULL;
struct nand_chip *chip;
dev = calloc(1, sizeof(*dev));
mp = strdup(_mp);
mtd = &nand_info[flash_dev];
if (!dev || !mp) {
/* Alloc error */
printf("Failed to allocate memory\n");
goto err;
}
if (flash_dev >= CONFIG_SYS_MAX_NAND_DEVICE) {
printf("Flash device invalid\n");
goto err;
}
if (end_block == 0)
end_block = mtd->size / mtd->erasesize - 1;
if (end_block < start_block) {
printf("Bad start/end\n");
goto err;
}
chip = mtd->priv;
/* Check for any conflicts */
yaffs_dev_rewind();
while (1) {
chk = yaffs_next_dev();
if (!chk)
break;
if (strcmp(chk->param.name, mp) == 0) {
printf("Mount point name already used\n");
goto err;
}
if (chk->driver_context == mtd &&
yaffs_regions_overlap(
chk->param.start_block, chk->param.end_block,
start_block, end_block)) {
printf("Region overlaps with partition %s\n",
chk->param.name);
goto err;
}
}
/* Seems sane, so configure */
memset(dev, 0, sizeof(*dev));
dev->param.name = mp;
dev->driver_context = mtd;
dev->param.start_block = start_block;
dev->param.end_block = end_block;
dev->param.chunks_per_block = mtd->erasesize / mtd->writesize;
dev->param.total_bytes_per_chunk = mtd->writesize;
dev->param.is_yaffs2 = 1;
dev->param.use_nand_ecc = 1;
dev->param.n_reserved_blocks = 5;
if (chip->ecc.layout->oobavail < sizeof(struct yaffs_packed_tags2))
dev->param.inband_tags = 1;
dev->param.n_caches = 10;
dev->param.write_chunk_tags_fn = nandmtd2_write_chunk_tags;
dev->param.read_chunk_tags_fn = nandmtd2_read_chunk_tags;
dev->param.erase_fn = nandmtd_EraseBlockInNAND;
dev->param.initialise_flash_fn = nandmtd_InitialiseNAND;
dev->param.bad_block_fn = nandmtd2_MarkNANDBlockBad;
dev->param.query_block_fn = nandmtd2_QueryNANDBlock;
yaffs_add_device(dev);
printf("Configures yaffs mount %s: dev %d start block %d, end block %d %s\n",
mp, flash_dev, start_block, end_block,
dev->param.inband_tags ? "using inband tags" : "");
return;
err:
free(dev);
free(mp);
}
void cmd_yaffs_dev_ls(void)
{
struct yaffs_dev *dev;
int flash_dev;
int free_space;
yaffs_dev_rewind();
while (1) {
dev = yaffs_next_dev();
if (!dev)
return;
flash_dev =
((unsigned) dev->driver_context - (unsigned) nand_info)/
sizeof(nand_info[0]);
printf("%-10s %5d 0x%05x 0x%05x %s",
dev->param.name, flash_dev,
dev->param.start_block, dev->param.end_block,
dev->param.inband_tags ? "using inband tags, " : "");
free_space = yaffs_freespace(dev->param.name);
if (free_space < 0)
printf("not mounted\n");
else
printf("free 0x%x\n", free_space);
}
}
void make_a_file(char *yaffsName, char bval, int sizeOfFile)
{
int outh;
int i;
unsigned char buffer[100];
outh = yaffs_open(yaffsName,
O_CREAT | O_RDWR | O_TRUNC,
S_IREAD | S_IWRITE);
if (outh < 0) {
printf("Error opening file: %d. %s\n", outh, yaffs_error_str());
return;
}
memset(buffer, bval, 100);
do {
i = sizeOfFile;
if (i > 100)
i = 100;
sizeOfFile -= i;
yaffs_write(outh, buffer, i);
} while (sizeOfFile > 0);
yaffs_close(outh);
}
void read_a_file(char *fn)
{
int h;
int i = 0;
unsigned char b;
h = yaffs_open(fn, O_RDWR, 0);
if (h < 0) {
printf("File not found\n");
return;
}
while (yaffs_read(h, &b, 1) > 0) {
printf("%02x ", b);
i++;
if (i > 32) {
printf("\n");
i = 0;;
}
}
printf("\n");
yaffs_close(h);
}
void cmd_yaffs_mount(char *mp)
{
int retval = yaffs_mount(mp);
if (retval < 0)
printf("Error mounting %s, return value: %d, %s\n", mp,
yaffsfs_GetError(), yaffs_error_str());
}
void cmd_yaffs_umount(char *mp)
{
if (yaffs_unmount(mp) == -1)
printf("Error umounting %s, return value: %d, %s\n", mp,
yaffsfs_GetError(), yaffs_error_str());
}
void cmd_yaffs_write_file(char *yaffsName, char bval, int sizeOfFile)
{
make_a_file(yaffsName, bval, sizeOfFile);
}
void cmd_yaffs_read_file(char *fn)
{
read_a_file(fn);
}
void cmd_yaffs_mread_file(char *fn, char *addr)
{
int h;
struct yaffs_stat s;
yaffs_stat(fn, &s);
printf("Copy %s to 0x%p... ", fn, addr);
h = yaffs_open(fn, O_RDWR, 0);
if (h < 0) {
printf("File not found\n");
return;
}
yaffs_read(h, addr, (int)s.st_size);
printf("\t[DONE]\n");
yaffs_close(h);
}
void cmd_yaffs_mwrite_file(char *fn, char *addr, int size)
{
int outh;
outh = yaffs_open(fn, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE);
if (outh < 0)
printf("Error opening file: %d, %s\n", outh, yaffs_error_str());
yaffs_write(outh, addr, size);
yaffs_close(outh);
}
void cmd_yaffs_ls(const char *mountpt, int longlist)
{
int i;
yaffs_DIR *d;
struct yaffs_dirent *de;
struct yaffs_stat stat;
char tempstr[255];
d = yaffs_opendir(mountpt);
if (!d) {
printf("opendir failed, %s\n", yaffs_error_str());
return;
}
for (i = 0; (de = yaffs_readdir(d)) != NULL; i++) {
if (longlist) {
sprintf(tempstr, "%s/%s", mountpt, de->d_name);
yaffs_lstat(tempstr, &stat);
printf("%-25s\t%7ld",
de->d_name,
(long)stat.st_size);
printf(" %5d %s\n",
stat.st_ino,
yaffs_file_type_str(&stat));
} else {
printf("%s\n", de->d_name);
}
}
yaffs_closedir(d);
}
void cmd_yaffs_mkdir(const char *dir)
{
int retval = yaffs_mkdir(dir, 0);
if (retval < 0)
printf("yaffs_mkdir returning error: %d, %s\n",
retval, yaffs_error_str());
}
void cmd_yaffs_rmdir(const char *dir)
{
int retval = yaffs_rmdir(dir);
if (retval < 0)
printf("yaffs_rmdir returning error: %d, %s\n",
retval, yaffs_error_str());
}
void cmd_yaffs_rm(const char *path)
{
int retval = yaffs_unlink(path);
if (retval < 0)
printf("yaffs_unlink returning error: %d, %s\n",
retval, yaffs_error_str());
}
void cmd_yaffs_mv(const char *oldPath, const char *newPath)
{
int retval = yaffs_rename(newPath, oldPath);
if (retval < 0)
printf("yaffs_unlink returning error: %d, %s\n",
retval, yaffs_error_str());
}

View File

@ -0,0 +1,529 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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_verify.h"
#include "yaffs_trace.h"
#include "yaffs_bitmap.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_nand.h"
int yaffs_skip_verification(struct yaffs_dev *dev)
{
dev = dev;
return !(yaffs_trace_mask &
(YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
}
static int yaffs_skip_full_verification(struct yaffs_dev *dev)
{
dev = dev;
return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
}
static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
{
dev = dev;
return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
}
static const char * const block_state_name[] = {
"Unknown",
"Needs scan",
"Scanning",
"Empty",
"Allocating",
"Full",
"Dirty",
"Checkpoint",
"Collecting",
"Dead"
};
void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
{
int actually_used;
int in_use;
if (yaffs_skip_verification(dev))
return;
/* Report illegal runtime states */
if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
yaffs_trace(YAFFS_TRACE_VERIFY,
"Block %d has undefined state %d",
n, bi->block_state);
switch (bi->block_state) {
case YAFFS_BLOCK_STATE_UNKNOWN:
case YAFFS_BLOCK_STATE_SCANNING:
case YAFFS_BLOCK_STATE_NEEDS_SCAN:
yaffs_trace(YAFFS_TRACE_VERIFY,
"Block %d has bad run-state %s",
n, block_state_name[bi->block_state]);
}
/* Check pages in use and soft deletions are legal */
actually_used = bi->pages_in_use - bi->soft_del_pages;
if (bi->pages_in_use < 0 ||
bi->pages_in_use > dev->param.chunks_per_block ||
bi->soft_del_pages < 0 ||
bi->soft_del_pages > dev->param.chunks_per_block ||
actually_used < 0 || actually_used > dev->param.chunks_per_block)
yaffs_trace(YAFFS_TRACE_VERIFY,
"Block %d has illegal values pages_in_used %d soft_del_pages %d",
n, bi->pages_in_use, bi->soft_del_pages);
/* Check chunk bitmap legal */
in_use = yaffs_count_chunk_bits(dev, n);
if (in_use != bi->pages_in_use)
yaffs_trace(YAFFS_TRACE_VERIFY,
"Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
n, bi->pages_in_use, in_use);
}
void yaffs_verify_collected_blk(struct yaffs_dev *dev,
struct yaffs_block_info *bi, int n)
{
yaffs_verify_blk(dev, bi, n);
/* After collection the block should be in the erased state */
if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
yaffs_trace(YAFFS_TRACE_ERROR,
"Block %d is in state %d after gc, should be erased",
n, bi->block_state);
}
}
void yaffs_verify_blocks(struct yaffs_dev *dev)
{
int i;
int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
int illegal_states = 0;
if (yaffs_skip_verification(dev))
return;
memset(state_count, 0, sizeof(state_count));
for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
yaffs_verify_blk(dev, bi, i);
if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
state_count[bi->block_state]++;
else
illegal_states++;
}
yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary");
yaffs_trace(YAFFS_TRACE_VERIFY,
"%d blocks have illegal states",
illegal_states);
if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
yaffs_trace(YAFFS_TRACE_VERIFY,
"Too many allocating blocks");
for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
yaffs_trace(YAFFS_TRACE_VERIFY,
"%s %d blocks",
block_state_name[i], state_count[i]);
if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
yaffs_trace(YAFFS_TRACE_VERIFY,
"Checkpoint block count wrong dev %d count %d",
dev->blocks_in_checkpt,
state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
yaffs_trace(YAFFS_TRACE_VERIFY,
"Erased block count wrong dev %d count %d",
dev->n_erased_blocks,
state_count[YAFFS_BLOCK_STATE_EMPTY]);
if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
yaffs_trace(YAFFS_TRACE_VERIFY,
"Too many collecting blocks %d (max is 1)",
state_count[YAFFS_BLOCK_STATE_COLLECTING]);
}
/*
* Verify the object header. oh must be valid, but obj and tags may be NULL in
* which case those tests will not be performed.
*/
void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
struct yaffs_ext_tags *tags, int parent_check)
{
if (obj && yaffs_skip_verification(obj->my_dev))
return;
if (!(tags && obj && oh)) {
yaffs_trace(YAFFS_TRACE_VERIFY,
"Verifying object header tags %p obj %p oh %p",
tags, obj, oh);
return;
}
if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
oh->type > YAFFS_OBJECT_TYPE_MAX)
yaffs_trace(YAFFS_TRACE_VERIFY,
"Obj %d header type is illegal value 0x%x",
tags->obj_id, oh->type);
if (tags->obj_id != obj->obj_id)
yaffs_trace(YAFFS_TRACE_VERIFY,
"Obj %d header mismatch obj_id %d",
tags->obj_id, obj->obj_id);
/*
* Check that the object's parent ids match if parent_check requested.
*
* Tests do not apply to the root object.
*/
if (parent_check && tags->obj_id > 1 && !obj->parent)
yaffs_trace(YAFFS_TRACE_VERIFY,
"Obj %d header mismatch parent_id %d obj->parent is NULL",
tags->obj_id, oh->parent_obj_id);
if (parent_check && obj->parent &&
oh->parent_obj_id != obj->parent->obj_id &&
(oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
yaffs_trace(YAFFS_TRACE_VERIFY,
"Obj %d header mismatch parent_id %d parent_obj_id %d",
tags->obj_id, oh->parent_obj_id,
obj->parent->obj_id);
if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
yaffs_trace(YAFFS_TRACE_VERIFY,
"Obj %d header name is NULL",
obj->obj_id);
if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */
yaffs_trace(YAFFS_TRACE_VERIFY,
"Obj %d header name is 0xff",
obj->obj_id);
}
void yaffs_verify_file(struct yaffs_obj *obj)
{
u32 x;
int required_depth;
int actual_depth;
int last_chunk;
u32 offset_in_chunk;
u32 the_chunk;
u32 i;
struct yaffs_dev *dev;
struct yaffs_ext_tags tags;
struct yaffs_tnode *tn;
u32 obj_id;
if (!obj)
return;
if (yaffs_skip_verification(obj->my_dev))
return;
dev = obj->my_dev;
obj_id = obj->obj_id;
/* Check file size is consistent with tnode depth */
yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
&last_chunk, &offset_in_chunk);
last_chunk++;
x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
required_depth = 0;
while (x > 0) {
x >>= YAFFS_TNODES_INTERNAL_BITS;
required_depth++;
}
actual_depth = obj->variant.file_variant.top_level;
/* Check that the chunks in the tnode tree are all correct.
* We do this by scanning through the tnode tree and
* checking the tags for every chunk match.
*/
if (yaffs_skip_nand_verification(dev))
return;
for (i = 1; i <= last_chunk; i++) {
tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
if (!tn)
continue;
the_chunk = yaffs_get_group_base(dev, tn, i);
if (the_chunk > 0) {
yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
&tags);
if (tags.obj_id != obj_id || tags.chunk_id != i)
yaffs_trace(YAFFS_TRACE_VERIFY,
"Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
obj_id, i, the_chunk,
tags.obj_id, tags.chunk_id);
}
}
}
void yaffs_verify_link(struct yaffs_obj *obj)
{
if (obj && yaffs_skip_verification(obj->my_dev))
return;
/* Verify sane equivalent object */
}
void yaffs_verify_symlink(struct yaffs_obj *obj)
{
if (obj && yaffs_skip_verification(obj->my_dev))
return;
/* Verify symlink string */
}
void yaffs_verify_special(struct yaffs_obj *obj)
{
if (obj && yaffs_skip_verification(obj->my_dev))
return;
}
void yaffs_verify_obj(struct yaffs_obj *obj)
{
struct yaffs_dev *dev;
u32 chunk_min;
u32 chunk_max;
u32 chunk_id_ok;
u32 chunk_in_range;
u32 chunk_wrongly_deleted;
u32 chunk_valid;
if (!obj)
return;
if (obj->being_created)
return;
dev = obj->my_dev;
if (yaffs_skip_verification(dev))
return;
/* Check sane object header chunk */
chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
chunk_max =
(dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
((unsigned)(obj->hdr_chunk)) <= chunk_max);
chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
chunk_valid = chunk_in_range &&
yaffs_check_chunk_bit(dev,
obj->hdr_chunk / dev->param.chunks_per_block,
obj->hdr_chunk % dev->param.chunks_per_block);
chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
yaffs_trace(YAFFS_TRACE_VERIFY,
"Obj %d has chunk_id %d %s %s",
obj->obj_id, obj->hdr_chunk,
chunk_id_ok ? "" : ",out of range",
chunk_wrongly_deleted ? ",marked as deleted" : "");
if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
struct yaffs_ext_tags tags;
struct yaffs_obj_hdr *oh;
u8 *buffer = yaffs_get_temp_buffer(dev);
oh = (struct yaffs_obj_hdr *)buffer;
yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
yaffs_verify_oh(obj, oh, &tags, 1);
yaffs_release_temp_buffer(dev, buffer);
}
/* Verify it has a parent */
if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
yaffs_trace(YAFFS_TRACE_VERIFY,
"Obj %d has parent pointer %p which does not look like an object",
obj->obj_id, obj->parent);
}
/* Verify parent is a directory */
if (obj->parent &&
obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
yaffs_trace(YAFFS_TRACE_VERIFY,
"Obj %d's parent is not a directory (type %d)",
obj->obj_id, obj->parent->variant_type);
}
switch (obj->variant_type) {
case YAFFS_OBJECT_TYPE_FILE:
yaffs_verify_file(obj);
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
yaffs_verify_symlink(obj);
break;
case YAFFS_OBJECT_TYPE_DIRECTORY:
yaffs_verify_dir(obj);
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
yaffs_verify_link(obj);
break;
case YAFFS_OBJECT_TYPE_SPECIAL:
yaffs_verify_special(obj);
break;
case YAFFS_OBJECT_TYPE_UNKNOWN:
default:
yaffs_trace(YAFFS_TRACE_VERIFY,
"Obj %d has illegaltype %d",
obj->obj_id, obj->variant_type);
break;
}
}
void yaffs_verify_objects(struct yaffs_dev *dev)
{
struct yaffs_obj *obj;
int i;
struct list_head *lh;
if (yaffs_skip_verification(dev))
return;
/* Iterate through the objects in each hash entry */
for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
list_for_each(lh, &dev->obj_bucket[i].list) {
obj = list_entry(lh, struct yaffs_obj, hash_link);
yaffs_verify_obj(obj);
}
}
}
void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
{
struct list_head *lh;
struct yaffs_obj *list_obj;
int count = 0;
if (!obj) {
yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
BUG();
return;
}
if (yaffs_skip_verification(obj->my_dev))
return;
if (!obj->parent) {
yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
BUG();
return;
}
if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
BUG();
}
/* Iterate through the objects in each hash entry */
list_for_each(lh, &obj->parent->variant.dir_variant.children) {
list_obj = list_entry(lh, struct yaffs_obj, siblings);
yaffs_verify_obj(list_obj);
if (obj == list_obj)
count++;
}
if (count != 1) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
"Object in directory %d times",
count);
BUG();
}
}
void yaffs_verify_dir(struct yaffs_obj *directory)
{
struct list_head *lh;
struct yaffs_obj *list_obj;
if (!directory) {
BUG();
return;
}
if (yaffs_skip_full_verification(directory->my_dev))
return;
if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
"Directory has wrong type: %d",
directory->variant_type);
BUG();
}
/* Iterate through the objects in each hash entry */
list_for_each(lh, &directory->variant.dir_variant.children) {
list_obj = list_entry(lh, struct yaffs_obj, siblings);
if (list_obj->parent != directory) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
"Object in directory list has wrong parent %p",
list_obj->parent);
BUG();
}
yaffs_verify_obj_in_dir(list_obj);
}
}
static int yaffs_free_verification_failures;
void yaffs_verify_free_chunks(struct yaffs_dev *dev)
{
int counted;
int difference;
if (yaffs_skip_verification(dev))
return;
counted = yaffs_count_free_chunks(dev);
difference = dev->n_free_chunks - counted;
if (difference) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
"Freechunks verification failure %d %d %d",
dev->n_free_chunks, counted, difference);
yaffs_free_verification_failures++;
}
}
int yaffs_verify_file_sane(struct yaffs_obj *in)
{
in = in;
return YAFFS_OK;
}

View File

@ -0,0 +1,43 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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_VERIFY_H__
#define __YAFFS_VERIFY_H__
#include "yaffs_guts.h"
void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
int n);
void yaffs_verify_collected_blk(struct yaffs_dev *dev,
struct yaffs_block_info *bi, int n);
void yaffs_verify_blocks(struct yaffs_dev *dev);
void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
struct yaffs_ext_tags *tags, int parent_check);
void yaffs_verify_file(struct yaffs_obj *obj);
void yaffs_verify_link(struct yaffs_obj *obj);
void yaffs_verify_symlink(struct yaffs_obj *obj);
void yaffs_verify_special(struct yaffs_obj *obj);
void yaffs_verify_obj(struct yaffs_obj *obj);
void yaffs_verify_objects(struct yaffs_dev *dev);
void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
void yaffs_verify_dir(struct yaffs_obj *directory);
void yaffs_verify_free_chunks(struct yaffs_dev *dev);
int yaffs_verify_file_sane(struct yaffs_obj *obj);
int yaffs_skip_verification(struct yaffs_dev *dev);
#endif

View File

@ -0,0 +1,422 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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_yaffs1.h"
#include "yportenv.h"
#include "yaffs_trace.h"
#include "yaffs_bitmap.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_nand.h"
#include "yaffs_attribs.h"
int yaffs1_scan(struct yaffs_dev *dev)
{
struct yaffs_ext_tags tags;
int blk;
int result;
int chunk;
int c;
int deleted;
enum yaffs_block_state state;
LIST_HEAD(hard_list);
struct yaffs_block_info *bi;
u32 seq_number;
struct yaffs_obj_hdr *oh;
struct yaffs_obj *in;
struct yaffs_obj *parent;
int alloc_failed = 0;
struct yaffs_shadow_fixer *shadow_fixers = NULL;
u8 *chunk_data;
yaffs_trace(YAFFS_TRACE_SCAN,
"yaffs1_scan starts intstartblk %d intendblk %d...",
dev->internal_start_block, dev->internal_end_block);
chunk_data = yaffs_get_temp_buffer(dev);
dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
/* Scan all the blocks to determine their state */
bi = dev->block_info;
for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
blk++) {
yaffs_clear_chunk_bits(dev, blk);
bi->pages_in_use = 0;
bi->soft_del_pages = 0;
yaffs_query_init_block_state(dev, blk, &state, &seq_number);
bi->block_state = state;
bi->seq_number = seq_number;
if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
"Block scanning block %d state %d seq %d",
blk, state, seq_number);
if (state == YAFFS_BLOCK_STATE_DEAD) {
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
"block %d is bad", blk);
} else if (state == YAFFS_BLOCK_STATE_EMPTY) {
yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
dev->n_erased_blocks++;
dev->n_free_chunks += dev->param.chunks_per_block;
}
bi++;
}
/* For each block.... */
for (blk = dev->internal_start_block;
!alloc_failed && blk <= dev->internal_end_block; blk++) {
cond_resched();
bi = yaffs_get_block_info(dev, blk);
state = bi->block_state;
deleted = 0;
/* For each chunk in each block that needs scanning.... */
for (c = 0;
!alloc_failed && c < dev->param.chunks_per_block &&
state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
/* Read the tags and decide what to do */
chunk = blk * dev->param.chunks_per_block + c;
result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
&tags);
/* Let's have a good look at this chunk... */
if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
tags.is_deleted) {
/* YAFFS1 only...
* A deleted chunk
*/
deleted++;
dev->n_free_chunks++;
} else if (!tags.chunk_used) {
/* An unassigned chunk in the block
* This means that either the block is empty or
* this is the one being allocated from
*/
if (c == 0) {
/* We're looking at the first chunk in
*the block so the block is unused */
state = YAFFS_BLOCK_STATE_EMPTY;
dev->n_erased_blocks++;
} else {
/* this is the block being allocated */
yaffs_trace(YAFFS_TRACE_SCAN,
" Allocating from %d %d",
blk, c);
state = YAFFS_BLOCK_STATE_ALLOCATING;
dev->alloc_block = blk;
dev->alloc_page = c;
dev->alloc_block_finder = blk;
}
dev->n_free_chunks +=
(dev->param.chunks_per_block - c);
} else if (tags.chunk_id > 0) {
/* chunk_id > 0 so it is a data chunk... */
unsigned int endpos;
yaffs_set_chunk_bit(dev, blk, c);
bi->pages_in_use++;
in = yaffs_find_or_create_by_number(dev,
tags.obj_id,
YAFFS_OBJECT_TYPE_FILE);
/* PutChunkIntoFile checks for a clash
* (two data chunks with the same chunk_id).
*/
if (!in)
alloc_failed = 1;
if (in) {
if (!yaffs_put_chunk_in_file
(in, tags.chunk_id, chunk, 1))
alloc_failed = 1;
}
endpos =
(tags.chunk_id - 1) *
dev->data_bytes_per_chunk +
tags.n_bytes;
if (in &&
in->variant_type ==
YAFFS_OBJECT_TYPE_FILE &&
in->variant.file_variant.scanned_size <
endpos) {
in->variant.file_variant.scanned_size =
endpos;
if (!dev->param.use_header_file_size) {
in->variant.
file_variant.file_size =
in->variant.
file_variant.scanned_size;
}
}
} else {
/* chunk_id == 0, so it is an ObjectHeader.
* Make the object
*/
yaffs_set_chunk_bit(dev, blk, c);
bi->pages_in_use++;
result = yaffs_rd_chunk_tags_nand(dev, chunk,
chunk_data,
NULL);
oh = (struct yaffs_obj_hdr *)chunk_data;
in = yaffs_find_by_number(dev, tags.obj_id);
if (in && in->variant_type != oh->type) {
/* This should not happen, but somehow
* Wev'e ended up with an obj_id that
* has been reused but not yet deleted,
* and worse still it has changed type.
* Delete the old object.
*/
yaffs_del_obj(in);
in = NULL;
}
in = yaffs_find_or_create_by_number(dev,
tags.obj_id,
oh->type);
if (!in)
alloc_failed = 1;
if (in && oh->shadows_obj > 0) {
struct yaffs_shadow_fixer *fixer;
fixer =
kmalloc(sizeof
(struct yaffs_shadow_fixer),
GFP_NOFS);
if (fixer) {
fixer->next = shadow_fixers;
shadow_fixers = fixer;
fixer->obj_id = tags.obj_id;
fixer->shadowed_id =
oh->shadows_obj;
yaffs_trace(YAFFS_TRACE_SCAN,
" Shadow fixer: %d shadows %d",
fixer->obj_id,
fixer->shadowed_id);
}
}
if (in && in->valid) {
/* We have already filled this one.
* We have a duplicate and need to
* resolve it. */
unsigned existing_serial = in->serial;
unsigned new_serial =
tags.serial_number;
if (((existing_serial + 1) & 3) ==
new_serial) {
/* Use new one - destroy the
* exisiting one */
yaffs_chunk_del(dev,
in->hdr_chunk,
1, __LINE__);
in->valid = 0;
} else {
/* Use existing - destroy
* this one. */
yaffs_chunk_del(dev, chunk, 1,
__LINE__);
}
}
if (in && !in->valid &&
(tags.obj_id == YAFFS_OBJECTID_ROOT ||
tags.obj_id ==
YAFFS_OBJECTID_LOSTNFOUND)) {
/* We only load some info, don't fiddle
* with directory structure */
in->valid = 1;
in->variant_type = oh->type;
in->yst_mode = oh->yst_mode;
yaffs_load_attribs(in, oh);
in->hdr_chunk = chunk;
in->serial = tags.serial_number;
} else if (in && !in->valid) {
/* we need to load this info */
in->valid = 1;
in->variant_type = oh->type;
in->yst_mode = oh->yst_mode;
yaffs_load_attribs(in, oh);
in->hdr_chunk = chunk;
in->serial = tags.serial_number;
yaffs_set_obj_name_from_oh(in, oh);
in->dirty = 0;
/* directory stuff...
* hook up to parent
*/
parent =
yaffs_find_or_create_by_number
(dev, oh->parent_obj_id,
YAFFS_OBJECT_TYPE_DIRECTORY);
if (!parent)
alloc_failed = 1;
if (parent && parent->variant_type ==
YAFFS_OBJECT_TYPE_UNKNOWN) {
/* Set up as a directory */
parent->variant_type =
YAFFS_OBJECT_TYPE_DIRECTORY;
INIT_LIST_HEAD(&parent->
variant.dir_variant.
children);
} else if (!parent ||
parent->variant_type !=
YAFFS_OBJECT_TYPE_DIRECTORY) {
/* Hoosterman, a problem....
* We're trying to use a
* non-directory as a directory
*/
yaffs_trace(YAFFS_TRACE_ERROR,
"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
);
parent = dev->lost_n_found;
}
yaffs_add_obj_to_dir(parent, in);
switch (in->variant_type) {
case YAFFS_OBJECT_TYPE_UNKNOWN:
/* Todo got a problem */
break;
case YAFFS_OBJECT_TYPE_FILE:
if (dev->param.
use_header_file_size)
in->variant.
file_variant.file_size
= yaffs_oh_to_size(oh);
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
in->variant.
hardlink_variant.equiv_id =
oh->equiv_id;
list_add(&in->hard_links,
&hard_list);
break;
case YAFFS_OBJECT_TYPE_DIRECTORY:
/* Do nothing */
break;
case YAFFS_OBJECT_TYPE_SPECIAL:
/* Do nothing */
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
in->variant.symlink_variant.
alias =
yaffs_clone_str(oh->alias);
if (!in->variant.
symlink_variant.alias)
alloc_failed = 1;
break;
}
}
}
}
if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
/* If we got this far while scanning,
* then the block is fully allocated. */
state = YAFFS_BLOCK_STATE_FULL;
}
if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
/* If the block was partially allocated then
* treat it as fully allocated. */
state = YAFFS_BLOCK_STATE_FULL;
dev->alloc_block = -1;
}
bi->block_state = state;
/* Now let's see if it was dirty */
if (bi->pages_in_use == 0 &&
!bi->has_shrink_hdr &&
bi->block_state == YAFFS_BLOCK_STATE_FULL)
yaffs_block_became_dirty(dev, blk);
}
/* Ok, we've done all the scanning.
* Fix up the hard link chains.
* We should now have scanned all the objects, now it's time to add
* these hardlinks.
*/
yaffs_link_fixup(dev, &hard_list);
/*
* Fix up any shadowed objects.
* There should not be more than one of these.
*/
{
struct yaffs_shadow_fixer *fixer;
struct yaffs_obj *obj;
while (shadow_fixers) {
fixer = shadow_fixers;
shadow_fixers = fixer->next;
/* Complete the rename transaction by deleting the
* shadowed object then setting the object header
to unshadowed.
*/
obj = yaffs_find_by_number(dev, fixer->shadowed_id);
if (obj)
yaffs_del_obj(obj);
obj = yaffs_find_by_number(dev, fixer->obj_id);
if (obj)
yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
kfree(fixer);
}
}
yaffs_release_temp_buffer(dev, chunk_data);
if (alloc_failed)
return YAFFS_FAIL;
yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
return YAFFS_OK;
}

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -13,9 +13,10 @@
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFSINTERFACE_H__
#define __YAFFSINTERFACE_H__
#ifndef __YAFFS_YAFFS1_H__
#define __YAFFS_YAFFS1_H__
int yaffs_Initialise(unsigned nBlocks);
#include "yaffs_guts.h"
int yaffs1_scan(struct yaffs_dev *dev);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 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_YAFFS2_H__
#define __YAFFS_YAFFS2_H__
#include "yaffs_guts.h"
void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
struct yaffs_block_info *bi);
void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
struct yaffs_block_info *bi);
int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
int yaffs2_checkpt_required(struct yaffs_dev *dev);
int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
int yaffs2_checkpt_save(struct yaffs_dev *dev);
int yaffs2_checkpt_restore(struct yaffs_dev *dev);
int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
int yaffs2_scan_backwards(struct yaffs_dev *dev);
#endif

View File

@ -1,420 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* yaffscfg.c The configuration for the "direct" use of yaffs.
*
* This file is intended to be modified to your requirements.
* There is no need to redistribute this file.
*/
/* XXX U-BOOT XXX */
#include <common.h>
#include <config.h>
#include "nand.h"
#include "yaffscfg.h"
#include "yaffsfs.h"
#include "yaffs_packedtags2.h"
#include "yaffs_mtdif.h"
#include "yaffs_mtdif2.h"
#if 0
#include <errno.h>
#else
#include "malloc.h"
#endif
unsigned yaffs_traceMask = 0x0; /* Disable logging */
static int yaffs_errno = 0;
void yaffsfs_SetError(int err)
{
//Do whatever to set error
yaffs_errno = err;
}
int yaffsfs_GetError(void)
{
return yaffs_errno;
}
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 int isMounted = 0;
#define MOUNT_POINT "/flash"
extern nand_info_t nand_info[];
/* XXX U-BOOT XXX */
#if 0
static yaffs_Device ramDev;
static yaffs_Device bootDev;
static yaffs_Device flashDev;
#endif
static yaffsfs_DeviceConfiguration yaffsfs_config[] = {
/* XXX U-BOOT XXX */
#if 0
{ "/ram", &ramDev},
{ "/boot", &bootDev},
{ "/flash", &flashDev},
#else
{ MOUNT_POINT, 0},
#endif
{(void *)0,(void *)0}
};
int yaffs_StartUp(void)
{
struct mtd_info *mtd = &nand_info[0];
int yaffsVersion = 2;
int nBlocks;
yaffs_Device *flashDev = calloc(1, sizeof(yaffs_Device));
yaffsfs_config[0].dev = flashDev;
/* store the mtd device for later use */
flashDev->genericDevice = mtd;
// Stuff to configure YAFFS
// Stuff to initialise anything special (eg lock semaphore).
yaffsfs_LocalInitialisation();
// Set up devices
/* XXX U-BOOT XXX */
#if 0
// /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;
#endif
// /flash
flashDev->nReservedBlocks = 5;
// flashDev->nShortOpCaches = (options.no_cache) ? 0 : 10;
flashDev->nShortOpCaches = 10; // Use caches
flashDev->useNANDECC = 0; // do not use YAFFS's ECC
if (yaffsVersion == 2)
{
flashDev->writeChunkWithTagsToNAND = nandmtd2_WriteChunkWithTagsToNAND;
flashDev->readChunkWithTagsFromNAND = nandmtd2_ReadChunkWithTagsFromNAND;
flashDev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
flashDev->queryNANDBlock = nandmtd2_QueryNANDBlock;
flashDev->spareBuffer = YMALLOC(mtd->oobsize);
flashDev->isYaffs2 = 1;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
flashDev->nDataBytesPerChunk = mtd->writesize;
flashDev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
#else
flashDev->nDataBytesPerChunk = mtd->oobblock;
flashDev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
#endif
nBlocks = mtd->size / mtd->erasesize;
flashDev->nCheckpointReservedBlocks = 10;
flashDev->startBlock = 0;
flashDev->endBlock = nBlocks - 1;
}
else
{
flashDev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
flashDev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
flashDev->isYaffs2 = 0;
nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
flashDev->startBlock = 320;
flashDev->endBlock = nBlocks - 1;
flashDev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
flashDev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
}
/* ... and common functions */
flashDev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
flashDev->initialiseNAND = nandmtd_InitialiseNAND;
yaffs_initialise(yaffsfs_config);
return 0;
}
void make_a_file(char *yaffsName,char bval,int sizeOfFile)
{
int outh;
int i;
unsigned char buffer[100];
outh = yaffs_open(yaffsName, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE);
if (outh < 0)
{
printf("Error opening file: %d\n", outh);
return;
}
memset(buffer,bval,100);
do{
i = sizeOfFile;
if(i > 100) i = 100;
sizeOfFile -= i;
yaffs_write(outh,buffer,i);
} while (sizeOfFile > 0);
yaffs_close(outh);
}
void read_a_file(char *fn)
{
int h;
int i = 0;
unsigned char b;
h = yaffs_open(fn, O_RDWR,0);
if(h<0)
{
printf("File not found\n");
return;
}
while(yaffs_read(h,&b,1)> 0)
{
printf("%02x ",b);
i++;
if(i > 32)
{
printf("\n");
i = 0;;
}
}
printf("\n");
yaffs_close(h);
}
void cmd_yaffs_mount(char *mp)
{
yaffs_StartUp();
int retval = yaffs_mount(mp);
if( retval != -1)
isMounted = 1;
else
printf("Error mounting %s, return value: %d\n", mp, yaffsfs_GetError());
}
static void checkMount(void)
{
if( !isMounted )
{
cmd_yaffs_mount(MOUNT_POINT);
}
}
void cmd_yaffs_umount(char *mp)
{
checkMount();
if( yaffs_unmount(mp) == -1)
printf("Error umounting %s, return value: %d\n", mp, yaffsfs_GetError());
}
void cmd_yaffs_write_file(char *yaffsName,char bval,int sizeOfFile)
{
checkMount();
make_a_file(yaffsName,bval,sizeOfFile);
}
void cmd_yaffs_read_file(char *fn)
{
checkMount();
read_a_file(fn);
}
void cmd_yaffs_mread_file(char *fn, char *addr)
{
int h;
struct yaffs_stat s;
checkMount();
yaffs_stat(fn,&s);
printf ("Copy %s to 0x%p... ", fn, addr);
h = yaffs_open(fn, O_RDWR,0);
if(h<0)
{
printf("File not found\n");
return;
}
yaffs_read(h,addr,(int)s.st_size);
printf("\t[DONE]\n");
yaffs_close(h);
}
void cmd_yaffs_mwrite_file(char *fn, char *addr, int size)
{
int outh;
checkMount();
outh = yaffs_open(fn, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE);
if (outh < 0)
{
printf("Error opening file: %d\n", outh);
}
yaffs_write(outh,addr,size);
yaffs_close(outh);
}
void cmd_yaffs_ls(const char *mountpt, int longlist)
{
int i;
yaffs_DIR *d;
yaffs_dirent *de;
struct yaffs_stat stat;
char tempstr[255];
checkMount();
d = yaffs_opendir(mountpt);
if(!d)
{
printf("opendir failed\n");
}
else
{
for(i = 0; (de = yaffs_readdir(d)) != NULL; i++)
{
if (longlist)
{
sprintf(tempstr, "%s/%s", mountpt, de->d_name);
yaffs_stat(tempstr, &stat);
printf("%-25s\t%7ld\n",de->d_name, stat.st_size);
}
else
{
printf("%s\n",de->d_name);
}
}
}
}
void cmd_yaffs_mkdir(const char *dir)
{
checkMount();
int retval = yaffs_mkdir(dir, 0);
if ( retval < 0)
printf("yaffs_mkdir returning error: %d\n", retval);
}
void cmd_yaffs_rmdir(const char *dir)
{
checkMount();
int retval = yaffs_rmdir(dir);
if ( retval < 0)
printf("yaffs_rmdir returning error: %d\n", retval);
}
void cmd_yaffs_rm(const char *path)
{
checkMount();
int retval = yaffs_unlink(path);
if ( retval < 0)
printf("yaffs_unlink returning error: %d\n", retval);
}
void cmd_yaffs_mv(const char *oldPath, const char *newPath)
{
checkMount();
int retval = yaffs_rename(newPath, oldPath);
if ( retval < 0)
printf("yaffs_unlink returning error: %d\n", retval);
}

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -23,23 +23,16 @@
#define __YAFFSCFG_H__
#include "devextras.h"
#include "yportenv.h"
#define YAFFSFS_N_HANDLES 200
#define YAFFSFS_N_HANDLES 100
#define YAFFSFS_N_DSC 20
typedef struct {
const char *prefix;
struct yaffs_DeviceStruct *dev;
} yaffsfs_DeviceConfiguration;
struct yaffsfs_DeviceConfiguration {
const YCHAR *prefix;
struct yaffs_dev *dev;
};
void yaffsfs_Lock(void);
void yaffsfs_Unlock(void);
__u32 yaffsfs_CurrentTime(void);
void yaffsfs_SetError(int err);
int yaffsfs_GetError(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -26,206 +26,184 @@
#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
#define YAFFS_MAX_FILE_SIZE (0x800000000LL - 1)
// 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 */
struct yaffs_dirent {
long d_ino; /* inode number */
off_t d_off; /* offset to this dirent */
unsigned short d_reclen; /* length of this dirent */
YUCHAR d_type; /* type of this record */
YCHAR d_name[NAME_MAX+1]; /* file name (null-terminated) */
unsigned d_dont_use; /* debug: not for public consumption */
};
typedef struct yaffs_dirent yaffs_dirent;
typedef struct __opaque yaffs_DIR;
typedef struct opaque_structure 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 */
struct yaffs_stat {
int st_dev; /* device */
int st_ino; /* inode */
unsigned st_mode; /* protection */
int st_nlink; /* number of hard links */
int st_uid; /* user ID of owner */
int st_gid; /* group ID of owner */
unsigned st_rdev; /* device type (if inode device) */
loff_t st_size; /* total size, in bytes */
unsigned long st_blksize; /* blocksize for filesystem I/O */
unsigned long st_blocks; /* number of blocks allocated */
#ifdef CONFIG_YAFFS_WINCE
/* Special 64-bit times for WinCE */
unsigned long yst_wince_atime[2];
unsigned long yst_wince_mtime[2];
unsigned long yst_wince_ctime[2];
#else
unsigned long yst_atime; /* time of last access */
unsigned long yst_mtime; /* time of last modification */
unsigned long yst_ctime; /* time of last change */
#endif
};
int yaffs_open(const char *path, int oflag, int mode) ;
struct yaffs_utimbuf {
unsigned long actime;
unsigned long modtime;
};
int yaffs_open(const YCHAR *path, int oflag, int mode) ;
int yaffs_close(int fd) ;
int yaffs_fsync(int fd) ;
int yaffs_fdatasync(int fd) ;
int yaffs_flush(int fd) ; /* same as yaffs_fsync() */
int yaffs_access(const YCHAR *path, int amode);
int yaffs_dup(int fd);
int yaffs_read(int fd, void *buf, unsigned int nbyte) ;
int yaffs_write(int fd, const void *buf, unsigned int nbyte) ;
int yaffs_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_pread(int fd, void *buf, unsigned int nbyte, loff_t offset);
int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, loff_t offset);
int yaffs_stat(const char *path, struct yaffs_stat *buf) ;
int yaffs_lstat(const char *path, struct yaffs_stat *buf) ;
loff_t yaffs_lseek(int fd, loff_t offset, int whence) ;
int yaffs_truncate(const YCHAR *path, loff_t new_size);
int yaffs_ftruncate(int fd, loff_t new_size);
int yaffs_unlink(const YCHAR *path) ;
int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath) ;
int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf) ;
int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf) ;
int yaffs_fstat(int fd, struct yaffs_stat *buf) ;
int yaffs_chmod(const char *path, mode_t mode);
int yaffs_utime(const YCHAR *path, const struct yaffs_utimbuf *buf);
int yaffs_futime(int fd, const struct yaffs_utimbuf *buf);
int yaffs_setxattr(const char *path, const char *name,
const void *data, int size, int flags);
int yaffs_lsetxattr(const char *path, const char *name,
const void *data, int size, int flags);
int yaffs_fsetxattr(int fd, const char *name,
const void *data, int size, int flags);
int yaffs_getxattr(const char *path, const char *name,
void *data, int size);
int yaffs_lgetxattr(const char *path, const char *name,
void *data, int size);
int yaffs_fgetxattr(int fd, const char *name,
void *data, int size);
int yaffs_removexattr(const char *path, const char *name);
int yaffs_lremovexattr(const char *path, const char *name);
int yaffs_fremovexattr(int fd, const char *name);
int yaffs_listxattr(const char *path, char *list, int size);
int yaffs_llistxattr(const char *path, char *list, int size);
int yaffs_flistxattr(int fd, char *list, int size);
#ifdef CONFIG_YAFFS_WINCE
int yaffs_set_wince_times(int fd,
const unsigned *wctime,
const unsigned *watime,
const unsigned *wmtime);
int yaffs_get_wince_times(int fd,
unsigned *wctime,
unsigned *watime,
unsigned *wmtime);
#endif
int yaffs_chmod(const YCHAR *path, mode_t mode);
int yaffs_fchmod(int fd, mode_t mode);
int yaffs_mkdir(const char *path, mode_t mode) ;
int yaffs_rmdir(const char *path) ;
int yaffs_mkdir(const YCHAR *path, mode_t mode) ;
int yaffs_rmdir(const YCHAR *path) ;
yaffs_DIR *yaffs_opendir(const char *dirname) ;
yaffs_DIR *yaffs_opendir(const YCHAR *dirname) ;
struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) ;
void yaffs_rewinddir(yaffs_DIR *dirp) ;
int yaffs_closedir(yaffs_DIR *dirp) ;
int yaffs_mount(const char *path) ;
int yaffs_unmount(const char *path) ;
int yaffs_mount(const YCHAR *path) ;
int yaffs_mount2(const YCHAR *path, int read_only);
int yaffs_mount_common(const YCHAR *path, int read_only, int skip_checkpt);
int yaffs_symlink(const char *oldpath, const char *newpath);
int yaffs_readlink(const char *path, char *buf, int bufsiz);
int yaffs_unmount(const YCHAR *path) ;
int yaffs_unmount2(const YCHAR *path, int force);
int yaffs_remount(const YCHAR *path, int force, int read_only);
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);
int yaffs_sync(const YCHAR *path) ;
void yaffs_initialise(yaffsfs_DeviceConfiguration *configList);
int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath);
int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz);
int yaffs_StartUp(void);
int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath);
int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev);
loff_t yaffs_freespace(const YCHAR *path);
loff_t yaffs_totalspace(const YCHAR *path);
int yaffs_inodecount(const YCHAR *path);
int yaffs_n_handles(const YCHAR *path);
#define YAFFS_SHARE_READ 1
#define YAFFS_SHARE_WRITE 2
int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int shareMode);
struct yaffs_dev;
void yaffs_add_device(struct yaffs_dev *dev);
int yaffs_start_up(void);
int yaffsfs_GetLastError(void);
/* Functions to iterate through devices. NB Use with extreme care! */
void yaffs_dev_rewind(void);
struct yaffs_dev *yaffs_next_dev(void);
/* Function to get the last error */
int yaffs_get_error(void);
const char *yaffs_error_to_str(int err);
/* Function only for debugging */
void *yaffs_getdev(const YCHAR *path);
int yaffs_dump_dev(const YCHAR *path);
int yaffs_set_error(int error);
/* Trace control functions */
unsigned yaffs_set_trace(unsigned tm);
unsigned yaffs_get_trace(void);
#endif

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -20,73 +20,75 @@
#ifndef __YDIRECTENV_H__
#define __YDIRECTENV_H__
/* Direct interface */
#include "devextras.h"
/* XXX U-BOOT XXX */
#if 0
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "assert.h"
#endif
#include "yaffs_malloc.h"
#include "yaffs_osglue.h"
#include "yaffs_hweight.h"
void yaffs_bug_fn(const char *file_name, int line_no);
#define BUG() do { yaffs_bug_fn(__FILE__, __LINE__); } while (0)
/* XXX U-BOOT XXX */
#if 0
#define YBUG() assert(1)
#endif
#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
#define yaffs_strcat(a, b) strcat(a, b)
#define yaffs_strcpy(a, b) strcpy(a, b)
#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
#define yaffs_strnlen(s, m) strnlen(s, m)
#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
#define yaffs_strcmp(a, b) strcasecmp(a, b)
#define yaffs_strncmp(a, b, c) strncasecmp(a, b, c)
#else
#define Y_INLINE inline
#define yaffs_strcmp(a, b) strcmp(a, b)
#define yaffs_strncmp(a, b, c) strncmp(a, b, c)
#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 hweight8(x) yaffs_hweight8(x)
#define hweight32(x) yaffs_hweight32(x)
#define YMALLOC_DMA(x) yaffs_malloc(x)
void yaffs_qsort(void *aa, size_t n, size_t es,
int (*cmp)(const void *, const void *));
#define YYIELD() do {} while(0)
#define sort(base, n, sz, cmp_fn, swp) yaffs_qsort(base, n, sz, cmp_fn)
#define YAFFS_PATH_DIVIDERS "/"
#ifdef NO_inline
#define inline
#else
#define inline __inline__
#endif
//#define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s))
//#define YALERT(s) YINFO(s)
#define kmalloc(x, flags) yaffsfs_malloc(x)
#define kfree(x) yaffsfs_free(x)
#define vmalloc(x) yaffsfs_malloc(x)
#define vfree(x) yaffsfs_free(x)
#define cond_resched() do {} while (0)
#define TENDSTR "\n"
#define TSTR(x) x
#define TOUT(p) printf p
#define yaffs_trace(msk, fmt, ...) do { \
if (yaffs_trace_mask & (msk)) \
printf("yaffs: " fmt "\n", ##__VA_ARGS__); \
} while (0)
#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_ROOT_MODE 0666
#define YAFFS_LOSTNFOUND_MODE 0666
#define yaffs_SumCompare(x,y) ((x) == (y))
#define yaffs_strcmp(a,b) strcmp(a,b)
#include "yaffs_list.h"
#include "yaffsfs.h"
#endif

View File

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -17,82 +17,62 @@
#ifndef __YPORTENV_H__
#define __YPORTENV_H__
/* XXX U-BOOT XXX */
#ifndef CONFIG_YAFFS_DIRECT
#define CONFIG_YAFFS_DIRECT
/* Definition of types */
#ifdef CONFIG_YAFFS_DEFINES_TYPES
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned u32;
#endif
#ifdef CONFIG_YAFFS_PROVIDE_DEFS
/* 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
/*
* Attribute flags.
* These are or-ed together to select 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
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;
};
#endif
#if defined CONFIG_YAFFS_WINCE
#include "ywinceenv.h"
/* XXX U-BOOT XXX */
#elif 0 /* 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
@ -101,46 +81,7 @@
#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)
#include "yutilsenv.h"
#else
/* Should have specified a configuration type */
@ -148,46 +89,220 @@
#endif
/* see yaffs_fs.c */
extern unsigned int yaffs_traceMask;
extern unsigned int yaffs_wr_attempts;
#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
/*
* Tracing flags.
* The flags masked in YAFFS_TRACE_ALWAYS are always traced.
*/
#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
#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
#ifndef O_RDONLY
#define O_RDONLY 00
#endif
#define YAFFS_TRACE_VERIFY 0x00010000
#define YAFFS_TRACE_VERIFY_NAND 0x00020000
#define YAFFS_TRACE_VERIFY_FULL 0x00040000
#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
#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 ENFILE
#define ENFILE 23
#endif
#ifndef EBADF
#define EBADF 9
#endif
#ifndef EACCES
#define EACCES 13
#endif
#ifndef EXDEV
#define EXDEV 18
#endif
#ifndef ENOENT
#define ENOENT 2
#endif
#ifndef ENOSPC
#define ENOSPC 28
#endif
#ifndef EROFS
#define EROFS 30
#endif
#ifndef ERANGE
#define ERANGE 34
#endif
#ifndef ENODATA
#define ENODATA 61
#endif
#ifndef ENOTEMPTY
#define ENOTEMPTY 39
#endif
#ifndef ENAMETOOLONG
#define ENAMETOOLONG 36
#endif
#ifndef ENOMEM
#define ENOMEM 12
#endif
#ifndef EFAULT
#define EFAULT 14
#endif
#ifndef EEXIST
#define EEXIST 17
#endif
#ifndef ENOTDIR
#define ENOTDIR 20
#endif
#ifndef EISDIR
#define EISDIR 21
#endif
#ifndef ELOOP
#define ELOOP 40
#endif
#define YAFFS_TRACE_ERROR 0x40000000
#define YAFFS_TRACE_BUG 0x80000000
#define YAFFS_TRACE_ALWAYS 0xF0000000
/* Mode flags */
#ifndef S_IFMT
#define S_IFMT 0170000
#endif
#ifndef S_IFSOCK
#define S_IFSOCK 0140000
#endif
#ifndef S_IFIFO
#define S_IFIFO 0010000
#endif
#ifndef S_IFCHR
#define S_IFCHR 0020000
#endif
#ifndef S_IFBLK
#define S_IFBLK 0060000
#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
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
#ifndef S_IREAD
#define S_IREAD 0000400
#endif
#ifndef CONFIG_YAFFS_WINCE
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))
#ifndef S_IWRITE
#define S_IWRITE 0000200
#endif
#ifndef S_IEXEC
#define S_IEXEC 0000100
#endif
#ifndef XATTR_CREATE
#define XATTR_CREATE 1
#endif
#ifndef XATTR_REPLACE
#define XATTR_REPLACE 2
#endif
#ifndef R_OK
#define R_OK 4
#define W_OK 2
#define X_OK 1
#define F_OK 0
#endif
#else
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
#endif
#ifndef Y_DUMP_STACK
#define Y_DUMP_STACK() do { } while (0)
#endif
#ifndef BUG
#define BUG() do {\
yaffs_trace(YAFFS_TRACE_BUG,\
"==>> yaffs bug: " __FILE__ " %d",\
__LINE__);\
Y_DUMP_STACK();\
} while (0)
#endif
#endif