Commit 753ac610 authored by Charles Manning's avatar Charles Manning Committed by Wolfgang Denk
Browse files

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: default avatarCharles Manning <cdhmanning@gmail.com>
parent 3874a377
/* 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);
/* ytrace - show/set yaffs trace mask */
int do_ytrace(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
if (argc > 1)
cmd_yaffs_tracemask(1, simple_strtol(argv[1], NULL, 16));
else
cmd_yaffs_tracemask(0, 0);
return 0;
}
int do_ymount (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_mount(mtpoint);
cmd_yaffs_dev_ls();
return(0);
return 0;
}
int do_yumount (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 *mtpoint = argv[1];
cmd_yaffs_umount(mtpoint);
char *mtpoint;
int mtd_dev;
int start_block;
int end_block;
if (argc != 5) {
printf
("Bad arguments: ydevconfig mount_pt mtd_dev start_block end_block\n");
return -1;
}
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);
return(0);
cmd_yaffs_devconfig(mtpoint, mtd_dev, start_block, end_block);
return 0;
}
int do_yls (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 *dirname = argv[argc-1];
char *mtpoint;
if (argc != 2) {
printf("Bad arguments: ymount mount_pt\n");
return -1;
}
mtpoint = argv[1];
printf("Mounting yaffs2 mount point %s\n", mtpoint);
cmd_yaffs_ls(dirname, (argc>2)?1:0);
cmd_yaffs_mount(mtpoint);
return(0);
return 0;
}
int do_yrd (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];
printf ("Reading file %s ", filename);
char *mtpoint;
cmd_yaffs_read_file(filename);
if (argc != 2) {
printf("Bad arguments: yumount mount_pt\n");
return -1;
}
printf ("done\n");
return(0);
mtpoint = argv[1];
printf("Unmounting yaffs2 mount point %s\n", mtpoint);
cmd_yaffs_umount(mtpoint);
return 0;
}
int do_ywr (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 value = simple_strtoul(argv[2], NULL, 16);
ulong numValues = simple_strtoul(argv[3], NULL, 16);
char *dirname;
if (argc < 2 || argc > 3 || (argc == 3 && strcmp(argv[1], "-l"))) {
printf("Bad arguments: yls [-l] dir\n");
return -1;
}
printf ("Writing value (%lx) %lx times to %s... ", value, numValues, filename);
dirname = argv[argc - 1];
cmd_yaffs_write_file(filename,value,numValues);
cmd_yaffs_ls(dirname, (argc > 2) ? 1 : 0);
printf ("done\n");
return(0);
return 0;
}
int do_yrdm (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);
char *filename;
if (argc != 2) {
printf("Bad arguments: yrd file_name\n");
return -1;
}
cmd_yaffs_mread_file(filename, (char *)addr);
filename = argv[1];
return(0);
printf("Reading file %s ", filename);
cmd_yaffs_read_file(filename);
printf("done\n");
return 0;
}
int do_ywrm (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 *filename = argv[1];
ulong addr = simple_strtoul(argv[2], NULL, 16);
ulong size = simple_strtoul(argv[3], NULL, 16);
char *filename;
ulong value;
ulong numValues;
if (argc != 4) {
printf("Bad arguments: ywr file_name value n_values\n");
return -1;
}
cmd_yaffs_mwrite_file(filename, (char *)addr, size);
filename = argv[1];
value = simple_strtoul(argv[2], NULL, 16);
numValues = simple_strtoul(argv[3], NULL, 16);
return(0);
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_ymkdir (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;
if (argc != 3) {
printf("Bad arguments: yrdm file_name addr\n");
return -1;
}
cmd_yaffs_mkdir(dirname);
filename = argv[1];
addr = simple_strtoul(argv[2], NULL, 16);
return(0);
cmd_yaffs_mread_file(filename, (char *)addr);
return 0;
}
int do_yrmdir (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 *dirname = argv[1];
char *filename;
ulong addr;
ulong size;
if (argc != 4) {
printf("Bad arguments: ywrm file_name addr size\n");
return -1;
}
filename = argv[1];
addr = simple_strtoul(argv[2], NULL, 16);
size = simple_strtoul(argv[3], NULL, 16);
cmd_yaffs_rmdir(dirname);
cmd_yaffs_mwrite_file(filename, (char *)addr, size);
return(0);
return 0;
}
int do_yrm (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 *path = argv[1];
char *dirname;
cmd_yaffs_rm(path);
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_ymv (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 *oldPath = argv[1];
char *newPath = argv[2];
char *dirname;
if (argc != 2) {
printf("Bad arguments: yrmdir dir_name\n");
return -1;
}
cmd_yaffs_mv(newPath, oldPath);
dirname = argv[1];
cmd_yaffs_rmdir(dirname);
return(0);
return 0;
}
int do_ydump (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_yrm(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 *name;
if (argc != 2) {
printf("Bad arguments: yrm name\n");
return -1;
}
name = argv[1];
cmd_yaffs_rm(name);
return 0;
}
int do_ymv(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *oldPath;
char *newPath;
if (argc != 3) {
printf("Bad arguments: ymv old_path new_path\n");
return -1;
}
oldPath = argv[1];
newPath = argv[2];
cmd_yaffs_mv(newPath, oldPath);
return 0;
}
U_BOOT_CMD(
ymount, 3, 0, do_ymount,
"mount yaffs",
""
);
U_BOOT_CMD(
yumount, 3, 0, do_yumount,
"unmount yaffs",
""
);
U_BOOT_CMD(
yls, 4, 0, do_yls,
"yaffs ls",
"[-l] name"
);
U_BOOT_CMD(
yrd, 2, 0, do_yrd,
"read file from yaffs",
"filename"
);
U_BOOT_CMD(
ywr, 4, 0, do_ywr,
"write file to yaffs",
"filename value num_vlues"
);
U_BOOT_CMD(
yrdm, 3, 0, do_yrdm,
"read file to memory from yaffs",
"filename offset"
);
U_BOOT_CMD(
ywrm, 4, 0, do_ywrm,
"write file from memory to yaffs",
"filename offset size"
);
U_BOOT_CMD(
ymkdir, 2, 0, do_ymkdir,
"YAFFS mkdir",
"dirname"
);
U_BOOT_CMD(
yrmdir, 2, 0, do_yrmdir,
"YAFFS rmdir",
"dirname"
);
U_BOOT_CMD(
yrm, 2, 0, do_yrm,
"YAFFS rm",
"path"
);
U_BOOT_CMD(
ymv, 4, 0, do_ymv,
"YAFFS mv",
"oldPath newPath"
);
U_BOOT_CMD(
ydump, 2, 0, do_ydump,
"YAFFS device struct",
"dirname"
);
U_BOOT_CMD(ytrace, 2, 0, do_ytrace,
"show/set yaffs trace mask",
"ytrace [new_mask] show/set yaffs trace mask");
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");
......@@ -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
......
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