generic: fold yaffs_git_2010_10_20 patch to generic/files

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>

SVN-Revision: 34013
This commit is contained in:
Gabor Juhos 2012-10-30 14:58:17 +00:00
parent 56190ed0fc
commit 449f88df0f
53 changed files with 11490 additions and 63077 deletions

View file

@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2
If unsure, say Y.
config YAFFS_DISABLE_LAZY_LOAD
bool "Disable lazy loading"
depends on YAFFS_YAFFS2
config YAFFS_DISABLE_TAGS_ECC
bool "Disable YAFFS from doing ECC on tags by default"
depends on YAFFS_FS && YAFFS_YAFFS2
default n
help
"Lazy loading" defers loading file details until they are
required. This saves mount time, but makes the first look-up
a bit longer.
Lazy loading will only happen if enabled by this option being 'n'
and if the appropriate tags are available, else yaffs2 will
automatically fall back to immediate loading and do the right
thing.
Lazy laoding will be required by checkpointing.
Setting this to 'y' will disable lazy loading.
This defaults Yaffs to using its own ECC calculations on tags instead of
just relying on the MTD.
This behavior can also be overridden with tags_ecc_on and
tags_ecc_off mount options.
If unsure, say N.
@ -154,3 +146,45 @@ config YAFFS_SHORT_NAMES_IN_RAM
but makes look-ups faster.
If unsure, say Y.
config YAFFS_EMPTY_LOST_AND_FOUND
bool "Empty lost and found on boot"
depends on YAFFS_FS
default n
help
If this is enabled then the contents of lost and found is
automatically dumped at mount.
If unsure, say N.
config YAFFS_DISABLE_BLOCK_REFRESHING
bool "Disable yaffs2 block refreshing"
depends on YAFFS_FS
default n
help
If this is set, then block refreshing is disabled.
Block refreshing infrequently refreshes the oldest block in
a yaffs2 file system. This mechanism helps to refresh flash to
mitigate against data loss. This is particularly useful for MLC.
If unsure, say N.
config YAFFS_DISABLE_BACKGROUND
bool "Disable yaffs2 background processing"
depends on YAFFS_FS
default n
help
If this is set, then background processing is disabled.
Background processing makes many foreground activities faster.
If unsure, say N.
config YAFFS_XATTR
bool "Enable yaffs2 xattr support"
depends on YAFFS_FS
default y
help
If this is set then yaffs2 will provide xattr support.
If unsure, say Y.

View file

@ -4,7 +4,14 @@
obj-$(CONFIG_YAFFS_FS) += yaffs.o
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o
yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
yaffs-y += yaffs_nameval.o
yaffs-y += yaffs_allocator.o
yaffs-y += yaffs_yaffs1.o
yaffs-y += yaffs_yaffs2.o
yaffs-y += yaffs_bitmap.o
yaffs-y += yaffs_verify.o

View file

@ -1,4 +1,4 @@
The yaffs2 source has been fetched from the yaffs2 CVS tree.
The yaffs2 source has been fetched from the yaffs2 GIT tree.
URL: cvs.aleph1.co.uk
Version: 2009-09-24
URL: git://www.aleph1.co.uk/yaffs2
Version: 7396445d7d0d13469b9505791114b9dc6b76ffe4 (2010-10-20)

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -24,6 +24,8 @@
#define __EXTRAS_H__
#include "yportenv.h"
#if !(defined __KERNEL__)
/* Definition of types */
@ -33,103 +35,6 @@ typedef unsigned __u32;
#endif
/*
* This is a simple doubly linked list implementation that matches the
* way the Linux kernel doubly linked list implementation works.
*/
struct ylist_head {
struct ylist_head *next; /* next in chain */
struct ylist_head *prev; /* previous in chain */
};
/* Initialise a static list */
#define YLIST_HEAD(name) \
struct ylist_head name = { &(name), &(name)}
/* Initialise a list head to an empty list */
#define YINIT_LIST_HEAD(p) \
do { \
(p)->next = (p);\
(p)->prev = (p); \
} while (0)
/* Add an element to a list */
static __inline__ void ylist_add(struct ylist_head *newEntry,
struct ylist_head *list)
{
struct ylist_head *listNext = list->next;
list->next = newEntry;
newEntry->prev = list;
newEntry->next = listNext;
listNext->prev = newEntry;
}
static __inline__ void ylist_add_tail(struct ylist_head *newEntry,
struct ylist_head *list)
{
struct ylist_head *listPrev = list->prev;
list->prev = newEntry;
newEntry->next = list;
newEntry->prev = listPrev;
listPrev->next = newEntry;
}
/* Take an element out of its current list, with or without
* reinitialising the links.of the entry*/
static __inline__ void ylist_del(struct ylist_head *entry)
{
struct ylist_head *listNext = entry->next;
struct ylist_head *listPrev = entry->prev;
listNext->prev = listPrev;
listPrev->next = listNext;
}
static __inline__ void ylist_del_init(struct ylist_head *entry)
{
ylist_del(entry);
entry->next = entry->prev = entry;
}
/* Test if the list is empty */
static __inline__ int ylist_empty(struct ylist_head *entry)
{
return (entry->next == entry);
}
/* ylist_entry takes a pointer to a list entry and offsets it to that
* we can find a pointer to the object it is embedded in.
*/
#define ylist_entry(entry, type, member) \
((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
/* ylist_for_each and list_for_each_safe iterate over lists.
* ylist_for_each_safe uses temporary storage to make the list delete safe
*/
#define ylist_for_each(itervar, list) \
for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
#define ylist_for_each_safe(itervar, saveVar, list) \
for (itervar = (list)->next, saveVar = (list)->next->next; \
itervar != (list); itervar = saveVar, saveVar = saveVar->next)
#if !(defined __KERNEL__)

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Martin Fouts <Martin.Fouts@palmsource.com>
@ -29,25 +29,46 @@
/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
/* #define CONFIG_YAFFS_DOES_ECC */
/* Default: Selected */
/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */
#define CONFIG_YAFFS_DOES_TAGS_ECC
/* Default: Not selected */
/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
/* CONFIG_YAFFS_DOES_ECC is set */
/* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
/* Default: Selected */
/* Meaning: Disables testing whether chunks are erased before writing to them*/
#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
/* Default: Not selected */
/* Meaning: Always test whether chunks are erased before writing to them.
Use during mtd debugging and init. */
/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */
/* Default: Not Selected */
/* Meaning: At mount automatically empty all files from lost and found. */
/* This is done to fix an old problem where rmdir was not checking for an */
/* empty directory. This can also be achieved with a mount option. */
#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
/* Default: Selected */
/* Meaning: Cache short names, taking more RAM, but faster look-ups */
#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
/* Default: 10 */
/* Meaning: set the count of blocks to reserve for checkpointing */
#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
/* Default: Unselected */
/* Meaning: Select to disable block refreshing. */
/* Block Refreshing periodically rewrites the oldest block. */
/* #define CONFIG_DISABLE_BLOCK_REFRESHING */
/* Default: Unselected */
/* Meaning: Select to disable background processing */
/* #define CONFIG_DISABLE_BACKGROUND */
/* Default: Selected */
/* Meaning: Enable XATTR support */
#define CONFIG_YAFFS_XATTR
/*
Older-style on-NAND data format has a "pageStatus" byte to record
Older-style on-NAND data format has a "page_status" byte to record
chunk/page state. This byte is zeroed when the page is discarded.
Choose this option if you have existing on-NAND data in this format
that you need to continue to support. New data written also uses the
@ -57,7 +78,7 @@ adjusted to use the older-style format. See notes on tags formats and
MTD versions in yaffs_mtdif1.c.
*/
/* Default: Not selected */
/* Meaning: Use older-style on-NAND data format with pageStatus byte */
/* Meaning: Use older-style on-NAND data format with page_status byte */
/* #define CONFIG_YAFFS_9BYTE_TAGS */
#endif /* YAFFS_OUT_OF_TREE */

View file

@ -0,0 +1,409 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#include "yaffs_allocator.h"
#include "yaffs_guts.h"
#include "yaffs_trace.h"
#include "yportenv.h"
#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
{
dev = dev;
}
void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
{
dev = dev;
}
yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
{
return (yaffs_tnode_t *)YMALLOC(dev->tnode_size);
}
void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
{
dev = dev;
YFREE(tn);
}
void yaffs_init_raw_objs(yaffs_dev_t *dev)
{
dev = dev;
}
void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
{
dev = dev;
}
yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
{
dev = dev;
return (yaffs_obj_t *) YMALLOC(sizeof(yaffs_obj_t));
}
void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
{
dev = dev;
YFREE(obj);
}
#else
struct yaffs_tnode_list {
struct yaffs_tnode_list *next;
yaffs_tnode_t *tnodes;
};
typedef struct yaffs_tnode_list yaffs_tnodelist_t;
struct yaffs_obj_tList_struct {
yaffs_obj_t *objects;
struct yaffs_obj_tList_struct *next;
};
typedef struct yaffs_obj_tList_struct yaffs_obj_tList;
struct yaffs_AllocatorStruct {
int n_tnodesCreated;
yaffs_tnode_t *freeTnodes;
int nFreeTnodes;
yaffs_tnodelist_t *allocatedTnodeList;
int n_objCreated;
yaffs_obj_t *freeObjects;
int nFreeObjects;
yaffs_obj_tList *allocatedObjectList;
};
typedef struct yaffs_AllocatorStruct yaffs_Allocator;
static void yaffs_deinit_raw_tnodes(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
yaffs_tnodelist_t *tmp;
if(!allocator){
YBUG();
return;
}
while (allocator->allocatedTnodeList) {
tmp = allocator->allocatedTnodeList->next;
YFREE(allocator->allocatedTnodeList->tnodes);
YFREE(allocator->allocatedTnodeList);
allocator->allocatedTnodeList = tmp;
}
allocator->freeTnodes = NULL;
allocator->nFreeTnodes = 0;
allocator->n_tnodesCreated = 0;
}
static void yaffs_init_raw_tnodes(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator = dev->allocator;
if(allocator){
allocator->allocatedTnodeList = NULL;
allocator->freeTnodes = NULL;
allocator->nFreeTnodes = 0;
allocator->n_tnodesCreated = 0;
} else
YBUG();
}
static int yaffs_create_tnodes(yaffs_dev_t *dev, int n_tnodes)
{
yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
int i;
yaffs_tnode_t *newTnodes;
__u8 *mem;
yaffs_tnode_t *curr;
yaffs_tnode_t *next;
yaffs_tnodelist_t *tnl;
if(!allocator){
YBUG();
return YAFFS_FAIL;
}
if (n_tnodes < 1)
return YAFFS_OK;
/* make these things */
newTnodes = YMALLOC(n_tnodes * dev->tnode_size);
mem = (__u8 *)newTnodes;
if (!newTnodes) {
T(YAFFS_TRACE_ERROR,
(TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
return YAFFS_FAIL;
}
/* New hookup for wide tnodes */
for (i = 0; i < n_tnodes - 1; i++) {
curr = (yaffs_tnode_t *) &mem[i * dev->tnode_size];
next = (yaffs_tnode_t *) &mem[(i+1) * dev->tnode_size];
curr->internal[0] = next;
}
curr = (yaffs_tnode_t *) &mem[(n_tnodes - 1) * dev->tnode_size];
curr->internal[0] = allocator->freeTnodes;
allocator->freeTnodes = (yaffs_tnode_t *)mem;
allocator->nFreeTnodes += n_tnodes;
allocator->n_tnodesCreated += 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 = YMALLOC(sizeof(yaffs_tnodelist_t));
if (!tnl) {
T(YAFFS_TRACE_ERROR,
(TSTR
("yaffs: Could not add tnodes to management list" TENDSTR)));
return YAFFS_FAIL;
} else {
tnl->tnodes = newTnodes;
tnl->next = allocator->allocatedTnodeList;
allocator->allocatedTnodeList = tnl;
}
T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
return YAFFS_OK;
}
yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
yaffs_tnode_t *tn = NULL;
if(!allocator){
YBUG();
return NULL;
}
/* If there are none left make more */
if (!allocator->freeTnodes)
yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
if (allocator->freeTnodes) {
tn = allocator->freeTnodes;
allocator->freeTnodes = allocator->freeTnodes->internal[0];
allocator->nFreeTnodes--;
}
return tn;
}
/* FreeTnode frees up a tnode and puts it back on the free list */
void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
{
yaffs_Allocator *allocator = dev->allocator;
if(!allocator){
YBUG();
return;
}
if (tn) {
tn->internal[0] = allocator->freeTnodes;
allocator->freeTnodes = tn;
allocator->nFreeTnodes++;
}
dev->checkpoint_blocks_required = 0; /* force recalculation*/
}
static void yaffs_init_raw_objs(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator = dev->allocator;
if(allocator) {
allocator->allocatedObjectList = NULL;
allocator->freeObjects = NULL;
allocator->nFreeObjects = 0;
} else
YBUG();
}
static void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator = dev->allocator;
yaffs_obj_tList *tmp;
if(!allocator){
YBUG();
return;
}
while (allocator->allocatedObjectList) {
tmp = allocator->allocatedObjectList->next;
YFREE(allocator->allocatedObjectList->objects);
YFREE(allocator->allocatedObjectList);
allocator->allocatedObjectList = tmp;
}
allocator->freeObjects = NULL;
allocator->nFreeObjects = 0;
allocator->n_objCreated = 0;
}
static int yaffs_create_free_objs(yaffs_dev_t *dev, int n_obj)
{
yaffs_Allocator *allocator = dev->allocator;
int i;
yaffs_obj_t *newObjects;
yaffs_obj_tList *list;
if(!allocator){
YBUG();
return YAFFS_FAIL;
}
if (n_obj < 1)
return YAFFS_OK;
/* make these things */
newObjects = YMALLOC(n_obj * sizeof(yaffs_obj_t));
list = YMALLOC(sizeof(yaffs_obj_tList));
if (!newObjects || !list) {
if (newObjects){
YFREE(newObjects);
newObjects = NULL;
}
if (list){
YFREE(list);
list = NULL;
}
T(YAFFS_TRACE_ALLOCATE,
(TSTR("yaffs: Could not allocate more objects" TENDSTR)));
return YAFFS_FAIL;
}
/* Hook them into the free list */
for (i = 0; i < n_obj - 1; i++) {
newObjects[i].siblings.next =
(struct ylist_head *)(&newObjects[i + 1]);
}
newObjects[n_obj - 1].siblings.next = (void *)allocator->freeObjects;
allocator->freeObjects = newObjects;
allocator->nFreeObjects += n_obj;
allocator->n_objCreated += n_obj;
/* Now add this bunch of Objects to a list for freeing up. */
list->objects = newObjects;
list->next = allocator->allocatedObjectList;
allocator->allocatedObjectList = list;
return YAFFS_OK;
}
yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
{
yaffs_obj_t *obj = NULL;
yaffs_Allocator *allocator = dev->allocator;
if(!allocator) {
YBUG();
return obj;
}
/* If there are none left make more */
if (!allocator->freeObjects)
yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
if (allocator->freeObjects) {
obj = allocator->freeObjects;
allocator->freeObjects =
(yaffs_obj_t *) (allocator->freeObjects->siblings.next);
allocator->nFreeObjects--;
}
return obj;
}
void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
{
yaffs_Allocator *allocator = dev->allocator;
if(!allocator)
YBUG();
else {
/* Link into the free list. */
obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
allocator->freeObjects = obj;
allocator->nFreeObjects++;
}
}
void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
{
if(dev->allocator){
yaffs_deinit_raw_tnodes(dev);
yaffs_deinit_raw_objs(dev);
YFREE(dev->allocator);
dev->allocator=NULL;
} else
YBUG();
}
void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator;
if(!dev->allocator){
allocator = YMALLOC(sizeof(yaffs_Allocator));
if(allocator){
dev->allocator = allocator;
yaffs_init_raw_tnodes(dev);
yaffs_init_raw_objs(dev);
}
} else
YBUG();
}
#endif

View file

@ -0,0 +1,30 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 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(yaffs_dev_t *dev);
void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev);
yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev);
void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn);
yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev);
void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj);
#endif

View file

@ -0,0 +1,105 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 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 Y_INLINE __u8 *yaffs_BlockBits(yaffs_dev_t *dev, int blk)
{
if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
T(YAFFS_TRACE_ERROR,
(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
blk));
YBUG();
}
return dev->chunk_bits +
(dev->chunk_bit_stride * (blk - dev->internal_start_block));
}
void yaffs_verify_chunk_bit_id(yaffs_dev_t *dev, int blk, int chunk)
{
if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
chunk < 0 || chunk >= dev->param.chunks_per_block) {
T(YAFFS_TRACE_ERROR,
(TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
blk, chunk));
YBUG();
}
}
void yaffs_clear_chunk_bits(yaffs_dev_t *dev, int blk)
{
__u8 *blkBits = yaffs_BlockBits(dev, blk);
memset(blkBits, 0, dev->chunk_bit_stride);
}
void yaffs_clear_chunk_bit(yaffs_dev_t *dev, int blk, int chunk)
{
__u8 *blkBits = yaffs_BlockBits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk);
blkBits[chunk / 8] &= ~(1 << (chunk & 7));
}
void yaffs_set_chunk_bit(yaffs_dev_t *dev, int blk, int chunk)
{
__u8 *blkBits = yaffs_BlockBits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk);
blkBits[chunk / 8] |= (1 << (chunk & 7));
}
int yaffs_check_chunk_bit(yaffs_dev_t *dev, int blk, int chunk)
{
__u8 *blkBits = yaffs_BlockBits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk);
return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
}
int yaffs_still_some_chunks(yaffs_dev_t *dev, int blk)
{
__u8 *blkBits = yaffs_BlockBits(dev, blk);
int i;
for (i = 0; i < dev->chunk_bit_stride; i++) {
if (*blkBits)
return 1;
blkBits++;
}
return 0;
}
int yaffs_count_chunk_bits(yaffs_dev_t *dev, int blk)
{
__u8 *blkBits = yaffs_BlockBits(dev, blk);
int i;
int n = 0;
for (i = 0; i < dev->chunk_bit_stride; i++) {
__u8 x = *blkBits;
while (x) {
if (x & 1)
n++;
x >>= 1;
}
blkBits++;
}
return n;
}

View file

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

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -11,16 +11,12 @@
* published by the Free Software Foundation.
*/
const char *yaffs_checkptrw_c_version =
"$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $";
#include "yaffs_checkptrw.h"
#include "yaffs_getblockinfo.h"
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
static int yaffs2_checkpt_space_ok(yaffs_dev_t *dev)
{
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks;
T(YAFFS_TRACE_CHECKPOINT,
(TSTR("checkpt blocks available = %d" TENDSTR),
@ -30,53 +26,56 @@ static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
}
static int yaffs_CheckpointErase(yaffs_Device *dev)
static int yaffs_checkpt_erase(yaffs_dev_t *dev)
{
int i;
if (!dev->eraseBlockInNAND)
if (!dev->param.erase_fn)
return 0;
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
dev->internalStartBlock, dev->internalEndBlock));
dev->internal_start_block, dev->internal_end_block));
for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
dev->nErasedBlocks++;
dev->nFreeChunks += dev->nChunksPerBlock;
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->markNANDBlockBad(dev, i);
bi->blockState = YAFFS_BLOCK_STATE_DEAD;
dev->param.bad_block_fn(dev, i);
bi->block_state = YAFFS_BLOCK_STATE_DEAD;
}
}
}
dev->blocksInCheckpoint = 0;
dev->blocks_in_checkpt = 0;
return 1;
}
static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
static void yaffs2_checkpt_find_erased_block(yaffs_dev_t *dev)
{
int i;
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks;
T(YAFFS_TRACE_CHECKPOINT,
(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
dev->n_erased_blocks, dev->param.n_reserved_blocks, blocksAvailable, dev->checkpt_next_block));
if (dev->checkpointNextBlock >= 0 &&
dev->checkpointNextBlock <= dev->internalEndBlock &&
if (dev->checkpt_next_block >= 0 &&
dev->checkpt_next_block <= dev->internal_end_block &&
blocksAvailable > 0) {
for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
dev->checkpointNextBlock = i + 1;
dev->checkpointCurrentBlock = i;
for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) {
yaffs_block_info_t *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;
T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i));
return;
}
@ -84,34 +83,34 @@ static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
}
T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR)));
dev->checkpointNextBlock = -1;
dev->checkpointCurrentBlock = -1;
dev->checkpt_next_block = -1;
dev->checkpt_cur_block = -1;
}
static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
static void yaffs2_checkpt_find_block(yaffs_dev_t *dev)
{
int i;
yaffs_ExtendedTags tags;
yaffs_ext_tags tags;
T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
dev->blocksInCheckpoint, dev->checkpointNextBlock));
dev->blocks_in_checkpt, dev->checkpt_next_block));
if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
int chunk = i * dev->nChunksPerBlock;
int realignedChunk = chunk - dev->chunkOffset;
if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) {
int chunk = i * dev->param.chunks_per_block;
int realignedChunk = chunk - dev->chunk_offset;
dev->readChunkWithTagsFromNAND(dev, realignedChunk,
dev->param.read_chunk_tags_fn(dev, realignedChunk,
NULL, &tags);
T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
i, tags.objectId, tags.sequenceNumber, tags.eccResult));
i, tags.obj_id, tags.seq_number, tags.ecc_result));
if (tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
/* Right kind of block */
dev->checkpointNextBlock = tags.objectId;
dev->checkpointCurrentBlock = i;
dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
dev->blocksInCheckpoint++;
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++;
T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i));
return;
}
@ -119,122 +118,127 @@ static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR)));
dev->checkpointNextBlock = -1;
dev->checkpointCurrentBlock = -1;
dev->checkpt_next_block = -1;
dev->checkpt_cur_block = -1;
}
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
int yaffs2_checkpt_open(yaffs_dev_t *dev, int forWriting)
{
dev->checkpt_open_write = forWriting;
/* Got the functions we need? */
if (!dev->writeChunkWithTagsToNAND ||
!dev->readChunkWithTagsFromNAND ||
!dev->eraseBlockInNAND ||
!dev->markNANDBlockBad)
if (!dev->param.write_chunk_tags_fn ||
!dev->param.read_chunk_tags_fn ||
!dev->param.erase_fn ||
!dev->param.bad_block_fn)
return 0;
if (forWriting && !yaffs_CheckpointSpaceOk(dev))
if (forWriting && !yaffs2_checkpt_space_ok(dev))
return 0;
if (!dev->checkpointBuffer)
dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
if (!dev->checkpointBuffer)
if (!dev->checkpt_buffer)
dev->checkpt_buffer = YMALLOC_DMA(dev->param.total_bytes_per_chunk);
if (!dev->checkpt_buffer)
return 0;
dev->checkpointPageSequence = 0;
dev->checkpointOpenForWrite = forWriting;
dev->checkpointByteCount = 0;
dev->checkpointSum = 0;
dev->checkpointXor = 0;
dev->checkpointCurrentBlock = -1;
dev->checkpointCurrentChunk = -1;
dev->checkpointNextBlock = dev->internalStartBlock;
dev->checkpt_page_seq = 0;
dev->checkpt_byte_count = 0;
dev->checkpt_sum = 0;
dev->checkpt_xor = 0;
dev->checkpt_cur_block = -1;
dev->checkpt_cur_chunk = -1;
dev->checkpt_next_block = dev->internal_start_block;
/* Erase all the blocks in the checkpoint area */
if (forWriting) {
memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
dev->checkpointByteOffset = 0;
return yaffs_CheckpointErase(dev);
memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
dev->checkpt_byte_offs = 0;
return yaffs_checkpt_erase(dev);
} else {
int i;
/* Set to a value that will kick off a read */
dev->checkpointByteOffset = dev->nDataBytesPerChunk;
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->blocksInCheckpoint = 0;
dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
for (i = 0; i < dev->checkpointMaxBlocks; i++)
dev->checkpointBlockList[i] = -1;
dev->blocks_in_checkpt = 0;
dev->checkpt_max_blocks = (dev->internal_end_block - dev->internal_start_block)/16 + 2;
dev->checkpt_block_list = YMALLOC(sizeof(int) * dev->checkpt_max_blocks);
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 yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
int yaffs2_get_checkpt_sum(yaffs_dev_t *dev, __u32 *sum)
{
__u32 compositeSum;
compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
compositeSum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xFF);
*sum = compositeSum;
return 1;
}
static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
static int yaffs2_checkpt_flush_buffer(yaffs_dev_t *dev)
{
int chunk;
int realignedChunk;
yaffs_ExtendedTags tags;
yaffs_ext_tags tags;
if (dev->checkpointCurrentBlock < 0) {
yaffs_CheckpointFindNextErasedBlock(dev);
dev->checkpointCurrentChunk = 0;
if (dev->checkpt_cur_block < 0) {
yaffs2_checkpt_find_erased_block(dev);
dev->checkpt_cur_chunk = 0;
}
if (dev->checkpointCurrentBlock < 0)
if (dev->checkpt_cur_block < 0)
return 0;
tags.chunkDeleted = 0;
tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
tags.chunkId = dev->checkpointPageSequence + 1;
tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
tags.byteCount = dev->nDataBytesPerChunk;
if (dev->checkpointCurrentChunk == 0) {
tags.is_deleted = 0;
tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
tags.chunk_id = dev->checkpt_page_seq + 1;
tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
tags.n_bytes = dev->data_bytes_per_chunk;
if (dev->checkpt_cur_chunk == 0) {
/* First chunk we write for the block? Set block state to
checkpoint */
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointCurrentBlock);
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
dev->blocksInCheckpoint++;
yaffs_block_info_t *bi = yaffs_get_block_info(dev, dev->checkpt_cur_block);
bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
dev->blocks_in_checkpt++;
}
chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
chunk = dev->checkpt_cur_block * dev->param.chunks_per_block + dev->checkpt_cur_chunk;
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk, tags.objectId, tags.chunkId));
chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, tags.obj_id, tags.chunk_id));
realignedChunk = chunk - dev->chunkOffset;
realignedChunk = chunk - dev->chunk_offset;
dev->writeChunkWithTagsToNAND(dev, realignedChunk,
dev->checkpointBuffer, &tags);
dev->checkpointByteOffset = 0;
dev->checkpointPageSequence++;
dev->checkpointCurrentChunk++;
if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {
dev->checkpointCurrentChunk = 0;
dev->checkpointCurrentBlock = -1;
dev->n_page_writes++;
dev->param.write_chunk_tags_fn(dev, realignedChunk,
dev->checkpt_buffer, &tags);
dev->checkpt_byte_offs = 0;
dev->checkpt_page_seq++;
dev->checkpt_cur_chunk++;
if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
dev->checkpt_cur_chunk = 0;
dev->checkpt_cur_block = -1;
}
memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
return 1;
}
int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
int yaffs2_checkpt_wr(yaffs_dev_t *dev, const void *data, int n_bytes)
{
int i = 0;
int ok = 1;
@ -244,36 +248,36 @@ int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
if (!dev->checkpointBuffer)
if (!dev->checkpt_buffer)
return 0;
if (!dev->checkpointOpenForWrite)
if (!dev->checkpt_open_write)
return -1;
while (i < nBytes && ok) {
dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes;
dev->checkpointSum += *dataBytes;
dev->checkpointXor ^= *dataBytes;
while (i < n_bytes && ok) {
dev->checkpt_buffer[dev->checkpt_byte_offs] = *dataBytes;
dev->checkpt_sum += *dataBytes;
dev->checkpt_xor ^= *dataBytes;
dev->checkpointByteOffset++;
dev->checkpt_byte_offs++;
i++;
dataBytes++;
dev->checkpointByteCount++;
dev->checkpt_byte_count++;
if (dev->checkpointByteOffset < 0 ||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
ok = yaffs_CheckpointFlushBuffer(dev);
if (dev->checkpt_byte_offs < 0 ||
dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
ok = yaffs2_checkpt_flush_buffer(dev);
}
return i;
}
int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
int yaffs2_checkpt_rd(yaffs_dev_t *dev, void *data, int n_bytes)
{
int i = 0;
int ok = 1;
yaffs_ExtendedTags tags;
yaffs_ext_tags tags;
int chunk;
@ -281,113 +285,116 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
__u8 *dataBytes = (__u8 *)data;
if (!dev->checkpointBuffer)
if (!dev->checkpt_buffer)
return 0;
if (dev->checkpointOpenForWrite)
if (dev->checkpt_open_write)
return -1;
while (i < nBytes && ok) {
while (i < n_bytes && ok) {
if (dev->checkpointByteOffset < 0 ||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
if (dev->checkpt_byte_offs < 0 ||
dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
if (dev->checkpointCurrentBlock < 0) {
yaffs_CheckpointFindNextCheckpointBlock(dev);
dev->checkpointCurrentChunk = 0;
if (dev->checkpt_cur_block < 0) {
yaffs2_checkpt_find_block(dev);
dev->checkpt_cur_chunk = 0;
}
if (dev->checkpointCurrentBlock < 0)
if (dev->checkpt_cur_block < 0)
ok = 0;
else {
chunk = dev->checkpointCurrentBlock *
dev->nChunksPerBlock +
dev->checkpointCurrentChunk;
chunk = dev->checkpt_cur_block *
dev->param.chunks_per_block +
dev->checkpt_cur_chunk;
realignedChunk = chunk - dev->chunkOffset;
realignedChunk = chunk - dev->chunk_offset;
dev->n_page_reads++;
/* read in the next chunk */
/* printf("read checkpoint page %d\n",dev->checkpointPage); */
dev->readChunkWithTagsFromNAND(dev,
dev->param.read_chunk_tags_fn(dev,
realignedChunk,
dev->checkpointBuffer,
dev->checkpt_buffer,
&tags);
if (tags.chunkId != (dev->checkpointPageSequence + 1) ||
tags.eccResult > YAFFS_ECC_RESULT_FIXED ||
tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
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;
dev->checkpointByteOffset = 0;
dev->checkpointPageSequence++;
dev->checkpointCurrentChunk++;
dev->checkpt_byte_offs = 0;
dev->checkpt_page_seq++;
dev->checkpt_cur_chunk++;
if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
dev->checkpointCurrentBlock = -1;
if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block)
dev->checkpt_cur_block = -1;
}
}
if (ok) {
*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
dev->checkpointSum += *dataBytes;
dev->checkpointXor ^= *dataBytes;
dev->checkpointByteOffset++;
*dataBytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
dev->checkpt_sum += *dataBytes;
dev->checkpt_xor ^= *dataBytes;
dev->checkpt_byte_offs++;
i++;
dataBytes++;
dev->checkpointByteCount++;
dev->checkpt_byte_count++;
}
}
return i;
}
int yaffs_CheckpointClose(yaffs_Device *dev)
int yaffs_checkpt_close(yaffs_dev_t *dev)
{
if (dev->checkpointOpenForWrite) {
if (dev->checkpointByteOffset != 0)
yaffs_CheckpointFlushBuffer(dev);
} else {
if (dev->checkpt_open_write) {
if (dev->checkpt_byte_offs != 0)
yaffs2_checkpt_flush_buffer(dev);
} else if(dev->checkpt_block_list){
int i;
for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
for (i = 0; i < dev->blocks_in_checkpt && dev->checkpt_block_list[i] >= 0; i++) {
int blk = dev->checkpt_block_list[i];
yaffs_block_info_t *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;
else {
/* Todo this looks odd... */
}
}
YFREE(dev->checkpointBlockList);
dev->checkpointBlockList = NULL;
YFREE(dev->checkpt_block_list);
dev->checkpt_block_list = NULL;
}
dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
dev->nErasedBlocks -= dev->blocksInCheckpoint;
dev->n_free_chunks -= dev->blocks_in_checkpt * dev->param.chunks_per_block;
dev->n_erased_blocks -= dev->blocks_in_checkpt;
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR),
dev->checkpointByteCount));
dev->checkpt_byte_count));
if (dev->checkpointBuffer) {
if (dev->checkpt_buffer) {
/* free the buffer */
YFREE(dev->checkpointBuffer);
dev->checkpointBuffer = NULL;
YFREE(dev->checkpt_buffer);
dev->checkpt_buffer = NULL;
return 1;
} else
return 0;
}
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
int yaffs2_checkpt_invalidate_stream(yaffs_dev_t *dev)
{
/* Erase the first checksum block */
/* Erase the checkpoint data */
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
dev->blocks_in_checkpt));
if (!yaffs_CheckpointSpaceOk(dev))
return 0;
return yaffs_CheckpointErase(dev);
return yaffs_checkpt_erase(dev);
}

View file

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

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -28,9 +28,6 @@
* this bytes influence on the line parity.
*/
const char *yaffs_ecc_c_version =
"$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $";
#include "yportenv.h"
#include "yaffs_ecc.h"
@ -72,7 +69,7 @@ static const unsigned char column_parity_table[] = {
/* Count the bits in an unsigned char or a U32 */
static int yaffs_CountBits(unsigned char x)
static int yaffs_count_bits(unsigned char x)
{
int r = 0;
while (x) {
@ -83,7 +80,7 @@ static int yaffs_CountBits(unsigned char x)
return r;
}
static int yaffs_CountBits32(unsigned x)
static int yaffs_count_bits32(unsigned x)
{
int r = 0;
while (x) {
@ -95,7 +92,7 @@ static int yaffs_CountBits32(unsigned x)
}
/* Calculate the ECC for a 256-byte block of data */
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc)
{
unsigned int i;
@ -166,7 +163,7 @@ void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
/* Correct the ECC on a 256 byte block of data */
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc)
{
unsigned char d0, d1, d2; /* deltas */
@ -226,9 +223,9 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
return 1; /* Corrected the error */
}
if ((yaffs_CountBits(d0) +
yaffs_CountBits(d1) +
yaffs_CountBits(d2)) == 1) {
if ((yaffs_count_bits(d0) +
yaffs_count_bits(d1) +
yaffs_count_bits(d2)) == 1) {
/* Reccoverable error in ecc */
read_ecc[0] = test_ecc[0];
@ -248,7 +245,7 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
/*
* ECCxxxOther does ECC calcs on arbitrary n bytes of data
*/
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
yaffs_ECCOther *eccOther)
{
unsigned int i;
@ -258,7 +255,7 @@ void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
unsigned line_parity_prime = 0;
unsigned char b;
for (i = 0; i < nBytes; i++) {
for (i = 0; i < n_bytes; i++) {
b = column_parity_table[*data++];
col_parity ^= b;
@ -275,7 +272,7 @@ void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
eccOther->lineParityPrime = line_parity_prime;
}
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
yaffs_ECCOther *read_ecc,
const yaffs_ECCOther *test_ecc)
{
@ -304,7 +301,7 @@ int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
if (cDelta & 0x02)
bit |= 0x01;
if (lDelta >= nBytes)
if (lDelta >= n_bytes)
return -1;
data[lDelta] ^= (1 << bit);
@ -312,8 +309,8 @@ int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
return 1; /* corrected */
}
if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
yaffs_CountBits(cDelta)) == 1) {
if ((yaffs_count_bits32(lDelta) + yaffs_count_bits32(lDeltaPrime) +
yaffs_count_bits(cDelta)) == 1) {
/* Reccoverable error in ecc */
*read_ecc = *test_ecc;

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -32,13 +32,13 @@ typedef struct {
unsigned lineParityPrime;
} yaffs_ECCOther;
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc);
int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc);
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
yaffs_ECCOther *ecc);
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
yaffs_ECCOther *read_ecc,
const yaffs_ECCOther *test_ecc);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -17,18 +17,19 @@
#define __YAFFS_GETBLOCKINFO_H__
#include "yaffs_guts.h"
#include "yaffs_trace.h"
/* Function to manipulate block info */
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
static Y_INLINE yaffs_block_info_t *yaffs_get_block_info(yaffs_dev_t * dev, int blk)
{
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
blk));
YBUG();
}
return &dev->blockInfo[blk - dev->internalStartBlock];
return &dev->block_info[blk - dev->internal_start_block];
}
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,43 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 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_LINUX_H__
#define __YAFFS_LINUX_H__
#include "devextras.h"
#include "yportenv.h"
struct yaffs_LinuxContext {
struct ylist_head contextList; /* List of these we have mounted */
struct yaffs_dev_s *dev;
struct super_block * superBlock;
struct task_struct *bgThread; /* Background thread for this device */
int bgRunning;
struct semaphore grossLock; /* Gross locking semaphore */
__u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
* at compile time so we have to allocate it.
*/
struct ylist_head searchContexts;
void (*putSuperFunc)(struct super_block *sb);
struct task_struct *readdirProcess;
unsigned mount_id;
};
#define yaffs_dev_to_lc(dev) ((struct yaffs_LinuxContext *)((dev)->os_context))
#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
#endif

View file

@ -0,0 +1,200 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 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.
*
* Note: Tis code is currently unused. Being checked in in case it becomes useful.
*/
#include "yaffs_allocator.h"
#include "yaffs_guts.h"
#include "yaffs_trace.h"
#include "yportenv.h"
#include "yaffs_linux.h"
/*
* Start out with the same allocator as yaffs direct.
* Todo: Change to Linux slab allocator.
*/
#define NAMELEN 20
struct yaffs_AllocatorStruct {
char tnode_name[NAMELEN+1];
char object_name[NAMELEN+1];
struct kmem_cache *tnode_cache;
struct kmem_cache *object_cache;
};
typedef struct yaffs_AllocatorStruct yaffs_Allocator;
int mount_id;
void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n")));
if(allocator){
if(allocator->tnode_cache){
kmem_cache_destroy(allocator->tnode_cache);
allocator->tnode_cache = NULL;
} else {
T(YAFFS_TRACE_ALWAYS,
(TSTR("NULL tnode cache\n")));
YBUG();
}
if(allocator->object_cache){
kmem_cache_destroy(allocator->object_cache);
allocator->object_cache = NULL;
} else {
T(YAFFS_TRACE_ALWAYS,
(TSTR("NULL object cache\n")));
YBUG();
}
YFREE(allocator);
} else {
T(YAFFS_TRACE_ALWAYS,
(TSTR("Deinitialising NULL allocator\n")));
YBUG();
}
dev->allocator = NULL;
}
static void fake_ctor0(void *data){data = data;}
static void fake_ctor1(void *data){data = data;}
static void fake_ctor2(void *data){data = data;}
static void fake_ctor3(void *data){data = data;}
static void fake_ctor4(void *data){data = data;}
static void fake_ctor5(void *data){data = data;}
static void fake_ctor6(void *data){data = data;}
static void fake_ctor7(void *data){data = data;}
static void fake_ctor8(void *data){data = data;}
static void fake_ctor9(void *data){data = data;}
static void (*fake_ctor_list[10]) (void *) = {
fake_ctor0,
fake_ctor1,
fake_ctor2,
fake_ctor3,
fake_ctor4,
fake_ctor5,
fake_ctor6,
fake_ctor7,
fake_ctor8,
fake_ctor9,
};
void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator;
unsigned mount_id = yaffs_dev_to_lc(dev)->mount_id;
T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n")));
if(dev->allocator)
YBUG();
else if(mount_id >= 10){
T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id));
} else {
allocator = YMALLOC(sizeof(yaffs_Allocator));
memset(allocator,0,sizeof(yaffs_Allocator));
dev->allocator = allocator;
if(!dev->allocator){
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs allocator creation failed\n")));
YBUG();
return;
}
sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id);
sprintf(allocator->object_name,"yaffs_o_%u",mount_id);
allocator->tnode_cache =
kmem_cache_create(allocator->tnode_name,
dev->tnode_size,
0, 0,
fake_ctor_list[mount_id]);
if(allocator->tnode_cache)
T(YAFFS_TRACE_ALLOCATE,
(TSTR("tnode cache \"%s\" %p\n"),
allocator->tnode_name,allocator->tnode_cache));
else {
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs cache creation failed\n")));
YBUG();
}
allocator->object_cache =
kmem_cache_create(allocator->object_name,
sizeof(yaffs_obj_t),
0, 0,
fake_ctor_list[mount_id]);
if(allocator->object_cache)
T(YAFFS_TRACE_ALLOCATE,
(TSTR("object cache \"%s\" %p\n"),
allocator->object_name,allocator->object_cache));
else {
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs cache creation failed\n")));
YBUG();
}
}
}
yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator = dev->allocator;
if(!allocator || !allocator->tnode_cache){
YBUG();
return NULL;
}
return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS);
}
void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
{
yaffs_Allocator *allocator = dev->allocator;
kmem_cache_free(allocator->tnode_cache,tn);
}
yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator = dev->allocator;
if(!allocator){
YBUG();
return NULL;
}
if(!allocator->object_cache){
YBUG();
return NULL;
}
return kmem_cache_alloc(allocator->object_cache, GFP_NOFS);
}
void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
{
yaffs_Allocator *allocator = dev->allocator;
kmem_cache_free(allocator->object_cache,obj);
}

View file

@ -0,0 +1,127 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* This file is just holds extra declarations of macros that would normally
* be providesd in the Linux kernel. These macros have been written from
* scratch but are functionally equivalent to the Linux ones.
*
*/
#ifndef __YAFFS_LIST_H__
#define __YAFFS_LIST_H__
#include "yportenv.h"
/*
* This is a simple doubly linked list implementation that matches the
* way the Linux kernel doubly linked list implementation works.
*/
struct ylist_head {
struct ylist_head *next; /* next in chain */
struct ylist_head *prev; /* previous in chain */
};
/* Initialise a static list */
#define YLIST_HEAD(name) \
struct ylist_head name = { &(name), &(name)}
/* Initialise a list head to an empty list */
#define YINIT_LIST_HEAD(p) \
do { \
(p)->next = (p);\
(p)->prev = (p); \
} while (0)
/* Add an element to a list */
static Y_INLINE void ylist_add(struct ylist_head *newEntry,
struct ylist_head *list)
{
struct ylist_head *listNext = list->next;
list->next = newEntry;
newEntry->prev = list;
newEntry->next = listNext;
listNext->prev = newEntry;
}
static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry,
struct ylist_head *list)
{
struct ylist_head *listPrev = list->prev;
list->prev = newEntry;
newEntry->next = list;
newEntry->prev = listPrev;
listPrev->next = newEntry;
}
/* Take an element out of its current list, with or without
* reinitialising the links.of the entry*/
static Y_INLINE void ylist_del(struct ylist_head *entry)
{
struct ylist_head *listNext = entry->next;
struct ylist_head *listPrev = entry->prev;
listNext->prev = listPrev;
listPrev->next = listNext;
}
static Y_INLINE void ylist_del_init(struct ylist_head *entry)
{
ylist_del(entry);
entry->next = entry->prev = entry;
}
/* Test if the list is empty */
static Y_INLINE int ylist_empty(struct ylist_head *entry)
{
return (entry->next == entry);
}
/* ylist_entry takes a pointer to a list entry and offsets it to that
* we can find a pointer to the object it is embedded in.
*/
#define ylist_entry(entry, type, member) \
((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
/* ylist_for_each and list_for_each_safe iterate over lists.
* ylist_for_each_safe uses temporary storage to make the list delete safe
*/
#define ylist_for_each(itervar, list) \
for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
#define ylist_for_each_safe(itervar, saveVar, list) \
for (itervar = (list)->next, saveVar = (list)->next->next; \
itervar != (list); itervar = saveVar, saveVar = saveVar->next)
#endif

View file

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

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -22,11 +22,6 @@
extern struct nand_oobinfo yaffs_oobinfo;
extern struct nand_oobinfo yaffs_noeccinfo;
#endif
int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
const __u8 *data, const yaffs_Spare *spare);
int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
yaffs_Spare *spare);
int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
int nandmtd_InitialiseNAND(yaffs_Device *dev);
int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber);
int nandmtd_InitialiseNAND(yaffs_dev_t *dev);
#endif

View file

@ -1,434 +0,0 @@
From ian@brightstareng.com Fri May 18 15:06:49 2007
From ian@brightstareng.com Fri May 18 15:08:21 2007
Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
(envelope-from <ian@brightstareng.com>)
id 1Hp380-00011e-T6
for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
Received: from localhost (localhost.localdomain [127.0.0.1])
by zebra.brightstareng.com (Postfix) with ESMTP
id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
Received: from zebra.brightstareng.com ([127.0.0.1])
by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
Received: from pippin (unknown [192.168.1.25])
by zebra.brightstareng.com (Postfix) with ESMTP
id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
From: Ian McDonnell <ian@brightstareng.com>
To: David Goodenough <david.goodenough@linkchoose.co.uk>
Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
Date: Fri, 18 May 2007 10:06:49 -0400
User-Agent: KMail/1.9.1
References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
Cc: Andrea Conti <alyf@alyf.net>,
Charles Manning <manningc2@actrix.gen.nz>
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
boundary="Boundary-00=_5LbTGmt62YoutxM"
Message-Id: <200705181006.49860.ian@brightstareng.com>
X-Virus-Scanned: by amavisd-new at brightstareng.com
Status: R
X-Status: NT
X-KMail-EncryptionState:
X-KMail-SignatureState:
X-KMail-MDN-Sent:
--Boundary-00=_5LbTGmt62YoutxM
Content-Type: text/plain;
charset="iso-8859-15"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
David, Andrea,
On Friday 18 May 2007 08:34, you wrote:
> Yea team. With this fix in place (I put it in the wrong place
> at first) I can now mount and ls the Yaffs partition without
> an error messages!
Good news!
Attached is a newer yaffs_mtdif1.c with a bandaid to help the
2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
See the LINUX_VERSION_CODE conditional in
nandmtd1_ReadChunkWithTagsFromNAND.
-imcd
--Boundary-00=_5LbTGmt62YoutxM
Content-Type: text/x-csrc;
charset="iso-8859-15";
name="yaffs_mtdif1.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="yaffs_mtdif1.c"
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
*
* Copyright (C) 2002 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This module provides the interface between yaffs_nand.c and the
* MTD API. This version is used when the MTD interface supports the
* 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
* and we have small-page NAND device.
*
* These functions are invoked via function pointers in yaffs_nand.c.
* This replaces functionality provided by functions in yaffs_mtdif.c
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
* called in yaffs_mtdif.c when the function pointers are NULL.
* We assume the MTD layer is performing ECC (useNANDECC is true).
*/
#include "yportenv.h"
#include "yaffs_guts.h"
#include "yaffs_packedtags1.h"
#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
#include "linux/kernel.h"
#include "linux/version.h"
#include "linux/types.h"
#include "linux/mtd/mtd.h"
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
const char *yaffs_mtdif1_c_version = "$Id$";
#ifndef CONFIG_YAFFS_9BYTE_TAGS
# define YTAG1_SIZE 8
#else
# define YTAG1_SIZE 9
#endif
#if 0
/* Use the following nand_ecclayout with MTD when using
* CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
* If you have existing Yaffs images and the byte order differs from this,
* adjust 'oobfree' to match your existing Yaffs data.
*
* This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
* pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
* the 9th byte.
*
* Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
* We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
* byte and B is the small-page bad-block indicator byte.
*/
static struct nand_ecclayout nand_oob_16 = {
.eccbytes = 6,
.eccpos = { 8, 9, 10, 13, 14, 15 },
.oobavail = 9,
.oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
};
#endif
/* Write a chunk (page) of data to NAND.
*
* Caller always provides ExtendedTags data which are converted to a more
* compact (packed) form for storage in NAND. A mini-ECC runs over the
* contents of the tags meta-data; used to valid the tags when read.
*
* - Pack ExtendedTags to PackedTags1 form
* - Compute mini-ECC for PackedTags1
* - Write data and packed tags to NAND.
*
* Note: Due to the use of the PackedTags1 meta-data which does not include
* a full sequence number (as found in the larger PackedTags2 form) it is
* necessary for Yaffs to re-write a chunk/page (just once) to mark it as
* discarded and dirty. This is not ideal: newer NAND parts are supposed
* to be written just once. When Yaffs performs this operation, this
* function is called with a NULL data pointer -- calling MTD write_oob
* without data is valid usage (2.6.17).
*
* Any underlying MTD error results in YAFFS_FAIL.
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkBytes = dev->nDataBytesPerChunk;
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
/* we assume that PackedTags1 and yaffs_Tags are compatible */
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
compile_time_assertion(sizeof(yaffs_Tags) == 8);
yaffs_PackTags1(&pt1, etags);
yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
/* When deleting a chunk, the upper layer provides only skeletal
* etags, one with chunkDeleted set. However, we need to update the
* tags, not erase them completely. So we use the NAND write property
* that only zeroed-bits stick and set tag bytes to all-ones and
* zero just the (not) deleted bit.
*/
#ifndef CONFIG_YAFFS_9BYTE_TAGS
if (etags->chunkDeleted) {
memset(&pt1, 0xff, 8);
/* clear delete status bit to indicate deleted */
pt1.deleted = 0;
}
#else
((__u8 *)&pt1)[8] = 0xff;
if (etags->chunkDeleted) {
memset(&pt1, 0xff, 8);
/* zero pageStatus byte to indicate deleted */
((__u8 *)&pt1)[8] = 0;
}
#endif
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = (__u8 *)data;
ops.oobbuf = (__u8 *)&pt1;
retval = mtd->write_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"write_oob failed, chunk %d, mtd error %d\n",
chunkInNAND, retval);
}
return retval ? YAFFS_FAIL : YAFFS_OK;
}
/* Return with empty ExtendedTags but add eccResult.
*/
static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
{
if (etags) {
memset(etags, 0, sizeof(*etags));
etags->eccResult = eccResult;
}
return retval;
}
/* Read a chunk (page) from NAND.
*
* Caller expects ExtendedTags data to be usable even on error; that is,
* all members except eccResult and blockBad are zeroed.
*
* - Check ECC results for data (if applicable)
* - Check for blank/erased block (return empty ExtendedTags if blank)
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
* - Convert PackedTags1 to ExtendedTags
* - Update eccResult and blockBad members to refect state.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkBytes = dev->nDataBytesPerChunk;
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
int deleted;
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = data;
ops.oobbuf = (__u8 *)&pt1;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
* help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
*/
ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
#endif
/* Read page and oob using MTD.
* Check status and determine ECC result.
*/
retval = mtd->read_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"read_oob failed, chunk %d, mtd error %d\n",
chunkInNAND, retval);
}
switch (retval) {
case 0:
/* no error */
break;
case -EUCLEAN:
/* MTD's ECC fixed the data */
eccres = YAFFS_ECC_RESULT_FIXED;
dev->eccFixed++;
break;
case -EBADMSG:
/* MTD's ECC could not fix the data */
dev->eccUnfixed++;
/* fall into... */
default:
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
etags->blockBad = (mtd->block_isbad)(mtd, addr);
return YAFFS_FAIL;
}
/* Check for a blank/erased chunk.
*/
if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
/* when blank, upper layers want eccResult to be <= NO_ERROR */
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
}
#ifndef CONFIG_YAFFS_9BYTE_TAGS
/* Read deleted status (bit) then return it to it's non-deleted
* state before performing tags mini-ECC check. pt1.deleted is
* inverted.
*/
deleted = !pt1.deleted;
pt1.deleted = 1;
#else
(void) deleted; /* not used */
#endif
/* Check the packed tags mini-ECC and correct if necessary/possible.
*/
retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
switch (retval) {
case 0:
/* no tags error, use MTD result */
break;
case 1:
/* recovered tags-ECC error */
dev->tagsEccFixed++;
eccres = YAFFS_ECC_RESULT_FIXED;
break;
default:
/* unrecovered tags-ECC error */
dev->tagsEccUnfixed++;
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
}
/* Unpack the tags to extended form and set ECC result.
* [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
*/
pt1.shouldBeFF = 0xFFFFFFFF;
yaffs_UnpackTags1(etags, &pt1);
etags->eccResult = eccres;
/* Set deleted state.
*/
#ifndef CONFIG_YAFFS_9BYTE_TAGS
etags->chunkDeleted = deleted;
#else
etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
#endif
return YAFFS_OK;
}
/* Mark a block bad.
*
* This is a persistant state.
* Use of this function should be rare.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
struct mtd_info * mtd = dev->genericDevice;
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
int retval;
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
/* Check any MTD prerequists.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
{
/* 2.6.18 has mtd->ecclayout->oobavail */
/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
int oobavail = mtd->ecclayout->oobavail;
if (oobavail < YTAG1_SIZE) {
yaffs_trace(YAFFS_TRACE_ERROR,
"mtd device has only %d bytes for tags, need %d",
oobavail, YTAG1_SIZE);
return YAFFS_FAIL;
}
return YAFFS_OK;
}
/* Query for the current state of a specific block.
*
* Examine the tags of the first chunk of the block and return the state:
* - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
* - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
* - YAFFS_BLOCK_STATE_EMPTY, the block is clean
*
* Always returns YAFFS_OK.
*/
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * pState, int *pSequenceNumber)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkNo = blockNo * dev->nChunksPerBlock;
yaffs_ExtendedTags etags;
int state = YAFFS_BLOCK_STATE_DEAD;
int seqnum = 0;
int retval;
/* We don't yet have a good place to test for MTD config prerequists.
* Do it here as we are called during the initial scan.
*/
if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
return YAFFS_FAIL;
}
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
if (etags.blockBad) {
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
"block %d is marked bad", blockNo);
state = YAFFS_BLOCK_STATE_DEAD;
}
else if (etags.chunkUsed) {
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
seqnum = etags.sequenceNumber;
}
else {
state = YAFFS_BLOCK_STATE_EMPTY;
}
*pState = state;
*pSequenceNumber = seqnum;
/* query always succeeds */
return YAFFS_OK;
}
#endif /*KERNEL_VERSION*/
--Boundary-00=_5LbTGmt62YoutxM--

View file

@ -2,7 +2,7 @@
* YAFFS: Yet another FFS. A NAND-flash specific file system.
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
*
* Copyright (C) 2002 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
@ -18,15 +18,17 @@
*
* These functions are invoked via function pointers in yaffs_nand.c.
* This replaces functionality provided by functions in yaffs_mtdif.c
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
* and the yaffs_tags_tCompatability functions in yaffs_tagscompat.c that are
* called in yaffs_mtdif.c when the function pointers are NULL.
* We assume the MTD layer is performing ECC (useNANDECC is true).
* We assume the MTD layer is performing ECC (use_nand_ecc is true).
*/
#include "yportenv.h"
#include "yaffs_trace.h"
#include "yaffs_guts.h"
#include "yaffs_packedtags1.h"
#include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */
#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */
#include "yaffs_linux.h"
#include "linux/kernel.h"
#include "linux/version.h"
@ -36,8 +38,6 @@
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $";
#ifndef CONFIG_YAFFS_9BYTE_TAGS
# define YTAG1_SIZE 8
#else
@ -51,12 +51,12 @@ const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:4
* adjust 'oobfree' to match your existing Yaffs data.
*
* This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
* pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
* page_status byte (at NAND spare offset 4) scattered/gathered from/to
* the 9th byte.
*
* Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
* We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
* We have/need PackedTags1 plus page_status: T0,T1,T2,T3,T4,T5,T6,T7,P
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the page_status
* byte and B is the small-page bad-block indicator byte.
*/
static struct nand_ecclayout nand_oob_16 = {
@ -88,42 +88,40 @@ static struct nand_ecclayout nand_oob_16 = {
* Any underlying MTD error results in YAFFS_FAIL.
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev,
int nand_chunk, const __u8 *data, const yaffs_ext_tags *etags)
{
struct mtd_info *mtd = dev->genericDevice;
int chunkBytes = dev->nDataBytesPerChunk;
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int chunkBytes = dev->data_bytes_per_chunk;
loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
/* we assume that PackedTags1 and yaffs_Tags are compatible */
/* we assume that PackedTags1 and yaffs_tags_t are compatible */
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
compile_time_assertion(sizeof(yaffs_Tags) == 8);
dev->nPageWrites++;
compile_time_assertion(sizeof(yaffs_tags_t) == 8);
yaffs_PackTags1(&pt1, etags);
yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
yaffs_calc_tags_ecc((yaffs_tags_t *)&pt1);
/* When deleting a chunk, the upper layer provides only skeletal
* etags, one with chunkDeleted set. However, we need to update the
* etags, one with is_deleted set. However, we need to update the
* tags, not erase them completely. So we use the NAND write property
* that only zeroed-bits stick and set tag bytes to all-ones and
* zero just the (not) deleted bit.
*/
#ifndef CONFIG_YAFFS_9BYTE_TAGS
if (etags->chunkDeleted) {
if (etags->is_deleted) {
memset(&pt1, 0xff, 8);
/* clear delete status bit to indicate deleted */
pt1.deleted = 0;
}
#else
((__u8 *)&pt1)[8] = 0xff;
if (etags->chunkDeleted) {
if (etags->is_deleted) {
memset(&pt1, 0xff, 8);
/* zero pageStatus byte to indicate deleted */
/* zero page_status byte to indicate deleted */
((__u8 *)&pt1)[8] = 0;
}
#endif
@ -137,20 +135,20 @@ int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
retval = mtd->write_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"write_oob failed, chunk %d, mtd error %d\n",
chunkInNAND, retval);
T(YAFFS_TRACE_MTD,
(TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
nand_chunk, retval));
}
return retval ? YAFFS_FAIL : YAFFS_OK;
}
/* Return with empty ExtendedTags but add eccResult.
/* Return with empty ExtendedTags but add ecc_result.
*/
static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval)
static int rettags(yaffs_ext_tags *etags, int ecc_result, int retval)
{
if (etags) {
memset(etags, 0, sizeof(*etags));
etags->eccResult = eccResult;
etags->ecc_result = ecc_result;
}
return retval;
}
@ -158,30 +156,28 @@ static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval)
/* Read a chunk (page) from NAND.
*
* Caller expects ExtendedTags data to be usable even on error; that is,
* all members except eccResult and blockBad are zeroed.
* all members except ecc_result and block_bad are zeroed.
*
* - Check ECC results for data (if applicable)
* - Check for blank/erased block (return empty ExtendedTags if blank)
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
* - Convert PackedTags1 to ExtendedTags
* - Update eccResult and blockBad members to refect state.
* - Update ecc_result and block_bad members to refect state.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev,
int nand_chunk, __u8 *data, yaffs_ext_tags *etags)
{
struct mtd_info *mtd = dev->genericDevice;
int chunkBytes = dev->nDataBytesPerChunk;
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int chunkBytes = dev->data_bytes_per_chunk;
loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
int deleted;
dev->nPageReads++;
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
@ -200,9 +196,9 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
*/
retval = mtd->read_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"read_oob failed, chunk %d, mtd error %d\n",
chunkInNAND, retval);
T(YAFFS_TRACE_MTD,
(TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
nand_chunk, retval));
}
switch (retval) {
@ -213,23 +209,23 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
case -EUCLEAN:
/* MTD's ECC fixed the data */
eccres = YAFFS_ECC_RESULT_FIXED;
dev->eccFixed++;
dev->n_ecc_fixed++;
break;
case -EBADMSG:
/* MTD's ECC could not fix the data */
dev->eccUnfixed++;
dev->n_ecc_unfixed++;
/* fall into... */
default:
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
etags->blockBad = (mtd->block_isbad)(mtd, addr);
etags->block_bad = (mtd->block_isbad)(mtd, addr);
return YAFFS_FAIL;
}
/* Check for a blank/erased chunk.
*/
if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
/* when blank, upper layers want eccResult to be <= NO_ERROR */
if (yaffs_check_ff((__u8 *)&pt1, 8)) {
/* when blank, upper layers want ecc_result to be <= NO_ERROR */
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
}
@ -241,37 +237,37 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
deleted = !pt1.deleted;
pt1.deleted = 1;
#else
deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
deleted = (yaffs_count_bits(((__u8 *)&pt1)[8]) < 7);
#endif
/* Check the packed tags mini-ECC and correct if necessary/possible.
*/
retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
retval = yaffs_check_tags_ecc((yaffs_tags_t *)&pt1);
switch (retval) {
case 0:
/* no tags error, use MTD result */
break;
case 1:
/* recovered tags-ECC error */
dev->tagsEccFixed++;
dev->n_tags_ecc_fixed++;
if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
eccres = YAFFS_ECC_RESULT_FIXED;
break;
default:
/* unrecovered tags-ECC error */
dev->tagsEccUnfixed++;
dev->n_tags_ecc_unfixed++;
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
}
/* Unpack the tags to extended form and set ECC result.
* [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
* [set shouldBeFF just to keep yaffs_unpack_tags1 happy]
*/
pt1.shouldBeFF = 0xFFFFFFFF;
yaffs_UnpackTags1(etags, &pt1);
etags->eccResult = eccres;
yaffs_unpack_tags1(etags, &pt1);
etags->ecc_result = eccres;
/* Set deleted state */
etags->chunkDeleted = deleted;
etags->is_deleted = deleted;
return YAFFS_OK;
}
@ -282,15 +278,15 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
int nandmtd1_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no)
{
struct mtd_info *mtd = dev->genericDevice;
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
int retval;
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), block_no));
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
retval = mtd->block_markbad(mtd, (loff_t)blocksize * block_no);
return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
@ -305,9 +301,9 @@ static int nandmtd1_TestPrerequists(struct mtd_info *mtd)
int oobavail = mtd->ecclayout->oobavail;
if (oobavail < YTAG1_SIZE) {
yaffs_trace(YAFFS_TRACE_ERROR,
"mtd device has only %d bytes for tags, need %d\n",
oobavail, YTAG1_SIZE);
T(YAFFS_TRACE_ERROR,
(TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR),
oobavail, YTAG1_SIZE));
return YAFFS_FAIL;
}
return YAFFS_OK;
@ -322,13 +318,13 @@ static int nandmtd1_TestPrerequists(struct mtd_info *mtd)
*
* Always returns YAFFS_OK.
*/
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState *pState, __u32 *pSequenceNumber)
int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
yaffs_block_state_t *pState, __u32 *pSequenceNumber)
{
struct mtd_info *mtd = dev->genericDevice;
int chunkNo = blockNo * dev->nChunksPerBlock;
loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
yaffs_ExtendedTags etags;
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int chunkNo = block_no * dev->param.chunks_per_block;
loff_t addr = (loff_t)chunkNo * dev->data_bytes_per_chunk;
yaffs_ext_tags etags;
int state = YAFFS_BLOCK_STATE_DEAD;
int seqnum = 0;
int retval;
@ -340,17 +336,17 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
return YAFFS_FAIL;
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
etags.blockBad = (mtd->block_isbad)(mtd, addr);
if (etags.blockBad) {
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
"block %d is marked bad\n", blockNo);
etags.block_bad = (mtd->block_isbad)(mtd, addr);
if (etags.block_bad) {
T(YAFFS_TRACE_BAD_BLOCKS,
(TSTR("block %d is marked bad"TENDSTR), block_no));
state = YAFFS_BLOCK_STATE_DEAD;
} else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
} else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
/* bad tags, need to look more closely */
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
} else if (etags.chunkUsed) {
} else if (etags.chunk_used) {
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
seqnum = etags.sequenceNumber;
seqnum = etags.seq_number;
} else {
state = YAFFS_BLOCK_STATE_EMPTY;
}

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
@ -14,15 +14,15 @@
#ifndef __YAFFS_MTDIF1_H__
#define __YAFFS_MTDIF1_H__
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
const __u8 *data, const yaffs_ExtendedTags *tags);
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
const __u8 *data, const yaffs_ext_tags *tags);
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
__u8 *data, yaffs_ExtendedTags *tags);
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
__u8 *data, yaffs_ext_tags *tags);
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandmtd1_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState *state, __u32 *sequenceNumber);
int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
yaffs_block_state_t *state, __u32 *seq_number);
#endif

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -13,11 +13,8 @@
/* mtd interface for YAFFS2 */
const char *yaffs_mtdif2_c_version =
"$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $";
#include "yportenv.h"
#include "yaffs_trace.h"
#include "yaffs_mtdif2.h"
@ -27,15 +24,17 @@ const char *yaffs_mtdif2_c_version =
#include "yaffs_packedtags2.h"
#include "yaffs_linux.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 nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
const __u8 *data,
const yaffs_ExtendedTags *tags)
const yaffs_ext_tags *tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
struct mtd_oob_ops ops;
#else
@ -47,13 +46,16 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
yaffs_PackedTags2 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;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
TENDSTR), nand_chunk, data, tags));
addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
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
@ -61,30 +63,30 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
*/
if (!data || !tags)
BUG();
else if (dev->inbandTags) {
else if (dev->param.inband_tags) {
yaffs_PackedTags2TagsPart *pt2tp;
pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->data_bytes_per_chunk);
yaffs_PackTags2TagsPart(pt2tp, tags);
} else
yaffs_PackTags2(&pt, tags);
yaffs_PackTags2(&pt, tags, !dev->param.no_tags_ecc);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
ops.mode = MTD_OOB_AUTO;
ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
ops.len = dev->totalBytesPerChunk;
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->inbandTags) ? NULL : (void *)&pt;
ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
retval = mtd->write_oob(mtd, addr, &ops);
#else
if (!dev->inbandTags) {
if (!dev->param.inband_tags) {
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) &pt, NULL);
mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
&dummy, data, (__u8 *) packed_tags_ptr, NULL);
} else {
retval =
mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
mtd->write(mtd, addr, dev->param.total_bytes_per_chunk, &dummy,
data);
}
#endif
@ -95,10 +97,10 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
return YAFFS_FAIL;
}
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
__u8 *data, yaffs_ExtendedTags *tags)
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
__u8 *data, yaffs_ext_tags *tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
struct mtd_oob_ops ops;
#endif
@ -106,20 +108,23 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
int retval = 0;
int localData = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
yaffs_PackedTags2 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;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
TENDSTR), nand_chunk, data, tags));
if (dev->inbandTags) {
if (dev->param.inband_tags) {
if (!data) {
localData = 1;
data = yaffs_GetTempBuffer(dev, __LINE__);
data = yaffs_get_temp_buffer(dev, __LINE__);
}
@ -127,30 +132,30 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
if (dev->inbandTags || (data && !tags))
retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
if (dev->param.inband_tags || (data && !tags))
retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
&dummy, data);
else if (tags) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = sizeof(pt);
ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
ops.ooblen = packed_tags_size;
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
ops.ooboffs = 0;
ops.datbuf = data;
ops.oobbuf = dev->spareBuffer;
ops.oobbuf = yaffs_dev_to_lc(dev)->spareBuffer;
retval = mtd->read_oob(mtd, addr, &ops);
}
#else
if (!dev->inbandTags && data && tags) {
if (!dev->param.inband_tags && data && tags) {
retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
retval = mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk,
&dummy, data, dev->spareBuffer,
NULL);
} else {
if (data)
retval =
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
mtd->read(mtd, addr, dev->data_bytes_per_chunk, &dummy,
data);
if (!dev->inbandTags && tags)
if (!dev->param.inband_tags && tags)
retval =
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
dev->spareBuffer);
@ -158,41 +163,47 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
#endif
if (dev->inbandTags) {
if (dev->param.inband_tags) {
if (tags) {
yaffs_PackedTags2TagsPart *pt2tp;
pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
yaffs_UnpackTags2TagsPart(tags, pt2tp);
pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->data_bytes_per_chunk];
yaffs_unpack_tags2tags_part(tags, pt2tp);
}
} else {
if (tags) {
memcpy(&pt, dev->spareBuffer, sizeof(pt));
yaffs_UnpackTags2(tags, &pt);
memcpy(packed_tags_ptr, yaffs_dev_to_lc(dev)->spareBuffer, packed_tags_size);
yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
}
}
if (localData)
yaffs_ReleaseTempBuffer(dev, data, __LINE__);
yaffs_release_temp_buffer(dev, data, __LINE__);
if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
if (tags && retval == -EBADMSG && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
dev->n_ecc_unfixed++;
}
if(tags && retval == -EUCLEAN && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
dev->n_ecc_fixed++;
}
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), block_no));
retval =
mtd->block_markbad(mtd,
blockNo * dev->nChunksPerBlock *
dev->totalBytesPerChunk);
block_no * dev->param.chunks_per_block *
dev->param.total_bytes_per_chunk);
if (retval == 0)
return YAFFS_OK;
@ -201,41 +212,41 @@ int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
}
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState *state, __u32 *sequenceNumber)
int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
yaffs_block_state_t *state, __u32 *seq_number)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), block_no));
retval =
mtd->block_isbad(mtd,
blockNo * dev->nChunksPerBlock *
dev->totalBytesPerChunk);
block_no * dev->param.chunks_per_block *
dev->param.total_bytes_per_chunk);
if (retval) {
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
*state = YAFFS_BLOCK_STATE_DEAD;
*sequenceNumber = 0;
*seq_number = 0;
} else {
yaffs_ExtendedTags t;
yaffs_ext_tags t;
nandmtd2_ReadChunkWithTagsFromNAND(dev,
blockNo *
dev->nChunksPerBlock, NULL,
block_no *
dev->param.chunks_per_block, NULL,
&t);
if (t.chunkUsed) {
*sequenceNumber = t.sequenceNumber;
if (t.chunk_used) {
*seq_number = t.seq_number;
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
} else {
*sequenceNumber = 0;
*seq_number = 0;
*state = YAFFS_BLOCK_STATE_EMPTY;
}
}
T(YAFFS_TRACE_MTD,
(TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
(TSTR("block is bad seq %d state %d" TENDSTR), *seq_number,
*state));
if (retval == 0)

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -17,13 +17,13 @@
#define __YAFFS_MTDIF2_H__
#include "yaffs_guts.h"
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
const __u8 *data,
const yaffs_ExtendedTags *tags);
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
__u8 *data, yaffs_ExtendedTags *tags);
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState *state, __u32 *sequenceNumber);
const yaffs_ext_tags *tags);
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
__u8 *data, yaffs_ext_tags *tags);
int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
yaffs_block_state_t *state, __u32 *seq_number);
#endif

View file

@ -0,0 +1,197 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 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.
* 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) == 0){
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 -1;
}
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){
/* 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;
} else
return -ENODATA;
}
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(size <= bsize){
memcpy(buf,xb + pos,size);
return size;
}
}
if(pos >= 0)
return -ERANGE;
else
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

@ -0,0 +1,25 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 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,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -11,124 +11,129 @@
* published by the Free Software Foundation.
*/
const char *yaffs_nand_c_version =
"$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $";
#include "yaffs_nand.h"
#include "yaffs_tagscompat.h"
#include "yaffs_tagsvalidity.h"
#include "yaffs_getblockinfo.h"
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
int yaffs_rd_chunk_tags_nand(yaffs_dev_t *dev, int nand_chunk,
__u8 *buffer,
yaffs_ExtendedTags *tags)
yaffs_ext_tags *tags)
{
int result;
yaffs_ExtendedTags localTags;
yaffs_ext_tags localTags;
int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
int realignedChunkInNAND = nand_chunk - dev->chunk_offset;
dev->n_page_reads++;
/* If there are no tags provided, use local tags to get prioritised gc working */
if (!tags)
tags = &localTags;
if (dev->readChunkWithTagsFromNAND)
result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
if (dev->param.read_chunk_tags_fn)
result = dev->param.read_chunk_tags_fn(dev, realignedChunkInNAND, buffer,
tags);
else
result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
result = yaffs_tags_compat_rd(dev,
realignedChunkInNAND,
buffer,
tags);
if (tags &&
tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) {
tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
yaffs_HandleChunkError(dev, bi);
yaffs_block_info_t *bi;
bi = yaffs_get_block_info(dev, nand_chunk/dev->param.chunks_per_block);
yaffs_handle_chunk_error(dev, bi);
}
return result;
}
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
int chunkInNAND,
int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev,
int nand_chunk,
const __u8 *buffer,
yaffs_ExtendedTags *tags)
yaffs_ext_tags *tags)
{
chunkInNAND -= dev->chunkOffset;
dev->n_page_writes++;
nand_chunk -= dev->chunk_offset;
if (tags) {
tags->sequenceNumber = dev->sequenceNumber;
tags->chunkUsed = 1;
if (!yaffs_ValidateTags(tags)) {
tags->seq_number = dev->seq_number;
tags->chunk_used = 1;
if (!yaffs_validate_tags(tags)) {
T(YAFFS_TRACE_ERROR,
(TSTR("Writing uninitialised tags" TENDSTR)));
YBUG();
}
T(YAFFS_TRACE_WRITE,
(TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
tags->objectId, tags->chunkId));
(TSTR("Writing chunk %d tags %d %d" TENDSTR), nand_chunk,
tags->obj_id, tags->chunk_id));
} else {
T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
YBUG();
}
if (dev->writeChunkWithTagsToNAND)
return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
if (dev->param.write_chunk_tags_fn)
return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer,
tags);
else
return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
chunkInNAND,
return yaffs_tags_compat_wr(dev,
nand_chunk,
buffer,
tags);
}
int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
int yaffs_mark_bad(yaffs_dev_t *dev, int block_no)
{
blockNo -= dev->blockOffset;
block_no -= dev->block_offset;
;
if (dev->markNANDBlockBad)
return dev->markNANDBlockBad(dev, blockNo);
if (dev->param.bad_block_fn)
return dev->param.bad_block_fn(dev, block_no);
else
return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
return yaffs_tags_compat_mark_bad(dev, block_no);
}
int yaffs_QueryInitialBlockState(yaffs_Device *dev,
int blockNo,
yaffs_BlockState *state,
__u32 *sequenceNumber)
int yaffs_query_init_block_state(yaffs_dev_t *dev,
int block_no,
yaffs_block_state_t *state,
__u32 *seq_number)
{
blockNo -= dev->blockOffset;
block_no -= dev->block_offset;
if (dev->queryNANDBlock)
return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
if (dev->param.query_block_fn)
return dev->param.query_block_fn(dev, block_no, state, seq_number);
else
return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
return yaffs_tags_compat_query_block(dev, block_no,
state,
sequenceNumber);
seq_number);
}
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND)
int yaffs_erase_block(struct yaffs_dev_s *dev,
int flash_block)
{
int result;
blockInNAND -= dev->blockOffset;
flash_block -= dev->block_offset;
dev->n_erasures++;
dev->nBlockErasures++;
result = dev->eraseBlockInNAND(dev, blockInNAND);
result = dev->param.erase_fn(dev, flash_block);
return result;
}
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
int yaffs_init_nand(struct yaffs_dev_s *dev)
{
return dev->initialiseNAND(dev);
if(dev->param.initialise_flash_fn)
return dev->param.initialise_flash_fn(dev);
return YAFFS_OK;
}

View file

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

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -20,18 +20,18 @@
#include "yaffs_guts.h"
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, const __u8 *data,
const yaffs_ExtendedTags *tags);
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, __u8 *data,
yaffs_ExtendedTags *tags);
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState *state, __u32 *sequenceNumber);
int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND);
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_dev_s *dev,
int nand_chunk, const __u8 *data,
const yaffs_ext_tags *tags);
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_dev_s *dev,
int nand_chunk, __u8 *data,
yaffs_ext_tags *tags);
int nandemul2k_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
int nandemul2k_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
yaffs_block_state_t *state, __u32 *seq_number);
int nandemul2k_EraseBlockInNAND(struct yaffs_dev_s *dev,
int flash_block);
int nandemul2k_InitialiseNAND(struct yaffs_dev_s *dev);
int nandemul2k_GetBytesPerChunk(void);
int nandemul2k_GetChunksPerBlock(void);
int nandemul2k_GetNumberOfBlocks(void);

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -14,37 +14,37 @@
#include "yaffs_packedtags1.h"
#include "yportenv.h"
void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t)
void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t)
{
pt->chunkId = t->chunkId;
pt->serialNumber = t->serialNumber;
pt->byteCount = t->byteCount;
pt->objectId = t->objectId;
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->chunkDeleted) ? 0 : 1;
pt->deleted = (t->is_deleted) ? 0 : 1;
pt->unusedStuff = 0;
pt->shouldBeFF = 0xFFFFFFFF;
}
void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt)
void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt)
{
static const __u8 allFF[] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff };
if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
t->blockBad = 0;
t->block_bad = 0;
if (pt->shouldBeFF != 0xFFFFFFFF)
t->blockBad = 1;
t->chunkUsed = 1;
t->objectId = pt->objectId;
t->chunkId = pt->chunkId;
t->byteCount = pt->byteCount;
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
t->chunkDeleted = (pt->deleted) ? 0 : 1;
t->serialNumber = pt->serialNumber;
t->block_bad = 1;
t->chunk_used = 1;
t->obj_id = pt->obj_id;
t->chunk_id = pt->chunk_id;
t->n_bytes = pt->n_bytes;
t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
t->is_deleted = (pt->deleted) ? 0 : 1;
t->serial_number = pt->serial_number;
} else {
memset(t, 0, sizeof(yaffs_ExtendedTags));
memset(t, 0, sizeof(yaffs_ext_tags));
}
}

View file

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

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -13,6 +13,7 @@
#include "yaffs_packedtags2.h"
#include "yportenv.h"
#include "yaffs_trace.h"
#include "yaffs_tagsvalidity.h"
/* This code packs a set of extended tags into a binary structure for
@ -24,7 +25,7 @@
* This is defined by having the EXTRA_HEADER_INFO_FLAG set.
*/
/* Extra flags applied to chunkId */
/* Extra flags applied to chunk_id */
#define EXTRA_HEADER_INFO_FLAG 0x80000000
#define EXTRA_SHRINK_FLAG 0x40000000
@ -42,53 +43,53 @@ static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt)
{
T(YAFFS_TRACE_MTD,
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
ptt->objectId, ptt->chunkId, ptt->byteCount,
ptt->sequenceNumber));
ptt->obj_id, ptt->chunk_id, ptt->n_bytes,
ptt->seq_number));
}
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
{
yaffs_DumpPackedTags2TagsPart(&pt->t);
}
static void yaffs_DumpTags2(const yaffs_ExtendedTags *t)
static void yaffs_DumpTags2(const yaffs_ext_tags *t)
{
T(YAFFS_TRACE_MTD,
(TSTR
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
t->sequenceNumber));
TENDSTR), t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
t->seq_number));
}
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt,
const yaffs_ExtendedTags *t)
const yaffs_ext_tags *t)
{
ptt->chunkId = t->chunkId;
ptt->sequenceNumber = t->sequenceNumber;
ptt->byteCount = t->byteCount;
ptt->objectId = t->objectId;
ptt->chunk_id = t->chunk_id;
ptt->seq_number = t->seq_number;
ptt->n_bytes = t->n_bytes;
ptt->obj_id = t->obj_id;
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
if (t->chunk_id == 0 && t->extra_available) {
/* Store the extra header info instead */
/* We save the parent object in the chunkId */
ptt->chunkId = EXTRA_HEADER_INFO_FLAG
| t->extraParentObjectId;
if (t->extraIsShrinkHeader)
ptt->chunkId |= EXTRA_SHRINK_FLAG;
if (t->extraShadows)
ptt->chunkId |= EXTRA_SHADOWS_FLAG;
/* We save the parent object in the chunk_id */
ptt->chunk_id = EXTRA_HEADER_INFO_FLAG
| t->extra_parent_id;
if (t->extra_is_shrink)
ptt->chunk_id |= EXTRA_SHRINK_FLAG;
if (t->extra_shadows)
ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
ptt->objectId |=
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
ptt->obj_id |=
(t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
ptt->byteCount = t->extraEquivalentObjectId;
else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE)
ptt->byteCount = t->extraFileLength;
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 = t->extra_length;
else
ptt->byteCount = 0;
ptt->n_bytes = 0;
}
yaffs_DumpPackedTags2TagsPart(ptt);
@ -96,59 +97,56 @@ void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt,
}
void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t)
void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC)
{
yaffs_PackTags2TagsPart(&pt->t, t);
#ifndef YAFFS_IGNORE_TAGS_ECC
{
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
if(tagsECC)
yaffs_ecc_calc_other((unsigned char *)&pt->t,
sizeof(yaffs_PackedTags2TagsPart),
&pt->ecc);
}
#endif
}
void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t,
void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t,
yaffs_PackedTags2TagsPart *ptt)
{
memset(t, 0, sizeof(yaffs_ExtendedTags));
memset(t, 0, sizeof(yaffs_ext_tags));
yaffs_InitialiseTags(t);
yaffs_init_tags(t);
if (ptt->sequenceNumber != 0xFFFFFFFF) {
t->blockBad = 0;
t->chunkUsed = 1;
t->objectId = ptt->objectId;
t->chunkId = ptt->chunkId;
t->byteCount = ptt->byteCount;
t->chunkDeleted = 0;
t->serialNumber = 0;
t->sequenceNumber = ptt->sequenceNumber;
if (ptt->seq_number != 0xFFFFFFFF) {
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->chunkId & EXTRA_HEADER_INFO_FLAG) {
t->chunkId = 0;
t->byteCount = 0;
if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
t->chunk_id = 0;
t->n_bytes = 0;
t->extraHeaderInfoAvailable = 1;
t->extraParentObjectId =
ptt->chunkId & (~(ALL_EXTRA_FLAGS));
t->extraIsShrinkHeader =
(ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
t->extraShadows =
(ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
t->extraObjectType =
ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT;
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
t->extra_available = 1;
t->extra_parent_id =
ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
t->extra_is_shrink =
(ptt->chunk_id & EXTRA_SHRINK_FLAG) ? 1 : 0;
t->extra_shadows =
(ptt->chunk_id & EXTRA_SHADOWS_FLAG) ? 1 : 0;
t->extra_obj_type =
ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
t->extraEquivalentObjectId = ptt->byteCount;
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
t->extra_equiv_id = ptt->n_bytes;
else
t->extraFileLength = ptt->byteCount;
t->extra_length = ptt->n_bytes;
}
}
@ -158,49 +156,43 @@ void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t,
}
void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)
void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC)
{
yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR;
yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
if (pt->t.sequenceNumber != 0xFFFFFFFF) {
/* Page is in use */
#ifndef YAFFS_IGNORE_TAGS_ECC
{
yaffs_ECCOther ecc;
int result;
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
sizeof
(yaffs_PackedTags2TagsPart),
&ecc);
result =
yaffs_ECCCorrectOther((unsigned char *)&pt->t,
sizeof
(yaffs_PackedTags2TagsPart),
&pt->ecc, &ecc);
switch (result) {
if (pt->t.seq_number != 0xFFFFFFFF &&
tagsECC){
/* Chunk is in use and we need to do ECC */
yaffs_ECCOther ecc;
int result;
yaffs_ecc_calc_other((unsigned char *)&pt->t,
sizeof(yaffs_PackedTags2TagsPart),
&ecc);
result = yaffs_ecc_correct_other((unsigned char *)&pt->t,
sizeof(yaffs_PackedTags2TagsPart),
&pt->ecc, &ecc);
switch (result) {
case 0:
eccResult = YAFFS_ECC_RESULT_NO_ERROR;
ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
break;
case 1:
eccResult = YAFFS_ECC_RESULT_FIXED;
ecc_result = YAFFS_ECC_RESULT_FIXED;
break;
case -1:
eccResult = YAFFS_ECC_RESULT_UNFIXED;
ecc_result = YAFFS_ECC_RESULT_UNFIXED;
break;
default:
eccResult = YAFFS_ECC_RESULT_UNKNOWN;
}
ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
}
#endif
}
yaffs_UnpackTags2TagsPart(t, &pt->t);
yaffs_unpack_tags2tags_part(t, &pt->t);
t->eccResult = eccResult;
t->ecc_result = ecc_result;
yaffs_DumpPackedTags2(pt);
yaffs_DumpTags2(t);
}

View file

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

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -17,7 +17,18 @@
#ifndef __YAFFS_QSORT_H__
#define __YAFFS_QSORT_H__
#ifdef __KERNEL__
#include <linux/sort.h>
extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
int (*cmp)(const void *, const void *)){
sort(base, total_elems, size, cmp, NULL);
}
#else
extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
int (*cmp)(const void *, const void *));
#endif
#endif

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -15,19 +15,20 @@
#include "yaffs_tagscompat.h"
#include "yaffs_ecc.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_trace.h"
static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND);
static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk);
#ifdef NOTYET
static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND);
static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
static void yaffs_check_written_block(yaffs_dev_t *dev, int nand_chunk);
static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
const __u8 *data,
const yaffs_Spare *spare);
static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
const yaffs_Spare *spare);
static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND);
const yaffs_spare *spare);
static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
const yaffs_spare *spare);
static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk);
#endif
static const char yaffs_countBitsTable[256] = {
static const char yaffs_count_bits_table[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
@ -46,26 +47,26 @@ static const char yaffs_countBitsTable[256] = {
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
int yaffs_CountBits(__u8 x)
int yaffs_count_bits(__u8 x)
{
int retVal;
retVal = yaffs_countBitsTable[x];
retVal = yaffs_count_bits_table[x];
return retVal;
}
/********** Tags ECC calculations *********/
void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
void yaffs_calc_ecc(const __u8 *data, yaffs_spare *spare)
{
yaffs_ECCCalculate(data, spare->ecc1);
yaffs_ECCCalculate(&data[256], spare->ecc2);
yaffs_ecc_cacl(data, spare->ecc1);
yaffs_ecc_cacl(&data[256], spare->ecc2);
}
void yaffs_CalcTagsECC(yaffs_Tags *tags)
void yaffs_calc_tags_ecc(yaffs_tags_t *tags)
{
/* Calculate an ecc */
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes;
unsigned i, j;
unsigned ecc = 0;
unsigned bit = 0;
@ -84,24 +85,24 @@ void yaffs_CalcTagsECC(yaffs_Tags *tags)
}
int yaffs_CheckECCOnTags(yaffs_Tags *tags)
int yaffs_check_tags_ecc(yaffs_tags_t *tags)
{
unsigned ecc = tags->ecc;
yaffs_CalcTagsECC(tags);
yaffs_calc_tags_ecc(tags);
ecc ^= tags->ecc;
if (ecc && ecc <= 64) {
/* TODO: Handle the failure better. Retire? */
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes;
ecc--;
b[ecc / 8] ^= (1 << (ecc & 7));
/* Now recvalc the ecc */
yaffs_CalcTagsECC(tags);
yaffs_calc_tags_ecc(tags);
return 1; /* recovered error */
} else if (ecc) {
@ -115,76 +116,73 @@ int yaffs_CheckECCOnTags(yaffs_Tags *tags)
/********** Tags **********/
static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr,
yaffs_Tags *tagsPtr)
static void yaffs_load_tags_to_spare(yaffs_spare *sparePtr,
yaffs_tags_t *tagsPtr)
{
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr;
yaffs_CalcTagsECC(tagsPtr);
yaffs_calc_tags_ecc(tagsPtr);
sparePtr->tagByte0 = tu->asBytes[0];
sparePtr->tagByte1 = tu->asBytes[1];
sparePtr->tagByte2 = tu->asBytes[2];
sparePtr->tagByte3 = tu->asBytes[3];
sparePtr->tagByte4 = tu->asBytes[4];
sparePtr->tagByte5 = tu->asBytes[5];
sparePtr->tagByte6 = tu->asBytes[6];
sparePtr->tagByte7 = tu->asBytes[7];
sparePtr->tb0 = tu->as_bytes[0];
sparePtr->tb1 = tu->as_bytes[1];
sparePtr->tb2 = tu->as_bytes[2];
sparePtr->tb3 = tu->as_bytes[3];
sparePtr->tb4 = tu->as_bytes[4];
sparePtr->tb5 = tu->as_bytes[5];
sparePtr->tb6 = tu->as_bytes[6];
sparePtr->tb7 = tu->as_bytes[7];
}
static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,
yaffs_Tags *tagsPtr)
static void yaffs_get_tags_from_spare(yaffs_dev_t *dev, yaffs_spare *sparePtr,
yaffs_tags_t *tagsPtr)
{
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr;
int result;
tu->asBytes[0] = sparePtr->tagByte0;
tu->asBytes[1] = sparePtr->tagByte1;
tu->asBytes[2] = sparePtr->tagByte2;
tu->asBytes[3] = sparePtr->tagByte3;
tu->asBytes[4] = sparePtr->tagByte4;
tu->asBytes[5] = sparePtr->tagByte5;
tu->asBytes[6] = sparePtr->tagByte6;
tu->asBytes[7] = sparePtr->tagByte7;
tu->as_bytes[0] = sparePtr->tb0;
tu->as_bytes[1] = sparePtr->tb1;
tu->as_bytes[2] = sparePtr->tb2;
tu->as_bytes[3] = sparePtr->tb3;
tu->as_bytes[4] = sparePtr->tb4;
tu->as_bytes[5] = sparePtr->tb5;
tu->as_bytes[6] = sparePtr->tb6;
tu->as_bytes[7] = sparePtr->tb7;
result = yaffs_CheckECCOnTags(tagsPtr);
result = yaffs_check_tags_ecc(tagsPtr);
if (result > 0)
dev->tagsEccFixed++;
dev->n_tags_ecc_fixed++;
else if (result < 0)
dev->tagsEccUnfixed++;
dev->n_tags_ecc_unfixed++;
}
static void yaffs_SpareInitialise(yaffs_Spare *spare)
static void yaffs_spare_init(yaffs_spare *spare)
{
memset(spare, 0xFF, sizeof(yaffs_Spare));
memset(spare, 0xFF, sizeof(yaffs_spare));
}
static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, const __u8 *data,
yaffs_Spare *spare)
static int yaffs_wr_nand(struct yaffs_dev_s *dev,
int nand_chunk, const __u8 *data,
yaffs_spare *spare)
{
if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
T(YAFFS_TRACE_ERROR,
(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
chunkInNAND));
nand_chunk));
return YAFFS_FAIL;
}
dev->nPageWrites++;
return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
}
static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND,
static int yaffs_rd_chunk_nand(struct yaffs_dev_s *dev,
int nand_chunk,
__u8 *data,
yaffs_Spare *spare,
yaffs_ECCResult *eccResult,
yaffs_spare *spare,
yaffs_ecc_result *ecc_result,
int doErrorCorrection)
{
int retVal;
yaffs_Spare localSpare;
dev->nPageReads++;
yaffs_spare localSpare;
if (!spare && data) {
/* If we don't have a real spare, then we use a local one. */
@ -192,107 +190,107 @@ static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
spare = &localSpare;
}
if (!dev->useNANDECC) {
retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
if (!dev->param.use_nand_ecc) {
retVal = dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
if (data && doErrorCorrection) {
/* Do ECC correction */
/* Todo handle any errors */
int eccResult1, eccResult2;
int ecc_result1, ecc_result2;
__u8 calcEcc[3];
yaffs_ECCCalculate(data, calcEcc);
eccResult1 =
yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
yaffs_ECCCalculate(&data[256], calcEcc);
eccResult2 =
yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
yaffs_ecc_cacl(data, calcEcc);
ecc_result1 =
yaffs_ecc_correct(data, spare->ecc1, calcEcc);
yaffs_ecc_cacl(&data[256], calcEcc);
ecc_result2 =
yaffs_ecc_correct(&data[256], spare->ecc2, calcEcc);
if (eccResult1 > 0) {
if (ecc_result1 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error fix performed on chunk %d:0"
TENDSTR), chunkInNAND));
dev->eccFixed++;
} else if (eccResult1 < 0) {
TENDSTR), nand_chunk));
dev->n_ecc_fixed++;
} else if (ecc_result1 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error unfixed on chunk %d:0"
TENDSTR), chunkInNAND));
dev->eccUnfixed++;
TENDSTR), nand_chunk));
dev->n_ecc_unfixed++;
}
if (eccResult2 > 0) {
if (ecc_result2 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error fix performed on chunk %d:1"
TENDSTR), chunkInNAND));
dev->eccFixed++;
} else if (eccResult2 < 0) {
TENDSTR), nand_chunk));
dev->n_ecc_fixed++;
} else if (ecc_result2 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error unfixed on chunk %d:1"
TENDSTR), chunkInNAND));
dev->eccUnfixed++;
TENDSTR), nand_chunk));
dev->n_ecc_unfixed++;
}
if (eccResult1 || eccResult2) {
if (ecc_result1 || ecc_result2) {
/* We had a data problem on this page */
yaffs_HandleReadDataError(dev, chunkInNAND);
yaffs_handle_rd_data_error(dev, nand_chunk);
}
if (eccResult1 < 0 || eccResult2 < 0)
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
else if (eccResult1 > 0 || eccResult2 > 0)
*eccResult = YAFFS_ECC_RESULT_FIXED;
if (ecc_result1 < 0 || ecc_result2 < 0)
*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
else if (ecc_result1 > 0 || ecc_result2 > 0)
*ecc_result = YAFFS_ECC_RESULT_FIXED;
else
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
}
} else {
/* Must allocate enough memory for spare+2*sizeof(int) */
/* for ecc results from device. */
struct yaffs_NANDSpare nspare;
struct yaffs_nand_spare nspare;
memset(&nspare, 0, sizeof(nspare));
retVal = dev->readChunkFromNAND(dev, chunkInNAND, data,
(yaffs_Spare *) &nspare);
memcpy(spare, &nspare, sizeof(yaffs_Spare));
retVal = dev->param.read_chunk_fn(dev, nand_chunk, data,
(yaffs_spare *) &nspare);
memcpy(spare, &nspare, sizeof(yaffs_spare));
if (data && doErrorCorrection) {
if (nspare.eccres1 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error fix performed on chunk %d:0"
TENDSTR), chunkInNAND));
TENDSTR), nand_chunk));
} else if (nspare.eccres1 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error unfixed on chunk %d:0"
TENDSTR), chunkInNAND));
TENDSTR), nand_chunk));
}
if (nspare.eccres2 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error fix performed on chunk %d:1"
TENDSTR), chunkInNAND));
TENDSTR), nand_chunk));
} else if (nspare.eccres2 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error unfixed on chunk %d:1"
TENDSTR), chunkInNAND));
TENDSTR), nand_chunk));
}
if (nspare.eccres1 || nspare.eccres2) {
/* We had a data problem on this page */
yaffs_HandleReadDataError(dev, chunkInNAND);
yaffs_handle_rd_data_error(dev, nand_chunk);
}
if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
*eccResult = YAFFS_ECC_RESULT_FIXED;
*ecc_result = YAFFS_ECC_RESULT_FIXED;
else
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
}
}
@ -300,17 +298,17 @@ static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
}
#ifdef NOTYET
static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
int chunkInNAND)
static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
int nand_chunk)
{
static int init;
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
static __u8 data[YAFFS_BYTES_PER_CHUNK];
/* Might as well always allocate the larger size for */
/* dev->useNANDECC == true; */
static __u8 spare[sizeof(struct yaffs_NANDSpare)];
/* dev->param.use_nand_ecc == true; */
static __u8 spare[sizeof(struct yaffs_nand_spare)];
dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
dev->param.read_chunk_fn(dev, nand_chunk, data, (yaffs_spare *) spare);
if (!init) {
memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
@ -331,14 +329,14 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
* Functions for robustisizing
*/
static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk)
{
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
int flash_block = nand_chunk / dev->param.chunks_per_block;
/* Mark the block for retirement */
yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1;
yaffs_get_block_info(dev, flash_block + dev->block_offset)->needs_retiring = 1;
T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
(TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
(TSTR("**>>Block %d marked for retirement" TENDSTR), flash_block));
/* TODO:
* Just do a garbage collection on the affected block
@ -348,44 +346,44 @@ static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
}
#ifdef NOTYET
static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND)
static void yaffs_check_written_block(yaffs_dev_t *dev, int nand_chunk)
{
}
static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
const __u8 *data,
const yaffs_Spare *spare)
const yaffs_spare *spare)
{
}
static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
const yaffs_Spare *spare)
static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
const yaffs_spare *spare)
{
}
static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND)
static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk)
{
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
int flash_block = nand_chunk / dev->param.chunks_per_block;
/* Mark the block for retirement */
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
yaffs_get_block_info(dev, flash_block)->needs_retiring = 1;
/* Delete the chunk */
yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
}
static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1,
const yaffs_Spare *s0, const yaffs_Spare *s1)
static int yaffs_verify_cmp(const __u8 *d0, const __u8 *d1,
const yaffs_spare *s0, const yaffs_spare *s1)
{
if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
s0->tagByte0 != s1->tagByte0 ||
s0->tagByte1 != s1->tagByte1 ||
s0->tagByte2 != s1->tagByte2 ||
s0->tagByte3 != s1->tagByte3 ||
s0->tagByte4 != s1->tagByte4 ||
s0->tagByte5 != s1->tagByte5 ||
s0->tagByte6 != s1->tagByte6 ||
s0->tagByte7 != s1->tagByte7 ||
s0->tb0 != s1->tb0 ||
s0->tb1 != s1->tb1 ||
s0->tb2 != s1->tb2 ||
s0->tb3 != s1->tb3 ||
s0->tb4 != s1->tb4 ||
s0->tb5 != s1->tb5 ||
s0->tb6 != s1->tb6 ||
s0->tb7 != s1->tb7 ||
s0->ecc1[0] != s1->ecc1[0] ||
s0->ecc1[1] != s1->ecc1[1] ||
s0->ecc1[2] != s1->ecc1[2] ||
@ -398,53 +396,53 @@ static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1,
}
#endif /* NOTYET */
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
int chunkInNAND,
int yaffs_tags_compat_wr(yaffs_dev_t *dev,
int nand_chunk,
const __u8 *data,
const yaffs_ExtendedTags *eTags)
const yaffs_ext_tags *eTags)
{
yaffs_Spare spare;
yaffs_Tags tags;
yaffs_spare spare;
yaffs_tags_t tags;
yaffs_SpareInitialise(&spare);
yaffs_spare_init(&spare);
if (eTags->chunkDeleted)
spare.pageStatus = 0;
if (eTags->is_deleted)
spare.page_status = 0;
else {
tags.objectId = eTags->objectId;
tags.chunkId = eTags->chunkId;
tags.obj_id = eTags->obj_id;
tags.chunk_id = eTags->chunk_id;
tags.byteCountLSB = eTags->byteCount & 0x3ff;
tags.n_bytes_lsb = eTags->n_bytes & 0x3ff;
if (dev->nDataBytesPerChunk >= 1024)
tags.byteCountMSB = (eTags->byteCount >> 10) & 3;
if (dev->data_bytes_per_chunk >= 1024)
tags.n_bytes_msb = (eTags->n_bytes >> 10) & 3;
else
tags.byteCountMSB = 3;
tags.n_bytes_msb = 3;
tags.serialNumber = eTags->serialNumber;
tags.serial_number = eTags->serial_number;
if (!dev->useNANDECC && data)
yaffs_CalcECC(data, &spare);
if (!dev->param.use_nand_ecc && data)
yaffs_calc_ecc(data, &spare);
yaffs_LoadTagsIntoSpare(&spare, &tags);
yaffs_load_tags_to_spare(&spare, &tags);
}
return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
return yaffs_wr_nand(dev, nand_chunk, data, &spare);
}
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
int chunkInNAND,
int yaffs_tags_compat_rd(yaffs_dev_t *dev,
int nand_chunk,
__u8 *data,
yaffs_ExtendedTags *eTags)
yaffs_ext_tags *eTags)
{
yaffs_Spare spare;
yaffs_Tags tags;
yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN;
yaffs_spare spare;
yaffs_tags_t tags;
yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
static yaffs_Spare spareFF;
static yaffs_spare spareFF;
static int init;
if (!init) {
@ -452,33 +450,33 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
init = 1;
}
if (yaffs_ReadChunkFromNAND
(dev, chunkInNAND, data, &spare, &eccResult, 1)) {
if (yaffs_rd_chunk_nand
(dev, nand_chunk, data, &spare, &ecc_result, 1)) {
/* eTags may be NULL */
if (eTags) {
int deleted =
(yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
(yaffs_count_bits(spare.page_status) < 7) ? 1 : 0;
eTags->chunkDeleted = deleted;
eTags->eccResult = eccResult;
eTags->blockBad = 0; /* We're reading it */
eTags->is_deleted = deleted;
eTags->ecc_result = ecc_result;
eTags->block_bad = 0; /* We're reading it */
/* therefore it is not a bad block */
eTags->chunkUsed =
eTags->chunk_used =
(memcmp(&spareFF, &spare, sizeof(spareFF)) !=
0) ? 1 : 0;
if (eTags->chunkUsed) {
yaffs_GetTagsFromSpare(dev, &spare, &tags);
if (eTags->chunk_used) {
yaffs_get_tags_from_spare(dev, &spare, &tags);
eTags->objectId = tags.objectId;
eTags->chunkId = tags.chunkId;
eTags->byteCount = tags.byteCountLSB;
eTags->obj_id = tags.obj_id;
eTags->chunk_id = tags.chunk_id;
eTags->n_bytes = tags.n_bytes_lsb;
if (dev->nDataBytesPerChunk >= 1024)
eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10);
if (dev->data_bytes_per_chunk >= 1024)
eTags->n_bytes |= (((unsigned) tags.n_bytes_msb) << 10);
eTags->serialNumber = tags.serialNumber;
eTags->serial_number = tags.serial_number;
}
}
@ -488,49 +486,49 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
}
}
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int blockInNAND)
int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev,
int flash_block)
{
yaffs_Spare spare;
yaffs_spare spare;
memset(&spare, 0xff, sizeof(yaffs_Spare));
memset(&spare, 0xff, sizeof(yaffs_spare));
spare.blockStatus = 'Y';
spare.block_status = 'Y';
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
&spare);
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
NULL, &spare);
return YAFFS_OK;
}
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo,
yaffs_BlockState *state,
__u32 *sequenceNumber)
int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev,
int block_no,
yaffs_block_state_t *state,
__u32 *seq_number)
{
yaffs_Spare spare0, spare1;
static yaffs_Spare spareFF;
yaffs_spare spare0, spare1;
static yaffs_spare spareFF;
static int init;
yaffs_ECCResult dummy;
yaffs_ecc_result dummy;
if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF));
init = 1;
}
*sequenceNumber = 0;
*seq_number = 0;
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL,
&spare0, &dummy, 1);
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, NULL,
&spare1, &dummy, 1);
if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
if (yaffs_count_bits(spare0.block_status & spare1.block_status) < 7)
*state = YAFFS_BLOCK_STATE_DEAD;
else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
*state = YAFFS_BLOCK_STATE_EMPTY;

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -17,23 +17,23 @@
#define __YAFFS_TAGSCOMPAT_H__
#include "yaffs_guts.h"
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
int chunkInNAND,
int yaffs_tags_compat_wr(yaffs_dev_t *dev,
int nand_chunk,
const __u8 *data,
const yaffs_ExtendedTags *tags);
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
int chunkInNAND,
const yaffs_ext_tags *tags);
int yaffs_tags_compat_rd(yaffs_dev_t *dev,
int nand_chunk,
__u8 *data,
yaffs_ExtendedTags *tags);
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int blockNo);
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo,
yaffs_BlockState *state,
__u32 *sequenceNumber);
yaffs_ext_tags *tags);
int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev,
int block_no);
int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev,
int block_no,
yaffs_block_state_t *state,
__u32 *seq_number);
void yaffs_CalcTagsECC(yaffs_Tags *tags);
int yaffs_CheckECCOnTags(yaffs_Tags *tags);
int yaffs_CountBits(__u8 byte);
void yaffs_calc_tags_ecc(yaffs_tags_t *tags);
int yaffs_check_tags_ecc(yaffs_tags_t *tags);
int yaffs_count_bits(__u8 byte);
#endif

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -13,16 +13,16 @@
#include "yaffs_tagsvalidity.h"
void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
void yaffs_init_tags(yaffs_ext_tags *tags)
{
memset(tags, 0, sizeof(yaffs_ExtendedTags));
tags->validMarker0 = 0xAAAAAAAA;
tags->validMarker1 = 0x55555555;
memset(tags, 0, sizeof(yaffs_ext_tags));
tags->validity1 = 0xAAAAAAAA;
tags->validty1 = 0x55555555;
}
int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
int yaffs_validate_tags(yaffs_ext_tags *tags)
{
return (tags->validMarker0 == 0xAAAAAAAA &&
tags->validMarker1 == 0x55555555);
return (tags->validity1 == 0xAAAAAAAA &&
tags->validty1 == 0x55555555);
}

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -19,6 +19,6 @@
#include "yaffs_guts.h"
void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
int yaffs_ValidateTags(yaffs_ExtendedTags *tags);
void yaffs_init_tags(yaffs_ext_tags *tags);
int yaffs_validate_tags(yaffs_ext_tags *tags);
#endif

View file

@ -0,0 +1,60 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 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_ERROR 0x40000000
#define YAFFS_TRACE_BUG 0x80000000
#define YAFFS_TRACE_ALWAYS 0xF0000000
#define T(mask, p) do { if ((mask) & (yaffs_trace_mask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
#endif

View file

@ -0,0 +1,626 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 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(yaffs_dev_t *dev)
{
dev=dev;
return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
}
static int yaffs_skip_full_verification(yaffs_dev_t *dev)
{
dev=dev;
return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
}
static int yaffs_skip_nand_verification(yaffs_dev_t *dev)
{
dev=dev;
return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
}
static const char *block_stateName[] = {
"Unknown",
"Needs scanning",
"Scanning",
"Empty",
"Allocating",
"Full",
"Dirty",
"Checkpoint",
"Collecting",
"Dead"
};
void yaffs_verify_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n)
{
int actuallyUsed;
int inUse;
if (yaffs_skip_verification(dev))
return;
/* Report illegal runtime states */
if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->block_state));
switch (bi->block_state) {
case YAFFS_BLOCK_STATE_UNKNOWN:
case YAFFS_BLOCK_STATE_SCANNING:
case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
n, block_stateName[bi->block_state]));
}
/* Check pages in use and soft deletions are legal */
actuallyUsed = 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 ||
actuallyUsed < 0 || actuallyUsed > dev->param.chunks_per_block)
T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pages_in_used %d soft_del_pages %d"TENDSTR),
n, bi->pages_in_use, bi->soft_del_pages));
/* Check chunk bitmap legal */
inUse = yaffs_count_chunk_bits(dev, n);
if (inUse != bi->pages_in_use)
T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pages_in_use %d counted chunk bits %d"TENDSTR),
n, bi->pages_in_use, inUse));
}
void yaffs_verify_collected_blk(yaffs_dev_t *dev, yaffs_block_info_t *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) {
T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
n, bi->block_state));
}
}
void yaffs_verify_blocks(yaffs_dev_t *dev)
{
int i;
int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
int nIllegalBlockStates = 0;
if (yaffs_skip_verification(dev))
return;
memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
yaffs_verify_blk(dev, bi, i);
if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
nBlocksPerState[bi->block_state]++;
else
nIllegalBlockStates++;
}
T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
T(YAFFS_TRACE_VERIFY,
(TSTR("%s %d blocks"TENDSTR),
block_stateName[i], nBlocksPerState[i]));
if (dev->blocks_in_checkpt != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
T(YAFFS_TRACE_VERIFY,
(TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
dev->blocks_in_checkpt, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
if (dev->n_erased_blocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
T(YAFFS_TRACE_VERIFY,
(TSTR("Erased block count wrong dev %d count %d"TENDSTR),
dev->n_erased_blocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
T(YAFFS_TRACE_VERIFY,
(TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
}
/*
* 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(yaffs_obj_t *obj, yaffs_obj_header *oh, yaffs_ext_tags *tags, int parentCheck)
{
if (obj && yaffs_skip_verification(obj->my_dev))
return;
if (!(tags && obj && oh)) {
T(YAFFS_TRACE_VERIFY,
(TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
tags, obj, oh));
return;
}
if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
oh->type > YAFFS_OBJECT_TYPE_MAX)
T(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
tags->obj_id, oh->type));
if (tags->obj_id != obj->obj_id)
T(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d header mismatch obj_id %d"TENDSTR),
tags->obj_id, obj->obj_id));
/*
* Check that the object's parent ids match if parentCheck requested.
*
* Tests do not apply to the root object.
*/
if (parentCheck && tags->obj_id > 1 && !obj->parent)
T(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d header mismatch parent_id %d obj->parent is NULL"TENDSTR),
tags->obj_id, oh->parent_obj_id));
if (parentCheck && obj->parent &&
oh->parent_obj_id != obj->parent->obj_id &&
(oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
T(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d header mismatch parent_id %d parent_obj_id %d"TENDSTR),
tags->obj_id, oh->parent_obj_id, obj->parent->obj_id));
if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
T(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d header name is NULL"TENDSTR),
obj->obj_id));
if (tags->obj_id > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
T(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d header name is 0xFF"TENDSTR),
obj->obj_id));
}
#if 0
/* Not being used, but don't want to throw away yet */
int yaffs_verify_tnode_worker(yaffs_obj_t *obj, yaffs_tnode_t *tn,
__u32 level, int chunk_offset)
{
int i;
yaffs_dev_t *dev = obj->my_dev;
int ok = 1;
if (tn) {
if (level > 0) {
for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
if (tn->internal[i]) {
ok = yaffs_verify_tnode_worker(obj,
tn->internal[i],
level - 1,
(chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i);
}
}
} else if (level == 0) {
yaffs_ext_tags tags;
__u32 obj_id = obj->obj_id;
chunk_offset <<= YAFFS_TNODES_LEVEL0_BITS;
for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
__u32 theChunk = yaffs_get_group_base(dev, tn, i);
if (theChunk > 0) {
/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.obj_id,tags.chunk_id,theChunk)); */
yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags);
if (tags.obj_id != obj_id || tags.chunk_id != chunk_offset) {
T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
obj_id, chunk_offset, theChunk,
tags.obj_id, tags.chunk_id));
}
}
chunk_offset++;
}
}
}
return ok;
}
#endif
void yaffs_verify_file(yaffs_obj_t *obj)
{
int requiredTallness;
int actualTallness;
__u32 lastChunk;
__u32 x;
__u32 i;
yaffs_dev_t *dev;
yaffs_ext_tags tags;
yaffs_tnode_t *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 */
lastChunk = obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1;
x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
requiredTallness = 0;
while (x > 0) {
x >>= YAFFS_TNODES_INTERNAL_BITS;
requiredTallness++;
}
actualTallness = obj->variant.file_variant.top_level;
/* Check that the chunks in the tnode tree are all correct.
* We do this by scanning through the tnode tree and
* checking the tags for every chunk match.
*/
if (yaffs_skip_nand_verification(dev))
return;
for (i = 1; i <= lastChunk; i++) {
tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
if (tn) {
__u32 theChunk = yaffs_get_group_base(dev, tn, i);
if (theChunk > 0) {
/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),obj_id,i,theChunk)); */
yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags);
if (tags.obj_id != obj_id || tags.chunk_id != i) {
T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
obj_id, i, theChunk,
tags.obj_id, tags.chunk_id));
}
}
}
}
}
void yaffs_verify_link(yaffs_obj_t *obj)
{
if (obj && yaffs_skip_verification(obj->my_dev))
return;
/* Verify sane equivalent object */
}
void yaffs_verify_symlink(yaffs_obj_t *obj)
{
if (obj && yaffs_skip_verification(obj->my_dev))
return;
/* Verify symlink string */
}
void yaffs_verify_special(yaffs_obj_t *obj)
{
if (obj && yaffs_skip_verification(obj->my_dev))
return;
}
void yaffs_verify_obj(yaffs_obj_t *obj)
{
yaffs_dev_t *dev;
__u32 chunkMin;
__u32 chunkMax;
__u32 chunk_idOk;
__u32 chunkInRange;
__u32 chunkShouldNotBeDeleted;
__u32 chunkValid;
if (!obj)
return;
if (obj->being_created)
return;
dev = obj->my_dev;
if (yaffs_skip_verification(dev))
return;
/* Check sane object header chunk */
chunkMin = dev->internal_start_block * dev->param.chunks_per_block;
chunkMax = (dev->internal_end_block+1) * dev->param.chunks_per_block - 1;
chunkInRange = (((unsigned)(obj->hdr_chunk)) >= chunkMin && ((unsigned)(obj->hdr_chunk)) <= chunkMax);
chunk_idOk = chunkInRange || (obj->hdr_chunk == 0);
chunkValid = chunkInRange &&
yaffs_check_chunk_bit(dev,
obj->hdr_chunk / dev->param.chunks_per_block,
obj->hdr_chunk % dev->param.chunks_per_block);
chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
if (!obj->fake &&
(!chunk_idOk || chunkShouldNotBeDeleted)) {
T(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d has chunk_id %d %s %s"TENDSTR),
obj->obj_id, obj->hdr_chunk,
chunk_idOk ? "" : ",out of range",
chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
}
if (chunkValid && !yaffs_skip_nand_verification(dev)) {
yaffs_ext_tags tags;
yaffs_obj_header *oh;
__u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
oh = (yaffs_obj_header *)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, __LINE__);
}
/* Verify it has a parent */
if (obj && !obj->fake &&
(!obj->parent || obj->parent->my_dev != dev)) {
T(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
obj->obj_id, obj->parent));
}
/* Verify parent is a directory */
if (obj->parent && obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
T(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
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:
T(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d has illegaltype %d"TENDSTR),
obj->obj_id, obj->variant_type));
break;
}
}
void yaffs_verify_objects(yaffs_dev_t *dev)
{
yaffs_obj_t *obj;
int i;
struct ylist_head *lh;
if (yaffs_skip_verification(dev))
return;
/* Iterate through the objects in each hash entry */
for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
ylist_for_each(lh, &dev->obj_bucket[i].list) {
if (lh) {
obj = ylist_entry(lh, yaffs_obj_t, hash_link);
yaffs_verify_obj(obj);
}
}
}
}
void yaffs_verify_obj_in_dir(yaffs_obj_t *obj)
{
struct ylist_head *lh;
yaffs_obj_t *listObj;
int count = 0;
if (!obj) {
T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
YBUG();
return;
}
if (yaffs_skip_verification(obj->my_dev))
return;
if (!obj->parent) {
T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
YBUG();
return;
}
if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
YBUG();
}
/* Iterate through the objects in each hash entry */
ylist_for_each(lh, &obj->parent->variant.dir_variant.children) {
if (lh) {
listObj = ylist_entry(lh, yaffs_obj_t, siblings);
yaffs_verify_obj(listObj);
if (obj == listObj)
count++;
}
}
if (count != 1) {
T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
YBUG();
}
}
void yaffs_verify_dir(yaffs_obj_t *directory)
{
struct ylist_head *lh;
yaffs_obj_t *listObj;
if (!directory) {
YBUG();
return;
}
if (yaffs_skip_full_verification(directory->my_dev))
return;
if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variant_type));
YBUG();
}
/* Iterate through the objects in each hash entry */
ylist_for_each(lh, &directory->variant.dir_variant.children) {
if (lh) {
listObj = ylist_entry(lh, yaffs_obj_t, siblings);
if (listObj->parent != directory) {
T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
YBUG();
}
yaffs_verify_obj_in_dir(listObj);
}
}
}
static int yaffs_free_verification_failures;
void yaffs_verify_free_chunks(yaffs_dev_t *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) {
T(YAFFS_TRACE_ALWAYS,
(TSTR("Freechunks verification failure %d %d %d" TENDSTR),
dev->n_free_chunks, counted, difference));
yaffs_free_verification_failures++;
}
}
int yaffs_verify_file_sane(yaffs_obj_t *in)
{
#if 0
int chunk;
int n_chunks;
int fSize;
int failed = 0;
int obj_id;
yaffs_tnode_t *tn;
yaffs_tags_t localTags;
yaffs_tags_t *tags = &localTags;
int theChunk;
int is_deleted;
if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
return YAFFS_FAIL;
obj_id = in->obj_id;
fSize = in->variant.file_variant.file_size;
n_chunks =
(fSize + in->my_dev->data_bytes_per_chunk - 1) / in->my_dev->data_bytes_per_chunk;
for (chunk = 1; chunk <= n_chunks; chunk++) {
tn = yaffs_find_tnode_0(in->my_dev, &in->variant.file_variant,
chunk);
if (tn) {
theChunk = yaffs_get_group_base(dev, tn, chunk);
if (yaffs_check_chunk_bits
(dev, theChunk / dev->param.chunks_per_block,
theChunk % dev->param.chunks_per_block)) {
yaffs_rd_chunk_tags_nand(in->my_dev, theChunk,
tags,
&is_deleted);
if (yaffs_tags_match
(tags, in->obj_id, chunk, is_deleted)) {
/* found it; */
}
} else {
failed = 1;
}
} else {
/* T(("No level 0 found for %d\n", chunk)); */
}
}
return failed ? YAFFS_FAIL : YAFFS_OK;
#else
in=in;
return YAFFS_OK;
#endif
}

View file

@ -0,0 +1,39 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 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.
*/
#ifndef __YAFFS_VERIFY_H__
#define __YAFFS_VERIFY_H__
#include "yaffs_guts.h"
void yaffs_verify_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n);
void yaffs_verify_collected_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n);
void yaffs_verify_blocks(yaffs_dev_t *dev);
void yaffs_verify_oh(yaffs_obj_t *obj, yaffs_obj_header *oh, yaffs_ext_tags *tags, int parentCheck);
void yaffs_verify_file(yaffs_obj_t *obj);
void yaffs_verify_link(yaffs_obj_t *obj);
void yaffs_verify_symlink(yaffs_obj_t *obj);
void yaffs_verify_special(yaffs_obj_t *obj);
void yaffs_verify_obj(yaffs_obj_t *obj);
void yaffs_verify_objects(yaffs_dev_t *dev);
void yaffs_verify_obj_in_dir(yaffs_obj_t *obj);
void yaffs_verify_dir(yaffs_obj_t *directory);
void yaffs_verify_free_chunks(yaffs_dev_t *dev);
int yaffs_verify_file_sane(yaffs_obj_t *obj);
int yaffs_skip_verification(yaffs_dev_t *dev);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,465 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 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"
int yaffs1_scan(yaffs_dev_t *dev)
{
yaffs_ext_tags tags;
int blk;
int blockIterator;
int startIterator;
int endIterator;
int result;
int chunk;
int c;
int deleted;
yaffs_block_state_t state;
yaffs_obj_t *hard_list = NULL;
yaffs_block_info_t *bi;
__u32 seq_number;
yaffs_obj_header *oh;
yaffs_obj_t *in;
yaffs_obj_t *parent;
int alloc_failed = 0;
struct yaffs_shadow_fixer_s *shadowFixerList = NULL;
__u8 *chunkData;
T(YAFFS_TRACE_SCAN,
(TSTR("yaffs1_scan starts intstartblk %d intendblk %d..." TENDSTR),
dev->internal_start_block, dev->internal_end_block));
chunkData = yaffs_get_temp_buffer(dev, __LINE__);
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;
T(YAFFS_TRACE_SCAN_DEBUG,
(TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
state, seq_number));
if (state == YAFFS_BLOCK_STATE_DEAD) {
T(YAFFS_TRACE_BAD_BLOCKS,
(TSTR("block %d is bad" TENDSTR), blk));
} else if (state == YAFFS_BLOCK_STATE_EMPTY) {
T(YAFFS_TRACE_SCAN_DEBUG,
(TSTR("Block empty " TENDSTR)));
dev->n_erased_blocks++;
dev->n_free_chunks += dev->param.chunks_per_block;
}
bi++;
}
startIterator = dev->internal_start_block;
endIterator = dev->internal_end_block;
/* For each block.... */
for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
blockIterator++) {
YYIELD();
YYIELD();
blk = blockIterator;
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_SCANNING; c++) {
/* Read the tags and decide what to do */
chunk = blk * dev->param.chunks_per_block + c;
result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
&tags);
/* Let's have a good look at this chunk... */
if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED || tags.is_deleted) {
/* YAFFS1 only...
* A deleted chunk
*/
deleted++;
dev->n_free_chunks++;
/*T((" %d %d deleted\n",blk,c)); */
} 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 from */
T(YAFFS_TRACE_SCAN,
(TSTR
(" Allocating from %d %d" TENDSTR),
blk, c));
state = YAFFS_BLOCK_STATE_ALLOCATING;
dev->alloc_block = blk;
dev->alloc_page = c;
dev->alloc_block_finder = blk;
/* Set block finder here to encourage the allocator to go forth from here. */
}
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;
}
}
/* T((" %d %d data %d %d\n",blk,c,tags.obj_id,tags.chunk_id)); */
} else {
/* chunk_id == 0, so it is an ObjectHeader.
* Thus, we read in the object header and make the object
*/
yaffs_set_chunk_bit(dev, blk, c);
bi->pages_in_use++;
result = yaffs_rd_chunk_tags_nand(dev, chunk,
chunkData,
NULL);
oh = (yaffs_obj_header *) chunkData;
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 = 0;
}
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_s *fixer;
fixer = YMALLOC(sizeof(struct yaffs_shadow_fixer_s));
if (fixer) {
fixer->next = shadowFixerList;
shadowFixerList = fixer;
fixer->obj_id = tags.obj_id;
fixer->shadowed_id = oh->shadows_obj;
T(YAFFS_TRACE_SCAN,
(TSTR
(" Shadow fixer: %d shadows %d" TENDSTR),
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 existingSerial = in->serial;
unsigned newSerial = tags.serial_number;
if (((existingSerial + 1) & 3) == newSerial) {
/* 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;
#ifdef CONFIG_YAFFS_WINCE
in->win_atime[0] = oh->win_atime[0];
in->win_ctime[0] = oh->win_ctime[0];
in->win_mtime[0] = oh->win_mtime[0];
in->win_atime[1] = oh->win_atime[1];
in->win_ctime[1] = oh->win_ctime[1];
in->win_mtime[1] = oh->win_mtime[1];
#else
in->yst_uid = oh->yst_uid;
in->yst_gid = oh->yst_gid;
in->yst_atime = oh->yst_atime;
in->yst_mtime = oh->yst_mtime;
in->yst_ctime = oh->yst_ctime;
in->yst_rdev = oh->yst_rdev;
#endif
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;
#ifdef CONFIG_YAFFS_WINCE
in->win_atime[0] = oh->win_atime[0];
in->win_ctime[0] = oh->win_ctime[0];
in->win_mtime[0] = oh->win_mtime[0];
in->win_atime[1] = oh->win_atime[1];
in->win_ctime[1] = oh->win_ctime[1];
in->win_mtime[1] = oh->win_mtime[1];
#else
in->yst_uid = oh->yst_uid;
in->yst_gid = oh->yst_gid;
in->yst_atime = oh->yst_atime;
in->yst_mtime = oh->yst_mtime;
in->yst_ctime = oh->yst_ctime;
in->yst_rdev = oh->yst_rdev;
#endif
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;
YINIT_LIST_HEAD(&parent->variant.
dir_variant.
children);
} else if (!parent || parent->variant_type !=
YAFFS_OBJECT_TYPE_DIRECTORY) {
/* Hoosterman, another problem....
* We're trying to use a non-directory as a directory
*/
T(YAFFS_TRACE_ERROR,
(TSTR
("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
TENDSTR)));
parent = dev->lost_n_found;
}
yaffs_add_obj_to_dir(parent, in);
if (0 && (parent == dev->del_dir ||
parent == dev->unlinked_dir)) {
in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
dev->n_deleted_files++;
}
/* Note re hardlinks.
* Since we might scan a hardlink before its equivalent object is scanned
* we put them all in a list.
* After scanning is complete, we should have all the objects, so we run through this
* list and fix up all the chains.
*/
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 =
oh->file_size;
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
in->variant.hardlink_variant.
equiv_id =
oh->equiv_id;
in->hard_links.next =
(struct ylist_head *)
hard_list;
hard_list = in;
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_SCANNING) {
/* 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 */
{
struct yaffs_shadow_fixer_s *fixer;
yaffs_obj_t *obj;
while (shadowFixerList) {
fixer = shadowFixerList;
shadowFixerList = 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);
YFREE(fixer);
}
}
yaffs_release_temp_buffer(dev, chunkData, __LINE__);
if (alloc_failed)
return YAFFS_FAIL;
T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_scan ends" TENDSTR)));
return YAFFS_OK;
}

View file

@ -0,0 +1,22 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 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(yaffs_dev_t *dev);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,36 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 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.
*/
#ifndef __YAFFS_YAFFS2_H__
#define __YAFFS_YAFFS2_H__
#include "yaffs_guts.h"
void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev);
void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev);
void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t *dev, yaffs_block_info_t *bi);
void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi);
int yaffs_block_ok_for_gc(yaffs_dev_t *dev, yaffs_block_info_t *bi);
__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev);
int yaffs2_checkpt_required(yaffs_dev_t *dev);
int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev);
void yaffs2_checkpt_invalidate(yaffs_dev_t *dev);
int yaffs2_checkpt_save(yaffs_dev_t *dev);
int yaffs2_checkpt_restore(yaffs_dev_t *dev);
int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size);
int yaffs2_scan_backwards(yaffs_dev_t *dev);
#endif

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -16,6 +16,6 @@
#ifndef __YAFFSINTERFACE_H__
#define __YAFFSINTERFACE_H__
int yaffs_Initialise(unsigned nBlocks);
int yaffs_initialise(unsigned nBlocks);
#endif

View file

@ -1,7 +1,7 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@ -41,12 +41,14 @@
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
#include <linux/config.h>
#endif
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/xattr.h>
#define YCHAR char
#define YUCHAR unsigned char
@ -55,11 +57,11 @@
#define yaffs_strcpy(a, b) strcpy(a, b)
#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
#define yaffs_strncmp(a, b, c) strncmp(a, b, c)
#define yaffs_strlen(s) strlen(s)
#define yaffs_strnlen(s,m) strnlen(s,m)
#define yaffs_sprintf sprintf
#define yaffs_toupper(a) toupper(a)
#define Y_INLINE inline
#define Y_INLINE __inline__
#define YAFFS_LOSTNFOUND_NAME "lost+found"
#define YAFFS_LOSTNFOUND_PREFIX "obj"
@ -71,11 +73,11 @@
#define YFREE_ALT(x) vfree(x)
#define YMALLOC_DMA(x) YMALLOC(x)
/* KR - added for use in scan so processes aren't blocked indefinitely. */
#define YYIELD() schedule()
#define Y_DUMP_STACK() dump_stack()
#define YAFFS_ROOT_MODE 0666
#define YAFFS_LOSTNFOUND_MODE 0666
#define YAFFS_ROOT_MODE 0755
#define YAFFS_LOSTNFOUND_MODE 0700
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
@ -85,19 +87,14 @@
#define Y_TIME_CONVERT(x) (x)
#endif
#define yaffs_SumCompare(x, y) ((x) == (y))
#define yaffs_sum_cmp(x, y) ((x) == (y))
#define yaffs_strcmp(a, b) strcmp(a, b)
#define TENDSTR "\n"
#define TSTR(x) KERN_WARNING x
#define TSTR(x) KERN_DEBUG x
#define TCONT(x) x
#define TOUT(p) printk p
#define yaffs_trace(mask, fmt, args...) \
do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
printk(KERN_WARNING "yaffs: " fmt, ## args); \
} while (0)
#define compile_time_assertion(assertion) \
({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
@ -116,7 +113,6 @@
#include "stdio.h"
#include "string.h"
#include "devextras.h"
#define YMALLOC(x) malloc(x)
#define YFREE(x) free(x)
@ -129,7 +125,7 @@
#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_strlen(s) strlen(s)
#define yaffs_strnlen(s,m) strnlen(s,m)
#define yaffs_sprintf sprintf
#define yaffs_toupper(a) toupper(a)
@ -146,10 +142,10 @@
#define YAFFS_LOSTNFOUND_PREFIX "obj"
/* #define YPRINTF(x) printf x */
#define YAFFS_ROOT_MODE 0666
#define YAFFS_LOSTNFOUND_MODE 0666
#define YAFFS_ROOT_MODE 0755
#define YAFFS_LOSTNFOUND_MODE 0700
#define yaffs_SumCompare(x, y) ((x) == (y))
#define yaffs_sum_cmp(x, y) ((x) == (y))
#define yaffs_strcmp(a, b) strcmp(a, b)
#else
@ -158,46 +154,180 @@
#endif
/* see yaffs_fs.c */
extern unsigned int yaffs_traceMask;
extern unsigned int yaffs_wr_attempts;
#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
/*
* Tracing flags.
* The flags masked in YAFFS_TRACE_ALWAYS are always traced.
*/
#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
#define YAFFS_TRACE_OS 0x00000002
#define YAFFS_TRACE_ALLOCATE 0x00000004
#define YAFFS_TRACE_SCAN 0x00000008
#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
#define YAFFS_TRACE_ERASE 0x00000020
#define YAFFS_TRACE_GC 0x00000040
#define YAFFS_TRACE_WRITE 0x00000080
#define YAFFS_TRACE_TRACING 0x00000100
#define YAFFS_TRACE_DELETION 0x00000200
#define YAFFS_TRACE_BUFFERS 0x00000400
#define YAFFS_TRACE_NANDACCESS 0x00000800
#define YAFFS_TRACE_GC_DETAIL 0x00001000
#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
#define YAFFS_TRACE_MTD 0x00004000
#define YAFFS_TRACE_CHECKPOINT 0x00008000
#ifndef O_RDONLY
#define O_RDONLY 00
#endif
#define YAFFS_TRACE_VERIFY 0x00010000
#define YAFFS_TRACE_VERIFY_NAND 0x00020000
#define YAFFS_TRACE_VERIFY_FULL 0x00040000
#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
#ifndef O_WRONLY
#define O_WRONLY 01
#endif
#ifndef O_RDWR
#define O_RDWR 02
#endif
#ifndef O_CREAT
#define O_CREAT 0100
#endif
#ifndef O_EXCL
#define O_EXCL 0200
#endif
#ifndef O_TRUNC
#define O_TRUNC 01000
#endif
#ifndef O_APPEND
#define O_APPEND 02000
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
#ifndef EBUSY
#define EBUSY 16
#endif
#ifndef ENODEV
#define ENODEV 19
#endif
#ifndef EINVAL
#define EINVAL 22
#endif
#ifndef 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 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 EEXIST
#define EEXIST 17
#endif
#ifndef ENOTDIR
#define ENOTDIR 20
#endif
#ifndef EISDIR
#define EISDIR 21
#endif
#define YAFFS_TRACE_ERROR 0x40000000
#define YAFFS_TRACE_BUG 0x80000000
#define YAFFS_TRACE_ALWAYS 0xF0000000
// Mode flags
#ifndef S_IFMT
#define S_IFMT 0170000
#endif
#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
#ifndef S_IFLNK
#define S_IFLNK 0120000
#endif
#ifndef S_IFDIR
#define S_IFDIR 0040000
#endif
#ifndef S_IFREG
#define S_IFREG 0100000
#endif
#ifndef S_IREAD
#define S_IREAD 0000400
#endif
#ifndef S_IWRITE
#define S_IWRITE 0000200
#endif
#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 YBUG
#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0)
#define YBUG() do {\
T(YAFFS_TRACE_BUG,\
(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\
__LINE__));\
Y_DUMP_STACK();\
} while (0)
#endif
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff