generic: fold yaffs_git_2010_10_20 patch to generic/files
Signed-off-by: Gabor Juhos <juhosg@openwrt.org> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@34013 3c298f89-4303-0410-b956-a3cf2f4a3e73master
parent
029a10f4cb
commit
e3f12313fe
|
@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2
|
||||||
|
|
||||||
If unsure, say Y.
|
If unsure, say Y.
|
||||||
|
|
||||||
config YAFFS_DISABLE_LAZY_LOAD
|
config YAFFS_DISABLE_TAGS_ECC
|
||||||
bool "Disable lazy loading"
|
bool "Disable YAFFS from doing ECC on tags by default"
|
||||||
depends on YAFFS_YAFFS2
|
depends on YAFFS_FS && YAFFS_YAFFS2
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
"Lazy loading" defers loading file details until they are
|
This defaults Yaffs to using its own ECC calculations on tags instead of
|
||||||
required. This saves mount time, but makes the first look-up
|
just relying on the MTD.
|
||||||
a bit longer.
|
This behavior can also be overridden with tags_ecc_on and
|
||||||
|
tags_ecc_off mount options.
|
||||||
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.
|
|
||||||
|
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
|
@ -154,3 +146,45 @@ config YAFFS_SHORT_NAMES_IN_RAM
|
||||||
but makes look-ups faster.
|
but makes look-ups faster.
|
||||||
|
|
||||||
If unsure, say Y.
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,14 @@
|
||||||
|
|
||||||
obj-$(CONFIG_YAFFS_FS) += yaffs.o
|
obj-$(CONFIG_YAFFS_FS) += yaffs.o
|
||||||
|
|
||||||
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.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_qsort.o
|
yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
|
||||||
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
|
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
|
||||||
yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.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
|
||||||
|
|
||||||
|
|
|
@ -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
|
URL: git://www.aleph1.co.uk/yaffs2
|
||||||
Version: 2009-09-24
|
Version: 7396445d7d0d13469b9505791114b9dc6b76ffe4 (2010-10-20)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -24,6 +24,8 @@
|
||||||
#define __EXTRAS_H__
|
#define __EXTRAS_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include "yportenv.h"
|
||||||
|
|
||||||
#if !(defined __KERNEL__)
|
#if !(defined __KERNEL__)
|
||||||
|
|
||||||
/* Definition of types */
|
/* Definition of types */
|
||||||
|
@ -33,103 +35,6 @@ typedef unsigned __u32;
|
||||||
|
|
||||||
#endif
|
#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__)
|
#if !(defined __KERNEL__)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Martin Fouts <Martin.Fouts@palmsource.com>
|
* Created by Martin Fouts <Martin.Fouts@palmsource.com>
|
||||||
|
@ -29,25 +29,46 @@
|
||||||
/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
|
/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
|
||||||
/* #define CONFIG_YAFFS_DOES_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 */
|
/* Default: Not selected */
|
||||||
/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
|
/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
|
||||||
/* CONFIG_YAFFS_DOES_ECC is set */
|
/* CONFIG_YAFFS_DOES_ECC is set */
|
||||||
/* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
|
/* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
|
||||||
|
|
||||||
/* Default: Selected */
|
/* Default: Not selected */
|
||||||
/* Meaning: Disables testing whether chunks are erased before writing to them*/
|
/* Meaning: Always test whether chunks are erased before writing to them.
|
||||||
#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
|
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 */
|
/* Default: Selected */
|
||||||
/* Meaning: Cache short names, taking more RAM, but faster look-ups */
|
/* Meaning: Cache short names, taking more RAM, but faster look-ups */
|
||||||
#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
|
#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
|
||||||
|
|
||||||
/* Default: 10 */
|
/* Default: Unselected */
|
||||||
/* Meaning: set the count of blocks to reserve for checkpointing */
|
/* Meaning: Select to disable block refreshing. */
|
||||||
#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
|
/* 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.
|
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
|
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
|
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.
|
MTD versions in yaffs_mtdif1.c.
|
||||||
*/
|
*/
|
||||||
/* Default: Not selected */
|
/* 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 */
|
/* #define CONFIG_YAFFS_9BYTE_TAGS */
|
||||||
|
|
||||||
#endif /* YAFFS_OUT_OF_TREE */
|
#endif /* YAFFS_OUT_OF_TREE */
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -11,16 +11,12 @@
|
||||||
* published by the Free Software Foundation.
|
* 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_checkptrw.h"
|
||||||
#include "yaffs_getblockinfo.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,
|
T(YAFFS_TRACE_CHECKPOINT,
|
||||||
(TSTR("checkpt blocks available = %d" TENDSTR),
|
(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;
|
int i;
|
||||||
|
|
||||||
if (!dev->eraseBlockInNAND)
|
if (!dev->param.erase_fn)
|
||||||
return 0;
|
return 0;
|
||||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
|
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++) {
|
for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
|
||||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
|
yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
|
||||||
if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
|
if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
|
||||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
|
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->n_erasures++;
|
||||||
dev->nErasedBlocks++;
|
|
||||||
dev->nFreeChunks += dev->nChunksPerBlock;
|
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 {
|
} else {
|
||||||
dev->markNANDBlockBad(dev, i);
|
dev->param.bad_block_fn(dev, i);
|
||||||
bi->blockState = YAFFS_BLOCK_STATE_DEAD;
|
bi->block_state = YAFFS_BLOCK_STATE_DEAD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->blocksInCheckpoint = 0;
|
dev->blocks_in_checkpt = 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
|
static void yaffs2_checkpt_find_erased_block(yaffs_dev_t *dev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
|
int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks;
|
||||||
T(YAFFS_TRACE_CHECKPOINT,
|
T(YAFFS_TRACE_CHECKPOINT,
|
||||||
(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
|
(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 &&
|
if (dev->checkpt_next_block >= 0 &&
|
||||||
dev->checkpointNextBlock <= dev->internalEndBlock &&
|
dev->checkpt_next_block <= dev->internal_end_block &&
|
||||||
blocksAvailable > 0) {
|
blocksAvailable > 0) {
|
||||||
|
|
||||||
for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
|
for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) {
|
||||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
|
yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
|
||||||
if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
|
if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
|
||||||
dev->checkpointNextBlock = i + 1;
|
dev->checkpt_next_block = i + 1;
|
||||||
dev->checkpointCurrentBlock = i;
|
dev->checkpt_cur_block = i;
|
||||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i));
|
T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -84,34 +83,34 @@ static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
|
||||||
}
|
}
|
||||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR)));
|
T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR)));
|
||||||
|
|
||||||
dev->checkpointNextBlock = -1;
|
dev->checkpt_next_block = -1;
|
||||||
dev->checkpointCurrentBlock = -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;
|
int i;
|
||||||
yaffs_ExtendedTags tags;
|
yaffs_ext_tags tags;
|
||||||
|
|
||||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
|
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)
|
if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
|
||||||
for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
|
for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) {
|
||||||
int chunk = i * dev->nChunksPerBlock;
|
int chunk = i * dev->param.chunks_per_block;
|
||||||
int realignedChunk = chunk - dev->chunkOffset;
|
int realignedChunk = chunk - dev->chunk_offset;
|
||||||
|
|
||||||
dev->readChunkWithTagsFromNAND(dev, realignedChunk,
|
dev->param.read_chunk_tags_fn(dev, realignedChunk,
|
||||||
NULL, &tags);
|
NULL, &tags);
|
||||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
|
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 */
|
/* Right kind of block */
|
||||||
dev->checkpointNextBlock = tags.objectId;
|
dev->checkpt_next_block = tags.obj_id;
|
||||||
dev->checkpointCurrentBlock = i;
|
dev->checkpt_cur_block = i;
|
||||||
dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
|
dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
|
||||||
dev->blocksInCheckpoint++;
|
dev->blocks_in_checkpt++;
|
||||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i));
|
T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -119,122 +118,127 @@ static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
|
||||||
|
|
||||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR)));
|
T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR)));
|
||||||
|
|
||||||
dev->checkpointNextBlock = -1;
|
dev->checkpt_next_block = -1;
|
||||||
dev->checkpointCurrentBlock = -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? */
|
/* Got the functions we need? */
|
||||||
if (!dev->writeChunkWithTagsToNAND ||
|
if (!dev->param.write_chunk_tags_fn ||
|
||||||
!dev->readChunkWithTagsFromNAND ||
|
!dev->param.read_chunk_tags_fn ||
|
||||||
!dev->eraseBlockInNAND ||
|
!dev->param.erase_fn ||
|
||||||
!dev->markNANDBlockBad)
|
!dev->param.bad_block_fn)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (forWriting && !yaffs_CheckpointSpaceOk(dev))
|
if (forWriting && !yaffs2_checkpt_space_ok(dev))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!dev->checkpointBuffer)
|
if (!dev->checkpt_buffer)
|
||||||
dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
|
dev->checkpt_buffer = YMALLOC_DMA(dev->param.total_bytes_per_chunk);
|
||||||
if (!dev->checkpointBuffer)
|
if (!dev->checkpt_buffer)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
dev->checkpointPageSequence = 0;
|
dev->checkpt_page_seq = 0;
|
||||||
|
dev->checkpt_byte_count = 0;
|
||||||
dev->checkpointOpenForWrite = forWriting;
|
dev->checkpt_sum = 0;
|
||||||
|
dev->checkpt_xor = 0;
|
||||||
dev->checkpointByteCount = 0;
|
dev->checkpt_cur_block = -1;
|
||||||
dev->checkpointSum = 0;
|
dev->checkpt_cur_chunk = -1;
|
||||||
dev->checkpointXor = 0;
|
dev->checkpt_next_block = dev->internal_start_block;
|
||||||
dev->checkpointCurrentBlock = -1;
|
|
||||||
dev->checkpointCurrentChunk = -1;
|
|
||||||
dev->checkpointNextBlock = dev->internalStartBlock;
|
|
||||||
|
|
||||||
/* Erase all the blocks in the checkpoint area */
|
/* Erase all the blocks in the checkpoint area */
|
||||||
if (forWriting) {
|
if (forWriting) {
|
||||||
memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
|
memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
|
||||||
dev->checkpointByteOffset = 0;
|
dev->checkpt_byte_offs = 0;
|
||||||
return yaffs_CheckpointErase(dev);
|
return yaffs_checkpt_erase(dev);
|
||||||
} else {
|
} else {
|
||||||
int i;
|
int i;
|
||||||
/* Set to a value that will kick off a read */
|
/* 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)
|
/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
|
||||||
* going to be way more than we need */
|
* going to be way more than we need */
|
||||||
dev->blocksInCheckpoint = 0;
|
dev->blocks_in_checkpt = 0;
|
||||||
dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
|
dev->checkpt_max_blocks = (dev->internal_end_block - dev->internal_start_block)/16 + 2;
|
||||||
dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
|
dev->checkpt_block_list = YMALLOC(sizeof(int) * dev->checkpt_max_blocks);
|
||||||
for (i = 0; i < dev->checkpointMaxBlocks; i++)
|
if(!dev->checkpt_block_list)
|
||||||
dev->checkpointBlockList[i] = -1;
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < dev->checkpt_max_blocks; i++)
|
||||||
|
dev->checkpt_block_list[i] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
|
int yaffs2_get_checkpt_sum(yaffs_dev_t *dev, __u32 *sum)
|
||||||
{
|
{
|
||||||
__u32 compositeSum;
|
__u32 compositeSum;
|
||||||
compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
|
compositeSum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xFF);
|
||||||
*sum = compositeSum;
|
*sum = compositeSum;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
|
static int yaffs2_checkpt_flush_buffer(yaffs_dev_t *dev)
|
||||||
{
|
{
|
||||||
int chunk;
|
int chunk;
|
||||||
int realignedChunk;
|
int realignedChunk;
|
||||||
|
|
||||||
yaffs_ExtendedTags tags;
|
yaffs_ext_tags tags;
|
||||||
|
|
||||||
if (dev->checkpointCurrentBlock < 0) {
|
if (dev->checkpt_cur_block < 0) {
|
||||||
yaffs_CheckpointFindNextErasedBlock(dev);
|
yaffs2_checkpt_find_erased_block(dev);
|
||||||
dev->checkpointCurrentChunk = 0;
|
dev->checkpt_cur_chunk = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->checkpointCurrentBlock < 0)
|
if (dev->checkpt_cur_block < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
tags.chunkDeleted = 0;
|
tags.is_deleted = 0;
|
||||||
tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
|
tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
|
||||||
tags.chunkId = dev->checkpointPageSequence + 1;
|
tags.chunk_id = dev->checkpt_page_seq + 1;
|
||||||
tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
|
tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
|
||||||
tags.byteCount = dev->nDataBytesPerChunk;
|
tags.n_bytes = dev->data_bytes_per_chunk;
|
||||||
if (dev->checkpointCurrentChunk == 0) {
|
if (dev->checkpt_cur_chunk == 0) {
|
||||||
/* First chunk we write for the block? Set block state to
|
/* First chunk we write for the block? Set block state to
|
||||||
checkpoint */
|
checkpoint */
|
||||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointCurrentBlock);
|
yaffs_block_info_t *bi = yaffs_get_block_info(dev, dev->checkpt_cur_block);
|
||||||
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
|
bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
|
||||||
dev->blocksInCheckpoint++;
|
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),
|
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->n_page_writes++;
|
||||||
dev->checkpointBuffer, &tags);
|
|
||||||
dev->checkpointByteOffset = 0;
|
dev->param.write_chunk_tags_fn(dev, realignedChunk,
|
||||||
dev->checkpointPageSequence++;
|
dev->checkpt_buffer, &tags);
|
||||||
dev->checkpointCurrentChunk++;
|
dev->checkpt_byte_offs = 0;
|
||||||
if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {
|
dev->checkpt_page_seq++;
|
||||||
dev->checkpointCurrentChunk = 0;
|
dev->checkpt_cur_chunk++;
|
||||||
dev->checkpointCurrentBlock = -1;
|
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;
|
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 i = 0;
|
||||||
int ok = 1;
|
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;
|
return 0;
|
||||||
|
|
||||||
if (!dev->checkpointOpenForWrite)
|
if (!dev->checkpt_open_write)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
while (i < nBytes && ok) {
|
while (i < n_bytes && ok) {
|
||||||
dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes;
|
dev->checkpt_buffer[dev->checkpt_byte_offs] = *dataBytes;
|
||||||
dev->checkpointSum += *dataBytes;
|
dev->checkpt_sum += *dataBytes;
|
||||||
dev->checkpointXor ^= *dataBytes;
|
dev->checkpt_xor ^= *dataBytes;
|
||||||
|
|
||||||
dev->checkpointByteOffset++;
|
dev->checkpt_byte_offs++;
|
||||||
i++;
|
i++;
|
||||||
dataBytes++;
|
dataBytes++;
|
||||||
dev->checkpointByteCount++;
|
dev->checkpt_byte_count++;
|
||||||
|
|
||||||
|
|
||||||
if (dev->checkpointByteOffset < 0 ||
|
if (dev->checkpt_byte_offs < 0 ||
|
||||||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
|
dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
|
||||||
ok = yaffs_CheckpointFlushBuffer(dev);
|
ok = yaffs2_checkpt_flush_buffer(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
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 i = 0;
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
yaffs_ExtendedTags tags;
|
yaffs_ext_tags tags;
|
||||||
|
|
||||||
|
|
||||||
int chunk;
|
int chunk;
|
||||||
|
@ -281,113 +285,116 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
|
||||||
|
|
||||||
__u8 *dataBytes = (__u8 *)data;
|
__u8 *dataBytes = (__u8 *)data;
|
||||||
|
|
||||||
if (!dev->checkpointBuffer)
|
if (!dev->checkpt_buffer)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (dev->checkpointOpenForWrite)
|
if (dev->checkpt_open_write)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
while (i < nBytes && ok) {
|
while (i < n_bytes && ok) {
|
||||||
|
|
||||||
|
|
||||||
if (dev->checkpointByteOffset < 0 ||
|
if (dev->checkpt_byte_offs < 0 ||
|
||||||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
|
dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
|
||||||
|
|
||||||
if (dev->checkpointCurrentBlock < 0) {
|
if (dev->checkpt_cur_block < 0) {
|
||||||
yaffs_CheckpointFindNextCheckpointBlock(dev);
|
yaffs2_checkpt_find_block(dev);
|
||||||
dev->checkpointCurrentChunk = 0;
|
dev->checkpt_cur_chunk = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->checkpointCurrentBlock < 0)
|
if (dev->checkpt_cur_block < 0)
|
||||||
ok = 0;
|
ok = 0;
|
||||||
else {
|
else {
|
||||||
chunk = dev->checkpointCurrentBlock *
|
chunk = dev->checkpt_cur_block *
|
||||||
dev->nChunksPerBlock +
|
dev->param.chunks_per_block +
|
||||||
dev->checkpointCurrentChunk;
|
dev->checkpt_cur_chunk;
|
||||||
|
|
||||||
realignedChunk = chunk - dev->chunkOffset;
|
realignedChunk = chunk - dev->chunk_offset;
|
||||||
|
|
||||||
|
dev->n_page_reads++;
|
||||||
|
|
||||||
/* read in the next chunk */
|
/* read in the next chunk */
|
||||||
/* printf("read checkpoint page %d\n",dev->checkpointPage); */
|
/* printf("read checkpoint page %d\n",dev->checkpointPage); */
|
||||||
dev->readChunkWithTagsFromNAND(dev,
|
dev->param.read_chunk_tags_fn(dev,
|
||||||
realignedChunk,
|
realignedChunk,
|
||||||
dev->checkpointBuffer,
|
dev->checkpt_buffer,
|
||||||
&tags);
|
&tags);
|
||||||
|
|
||||||
if (tags.chunkId != (dev->checkpointPageSequence + 1) ||
|
if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
|
||||||
tags.eccResult > YAFFS_ECC_RESULT_FIXED ||
|
tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
|
||||||
tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
|
tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
|
||||||
ok = 0;
|
ok = 0;
|
||||||
|
|
||||||
dev->checkpointByteOffset = 0;
|
dev->checkpt_byte_offs = 0;
|
||||||
dev->checkpointPageSequence++;
|
dev->checkpt_page_seq++;
|
||||||
dev->checkpointCurrentChunk++;
|
dev->checkpt_cur_chunk++;
|
||||||
|
|
||||||
if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
|
if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block)
|
||||||
dev->checkpointCurrentBlock = -1;
|
dev->checkpt_cur_block = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
|
*dataBytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
|
||||||
dev->checkpointSum += *dataBytes;
|
dev->checkpt_sum += *dataBytes;
|
||||||
dev->checkpointXor ^= *dataBytes;
|
dev->checkpt_xor ^= *dataBytes;
|
||||||
dev->checkpointByteOffset++;
|
dev->checkpt_byte_offs++;
|
||||||
i++;
|
i++;
|
||||||
dataBytes++;
|
dataBytes++;
|
||||||
dev->checkpointByteCount++;
|
dev->checkpt_byte_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int yaffs_CheckpointClose(yaffs_Device *dev)
|
int yaffs_checkpt_close(yaffs_dev_t *dev)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (dev->checkpointOpenForWrite) {
|
if (dev->checkpt_open_write) {
|
||||||
if (dev->checkpointByteOffset != 0)
|
if (dev->checkpt_byte_offs != 0)
|
||||||
yaffs_CheckpointFlushBuffer(dev);
|
yaffs2_checkpt_flush_buffer(dev);
|
||||||
} else {
|
} else if(dev->checkpt_block_list){
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
|
for (i = 0; i < dev->blocks_in_checkpt && dev->checkpt_block_list[i] >= 0; i++) {
|
||||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
|
int blk = dev->checkpt_block_list[i];
|
||||||
if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
|
yaffs_block_info_t *bi = NULL;
|
||||||
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
|
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 {
|
else {
|
||||||
/* Todo this looks odd... */
|
/* Todo this looks odd... */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
YFREE(dev->checkpointBlockList);
|
YFREE(dev->checkpt_block_list);
|
||||||
dev->checkpointBlockList = NULL;
|
dev->checkpt_block_list = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
|
dev->n_free_chunks -= dev->blocks_in_checkpt * dev->param.chunks_per_block;
|
||||||
dev->nErasedBlocks -= dev->blocksInCheckpoint;
|
dev->n_erased_blocks -= dev->blocks_in_checkpt;
|
||||||
|
|
||||||
|
|
||||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR),
|
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 */
|
/* free the buffer */
|
||||||
YFREE(dev->checkpointBuffer);
|
YFREE(dev->checkpt_buffer);
|
||||||
dev->checkpointBuffer = NULL;
|
dev->checkpt_buffer = NULL;
|
||||||
return 1;
|
return 1;
|
||||||
} else
|
} else
|
||||||
return 0;
|
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 yaffs_checkpt_erase(dev);
|
||||||
return 0;
|
|
||||||
|
|
||||||
return yaffs_CheckpointErase(dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -18,18 +18,17 @@
|
||||||
|
|
||||||
#include "yaffs_guts.h"
|
#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
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -28,9 +28,6 @@
|
||||||
* this bytes influence on the line parity.
|
* 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 "yportenv.h"
|
||||||
|
|
||||||
#include "yaffs_ecc.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 */
|
/* 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;
|
int r = 0;
|
||||||
while (x) {
|
while (x) {
|
||||||
|
@ -83,7 +80,7 @@ static int yaffs_CountBits(unsigned char x)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int yaffs_CountBits32(unsigned x)
|
static int yaffs_count_bits32(unsigned x)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
while (x) {
|
while (x) {
|
||||||
|
@ -95,7 +92,7 @@ static int yaffs_CountBits32(unsigned x)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the ECC for a 256-byte block of data */
|
/* 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;
|
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 */
|
/* 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)
|
const unsigned char *test_ecc)
|
||||||
{
|
{
|
||||||
unsigned char d0, d1, d2; /* deltas */
|
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 */
|
return 1; /* Corrected the error */
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((yaffs_CountBits(d0) +
|
if ((yaffs_count_bits(d0) +
|
||||||
yaffs_CountBits(d1) +
|
yaffs_count_bits(d1) +
|
||||||
yaffs_CountBits(d2)) == 1) {
|
yaffs_count_bits(d2)) == 1) {
|
||||||
/* Reccoverable error in ecc */
|
/* Reccoverable error in ecc */
|
||||||
|
|
||||||
read_ecc[0] = test_ecc[0];
|
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
|
* 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)
|
yaffs_ECCOther *eccOther)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
@ -258,7 +255,7 @@ void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
|
||||||
unsigned line_parity_prime = 0;
|
unsigned line_parity_prime = 0;
|
||||||
unsigned char b;
|
unsigned char b;
|
||||||
|
|
||||||
for (i = 0; i < nBytes; i++) {
|
for (i = 0; i < n_bytes; i++) {
|
||||||
b = column_parity_table[*data++];
|
b = column_parity_table[*data++];
|
||||||
col_parity ^= b;
|
col_parity ^= b;
|
||||||
|
|
||||||
|
@ -275,7 +272,7 @@ void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
|
||||||
eccOther->lineParityPrime = line_parity_prime;
|
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,
|
yaffs_ECCOther *read_ecc,
|
||||||
const yaffs_ECCOther *test_ecc)
|
const yaffs_ECCOther *test_ecc)
|
||||||
{
|
{
|
||||||
|
@ -304,7 +301,7 @@ int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
|
||||||
if (cDelta & 0x02)
|
if (cDelta & 0x02)
|
||||||
bit |= 0x01;
|
bit |= 0x01;
|
||||||
|
|
||||||
if (lDelta >= nBytes)
|
if (lDelta >= n_bytes)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
data[lDelta] ^= (1 << bit);
|
data[lDelta] ^= (1 << bit);
|
||||||
|
@ -312,8 +309,8 @@ int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
|
||||||
return 1; /* corrected */
|
return 1; /* corrected */
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
|
if ((yaffs_count_bits32(lDelta) + yaffs_count_bits32(lDeltaPrime) +
|
||||||
yaffs_CountBits(cDelta)) == 1) {
|
yaffs_count_bits(cDelta)) == 1) {
|
||||||
/* Reccoverable error in ecc */
|
/* Reccoverable error in ecc */
|
||||||
|
|
||||||
*read_ecc = *test_ecc;
|
*read_ecc = *test_ecc;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -32,13 +32,13 @@ typedef struct {
|
||||||
unsigned lineParityPrime;
|
unsigned lineParityPrime;
|
||||||
} yaffs_ECCOther;
|
} yaffs_ECCOther;
|
||||||
|
|
||||||
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
|
void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc);
|
||||||
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);
|
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);
|
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,
|
yaffs_ECCOther *read_ecc,
|
||||||
const yaffs_ECCOther *test_ecc);
|
const yaffs_ECCOther *test_ecc);
|
||||||
#endif
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -17,18 +17,19 @@
|
||||||
#define __YAFFS_GETBLOCKINFO_H__
|
#define __YAFFS_GETBLOCKINFO_H__
|
||||||
|
|
||||||
#include "yaffs_guts.h"
|
#include "yaffs_guts.h"
|
||||||
|
#include "yaffs_trace.h"
|
||||||
|
|
||||||
/* Function to manipulate block info */
|
/* 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,
|
T(YAFFS_TRACE_ERROR,
|
||||||
(TSTR
|
(TSTR
|
||||||
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
|
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
|
||||||
blk));
|
blk));
|
||||||
YBUG();
|
YBUG();
|
||||||
}
|
}
|
||||||
return &dev->blockInfo[blk - dev->internalStartBlock];
|
return &dev->block_info[blk - dev->internal_start_block];
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -11,9 +11,6 @@
|
||||||
* published by the Free Software Foundation.
|
* 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"
|
#include "yportenv.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,208 +21,26 @@ const char *yaffs_mtdif_c_version =
|
||||||
#include "linux/time.h"
|
#include "linux/time.h"
|
||||||
#include "linux/mtd/nand.h"
|
#include "linux/mtd/nand.h"
|
||||||
|
|
||||||
#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
|
#include "yaffs_linux.h"
|
||||||
static struct nand_oobinfo yaffs_oobinfo = {
|
|
||||||
.useecc = 1,
|
|
||||||
.eccbytes = 6,
|
|
||||||
.eccpos = {8, 9, 10, 13, 14, 15}
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct nand_oobinfo yaffs_noeccinfo = {
|
int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber)
|
||||||
.useecc = 0,
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
|
|
||||||
static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
|
|
||||||
{
|
{
|
||||||
oob[0] = spare->tagByte0;
|
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||||
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);
|
|
||||||
__u32 addr =
|
__u32 addr =
|
||||||
((loff_t) blockNumber) * dev->nDataBytesPerChunk
|
((loff_t) blockNumber) * dev->param.total_bytes_per_chunk
|
||||||
* dev->nChunksPerBlock;
|
* dev->param.chunks_per_block;
|
||||||
struct erase_info ei;
|
struct erase_info ei;
|
||||||
|
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
ei.mtd = mtd;
|
ei.mtd = mtd;
|
||||||
ei.addr = addr;
|
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.time = 1000;
|
||||||
ei.retries = 2;
|
ei.retries = 2;
|
||||||
ei.callback = NULL;
|
ei.callback = NULL;
|
||||||
ei.priv = (u_long) dev;
|
ei.priv = (u_long) dev;
|
||||||
|
|
||||||
/* Todo finish off the ei if required */
|
|
||||||
|
|
||||||
sema_init(&dev->sem, 0);
|
|
||||||
|
|
||||||
retval = mtd->erase(mtd, &ei);
|
retval = mtd->erase(mtd, &ei);
|
||||||
|
|
||||||
if (retval == 0)
|
if (retval == 0)
|
||||||
|
@ -234,7 +49,7 @@ int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
|
||||||
return YAFFS_FAIL;
|
return YAFFS_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nandmtd_InitialiseNAND(yaffs_Device *dev)
|
int nandmtd_InitialiseNAND(yaffs_dev_t *dev)
|
||||||
{
|
{
|
||||||
return YAFFS_OK;
|
return YAFFS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -22,11 +22,6 @@
|
||||||
extern struct nand_oobinfo yaffs_oobinfo;
|
extern struct nand_oobinfo yaffs_oobinfo;
|
||||||
extern struct nand_oobinfo yaffs_noeccinfo;
|
extern struct nand_oobinfo yaffs_noeccinfo;
|
||||||
#endif
|
#endif
|
||||||
|
int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber);
|
||||||
int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
|
int nandmtd_InitialiseNAND(yaffs_dev_t *dev);
|
||||||
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);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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--
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* YAFFS: Yet another FFS. A NAND-flash specific file system.
|
* YAFFS: Yet another FFS. A NAND-flash specific file system.
|
||||||
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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.
|
* These functions are invoked via function pointers in yaffs_nand.c.
|
||||||
* This replaces functionality provided by functions in yaffs_mtdif.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.
|
* 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 "yportenv.h"
|
||||||
|
#include "yaffs_trace.h"
|
||||||
#include "yaffs_guts.h"
|
#include "yaffs_guts.h"
|
||||||
#include "yaffs_packedtags1.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/kernel.h"
|
||||||
#include "linux/version.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 */
|
/* 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))
|
#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
|
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||||
# define YTAG1_SIZE 8
|
# define YTAG1_SIZE 8
|
||||||
#else
|
#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.
|
* adjust 'oobfree' to match your existing Yaffs data.
|
||||||
*
|
*
|
||||||
* This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
|
* 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.
|
* the 9th byte.
|
||||||
*
|
*
|
||||||
* Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
|
* 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
|
* 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 pageStatus
|
* 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.
|
* byte and B is the small-page bad-block indicator byte.
|
||||||
*/
|
*/
|
||||||
static struct nand_ecclayout nand_oob_16 = {
|
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.
|
* Any underlying MTD error results in YAFFS_FAIL.
|
||||||
* Returns YAFFS_OK or YAFFS_FAIL.
|
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||||
*/
|
*/
|
||||||
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
|
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev,
|
||||||
int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
|
int nand_chunk, const __u8 *data, const yaffs_ext_tags *etags)
|
||||||
{
|
{
|
||||||
struct mtd_info *mtd = dev->genericDevice;
|
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||||
int chunkBytes = dev->nDataBytesPerChunk;
|
int chunkBytes = dev->data_bytes_per_chunk;
|
||||||
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
|
loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
|
||||||
struct mtd_oob_ops ops;
|
struct mtd_oob_ops ops;
|
||||||
yaffs_PackedTags1 pt1;
|
yaffs_PackedTags1 pt1;
|
||||||
int retval;
|
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_PackedTags1) == 12);
|
||||||
compile_time_assertion(sizeof(yaffs_Tags) == 8);
|
compile_time_assertion(sizeof(yaffs_tags_t) == 8);
|
||||||
|
|
||||||
dev->nPageWrites++;
|
|
||||||
|
|
||||||
yaffs_PackTags1(&pt1, etags);
|
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
|
/* 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
|
* 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
|
* that only zeroed-bits stick and set tag bytes to all-ones and
|
||||||
* zero just the (not) deleted bit.
|
* zero just the (not) deleted bit.
|
||||||
*/
|
*/
|
||||||
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||||
if (etags->chunkDeleted) {
|
if (etags->is_deleted) {
|
||||||
memset(&pt1, 0xff, 8);
|
memset(&pt1, 0xff, 8);
|
||||||
/* clear delete status bit to indicate deleted */
|
/* clear delete status bit to indicate deleted */
|
||||||
pt1.deleted = 0;
|
pt1.deleted = 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
((__u8 *)&pt1)[8] = 0xff;
|
((__u8 *)&pt1)[8] = 0xff;
|
||||||
if (etags->chunkDeleted) {
|
if (etags->is_deleted) {
|
||||||
memset(&pt1, 0xff, 8);
|
memset(&pt1, 0xff, 8);
|
||||||
/* zero pageStatus byte to indicate deleted */
|
/* zero page_status byte to indicate deleted */
|
||||||
((__u8 *)&pt1)[8] = 0;
|
((__u8 *)&pt1)[8] = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -137,20 +135,20 @@ int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
|
||||||
|
|
||||||
retval = mtd->write_oob(mtd, addr, &ops);
|
retval = mtd->write_oob(mtd, addr, &ops);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
yaffs_trace(YAFFS_TRACE_MTD,
|
T(YAFFS_TRACE_MTD,
|
||||||
"write_oob failed, chunk %d, mtd error %d\n",
|
(TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
|
||||||
chunkInNAND, retval);
|
nand_chunk, retval));
|
||||||
}
|
}
|
||||||
return retval ? YAFFS_FAIL : YAFFS_OK;
|
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) {
|
if (etags) {
|
||||||
memset(etags, 0, sizeof(*etags));
|
memset(etags, 0, sizeof(*etags));
|
||||||
etags->eccResult = eccResult;
|
etags->ecc_result = ecc_result;
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -158,30 +156,28 @@ static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval)
|
||||||
/* Read a chunk (page) from NAND.
|
/* Read a chunk (page) from NAND.
|
||||||
*
|
*
|
||||||
* Caller expects ExtendedTags data to be usable even on error; that is,
|
* 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 ECC results for data (if applicable)
|
||||||
* - Check for blank/erased block (return empty ExtendedTags if blank)
|
* - Check for blank/erased block (return empty ExtendedTags if blank)
|
||||||
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
|
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
|
||||||
* - Convert PackedTags1 to ExtendedTags
|
* - 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.
|
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||||
*/
|
*/
|
||||||
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev,
|
||||||
int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)
|
int nand_chunk, __u8 *data, yaffs_ext_tags *etags)
|
||||||
{
|
{
|
||||||
struct mtd_info *mtd = dev->genericDevice;
|
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||||
int chunkBytes = dev->nDataBytesPerChunk;
|
int chunkBytes = dev->data_bytes_per_chunk;
|
||||||
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
|
loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
|
||||||
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
|
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
|
||||||
struct mtd_oob_ops ops;
|
struct mtd_oob_ops ops;
|
||||||
yaffs_PackedTags1 pt1;
|
yaffs_PackedTags1 pt1;
|
||||||
int retval;
|
int retval;
|
||||||
int deleted;
|
int deleted;
|
||||||
|
|
||||||
dev->nPageReads++;
|
|
||||||
|
|
||||||
memset(&ops, 0, sizeof(ops));
|
memset(&ops, 0, sizeof(ops));
|
||||||
ops.mode = MTD_OOB_AUTO;
|
ops.mode = MTD_OOB_AUTO;
|
||||||
ops.len = (data) ? chunkBytes : 0;
|
ops.len = (data) ? chunkBytes : 0;
|
||||||
|
@ -200,9 +196,9 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||||
*/
|
*/
|
||||||
retval = mtd->read_oob(mtd, addr, &ops);
|
retval = mtd->read_oob(mtd, addr, &ops);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
yaffs_trace(YAFFS_TRACE_MTD,
|
T(YAFFS_TRACE_MTD,
|
||||||
"read_oob failed, chunk %d, mtd error %d\n",
|
(TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
|
||||||
chunkInNAND, retval);
|
nand_chunk, retval));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
|
@ -213,23 +209,23 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||||
case -EUCLEAN:
|
case -EUCLEAN:
|
||||||
/* MTD's ECC fixed the data */
|
/* MTD's ECC fixed the data */
|
||||||
eccres = YAFFS_ECC_RESULT_FIXED;
|
eccres = YAFFS_ECC_RESULT_FIXED;
|
||||||
dev->eccFixed++;
|
dev->n_ecc_fixed++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -EBADMSG:
|
case -EBADMSG:
|
||||||
/* MTD's ECC could not fix the data */
|
/* MTD's ECC could not fix the data */
|
||||||
dev->eccUnfixed++;
|
dev->n_ecc_unfixed++;
|
||||||
/* fall into... */
|
/* fall into... */
|
||||||
default:
|
default:
|
||||||
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
|
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;
|
return YAFFS_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for a blank/erased chunk.
|
/* Check for a blank/erased chunk.
|
||||||
*/
|
*/
|
||||||
if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
|
if (yaffs_check_ff((__u8 *)&pt1, 8)) {
|
||||||
/* when blank, upper layers want eccResult to be <= NO_ERROR */
|
/* when blank, upper layers want ecc_result to be <= NO_ERROR */
|
||||||
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
|
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,37 +237,37 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||||
deleted = !pt1.deleted;
|
deleted = !pt1.deleted;
|
||||||
pt1.deleted = 1;
|
pt1.deleted = 1;
|
||||||
#else
|
#else
|
||||||
deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
|
deleted = (yaffs_count_bits(((__u8 *)&pt1)[8]) < 7);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Check the packed tags mini-ECC and correct if necessary/possible.
|
/* 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) {
|
switch (retval) {
|
||||||
case 0:
|
case 0:
|
||||||
/* no tags error, use MTD result */
|
/* no tags error, use MTD result */
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* recovered tags-ECC error */
|
/* recovered tags-ECC error */
|
||||||
dev->tagsEccFixed++;
|
dev->n_tags_ecc_fixed++;
|
||||||
if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
|
if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
|
||||||
eccres = YAFFS_ECC_RESULT_FIXED;
|
eccres = YAFFS_ECC_RESULT_FIXED;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* unrecovered tags-ECC error */
|
/* unrecovered tags-ECC error */
|
||||||
dev->tagsEccUnfixed++;
|
dev->n_tags_ecc_unfixed++;
|
||||||
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
|
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unpack the tags to extended form and set ECC result.
|
/* 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;
|
pt1.shouldBeFF = 0xFFFFFFFF;
|
||||||
yaffs_UnpackTags1(etags, &pt1);
|
yaffs_unpack_tags1(etags, &pt1);
|
||||||
etags->eccResult = eccres;
|
etags->ecc_result = eccres;
|
||||||
|
|
||||||
/* Set deleted state */
|
/* Set deleted state */
|
||||||
etags->chunkDeleted = deleted;
|
etags->is_deleted = deleted;
|
||||||
return YAFFS_OK;
|
return YAFFS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,15 +278,15 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||||
*
|
*
|
||||||
* Returns YAFFS_OK or YAFFS_FAIL.
|
* 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;
|
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||||
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
|
int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
|
||||||
int retval;
|
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;
|
return (retval) ? YAFFS_FAIL : YAFFS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,9 +301,9 @@ static int nandmtd1_TestPrerequists(struct mtd_info *mtd)
|
||||||
int oobavail = mtd->ecclayout->oobavail;
|
int oobavail = mtd->ecclayout->oobavail;
|
||||||
|
|
||||||
if (oobavail < YTAG1_SIZE) {
|
if (oobavail < YTAG1_SIZE) {
|
||||||
yaffs_trace(YAFFS_TRACE_ERROR,
|
T(YAFFS_TRACE_ERROR,
|
||||||
"mtd device has only %d bytes for tags, need %d\n",
|
(TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR),
|
||||||
oobavail, YTAG1_SIZE);
|
oobavail, YTAG1_SIZE));
|
||||||
return YAFFS_FAIL;
|
return YAFFS_FAIL;
|
||||||
}
|
}
|
||||||
return YAFFS_OK;
|
return YAFFS_OK;
|
||||||
|
@ -322,13 +318,13 @@ static int nandmtd1_TestPrerequists(struct mtd_info *mtd)
|
||||||
*
|
*
|
||||||
* Always returns YAFFS_OK.
|
* Always returns YAFFS_OK.
|
||||||
*/
|
*/
|
||||||
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
|
||||||
yaffs_BlockState *pState, __u32 *pSequenceNumber)
|
yaffs_block_state_t *pState, __u32 *pSequenceNumber)
|
||||||
{
|
{
|
||||||
struct mtd_info *mtd = dev->genericDevice;
|
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||||
int chunkNo = blockNo * dev->nChunksPerBlock;
|
int chunkNo = block_no * dev->param.chunks_per_block;
|
||||||
loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
|
loff_t addr = (loff_t)chunkNo * dev->data_bytes_per_chunk;
|
||||||
yaffs_ExtendedTags etags;
|
yaffs_ext_tags etags;
|
||||||
int state = YAFFS_BLOCK_STATE_DEAD;
|
int state = YAFFS_BLOCK_STATE_DEAD;
|
||||||
int seqnum = 0;
|
int seqnum = 0;
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -340,17 +336,17 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||||
return YAFFS_FAIL;
|
return YAFFS_FAIL;
|
||||||
|
|
||||||
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
|
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
|
||||||
etags.blockBad = (mtd->block_isbad)(mtd, addr);
|
etags.block_bad = (mtd->block_isbad)(mtd, addr);
|
||||||
if (etags.blockBad) {
|
if (etags.block_bad) {
|
||||||
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
|
T(YAFFS_TRACE_BAD_BLOCKS,
|
||||||
"block %d is marked bad\n", blockNo);
|
(TSTR("block %d is marked bad"TENDSTR), block_no));
|
||||||
state = YAFFS_BLOCK_STATE_DEAD;
|
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 */
|
/* bad tags, need to look more closely */
|
||||||
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||||
} else if (etags.chunkUsed) {
|
} else if (etags.chunk_used) {
|
||||||
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||||
seqnum = etags.sequenceNumber;
|
seqnum = etags.seq_number;
|
||||||
} else {
|
} else {
|
||||||
state = YAFFS_BLOCK_STATE_EMPTY;
|
state = YAFFS_BLOCK_STATE_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System. A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -14,15 +14,15 @@
|
||||||
#ifndef __YAFFS_MTDIF1_H__
|
#ifndef __YAFFS_MTDIF1_H__
|
||||||
#define __YAFFS_MTDIF1_H__
|
#define __YAFFS_MTDIF1_H__
|
||||||
|
|
||||||
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
|
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
|
||||||
const __u8 *data, const yaffs_ExtendedTags *tags);
|
const __u8 *data, const yaffs_ext_tags *tags);
|
||||||
|
|
||||||
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
|
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
|
||||||
__u8 *data, yaffs_ExtendedTags *tags);
|
__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,
|
int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
|
||||||
yaffs_BlockState *state, __u32 *sequenceNumber);
|
yaffs_block_state_t *state, __u32 *seq_number);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -13,11 +13,8 @@
|
||||||
|
|
||||||
/* mtd interface for YAFFS2 */
|
/* 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 "yportenv.h"
|
||||||
|
#include "yaffs_trace.h"
|
||||||
|
|
||||||
#include "yaffs_mtdif2.h"
|
#include "yaffs_mtdif2.h"
|
||||||
|
|
||||||
|
@ -27,15 +24,17 @@ const char *yaffs_mtdif2_c_version =
|
||||||
|
|
||||||
#include "yaffs_packedtags2.h"
|
#include "yaffs_packedtags2.h"
|
||||||
|
|
||||||
|
#include "yaffs_linux.h"
|
||||||
|
|
||||||
/* NB For use with inband tags....
|
/* NB For use with inband tags....
|
||||||
* We assume that the data buffer is of size totalBytersPerChunk so that we can also
|
* We assume that the data buffer is of size totalBytersPerChunk so that we can also
|
||||||
* use it to load the tags.
|
* 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 __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))
|
#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
|
||||||
struct mtd_oob_ops ops;
|
struct mtd_oob_ops ops;
|
||||||
#else
|
#else
|
||||||
|
@ -47,13 +46,16 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
|
||||||
|
|
||||||
yaffs_PackedTags2 pt;
|
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,
|
T(YAFFS_TRACE_MTD,
|
||||||
(TSTR
|
(TSTR
|
||||||
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
|
("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.
|
/* For yaffs2 writing there must be both data and tags.
|
||||||
* If we're using inband tags, then the tags are stuffed into
|
* 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)
|
if (!data || !tags)
|
||||||
BUG();
|
BUG();
|
||||||
else if (dev->inbandTags) {
|
else if (dev->param.inband_tags) {
|
||||||
yaffs_PackedTags2TagsPart *pt2tp;
|
yaffs_PackedTags2TagsPart *pt2tp;
|
||||||
pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
|
pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->data_bytes_per_chunk);
|
||||||
yaffs_PackTags2TagsPart(pt2tp, tags);
|
yaffs_PackTags2TagsPart(pt2tp, tags);
|
||||||
} else
|
} else
|
||||||
yaffs_PackTags2(&pt, tags);
|
yaffs_PackTags2(&pt, tags, !dev->param.no_tags_ecc);
|
||||||
|
|
||||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
|
||||||
ops.mode = MTD_OOB_AUTO;
|
ops.mode = MTD_OOB_AUTO;
|
||||||
ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
|
ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
|
||||||
ops.len = dev->totalBytesPerChunk;
|
ops.len = dev->param.total_bytes_per_chunk;
|
||||||
ops.ooboffs = 0;
|
ops.ooboffs = 0;
|
||||||
ops.datbuf = (__u8 *)data;
|
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);
|
retval = mtd->write_oob(mtd, addr, &ops);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
if (!dev->inbandTags) {
|
if (!dev->param.inband_tags) {
|
||||||
retval =
|
retval =
|
||||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
|
||||||
&dummy, data, (__u8 *) &pt, NULL);
|
&dummy, data, (__u8 *) packed_tags_ptr, NULL);
|
||||||
} else {
|
} else {
|
||||||
retval =
|
retval =
|
||||||
mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
|
mtd->write(mtd, addr, dev->param.total_bytes_per_chunk, &dummy,
|
||||||
data);
|
data);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -95,10 +97,10 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
|
||||||
return YAFFS_FAIL;
|
return YAFFS_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
|
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
|
||||||
__u8 *data, yaffs_ExtendedTags *tags)
|
__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))
|
#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
|
||||||
struct mtd_oob_ops ops;
|
struct mtd_oob_ops ops;
|
||||||
#endif
|
#endif
|
||||||
|
@ -106,20 +108,23 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
int localData = 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;
|
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,
|
T(YAFFS_TRACE_MTD,
|
||||||
(TSTR
|
(TSTR
|
||||||
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
|
("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) {
|
if (!data) {
|
||||||
localData = 1;
|
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 (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
|
||||||
if (dev->inbandTags || (data && !tags))
|
if (dev->param.inband_tags || (data && !tags))
|
||||||
retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
|
retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
|
||||||
&dummy, data);
|
&dummy, data);
|
||||||
else if (tags) {
|
else if (tags) {
|
||||||
ops.mode = MTD_OOB_AUTO;
|
ops.mode = MTD_OOB_AUTO;
|
||||||
ops.ooblen = sizeof(pt);
|
ops.ooblen = packed_tags_size;
|
||||||
ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
|
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
|
||||||
ops.ooboffs = 0;
|
ops.ooboffs = 0;
|
||||||
ops.datbuf = data;
|
ops.datbuf = data;
|
||||||
ops.oobbuf = dev->spareBuffer;
|
ops.oobbuf = yaffs_dev_to_lc(dev)->spareBuffer;
|
||||||
retval = mtd->read_oob(mtd, addr, &ops);
|
retval = mtd->read_oob(mtd, addr, &ops);
|
||||||
}
|
}
|
||||||
#else
|
#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,
|
&dummy, data, dev->spareBuffer,
|
||||||
NULL);
|
NULL);
|
||||||
} else {
|
} else {
|
||||||
if (data)
|
if (data)
|
||||||
retval =
|
retval =
|
||||||
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
mtd->read(mtd, addr, dev->data_bytes_per_chunk, &dummy,
|
||||||
data);
|
data);
|
||||||
if (!dev->inbandTags && tags)
|
if (!dev->param.inband_tags && tags)
|
||||||
retval =
|
retval =
|
||||||
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
|
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||||
dev->spareBuffer);
|
dev->spareBuffer);
|
||||||
|
@ -158,41 +163,47 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
if (dev->inbandTags) {
|
if (dev->param.inband_tags) {
|
||||||
if (tags) {
|
if (tags) {
|
||||||
yaffs_PackedTags2TagsPart *pt2tp;
|
yaffs_PackedTags2TagsPart *pt2tp;
|
||||||
pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
|
pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->data_bytes_per_chunk];
|
||||||
yaffs_UnpackTags2TagsPart(tags, pt2tp);
|
yaffs_unpack_tags2tags_part(tags, pt2tp);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (tags) {
|
if (tags) {
|
||||||
memcpy(&pt, dev->spareBuffer, sizeof(pt));
|
memcpy(packed_tags_ptr, yaffs_dev_to_lc(dev)->spareBuffer, packed_tags_size);
|
||||||
yaffs_UnpackTags2(tags, &pt);
|
yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localData)
|
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)
|
if (tags && retval == -EBADMSG && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
|
||||||
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
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)
|
if (retval == 0)
|
||||||
return YAFFS_OK;
|
return YAFFS_OK;
|
||||||
else
|
else
|
||||||
return YAFFS_FAIL;
|
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;
|
int retval;
|
||||||
T(YAFFS_TRACE_MTD,
|
T(YAFFS_TRACE_MTD,
|
||||||
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
|
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), block_no));
|
||||||
|
|
||||||
retval =
|
retval =
|
||||||
mtd->block_markbad(mtd,
|
mtd->block_markbad(mtd,
|
||||||
blockNo * dev->nChunksPerBlock *
|
block_no * dev->param.chunks_per_block *
|
||||||
dev->totalBytesPerChunk);
|
dev->param.total_bytes_per_chunk);
|
||||||
|
|
||||||
if (retval == 0)
|
if (retval == 0)
|
||||||
return YAFFS_OK;
|
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,
|
int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
|
||||||
yaffs_BlockState *state, __u32 *sequenceNumber)
|
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;
|
int retval;
|
||||||
|
|
||||||
T(YAFFS_TRACE_MTD,
|
T(YAFFS_TRACE_MTD,
|
||||||
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
|
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), block_no));
|
||||||
retval =
|
retval =
|
||||||
mtd->block_isbad(mtd,
|
mtd->block_isbad(mtd,
|
||||||
blockNo * dev->nChunksPerBlock *
|
block_no * dev->param.chunks_per_block *
|
||||||
dev->totalBytesPerChunk);
|
dev->param.total_bytes_per_chunk);
|
||||||
|
|
||||||
if (retval) {
|
if (retval) {
|
||||||
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
|
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
|
||||||
|
|
||||||
*state = YAFFS_BLOCK_STATE_DEAD;
|
*state = YAFFS_BLOCK_STATE_DEAD;
|
||||||
*sequenceNumber = 0;
|
*seq_number = 0;
|
||||||
} else {
|
} else {
|
||||||
yaffs_ExtendedTags t;
|
yaffs_ext_tags t;
|
||||||
nandmtd2_ReadChunkWithTagsFromNAND(dev,
|
nandmtd2_ReadChunkWithTagsFromNAND(dev,
|
||||||
blockNo *
|
block_no *
|
||||||
dev->nChunksPerBlock, NULL,
|
dev->param.chunks_per_block, NULL,
|
||||||
&t);
|
&t);
|
||||||
|
|
||||||
if (t.chunkUsed) {
|
if (t.chunk_used) {
|
||||||
*sequenceNumber = t.sequenceNumber;
|
*seq_number = t.seq_number;
|
||||||
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||||
} else {
|
} else {
|
||||||
*sequenceNumber = 0;
|
*seq_number = 0;
|
||||||
*state = YAFFS_BLOCK_STATE_EMPTY;
|
*state = YAFFS_BLOCK_STATE_EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
T(YAFFS_TRACE_MTD,
|
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));
|
*state));
|
||||||
|
|
||||||
if (retval == 0)
|
if (retval == 0)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -17,13 +17,13 @@
|
||||||
#define __YAFFS_MTDIF2_H__
|
#define __YAFFS_MTDIF2_H__
|
||||||
|
|
||||||
#include "yaffs_guts.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 __u8 *data,
|
||||||
const yaffs_ExtendedTags *tags);
|
const yaffs_ext_tags *tags);
|
||||||
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
|
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
|
||||||
__u8 *data, yaffs_ExtendedTags *tags);
|
__u8 *data, yaffs_ext_tags *tags);
|
||||||
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
|
||||||
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
|
||||||
yaffs_BlockState *state, __u32 *sequenceNumber);
|
yaffs_block_state_t *state, __u32 *seq_number);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -11,124 +11,129 @@
|
||||||
* published by the Free Software Foundation.
|
* 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_nand.h"
|
||||||
#include "yaffs_tagscompat.h"
|
#include "yaffs_tagscompat.h"
|
||||||
#include "yaffs_tagsvalidity.h"
|
#include "yaffs_tagsvalidity.h"
|
||||||
|
|
||||||
#include "yaffs_getblockinfo.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,
|
__u8 *buffer,
|
||||||
yaffs_ExtendedTags *tags)
|
yaffs_ext_tags *tags)
|
||||||
{
|
{
|
||||||
int result;
|
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 there are no tags provided, use local tags to get prioritised gc working */
|
||||||
if (!tags)
|
if (!tags)
|
||||||
tags = &localTags;
|
tags = &localTags;
|
||||||
|
|
||||||
if (dev->readChunkWithTagsFromNAND)
|
if (dev->param.read_chunk_tags_fn)
|
||||||
result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
|
result = dev->param.read_chunk_tags_fn(dev, realignedChunkInNAND, buffer,
|
||||||
tags);
|
tags);
|
||||||
else
|
else
|
||||||
result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
|
result = yaffs_tags_compat_rd(dev,
|
||||||
realignedChunkInNAND,
|
realignedChunkInNAND,
|
||||||
buffer,
|
buffer,
|
||||||
tags);
|
tags);
|
||||||
if (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_block_info_t *bi;
|
||||||
yaffs_HandleChunkError(dev, bi);
|
bi = yaffs_get_block_info(dev, nand_chunk/dev->param.chunks_per_block);
|
||||||
|
yaffs_handle_chunk_error(dev, bi);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
|
int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev,
|
||||||
int chunkInNAND,
|
int nand_chunk,
|
||||||
const __u8 *buffer,
|
const __u8 *buffer,
|
||||||
yaffs_ExtendedTags *tags)
|
yaffs_ext_tags *tags)
|
||||||
{
|
{
|
||||||
chunkInNAND -= dev->chunkOffset;
|
|
||||||
|
dev->n_page_writes++;
|
||||||
|
|
||||||
|
nand_chunk -= dev->chunk_offset;
|
||||||
|
|
||||||
|
|
||||||
if (tags) {
|
if (tags) {
|
||||||
tags->sequenceNumber = dev->sequenceNumber;
|
tags->seq_number = dev->seq_number;
|
||||||
tags->chunkUsed = 1;
|
tags->chunk_used = 1;
|
||||||
if (!yaffs_ValidateTags(tags)) {
|
if (!yaffs_validate_tags(tags)) {
|
||||||
T(YAFFS_TRACE_ERROR,
|
T(YAFFS_TRACE_ERROR,
|
||||||
(TSTR("Writing uninitialised tags" TENDSTR)));
|
(TSTR("Writing uninitialised tags" TENDSTR)));
|
||||||
YBUG();
|
YBUG();
|
||||||
}
|
}
|
||||||
T(YAFFS_TRACE_WRITE,
|
T(YAFFS_TRACE_WRITE,
|
||||||
(TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
|
(TSTR("Writing chunk %d tags %d %d" TENDSTR), nand_chunk,
|
||||||
tags->objectId, tags->chunkId));
|
tags->obj_id, tags->chunk_id));
|
||||||
} else {
|
} else {
|
||||||
T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
|
T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
|
||||||
YBUG();
|
YBUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->writeChunkWithTagsToNAND)
|
if (dev->param.write_chunk_tags_fn)
|
||||||
return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
|
return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer,
|
||||||
tags);
|
tags);
|
||||||
else
|
else
|
||||||
return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
|
return yaffs_tags_compat_wr(dev,
|
||||||
chunkInNAND,
|
nand_chunk,
|
||||||
buffer,
|
buffer,
|
||||||
tags);
|
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)
|
if (dev->param.bad_block_fn)
|
||||||
return dev->markNANDBlockBad(dev, blockNo);
|
return dev->param.bad_block_fn(dev, block_no);
|
||||||
else
|
else
|
||||||
return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
|
return yaffs_tags_compat_mark_bad(dev, block_no);
|
||||||
}
|
}
|
||||||
|
|
||||||
int yaffs_QueryInitialBlockState(yaffs_Device *dev,
|
int yaffs_query_init_block_state(yaffs_dev_t *dev,
|
||||||
int blockNo,
|
int block_no,
|
||||||
yaffs_BlockState *state,
|
yaffs_block_state_t *state,
|
||||||
__u32 *sequenceNumber)
|
__u32 *seq_number)
|
||||||
{
|
{
|
||||||
blockNo -= dev->blockOffset;
|
block_no -= dev->block_offset;
|
||||||
|
|
||||||
if (dev->queryNANDBlock)
|
if (dev->param.query_block_fn)
|
||||||
return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
|
return dev->param.query_block_fn(dev, block_no, state, seq_number);
|
||||||
else
|
else
|
||||||
return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
|
return yaffs_tags_compat_query_block(dev, block_no,
|
||||||
state,
|
state,
|
||||||
sequenceNumber);
|
seq_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
int yaffs_erase_block(struct yaffs_dev_s *dev,
|
||||||
int blockInNAND)
|
int flash_block)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
blockInNAND -= dev->blockOffset;
|
flash_block -= dev->block_offset;
|
||||||
|
|
||||||
|
dev->n_erasures++;
|
||||||
|
|
||||||
dev->nBlockErasures++;
|
result = dev->param.erase_fn(dev, flash_block);
|
||||||
result = dev->eraseBlockInNAND(dev, blockInNAND);
|
|
||||||
|
|
||||||
return result;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* 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,
|
__u8 *buffer,
|
||||||
yaffs_ExtendedTags *tags);
|
yaffs_ext_tags *tags);
|
||||||
|
|
||||||
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
|
int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev,
|
||||||
int chunkInNAND,
|
int nand_chunk,
|
||||||
const __u8 *buffer,
|
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 yaffs_query_init_block_state(yaffs_dev_t *dev,
|
||||||
int blockNo,
|
int block_no,
|
||||||
yaffs_BlockState *state,
|
yaffs_block_state_t *state,
|
||||||
unsigned *sequenceNumber);
|
unsigned *seq_number);
|
||||||
|
|
||||||
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
int yaffs_erase_block(struct yaffs_dev_s *dev,
|
||||||
int blockInNAND);
|
int flash_block);
|
||||||
|
|
||||||
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
|
int yaffs_init_nand(struct yaffs_dev_s *dev);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -20,18 +20,18 @@
|
||||||
|
|
||||||
#include "yaffs_guts.h"
|
#include "yaffs_guts.h"
|
||||||
|
|
||||||
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
|
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_dev_s *dev,
|
||||||
int chunkInNAND, const __u8 *data,
|
int nand_chunk, const __u8 *data,
|
||||||
const yaffs_ExtendedTags *tags);
|
const yaffs_ext_tags *tags);
|
||||||
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
|
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_dev_s *dev,
|
||||||
int chunkInNAND, __u8 *data,
|
int nand_chunk, __u8 *data,
|
||||||
yaffs_ExtendedTags *tags);
|
yaffs_ext_tags *tags);
|
||||||
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
int nandemul2k_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
|
||||||
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
int nandemul2k_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
|
||||||
yaffs_BlockState *state, __u32 *sequenceNumber);
|
yaffs_block_state_t *state, __u32 *seq_number);
|
||||||
int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
int nandemul2k_EraseBlockInNAND(struct yaffs_dev_s *dev,
|
||||||
int blockInNAND);
|
int flash_block);
|
||||||
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
|
int nandemul2k_InitialiseNAND(struct yaffs_dev_s *dev);
|
||||||
int nandemul2k_GetBytesPerChunk(void);
|
int nandemul2k_GetBytesPerChunk(void);
|
||||||
int nandemul2k_GetChunksPerBlock(void);
|
int nandemul2k_GetChunksPerBlock(void);
|
||||||
int nandemul2k_GetNumberOfBlocks(void);
|
int nandemul2k_GetNumberOfBlocks(void);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -14,37 +14,37 @@
|
||||||
#include "yaffs_packedtags1.h"
|
#include "yaffs_packedtags1.h"
|
||||||
#include "yportenv.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->chunk_id = t->chunk_id;
|
||||||
pt->serialNumber = t->serialNumber;
|
pt->serial_number = t->serial_number;
|
||||||
pt->byteCount = t->byteCount;
|
pt->n_bytes = t->n_bytes;
|
||||||
pt->objectId = t->objectId;
|
pt->obj_id = t->obj_id;
|
||||||
pt->ecc = 0;
|
pt->ecc = 0;
|
||||||
pt->deleted = (t->chunkDeleted) ? 0 : 1;
|
pt->deleted = (t->is_deleted) ? 0 : 1;
|
||||||
pt->unusedStuff = 0;
|
pt->unusedStuff = 0;
|
||||||
pt->shouldBeFF = 0xFFFFFFFF;
|
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[] =
|
static const __u8 allFF[] =
|
||||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
0xff };
|
0xff };
|
||||||
|
|
||||||
if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
|
if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
|
||||||
t->blockBad = 0;
|
t->block_bad = 0;
|
||||||
if (pt->shouldBeFF != 0xFFFFFFFF)
|
if (pt->shouldBeFF != 0xFFFFFFFF)
|
||||||
t->blockBad = 1;
|
t->block_bad = 1;
|
||||||
t->chunkUsed = 1;
|
t->chunk_used = 1;
|
||||||
t->objectId = pt->objectId;
|
t->obj_id = pt->obj_id;
|
||||||
t->chunkId = pt->chunkId;
|
t->chunk_id = pt->chunk_id;
|
||||||
t->byteCount = pt->byteCount;
|
t->n_bytes = pt->n_bytes;
|
||||||
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
|
||||||
t->chunkDeleted = (pt->deleted) ? 0 : 1;
|
t->is_deleted = (pt->deleted) ? 0 : 1;
|
||||||
t->serialNumber = pt->serialNumber;
|
t->serial_number = pt->serial_number;
|
||||||
} else {
|
} else {
|
||||||
memset(t, 0, sizeof(yaffs_ExtendedTags));
|
memset(t, 0, sizeof(yaffs_ext_tags));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -21,10 +21,10 @@
|
||||||
#include "yaffs_guts.h"
|
#include "yaffs_guts.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned chunkId:20;
|
unsigned chunk_id:20;
|
||||||
unsigned serialNumber:2;
|
unsigned serial_number:2;
|
||||||
unsigned byteCount:10;
|
unsigned n_bytes:10;
|
||||||
unsigned objectId:18;
|
unsigned obj_id:18;
|
||||||
unsigned ecc:12;
|
unsigned ecc:12;
|
||||||
unsigned deleted:1;
|
unsigned deleted:1;
|
||||||
unsigned unusedStuff:1;
|
unsigned unusedStuff:1;
|
||||||
|
@ -32,6 +32,6 @@ typedef struct {
|
||||||
|
|
||||||
} yaffs_PackedTags1;
|
} yaffs_PackedTags1;
|
||||||
|
|
||||||
void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t);
|
void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t);
|
||||||
void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt);
|
void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "yaffs_packedtags2.h"
|
#include "yaffs_packedtags2.h"
|
||||||
#include "yportenv.h"
|
#include "yportenv.h"
|
||||||
|
#include "yaffs_trace.h"
|
||||||
#include "yaffs_tagsvalidity.h"
|
#include "yaffs_tagsvalidity.h"
|
||||||
|
|
||||||
/* This code packs a set of extended tags into a binary structure for
|
/* 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.
|
* 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_HEADER_INFO_FLAG 0x80000000
|
||||||
#define EXTRA_SHRINK_FLAG 0x40000000
|
#define EXTRA_SHRINK_FLAG 0x40000000
|
||||||
|
@ -42,53 +43,53 @@ static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt)
|
||||||
{
|
{
|
||||||
T(YAFFS_TRACE_MTD,
|
T(YAFFS_TRACE_MTD,
|
||||||
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
|
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
|
||||||
ptt->objectId, ptt->chunkId, ptt->byteCount,
|
ptt->obj_id, ptt->chunk_id, ptt->n_bytes,
|
||||||
ptt->sequenceNumber));
|
ptt->seq_number));
|
||||||
}
|
}
|
||||||
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
|
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
|
||||||
{
|
{
|
||||||
yaffs_DumpPackedTags2TagsPart(&pt->t);
|
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,
|
T(YAFFS_TRACE_MTD,
|
||||||
(TSTR
|
(TSTR
|
||||||
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
|
("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,
|
TENDSTR), t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
|
||||||
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
|
t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
|
||||||
t->sequenceNumber));
|
t->seq_number));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt,
|
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt,
|
||||||
const yaffs_ExtendedTags *t)
|
const yaffs_ext_tags *t)
|
||||||
{
|
{
|
||||||
ptt->chunkId = t->chunkId;
|
ptt->chunk_id = t->chunk_id;
|
||||||
ptt->sequenceNumber = t->sequenceNumber;
|
ptt->seq_number = t->seq_number;
|
||||||
ptt->byteCount = t->byteCount;
|
ptt->n_bytes = t->n_bytes;
|
||||||
ptt->objectId = t->objectId;
|
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 */
|
/* Store the extra header info instead */
|
||||||
/* We save the parent object in the chunkId */
|
/* We save the parent object in the chunk_id */
|
||||||
ptt->chunkId = EXTRA_HEADER_INFO_FLAG
|
ptt->chunk_id = EXTRA_HEADER_INFO_FLAG
|
||||||
| t->extraParentObjectId;
|
| t->extra_parent_id;
|
||||||
if (t->extraIsShrinkHeader)
|
if (t->extra_is_shrink)
|
||||||
ptt->chunkId |= EXTRA_SHRINK_FLAG;
|
ptt->chunk_id |= EXTRA_SHRINK_FLAG;
|
||||||
if (t->extraShadows)
|
if (t->extra_shadows)
|
||||||
ptt->chunkId |= EXTRA_SHADOWS_FLAG;
|
ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
|
||||||
|
|
||||||
ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||||
ptt->objectId |=
|
ptt->obj_id |=
|
||||||
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
|
(t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
|
||||||
|
|
||||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
|
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
|
||||||
ptt->byteCount = t->extraEquivalentObjectId;
|
ptt->n_bytes = t->extra_equiv_id;
|
||||||
else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE)
|
else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
|
||||||
ptt->byteCount = t->extraFileLength;
|
ptt->n_bytes = t->extra_length;
|
||||||
else
|
else
|
||||||
ptt->byteCount = 0;
|
ptt->n_bytes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
yaffs_DumpPackedTags2TagsPart(ptt);
|
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);
|
yaffs_PackTags2TagsPart(&pt->t, t);
|
||||||
|
|
||||||
#ifndef YAFFS_IGNORE_TAGS_ECC
|
if(tagsECC)
|
||||||
{
|
yaffs_ecc_calc_other((unsigned char *)&pt->t,
|
||||||
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
|
|
||||||
sizeof(yaffs_PackedTags2TagsPart),
|
sizeof(yaffs_PackedTags2TagsPart),
|
||||||
&pt->ecc);
|
&pt->ecc);
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t,
|
void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t,
|
||||||
yaffs_PackedTags2TagsPart *ptt)
|
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) {
|
if (ptt->seq_number != 0xFFFFFFFF) {
|
||||||
t->blockBad = 0;
|
t->block_bad = 0;
|
||||||
t->chunkUsed = 1;
|
t->chunk_used = 1;
|
||||||
t->objectId = ptt->objectId;
|
t->obj_id = ptt->obj_id;
|
||||||
t->chunkId = ptt->chunkId;
|
t->chunk_id = ptt->chunk_id;
|
||||||
t->byteCount = ptt->byteCount;
|
t->n_bytes = ptt->n_bytes;
|
||||||
t->chunkDeleted = 0;
|
t->is_deleted = 0;
|
||||||
t->serialNumber = 0;
|
t->serial_number = 0;
|
||||||
t->sequenceNumber = ptt->sequenceNumber;
|
t->seq_number = ptt->seq_number;
|
||||||
|
|
||||||
/* Do extra header info stuff */
|
/* Do extra header info stuff */
|
||||||
|
|
||||||
if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) {
|
if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
|
||||||
t->chunkId = 0;
|
t->chunk_id = 0;
|
||||||
t->byteCount = 0;
|
t->n_bytes = 0;
|
||||||
|
|
||||||
t->extraHeaderInfoAvailable = 1;
|
t->extra_available = 1;
|
||||||
t->extraParentObjectId =
|
t->extra_parent_id =
|
||||||
ptt->chunkId & (~(ALL_EXTRA_FLAGS));
|
ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
|
||||||
t->extraIsShrinkHeader =
|
t->extra_is_shrink =
|
||||||
(ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
|
(ptt->chunk_id & EXTRA_SHRINK_FLAG) ? 1 : 0;
|
||||||
t->extraShadows =
|
t->extra_shadows =
|
||||||
(ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
|
(ptt->chunk_id & EXTRA_SHADOWS_FLAG) ? 1 : 0;
|
||||||
t->extraObjectType =
|
t->extra_obj_type =
|
||||||
ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT;
|
ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
|
||||||
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||||
|
|
||||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
|
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
|
||||||
t->extraEquivalentObjectId = ptt->byteCount;
|
t->extra_equiv_id = ptt->n_bytes;
|
||||||
else
|
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.seq_number != 0xFFFFFFFF &&
|
||||||
|
tagsECC){
|
||||||
|
/* Chunk is in use and we need to do ECC */
|
||||||
|
|
||||||
if (pt->t.sequenceNumber != 0xFFFFFFFF) {
|
|
||||||
/* Page is in use */
|
|
||||||
#ifndef YAFFS_IGNORE_TAGS_ECC
|
|
||||||
{
|
|
||||||
yaffs_ECCOther ecc;
|
yaffs_ECCOther ecc;
|
||||||
int result;
|
int result;
|
||||||
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
|
yaffs_ecc_calc_other((unsigned char *)&pt->t,
|
||||||
sizeof
|
sizeof(yaffs_PackedTags2TagsPart),
|
||||||
(yaffs_PackedTags2TagsPart),
|
|
||||||
&ecc);
|
&ecc);
|
||||||
result =
|
result = yaffs_ecc_correct_other((unsigned char *)&pt->t,
|
||||||
yaffs_ECCCorrectOther((unsigned char *)&pt->t,
|
sizeof(yaffs_PackedTags2TagsPart),
|
||||||
sizeof
|
|
||||||
(yaffs_PackedTags2TagsPart),
|
|
||||||
&pt->ecc, &ecc);
|
&pt->ecc, &ecc);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case 0:
|
case 0:
|
||||||
eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
eccResult = YAFFS_ECC_RESULT_FIXED;
|
ecc_result = YAFFS_ECC_RESULT_FIXED;
|
||||||
break;
|
break;
|
||||||
case -1:
|
case -1:
|
||||||
eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
ecc_result = YAFFS_ECC_RESULT_UNFIXED;
|
||||||
break;
|
break;
|
||||||
default:
|
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_DumpPackedTags2(pt);
|
||||||
yaffs_DumpTags2(t);
|
yaffs_DumpTags2(t);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -22,10 +22,10 @@
|
||||||
#include "yaffs_ecc.h"
|
#include "yaffs_ecc.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned sequenceNumber;
|
unsigned seq_number;
|
||||||
unsigned objectId;
|
unsigned obj_id;
|
||||||
unsigned chunkId;
|
unsigned chunk_id;
|
||||||
unsigned byteCount;
|
unsigned n_bytes;
|
||||||
} yaffs_PackedTags2TagsPart;
|
} yaffs_PackedTags2TagsPart;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -34,10 +34,10 @@ typedef struct {
|
||||||
} yaffs_PackedTags2;
|
} yaffs_PackedTags2;
|
||||||
|
|
||||||
/* Full packed tags with ECC, used for oob tags */
|
/* Full packed tags with ECC, used for oob tags */
|
||||||
void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t);
|
void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC);
|
||||||
void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt);
|
void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC);
|
||||||
|
|
||||||
/* Only the tags part (no ECC for use with inband tags */
|
/* Only the tags part (no ECC for use with inband tags */
|
||||||
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t);
|
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ext_tags *t);
|
||||||
void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, yaffs_PackedTags2TagsPart *pt);
|
void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t, yaffs_PackedTags2TagsPart *pt);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -17,7 +17,18 @@
|
||||||
#ifndef __YAFFS_QSORT_H__
|
#ifndef __YAFFS_QSORT_H__
|
||||||
#define __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,
|
extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
|
||||||
int (*cmp)(const void *, const void *));
|
int (*cmp)(const void *, const void *));
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -15,19 +15,20 @@
|
||||||
#include "yaffs_tagscompat.h"
|
#include "yaffs_tagscompat.h"
|
||||||
#include "yaffs_ecc.h"
|
#include "yaffs_ecc.h"
|
||||||
#include "yaffs_getblockinfo.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
|
#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 __u8 *data,
|
||||||
const yaffs_Spare *spare);
|
const yaffs_spare *spare);
|
||||||
static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
|
static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
|
||||||
const yaffs_Spare *spare);
|
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);
|
||||||
#endif
|
#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,
|
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,
|
||||||
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
|
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;
|
int retVal;
|
||||||
retVal = yaffs_countBitsTable[x];
|
retVal = yaffs_count_bits_table[x];
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********** Tags ECC calculations *********/
|
/********** 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_ecc_cacl(data, spare->ecc1);
|
||||||
yaffs_ECCCalculate(&data[256], spare->ecc2);
|
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 */
|
/* Calculate an ecc */
|
||||||
|
|
||||||
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
|
unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes;
|
||||||
unsigned i, j;
|
unsigned i, j;
|
||||||
unsigned ecc = 0;
|
unsigned ecc = 0;
|
||||||
unsigned bit = 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;
|
unsigned ecc = tags->ecc;
|
||||||
|
|
||||||
yaffs_CalcTagsECC(tags);
|
yaffs_calc_tags_ecc(tags);
|
||||||
|
|
||||||
ecc ^= tags->ecc;
|
ecc ^= tags->ecc;
|
||||||
|
|
||||||
if (ecc && ecc <= 64) {
|
if (ecc && ecc <= 64) {
|
||||||
/* TODO: Handle the failure better. Retire? */
|
/* TODO: Handle the failure better. Retire? */
|
||||||
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
|
unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes;
|
||||||
|
|
||||||
ecc--;
|
ecc--;
|
||||||
|
|
||||||
b[ecc / 8] ^= (1 << (ecc & 7));
|
b[ecc / 8] ^= (1 << (ecc & 7));
|
||||||
|
|
||||||
/* Now recvalc the ecc */
|
/* Now recvalc the ecc */
|
||||||
yaffs_CalcTagsECC(tags);
|
yaffs_calc_tags_ecc(tags);
|
||||||
|
|
||||||
return 1; /* recovered error */
|
return 1; /* recovered error */
|
||||||
} else if (ecc) {
|
} else if (ecc) {
|
||||||
|
@ -115,76 +116,73 @@ int yaffs_CheckECCOnTags(yaffs_Tags *tags)
|
||||||
|
|
||||||
/********** Tags **********/
|
/********** Tags **********/
|
||||||
|
|
||||||
static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr,
|
static void yaffs_load_tags_to_spare(yaffs_spare *sparePtr,
|
||||||
yaffs_Tags *tagsPtr)
|
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->tb0 = tu->as_bytes[0];
|
||||||
sparePtr->tagByte1 = tu->asBytes[1];
|
sparePtr->tb1 = tu->as_bytes[1];
|
||||||
sparePtr->tagByte2 = tu->asBytes[2];
|
sparePtr->tb2 = tu->as_bytes[2];
|
||||||
sparePtr->tagByte3 = tu->asBytes[3];
|
sparePtr->tb3 = tu->as_bytes[3];
|
||||||
sparePtr->tagByte4 = tu->asBytes[4];
|
sparePtr->tb4 = tu->as_bytes[4];
|
||||||
sparePtr->tagByte5 = tu->asBytes[5];
|
sparePtr->tb5 = tu->as_bytes[5];
|
||||||
sparePtr->tagByte6 = tu->asBytes[6];
|
sparePtr->tb6 = tu->as_bytes[6];
|
||||||
sparePtr->tagByte7 = tu->asBytes[7];
|
sparePtr->tb7 = tu->as_bytes[7];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,
|
static void yaffs_get_tags_from_spare(yaffs_dev_t *dev, yaffs_spare *sparePtr,
|
||||||
yaffs_Tags *tagsPtr)
|
yaffs_tags_t *tagsPtr)
|
||||||
{
|
{
|
||||||
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
|
yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
tu->asBytes[0] = sparePtr->tagByte0;
|
tu->as_bytes[0] = sparePtr->tb0;
|
||||||
tu->asBytes[1] = sparePtr->tagByte1;
|
tu->as_bytes[1] = sparePtr->tb1;
|
||||||
tu->asBytes[2] = sparePtr->tagByte2;
|
tu->as_bytes[2] = sparePtr->tb2;
|
||||||
tu->asBytes[3] = sparePtr->tagByte3;
|
tu->as_bytes[3] = sparePtr->tb3;
|
||||||
tu->asBytes[4] = sparePtr->tagByte4;
|
tu->as_bytes[4] = sparePtr->tb4;
|
||||||
tu->asBytes[5] = sparePtr->tagByte5;
|
tu->as_bytes[5] = sparePtr->tb5;
|
||||||
tu->asBytes[6] = sparePtr->tagByte6;
|
tu->as_bytes[6] = sparePtr->tb6;
|
||||||
tu->asBytes[7] = sparePtr->tagByte7;
|
tu->as_bytes[7] = sparePtr->tb7;
|
||||||
|
|
||||||
result = yaffs_CheckECCOnTags(tagsPtr);
|
result = yaffs_check_tags_ecc(tagsPtr);
|
||||||
if (result > 0)
|
if (result > 0)
|
||||||
dev->tagsEccFixed++;
|
dev->n_tags_ecc_fixed++;
|
||||||
else if (result < 0)
|
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,
|
static int yaffs_wr_nand(struct yaffs_dev_s *dev,
|
||||||
int chunkInNAND, const __u8 *data,
|
int nand_chunk, const __u8 *data,
|
||||||
yaffs_Spare *spare)
|
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,
|
T(YAFFS_TRACE_ERROR,
|
||||||
(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
|
(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
|
||||||
chunkInNAND));
|
nand_chunk));
|
||||||
return YAFFS_FAIL;
|
return YAFFS_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->nPageWrites++;
|
return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
|
||||||
return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
|
static int yaffs_rd_chunk_nand(struct yaffs_dev_s *dev,
|
||||||
int chunkInNAND,
|
int nand_chunk,
|
||||||
__u8 *data,
|
__u8 *data,
|
||||||
yaffs_Spare *spare,
|
yaffs_spare *spare,
|
||||||
yaffs_ECCResult *eccResult,
|
yaffs_ecc_result *ecc_result,
|
||||||
int doErrorCorrection)
|
int doErrorCorrection)
|
||||||
{
|
{
|
||||||
int retVal;
|
int retVal;
|
||||||
yaffs_Spare localSpare;
|
yaffs_spare localSpare;
|
||||||
|
|
||||||
dev->nPageReads++;
|
|
||||||
|
|
||||||
if (!spare && data) {
|
if (!spare && data) {
|
||||||
/* If we don't have a real spare, then we use a local one. */
|
/* 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;
|
spare = &localSpare;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dev->useNANDECC) {
|
if (!dev->param.use_nand_ecc) {
|
||||||
retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
|
retVal = dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
|
||||||
if (data && doErrorCorrection) {
|
if (data && doErrorCorrection) {
|
||||||
/* Do ECC correction */
|
/* Do ECC correction */
|
||||||
/* Todo handle any errors */
|
/* Todo handle any errors */
|
||||||
int eccResult1, eccResult2;
|
int ecc_result1, ecc_result2;
|
||||||
__u8 calcEcc[3];
|
__u8 calcEcc[3];
|
||||||
|
|
||||||
yaffs_ECCCalculate(data, calcEcc);
|
yaffs_ecc_cacl(data, calcEcc);
|
||||||
eccResult1 =
|
ecc_result1 =
|
||||||
yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
|
yaffs_ecc_correct(data, spare->ecc1, calcEcc);
|
||||||
yaffs_ECCCalculate(&data[256], calcEcc);
|
yaffs_ecc_cacl(&data[256], calcEcc);
|
||||||
eccResult2 =
|
ecc_result2 =
|
||||||
yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
|
yaffs_ecc_correct(&data[256], spare->ecc2, calcEcc);
|
||||||
|
|
||||||
if (eccResult1 > 0) {
|
if (ecc_result1 > 0) {
|
||||||
T(YAFFS_TRACE_ERROR,
|
T(YAFFS_TRACE_ERROR,
|
||||||
(TSTR
|
(TSTR
|
||||||
("**>>yaffs ecc error fix performed on chunk %d:0"
|
("**>>yaffs ecc error fix performed on chunk %d:0"
|
||||||
TENDSTR), chunkInNAND));
|
TENDSTR), nand_chunk));
|
||||||
dev->eccFixed++;
|
dev->n_ecc_fixed++;
|
||||||
} else if (eccResult1 < 0) {
|
} else if (ecc_result1 < 0) {
|
||||||
T(YAFFS_TRACE_ERROR,
|
T(YAFFS_TRACE_ERROR,
|
||||||
(TSTR
|
(TSTR
|
||||||
("**>>yaffs ecc error unfixed on chunk %d:0"
|
("**>>yaffs ecc error unfixed on chunk %d:0"
|
||||||
TENDSTR), chunkInNAND));
|
TENDSTR), nand_chunk));
|
||||||
dev->eccUnfixed++;
|
dev->n_ecc_unfixed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eccResult2 > 0) {
|
if (ecc_result2 > 0) {
|
||||||
T(YAFFS_TRACE_ERROR,
|
T(YAFFS_TRACE_ERROR,
|
||||||
(TSTR
|
(TSTR
|
||||||
("**>>yaffs ecc error fix performed on chunk %d:1"
|
("**>>yaffs ecc error fix performed on chunk %d:1"
|
||||||
TENDSTR), chunkInNAND));
|
TENDSTR), nand_chunk));
|
||||||
dev->eccFixed++;
|
dev->n_ecc_fixed++;
|
||||||
} else if (eccResult2 < 0) {
|
} else if (ecc_result2 < 0) {
|
||||||
T(YAFFS_TRACE_ERROR,
|
T(YAFFS_TRACE_ERROR,
|
||||||
(TSTR
|
(TSTR
|
||||||
("**>>yaffs ecc error unfixed on chunk %d:1"
|
("**>>yaffs ecc error unfixed on chunk %d:1"
|
||||||
TENDSTR), chunkInNAND));
|
TENDSTR), nand_chunk));
|
||||||
dev->eccUnfixed++;
|
dev->n_ecc_unfixed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eccResult1 || eccResult2) {
|
if (ecc_result1 || ecc_result2) {
|
||||||
/* We had a data problem on this page */
|
/* 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)
|
if (ecc_result1 < 0 || ecc_result2 < 0)
|
||||||
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
|
||||||
else if (eccResult1 > 0 || eccResult2 > 0)
|
else if (ecc_result1 > 0 || ecc_result2 > 0)
|
||||||
*eccResult = YAFFS_ECC_RESULT_FIXED;
|
*ecc_result = YAFFS_ECC_RESULT_FIXED;
|
||||||
else
|
else
|
||||||
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Must allocate enough memory for spare+2*sizeof(int) */
|
/* Must allocate enough memory for spare+2*sizeof(int) */
|
||||||
/* for ecc results from device. */
|
/* for ecc results from device. */
|
||||||
struct yaffs_NANDSpare nspare;
|
struct yaffs_nand_spare nspare;
|
||||||
|
|
||||||
memset(&nspare, 0, sizeof(nspare));
|
memset(&nspare, 0, sizeof(nspare));
|
||||||
|
|
||||||
retVal = dev->readChunkFromNAND(dev, chunkInNAND, data,
|
retVal = dev->param.read_chunk_fn(dev, nand_chunk, data,
|
||||||
(yaffs_Spare *) &nspare);
|
(yaffs_spare *) &nspare);
|
||||||
memcpy(spare, &nspare, sizeof(yaffs_Spare));
|
memcpy(spare, &nspare, sizeof(yaffs_spare));
|
||||||
if (data && doErrorCorrection) {
|
if (data && doErrorCorrection) {
|
||||||
if (nspare.eccres1 > 0) {
|
if (nspare.eccres1 > 0) {
|
||||||
T(YAFFS_TRACE_ERROR,
|
T(YAFFS_TRACE_ERROR,
|
||||||
(TSTR
|
(TSTR
|
||||||
("**>>mtd ecc error fix performed on chunk %d:0"
|
("**>>mtd ecc error fix performed on chunk %d:0"
|
||||||
TENDSTR), chunkInNAND));
|
TENDSTR), nand_chunk));
|
||||||
} else if (nspare.eccres1 < 0) {
|
} else if (nspare.eccres1 < 0) {
|
||||||
T(YAFFS_TRACE_ERROR,
|
T(YAFFS_TRACE_ERROR,
|
||||||
(TSTR
|
(TSTR
|
||||||
("**>>mtd ecc error unfixed on chunk %d:0"
|
("**>>mtd ecc error unfixed on chunk %d:0"
|
||||||
TENDSTR), chunkInNAND));
|
TENDSTR), nand_chunk));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nspare.eccres2 > 0) {
|
if (nspare.eccres2 > 0) {
|
||||||
T(YAFFS_TRACE_ERROR,
|
T(YAFFS_TRACE_ERROR,
|
||||||
(TSTR
|
(TSTR
|
||||||
("**>>mtd ecc error fix performed on chunk %d:1"
|
("**>>mtd ecc error fix performed on chunk %d:1"
|
||||||
TENDSTR), chunkInNAND));
|
TENDSTR), nand_chunk));
|
||||||
} else if (nspare.eccres2 < 0) {
|
} else if (nspare.eccres2 < 0) {
|
||||||
T(YAFFS_TRACE_ERROR,
|
T(YAFFS_TRACE_ERROR,
|
||||||
(TSTR
|
(TSTR
|
||||||
("**>>mtd ecc error unfixed on chunk %d:1"
|
("**>>mtd ecc error unfixed on chunk %d:1"
|
||||||
TENDSTR), chunkInNAND));
|
TENDSTR), nand_chunk));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nspare.eccres1 || nspare.eccres2) {
|
if (nspare.eccres1 || nspare.eccres2) {
|
||||||
/* We had a data problem on this page */
|
/* 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)
|
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)
|
else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
|
||||||
*eccResult = YAFFS_ECC_RESULT_FIXED;
|
*ecc_result = YAFFS_ECC_RESULT_FIXED;
|
||||||
else
|
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
|
#ifdef NOTYET
|
||||||
static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
|
static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
|
||||||
int chunkInNAND)
|
int nand_chunk)
|
||||||
{
|
{
|
||||||
static int init;
|
static int init;
|
||||||
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
|
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
|
||||||
static __u8 data[YAFFS_BYTES_PER_CHUNK];
|
static __u8 data[YAFFS_BYTES_PER_CHUNK];
|
||||||
/* Might as well always allocate the larger size for */
|
/* Might as well always allocate the larger size for */
|
||||||
/* dev->useNANDECC == true; */
|
/* dev->param.use_nand_ecc == true; */
|
||||||
static __u8 spare[sizeof(struct yaffs_NANDSpare)];
|
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) {
|
if (!init) {
|
||||||
memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
|
memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
|
||||||
|
@ -331,14 +329,14 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
|
||||||
* Functions for robustisizing
|
* 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 */
|
/* 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,
|
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:
|
/* TODO:
|
||||||
* Just do a garbage collection on the affected block
|
* Just do a garbage collection on the affected block
|
||||||
|
@ -348,44 +346,44 @@ static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NOTYET
|
#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 __u8 *data,
|
||||||
const yaffs_Spare *spare)
|
const yaffs_spare *spare)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
|
static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
|
||||||
const yaffs_Spare *spare)
|
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 */
|
/* Mark the block for retirement */
|
||||||
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
|
yaffs_get_block_info(dev, flash_block)->needs_retiring = 1;
|
||||||
/* Delete the chunk */
|
/* 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,
|
static int yaffs_verify_cmp(const __u8 *d0, const __u8 *d1,
|
||||||
const yaffs_Spare *s0, const yaffs_Spare *s1)
|
const yaffs_spare *s0, const yaffs_spare *s1)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
|
if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
|
||||||
s0->tagByte0 != s1->tagByte0 ||
|
s0->tb0 != s1->tb0 ||
|
||||||
s0->tagByte1 != s1->tagByte1 ||
|
s0->tb1 != s1->tb1 ||
|
||||||
s0->tagByte2 != s1->tagByte2 ||
|
s0->tb2 != s1->tb2 ||
|
||||||
s0->tagByte3 != s1->tagByte3 ||
|
s0->tb3 != s1->tb3 ||
|
||||||
s0->tagByte4 != s1->tagByte4 ||
|
s0->tb4 != s1->tb4 ||
|
||||||
s0->tagByte5 != s1->tagByte5 ||
|
s0->tb5 != s1->tb5 ||
|
||||||
s0->tagByte6 != s1->tagByte6 ||
|
s0->tb6 != s1->tb6 ||
|
||||||
s0->tagByte7 != s1->tagByte7 ||
|
s0->tb7 != s1->tb7 ||
|
||||||
s0->ecc1[0] != s1->ecc1[0] ||
|
s0->ecc1[0] != s1->ecc1[0] ||
|
||||||
s0->ecc1[1] != s1->ecc1[1] ||
|
s0->ecc1[1] != s1->ecc1[1] ||
|
||||||
s0->ecc1[2] != s1->ecc1[2] ||
|
s0->ecc1[2] != s1->ecc1[2] ||
|
||||||
|
@ -398,53 +396,53 @@ static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1,
|
||||||
}
|
}
|
||||||
#endif /* NOTYET */
|
#endif /* NOTYET */
|
||||||
|
|
||||||
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
|
int yaffs_tags_compat_wr(yaffs_dev_t *dev,
|
||||||
int chunkInNAND,
|
int nand_chunk,
|
||||||
const __u8 *data,
|
const __u8 *data,
|
||||||
const yaffs_ExtendedTags *eTags)
|
const yaffs_ext_tags *eTags)
|
||||||
{
|
{
|
||||||
yaffs_Spare spare;
|
yaffs_spare spare;
|
||||||
yaffs_Tags tags;
|
yaffs_tags_t tags;
|
||||||
|
|
||||||
yaffs_SpareInitialise(&spare);
|
yaffs_spare_init(&spare);
|
||||||
|
|
||||||
if (eTags->chunkDeleted)
|
if (eTags->is_deleted)
|
||||||
spare.pageStatus = 0;
|
spare.page_status = 0;
|
||||||
else {
|
else {
|
||||||
tags.objectId = eTags->objectId;
|
tags.obj_id = eTags->obj_id;
|
||||||
tags.chunkId = eTags->chunkId;
|
tags.chunk_id = eTags->chunk_id;
|
||||||
|
|
||||||
tags.byteCountLSB = eTags->byteCount & 0x3ff;
|
tags.n_bytes_lsb = eTags->n_bytes & 0x3ff;
|
||||||
|
|
||||||
if (dev->nDataBytesPerChunk >= 1024)
|
if (dev->data_bytes_per_chunk >= 1024)
|
||||||
tags.byteCountMSB = (eTags->byteCount >> 10) & 3;
|
tags.n_bytes_msb = (eTags->n_bytes >> 10) & 3;
|
||||||
else
|
else
|
||||||
tags.byteCountMSB = 3;
|
tags.n_bytes_msb = 3;
|
||||||
|
|
||||||
|
|
||||||
tags.serialNumber = eTags->serialNumber;
|
tags.serial_number = eTags->serial_number;
|
||||||
|
|
||||||
if (!dev->useNANDECC && data)
|
if (!dev->param.use_nand_ecc && data)
|
||||||
yaffs_CalcECC(data, &spare);
|
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 yaffs_tags_compat_rd(yaffs_dev_t *dev,
|
||||||
int chunkInNAND,
|
int nand_chunk,
|
||||||
__u8 *data,
|
__u8 *data,
|
||||||
yaffs_ExtendedTags *eTags)
|
yaffs_ext_tags *eTags)
|
||||||
{
|
{
|
||||||
|
|
||||||
yaffs_Spare spare;
|
yaffs_spare spare;
|
||||||
yaffs_Tags tags;
|
yaffs_tags_t tags;
|
||||||
yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN;
|
yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
|
||||||
|
|
||||||
static yaffs_Spare spareFF;
|
static yaffs_spare spareFF;
|
||||||
static int init;
|
static int init;
|
||||||
|
|
||||||
if (!init) {
|
if (!init) {
|
||||||
|
@ -452,33 +450,33 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||||
init = 1;
|
init = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (yaffs_ReadChunkFromNAND
|
if (yaffs_rd_chunk_nand
|
||||||
(dev, chunkInNAND, data, &spare, &eccResult, 1)) {
|
(dev, nand_chunk, data, &spare, &ecc_result, 1)) {
|
||||||
/* eTags may be NULL */
|
/* eTags may be NULL */
|
||||||
if (eTags) {
|
if (eTags) {
|
||||||
|
|
||||||
int deleted =
|
int deleted =
|
||||||
(yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
|
(yaffs_count_bits(spare.page_status) < 7) ? 1 : 0;
|
||||||
|
|
||||||
eTags->chunkDeleted = deleted;
|
eTags->is_deleted = deleted;
|
||||||
eTags->eccResult = eccResult;
|
eTags->ecc_result = ecc_result;
|
||||||
eTags->blockBad = 0; /* We're reading it */
|
eTags->block_bad = 0; /* We're reading it */
|
||||||
/* therefore it is not a bad block */
|
/* therefore it is not a bad block */
|
||||||
eTags->chunkUsed =
|
eTags->chunk_used =
|
||||||
(memcmp(&spareFF, &spare, sizeof(spareFF)) !=
|
(memcmp(&spareFF, &spare, sizeof(spareFF)) !=
|
||||||
0) ? 1 : 0;
|
0) ? 1 : 0;
|
||||||
|
|
||||||
if (eTags->chunkUsed) {
|
if (eTags->chunk_used) {
|
||||||
yaffs_GetTagsFromSpare(dev, &spare, &tags);
|
yaffs_get_tags_from_spare(dev, &spare, &tags);
|
||||||
|
|
||||||
eTags->objectId = tags.objectId;
|
eTags->obj_id = tags.obj_id;
|
||||||
eTags->chunkId = tags.chunkId;
|
eTags->chunk_id = tags.chunk_id;
|
||||||
eTags->byteCount = tags.byteCountLSB;
|
eTags->n_bytes = tags.n_bytes_lsb;
|
||||||
|
|
||||||
if (dev->nDataBytesPerChunk >= 1024)
|
if (dev->data_bytes_per_chunk >= 1024)
|
||||||
eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10);
|
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 yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev,
|
||||||
int blockInNAND)
|
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);
|
&spare);
|
||||||
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
|
yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
|
||||||
NULL, &spare);
|
NULL, &spare);
|
||||||
|
|
||||||
return YAFFS_OK;
|
return YAFFS_OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev,
|
||||||
int blockNo,
|
int block_no,
|
||||||
yaffs_BlockState *state,
|
yaffs_block_state_t *state,
|
||||||
__u32 *sequenceNumber)
|
__u32 *seq_number)
|
||||||
{
|
{
|
||||||
|
|
||||||
yaffs_Spare spare0, spare1;
|
yaffs_spare spare0, spare1;
|
||||||
static yaffs_Spare spareFF;
|
static yaffs_spare spareFF;
|
||||||
static int init;
|
static int init;
|
||||||
yaffs_ECCResult dummy;
|
yaffs_ecc_result dummy;
|
||||||
|
|
||||||
if (!init) {
|
if (!init) {
|
||||||
memset(&spareFF, 0xFF, sizeof(spareFF));
|
memset(&spareFF, 0xFF, sizeof(spareFF));
|
||||||
init = 1;
|
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);
|
&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);
|
&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;
|
*state = YAFFS_BLOCK_STATE_DEAD;
|
||||||
else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
|
else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
|
||||||
*state = YAFFS_BLOCK_STATE_EMPTY;
|
*state = YAFFS_BLOCK_STATE_EMPTY;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -17,23 +17,23 @@
|
||||||
#define __YAFFS_TAGSCOMPAT_H__
|
#define __YAFFS_TAGSCOMPAT_H__
|
||||||
|
|
||||||
#include "yaffs_guts.h"
|
#include "yaffs_guts.h"
|
||||||
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
|
int yaffs_tags_compat_wr(yaffs_dev_t *dev,
|
||||||
int chunkInNAND,
|
int nand_chunk,
|
||||||
const __u8 *data,
|
const __u8 *data,
|
||||||
const yaffs_ExtendedTags *tags);
|
const yaffs_ext_tags *tags);
|
||||||
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
int yaffs_tags_compat_rd(yaffs_dev_t *dev,
|
||||||
int chunkInNAND,
|
int nand_chunk,
|
||||||
__u8 *data,
|
__u8 *data,
|
||||||
yaffs_ExtendedTags *tags);
|
yaffs_ext_tags *tags);
|
||||||
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev,
|
||||||
int blockNo);
|
int block_no);
|
||||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev,
|
||||||
int blockNo,
|
int block_no,
|
||||||
yaffs_BlockState *state,
|
yaffs_block_state_t *state,
|
||||||
__u32 *sequenceNumber);
|
__u32 *seq_number);
|
||||||
|
|
||||||
void yaffs_CalcTagsECC(yaffs_Tags *tags);
|
void yaffs_calc_tags_ecc(yaffs_tags_t *tags);
|
||||||
int yaffs_CheckECCOnTags(yaffs_Tags *tags);
|
int yaffs_check_tags_ecc(yaffs_tags_t *tags);
|
||||||
int yaffs_CountBits(__u8 byte);
|
int yaffs_count_bits(__u8 byte);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -13,16 +13,16 @@
|
||||||
|
|
||||||
#include "yaffs_tagsvalidity.h"
|
#include "yaffs_tagsvalidity.h"
|
||||||
|
|
||||||
void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
|
void yaffs_init_tags(yaffs_ext_tags *tags)
|
||||||
{
|
{
|
||||||
memset(tags, 0, sizeof(yaffs_ExtendedTags));
|
memset(tags, 0, sizeof(yaffs_ext_tags));
|
||||||
tags->validMarker0 = 0xAAAAAAAA;
|
tags->validity1 = 0xAAAAAAAA;
|
||||||
tags->validMarker1 = 0x55555555;
|
tags->validty1 = 0x55555555;
|
||||||
}
|
}
|
||||||
|
|
||||||
int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
|
int yaffs_validate_tags(yaffs_ext_tags *tags)
|
||||||
{
|
{
|
||||||
return (tags->validMarker0 == 0xAAAAAAAA &&
|
return (tags->validity1 == 0xAAAAAAAA &&
|
||||||
tags->validMarker1 == 0x55555555);
|
tags->validty1 == 0x55555555);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -19,6 +19,6 @@
|
||||||
|
|
||||||
#include "yaffs_guts.h"
|
#include "yaffs_guts.h"
|
||||||
|
|
||||||
void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
|
void yaffs_init_tags(yaffs_ext_tags *tags);
|
||||||
int yaffs_ValidateTags(yaffs_ExtendedTags *tags);
|
int yaffs_validate_tags(yaffs_ext_tags *tags);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
@ -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
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -16,6 +16,6 @@
|
||||||
#ifndef __YAFFSINTERFACE_H__
|
#ifndef __YAFFSINTERFACE_H__
|
||||||
#define __YAFFSINTERFACE_H__
|
#define __YAFFSINTERFACE_H__
|
||||||
|
|
||||||
int yaffs_Initialise(unsigned nBlocks);
|
int yaffs_initialise(unsigned nBlocks);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
* 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
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
*
|
*
|
||||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
@ -41,12 +41,14 @@
|
||||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/xattr.h>
|
||||||
|
|
||||||
#define YCHAR char
|
#define YCHAR char
|
||||||
#define YUCHAR unsigned char
|
#define YUCHAR unsigned char
|
||||||
|
@ -55,11 +57,11 @@
|
||||||
#define yaffs_strcpy(a, b) strcpy(a, b)
|
#define yaffs_strcpy(a, b) strcpy(a, b)
|
||||||
#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
|
#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
|
||||||
#define yaffs_strncmp(a, b, c) strncmp(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_sprintf sprintf
|
||||||
#define yaffs_toupper(a) toupper(a)
|
#define yaffs_toupper(a) toupper(a)
|
||||||
|
|
||||||
#define Y_INLINE inline
|
#define Y_INLINE __inline__
|
||||||
|
|
||||||
#define YAFFS_LOSTNFOUND_NAME "lost+found"
|
#define YAFFS_LOSTNFOUND_NAME "lost+found"
|
||||||
#define YAFFS_LOSTNFOUND_PREFIX "obj"
|
#define YAFFS_LOSTNFOUND_PREFIX "obj"
|
||||||
|
@ -71,11 +73,11 @@
|
||||||
#define YFREE_ALT(x) vfree(x)
|
#define YFREE_ALT(x) vfree(x)
|
||||||
#define YMALLOC_DMA(x) YMALLOC(x)
|
#define YMALLOC_DMA(x) YMALLOC(x)
|
||||||
|
|
||||||
/* KR - added for use in scan so processes aren't blocked indefinitely. */
|
|
||||||
#define YYIELD() schedule()
|
#define YYIELD() schedule()
|
||||||
|
#define Y_DUMP_STACK() dump_stack()
|
||||||
|
|
||||||
#define YAFFS_ROOT_MODE 0666
|
#define YAFFS_ROOT_MODE 0755
|
||||||
#define YAFFS_LOSTNFOUND_MODE 0666
|
#define YAFFS_LOSTNFOUND_MODE 0700
|
||||||
|
|
||||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
|
||||||
#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
|
#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
|
||||||
|
@ -85,19 +87,14 @@
|
||||||
#define Y_TIME_CONVERT(x) (x)
|
#define Y_TIME_CONVERT(x) (x)
|
||||||
#endif
|
#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 yaffs_strcmp(a, b) strcmp(a, b)
|
||||||
|
|
||||||
#define TENDSTR "\n"
|
#define TENDSTR "\n"
|
||||||
#define TSTR(x) KERN_WARNING x
|
#define TSTR(x) KERN_DEBUG x
|
||||||
#define TCONT(x) x
|
#define TCONT(x) x
|
||||||
#define TOUT(p) printk p
|
#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) \
|
#define compile_time_assertion(assertion) \
|
||||||
({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
|
({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
|
||||||
|
|
||||||
|
@ -116,7 +113,6 @@
|
||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
#include "devextras.h"
|
|
||||||
|
|
||||||
#define YMALLOC(x) malloc(x)
|
#define YMALLOC(x) malloc(x)
|
||||||
#define YFREE(x) free(x)
|
#define YFREE(x) free(x)
|
||||||
|
@ -129,7 +125,7 @@
|
||||||
#define yaffs_strcat(a, b) strcat(a, b)
|
#define yaffs_strcat(a, b) strcat(a, b)
|
||||||
#define yaffs_strcpy(a, b) strcpy(a, b)
|
#define yaffs_strcpy(a, b) strcpy(a, b)
|
||||||
#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
|
#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_sprintf sprintf
|
||||||
#define yaffs_toupper(a) toupper(a)
|
#define yaffs_toupper(a) toupper(a)
|
||||||
|
|
||||||
|
@ -146,10 +142,10 @@
|
||||||
#define YAFFS_LOSTNFOUND_PREFIX "obj"
|
#define YAFFS_LOSTNFOUND_PREFIX "obj"
|
||||||
/* #define YPRINTF(x) printf x */
|
/* #define YPRINTF(x) printf x */
|
||||||
|
|
||||||
#define YAFFS_ROOT_MODE 0666
|
#define YAFFS_ROOT_MODE 0755
|
||||||
#define YAFFS_LOSTNFOUND_MODE 0666
|
#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)
|
#define yaffs_strcmp(a, b) strcmp(a, b)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -158,46 +154,180 @@
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* see yaffs_fs.c */
|
#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
|
||||||
extern unsigned int yaffs_traceMask;
|
|
||||||
extern unsigned int yaffs_wr_attempts;
|
|
||||||
|
|
||||||
/*
|
#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
|
||||||
* Tracing flags.
|
|
||||||
* The flags masked in YAFFS_TRACE_ALWAYS are always traced.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define YAFFS_TRACE_OS 0x00000002
|
#ifndef O_RDONLY
|
||||||
#define YAFFS_TRACE_ALLOCATE 0x00000004
|
#define O_RDONLY 00
|
||||||
#define YAFFS_TRACE_SCAN 0x00000008
|
#endif
|
||||||
#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
|
#ifndef O_WRONLY
|
||||||
#define YAFFS_TRACE_VERIFY_NAND 0x00020000
|
#define O_WRONLY 01
|
||||||
#define YAFFS_TRACE_VERIFY_FULL 0x00040000
|
#endif
|
||||||
#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
|
|
||||||
|
#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
|
// Mode flags
|
||||||
#define YAFFS_TRACE_BUG 0x80000000
|
|
||||||
#define YAFFS_TRACE_ALWAYS 0xF0000000
|
|
||||||
|
|
||||||
|
#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
|
#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
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue