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>
This commit is contained in:
parent
3874a37745
commit
753ac61088
common
fs/yaffs2
MakefileREADME-linuxdevextras.hstdio.hstdlib.hstring.hyaffs_allocator.cyaffs_allocator.hyaffs_attribs.cyaffs_attribs.hyaffs_bitmap.cyaffs_bitmap.hyaffs_checkptrw.cyaffs_checkptrw.hyaffs_ecc.cyaffs_ecc.hyaffs_error.cyaffs_flashif.hyaffs_flashif2.hyaffs_getblockinfo.hyaffs_guts.cyaffs_guts.hyaffs_hweight.cyaffs_hweight.hyaffs_list.hyaffs_mtdif.cyaffs_mtdif.hyaffs_mtdif2.cyaffs_mtdif2.hyaffs_nameval.cyaffs_nameval.hyaffs_nand.cyaffs_nand.hyaffs_nandemul2k.hyaffs_nandif.cyaffs_nandif.hyaffs_osglue.hyaffs_packedtags1.cyaffs_packedtags1.hyaffs_packedtags2.cyaffs_packedtags2.hyaffs_qsort.cyaffs_ramdisk.hyaffs_summary.cyaffs_summary.hyaffs_tagscompat.cyaffs_tagscompat.hyaffs_tagsvalidity.cyaffs_trace.hyaffs_uboot_glue.cyaffs_verify.cyaffs_verify.hyaffs_yaffs1.cyaffs_yaffs1.hyaffs_yaffs2.cyaffs_yaffs2.hyaffscfg.cyaffscfg.hyaffsfs.cyaffsfs.hydirectenv.hyportenv.h
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
-------------
|
@ -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
|
1
fs/yaffs2/stdio.h
Normal file
1
fs/yaffs2/stdio.h
Normal file
@ -0,0 +1 @@
|
||||
/* Dummy header for u-boot */
|
1
fs/yaffs2/stdlib.h
Normal file
1
fs/yaffs2/stdlib.h
Normal file
@ -0,0 +1 @@
|
||||
/* Dummy header for u-boot */
|
4
fs/yaffs2/string.h
Normal file
4
fs/yaffs2/string.h
Normal file
@ -0,0 +1,4 @@
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/stat.h>
|
||||
#include <common.h>
|
356
fs/yaffs2/yaffs_allocator.c
Normal file
356
fs/yaffs2/yaffs_allocator.c
Normal 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);
|
||||
}
|
||||
}
|
30
fs/yaffs2/yaffs_allocator.h
Normal file
30
fs/yaffs2/yaffs_allocator.h
Normal 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
|
152
fs/yaffs2/yaffs_attribs.c
Normal file
152
fs/yaffs2/yaffs_attribs.c
Normal 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;
|
||||
}
|
28
fs/yaffs2/yaffs_attribs.h
Normal file
28
fs/yaffs2/yaffs_attribs.h
Normal 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
|
97
fs/yaffs2/yaffs_bitmap.c
Normal file
97
fs/yaffs2/yaffs_bitmap.c
Normal 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;
|
||||
}
|
33
fs/yaffs2/yaffs_bitmap.h
Normal file
33
fs/yaffs2/yaffs_bitmap.h
Normal 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
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
58
fs/yaffs2/yaffs_error.c
Normal file
58
fs/yaffs2/yaffs_error.c
Normal 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";
|
||||
}
|
@ -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
|
||||
|
35
fs/yaffs2/yaffs_flashif2.h
Normal file
35
fs/yaffs2/yaffs_flashif2.h
Normal 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
|
35
fs/yaffs2/yaffs_getblockinfo.h
Normal file
35
fs/yaffs2/yaffs_getblockinfo.h
Normal 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
52
fs/yaffs2/yaffs_hweight.c
Normal file
52
fs/yaffs2/yaffs_hweight.c
Normal 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);
|
||||
}
|
@ -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
|
126
fs/yaffs2/yaffs_list.h
Normal file
126
fs/yaffs2/yaffs_list.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
208
fs/yaffs2/yaffs_nameval.c
Normal file
208
fs/yaffs2/yaffs_nameval.c
Normal 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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
251
fs/yaffs2/yaffs_nandif.c
Normal file
251
fs/yaffs2/yaffs_nandif.c
Normal 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;
|
||||
}
|
65
fs/yaffs2/yaffs_nandif.h
Normal file
65
fs/yaffs2/yaffs_nandif.h
Normal 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
|
@ -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
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
313
fs/yaffs2/yaffs_summary.c
Normal file
313
fs/yaffs2/yaffs_summary.c
Normal 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++;
|
||||
}
|
||||
}
|
||||
}
|
37
fs/yaffs2/yaffs_summary.h
Normal file
37
fs/yaffs2/yaffs_summary.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
}
|
57
fs/yaffs2/yaffs_trace.h
Normal file
57
fs/yaffs2/yaffs_trace.h
Normal 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
|
464
fs/yaffs2/yaffs_uboot_glue.c
Normal file
464
fs/yaffs2/yaffs_uboot_glue.c
Normal 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());
|
||||
}
|
529
fs/yaffs2/yaffs_verify.c
Normal file
529
fs/yaffs2/yaffs_verify.c
Normal 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;
|
||||
}
|
43
fs/yaffs2/yaffs_verify.h
Normal file
43
fs/yaffs2/yaffs_verify.h
Normal 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
|
422
fs/yaffs2/yaffs_yaffs1.c
Normal file
422
fs/yaffs2/yaffs_yaffs1.c
Normal 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;
|
||||
}
|
@ -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
|
1532
fs/yaffs2/yaffs_yaffs2.c
Normal file
1532
fs/yaffs2/yaffs_yaffs2.c
Normal file
File diff suppressed because it is too large
Load Diff
39
fs/yaffs2/yaffs_yaffs2.h
Normal file
39
fs/yaffs2/yaffs_yaffs2.h
Normal 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
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
3648
fs/yaffs2/yaffsfs.c
3648
fs/yaffs2/yaffsfs.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user