fs: eliminate YAFFS2 implementation

Upstream development stopped 2012.
Linux eliminated YAFFS2 in 2010.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
Reviewed-by: Tom Rini <trini@konsulko.com>
This commit is contained in:
Heinrich Schuchardt 2025-01-04 01:34:02 +01:00 committed by Tom Rini
parent 639cd40998
commit b77791a11a
57 changed files with 0 additions and 17355 deletions

View file

@ -2881,17 +2881,6 @@ config MTDPARTS_DEFAULT
Defines a default MTD partitioning scheme in the Linux MTD command Defines a default MTD partitioning scheme in the Linux MTD command
line partitions format line partitions format
config CMD_YAFFS2
bool "yaffs2 - Access of YAFFS2 filesystem"
depends on YAFFS2
default y
help
This provides commands for accessing a YAFFS2 filesystem. Yet
Another Flash Filesystem 2 is a filesystem designed specifically
for NAND flash. It incorporates bad-block management and ensures
that device writes are sequential regardless of filesystem
activity.
config CMD_ZFS config CMD_ZFS
bool "zfs - Access of ZFS filesystem" bool "zfs - Access of ZFS filesystem"
help help

View file

@ -214,7 +214,6 @@ obj-$(CONFIG_CMD_THOR_DOWNLOAD) += thordown.o
obj-$(CONFIG_CMD_VBE) += vbe.o obj-$(CONFIG_CMD_VBE) += vbe.o
obj-$(CONFIG_CMD_XIMG) += ximg.o obj-$(CONFIG_CMD_XIMG) += ximg.o
obj-$(CONFIG_CMD_XXD) += xxd.o obj-$(CONFIG_CMD_XXD) += xxd.o
obj-$(CONFIG_CMD_YAFFS2) += yaffs2.o
obj-$(CONFIG_CMD_SPL) += spl.o obj-$(CONFIG_CMD_SPL) += spl.o
obj-$(CONFIG_CMD_W1) += w1.o obj-$(CONFIG_CMD_W1) += w1.o
obj-$(CONFIG_CMD_ZIP) += zip.o obj-$(CONFIG_CMD_ZIP) += zip.o

View file

@ -1,324 +0,0 @@
/* 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 <config.h>
#include <command.h>
#ifdef YAFFS2_DEBUG
#define PRINTF(fmt, args...) printf(fmt, ##args)
#else
#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_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);
extern void cmd_yaffs_mkdir(const char *dir);
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_dump_dev(const char *path);
/* ytrace - show/set yaffs trace mask */
int do_ytrace(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
if (argc > 1)
cmd_yaffs_tracemask(1, simple_strtol(argv[1], NULL, 16));
else
cmd_yaffs_tracemask(0, 0);
return 0;
}
/* ydevls - lists yaffs mount points. */
int do_ydevls(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
cmd_yaffs_dev_ls();
return 0;
}
/* ydevconfig mount_pt mtd_dev_num start_block end_block */
int do_ydevconfig(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *mtpoint;
int mtd_dev;
int start_block;
int end_block;
if (argc != 5) {
printf
("Bad arguments: ydevconfig mount_pt mtd_dev start_block end_block\n");
return -1;
}
mtpoint = argv[1];
mtd_dev = simple_strtol(argv[2], NULL, 16);
start_block = simple_strtol(argv[3], NULL, 16);
end_block = simple_strtol(argv[4], NULL, 16);
cmd_yaffs_devconfig(mtpoint, mtd_dev, start_block, end_block);
return 0;
}
int do_ymount(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *mtpoint;
if (argc != 2) {
printf("Bad arguments: ymount mount_pt\n");
return -1;
}
mtpoint = argv[1];
printf("Mounting yaffs2 mount point %s\n", mtpoint);
cmd_yaffs_mount(mtpoint);
return 0;
}
int do_yumount(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *mtpoint;
if (argc != 2) {
printf("Bad arguments: yumount mount_pt\n");
return -1;
}
mtpoint = argv[1];
printf("Unmounting yaffs2 mount point %s\n", mtpoint);
cmd_yaffs_umount(mtpoint);
return 0;
}
int do_yls(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *dirname;
if (argc < 2 || argc > 3 || (argc == 3 && strcmp(argv[1], "-l"))) {
printf("Bad arguments: yls [-l] dir\n");
return -1;
}
dirname = argv[argc - 1];
cmd_yaffs_ls(dirname, (argc > 2) ? 1 : 0);
return 0;
}
int do_yrd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *filename;
if (argc != 2) {
printf("Bad arguments: yrd file_name\n");
return -1;
}
filename = argv[1];
printf("Reading file %s ", filename);
cmd_yaffs_read_file(filename);
printf("done\n");
return 0;
}
int do_ywr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *filename;
ulong value;
ulong numValues;
if (argc != 4) {
printf("Bad arguments: ywr file_name value n_values\n");
return -1;
}
filename = argv[1];
value = hextoul(argv[2], NULL);
numValues = hextoul(argv[3], NULL);
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_yrdm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *filename;
ulong addr;
if (argc != 3) {
printf("Bad arguments: yrdm file_name addr\n");
return -1;
}
filename = argv[1];
addr = hextoul(argv[2], NULL);
cmd_yaffs_mread_file(filename, (char *)addr);
return 0;
}
int do_ywrm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *filename;
ulong addr;
ulong size;
if (argc != 4) {
printf("Bad arguments: ywrm file_name addr size\n");
return -1;
}
filename = argv[1];
addr = hextoul(argv[2], NULL);
size = hextoul(argv[3], NULL);
cmd_yaffs_mwrite_file(filename, (char *)addr, size);
return 0;
}
int do_ymkdir(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *dirname;
if (argc != 2) {
printf("Bad arguments: ymkdir dir_name\n");
return -1;
}
dirname = argv[1];
cmd_yaffs_mkdir(dirname);
return 0;
}
int do_yrmdir(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *dirname;
if (argc != 2) {
printf("Bad arguments: yrmdir dir_name\n");
return -1;
}
dirname = argv[1];
cmd_yaffs_rmdir(dirname);
return 0;
}
int do_yrm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *name;
if (argc != 2) {
printf("Bad arguments: yrm name\n");
return -1;
}
name = argv[1];
cmd_yaffs_rm(name);
return 0;
}
int do_ymv(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *oldPath;
char *newPath;
if (argc != 3) {
printf("Bad arguments: ymv old_path new_path\n");
return -1;
}
oldPath = argv[1];
newPath = argv[2];
cmd_yaffs_mv(newPath, oldPath);
return 0;
}
U_BOOT_CMD(ytrace, 2, 0, do_ytrace,
"show/set yaffs trace mask",
"[new_mask] show/set yaffs trace mask");
U_BOOT_CMD(ydevls, 1, 0, do_ydevls,
"list yaffs mount points", "list yaffs mount points");
U_BOOT_CMD(ydevconfig, 5, 0, do_ydevconfig,
"configure yaffs mount point",
"mtpoint mtd_id start_block end_block configures a yaffs2 mount point");
U_BOOT_CMD(ymount, 2, 0, do_ymount,
"mount yaffs", "mtpoint mounts a yaffs2 mount point");
U_BOOT_CMD(yumount, 2, 0, do_yumount,
"unmount yaffs", "mtpoint unmounts a yaffs2 mount point");
U_BOOT_CMD(yls, 3, 0, do_yls, "yaffs ls", "[-l] dirname");
U_BOOT_CMD(yrd, 2, 0, do_yrd,
"read file from yaffs", "path read file from yaffs");
U_BOOT_CMD(ywr, 4, 0, do_ywr,
"write file to yaffs",
"filename value num_vlues write values to yaffs file");
U_BOOT_CMD(yrdm, 3, 0, do_yrdm,
"read file to memory from yaffs",
"filename offset reads yaffs file into memory");
U_BOOT_CMD(ywrm, 4, 0, do_ywrm,
"write file from memory to yaffs",
"filename offset size writes memory to yaffs file");
U_BOOT_CMD(ymkdir, 2, 0, do_ymkdir,
"YAFFS mkdir", "dir create a yaffs directory");
U_BOOT_CMD(yrmdir, 2, 0, do_yrmdir,
"YAFFS rmdir", "dirname removes a yaffs directory");
U_BOOT_CMD(yrm, 2, 0, do_yrm, "YAFFS rm", "path removes a yaffs file");
U_BOOT_CMD(ymv, 4, 0, do_ymv,
"YAFFS mv",
"old_path new_path moves/rename files within a yaffs mount point");

View file

@ -20,8 +20,6 @@ source "fs/ubifs/Kconfig"
source "fs/cramfs/Kconfig" source "fs/cramfs/Kconfig"
source "fs/yaffs2/Kconfig"
source "fs/squashfs/Kconfig" source "fs/squashfs/Kconfig"
source "fs/erofs/Kconfig" source "fs/erofs/Kconfig"

View file

@ -22,7 +22,6 @@ obj-$(CONFIG_FS_JFFS2) += jffs2/
obj-$(CONFIG_SANDBOX) += sandbox/ obj-$(CONFIG_SANDBOX) += sandbox/
obj-$(CONFIG_SEMIHOSTING) += semihostingfs.o obj-$(CONFIG_SEMIHOSTING) += semihostingfs.o
obj-$(CONFIG_CMD_UBIFS) += ubifs/ obj-$(CONFIG_CMD_UBIFS) += ubifs/
obj-$(CONFIG_YAFFS2) += yaffs2/
obj-$(CONFIG_CMD_ZFS) += zfs/ obj-$(CONFIG_CMD_ZFS) += zfs/
obj-$(CONFIG_FS_SQUASHFS) += squashfs/ obj-$(CONFIG_FS_SQUASHFS) += squashfs/
obj-$(CONFIG_FS_EROFS) += erofs/ obj-$(CONFIG_FS_EROFS) += erofs/

View file

@ -1,19 +0,0 @@
config YAFFS_DIRECT
bool
config YAFFS_PROVIDE_DEFS
bool
config YAFFSFS_PROVIDE_VALUES
bool
config YAFFS2
bool "YAFFS2 filesystem support"
select YAFFS_DIRECT
select YAFFS_PROVIDE_DEFS
select YAFFSFS_PROVIDE_VALUES
help
This provides access to YAFFS2 filesystems. Yet Another Flash
Filesystem 2 is a filesystem designed specifically for NAND flash.
It incorporates bad-block management and ensures that device
writes are sequential regardless of filesystem activity.

View file

@ -1,18 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for YAFFS direct test
# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
#
# Copyright (C) 2003 Aleph One Ltd.
#
#
# Created by Charles Manning <charles@aleph1.co.uk>
#
#
obj-y := \
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_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

View file

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

View file

@ -1,30 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_ALLOCATOR_H__
#define __YAFFS_ALLOCATOR_H__
#include "yaffs_guts.h"
void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
#endif

View file

@ -1,150 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_attribs.h"
void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
{
obj->yst_uid = oh->yst_uid;
obj->yst_gid = oh->yst_gid;
obj->yst_atime = oh->yst_atime;
obj->yst_mtime = oh->yst_mtime;
obj->yst_ctime = oh->yst_ctime;
obj->yst_rdev = oh->yst_rdev;
}
void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
{
#ifdef CONFIG_YAFFS_WINCE
oh->win_atime[0] = obj->win_atime[0];
oh->win_ctime[0] = obj->win_ctime[0];
oh->win_mtime[0] = obj->win_mtime[0];
oh->win_atime[1] = obj->win_atime[1];
oh->win_ctime[1] = obj->win_ctime[1];
oh->win_mtime[1] = obj->win_mtime[1];
#else
oh->yst_uid = obj->yst_uid;
oh->yst_gid = obj->yst_gid;
oh->yst_atime = obj->yst_atime;
oh->yst_mtime = obj->yst_mtime;
oh->yst_ctime = obj->yst_ctime;
oh->yst_rdev = obj->yst_rdev;
#endif
}
void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
{
#ifdef CONFIG_YAFFS_WINCE
yfsd_win_file_time_now(obj->win_atime);
obj->win_ctime[0] = obj->win_mtime[0] = obj->win_atime[0];
obj->win_ctime[1] = obj->win_mtime[1] = obj->win_atime[1];
#else
yaffs_load_current_time(obj, 1, 1);
obj->yst_rdev = rdev;
obj->yst_uid = uid;
obj->yst_gid = gid;
#endif
}
void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
{
#ifdef CONFIG_YAFFS_WINCE
yfsd_win_file_time_now(the_obj->win_atime);
the_obj->win_ctime[0] = the_obj->win_mtime[0] =
the_obj->win_atime[0];
the_obj->win_ctime[1] = the_obj->win_mtime[1] =
the_obj->win_atime[1];
#else
obj->yst_mtime = Y_CURRENT_TIME;
if (do_a)
obj->yst_atime = obj->yst_atime;
if (do_c)
obj->yst_ctime = obj->yst_atime;
#endif
}
loff_t yaffs_get_file_size(struct yaffs_obj *obj)
{
YCHAR *alias = NULL;
obj = yaffs_get_equivalent_obj(obj);
switch (obj->variant_type) {
case YAFFS_OBJECT_TYPE_FILE:
return obj->variant.file_variant.file_size;
case YAFFS_OBJECT_TYPE_SYMLINK:
alias = obj->variant.symlink_variant.alias;
if (!alias)
return 0;
return yaffs_strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
default:
return 0;
}
}
int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
{
unsigned int valid = attr->ia_valid;
if (valid & ATTR_MODE)
obj->yst_mode = attr->ia_mode;
if (valid & ATTR_UID)
obj->yst_uid = attr->ia_uid;
if (valid & ATTR_GID)
obj->yst_gid = attr->ia_gid;
if (valid & ATTR_ATIME)
obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
if (valid & ATTR_CTIME)
obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
if (valid & ATTR_MTIME)
obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
if (valid & ATTR_SIZE)
yaffs_resize_file(obj, attr->ia_size);
yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
return YAFFS_OK;
}
int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
{
unsigned int valid = 0;
attr->ia_mode = obj->yst_mode;
valid |= ATTR_MODE;
attr->ia_uid = obj->yst_uid;
valid |= ATTR_UID;
attr->ia_gid = obj->yst_gid;
valid |= ATTR_GID;
Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
valid |= ATTR_ATIME;
Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
valid |= ATTR_CTIME;
Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
valid |= ATTR_MTIME;
attr->ia_size = yaffs_get_file_size(obj);
valid |= ATTR_SIZE;
attr->ia_valid = valid;
return YAFFS_OK;
}

View file

@ -1,28 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_ATTRIBS_H__
#define __YAFFS_ATTRIBS_H__
#include "yaffs_guts.h"
void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
#endif

View file

@ -1,97 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_bitmap.h"
#include "yaffs_trace.h"
/*
* Chunk bitmap manipulations
*/
static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
{
if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
yaffs_trace(YAFFS_TRACE_ERROR,
"BlockBits block %d is not valid",
blk);
BUG();
}
return dev->chunk_bits +
(dev->chunk_bit_stride * (blk - dev->internal_start_block));
}
void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
{
if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
chunk < 0 || chunk >= dev->param.chunks_per_block) {
yaffs_trace(YAFFS_TRACE_ERROR,
"Chunk Id (%d:%d) invalid",
blk, chunk);
BUG();
}
}
void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
memset(blk_bits, 0, dev->chunk_bit_stride);
}
void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk);
blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
}
void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk);
blk_bits[chunk / 8] |= (1 << (chunk & 7));
}
int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk);
return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
}
int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
int i;
for (i = 0; i < dev->chunk_bit_stride; i++) {
if (*blk_bits)
return 1;
blk_bits++;
}
return 0;
}
int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
int i;
int n = 0;
for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
n += hweight8(*blk_bits);
return n;
}

View file

@ -1,33 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* Chunk bitmap manipulations
*/
#ifndef __YAFFS_BITMAP_H__
#define __YAFFS_BITMAP_H__
#include "yaffs_guts.h"
void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
#endif

View file

@ -1,409 +0,0 @@
/*
* 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_checkptrw.h"
#include "yaffs_getblockinfo.h"
#include <dm/devres.h>
static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
{
int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"checkpt blocks_avail = %d", blocks_avail);
return (blocks_avail <= 0) ? 0 : 1;
}
static int yaffs_checkpt_erase(struct yaffs_dev *dev)
{
int i;
if (!dev->param.erase_fn)
return 0;
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"checking blocks %d to %d",
dev->internal_start_block, dev->internal_end_block);
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->blocks_in_checkpt = 0;
return 1;
}
static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
{
int i;
int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
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);
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;
}
}
}
yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
dev->checkpt_next_block = -1;
dev->checkpt_cur_block = -1;
}
static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
{
int i;
struct yaffs_ext_tags tags;
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"find next checkpt block: start: blocks %d next %d",
dev->blocks_in_checkpt, dev->checkpt_next_block);
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->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.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
/* Right kind of block */
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;
}
}
yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
dev->checkpt_next_block = -1;
dev->checkpt_cur_block = -1;
}
int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
{
int i;
dev->checkpt_open_write = writing;
/* Got the functions we need? */
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 (writing && !yaffs2_checkpt_space_ok(dev))
return 0;
if (!dev->checkpt_buffer)
dev->checkpt_buffer =
kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
if (!dev->checkpt_buffer)
return 0;
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 (writing) {
memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
dev->checkpt_byte_offs = 0;
return yaffs_checkpt_erase(dev);
}
/* 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);
if (!dev->checkpt_block_list)
return 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 */
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->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);
realigned_chunk = chunk - dev->chunk_offset;
dev->n_page_writes++;
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->checkpt_buffer, 0, dev->data_bytes_per_chunk);
return 1;
}
int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
{
int i = 0;
int ok = 1;
u8 *data_bytes = (u8 *) data;
if (!dev->checkpt_buffer)
return 0;
if (!dev->checkpt_open_write)
return -1;
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->checkpt_byte_offs++;
i++;
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;
}
int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
{
int i = 0;
int ok = 1;
struct yaffs_ext_tags tags;
int chunk;
int realigned_chunk;
u8 *data_bytes = (u8 *) data;
if (!dev->checkpt_buffer)
return 0;
if (dev->checkpt_open_write)
return -1;
while (i < n_bytes && ok) {
if (dev->checkpt_byte_offs < 0 ||
dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
if (dev->checkpt_cur_block < 0) {
yaffs2_checkpt_find_block(dev);
dev->checkpt_cur_chunk = 0;
}
if (dev->checkpt_cur_block < 0) {
ok = 0;
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;
}
*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;
}
int yaffs_checkpt_close(struct yaffs_dev *dev)
{
int i;
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;
}
kfree(dev->checkpt_block_list);
dev->checkpt_block_list = NULL;
}
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);
if (dev->checkpt_buffer) {
/* free the buffer */
kfree(dev->checkpt_buffer);
dev->checkpt_buffer = NULL;
return 1;
} else {
return 0;
}
}
int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
{
/* Erase the checkpoint data */
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"checkpoint invalidate of %d blocks",
dev->blocks_in_checkpt);
return yaffs_checkpt_erase(dev);
}

View file

@ -1,33 +0,0 @@
/*
* 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_CHECKPTRW_H__
#define __YAFFS_CHECKPTRW_H__
#include "yaffs_guts.h"
int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
int yaffs_checkpt_close(struct yaffs_dev *dev);
int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
#endif

View file

@ -1,280 +0,0 @@
/*
* 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 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.
*
*/
#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,
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
};
/* Calculate the ECC for a 256-byte block of data */
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;
unsigned char t;
unsigned char b;
for (i = 0; i < 256; i++) {
b = column_parity_table[*data++];
col_parity ^= b;
if (b & 0x01) { /* odd number of bits in the byte */
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
ecc[2] = (~col_parity) | 0x03;
t = 0;
if (line_parity & 0x80)
t |= 0x80;
if (line_parity_prime & 0x80)
t |= 0x40;
if (line_parity & 0x40)
t |= 0x20;
if (line_parity_prime & 0x40)
t |= 0x10;
if (line_parity & 0x20)
t |= 0x08;
if (line_parity_prime & 0x20)
t |= 0x04;
if (line_parity & 0x10)
t |= 0x02;
if (line_parity_prime & 0x10)
t |= 0x01;
ecc[1] = ~t;
t = 0;
if (line_parity & 0x08)
t |= 0x80;
if (line_parity_prime & 0x08)
t |= 0x40;
if (line_parity & 0x04)
t |= 0x20;
if (line_parity_prime & 0x04)
t |= 0x10;
if (line_parity & 0x02)
t |= 0x08;
if (line_parity_prime & 0x02)
t |= 0x04;
if (line_parity & 0x01)
t |= 0x02;
if (line_parity_prime & 0x01)
t |= 0x01;
ecc[0] = ~t;
}
/* Correct the ECC on a 256 byte block of data */
int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc)
{
unsigned char d0, d1, d2; /* deltas */
d0 = read_ecc[0] ^ test_ecc[0];
d1 = read_ecc[1] ^ test_ecc[1];
d2 = read_ecc[2] ^ test_ecc[2];
if ((d0 | d1 | d2) == 0)
return 0; /* no error */
if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
/* Single bit (recoverable) error in data */
unsigned byte;
unsigned bit;
bit = byte = 0;
if (d1 & 0x80)
byte |= 0x80;
if (d1 & 0x20)
byte |= 0x40;
if (d1 & 0x08)
byte |= 0x20;
if (d1 & 0x02)
byte |= 0x10;
if (d0 & 0x80)
byte |= 0x08;
if (d0 & 0x20)
byte |= 0x04;
if (d0 & 0x08)
byte |= 0x02;
if (d0 & 0x02)
byte |= 0x01;
if (d2 & 0x80)
bit |= 0x04;
if (d2 & 0x20)
bit |= 0x02;
if (d2 & 0x08)
bit |= 0x01;
data[byte] ^= (1 << bit);
return 1; /* Corrected the error */
}
if ((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 */
}
/* Unrecoverable error */
return -1;
}
/*
* ECCxxxOther does ECC calcs on arbitrary n bytes of data
*/
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 < n_bytes; i++) {
b = column_parity_table[*data++];
col_parity ^= b;
if (b & 0x01) {
/* odd number of bits in the byte */
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
ecc_other->col_parity = (col_parity >> 2) & 0x3f;
ecc_other->line_parity = line_parity;
ecc_other->line_parity_prime = line_parity_prime;
}
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 delta_col; /* column parity delta */
unsigned delta_line; /* line parity delta */
unsigned delta_line_prime; /* line parity delta */
unsigned bit;
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 ((delta_col | delta_line | delta_line_prime) == 0)
return 0; /* no error */
if (delta_line == ~delta_line_prime &&
(((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
/* Single bit (recoverable) error in data */
bit = 0;
if (delta_col & 0x20)
bit |= 0x04;
if (delta_col & 0x08)
bit |= 0x02;
if (delta_col & 0x02)
bit |= 0x01;
if (delta_line >= n_bytes)
return -1;
data[delta_line] ^= (1 << bit);
return 1; /* corrected */
}
if ((hweight32(delta_line) +
hweight32(delta_line_prime) +
hweight8(delta_col)) == 1) {
/* Reccoverable error in ecc */
*read_ecc = *test_ecc;
return 1; /* corrected */
}
/* Unrecoverable error */
return -1;
}

View file

@ -1,44 +0,0 @@
/*
* 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 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__
struct yaffs_ecc_other {
unsigned char col_parity;
unsigned line_parity;
unsigned line_parity_prime;
};
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_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
struct yaffs_ecc_other *ecc);
int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
struct yaffs_ecc_other *read_ecc,
const struct yaffs_ecc_other *test_ecc);
#endif

View file

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

View file

@ -1,34 +0,0 @@
/*
* 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_FLASH_H__
#define __YAFFS_FLASH_H__
#include "yaffs_guts.h"
int yflash_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber);
int yflash_WriteChunkToNAND(struct yaffs_dev *dev, int nand_chunk,
const u8 *data, const struct yaffs_spare *spare);
int yflash_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk,
const u8 *data, const struct yaffs_ext_tags *tags);
int yflash_ReadChunkFromNAND(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_spare *spare);
int yflash_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_ext_tags *tags);
int yflash_InitialiseNAND(struct yaffs_dev *dev);
int yflash_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no);
int yflash_QueryNANDBlock(struct yaffs_dev *dev, int block_no,
enum yaffs_block_state *state, u32 *seq_number);
#endif

View file

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

View file

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

View file

@ -1,969 +0,0 @@
/*
* 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_GUTS_H__
#define __YAFFS_GUTS_H__
#include "yportenv.h"
#define YAFFS_OK 1
#define YAFFS_FAIL 0
/* Give us a Y=0x59,
* Give us an A=0x41,
* Give us an FF=0xff
* Give us an S=0x53
* And what have we got...
*/
#define YAFFS_MAGIC 0x5941ff53
/*
* Tnodes form a tree with the tnodes in "levels"
* Levels greater than 0 hold 8 slots which point to other tnodes.
* Those at level 0 hold 16 slots which point to chunks in NAND.
*
* A maximum level of 8 thust supports files of size up to:
*
* 2^(3*MAX_LEVEL+4)
*
* Thus a max level of 8 supports files with up to 2^^28 chunks which gives
* a maximum file size of arounf 51Gbytees with 2k chunks.
*/
#define YAFFS_NTNODES_LEVEL0 16
#define YAFFS_TNODES_LEVEL0_BITS 4
#define YAFFS_TNODES_LEVEL0_MASK 0xf
#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
#define YAFFS_TNODES_INTERNAL_MASK 0x7
#define YAFFS_TNODES_MAX_LEVEL 8
#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \
YAFFS_TNODES_INTERNAL_BITS * \
YAFFS_TNODES_MAX_LEVEL)
#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1)
/* Constants for YAFFS1 mode */
#define YAFFS_BYTES_PER_SPARE 16
#define YAFFS_BYTES_PER_CHUNK 512
#define YAFFS_CHUNK_SIZE_SHIFT 9
#define YAFFS_CHUNKS_PER_BLOCK 32
#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
#define YAFFS_ALLOCATION_NOBJECTS 100
#define YAFFS_ALLOCATION_NTNODES 100
#define YAFFS_ALLOCATION_NLINKS 100
#define YAFFS_NOBJECT_BUCKETS 256
#define YAFFS_OBJECT_SPACE 0x40000
#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1)
/* Binary data version stamps */
#define YAFFS_SUMMARY_VERSION 1
#define YAFFS_CHECKPOINT_VERSION 6
#ifdef CONFIG_YAFFS_UNICODE
#define YAFFS_MAX_NAME_LENGTH 127
#define YAFFS_MAX_ALIAS_LENGTH 79
#else
#define YAFFS_MAX_NAME_LENGTH 255
#define YAFFS_MAX_ALIAS_LENGTH 159
#endif
#define YAFFS_SHORT_NAME_LENGTH 15
/* Some special object ids for pseudo objects */
#define YAFFS_OBJECTID_ROOT 1
#define YAFFS_OBJECTID_LOSTNFOUND 2
#define YAFFS_OBJECTID_UNLINKED 3
#define YAFFS_OBJECTID_DELETED 4
/* Fake object Id for summary data */
#define YAFFS_OBJECTID_SUMMARY 0x10
/* Pseudo object ids for checkpointing */
#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
#define YAFFS_MAX_SHORT_OP_CACHES 20
#define YAFFS_N_TEMP_BUFFERS 6
/* We limit the number attempts at sucessfully saving a chunk of data.
* Small-page devices have 32 pages per block; large-page devices have 64.
* Default to something in the order of 5 to 10 blocks worth of chunks.
*/
#define YAFFS_WR_ATTEMPTS (5*64)
/* Sequence numbers are used in YAFFS2 to determine block allocation order.
* The range is limited slightly to help distinguish bad numbers from good.
* This also allows us to perhaps in the future use special numbers for
* special purposes.
* EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
* and is a larger number than the lifetime of a 2GB device.
*/
#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00
/* Special sequence number for bad block that failed to be marked bad */
#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000
/* ChunkCache is used for short read/write operations.*/
struct yaffs_cache {
struct yaffs_obj *object;
int chunk_id;
int last_use;
int dirty;
int n_bytes; /* Only valid if the cache is dirty */
int locked; /* Can't push out or flush while locked. */
u8 *data;
};
/* yaffs1 tags structures in RAM
* NB This uses bitfield. Bitfields should not straddle a u32 boundary
* otherwise the structure size will get blown out.
*/
struct yaffs_tags {
unsigned chunk_id:20;
unsigned serial_number:2;
unsigned n_bytes_lsb:10;
unsigned obj_id:18;
unsigned ecc:12;
unsigned n_bytes_msb:2;
};
union yaffs_tags_union {
struct yaffs_tags as_tags;
u8 as_bytes[8];
};
/* Stuff used for extended tags in YAFFS2 */
enum yaffs_ecc_result {
YAFFS_ECC_RESULT_UNKNOWN,
YAFFS_ECC_RESULT_NO_ERROR,
YAFFS_ECC_RESULT_FIXED,
YAFFS_ECC_RESULT_UNFIXED
};
enum yaffs_obj_type {
YAFFS_OBJECT_TYPE_UNKNOWN,
YAFFS_OBJECT_TYPE_FILE,
YAFFS_OBJECT_TYPE_SYMLINK,
YAFFS_OBJECT_TYPE_DIRECTORY,
YAFFS_OBJECT_TYPE_HARDLINK,
YAFFS_OBJECT_TYPE_SPECIAL
};
#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
struct yaffs_ext_tags {
unsigned chunk_used; /* Status of the chunk: used or unused */
unsigned obj_id; /* If 0 this is not used */
unsigned chunk_id; /* If 0 this is a header, else a data chunk */
unsigned n_bytes; /* Only valid for data chunks */
/* The following stuff only has meaning when we read */
enum yaffs_ecc_result ecc_result;
unsigned block_bad;
/* YAFFS 1 stuff */
unsigned is_deleted; /* The chunk is marked deleted */
unsigned serial_number; /* Yaffs1 2-bit serial number */
/* YAFFS2 stuff */
unsigned seq_number; /* The sequence number of this block */
/* Extra info if this is an object header (YAFFS2 only) */
unsigned extra_available; /* Extra info available if not zero */
unsigned extra_parent_id; /* The parent object */
unsigned extra_is_shrink; /* Is it a shrink header? */
unsigned extra_shadows; /* Does this shadow another object? */
enum yaffs_obj_type extra_obj_type; /* What object type? */
loff_t extra_file_size; /* Length if it is a file */
unsigned extra_equiv_id; /* Equivalent object for a hard link */
};
/* Spare structure for YAFFS1 */
struct yaffs_spare {
u8 tb0;
u8 tb1;
u8 tb2;
u8 tb3;
u8 page_status; /* set to 0 to delete the chunk */
u8 block_status;
u8 tb4;
u8 tb5;
u8 ecc1[3];
u8 tb6;
u8 tb7;
u8 ecc2[3];
};
/*Special structure for passing through to mtd */
struct yaffs_nand_spare {
struct yaffs_spare spare;
int eccres1;
int eccres2;
};
/* Block data in RAM */
enum yaffs_block_state {
YAFFS_BLOCK_STATE_UNKNOWN = 0,
YAFFS_BLOCK_STATE_SCANNING,
/* Being scanned */
YAFFS_BLOCK_STATE_NEEDS_SCAN,
/* The block might have something on it (ie it is allocating or full,
* perhaps empty) but it needs to be scanned to determine its true
* state.
* This state is only valid during scanning.
* NB We tolerate empty because the pre-scanner might be incapable of
* deciding
* However, if this state is returned on a YAFFS2 device,
* then we expect a sequence number
*/
YAFFS_BLOCK_STATE_EMPTY,
/* This block is empty */
YAFFS_BLOCK_STATE_ALLOCATING,
/* This block is partially allocated.
* At least one page holds valid data.
* This is the one currently being used for page
* allocation. Should never be more than one of these.
* If a block is only partially allocated at mount it is treated as
* full.
*/
YAFFS_BLOCK_STATE_FULL,
/* All the pages in this block have been allocated.
* If a block was only partially allocated when mounted we treat
* it as fully allocated.
*/
YAFFS_BLOCK_STATE_DIRTY,
/* The block was full and now all chunks have been deleted.
* Erase me, reuse me.
*/
YAFFS_BLOCK_STATE_CHECKPOINT,
/* This block is assigned to holding checkpoint data. */
YAFFS_BLOCK_STATE_COLLECTING,
/* This block is being garbage collected */
YAFFS_BLOCK_STATE_DEAD
/* This block has failed and is not in use */
};
#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
struct yaffs_block_info {
int soft_del_pages:10; /* number of soft deleted pages */
int pages_in_use:10; /* number of pages in use */
unsigned block_state:4; /* One of the above block states. */
/* NB use unsigned because enum is sometimes
* an int */
u32 needs_retiring:1; /* Data has failed on this block, */
/*need to get valid data off and retire*/
u32 skip_erased_check:1;/* Skip the erased check on this block */
u32 gc_prioritise:1; /* An ECC check or blank check has failed.
Block should be prioritised for GC */
u32 chunk_error_strikes:3; /* How many times we've had ecc etc
failures on this block and tried to reuse it */
u32 has_summary:1; /* The block has a summary */
u32 has_shrink_hdr:1; /* This block has at least one shrink header */
u32 seq_number; /* block sequence number for yaffs2 */
};
/* -------------------------- Object structure -------------------------------*/
/* This is the object structure as stored on NAND */
struct yaffs_obj_hdr {
enum yaffs_obj_type type;
/* Apply to everything */
int parent_obj_id;
u16 sum_no_longer_used; /* checksum of name. No longer used */
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
/* The following apply to all object types except for hard links */
u32 yst_mode; /* protection */
u32 yst_uid;
u32 yst_gid;
u32 yst_atime;
u32 yst_mtime;
u32 yst_ctime;
/* File size applies to files only */
u32 file_size_low;
/* Equivalent object id applies to hard links only. */
int equiv_id;
/* Alias is for symlinks only. */
YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
u32 yst_rdev; /* stuff for block and char devices (major/min) */
u32 win_ctime[2];
u32 win_atime[2];
u32 win_mtime[2];
u32 inband_shadowed_obj_id;
u32 inband_is_shrink;
u32 file_size_high;
u32 reserved[1];
int shadows_obj; /* This object header shadows the
specified object if > 0 */
/* is_shrink applies to object headers written when wemake a hole. */
u32 is_shrink;
};
/*--------------------------- Tnode -------------------------- */
struct yaffs_tnode {
struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
};
/*------------------------ Object -----------------------------*/
/* An object can be one of:
* - a directory (no data, has children links
* - a regular file (data.... not prunes :->).
* - a symlink [symbolic link] (the alias).
* - a hard link
*/
struct yaffs_file_var {
loff_t file_size;
loff_t scanned_size;
loff_t shrink_size;
int top_level;
struct yaffs_tnode *top;
};
struct yaffs_dir_var {
struct list_head children; /* list of child links */
struct list_head dirty; /* Entry for list of dirty directories */
};
struct yaffs_symlink_var {
YCHAR *alias;
};
struct yaffs_hardlink_var {
struct yaffs_obj *equiv_obj;
u32 equiv_id;
};
union yaffs_obj_var {
struct yaffs_file_var file_variant;
struct yaffs_dir_var dir_variant;
struct yaffs_symlink_var symlink_variant;
struct yaffs_hardlink_var hardlink_variant;
};
struct yaffs_obj {
u8 deleted:1; /* This should only apply to unlinked files. */
u8 soft_del:1; /* it has also been soft deleted */
u8 unlinked:1; /* An unlinked file.*/
u8 fake:1; /* A fake object has no presence on NAND. */
u8 rename_allowed:1; /* Some objects cannot be renamed. */
u8 unlink_allowed:1;
u8 dirty:1; /* the object needs to be written to flash */
u8 valid:1; /* When the file system is being loaded up, this
* object might be created before the data
* is available
* ie. file data chunks encountered before
* the header.
*/
u8 lazy_loaded:1; /* This object has been lazy loaded and
* is missing some detail */
u8 defered_free:1; /* Object is removed from NAND, but is
* still in the inode cache.
* Free of object is defered.
* until the inode is released.
*/
u8 being_created:1; /* This object is still being created
* so skip some verification checks. */
u8 is_shadowed:1; /* This object is shadowed on the way
* to being renamed. */
u8 xattr_known:1; /* We know if this has object has xattribs
* or not. */
u8 has_xattr:1; /* This object has xattribs.
* Only valid if xattr_known. */
u8 serial; /* serial number of chunk in NAND.*/
u16 sum; /* sum of the name to speed searching */
struct yaffs_dev *my_dev; /* The device I'm on */
struct list_head hash_link; /* list of objects in hash bucket */
struct list_head hard_links; /* hard linked object chain*/
/* directory structure stuff */
/* also used for linking up the free list */
struct yaffs_obj *parent;
struct list_head siblings;
/* Where's my object header in NAND? */
int hdr_chunk;
int n_data_chunks; /* Number of data chunks for this file. */
u32 obj_id; /* the object id value */
u32 yst_mode;
YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
#ifdef CONFIG_YAFFS_WINCE
u32 win_ctime[2];
u32 win_mtime[2];
u32 win_atime[2];
#else
u32 yst_uid;
u32 yst_gid;
u32 yst_atime;
u32 yst_mtime;
u32 yst_ctime;
#endif
u32 yst_rdev;
void *my_inode;
enum yaffs_obj_type variant_type;
union yaffs_obj_var variant;
};
struct yaffs_obj_bucket {
struct list_head list;
int count;
};
/* yaffs_checkpt_obj holds the definition of an object as dumped
* by checkpointing.
*/
struct yaffs_checkpt_obj {
int struct_type;
u32 obj_id;
u32 parent_id;
int hdr_chunk;
enum yaffs_obj_type variant_type:3;
u8 deleted:1;
u8 soft_del:1;
u8 unlinked:1;
u8 fake:1;
u8 rename_allowed:1;
u8 unlink_allowed:1;
u8 serial;
int n_data_chunks;
loff_t size_or_equiv_obj;
};
/*--------------------- Temporary buffers ----------------
*
* These are chunk-sized working buffers. Each device has a few.
*/
struct yaffs_buffer {
u8 *buffer;
int in_use;
};
/*----------------- Device ---------------------------------*/
struct yaffs_param {
const YCHAR *name;
/*
* Entry parameters set up way early. Yaffs sets up the rest.
* The structure should be zeroed out before use so that unused
* and defualt values are zero.
*/
int inband_tags; /* Use unband tags */
u32 total_bytes_per_chunk; /* Should be >= 512, does not need to
be a power of 2 */
int chunks_per_block; /* does not need to be a power of 2 */
int spare_bytes_per_chunk; /* spare area size */
int start_block; /* Start block we're allowed to use */
int end_block; /* End block we're allowed to use */
int n_reserved_blocks; /* Tuneable so that we can reduce
* reserved blocks on NOR and RAM. */
int n_caches; /* If <= 0, then short op caching is disabled,
* else the number of short op caches.
*/
int use_nand_ecc; /* Flag to decide whether or not to use
* NAND driver ECC on data (yaffs1) */
int tags_9bytes; /* Use 9 byte tags */
int no_tags_ecc; /* Flag to decide whether or not to do ECC
* on packed tags (yaffs2) */
int is_yaffs2; /* Use yaffs2 mode on this device */
int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
int refresh_period; /* How often to check for a block refresh */
/* Checkpoint control. Can be set before or after initialisation */
u8 skip_checkpt_rd;
u8 skip_checkpt_wr;
int enable_xattr; /* Enable xattribs */
/* NAND access functions (Must be set before calling YAFFS) */
int (*write_chunk_fn) (struct yaffs_dev *dev,
int nand_chunk, const u8 *data,
const struct yaffs_spare *spare);
int (*read_chunk_fn) (struct yaffs_dev *dev,
int nand_chunk, u8 *data,
struct yaffs_spare *spare);
int (*erase_fn) (struct yaffs_dev *dev, int flash_block);
int (*initialise_flash_fn) (struct yaffs_dev *dev);
int (*deinitialise_flash_fn) (struct yaffs_dev *dev);
/* yaffs2 mode functions */
int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
int nand_chunk, const u8 *data,
const struct yaffs_ext_tags *tags);
int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
int nand_chunk, u8 *data,
struct yaffs_ext_tags *tags);
int (*bad_block_fn) (struct yaffs_dev *dev, int block_no);
int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
enum yaffs_block_state *state,
u32 *seq_number);
/* The remove_obj_fn function must be supplied by OS flavours that
* need it.
* yaffs direct uses it to implement the faster readdir.
* Linux uses it to protect the directory during unlocking.
*/
void (*remove_obj_fn) (struct yaffs_obj *obj);
/* Callback to mark the superblock dirty */
void (*sb_dirty_fn) (struct yaffs_dev *dev);
/* Callback to control garbage collection. */
unsigned (*gc_control) (struct yaffs_dev *dev);
/* Debug control flags. Don't use unless you know what you're doing */
int use_header_file_size; /* Flag to determine if we should use
* file sizes from the header */
int disable_lazy_load; /* Disable lazy loading on this device */
int wide_tnodes_disabled; /* Set to disable wide tnodes */
int disable_soft_del; /* yaffs 1 only: Set to disable the use of
* softdeletion. */
int defered_dir_update; /* Set to defer directory updates */
#ifdef CONFIG_YAFFS_AUTO_UNICODE
int auto_unicode;
#endif
int always_check_erased; /* Force chunk erased check always on */
int disable_summary;
int max_objects; /*
* Set to limit the number of objects created.
* 0 = no limit.
*/
};
struct yaffs_dev {
struct yaffs_param param;
/* Context storage. Holds extra OS specific data for this device */
void *os_context;
void *driver_context;
struct list_head dev_list;
/* Runtime parameters. Set up by YAFFS. */
int data_bytes_per_chunk;
/* Non-wide tnode stuff */
u16 chunk_grp_bits; /* Number of bits that need to be resolved if
* the tnodes are not wide enough.
*/
u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
/* Stuff to support wide tnodes */
u32 tnode_width;
u32 tnode_mask;
u32 tnode_size;
/* Stuff for figuring out file offset to chunk conversions */
u32 chunk_shift; /* Shift value */
u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */
u32 chunk_mask; /* Mask to use for power-of-2 case */
int is_mounted;
int read_only;
int is_checkpointed;
/* Stuff to support block offsetting to support start block zero */
int internal_start_block;
int internal_end_block;
int block_offset;
int chunk_offset;
/* Runtime checkpointing stuff */
int checkpt_page_seq; /* running sequence number of checkpt pages */
int checkpt_byte_count;
int checkpt_byte_offs;
u8 *checkpt_buffer;
int checkpt_open_write;
int blocks_in_checkpt;
int checkpt_cur_chunk;
int checkpt_cur_block;
int checkpt_next_block;
int *checkpt_block_list;
int checkpt_max_blocks;
u32 checkpt_sum;
u32 checkpt_xor;
int checkpoint_blocks_required; /* Number of blocks needed to store
* current checkpoint set */
/* Block Info */
struct yaffs_block_info *block_info;
u8 *chunk_bits; /* bitmap of chunks in use */
unsigned block_info_alt:1; /* allocated using alternative alloc */
unsigned chunk_bits_alt:1; /* allocated using alternative alloc */
int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
* Must be consistent with chunks_per_block.
*/
int n_erased_blocks;
int alloc_block; /* Current block being allocated off */
u32 alloc_page;
int alloc_block_finder; /* Used to search for next allocation block */
/* Object and Tnode memory management */
void *allocator;
int n_obj;
int n_tnodes;
int n_hardlinks;
struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
u32 bucket_finder;
int n_free_chunks;
/* Garbage collection control */
u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
u32 n_clean_ups;
unsigned has_pending_prioritised_gc; /* We think this device might
have pending prioritised gcs */
unsigned gc_disable;
unsigned gc_block_finder;
unsigned gc_dirtiest;
unsigned gc_pages_in_use;
unsigned gc_not_done;
unsigned gc_block;
unsigned gc_chunk;
unsigned gc_skip;
struct yaffs_summary_tags *gc_sum_tags;
/* Special directories */
struct yaffs_obj *root_dir;
struct yaffs_obj *lost_n_found;
int buffered_block; /* Which block is buffered here? */
int doing_buffered_block_rewrite;
struct yaffs_cache *cache;
int cache_last_use;
/* Stuff for background deletion and unlinked files. */
struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted
files live. */
struct yaffs_obj *del_dir; /* Directory where deleted objects are
sent to disappear. */
struct yaffs_obj *unlinked_deletion; /* Current file being
background deleted. */
int n_deleted_files; /* Count of files awaiting deletion; */
int n_unlinked_files; /* Count of unlinked files. */
int n_bg_deletions; /* Count of background deletions. */
/* Temporary buffer management */
struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
int max_temp;
int temp_in_use;
int unmanaged_buffer_allocs;
int unmanaged_buffer_deallocs;
/* yaffs2 runtime stuff */
unsigned seq_number; /* Sequence number of currently
allocating block */
unsigned oldest_dirty_seq;
unsigned oldest_dirty_block;
/* Block refreshing */
int refresh_skip; /* A skip down counter.
* Refresh happens when this gets to zero. */
/* Dirty directory handling */
struct list_head dirty_dirs; /* List of dirty directories */
/* Summary */
int chunks_per_summary;
struct yaffs_summary_tags *sum_tags;
/* Statistics */
u32 n_page_writes;
u32 n_page_reads;
u32 n_erasures;
u32 n_erase_failures;
u32 n_gc_copies;
u32 all_gcs;
u32 passive_gc_count;
u32 oldest_dirty_gc_count;
u32 n_gc_blocks;
u32 bg_gcs;
u32 n_retried_writes;
u32 n_retired_blocks;
u32 n_ecc_fixed;
u32 n_ecc_unfixed;
u32 n_tags_ecc_fixed;
u32 n_tags_ecc_unfixed;
u32 n_deletions;
u32 n_unmarked_deletions;
u32 refresh_count;
u32 cache_hits;
u32 tags_used;
u32 summary_used;
};
/* The CheckpointDevice structure holds the device information that changes
*at runtime and must be preserved over unmount/mount cycles.
*/
struct yaffs_checkpt_dev {
int struct_type;
int n_erased_blocks;
int alloc_block; /* Current block being allocated off */
u32 alloc_page;
int n_free_chunks;
int n_deleted_files; /* Count of files awaiting deletion; */
int n_unlinked_files; /* Count of unlinked files. */
int n_bg_deletions; /* Count of background deletions. */
/* yaffs2 runtime stuff */
unsigned seq_number; /* Sequence number of currently
* allocating block */
};
struct yaffs_checkpt_validity {
int struct_type;
u32 magic;
u32 version;
u32 head;
};
struct yaffs_shadow_fixer {
int obj_id;
int shadowed_id;
struct yaffs_shadow_fixer *next;
};
/* Structure for doing xattr modifications */
struct yaffs_xattr_mod {
int set; /* If 0 then this is a deletion */
const YCHAR *name;
const void *data;
int size;
int flags;
int result;
};
/*----------------------- YAFFS Functions -----------------------*/
int yaffs_guts_initialise(struct yaffs_dev *dev);
void yaffs_deinitialise(struct yaffs_dev *dev);
int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
struct yaffs_obj *new_dir, const YCHAR * new_name);
int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
int yaffs_del_obj(struct yaffs_obj *obj);
int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
int yaffs_get_obj_inode(struct yaffs_obj *obj);
unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
int yaffs_get_obj_link_count(struct yaffs_obj *obj);
/* File operations */
int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
int n_bytes);
int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
int n_bytes, int write_trhrough);
int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
const YCHAR *name, u32 mode, u32 uid,
u32 gid);
int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
/* Flushing and checkpointing */
void yaffs_flush_whole_cache(struct yaffs_dev *dev);
int yaffs_checkpoint_save(struct yaffs_dev *dev);
int yaffs_checkpoint_restore(struct yaffs_dev *dev);
/* Directory operations */
struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
u32 mode, u32 uid, u32 gid);
struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
const YCHAR *name);
struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
/* Link operations */
struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
struct yaffs_obj *equiv_obj);
struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
/* Symlink operations */
struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
const YCHAR *name, u32 mode, u32 uid,
u32 gid, const YCHAR *alias);
YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
/* Special inodes (fifos, sockets and devices) */
struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
const YCHAR *name, u32 mode, u32 uid,
u32 gid, u32 rdev);
int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
const void *value, int size, int flags);
int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
int size);
int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);
/* Special directories */
struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
void yaffs_handle_defered_free(struct yaffs_obj *obj);
void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
/* Debug dump */
int yaffs_dump_obj(struct yaffs_obj *obj);
void yaffs_guts_test(struct yaffs_dev *dev);
/* A few useful functions to be used within the core files*/
void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
int lyn);
int yaffs_check_ff(u8 *buffer, int n_bytes);
void yaffs_handle_chunk_error(struct yaffs_dev *dev,
struct yaffs_block_info *bi);
u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);
struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
int number,
enum yaffs_obj_type type);
int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
int nand_chunk, int in_scan);
void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
const struct yaffs_obj_hdr *oh);
void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
YCHAR *yaffs_clone_str(const YCHAR *str);
void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
int force, int is_shrink, int shadows,
struct yaffs_xattr_mod *xop);
void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
int backward_scanning);
int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
struct yaffs_file_var *file_struct,
u32 chunk_id,
struct yaffs_tnode *passed_tn);
int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
int n_bytes, int write_trhrough);
void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
int yaffs_count_free_chunks(struct yaffs_dev *dev);
struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
struct yaffs_file_var *file_struct,
u32 chunk_id);
u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
unsigned pos);
int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
int *chunk_out, u32 *offset_out);
/*
* Marshalling functions to get loff_t file sizes into aand out of
* object headers.
*/
void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
loff_t yaffs_max_file_size(struct yaffs_dev *dev);
#endif

View file

@ -1,159 +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 "yportenv.h"
#include "yaffs_mtdif.h"
#include <linux/mtd/mtd.h>
#include <linux/types.h>
#include <linux/time.h>
#include <linux/mtd/rawnand.h>
static inline void translate_spare2oob(const struct yaffs_spare *spare, u8 *oob)
{
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(struct yaffs_spare *spare, u8 *oob)
{
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->tb6 = oob[6];
spare->tb7 = oob[7];
spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
}
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->driver_context);
struct mtd_oob_ops ops;
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->data_bytes_per_chunk;
u8 spareAsBytes[8]; /* OOB */
if (data && !spare)
retval = mtd_write(mtd, addr, dev->data_bytes_per_chunk,
&dummy, data);
else if (spare) {
if (dev->param.use_nand_ecc) {
translate_spare2oob(spare, spareAsBytes);
ops.mode = MTD_OPS_AUTO_OOB;
ops.ooblen = 8; /* temp hack */
} else {
ops.mode = MTD_OPS_RAW;
ops.ooblen = YAFFS_BYTES_PER_SPARE;
}
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);
}
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd_ReadChunkFromNAND(struct yaffs_dev *dev, int chunkInNAND, u8 *data,
struct yaffs_spare *spare)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
struct mtd_oob_ops ops;
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->data_bytes_per_chunk;
u8 spareAsBytes[8]; /* OOB */
if (data && !spare)
retval = mtd_read(mtd, addr, dev->data_bytes_per_chunk,
&dummy, data);
else if (spare) {
if (dev->param.use_nand_ecc) {
ops.mode = MTD_OPS_AUTO_OOB;
ops.ooblen = 8; /* temp hack */
} else {
ops.mode = MTD_OPS_RAW;
ops.ooblen = YAFFS_BYTES_PER_SPARE;
}
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->param.use_nand_ecc)
translate_oob2spare(spare, spareAsBytes);
}
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
__u32 addr =
((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->data_bytes_per_chunk * dev->param.chunks_per_block;
ei.time = 1000;
ei.retries = 2;
ei.priv = (u_long) dev;
/* Todo finish off the ei if required */
retval = mtd_erase(mtd, &ei);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd_InitialiseNAND(struct yaffs_dev *dev)
{
return YAFFS_OK;
}

View file

@ -1,27 +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.
*/
#ifndef __YAFFS_MTDIF_H__
#define __YAFFS_MTDIF_H__
#include "yaffs_guts.h"
int nandmtd_WriteChunkToNAND(struct yaffs_dev *dev, int chunkInNAND,
const u8 *data, const struct yaffs_spare *spare);
int nandmtd_ReadChunkFromNAND(struct yaffs_dev *dev, int chunkInNAND, u8 *data,
struct yaffs_spare *spare);
int nandmtd_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber);
int nandmtd_InitialiseNAND(struct yaffs_dev *dev);
#endif

View file

@ -1,230 +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.
*/
/* mtd interface for YAFFS2 */
/* XXX U-BOOT XXX */
#include <linux/bug.h>
#include <linux/errno.h>
#include "yportenv.h"
#include "yaffs_trace.h"
#include "yaffs_mtdif2.h"
#include <linux/mtd/mtd.h>
#include <linux/types.h>
#include <linux/time.h>
#include "yaffs_trace.h"
#include "yaffs_packedtags2.h"
#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 = yaffs_dev_to_mtd(dev);
struct mtd_oob_ops ops;
int retval = 0;
loff_t addr;
struct yaffs_packed_tags2 pt;
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;
yaffs_trace(YAFFS_TRACE_MTD,
"nandmtd2_write_chunk_tags chunk %d data %p tags %p",
nand_chunk, data, tags);
addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
/* 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 {
yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
}
ops.mode = MTD_OPS_AUTO_OOB;
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;
else
return YAFFS_FAIL;
}
int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_ext_tags *tags)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
u8 local_spare[128];
struct mtd_oob_ops ops;
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;
yaffs_trace(YAFFS_TRACE_MTD,
"nandmtd2_read_chunk_tags chunk %d data %p tags %p",
nand_chunk, data, tags);
if (dev->param.inband_tags) {
if (!data) {
local_data = 1;
data = yaffs_get_temp_buffer(dev);
}
}
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_OPS_AUTO_OOB;
ops.ooblen = packed_tags_size;
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
ops.ooboffs = 0;
ops.datbuf = data;
ops.oobbuf = local_spare;
retval = mtd_read_oob(mtd, addr, &ops);
}
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) {
memcpy(packed_tags_ptr,
local_spare,
packed_tags_size);
yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
}
}
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_dev *dev, int blockNo)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
int retval;
yaffs_trace(YAFFS_TRACE_MTD,
"nandmtd2_MarkNANDBlockBad %d", blockNo);
retval =
mtd_block_markbad(mtd,
blockNo * dev->param.chunks_per_block *
dev->data_bytes_per_chunk);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_QueryNANDBlock(struct yaffs_dev *dev, int blockNo,
enum yaffs_block_state *state, u32 *sequenceNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
int retval;
yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_QueryNANDBlock %d", blockNo);
retval =
mtd_block_isbad(mtd,
blockNo * dev->param.chunks_per_block *
dev->data_bytes_per_chunk);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
*state = YAFFS_BLOCK_STATE_DEAD;
*sequenceNumber = 0;
} else {
struct yaffs_ext_tags t;
nandmtd2_read_chunk_tags(dev,
blockNo *
dev->param.chunks_per_block, NULL,
&t);
if (t.chunk_used) {
*sequenceNumber = t.seq_number;
*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
} else {
*sequenceNumber = 0;
*state = YAFFS_BLOCK_STATE_EMPTY;
}
}
yaffs_trace(YAFFS_TRACE_MTD, "block is bad seq %d state %d",
*sequenceNumber, *state);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}

View file

@ -1,30 +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.
*/
#ifndef __YAFFS_MTDIF2_H__
#define __YAFFS_MTDIF2_H__
#include "yaffs_guts.h"
int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int chunkInNAND,
const u8 *data,
const struct yaffs_ext_tags *tags);
int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int chunkInNAND,
u8 *data, struct yaffs_ext_tags *tags);
int nandmtd2_MarkNANDBlockBad(struct yaffs_dev *dev, int blockNo);
int nandmtd2_QueryNANDBlock(struct yaffs_dev *dev, int blockNo,
enum yaffs_block_state *state, u32 *sequenceNumber);
#endif

View file

@ -1,208 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This simple implementation of a name-value store assumes a small number of
* values and fits into a small finite buffer.
*
* Each attribute is stored as a record:
* sizeof(int) bytes record size.
* yaffs_strnlen+1 bytes name null terminated.
* nbytes value.
* ----------
* total size stored in record size
*
* This code has not been tested with unicode yet.
*/
#include "yaffs_nameval.h"
#include "yportenv.h"
static int nval_find(const char *xb, int xb_size, const YCHAR *name,
int *exist_size)
{
int pos = 0;
int size;
memcpy(&size, xb, sizeof(int));
while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
if (!yaffs_strncmp((YCHAR *) (xb + pos + sizeof(int)),
name, size)) {
if (exist_size)
*exist_size = size;
return pos;
}
pos += size;
if (pos < xb_size - sizeof(int))
memcpy(&size, xb + pos, sizeof(int));
else
size = 0;
}
if (exist_size)
*exist_size = 0;
return -ENODATA;
}
static int nval_used(const char *xb, int xb_size)
{
int pos = 0;
int size;
memcpy(&size, xb + pos, sizeof(int));
while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
pos += size;
if (pos < xb_size - sizeof(int))
memcpy(&size, xb + pos, sizeof(int));
else
size = 0;
}
return pos;
}
int nval_del(char *xb, int xb_size, const YCHAR *name)
{
int pos = nval_find(xb, xb_size, name, NULL);
int size;
if (pos < 0 || pos >= xb_size)
return -ENODATA;
/* Find size, shift rest over this record,
* then zero out the rest of buffer */
memcpy(&size, xb + pos, sizeof(int));
memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
memset(xb + (xb_size - size), 0, size);
return 0;
}
int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
int bsize, int flags)
{
int pos;
int namelen = yaffs_strnlen(name, xb_size);
int reclen;
int size_exist = 0;
int space;
int start;
pos = nval_find(xb, xb_size, name, &size_exist);
if (flags & XATTR_CREATE && pos >= 0)
return -EEXIST;
if (flags & XATTR_REPLACE && pos < 0)
return -ENODATA;
start = nval_used(xb, xb_size);
space = xb_size - start + size_exist;
reclen = (sizeof(int) + namelen + 1 + bsize);
if (reclen > space)
return -ENOSPC;
if (pos >= 0) {
nval_del(xb, xb_size, name);
start = nval_used(xb, xb_size);
}
pos = start;
memcpy(xb + pos, &reclen, sizeof(int));
pos += sizeof(int);
yaffs_strncpy((YCHAR *) (xb + pos), name, reclen);
pos += (namelen + 1);
memcpy(xb + pos, buf, bsize);
return 0;
}
int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
int bsize)
{
int pos = nval_find(xb, xb_size, name, NULL);
int size;
if (pos >= 0 && pos < xb_size) {
memcpy(&size, xb + pos, sizeof(int));
pos += sizeof(int); /* advance past record length */
size -= sizeof(int);
/* Advance over name string */
while (xb[pos] && size > 0 && pos < xb_size) {
pos++;
size--;
}
/*Advance over NUL */
pos++;
size--;
/* If bsize is zero then this is a size query.
* Return the size, but don't copy.
*/
if (!bsize)
return size;
if (size <= bsize) {
memcpy(buf, xb + pos, size);
return size;
}
}
if (pos >= 0)
return -ERANGE;
return -ENODATA;
}
int nval_list(const char *xb, int xb_size, char *buf, int bsize)
{
int pos = 0;
int size;
int name_len;
int ncopied = 0;
int filled = 0;
memcpy(&size, xb + pos, sizeof(int));
while (size > sizeof(int) &&
size <= xb_size &&
(pos + size) < xb_size &&
!filled) {
pos += sizeof(int);
size -= sizeof(int);
name_len = yaffs_strnlen((YCHAR *) (xb + pos), size);
if (ncopied + name_len + 1 < bsize) {
memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
buf += name_len;
*buf = '\0';
buf++;
if (sizeof(YCHAR) > 1) {
*buf = '\0';
buf++;
}
ncopied += (name_len + 1);
} else {
filled = 1;
}
pos += size;
if (pos < xb_size - sizeof(int))
memcpy(&size, xb + pos, sizeof(int));
else
size = 0;
}
return ncopied;
}
int nval_hasvalues(const char *xb, int xb_size)
{
return nval_used(xb, xb_size) > 0;
}

View file

@ -1,28 +0,0 @@
/*
* 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 __NAMEVAL_H__
#define __NAMEVAL_H__
#include "yportenv.h"
int nval_del(char *xb, int xb_size, const YCHAR * name);
int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
int bsize, int flags);
int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
int bsize);
int nval_list(const char *xb, int xb_size, char *buf, int bsize);
int nval_hasvalues(const char *xb, int xb_size);
#endif

View file

@ -1,120 +0,0 @@
/*
* 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_nand.h"
#include "yaffs_tagscompat.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_summary.h"
int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
u8 *buffer, struct yaffs_ext_tags *tags)
{
int result;
struct yaffs_ext_tags local_tags;
int flash_chunk = nand_chunk - dev->chunk_offset;
dev->n_page_reads++;
/* If there are no tags provided use local tags. */
if (!tags)
tags = &local_tags;
if (dev->param.read_chunk_tags_fn)
result =
dev->param.read_chunk_tags_fn(dev, flash_chunk, buffer,
tags);
else
result = yaffs_tags_compat_rd(dev,
flash_chunk, buffer, tags);
if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
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_wr_chunk_tags_nand(struct yaffs_dev *dev,
int nand_chunk,
const u8 *buffer, struct yaffs_ext_tags *tags)
{
int result;
int flash_chunk = nand_chunk - dev->chunk_offset;
dev->n_page_writes++;
if (tags) {
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 {
yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
BUG();
return YAFFS_FAIL;
}
if (dev->param.write_chunk_tags_fn)
result = dev->param.write_chunk_tags_fn(dev, flash_chunk,
buffer, tags);
else
result = yaffs_tags_compat_wr(dev, flash_chunk, buffer, tags);
yaffs_summary_add(dev, tags, nand_chunk);
return result;
}
int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
{
block_no -= dev->block_offset;
if (dev->param.bad_block_fn)
return dev->param.bad_block_fn(dev, block_no);
return yaffs_tags_compat_mark_bad(dev, block_no);
}
int yaffs_query_init_block_state(struct yaffs_dev *dev,
int block_no,
enum yaffs_block_state *state,
u32 *seq_number)
{
block_no -= dev->block_offset;
if (dev->param.query_block_fn)
return dev->param.query_block_fn(dev, block_no, state,
seq_number);
return yaffs_tags_compat_query_block(dev, block_no, state, seq_number);
}
int yaffs_erase_block(struct yaffs_dev *dev, int flash_block)
{
int result;
flash_block -= dev->block_offset;
dev->n_erasures++;
result = dev->param.erase_fn(dev, flash_block);
return result;
}
int yaffs_init_nand(struct yaffs_dev *dev)
{
if (dev->param.initialise_flash_fn)
return dev->param.initialise_flash_fn(dev);
return YAFFS_OK;
}

View file

@ -1,38 +0,0 @@
/*
* 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_NAND_H__
#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_mark_bad(struct yaffs_dev *dev, int block_no);
int yaffs_query_init_block_state(struct yaffs_dev *dev,
int block_no,
enum yaffs_block_state *state,
unsigned *seq_number);
int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
int yaffs_init_nand(struct yaffs_dev *dev);
#endif

View file

@ -1,39 +0,0 @@
/*
* 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.
*/
/* Interface to emulated NAND functions (2k page size) */
#ifndef __YAFFS_NANDEMUL2K_H__
#define __YAFFS_NANDEMUL2K_H__
#include "yaffs_guts.h"
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_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);
#endif

View file

@ -1,246 +0,0 @@
/*
* 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 <malloc.h>
#include "yaffs_nandif.h"
#include "yaffs_packedtags2.h"
#include "yramsim.h"
#include "yaffs_trace.h"
#include "yaffsfs.h"
/* NB For use with inband tags....
* We assume that the data buffer is of size totalBytersPerChunk so that
* we can also use it to load the tags.
*/
int ynandif_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk,
const u8 *data,
const struct yaffs_ext_tags *tags)
{
int retval = 0;
struct yaffs_packed_tags2 pt;
void *spare;
unsigned spareSize = 0;
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
yaffs_trace(YAFFS_TRACE_MTD,
"nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p",
nand_chunk, data, tags);
/* For yaffs2 writing there must be both data and tags.
* If we're using inband tags, then the tags are stuffed into
* the end of the data buffer.
*/
if (dev->param.inband_tags) {
struct yaffs_packed_tags2_tags_only *pt2tp;
pt2tp = (struct yaffs_packed_tags2_tags_only *)
(data + dev->data_bytes_per_chunk);
yaffs_pack_tags2_tags_only(pt2tp, tags);
spare = NULL;
spareSize = 0;
} else {
yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
spare = &pt;
spareSize = sizeof(struct yaffs_packed_tags2);
}
retval = geometry->writeChunk(dev, nand_chunk,
data, dev->param.total_bytes_per_chunk,
spare, spareSize);
return retval;
}
int ynandif_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_ext_tags *tags)
{
struct yaffs_packed_tags2 pt;
int localData = 0;
void *spare = NULL;
unsigned spareSize;
int retval = 0;
int eccStatus; /* 0 = ok, 1 = fixed, -1 = unfixed */
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
yaffs_trace(YAFFS_TRACE_MTD,
"nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p",
nand_chunk, data, tags);
if (!tags) {
spare = NULL;
spareSize = 0;
} else if (dev->param.inband_tags) {
if (!data) {
localData = 1;
data = yaffs_get_temp_buffer(dev);
}
spare = NULL;
spareSize = 0;
} else {
spare = &pt;
spareSize = sizeof(struct yaffs_packed_tags2);
}
retval = geometry->readChunk(dev, nand_chunk,
data,
data ? dev->param.total_bytes_per_chunk : 0,
spare, spareSize,
&eccStatus);
if (dev->param.inband_tags) {
if (tags) {
struct yaffs_packed_tags2_tags_only *pt2tp;
pt2tp = (struct yaffs_packed_tags2_tags_only *)
&data[dev->data_bytes_per_chunk];
yaffs_unpack_tags2_tags_only(tags, pt2tp);
}
} else {
if (tags)
yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
}
if (tags && tags->chunk_used) {
if (eccStatus < 0 ||
tags->ecc_result == YAFFS_ECC_RESULT_UNFIXED)
tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
else if (eccStatus > 0 ||
tags->ecc_result == YAFFS_ECC_RESULT_FIXED)
tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
else
tags->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
}
if (localData)
yaffs_release_temp_buffer(dev, data);
return retval;
}
int ynandif_MarkNANDBlockBad(struct yaffs_dev *dev, int blockId)
{
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
return geometry->markBlockBad(dev, blockId);
}
int ynandif_EraseBlockInNAND(struct yaffs_dev *dev, int blockId)
{
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
return geometry->eraseBlock(dev, blockId);
}
static int ynandif_IsBlockOk(struct yaffs_dev *dev, int blockId)
{
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
return geometry->checkBlockOk(dev, blockId);
}
int ynandif_QueryNANDBlock(struct yaffs_dev *dev, int blockId,
enum yaffs_block_state *state, u32 *seq_number)
{
unsigned chunkNo;
struct yaffs_ext_tags tags;
*seq_number = 0;
chunkNo = blockId * dev->param.chunks_per_block;
if (!ynandif_IsBlockOk(dev, blockId)) {
*state = YAFFS_BLOCK_STATE_DEAD;
} else {
ynandif_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &tags);
if (!tags.chunk_used) {
*state = YAFFS_BLOCK_STATE_EMPTY;
} else {
*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
*seq_number = tags.seq_number;
}
}
return YAFFS_OK;
}
int ynandif_InitialiseNAND(struct yaffs_dev *dev)
{
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
geometry->initialise(dev);
return YAFFS_OK;
}
int ynandif_Deinitialise_flash_fn(struct yaffs_dev *dev)
{
struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
geometry->deinitialise(dev);
return YAFFS_OK;
}
struct yaffs_dev *
yaffs_add_dev_from_geometry(const YCHAR *name,
const struct ynandif_Geometry *geometry)
{
YCHAR *clonedName = malloc(sizeof(YCHAR) *
(strnlen(name, YAFFS_MAX_NAME_LENGTH)+1));
struct yaffs_dev *dev = malloc(sizeof(struct yaffs_dev));
struct yaffs_param *param;
if (dev && clonedName) {
memset(dev, 0, sizeof(struct yaffs_dev));
strcpy(clonedName, name);
param = &dev->param;
param->name = clonedName;
param->write_chunk_tags_fn = ynandif_WriteChunkWithTagsToNAND;
param->read_chunk_tags_fn = ynandif_ReadChunkWithTagsFromNAND;
param->erase_fn = ynandif_EraseBlockInNAND;
param->initialise_flash_fn = ynandif_InitialiseNAND;
param->query_block_fn = ynandif_QueryNANDBlock;
param->bad_block_fn = ynandif_MarkNANDBlockBad;
param->n_caches = 20;
param->start_block = geometry->start_block;
param->end_block = geometry->end_block;
param->total_bytes_per_chunk = geometry->dataSize;
param->spare_bytes_per_chunk = geometry->spareSize;
param->inband_tags = geometry->inband_tags;
param->chunks_per_block = geometry->pagesPerBlock;
param->use_nand_ecc = geometry->hasECC;
param->is_yaffs2 = geometry->useYaffs2;
param->n_reserved_blocks = 5;
dev->driver_context = (void *)geometry;
yaffs_add_device(dev);
return dev;
}
free(dev);
free(clonedName);
return NULL;
}

View file

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

View file

@ -1,38 +0,0 @@
/*
* 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.
*/
/*
* Header file for using yaffs in an application via
* a direct interface.
*/
#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);
#endif

View file

@ -1,56 +0,0 @@
/*
* 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_packedtags1.h"
#include "yportenv.h"
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_unpack_tags1(struct yaffs_ext_tags *t,
const struct yaffs_packed_tags1 *pt)
{
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(struct yaffs_ext_tags));
}
}

View file

@ -1,39 +0,0 @@
/*
* 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 is used to pack YAFFS1 tags, not YAFFS2 tags. */
#ifndef __YAFFS_PACKEDTAGS1_H__
#define __YAFFS_PACKEDTAGS1_H__
#include "yaffs_guts.h"
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 unused_stuff:1;
unsigned should_be_ff;
};
void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
const struct yaffs_ext_tags *t);
void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
const struct yaffs_packed_tags1 *pt);
#endif

View file

@ -1,197 +0,0 @@
/*
* 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_packedtags2.h"
#include "yportenv.h"
#include "yaffs_trace.h"
/* This code packs a set of extended tags into a binary structure for
* NAND storage
*/
/* Some of the information is "extra" struff which can be packed in to
* speed scanning
* This is defined by having the EXTRA_HEADER_INFO_FLAG set.
*/
/* Extra flags applied to 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
/* Also, the top 4 bits of the object Id are set to the object type. */
#define EXTRA_OBJECT_TYPE_SHIFT (28)
#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
static void yaffs_dump_packed_tags2_tags_only(
const struct yaffs_packed_tags2_tags_only *ptt)
{
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_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
{
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);
}
static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
{
if (t->chunk_id != 0 || !t->extra_available)
return 0;
/* 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 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;
ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
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_dump_packed_tags2_tags_only(ptt);
yaffs_dump_tags2(t);
}
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);
if (tags_ecc)
yaffs_ecc_calc_other((unsigned char *)&pt->t,
sizeof(struct yaffs_packed_tags2_tags_only),
&pt->ecc);
}
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 (ptt->seq_number == 0xffffffff)
return;
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;
/* Do extra header info stuff */
if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
t->chunk_id = 0;
t->n_bytes = 0;
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->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);
t->ecc_result = ecc_result;
yaffs_dump_packed_tags2(pt);
yaffs_dump_tags2(t);
}

View file

@ -1,47 +0,0 @@
/*
* 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 is used to pack YAFFS2 tags, not YAFFS1tags. */
#ifndef __YAFFS_PACKEDTAGS2_H__
#define __YAFFS_PACKEDTAGS2_H__
#include "yaffs_guts.h"
#include "yaffs_ecc.h"
struct yaffs_packed_tags2_tags_only {
unsigned seq_number;
unsigned obj_id;
unsigned chunk_id;
unsigned n_bytes;
};
struct yaffs_packed_tags2 {
struct yaffs_packed_tags2_tags_only t;
struct yaffs_ecc_other ecc;
};
/* Full packed tags with ECC, used for oob tags */
void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
const struct yaffs_ext_tags *t, int tags_ecc);
void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
int tags_ecc);
/* Only the tags part (no ECC for use with inband tags */
void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
const struct yaffs_ext_tags *t);
void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
struct yaffs_packed_tags2_tags_only *pt);
#endif

View file

@ -1,141 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*/
#include "yportenv.h"
#include <sort.h>
/* #include <linux/string.h> */
/*
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*/
#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;
static inline void
swapfunc(char *a, char *b, int n, int swaptype)
{
if (swaptype <= 1)
swapcode(long, a, b, n);
else
swapcode(char, a, b, n);
}
#define yswap(a, b) do { \
if (swaptype == 0) { \
long t = *(long *)(a); \
*(long *)(a) = *(long *)(b); \
*(long *)(b) = t; \
} else \
swapfunc(a, b, es, swaptype); \
} while (0)
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
static inline char *
med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
{
return cmp(a, b) < 0 ?
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a))
: (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c));
}
#ifndef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
void
yaffs_qsort(void *aa, size_t n, size_t es,
int (*cmp)(const void *, const void *))
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
int d, r, swaptype, swap_cnt;
register char *a = aa;
loop: SWAPINIT(a, es);
swap_cnt = 0;
if (n < 7) {
for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
pl -= es)
yswap(pl, pl - es);
return;
}
pm = (char *)a + (n / 2) * es;
if (n > 7) {
pl = (char *)a;
pn = (char *)a + (n - 1) * es;
if (n > 40) {
d = (n / 8) * es;
pl = med3(pl, pl + d, pl + 2 * d, cmp);
pm = med3(pm - d, pm, pm + d, cmp);
pn = med3(pn - 2 * d, pn - d, pn, cmp);
}
pm = med3(pl, pm, pn, cmp);
}
yswap(a, pm);
pa = pb = (char *)a + es;
pc = pd = (char *)a + (n - 1) * es;
for (;;) {
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
if (r == 0) {
swap_cnt = 1;
yswap(pa, pb);
pa += es;
}
pb += es;
}
while (pb <= pc && (r = cmp(pc, a)) >= 0) {
if (r == 0) {
swap_cnt = 1;
yswap(pc, pd);
pd -= es;
}
pc -= es;
}
if (pb > pc)
break;
yswap(pb, pc);
swap_cnt = 1;
pb += es;
pc -= es;
}
if (swap_cnt == 0) { /* Switch to insertion sort */
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
pl -= es)
yswap(pl, pl - es);
return;
}
pn = (char *)a + n * es;
r = min(pa - (char *)a, pb - pa);
vecswap(a, pb - r, r);
r = min((long)(pd - pc), (long)(pn - pd - es));
vecswap(pb, pn - r, r);
r = pb - pa;
if (r > es)
yaffs_qsort(a, r / es, es, cmp);
r = pd - pc;
if (r > es) {
/* Iterate rather than recurse to save stack space */
a = pn - r;
n = r / es;
goto loop;
}
/* yaffs_qsort(pn - r, r / es, es, cmp);*/
}

View file

@ -1,306 +0,0 @@
/*
* 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"
#include <dm/devres.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);
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.seq != bi->seq_number ||
hdr.sum != yaffs_summary_sum(dev))
result = YAFFS_FAIL;
}
if (st == dev->sum_tags && result == YAFFS_OK)
bi->has_summary = 1;
return result;
}
int yaffs_summary_add(struct yaffs_dev *dev,
struct yaffs_ext_tags *tags,
int chunk_in_nand)
{
struct yaffs_packed_tags2_tags_only tags_only;
struct yaffs_summary_tags *sum_tags;
int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
if (!dev->sum_tags)
return YAFFS_OK;
if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
yaffs_pack_tags2_tags_only(&tags_only, tags);
sum_tags = &dev->sum_tags[chunk_in_block];
sum_tags->chunk_id = tags_only.chunk_id;
sum_tags->n_bytes = tags_only.n_bytes;
sum_tags->obj_id = tags_only.obj_id;
if (chunk_in_block == dev->chunks_per_summary - 1) {
/* Time to write out the summary */
yaffs_summary_write(dev, block_in_nand);
yaffs_summary_clear(dev);
yaffs_skip_rest_of_block(dev);
}
}
return YAFFS_OK;
}
int yaffs_summary_fetch(struct yaffs_dev *dev,
struct yaffs_ext_tags *tags,
int chunk_in_block)
{
struct yaffs_packed_tags2_tags_only tags_only;
struct yaffs_summary_tags *sum_tags;
if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
sum_tags = &dev->sum_tags[chunk_in_block];
tags_only.chunk_id = sum_tags->chunk_id;
tags_only.n_bytes = sum_tags->n_bytes;
tags_only.obj_id = sum_tags->obj_id;
yaffs_unpack_tags2_tags_only(tags, &tags_only);
return YAFFS_OK;
}
return YAFFS_FAIL;
}
void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
{
struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
int i;
if (!bi->has_summary)
return;
for (i = dev->chunks_per_summary;
i < dev->param.chunks_per_block;
i++) {
if (yaffs_check_chunk_bit(dev, blk, i)) {
yaffs_clear_chunk_bit(dev, blk, i);
bi->pages_in_use--;
dev->n_free_chunks++;
}
}
}

View file

@ -1,35 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_SUMMARY_H__
#define __YAFFS_SUMMARY_H__
#include "yaffs_packedtags2.h"
int yaffs_summary_init(struct yaffs_dev *dev);
void yaffs_summary_deinit(struct yaffs_dev *dev);
int yaffs_summary_add(struct yaffs_dev *dev,
struct yaffs_ext_tags *tags,
int chunk_in_block);
int yaffs_summary_fetch(struct yaffs_dev *dev,
struct yaffs_ext_tags *tags,
int chunk_in_block);
int yaffs_summary_read(struct yaffs_dev *dev,
struct yaffs_summary_tags *st,
int blk);
void yaffs_summary_gc(struct yaffs_dev *dev, int blk);
#endif

View file

@ -1,406 +0,0 @@
/*
* 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_guts.h"
#include "yaffs_tagscompat.h"
#include "yaffs_ecc.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_trace.h"
static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
/********** Tags ECC calculations *********/
void yaffs_calc_ecc(const u8 *data, struct yaffs_spare *spare)
{
yaffs_ecc_calc(data, spare->ecc1);
yaffs_ecc_calc(&data[256], spare->ecc2);
}
void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
{
/* Calculate an ecc */
unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
unsigned i, j;
unsigned ecc = 0;
unsigned bit = 0;
tags->ecc = 0;
for (i = 0; i < 8; i++) {
for (j = 1; j & 0xff; j <<= 1) {
bit++;
if (b[i] & j)
ecc ^= bit;
}
}
tags->ecc = ecc;
}
int yaffs_check_tags_ecc(struct yaffs_tags *tags)
{
unsigned ecc = tags->ecc;
yaffs_calc_tags_ecc(tags);
ecc ^= tags->ecc;
if (ecc && ecc <= 64) {
/* TODO: Handle the failure better. Retire? */
unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
ecc--;
b[ecc / 8] ^= (1 << (ecc & 7));
/* Now recvalc the ecc */
yaffs_calc_tags_ecc(tags);
return 1; /* recovered error */
} else if (ecc) {
/* Wierd ecc failure value */
/* TODO Need to do somethiong here */
return -1; /* unrecovered error */
}
return 0;
}
/********** Tags **********/
static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
struct yaffs_tags *tags_ptr)
{
union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
yaffs_calc_tags_ecc(tags_ptr);
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_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->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_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_spare_init(struct yaffs_spare *spare)
{
memset(spare, 0xff, sizeof(struct yaffs_spare));
}
static int yaffs_wr_nand(struct yaffs_dev *dev,
int nand_chunk, const u8 *data,
struct yaffs_spare *spare)
{
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;
}
return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
}
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 ret_val;
struct yaffs_spare local_spare;
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 = &local_spare;
}
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 ecc_result1, ecc_result2;
u8 calc_ecc[3];
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 (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 (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 (ecc_result1 || ecc_result2) {
/* We had a data problem on this page */
yaffs_handle_rd_data_error(dev, nand_chunk);
}
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
*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
}
} else {
/* Must allocate enough memory for spare+2*sizeof(int) */
/* for ecc results from device. */
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) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>mtd ecc error fix performed on chunk %d:0",
nand_chunk);
} else if (nspare.eccres1 < 0) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>mtd ecc error unfixed on chunk %d:0",
nand_chunk);
}
if (nspare.eccres2 > 0) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>mtd ecc error fix performed on chunk %d:1",
nand_chunk);
} else if (nspare.eccres2 < 0) {
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_handle_rd_data_error(dev, nand_chunk);
}
if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
*ecc_result = YAFFS_ECC_RESULT_FIXED;
else
*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
}
}
return ret_val;
}
/*
* Functions for robustisizing
*/
static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
{
int flash_block = nand_chunk / dev->param.chunks_per_block;
/* Mark the block for retirement */
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
* then retire the block
* NB recursion
*/
}
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;
yaffs_spare_init(&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;
tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
if (dev->data_bytes_per_chunk >= 1024)
tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
else
tags.n_bytes_msb = 3;
tags.serial_number = ext_tags->serial_number;
if (!dev->param.use_nand_ecc && data)
yaffs_calc_ecc(data, &spare);
yaffs_load_tags_to_spare(&spare, &tags);
}
return yaffs_wr_nand(dev, nand_chunk, data, &spare);
}
int yaffs_tags_compat_rd(struct yaffs_dev *dev,
int nand_chunk,
u8 *data, struct yaffs_ext_tags *ext_tags)
{
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(&spare_ff, 0xff, sizeof(spare_ff));
init = 1;
}
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;
}
return YAFFS_OK;
}
int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
{
struct yaffs_spare spare;
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;
enum yaffs_ecc_result dummy;
if (!init) {
memset(&spare_ff, 0xff, sizeof(spare_ff));
init = 1;
}
*seq_number = 0;
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 (hweight8(spare0.block_status & spare1.block_status) < 7)
*state = YAFFS_BLOCK_STATE_DEAD;
else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
*state = YAFFS_BLOCK_STATE_EMPTY;
else
*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
return YAFFS_OK;
}

View file

@ -1,36 +0,0 @@
/*
* 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_TAGSCOMPAT_H__
#define __YAFFS_TAGSCOMPAT_H__
#include "yaffs_guts.h"
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_calc_tags_ecc(struct yaffs_tags *tags);
int yaffs_check_tags_ecc(struct yaffs_tags *tags);
int yaffs_count_bits(u8 byte);
#endif

View file

@ -1,57 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YTRACE_H__
#define __YTRACE_H__
extern unsigned int yaffs_trace_mask;
extern unsigned int yaffs_wr_attempts;
/*
* Tracing flags.
* The flags masked in YAFFS_TRACE_ALWAYS are always traced.
*/
#define YAFFS_TRACE_OS 0x00000002
#define YAFFS_TRACE_ALLOCATE 0x00000004
#define YAFFS_TRACE_SCAN 0x00000008
#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
#define YAFFS_TRACE_ERASE 0x00000020
#define YAFFS_TRACE_GC 0x00000040
#define YAFFS_TRACE_WRITE 0x00000080
#define YAFFS_TRACE_TRACING 0x00000100
#define YAFFS_TRACE_DELETION 0x00000200
#define YAFFS_TRACE_BUFFERS 0x00000400
#define YAFFS_TRACE_NANDACCESS 0x00000800
#define YAFFS_TRACE_GC_DETAIL 0x00001000
#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
#define YAFFS_TRACE_MTD 0x00004000
#define YAFFS_TRACE_CHECKPOINT 0x00008000
#define YAFFS_TRACE_VERIFY 0x00010000
#define YAFFS_TRACE_VERIFY_NAND 0x00020000
#define YAFFS_TRACE_VERIFY_FULL 0x00040000
#define YAFFS_TRACE_VERIFY_ALL 0x000f0000
#define YAFFS_TRACE_SYNC 0x00100000
#define YAFFS_TRACE_BACKGROUND 0x00200000
#define YAFFS_TRACE_LOCK 0x00400000
#define YAFFS_TRACE_MOUNT 0x00800000
#define YAFFS_TRACE_ERROR 0x40000000
#define YAFFS_TRACE_BUG 0x80000000
#define YAFFS_TRACE_ALWAYS 0xf0000000
#endif

View file

@ -1,457 +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 is set up for u-boot.
*
* This version now uses the ydevconfig mechanism to set up partitions.
*/
#include <div64.h>
#include <malloc.h>
#include <linux/printk.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
#include <linux/mtd/rawnand.h>
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";
}
}
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;
mtd = get_nand_dev_by_index(flash_dev);
if (!mtd) {
pr_err("\nno NAND devices available\n");
return;
}
dev = calloc(1, sizeof(*dev));
mp = strdup(_mp);
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 = lldiv(mtd->size, mtd->erasesize - 1);
if (end_block < start_block) {
printf("Bad start/end\n");
goto err;
}
chip = mtd_to_nand(mtd);
/* 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 = nand_mtd_to_devnum(dev->driver_context);
printf("%-10s %5d 0x%05x 0x%05x %s",
dev->param.name, flash_dev,
dev->param.start_block, dev->param.end_block,
dev->param.inband_tags ? "using inband tags, " : "");
free_space = yaffs_freespace(dev->param.name);
if (free_space < 0)
printf("not mounted\n");
else
printf("free 0x%x\n", free_space);
}
}
void make_a_file(char *yaffsName, char bval, int sizeOfFile)
{
int outh;
int i;
unsigned char buffer[100];
outh = yaffs_open(yaffsName,
O_CREAT | O_RDWR | O_TRUNC,
S_IREAD | S_IWRITE);
if (outh < 0) {
printf("Error opening file: %d. %s\n", outh, yaffs_error_str());
return;
}
memset(buffer, bval, 100);
do {
i = sizeOfFile;
if (i > 100)
i = 100;
sizeOfFile -= i;
yaffs_write(outh, buffer, i);
} while (sizeOfFile > 0);
yaffs_close(outh);
}
void read_a_file(char *fn)
{
int h;
int i = 0;
unsigned char b;
h = yaffs_open(fn, O_RDWR, 0);
if (h < 0) {
printf("File not found\n");
return;
}
while (yaffs_read(h, &b, 1) > 0) {
printf("%02x ", b);
i++;
if (i > 32) {
printf("\n");
i = 0;
}
}
printf("\n");
yaffs_close(h);
}
void cmd_yaffs_mount(char *mp)
{
int retval = yaffs_mount(mp);
if (retval < 0)
printf("Error mounting %s, return value: %d, %s\n", mp,
yaffsfs_GetError(), yaffs_error_str());
}
void cmd_yaffs_umount(char *mp)
{
if (yaffs_unmount(mp) == -1)
printf("Error umounting %s, return value: %d, %s\n", mp,
yaffsfs_GetError(), yaffs_error_str());
}
void cmd_yaffs_write_file(char *yaffsName, char bval, int sizeOfFile)
{
make_a_file(yaffsName, bval, sizeOfFile);
}
void cmd_yaffs_read_file(char *fn)
{
read_a_file(fn);
}
void cmd_yaffs_mread_file(char *fn, char *addr)
{
int h;
struct yaffs_stat s;
yaffs_stat(fn, &s);
printf("Copy %s to 0x%p... ", fn, addr);
h = yaffs_open(fn, O_RDWR, 0);
if (h < 0) {
printf("File not found\n");
return;
}
yaffs_read(h, addr, (int)s.st_size);
printf("\t[DONE]\n");
yaffs_close(h);
}
void cmd_yaffs_mwrite_file(char *fn, char *addr, int size)
{
int outh;
outh = yaffs_open(fn, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE);
if (outh < 0)
printf("Error opening file: %d, %s\n", outh, yaffs_error_str());
yaffs_write(outh, addr, size);
yaffs_close(outh);
}
void cmd_yaffs_ls(const char *mountpt, int longlist)
{
int i;
yaffs_DIR *d;
struct yaffs_dirent *de;
struct yaffs_stat stat;
char tempstr[255];
d = yaffs_opendir(mountpt);
if (!d) {
printf("opendir failed, %s\n", yaffs_error_str());
return;
}
for (i = 0; (de = yaffs_readdir(d)) != NULL; i++) {
if (longlist) {
sprintf(tempstr, "%s/%s", mountpt, de->d_name);
yaffs_lstat(tempstr, &stat);
printf("%-25s\t%7ld",
de->d_name,
(long)stat.st_size);
printf(" %5d %s\n",
stat.st_ino,
yaffs_file_type_str(&stat));
} else {
printf("%s\n", de->d_name);
}
}
yaffs_closedir(d);
}
void cmd_yaffs_mkdir(const char *dir)
{
int retval = yaffs_mkdir(dir, 0);
if (retval < 0)
printf("yaffs_mkdir returning error: %d, %s\n",
retval, yaffs_error_str());
}
void cmd_yaffs_rmdir(const char *dir)
{
int retval = yaffs_rmdir(dir);
if (retval < 0)
printf("yaffs_rmdir returning error: %d, %s\n",
retval, yaffs_error_str());
}
void cmd_yaffs_rm(const char *path)
{
int retval = yaffs_unlink(path);
if (retval < 0)
printf("yaffs_unlink returning error: %d, %s\n",
retval, yaffs_error_str());
}
void cmd_yaffs_mv(const char *oldPath, const char *newPath)
{
int retval = yaffs_rename(newPath, oldPath);
if (retval < 0)
printf("yaffs_unlink returning error: %d, %s\n",
retval, yaffs_error_str());
}

View file

@ -1,521 +0,0 @@
/*
* 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)
{
return !(yaffs_trace_mask &
(YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
}
static int yaffs_skip_full_verification(struct yaffs_dev *dev)
{
return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
}
static int yaffs_skip_nand_verification(struct yaffs_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 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++;
}
/* 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)
{
return YAFFS_OK;
}

View file

@ -1,43 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_VERIFY_H__
#define __YAFFS_VERIFY_H__
#include "yaffs_guts.h"
void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
int n);
void yaffs_verify_collected_blk(struct yaffs_dev *dev,
struct yaffs_block_info *bi, int n);
void yaffs_verify_blocks(struct yaffs_dev *dev);
void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
struct yaffs_ext_tags *tags, int parent_check);
void yaffs_verify_file(struct yaffs_obj *obj);
void yaffs_verify_link(struct yaffs_obj *obj);
void yaffs_verify_symlink(struct yaffs_obj *obj);
void yaffs_verify_special(struct yaffs_obj *obj);
void yaffs_verify_obj(struct yaffs_obj *obj);
void yaffs_verify_objects(struct yaffs_dev *dev);
void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
void yaffs_verify_dir(struct yaffs_obj *directory);
void yaffs_verify_free_chunks(struct yaffs_dev *dev);
int yaffs_verify_file_sane(struct yaffs_obj *obj);
int yaffs_skip_verification(struct yaffs_dev *dev);
#endif

View file

@ -1,420 +0,0 @@
/*
* 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"
#include <dm/devres.h>
int yaffs1_scan(struct yaffs_dev *dev)
{
struct yaffs_ext_tags tags;
int blk;
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;
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++;
yaffs_rd_chunk_tags_nand(dev, chunk,
chunk_data, NULL);
oh = (struct yaffs_obj_hdr *)chunk_data;
in = yaffs_find_by_number(dev, tags.obj_id);
if (in && in->variant_type != oh->type) {
/* This should not happen, but somehow
* Wev'e ended up with an obj_id that
* has been reused but not yet deleted,
* and worse still it has changed type.
* Delete the old object.
*/
yaffs_del_obj(in);
in = NULL;
}
in = yaffs_find_or_create_by_number(dev,
tags.obj_id,
oh->type);
if (!in)
alloc_failed = 1;
if (in && oh->shadows_obj > 0) {
struct yaffs_shadow_fixer *fixer;
fixer =
kmalloc(sizeof
(struct yaffs_shadow_fixer),
GFP_NOFS);
if (fixer) {
fixer->next = shadow_fixers;
shadow_fixers = fixer;
fixer->obj_id = tags.obj_id;
fixer->shadowed_id =
oh->shadows_obj;
yaffs_trace(YAFFS_TRACE_SCAN,
" Shadow fixer: %d shadows %d",
fixer->obj_id,
fixer->shadowed_id);
}
}
if (in && in->valid) {
/* We have already filled this one.
* We have a duplicate and need to
* resolve it. */
unsigned existing_serial = in->serial;
unsigned new_serial =
tags.serial_number;
if (((existing_serial + 1) & 3) ==
new_serial) {
/* Use new one - destroy the
* exisiting one */
yaffs_chunk_del(dev,
in->hdr_chunk,
1, __LINE__);
in->valid = 0;
} else {
/* Use existing - destroy
* this one. */
yaffs_chunk_del(dev, chunk, 1,
__LINE__);
}
}
if (in && !in->valid &&
(tags.obj_id == YAFFS_OBJECTID_ROOT ||
tags.obj_id ==
YAFFS_OBJECTID_LOSTNFOUND)) {
/* We only load some info, don't fiddle
* with directory structure */
in->valid = 1;
in->variant_type = oh->type;
in->yst_mode = oh->yst_mode;
yaffs_load_attribs(in, oh);
in->hdr_chunk = chunk;
in->serial = tags.serial_number;
} else if (in && !in->valid) {
/* we need to load this info */
in->valid = 1;
in->variant_type = oh->type;
in->yst_mode = oh->yst_mode;
yaffs_load_attribs(in, oh);
in->hdr_chunk = chunk;
in->serial = tags.serial_number;
yaffs_set_obj_name_from_oh(in, oh);
in->dirty = 0;
/* directory stuff...
* hook up to parent
*/
parent =
yaffs_find_or_create_by_number
(dev, oh->parent_obj_id,
YAFFS_OBJECT_TYPE_DIRECTORY);
if (!parent)
alloc_failed = 1;
if (parent && parent->variant_type ==
YAFFS_OBJECT_TYPE_UNKNOWN) {
/* Set up as a directory */
parent->variant_type =
YAFFS_OBJECT_TYPE_DIRECTORY;
INIT_LIST_HEAD(&parent->
variant.dir_variant.
children);
} else if (!parent ||
parent->variant_type !=
YAFFS_OBJECT_TYPE_DIRECTORY) {
/* Hoosterman, a problem....
* We're trying to use a
* non-directory as a directory
*/
yaffs_trace(YAFFS_TRACE_ERROR,
"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
);
parent = dev->lost_n_found;
}
yaffs_add_obj_to_dir(parent, in);
switch (in->variant_type) {
case YAFFS_OBJECT_TYPE_UNKNOWN:
/* Todo got a problem */
break;
case YAFFS_OBJECT_TYPE_FILE:
if (dev->param.
use_header_file_size)
in->variant.
file_variant.file_size
= yaffs_oh_to_size(oh);
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
in->variant.
hardlink_variant.equiv_id =
oh->equiv_id;
list_add(&in->hard_links,
&hard_list);
break;
case YAFFS_OBJECT_TYPE_DIRECTORY:
/* Do nothing */
break;
case YAFFS_OBJECT_TYPE_SPECIAL:
/* Do nothing */
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
in->variant.symlink_variant.
alias =
yaffs_clone_str(oh->alias);
if (!in->variant.
symlink_variant.alias)
alloc_failed = 1;
break;
}
}
}
}
if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
/* If we got this far while scanning,
* then the block is fully allocated. */
state = YAFFS_BLOCK_STATE_FULL;
}
if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
/* If the block was partially allocated then
* treat it as fully allocated. */
state = YAFFS_BLOCK_STATE_FULL;
dev->alloc_block = -1;
}
bi->block_state = state;
/* Now let's see if it was dirty */
if (bi->pages_in_use == 0 &&
!bi->has_shrink_hdr &&
bi->block_state == YAFFS_BLOCK_STATE_FULL)
yaffs_block_became_dirty(dev, blk);
}
/* Ok, we've done all the scanning.
* Fix up the hard link chains.
* We should now have scanned all the objects, now it's time to add
* these hardlinks.
*/
yaffs_link_fixup(dev, &hard_list);
/*
* Fix up any shadowed objects.
* There should not be more than one of these.
*/
{
struct yaffs_shadow_fixer *fixer;
struct yaffs_obj *obj;
while (shadow_fixers) {
fixer = shadow_fixers;
shadow_fixers = fixer->next;
/* Complete the rename transaction by deleting the
* shadowed object then setting the object header
to unshadowed.
*/
obj = yaffs_find_by_number(dev, fixer->shadowed_id);
if (obj)
yaffs_del_obj(obj);
obj = yaffs_find_by_number(dev, fixer->obj_id);
if (obj)
yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
kfree(fixer);
}
}
yaffs_release_temp_buffer(dev, chunk_data);
if (alloc_failed)
return YAFFS_FAIL;
yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
return YAFFS_OK;
}

View file

@ -1,22 +0,0 @@
/*
* 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_YAFFS1_H__
#define __YAFFS_YAFFS1_H__
#include "yaffs_guts.h"
int yaffs1_scan(struct yaffs_dev *dev);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,39 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_YAFFS2_H__
#define __YAFFS_YAFFS2_H__
#include "yaffs_guts.h"
void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
struct yaffs_block_info *bi);
void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
struct yaffs_block_info *bi);
int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
int yaffs2_checkpt_required(struct yaffs_dev *dev);
int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
int yaffs2_checkpt_save(struct yaffs_dev *dev);
int yaffs2_checkpt_restore(struct yaffs_dev *dev);
int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
int yaffs2_scan_backwards(struct yaffs_dev *dev);
#endif

View file

@ -1,34 +0,0 @@
/*
* 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.
*/
/*
* Header file for using yaffs in an application via
* a direct interface.
*/
#ifndef __YAFFSCFG_H__
#define __YAFFSCFG_H__
#include "yportenv.h"
#define YAFFSFS_N_HANDLES 100
#define YAFFSFS_N_DSC 20
struct yaffsfs_DeviceConfiguration {
const YCHAR *prefix;
struct yaffs_dev *dev;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,199 +0,0 @@
/*
* 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.
*/
/*
* Header file for using yaffs in an application via
* a direct interface.
*/
#ifndef __YAFFSFS_H__
#define __YAFFSFS_H__
#include "yaffscfg.h"
#include "yportenv.h"
#ifndef NAME_MAX
#define NAME_MAX 256
#endif
#define YAFFS_MAX_FILE_SIZE (0x800000000LL - 1)
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 opaque_structure yaffs_DIR;
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
};
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_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);
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_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 YCHAR *path, mode_t mode) ;
int yaffs_rmdir(const YCHAR *path) ;
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 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_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_sync(const YCHAR *path) ;
int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath);
int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz);
int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath);
int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev);
loff_t yaffs_freespace(const YCHAR *path);
loff_t yaffs_totalspace(const YCHAR *path);
int yaffs_inodecount(const YCHAR *path);
int yaffs_n_handles(const YCHAR *path);
#define YAFFS_SHARE_READ 1
#define YAFFS_SHARE_WRITE 2
int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int shareMode);
struct yaffs_dev;
void yaffs_add_device(struct yaffs_dev *dev);
int yaffs_start_up(void);
int yaffsfs_GetLastError(void);
/* Functions to iterate through devices. NB Use with extreme care! */
void yaffs_dev_rewind(void);
struct yaffs_dev *yaffs_next_dev(void);
/* Function to get the last error */
int yaffs_get_error(void);
const char *yaffs_error_to_str(int err);
/* Function only for debugging */
void *yaffs_getdev(const YCHAR *path);
int yaffs_dump_dev(const YCHAR *path);
int yaffs_set_error(int error);
/* Trace control functions */
unsigned yaffs_set_trace(unsigned tm);
unsigned yaffs_get_trace(void);
#endif

View file

@ -1,77 +0,0 @@
/*
* 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.
*/
/*
* ydirectenv.h: Environment wrappers for YAFFS direct.
*/
#ifndef __YDIRECTENV_H__
#define __YDIRECTENV_H__
#include <malloc.h>
#include <linux/compat.h>
#include "yaffs_osglue.h"
void yaffs_bug_fn(const char *file_name, int line_no);
#define YCHAR char
#define YUCHAR unsigned char
#define _Y(x) x
#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 yaffs_strcmp(a, b) strcmp(a, b)
#define yaffs_strncmp(a, b, c) strncmp(a, b, c)
#endif
void yaffs_qsort(void *aa, size_t n, size_t es,
int (*cmp)(const void *, const void *));
#define sort(base, n, sz, cmp_fn, swp) yaffs_qsort(base, n, sz, cmp_fn)
#define YAFFS_PATH_DIVIDERS "/"
#ifdef NO_inline
#define inline
#endif
#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"
#include "yaffscfg.h"
#define Y_CURRENT_TIME yaffsfs_CurrentTime()
#define Y_TIME_CONVERT(x) x
#define YAFFS_ROOT_MODE 0666
#define YAFFS_LOSTNFOUND_MODE 0666
#include <linux/list.h>
#include "yaffsfs.h"
#endif

View file

@ -1,301 +0,0 @@
/*
* 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 __YPORTENV_H__
#define __YPORTENV_H__
#include <linux/bug.h>
#include <linux/types.h>
/* 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"
#elif defined CONFIG_YAFFS_DIRECT
/* Direct interface */
#include "ydirectenv.h"
#elif defined CONFIG_YAFFS_UTIL
#include "yutilsenv.h"
#else
/* Should have specified a configuration type */
#error Unknown configuration
#endif
#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
#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 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
/* 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)
#ifndef S_IREAD
#define S_IREAD 0000400
#endif
#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