generic-2.6: sync yaffs code with the official CVS tree
SVN-Revision: 11378
This commit is contained in:
parent
306f3677ec
commit
477d43b281
66 changed files with 1983 additions and 2964 deletions
|
@ -43,7 +43,8 @@ config YAFFS_9BYTE_TAGS
|
|||
format that you need to continue to support. New data written
|
||||
also uses the older-style format. Note: Use of this option
|
||||
generally requires that MTD's oob layout be adjusted to use the
|
||||
older-style format. See notes on tags formats and MTD versions.
|
||||
older-style format. See notes on tags formats and MTD versions
|
||||
in yaffs_mtdif1.c.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
|
@ -109,26 +110,6 @@ config YAFFS_DISABLE_LAZY_LOAD
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config YAFFS_CHECKPOINT_RESERVED_BLOCKS
|
||||
int "Reserved blocks for checkpointing"
|
||||
depends on YAFFS_YAFFS2
|
||||
default 10
|
||||
help
|
||||
Give the number of Blocks to reserve for checkpointing.
|
||||
Checkpointing saves the state at unmount so that mounting is
|
||||
much faster as a scan of all the flash to regenerate this state
|
||||
is not needed. These Blocks are reserved per partition, so if
|
||||
you have very small partitions the default (10) may be a mess
|
||||
for you. You can set this value to 0, but that does not mean
|
||||
checkpointing is disabled at all. There only won't be any
|
||||
specially reserved blocks for checkpointing, so if there is
|
||||
enough free space on the filesystem, it will be used for
|
||||
checkpointing.
|
||||
|
||||
If unsure, leave at default (10), but don't wonder if there are
|
||||
always 2MB used on your large page device partition (10 x 2k
|
||||
pagesize). When using small partitions or when being very small
|
||||
on space, you probably want to set this to zero.
|
||||
|
||||
config YAFFS_DISABLE_WIDE_TNODES
|
||||
bool "Turn off wide tnodes"
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
obj-$(CONFIG_YAFFS_FS) += yaffs.o
|
||||
|
||||
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
|
||||
yaffs-y += yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
|
||||
yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
|
||||
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
|
||||
yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o
|
||||
yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o
|
||||
yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
|
||||
|
|
|
@ -14,194 +14,117 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* This file is just holds extra declarations used during development.
|
||||
* Most of these are from kernel includes placed here so we can use them in
|
||||
* applications.
|
||||
* 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 __EXTRAS_H__
|
||||
#define __EXTRAS_H__
|
||||
|
||||
#if defined WIN32
|
||||
#define __inline__ __inline
|
||||
#define new newHack
|
||||
#endif
|
||||
|
||||
#if !(defined __KERNEL__) || (defined WIN32)
|
||||
|
||||
/* User space defines */
|
||||
#if !(defined __KERNEL__)
|
||||
|
||||
/* Definition of types */
|
||||
typedef unsigned char __u8;
|
||||
typedef unsigned short __u16;
|
||||
typedef unsigned __u32;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
* This is a simple doubly linked list implementation that matches the
|
||||
* way the Linux kernel doubly linked list implementation works.
|
||||
*/
|
||||
|
||||
#define prefetch(x) 1
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
struct ylist_head {
|
||||
struct ylist_head *next; /* next in chain */
|
||||
struct ylist_head *prev; /* previous in chain */
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
/* Initialise a list head to an empty list */
|
||||
#define YINIT_LIST_HEAD(p) \
|
||||
do { \
|
||||
(p)->next = (p);\
|
||||
(p)->prev = (p); \
|
||||
} while(0)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
/* Add an element to a list */
|
||||
static __inline__ void ylist_add(struct ylist_head *newEntry,
|
||||
struct ylist_head *list)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
struct ylist_head *listNext = list->next;
|
||||
|
||||
list->next = newEntry;
|
||||
newEntry->prev = list;
|
||||
newEntry->next = listNext;
|
||||
listNext->prev = newEntry;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static __inline__ void list_add(struct list_head *new, struct list_head *head)
|
||||
|
||||
/* 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)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
struct ylist_head *listNext = entry->next;
|
||||
struct ylist_head *listPrev = entry->prev;
|
||||
|
||||
listNext->prev = listPrev;
|
||||
listPrev->next = listNext;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static __inline__ void list_add_tail(struct list_head *new,
|
||||
struct list_head *head)
|
||||
static __inline__ void ylist_del_init(struct ylist_head *entry)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
ylist_del(entry);
|
||||
entry->next = entry->prev = entry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_del(struct list_head *prev,
|
||||
struct list_head *next)
|
||||
|
||||
/* Test if the list is empty */
|
||||
static __inline__ int ylist_empty(struct ylist_head *entry)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
return (entry->next == entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
static __inline__ void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
|
||||
#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
|
||||
*/
|
||||
static __inline__ void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static __inline__ int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
#define ylist_for_each(itervar, list) \
|
||||
for (itervar = (list)->next; itervar != (list); itervar = itervar->next )
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static __inline__ void list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
#define ylist_for_each_safe(itervar,saveVar, list) \
|
||||
for (itervar = (list)->next, saveVar = (list)->next->next; itervar != (list); \
|
||||
itervar = saveVar, saveVar = saveVar->next)
|
||||
|
||||
if (first != list) {
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
#if !(defined __KERNEL__)
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||
#ifndef WIN32
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
|
||||
pos = pos->next, prefetch(pos->next))
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal
|
||||
* of list entry
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
#ifdef CONFIG_YAFFS_PROVIDE_DEFS
|
||||
/* File types */
|
||||
|
||||
|
||||
/*
|
||||
* File types
|
||||
*/
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_FIFO 1
|
||||
#define DT_CHR 2
|
||||
|
@ -212,13 +135,13 @@ static __inline__ void list_splice(struct list_head *list,
|
|||
#define DT_SOCK 12
|
||||
#define DT_WHT 14
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Attribute flags. These should be or-ed together to figure out what
|
||||
* has been changed!
|
||||
* Attribute flags.
|
||||
*/
|
||||
#define ATTR_MODE 1
|
||||
#define ATTR_UID 2
|
||||
|
@ -227,10 +150,7 @@ static __inline__ void list_splice(struct list_head *list,
|
|||
#define ATTR_ATIME 16
|
||||
#define ATTR_MTIME 32
|
||||
#define ATTR_CTIME 64
|
||||
#define ATTR_ATIME_SET 128
|
||||
#define ATTR_MTIME_SET 256
|
||||
#define ATTR_FORCE 512 /* Not a change, but a change it */
|
||||
#define ATTR_ATTR_FLAG 1024
|
||||
|
||||
|
||||
struct iattr {
|
||||
unsigned int ia_valid;
|
||||
|
@ -244,21 +164,18 @@ struct iattr {
|
|||
unsigned int ia_attr_flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define KERN_DEBUG
|
||||
|
||||
#else
|
||||
|
||||
#ifndef WIN32
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/stat.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined WIN32
|
||||
#undef new
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,11 +54,11 @@ that you need to continue to support. New data written also uses the
|
|||
older-style format.
|
||||
Note: Use of this option generally requires that MTD's oob layout be
|
||||
adjusted to use the older-style format. See notes on tags formats and
|
||||
MTD versions.
|
||||
MTD versions in yaffs_mtdif1.c.
|
||||
*/
|
||||
/* Default: Not selected */
|
||||
/* Meaning: Use older-style on-NAND data format with pageStatus byte */
|
||||
#define CONFIG_YAFFS_9BYTE_TAGS
|
||||
//#define CONFIG_YAFFS_9BYTE_TAGS
|
||||
|
||||
#endif /* YAFFS_OUT_OF_TREE */
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_checkptrw_c_version =
|
||||
"$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $";
|
||||
"$Id: yaffs_checkptrw.c,v 1.16 2008-05-05 07:58:58 charles Exp $";
|
||||
|
||||
|
||||
#include "yaffs_checkptrw.h"
|
||||
|
||||
#include "yaffs_getblockinfo.h"
|
||||
|
||||
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
|
||||
{
|
||||
|
@ -142,7 +142,7 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
|
|||
return 0;
|
||||
|
||||
if(!dev->checkpointBuffer)
|
||||
dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
|
||||
dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
|
||||
if(!dev->checkpointBuffer)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_ecc_c_version =
|
||||
"$Id: yaffs_ecc.c,v 1.9 2007-02-14 01:09:06 wookey Exp $";
|
||||
"$Id: yaffs_ecc.c,v 1.10 2007-12-13 15:35:17 wookey Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_fs_c_version =
|
||||
"$Id: yaffs_fs.c,v 1.63 2007-09-19 20:35:40 imcd Exp $";
|
||||
"$Id: yaffs_fs.c,v 1.66 2008-05-05 07:58:58 charles Exp $";
|
||||
extern const char *yaffs_guts_c_version;
|
||||
|
||||
#include <linux/version.h>
|
||||
|
@ -53,6 +53,8 @@ extern const char *yaffs_guts_c_version;
|
|||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include "asm/div64.h"
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
|
||||
|
||||
#include <linux/statfs.h> /* Added NCB 15-8-2003 */
|
||||
|
@ -753,6 +755,8 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
|
|||
break;
|
||||
}
|
||||
|
||||
inode->i_flags |= S_NOATIME;
|
||||
|
||||
inode->i_ino = obj->objectId;
|
||||
inode->i_mode = obj->yst_mode;
|
||||
inode->i_uid = obj->yst_uid;
|
||||
|
@ -1350,25 +1354,47 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
|
|||
buf->f_type = YAFFS_MAGIC;
|
||||
buf->f_bsize = sb->s_blocksize;
|
||||
buf->f_namelen = 255;
|
||||
if (sb->s_blocksize > dev->nDataBytesPerChunk) {
|
||||
|
||||
if(dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)){
|
||||
/* Do this if chunk size is not a power of 2 */
|
||||
|
||||
uint64_t bytesInDev;
|
||||
uint64_t bytesFree;
|
||||
|
||||
bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock +1))) *
|
||||
((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
|
||||
|
||||
do_div(bytesInDev,sb->s_blocksize); /* bytesInDev becomes the number of blocks */
|
||||
buf->f_blocks = bytesInDev;
|
||||
|
||||
bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
|
||||
((uint64_t)(dev->nDataBytesPerChunk));
|
||||
|
||||
do_div(bytesFree,sb->s_blocksize);
|
||||
|
||||
buf->f_bfree = bytesFree;
|
||||
|
||||
} else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
|
||||
|
||||
buf->f_blocks =
|
||||
(dev->endBlock - dev->startBlock +
|
||||
1) * dev->nChunksPerBlock / (sb->s_blocksize /
|
||||
dev->nDataBytesPerChunk);
|
||||
buf->f_bfree =
|
||||
yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize /
|
||||
dev->nDataBytesPerChunk);
|
||||
(dev->endBlock - dev->startBlock + 1) *
|
||||
dev->nChunksPerBlock /
|
||||
(sb->s_blocksize / dev->nDataBytesPerChunk);
|
||||
buf->f_bfree =
|
||||
yaffs_GetNumberOfFreeChunks(dev) /
|
||||
(sb->s_blocksize / dev->nDataBytesPerChunk);
|
||||
} else {
|
||||
buf->f_blocks =
|
||||
(dev->endBlock - dev->startBlock + 1) *
|
||||
dev->nChunksPerBlock *
|
||||
(dev->nDataBytesPerChunk / sb->s_blocksize);
|
||||
|
||||
buf->f_blocks =
|
||||
(dev->endBlock - dev->startBlock +
|
||||
1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk /
|
||||
sb->s_blocksize);
|
||||
buf->f_bfree =
|
||||
yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk /
|
||||
sb->s_blocksize);
|
||||
buf->f_bfree =
|
||||
yaffs_GetNumberOfFreeChunks(dev) *
|
||||
(dev->nDataBytesPerChunk / sb->s_blocksize);
|
||||
}
|
||||
|
||||
|
||||
buf->f_files = 0;
|
||||
buf->f_ffree = 0;
|
||||
buf->f_bavail = buf->f_bfree;
|
||||
|
@ -1602,6 +1628,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
|
||||
sb->s_magic = YAFFS_MAGIC;
|
||||
sb->s_op = &yaffs_super_ops;
|
||||
sb->s_flags |= MS_NOATIME;
|
||||
|
||||
if (!sb)
|
||||
printk(KERN_INFO "yaffs: sb is NULL\n");
|
||||
|
@ -1678,22 +1705,15 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
#ifdef CONFIG_YAFFS_AUTO_YAFFS2
|
||||
|
||||
if (yaffsVersion == 1 &&
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
mtd->writesize >= 2048) {
|
||||
#else
|
||||
mtd->oobblock >= 2048) {
|
||||
#endif
|
||||
WRITE_SIZE(mtd) >= 2048) {
|
||||
T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
|
||||
yaffsVersion = 2;
|
||||
}
|
||||
|
||||
/* Added NCB 26/5/2006 for completeness */
|
||||
if (yaffsVersion == 2 &&
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
mtd->writesize == 512) {
|
||||
#else
|
||||
mtd->oobblock == 512) {
|
||||
#endif
|
||||
!options.inband_tags &&
|
||||
WRITE_SIZE(mtd) == 512){
|
||||
T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
|
||||
yaffsVersion = 1;
|
||||
}
|
||||
|
@ -1719,12 +1739,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
|
||||
#else
|
||||
if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
|
||||
#endif
|
||||
mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) {
|
||||
if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
|
||||
mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
|
||||
!options.inband_tags) {
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
("yaffs: MTD device does not have the "
|
||||
"right page sizes\n"));
|
||||
|
@ -1784,9 +1801,10 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
dev->startBlock = 0;
|
||||
dev->endBlock = nBlocks - 1;
|
||||
dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
|
||||
dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
|
||||
dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
|
||||
dev->nReservedBlocks = 5;
|
||||
dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
|
||||
dev->inbandTags = options.inband_tags;
|
||||
|
||||
/* ... and the functions. */
|
||||
if (yaffsVersion == 2) {
|
||||
|
@ -1799,15 +1817,14 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
dev->spareBuffer = YMALLOC(mtd->oobsize);
|
||||
dev->isYaffs2 = 1;
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
dev->nDataBytesPerChunk = mtd->writesize;
|
||||
dev->totalBytesPerChunk = mtd->writesize;
|
||||
dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
|
||||
#else
|
||||
dev->nDataBytesPerChunk = mtd->oobblock;
|
||||
dev->totalBytesPerChunk = mtd->oobblock;
|
||||
dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
|
||||
#endif
|
||||
nBlocks = mtd->size / mtd->erasesize;
|
||||
|
||||
dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS;
|
||||
dev->startBlock = 0;
|
||||
dev->endBlock = nBlocks - 1;
|
||||
} else {
|
||||
|
@ -1990,12 +2007,12 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
|
|||
{
|
||||
buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
|
||||
buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
|
||||
buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
|
||||
buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
|
||||
buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
|
||||
buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
|
||||
buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
|
||||
buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
|
||||
buf += sprintf(buf, "nCheckptResBlocks.. %d\n", dev->nCheckpointReservedBlocks);
|
||||
buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
|
||||
buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
|
||||
buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
|
||||
|
@ -2006,10 +2023,8 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
|
|||
buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
|
||||
buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
|
||||
buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
|
||||
buf +=
|
||||
sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
|
||||
buf +=
|
||||
sprintf(buf, "passiveGCs......... %d\n",
|
||||
buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
|
||||
buf += sprintf(buf, "passiveGCs......... %d\n",
|
||||
dev->passiveGarbageCollections);
|
||||
buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
|
||||
buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
|
||||
|
@ -2025,6 +2040,7 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
|
|||
sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
|
||||
buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
|
||||
buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
|
||||
buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_GETBLOCKINFO_H__
|
||||
#define __YAFFS_GETBLOCKINFO_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
/* Function to manipulate block info */
|
||||
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
|
||||
{
|
||||
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
|
||||
blk));
|
||||
YBUG();
|
||||
}
|
||||
return &dev->blockInfo[blk - dev->internalStartBlock];
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -90,7 +90,7 @@
|
|||
|
||||
#define YAFFS_MAX_SHORT_OP_CACHES 20
|
||||
|
||||
#define YAFFS_N_TEMP_BUFFERS 4
|
||||
#define YAFFS_N_TEMP_BUFFERS 6
|
||||
|
||||
/* We limit the number attempts at sucessfully saving a chunk of data.
|
||||
* Small-page devices have 32 pages per block; large-page devices have 64.
|
||||
|
@ -277,7 +277,7 @@ typedef struct {
|
|||
|
||||
int softDeletions:10; /* number of soft deleted pages */
|
||||
int pagesInUse:10; /* number of pages in use */
|
||||
yaffs_BlockState blockState:4; /* One of the above block states */
|
||||
unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
|
||||
__u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
|
||||
/* and retire the block. */
|
||||
__u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */
|
||||
|
@ -303,7 +303,7 @@ typedef struct {
|
|||
__u16 sum__NoLongerUsed; /* checksum of name. No longer used */
|
||||
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
|
||||
|
||||
/* Thes following apply to directories, files, symlinks - not hard links */
|
||||
/* The following apply to directories, files, symlinks - not hard links */
|
||||
__u32 yst_mode; /* protection */
|
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE
|
||||
|
@ -331,11 +331,14 @@ typedef struct {
|
|||
__u32 win_ctime[2];
|
||||
__u32 win_atime[2];
|
||||
__u32 win_mtime[2];
|
||||
__u32 roomToGrow[4];
|
||||
#else
|
||||
__u32 roomToGrow[10];
|
||||
#endif
|
||||
__u32 roomToGrow[6];
|
||||
|
||||
#endif
|
||||
__u32 inbandShadowsObject;
|
||||
__u32 inbandIsShrink;
|
||||
|
||||
__u32 reservedSpace[2];
|
||||
int shadowsObject; /* This object header shadows the specified object if > 0 */
|
||||
|
||||
/* isShrink applies to object headers written when we shrink the file (ie resize) */
|
||||
|
@ -381,7 +384,7 @@ typedef struct {
|
|||
} yaffs_FileStructure;
|
||||
|
||||
typedef struct {
|
||||
struct list_head children; /* list of child links */
|
||||
struct ylist_head children; /* list of child links */
|
||||
} yaffs_DirectoryStructure;
|
||||
|
||||
typedef struct {
|
||||
|
@ -424,14 +427,14 @@ struct yaffs_ObjectStruct {
|
|||
|
||||
struct yaffs_DeviceStruct *myDev; /* The device I'm on */
|
||||
|
||||
struct list_head hashLink; /* list of objects in this hash bucket */
|
||||
struct ylist_head hashLink; /* list of objects in this hash bucket */
|
||||
|
||||
struct list_head hardLinks; /* all the equivalent hard linked objects */
|
||||
struct ylist_head hardLinks; /* all the equivalent hard linked objects */
|
||||
|
||||
/* directory structure stuff */
|
||||
/* also used for linking up the free list */
|
||||
struct yaffs_ObjectStruct *parent;
|
||||
struct list_head siblings;
|
||||
struct ylist_head siblings;
|
||||
|
||||
/* Where's my object header in NAND? */
|
||||
int chunkId;
|
||||
|
@ -485,7 +488,7 @@ struct yaffs_ObjectList_struct {
|
|||
typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
|
||||
|
||||
typedef struct {
|
||||
struct list_head list;
|
||||
struct ylist_head list;
|
||||
int count;
|
||||
} yaffs_ObjectBucket;
|
||||
|
||||
|
@ -528,7 +531,7 @@ typedef struct {
|
|||
/*----------------- Device ---------------------------------*/
|
||||
|
||||
struct yaffs_DeviceStruct {
|
||||
struct list_head devList;
|
||||
struct ylist_head devList;
|
||||
const char *name;
|
||||
|
||||
/* Entry parameters set up way early. Yaffs sets up the rest.*/
|
||||
|
@ -544,7 +547,7 @@ struct yaffs_DeviceStruct {
|
|||
/* Stuff used by the shared space checkpointing mechanism */
|
||||
/* If this value is zero, then this mechanism is disabled */
|
||||
|
||||
int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */
|
||||
// int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */
|
||||
|
||||
|
||||
|
||||
|
@ -583,7 +586,7 @@ struct yaffs_DeviceStruct {
|
|||
yaffs_ExtendedTags * tags);
|
||||
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
|
||||
int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,
|
||||
yaffs_BlockState * state, int *sequenceNumber);
|
||||
yaffs_BlockState * state, __u32 *sequenceNumber);
|
||||
#endif
|
||||
|
||||
int isYaffs2;
|
||||
|
@ -599,6 +602,7 @@ struct yaffs_DeviceStruct {
|
|||
|
||||
int wideTnodesDisabled; /* Set to disable wide tnodes */
|
||||
|
||||
YCHAR *pathDividers; /* String of legal path dividers */
|
||||
|
||||
/* End of stuff that must be set before initialisation. */
|
||||
|
||||
|
@ -615,16 +619,14 @@ struct yaffs_DeviceStruct {
|
|||
__u32 tnodeWidth;
|
||||
__u32 tnodeMask;
|
||||
|
||||
/* Stuff to support various file offses to chunk/offset translations */
|
||||
/* "Crumbs" for nDataBytesPerChunk not being a power of 2 */
|
||||
__u32 crumbMask;
|
||||
__u32 crumbShift;
|
||||
__u32 crumbsPerChunk;
|
||||
|
||||
/* Straight shifting for nDataBytesPerChunk being a power of 2 */
|
||||
__u32 chunkShift;
|
||||
__u32 chunkMask;
|
||||
/* Stuff for figuring out file offset to chunk conversions */
|
||||
__u32 chunkShift; /* Shift value */
|
||||
__u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
|
||||
__u32 chunkMask; /* Mask to use for power-of-2 case */
|
||||
|
||||
/* Stuff to handle inband tags */
|
||||
int inbandTags;
|
||||
__u32 totalBytesPerChunk;
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
|
@ -663,6 +665,8 @@ struct yaffs_DeviceStruct {
|
|||
__u32 checkpointSum;
|
||||
__u32 checkpointXor;
|
||||
|
||||
int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */
|
||||
|
||||
/* Block Info */
|
||||
yaffs_BlockInfo *blockInfo;
|
||||
__u8 *chunkBits; /* bitmap of chunks in use */
|
||||
|
@ -745,8 +749,10 @@ struct yaffs_DeviceStruct {
|
|||
int nBackgroundDeletions; /* Count of background deletions. */
|
||||
|
||||
|
||||
/* Temporary buffer management */
|
||||
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
|
||||
int maxTemp;
|
||||
int tempInUse;
|
||||
int unmanagedTempAllocations;
|
||||
int unmanagedTempDeallocations;
|
||||
|
||||
|
@ -758,7 +764,7 @@ struct yaffs_DeviceStruct {
|
|||
|
||||
typedef struct yaffs_DeviceStruct yaffs_Device;
|
||||
|
||||
/* The static layout of bllock usage etc is stored in the super block header */
|
||||
/* The static layout of block usage etc is stored in the super block header */
|
||||
typedef struct {
|
||||
int StructType;
|
||||
int version;
|
||||
|
@ -797,18 +803,6 @@ typedef struct {
|
|||
__u32 head;
|
||||
} yaffs_CheckpointValidity;
|
||||
|
||||
/* Function to manipulate block info */
|
||||
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
|
||||
{
|
||||
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
|
||||
blk));
|
||||
YBUG();
|
||||
}
|
||||
return &dev->blockInfo[blk - dev->internalStartBlock];
|
||||
}
|
||||
|
||||
/*----------------------- YAFFS Functions -----------------------*/
|
||||
|
||||
|
@ -899,4 +893,7 @@ void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn);
|
|||
int yaffs_CheckFF(__u8 * buffer, int nBytes);
|
||||
void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
|
||||
|
||||
__u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo);
|
||||
void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, int lineNo);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_mtdif_c_version =
|
||||
"$Id: yaffs_mtdif.c,v 1.19 2007-02-14 01:09:06 wookey Exp $";
|
||||
"$Id: yaffs_mtdif.c,v 1.21 2007-12-13 15:35:18 wookey Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
@ -24,7 +24,7 @@ const char *yaffs_mtdif_c_version =
|
|||
#include "linux/time.h"
|
||||
#include "linux/mtd/nand.h"
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
|
||||
#if (MTD_VERSION_CODE < MTD_VERSION(2,6,18))
|
||||
static struct nand_oobinfo yaffs_oobinfo = {
|
||||
.useecc = 1,
|
||||
.eccbytes = 6,
|
||||
|
@ -36,7 +36,7 @@ static struct nand_oobinfo yaffs_noeccinfo = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
|
||||
{
|
||||
oob[0] = spare->tagByte0;
|
||||
|
@ -75,14 +75,14 @@ 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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
__u8 spareAsBytes[8]; /* OOB */
|
||||
|
||||
if (data && !spare)
|
||||
|
@ -139,14 +139,14 @@ int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
|
|||
yaffs_Spare * spare)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
__u8 spareAsBytes[8]; /* OOB */
|
||||
|
||||
if (data && !spare)
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
#if (MTD_VERSION_CODE < MTD_VERSION(2,6,18))
|
||||
extern struct nand_oobinfo yaffs_oobinfo;
|
||||
extern struct nand_oobinfo yaffs_noeccinfo;
|
||||
#endif
|
||||
|
||||
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data, const yaffs_Spare * spare);
|
||||
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
|
||||
|
|
|
@ -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: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $";
|
||||
|
||||
#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--
|
||||
|
||||
|
||||
|
|
@ -34,9 +34,9 @@
|
|||
#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))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
|
||||
const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $";
|
||||
const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.7 2007-12-13 15:35:18 wookey Exp $";
|
||||
|
||||
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||
# define YTAG1_SIZE 8
|
||||
|
@ -189,7 +189,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
|||
ops.datbuf = data;
|
||||
ops.oobbuf = (__u8 *)&pt1;
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
|
||||
#if (MTD_VERSION_CODE < MTD_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.
|
||||
*/
|
||||
|
@ -288,7 +288,7 @@ int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
|||
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
|
||||
int retval;
|
||||
|
||||
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
|
||||
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
|
||||
|
||||
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
|
||||
return (retval) ? YAFFS_FAIL : YAFFS_OK;
|
||||
|
@ -327,6 +327,7 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
|||
{
|
||||
struct mtd_info * mtd = dev->genericDevice;
|
||||
int chunkNo = blockNo * dev->nChunksPerBlock;
|
||||
loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
|
||||
yaffs_ExtendedTags etags;
|
||||
int state = YAFFS_BLOCK_STATE_DEAD;
|
||||
int seqnum = 0;
|
||||
|
@ -340,11 +341,16 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
|||
}
|
||||
|
||||
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
|
||||
etags.blockBad = (mtd->block_isbad)(mtd, addr);
|
||||
if (etags.blockBad) {
|
||||
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
|
||||
"block %d is marked bad", blockNo);
|
||||
"block %d is marked bad\n", blockNo);
|
||||
state = YAFFS_BLOCK_STATE_DEAD;
|
||||
}
|
||||
else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
/* bad tags, need to look more closely */
|
||||
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
}
|
||||
else if (etags.chunkUsed) {
|
||||
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
seqnum = etags.sequenceNumber;
|
||||
|
@ -360,4 +366,4 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
|||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
#endif /*KERNEL_VERSION*/
|
||||
#endif /*MTD_VERSION*/
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
/* mtd interface for YAFFS2 */
|
||||
|
||||
const char *yaffs_mtdif2_c_version =
|
||||
"$Id: yaffs_mtdif2.c,v 1.17 2007-02-14 01:09:06 wookey Exp $";
|
||||
"$Id: yaffs_mtdif2.c,v 1.20 2008-05-05 07:58:58 charles Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
@ -27,19 +27,23 @@ const char *yaffs_mtdif2_c_version =
|
|||
|
||||
#include "yaffs_packedtags2.h"
|
||||
|
||||
/* NB For use with inband tags....
|
||||
* We assume that the data buffer is of size totalBytersPerChunk so that we can also
|
||||
* use it to load the tags.
|
||||
*/
|
||||
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data,
|
||||
const yaffs_ExtendedTags * tags)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
struct mtd_oob_ops ops;
|
||||
#else
|
||||
size_t dummy;
|
||||
#endif
|
||||
int retval = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||
loff_t addr;
|
||||
|
||||
yaffs_PackedTags2 pt;
|
||||
|
||||
|
@ -48,46 +52,41 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
|||
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
|
||||
TENDSTR), chunkInNAND, data, tags));
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
if (tags)
|
||||
yaffs_PackTags2(&pt, tags);
|
||||
else
|
||||
BUG(); /* both tags and data should always be present */
|
||||
|
||||
if (data) {
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.ooblen = sizeof(pt);
|
||||
ops.len = dev->nDataBytesPerChunk;
|
||||
ops.ooboffs = 0;
|
||||
ops.datbuf = (__u8 *)data;
|
||||
ops.oobbuf = (void *)&pt;
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
} else
|
||||
BUG(); /* both tags and data should always be present */
|
||||
#else
|
||||
if (tags) {
|
||||
yaffs_PackTags2(&pt, tags);
|
||||
addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
|
||||
|
||||
/* For yaffs2 writing there must be both data and tags.
|
||||
* If we're using inband tags, then the tags are stuffed into
|
||||
* the end of the data buffer.
|
||||
*/
|
||||
if(!data || !tags)
|
||||
BUG();
|
||||
else if(dev->inbandTags){
|
||||
yaffs_PackedTags2TagsPart *pt2tp;
|
||||
pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
|
||||
yaffs_PackTags2TagsPart(pt2tp,tags);
|
||||
}
|
||||
else
|
||||
yaffs_PackTags2(&pt, tags);
|
||||
|
||||
if (data && tags) {
|
||||
if (dev->useNANDECC)
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, (__u8 *) & pt, NULL);
|
||||
else
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, (__u8 *) & pt, NULL);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
|
||||
ops.len = dev->totalBytesPerChunk;
|
||||
ops.ooboffs = 0;
|
||||
ops.datbuf = (__u8 *)data;
|
||||
ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
|
||||
#else
|
||||
if (!dev->inbandTags) {
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, (__u8 *) & pt, NULL);
|
||||
} else {
|
||||
if (data)
|
||||
retval =
|
||||
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||
data);
|
||||
if (tags)
|
||||
retval =
|
||||
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||
(__u8 *) & pt);
|
||||
|
||||
retval =
|
||||
mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
|
||||
data);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -101,11 +100,12 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
|||
__u8 * data, yaffs_ExtendedTags * tags)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
struct mtd_oob_ops ops;
|
||||
#endif
|
||||
size_t dummy;
|
||||
int retval = 0;
|
||||
int localData = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||
|
||||
|
@ -116,9 +116,20 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
|||
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
|
||||
TENDSTR), chunkInNAND, data, tags));
|
||||
|
||||
if(dev->inbandTags){
|
||||
|
||||
if(!data) {
|
||||
localData = 1;
|
||||
data = yaffs_GetTempBuffer(dev,__LINE__);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
if (data && !tags)
|
||||
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
|
||||
if (dev->inbandTags || (data && !tags))
|
||||
retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
|
||||
&dummy, data);
|
||||
else if (tags) {
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
|
@ -130,38 +141,43 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
|||
retval = mtd->read_oob(mtd, addr, &ops);
|
||||
}
|
||||
#else
|
||||
if (data && tags) {
|
||||
if (dev->useNANDECC) {
|
||||
retval =
|
||||
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
if (!dev->inbandTags && data && tags) {
|
||||
|
||||
retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, dev->spareBuffer,
|
||||
NULL);
|
||||
} else {
|
||||
retval =
|
||||
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, dev->spareBuffer,
|
||||
NULL);
|
||||
}
|
||||
} else {
|
||||
if (data)
|
||||
retval =
|
||||
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||
data);
|
||||
if (tags)
|
||||
if (!dev->inbandTags && tags)
|
||||
retval =
|
||||
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||
dev->spareBuffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy(&pt, dev->spareBuffer, sizeof(pt));
|
||||
|
||||
if (tags)
|
||||
yaffs_UnpackTags2(tags, &pt);
|
||||
if(dev->inbandTags){
|
||||
if(tags){
|
||||
yaffs_PackedTags2TagsPart * pt2tp;
|
||||
pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
|
||||
yaffs_UnpackTags2TagsPart(tags,pt2tp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (tags){
|
||||
memcpy(&pt, dev->spareBuffer, sizeof(pt));
|
||||
yaffs_UnpackTags2(tags, &pt);
|
||||
}
|
||||
}
|
||||
|
||||
if(localData)
|
||||
yaffs_ReleaseTempBuffer(dev,data,__LINE__);
|
||||
|
||||
if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
|
||||
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
|
|
|
@ -12,12 +12,13 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_nand_c_version =
|
||||
"$Id: yaffs_nand.c,v 1.7 2007-02-14 01:09:06 wookey Exp $";
|
||||
"$Id: yaffs_nand.c,v 1.9 2008-05-05 07:58:58 charles Exp $";
|
||||
|
||||
#include "yaffs_nand.h"
|
||||
#include "yaffs_tagscompat.h"
|
||||
#include "yaffs_tagsvalidity.h"
|
||||
|
||||
#include "yaffs_getblockinfo.h"
|
||||
|
||||
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
__u8 * buffer,
|
||||
|
@ -98,7 +99,7 @@ int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
|
|||
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
|
||||
int blockNo,
|
||||
yaffs_BlockState * state,
|
||||
unsigned *sequenceNumber)
|
||||
__u32 *sequenceNumber)
|
||||
{
|
||||
blockNo -= dev->blockOffset;
|
||||
|
||||
|
|
|
@ -22,13 +22,13 @@
|
|||
|
||||
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND, const __u8 * data,
|
||||
yaffs_ExtendedTags * tags);
|
||||
const yaffs_ExtendedTags * tags);
|
||||
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND, __u8 * data,
|
||||
yaffs_ExtendedTags * tags);
|
||||
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState * state, int *sequenceNumber);
|
||||
yaffs_BlockState * state, __u32 *sequenceNumber);
|
||||
int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
||||
int blockInNAND);
|
||||
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
|
||||
|
|
|
@ -37,60 +37,70 @@
|
|||
#define EXTRA_OBJECT_TYPE_SHIFT (28)
|
||||
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
|
||||
|
||||
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
|
||||
|
||||
static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart * ptt)
|
||||
{
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
|
||||
pt->t.objectId, pt->t.chunkId, pt->t.byteCount,
|
||||
pt->t.sequenceNumber));
|
||||
ptt->objectId, ptt->chunkId, ptt->byteCount,
|
||||
ptt->sequenceNumber));
|
||||
}
|
||||
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
|
||||
{
|
||||
yaffs_DumpPackedTags2TagsPart(&pt->t);
|
||||
}
|
||||
|
||||
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
|
||||
{
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR
|
||||
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte "
|
||||
"%d del %d ser %d seq %d"
|
||||
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
|
||||
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
|
||||
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
|
||||
t->sequenceNumber));
|
||||
|
||||
}
|
||||
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
|
||||
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart * ptt, const yaffs_ExtendedTags * t)
|
||||
{
|
||||
pt->t.chunkId = t->chunkId;
|
||||
pt->t.sequenceNumber = t->sequenceNumber;
|
||||
pt->t.byteCount = t->byteCount;
|
||||
pt->t.objectId = t->objectId;
|
||||
ptt->chunkId = t->chunkId;
|
||||
ptt->sequenceNumber = t->sequenceNumber;
|
||||
ptt->byteCount = t->byteCount;
|
||||
ptt->objectId = t->objectId;
|
||||
|
||||
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
|
||||
/* Store the extra header info instead */
|
||||
/* We save the parent object in the chunkId */
|
||||
pt->t.chunkId = EXTRA_HEADER_INFO_FLAG
|
||||
ptt->chunkId = EXTRA_HEADER_INFO_FLAG
|
||||
| t->extraParentObjectId;
|
||||
if (t->extraIsShrinkHeader) {
|
||||
pt->t.chunkId |= EXTRA_SHRINK_FLAG;
|
||||
ptt->chunkId |= EXTRA_SHRINK_FLAG;
|
||||
}
|
||||
if (t->extraShadows) {
|
||||
pt->t.chunkId |= EXTRA_SHADOWS_FLAG;
|
||||
ptt->chunkId |= EXTRA_SHADOWS_FLAG;
|
||||
}
|
||||
|
||||
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
pt->t.objectId |=
|
||||
ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
ptt->objectId |=
|
||||
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||
pt->t.byteCount = t->extraEquivalentObjectId;
|
||||
ptt->byteCount = t->extraEquivalentObjectId;
|
||||
} else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
|
||||
pt->t.byteCount = t->extraFileLength;
|
||||
ptt->byteCount = t->extraFileLength;
|
||||
} else {
|
||||
pt->t.byteCount = 0;
|
||||
ptt->byteCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2(pt);
|
||||
yaffs_DumpPackedTags2TagsPart(ptt);
|
||||
yaffs_DumpTags2(t);
|
||||
}
|
||||
|
||||
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
|
||||
{
|
||||
yaffs_PackTags2TagsPart(&pt->t,t);
|
||||
|
||||
#ifndef YAFFS_IGNORE_TAGS_ECC
|
||||
{
|
||||
|
@ -101,13 +111,60 @@ void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
|
|||
#endif
|
||||
}
|
||||
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
|
||||
|
||||
void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags * t, yaffs_PackedTags2TagsPart * ptt)
|
||||
{
|
||||
|
||||
memset(t, 0, sizeof(yaffs_ExtendedTags));
|
||||
|
||||
yaffs_InitialiseTags(t);
|
||||
|
||||
if (ptt->sequenceNumber != 0xFFFFFFFF) {
|
||||
t->blockBad = 0;
|
||||
t->chunkUsed = 1;
|
||||
t->objectId = ptt->objectId;
|
||||
t->chunkId = ptt->chunkId;
|
||||
t->byteCount = ptt->byteCount;
|
||||
t->chunkDeleted = 0;
|
||||
t->serialNumber = 0;
|
||||
t->sequenceNumber = ptt->sequenceNumber;
|
||||
|
||||
/* Do extra header info stuff */
|
||||
|
||||
if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) {
|
||||
t->chunkId = 0;
|
||||
t->byteCount = 0;
|
||||
|
||||
t->extraHeaderInfoAvailable = 1;
|
||||
t->extraParentObjectId =
|
||||
ptt->chunkId & (~(ALL_EXTRA_FLAGS));
|
||||
t->extraIsShrinkHeader =
|
||||
(ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
|
||||
t->extraShadows =
|
||||
(ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
|
||||
t->extraObjectType =
|
||||
ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT;
|
||||
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||
t->extraEquivalentObjectId = ptt->byteCount;
|
||||
} else {
|
||||
t->extraFileLength = ptt->byteCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2TagsPart(ptt);
|
||||
yaffs_DumpTags2(t);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
|
||||
{
|
||||
|
||||
yaffs_UnpackTags2TagsPart(t,&pt->t);
|
||||
|
||||
if (pt->t.sequenceNumber != 0xFFFFFFFF) {
|
||||
/* Page is in use */
|
||||
#ifdef YAFFS_IGNORE_TAGS_ECC
|
||||
|
@ -142,41 +199,10 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
t->blockBad = 0;
|
||||
t->chunkUsed = 1;
|
||||
t->objectId = pt->t.objectId;
|
||||
t->chunkId = pt->t.chunkId;
|
||||
t->byteCount = pt->t.byteCount;
|
||||
t->chunkDeleted = 0;
|
||||
t->serialNumber = 0;
|
||||
t->sequenceNumber = pt->t.sequenceNumber;
|
||||
|
||||
/* Do extra header info stuff */
|
||||
|
||||
if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) {
|
||||
t->chunkId = 0;
|
||||
t->byteCount = 0;
|
||||
|
||||
t->extraHeaderInfoAvailable = 1;
|
||||
t->extraParentObjectId =
|
||||
pt->t.chunkId & (~(ALL_EXTRA_FLAGS));
|
||||
t->extraIsShrinkHeader =
|
||||
(pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
|
||||
t->extraShadows =
|
||||
(pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
|
||||
t->extraObjectType =
|
||||
pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT;
|
||||
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||
t->extraEquivalentObjectId = pt->t.byteCount;
|
||||
} else {
|
||||
t->extraFileLength = pt->t.byteCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2(pt);
|
||||
yaffs_DumpTags2(t);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ typedef struct {
|
|||
yaffs_ECCOther ecc;
|
||||
} yaffs_PackedTags2;
|
||||
|
||||
/* Full packed tags with ECC, used for oob tags */
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt);
|
||||
|
||||
/* Only the tags part (no ECC for use with inband tags */
|
||||
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart * pt, const yaffs_ExtendedTags * t);
|
||||
void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags * t, yaffs_PackedTags2TagsPart * pt);
|
||||
#endif
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "yaffs_guts.h"
|
||||
#include "yaffs_tagscompat.h"
|
||||
#include "yaffs_ecc.h"
|
||||
#include "yaffs_getblockinfo.h"
|
||||
|
||||
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
|
||||
#ifdef NOTYET
|
||||
|
@ -438,7 +439,7 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
|
|||
yaffs_ECCResult eccResult;
|
||||
|
||||
static yaffs_Spare spareFF;
|
||||
static int init;
|
||||
static int init = 0;
|
||||
|
||||
if (!init) {
|
||||
memset(&spareFF, 0xFF, sizeof(spareFF));
|
||||
|
@ -497,9 +498,9 @@ int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
|||
}
|
||||
|
||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo, yaffs_BlockState *
|
||||
state,
|
||||
int *sequenceNumber)
|
||||
int blockNo,
|
||||
yaffs_BlockState *state,
|
||||
__u32 *sequenceNumber)
|
||||
{
|
||||
|
||||
yaffs_Spare spare0, spare1;
|
||||
|
|
|
@ -30,8 +30,9 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
|
|||
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo);
|
||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo, yaffs_BlockState *
|
||||
state, int *sequenceNumber);
|
||||
int blockNo,
|
||||
yaffs_BlockState *state,
|
||||
__u32 *sequenceNumber);
|
||||
|
||||
void yaffs_CalcTagsECC(yaffs_Tags * tags);
|
||||
int yaffs_CheckECCOnTags(yaffs_Tags * tags);
|
||||
|
|
|
@ -17,6 +17,14 @@
|
|||
#ifndef __YPORTENV_H__
|
||||
#define __YPORTENV_H__
|
||||
|
||||
/*
|
||||
* Define the MTD version in terms of Linux Kernel versions
|
||||
* This allows yaffs to be used independantly of the kernel
|
||||
* as well as with it.
|
||||
*/
|
||||
|
||||
#define MTD_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
|
||||
|
||||
#if defined CONFIG_YAFFS_WINCE
|
||||
|
||||
#include "ywinceenv.h"
|
||||
|
@ -26,7 +34,10 @@
|
|||
#include "moduleconfig.h"
|
||||
|
||||
/* Linux kernel */
|
||||
|
||||
#include <linux/version.h>
|
||||
#define MTD_VERSION_CODE LINUX_VERSION_CODE
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
|
||||
#include <linux/config.h>
|
||||
#endif
|
||||
|
@ -90,6 +101,8 @@
|
|||
|
||||
#elif defined CONFIG_YAFFS_DIRECT
|
||||
|
||||
#define MTD_VERSION_CODE MTD_VERSION(2,6,22)
|
||||
|
||||
/* Direct interface */
|
||||
#include "ydirectenv.h"
|
||||
|
||||
|
@ -180,8 +193,8 @@ extern unsigned int yaffs_wr_attempts;
|
|||
|
||||
#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
|
||||
|
||||
#ifndef CONFIG_YAFFS_WINCE
|
||||
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))
|
||||
#ifndef YBUG
|
||||
#define YBUG() do {T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__));} while(0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,7 +43,8 @@ config YAFFS_9BYTE_TAGS
|
|||
format that you need to continue to support. New data written
|
||||
also uses the older-style format. Note: Use of this option
|
||||
generally requires that MTD's oob layout be adjusted to use the
|
||||
older-style format. See notes on tags formats and MTD versions.
|
||||
older-style format. See notes on tags formats and MTD versions
|
||||
in yaffs_mtdif1.c.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
|
@ -109,26 +110,6 @@ config YAFFS_DISABLE_LAZY_LOAD
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config YAFFS_CHECKPOINT_RESERVED_BLOCKS
|
||||
int "Reserved blocks for checkpointing"
|
||||
depends on YAFFS_YAFFS2
|
||||
default 10
|
||||
help
|
||||
Give the number of Blocks to reserve for checkpointing.
|
||||
Checkpointing saves the state at unmount so that mounting is
|
||||
much faster as a scan of all the flash to regenerate this state
|
||||
is not needed. These Blocks are reserved per partition, so if
|
||||
you have very small partitions the default (10) may be a mess
|
||||
for you. You can set this value to 0, but that does not mean
|
||||
checkpointing is disabled at all. There only won't be any
|
||||
specially reserved blocks for checkpointing, so if there is
|
||||
enough free space on the filesystem, it will be used for
|
||||
checkpointing.
|
||||
|
||||
If unsure, leave at default (10), but don't wonder if there are
|
||||
always 2MB used on your large page device partition (10 x 2k
|
||||
pagesize). When using small partitions or when being very small
|
||||
on space, you probably want to set this to zero.
|
||||
|
||||
config YAFFS_DISABLE_WIDE_TNODES
|
||||
bool "Turn off wide tnodes"
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
obj-$(CONFIG_YAFFS_FS) += yaffs.o
|
||||
|
||||
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
|
||||
yaffs-y += yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
|
||||
yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
|
||||
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
|
||||
yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o
|
||||
yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o
|
||||
yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
|
||||
|
|
|
@ -14,194 +14,117 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* This file is just holds extra declarations used during development.
|
||||
* Most of these are from kernel includes placed here so we can use them in
|
||||
* applications.
|
||||
* 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 __EXTRAS_H__
|
||||
#define __EXTRAS_H__
|
||||
|
||||
#if defined WIN32
|
||||
#define __inline__ __inline
|
||||
#define new newHack
|
||||
#endif
|
||||
|
||||
#if !(defined __KERNEL__) || (defined WIN32)
|
||||
|
||||
/* User space defines */
|
||||
#if !(defined __KERNEL__)
|
||||
|
||||
/* Definition of types */
|
||||
typedef unsigned char __u8;
|
||||
typedef unsigned short __u16;
|
||||
typedef unsigned __u32;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
* This is a simple doubly linked list implementation that matches the
|
||||
* way the Linux kernel doubly linked list implementation works.
|
||||
*/
|
||||
|
||||
#define prefetch(x) 1
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
struct ylist_head {
|
||||
struct ylist_head *next; /* next in chain */
|
||||
struct ylist_head *prev; /* previous in chain */
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
/* Initialise a list head to an empty list */
|
||||
#define YINIT_LIST_HEAD(p) \
|
||||
do { \
|
||||
(p)->next = (p);\
|
||||
(p)->prev = (p); \
|
||||
} while(0)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
/* Add an element to a list */
|
||||
static __inline__ void ylist_add(struct ylist_head *newEntry,
|
||||
struct ylist_head *list)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
struct ylist_head *listNext = list->next;
|
||||
|
||||
list->next = newEntry;
|
||||
newEntry->prev = list;
|
||||
newEntry->next = listNext;
|
||||
listNext->prev = newEntry;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static __inline__ void list_add(struct list_head *new, struct list_head *head)
|
||||
|
||||
/* 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)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
struct ylist_head *listNext = entry->next;
|
||||
struct ylist_head *listPrev = entry->prev;
|
||||
|
||||
listNext->prev = listPrev;
|
||||
listPrev->next = listNext;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static __inline__ void list_add_tail(struct list_head *new,
|
||||
struct list_head *head)
|
||||
static __inline__ void ylist_del_init(struct ylist_head *entry)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
ylist_del(entry);
|
||||
entry->next = entry->prev = entry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_del(struct list_head *prev,
|
||||
struct list_head *next)
|
||||
|
||||
/* Test if the list is empty */
|
||||
static __inline__ int ylist_empty(struct ylist_head *entry)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
return (entry->next == entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
static __inline__ void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
|
||||
#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
|
||||
*/
|
||||
static __inline__ void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static __inline__ int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
#define ylist_for_each(itervar, list) \
|
||||
for (itervar = (list)->next; itervar != (list); itervar = itervar->next )
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static __inline__ void list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
#define ylist_for_each_safe(itervar,saveVar, list) \
|
||||
for (itervar = (list)->next, saveVar = (list)->next->next; itervar != (list); \
|
||||
itervar = saveVar, saveVar = saveVar->next)
|
||||
|
||||
if (first != list) {
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
#if !(defined __KERNEL__)
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||
#ifndef WIN32
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
|
||||
pos = pos->next, prefetch(pos->next))
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal
|
||||
* of list entry
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
#ifdef CONFIG_YAFFS_PROVIDE_DEFS
|
||||
/* File types */
|
||||
|
||||
|
||||
/*
|
||||
* File types
|
||||
*/
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_FIFO 1
|
||||
#define DT_CHR 2
|
||||
|
@ -212,13 +135,13 @@ static __inline__ void list_splice(struct list_head *list,
|
|||
#define DT_SOCK 12
|
||||
#define DT_WHT 14
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Attribute flags. These should be or-ed together to figure out what
|
||||
* has been changed!
|
||||
* Attribute flags.
|
||||
*/
|
||||
#define ATTR_MODE 1
|
||||
#define ATTR_UID 2
|
||||
|
@ -227,10 +150,7 @@ static __inline__ void list_splice(struct list_head *list,
|
|||
#define ATTR_ATIME 16
|
||||
#define ATTR_MTIME 32
|
||||
#define ATTR_CTIME 64
|
||||
#define ATTR_ATIME_SET 128
|
||||
#define ATTR_MTIME_SET 256
|
||||
#define ATTR_FORCE 512 /* Not a change, but a change it */
|
||||
#define ATTR_ATTR_FLAG 1024
|
||||
|
||||
|
||||
struct iattr {
|
||||
unsigned int ia_valid;
|
||||
|
@ -244,21 +164,18 @@ struct iattr {
|
|||
unsigned int ia_attr_flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define KERN_DEBUG
|
||||
|
||||
#else
|
||||
|
||||
#ifndef WIN32
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/stat.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined WIN32
|
||||
#undef new
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,11 +54,11 @@ that you need to continue to support. New data written also uses the
|
|||
older-style format.
|
||||
Note: Use of this option generally requires that MTD's oob layout be
|
||||
adjusted to use the older-style format. See notes on tags formats and
|
||||
MTD versions.
|
||||
MTD versions in yaffs_mtdif1.c.
|
||||
*/
|
||||
/* Default: Not selected */
|
||||
/* Meaning: Use older-style on-NAND data format with pageStatus byte */
|
||||
#define CONFIG_YAFFS_9BYTE_TAGS
|
||||
//#define CONFIG_YAFFS_9BYTE_TAGS
|
||||
|
||||
#endif /* YAFFS_OUT_OF_TREE */
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_checkptrw_c_version =
|
||||
"$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $";
|
||||
"$Id: yaffs_checkptrw.c,v 1.16 2008-05-05 07:58:58 charles Exp $";
|
||||
|
||||
|
||||
#include "yaffs_checkptrw.h"
|
||||
|
||||
#include "yaffs_getblockinfo.h"
|
||||
|
||||
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
|
||||
{
|
||||
|
@ -142,7 +142,7 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
|
|||
return 0;
|
||||
|
||||
if(!dev->checkpointBuffer)
|
||||
dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
|
||||
dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
|
||||
if(!dev->checkpointBuffer)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_ecc_c_version =
|
||||
"$Id: yaffs_ecc.c,v 1.9 2007-02-14 01:09:06 wookey Exp $";
|
||||
"$Id: yaffs_ecc.c,v 1.10 2007-12-13 15:35:17 wookey Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_fs_c_version =
|
||||
"$Id: yaffs_fs.c,v 1.63 2007-09-19 20:35:40 imcd Exp $";
|
||||
"$Id: yaffs_fs.c,v 1.66 2008-05-05 07:58:58 charles Exp $";
|
||||
extern const char *yaffs_guts_c_version;
|
||||
|
||||
#include <linux/version.h>
|
||||
|
@ -53,6 +53,8 @@ extern const char *yaffs_guts_c_version;
|
|||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include "asm/div64.h"
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
|
||||
|
||||
#include <linux/statfs.h> /* Added NCB 15-8-2003 */
|
||||
|
@ -753,6 +755,8 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
|
|||
break;
|
||||
}
|
||||
|
||||
inode->i_flags |= S_NOATIME;
|
||||
|
||||
inode->i_ino = obj->objectId;
|
||||
inode->i_mode = obj->yst_mode;
|
||||
inode->i_uid = obj->yst_uid;
|
||||
|
@ -1350,25 +1354,47 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
|
|||
buf->f_type = YAFFS_MAGIC;
|
||||
buf->f_bsize = sb->s_blocksize;
|
||||
buf->f_namelen = 255;
|
||||
if (sb->s_blocksize > dev->nDataBytesPerChunk) {
|
||||
|
||||
if(dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)){
|
||||
/* Do this if chunk size is not a power of 2 */
|
||||
|
||||
uint64_t bytesInDev;
|
||||
uint64_t bytesFree;
|
||||
|
||||
bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock +1))) *
|
||||
((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
|
||||
|
||||
do_div(bytesInDev,sb->s_blocksize); /* bytesInDev becomes the number of blocks */
|
||||
buf->f_blocks = bytesInDev;
|
||||
|
||||
bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
|
||||
((uint64_t)(dev->nDataBytesPerChunk));
|
||||
|
||||
do_div(bytesFree,sb->s_blocksize);
|
||||
|
||||
buf->f_bfree = bytesFree;
|
||||
|
||||
} else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
|
||||
|
||||
buf->f_blocks =
|
||||
(dev->endBlock - dev->startBlock +
|
||||
1) * dev->nChunksPerBlock / (sb->s_blocksize /
|
||||
dev->nDataBytesPerChunk);
|
||||
buf->f_bfree =
|
||||
yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize /
|
||||
dev->nDataBytesPerChunk);
|
||||
(dev->endBlock - dev->startBlock + 1) *
|
||||
dev->nChunksPerBlock /
|
||||
(sb->s_blocksize / dev->nDataBytesPerChunk);
|
||||
buf->f_bfree =
|
||||
yaffs_GetNumberOfFreeChunks(dev) /
|
||||
(sb->s_blocksize / dev->nDataBytesPerChunk);
|
||||
} else {
|
||||
buf->f_blocks =
|
||||
(dev->endBlock - dev->startBlock + 1) *
|
||||
dev->nChunksPerBlock *
|
||||
(dev->nDataBytesPerChunk / sb->s_blocksize);
|
||||
|
||||
buf->f_blocks =
|
||||
(dev->endBlock - dev->startBlock +
|
||||
1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk /
|
||||
sb->s_blocksize);
|
||||
buf->f_bfree =
|
||||
yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk /
|
||||
sb->s_blocksize);
|
||||
buf->f_bfree =
|
||||
yaffs_GetNumberOfFreeChunks(dev) *
|
||||
(dev->nDataBytesPerChunk / sb->s_blocksize);
|
||||
}
|
||||
|
||||
|
||||
buf->f_files = 0;
|
||||
buf->f_ffree = 0;
|
||||
buf->f_bavail = buf->f_bfree;
|
||||
|
@ -1602,6 +1628,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
|
||||
sb->s_magic = YAFFS_MAGIC;
|
||||
sb->s_op = &yaffs_super_ops;
|
||||
sb->s_flags |= MS_NOATIME;
|
||||
|
||||
if (!sb)
|
||||
printk(KERN_INFO "yaffs: sb is NULL\n");
|
||||
|
@ -1678,22 +1705,15 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
#ifdef CONFIG_YAFFS_AUTO_YAFFS2
|
||||
|
||||
if (yaffsVersion == 1 &&
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
mtd->writesize >= 2048) {
|
||||
#else
|
||||
mtd->oobblock >= 2048) {
|
||||
#endif
|
||||
WRITE_SIZE(mtd) >= 2048) {
|
||||
T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
|
||||
yaffsVersion = 2;
|
||||
}
|
||||
|
||||
/* Added NCB 26/5/2006 for completeness */
|
||||
if (yaffsVersion == 2 &&
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
mtd->writesize == 512) {
|
||||
#else
|
||||
mtd->oobblock == 512) {
|
||||
#endif
|
||||
!options.inband_tags &&
|
||||
WRITE_SIZE(mtd) == 512){
|
||||
T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
|
||||
yaffsVersion = 1;
|
||||
}
|
||||
|
@ -1719,12 +1739,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
|
||||
#else
|
||||
if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
|
||||
#endif
|
||||
mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) {
|
||||
if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
|
||||
mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
|
||||
!options.inband_tags) {
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
("yaffs: MTD device does not have the "
|
||||
"right page sizes\n"));
|
||||
|
@ -1784,9 +1801,10 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
dev->startBlock = 0;
|
||||
dev->endBlock = nBlocks - 1;
|
||||
dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
|
||||
dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
|
||||
dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
|
||||
dev->nReservedBlocks = 5;
|
||||
dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
|
||||
dev->inbandTags = options.inband_tags;
|
||||
|
||||
/* ... and the functions. */
|
||||
if (yaffsVersion == 2) {
|
||||
|
@ -1799,15 +1817,14 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
dev->spareBuffer = YMALLOC(mtd->oobsize);
|
||||
dev->isYaffs2 = 1;
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
dev->nDataBytesPerChunk = mtd->writesize;
|
||||
dev->totalBytesPerChunk = mtd->writesize;
|
||||
dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
|
||||
#else
|
||||
dev->nDataBytesPerChunk = mtd->oobblock;
|
||||
dev->totalBytesPerChunk = mtd->oobblock;
|
||||
dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
|
||||
#endif
|
||||
nBlocks = mtd->size / mtd->erasesize;
|
||||
|
||||
dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS;
|
||||
dev->startBlock = 0;
|
||||
dev->endBlock = nBlocks - 1;
|
||||
} else {
|
||||
|
@ -1990,12 +2007,12 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
|
|||
{
|
||||
buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
|
||||
buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
|
||||
buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
|
||||
buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
|
||||
buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
|
||||
buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
|
||||
buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
|
||||
buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
|
||||
buf += sprintf(buf, "nCheckptResBlocks.. %d\n", dev->nCheckpointReservedBlocks);
|
||||
buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
|
||||
buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
|
||||
buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
|
||||
|
@ -2006,10 +2023,8 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
|
|||
buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
|
||||
buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
|
||||
buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
|
||||
buf +=
|
||||
sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
|
||||
buf +=
|
||||
sprintf(buf, "passiveGCs......... %d\n",
|
||||
buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
|
||||
buf += sprintf(buf, "passiveGCs......... %d\n",
|
||||
dev->passiveGarbageCollections);
|
||||
buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
|
||||
buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
|
||||
|
@ -2025,6 +2040,7 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
|
|||
sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
|
||||
buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
|
||||
buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
|
||||
buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_GETBLOCKINFO_H__
|
||||
#define __YAFFS_GETBLOCKINFO_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
/* Function to manipulate block info */
|
||||
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
|
||||
{
|
||||
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
|
||||
blk));
|
||||
YBUG();
|
||||
}
|
||||
return &dev->blockInfo[blk - dev->internalStartBlock];
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -90,7 +90,7 @@
|
|||
|
||||
#define YAFFS_MAX_SHORT_OP_CACHES 20
|
||||
|
||||
#define YAFFS_N_TEMP_BUFFERS 4
|
||||
#define YAFFS_N_TEMP_BUFFERS 6
|
||||
|
||||
/* We limit the number attempts at sucessfully saving a chunk of data.
|
||||
* Small-page devices have 32 pages per block; large-page devices have 64.
|
||||
|
@ -277,7 +277,7 @@ typedef struct {
|
|||
|
||||
int softDeletions:10; /* number of soft deleted pages */
|
||||
int pagesInUse:10; /* number of pages in use */
|
||||
yaffs_BlockState blockState:4; /* One of the above block states */
|
||||
unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
|
||||
__u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
|
||||
/* and retire the block. */
|
||||
__u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */
|
||||
|
@ -303,7 +303,7 @@ typedef struct {
|
|||
__u16 sum__NoLongerUsed; /* checksum of name. No longer used */
|
||||
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
|
||||
|
||||
/* Thes following apply to directories, files, symlinks - not hard links */
|
||||
/* The following apply to directories, files, symlinks - not hard links */
|
||||
__u32 yst_mode; /* protection */
|
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE
|
||||
|
@ -331,11 +331,14 @@ typedef struct {
|
|||
__u32 win_ctime[2];
|
||||
__u32 win_atime[2];
|
||||
__u32 win_mtime[2];
|
||||
__u32 roomToGrow[4];
|
||||
#else
|
||||
__u32 roomToGrow[10];
|
||||
#endif
|
||||
__u32 roomToGrow[6];
|
||||
|
||||
#endif
|
||||
__u32 inbandShadowsObject;
|
||||
__u32 inbandIsShrink;
|
||||
|
||||
__u32 reservedSpace[2];
|
||||
int shadowsObject; /* This object header shadows the specified object if > 0 */
|
||||
|
||||
/* isShrink applies to object headers written when we shrink the file (ie resize) */
|
||||
|
@ -381,7 +384,7 @@ typedef struct {
|
|||
} yaffs_FileStructure;
|
||||
|
||||
typedef struct {
|
||||
struct list_head children; /* list of child links */
|
||||
struct ylist_head children; /* list of child links */
|
||||
} yaffs_DirectoryStructure;
|
||||
|
||||
typedef struct {
|
||||
|
@ -424,14 +427,14 @@ struct yaffs_ObjectStruct {
|
|||
|
||||
struct yaffs_DeviceStruct *myDev; /* The device I'm on */
|
||||
|
||||
struct list_head hashLink; /* list of objects in this hash bucket */
|
||||
struct ylist_head hashLink; /* list of objects in this hash bucket */
|
||||
|
||||
struct list_head hardLinks; /* all the equivalent hard linked objects */
|
||||
struct ylist_head hardLinks; /* all the equivalent hard linked objects */
|
||||
|
||||
/* directory structure stuff */
|
||||
/* also used for linking up the free list */
|
||||
struct yaffs_ObjectStruct *parent;
|
||||
struct list_head siblings;
|
||||
struct ylist_head siblings;
|
||||
|
||||
/* Where's my object header in NAND? */
|
||||
int chunkId;
|
||||
|
@ -485,7 +488,7 @@ struct yaffs_ObjectList_struct {
|
|||
typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
|
||||
|
||||
typedef struct {
|
||||
struct list_head list;
|
||||
struct ylist_head list;
|
||||
int count;
|
||||
} yaffs_ObjectBucket;
|
||||
|
||||
|
@ -528,7 +531,7 @@ typedef struct {
|
|||
/*----------------- Device ---------------------------------*/
|
||||
|
||||
struct yaffs_DeviceStruct {
|
||||
struct list_head devList;
|
||||
struct ylist_head devList;
|
||||
const char *name;
|
||||
|
||||
/* Entry parameters set up way early. Yaffs sets up the rest.*/
|
||||
|
@ -544,7 +547,7 @@ struct yaffs_DeviceStruct {
|
|||
/* Stuff used by the shared space checkpointing mechanism */
|
||||
/* If this value is zero, then this mechanism is disabled */
|
||||
|
||||
int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */
|
||||
// int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */
|
||||
|
||||
|
||||
|
||||
|
@ -583,7 +586,7 @@ struct yaffs_DeviceStruct {
|
|||
yaffs_ExtendedTags * tags);
|
||||
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
|
||||
int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,
|
||||
yaffs_BlockState * state, int *sequenceNumber);
|
||||
yaffs_BlockState * state, __u32 *sequenceNumber);
|
||||
#endif
|
||||
|
||||
int isYaffs2;
|
||||
|
@ -599,6 +602,7 @@ struct yaffs_DeviceStruct {
|
|||
|
||||
int wideTnodesDisabled; /* Set to disable wide tnodes */
|
||||
|
||||
YCHAR *pathDividers; /* String of legal path dividers */
|
||||
|
||||
/* End of stuff that must be set before initialisation. */
|
||||
|
||||
|
@ -615,16 +619,14 @@ struct yaffs_DeviceStruct {
|
|||
__u32 tnodeWidth;
|
||||
__u32 tnodeMask;
|
||||
|
||||
/* Stuff to support various file offses to chunk/offset translations */
|
||||
/* "Crumbs" for nDataBytesPerChunk not being a power of 2 */
|
||||
__u32 crumbMask;
|
||||
__u32 crumbShift;
|
||||
__u32 crumbsPerChunk;
|
||||
|
||||
/* Straight shifting for nDataBytesPerChunk being a power of 2 */
|
||||
__u32 chunkShift;
|
||||
__u32 chunkMask;
|
||||
/* Stuff for figuring out file offset to chunk conversions */
|
||||
__u32 chunkShift; /* Shift value */
|
||||
__u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
|
||||
__u32 chunkMask; /* Mask to use for power-of-2 case */
|
||||
|
||||
/* Stuff to handle inband tags */
|
||||
int inbandTags;
|
||||
__u32 totalBytesPerChunk;
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
|
@ -663,6 +665,8 @@ struct yaffs_DeviceStruct {
|
|||
__u32 checkpointSum;
|
||||
__u32 checkpointXor;
|
||||
|
||||
int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */
|
||||
|
||||
/* Block Info */
|
||||
yaffs_BlockInfo *blockInfo;
|
||||
__u8 *chunkBits; /* bitmap of chunks in use */
|
||||
|
@ -745,8 +749,10 @@ struct yaffs_DeviceStruct {
|
|||
int nBackgroundDeletions; /* Count of background deletions. */
|
||||
|
||||
|
||||
/* Temporary buffer management */
|
||||
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
|
||||
int maxTemp;
|
||||
int tempInUse;
|
||||
int unmanagedTempAllocations;
|
||||
int unmanagedTempDeallocations;
|
||||
|
||||
|
@ -758,7 +764,7 @@ struct yaffs_DeviceStruct {
|
|||
|
||||
typedef struct yaffs_DeviceStruct yaffs_Device;
|
||||
|
||||
/* The static layout of bllock usage etc is stored in the super block header */
|
||||
/* The static layout of block usage etc is stored in the super block header */
|
||||
typedef struct {
|
||||
int StructType;
|
||||
int version;
|
||||
|
@ -797,18 +803,6 @@ typedef struct {
|
|||
__u32 head;
|
||||
} yaffs_CheckpointValidity;
|
||||
|
||||
/* Function to manipulate block info */
|
||||
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
|
||||
{
|
||||
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
|
||||
blk));
|
||||
YBUG();
|
||||
}
|
||||
return &dev->blockInfo[blk - dev->internalStartBlock];
|
||||
}
|
||||
|
||||
/*----------------------- YAFFS Functions -----------------------*/
|
||||
|
||||
|
@ -899,4 +893,7 @@ void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn);
|
|||
int yaffs_CheckFF(__u8 * buffer, int nBytes);
|
||||
void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
|
||||
|
||||
__u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo);
|
||||
void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, int lineNo);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_mtdif_c_version =
|
||||
"$Id: yaffs_mtdif.c,v 1.19 2007-02-14 01:09:06 wookey Exp $";
|
||||
"$Id: yaffs_mtdif.c,v 1.21 2007-12-13 15:35:18 wookey Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
@ -24,7 +24,7 @@ const char *yaffs_mtdif_c_version =
|
|||
#include "linux/time.h"
|
||||
#include "linux/mtd/nand.h"
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
|
||||
#if (MTD_VERSION_CODE < MTD_VERSION(2,6,18))
|
||||
static struct nand_oobinfo yaffs_oobinfo = {
|
||||
.useecc = 1,
|
||||
.eccbytes = 6,
|
||||
|
@ -36,7 +36,7 @@ static struct nand_oobinfo yaffs_noeccinfo = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
|
||||
{
|
||||
oob[0] = spare->tagByte0;
|
||||
|
@ -75,14 +75,14 @@ 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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
__u8 spareAsBytes[8]; /* OOB */
|
||||
|
||||
if (data && !spare)
|
||||
|
@ -139,14 +139,14 @@ int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
|
|||
yaffs_Spare * spare)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
__u8 spareAsBytes[8]; /* OOB */
|
||||
|
||||
if (data && !spare)
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
#if (MTD_VERSION_CODE < MTD_VERSION(2,6,18))
|
||||
extern struct nand_oobinfo yaffs_oobinfo;
|
||||
extern struct nand_oobinfo yaffs_noeccinfo;
|
||||
#endif
|
||||
|
||||
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data, const yaffs_Spare * spare);
|
||||
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
|
||||
|
|
|
@ -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: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $";
|
||||
|
||||
#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--
|
||||
|
||||
|
||||
|
|
@ -34,9 +34,9 @@
|
|||
#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))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
|
||||
const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $";
|
||||
const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.7 2007-12-13 15:35:18 wookey Exp $";
|
||||
|
||||
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||
# define YTAG1_SIZE 8
|
||||
|
@ -189,7 +189,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
|||
ops.datbuf = data;
|
||||
ops.oobbuf = (__u8 *)&pt1;
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
|
||||
#if (MTD_VERSION_CODE < MTD_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.
|
||||
*/
|
||||
|
@ -288,7 +288,7 @@ int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
|||
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
|
||||
int retval;
|
||||
|
||||
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
|
||||
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
|
||||
|
||||
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
|
||||
return (retval) ? YAFFS_FAIL : YAFFS_OK;
|
||||
|
@ -327,6 +327,7 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
|||
{
|
||||
struct mtd_info * mtd = dev->genericDevice;
|
||||
int chunkNo = blockNo * dev->nChunksPerBlock;
|
||||
loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
|
||||
yaffs_ExtendedTags etags;
|
||||
int state = YAFFS_BLOCK_STATE_DEAD;
|
||||
int seqnum = 0;
|
||||
|
@ -340,11 +341,16 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
|||
}
|
||||
|
||||
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
|
||||
etags.blockBad = (mtd->block_isbad)(mtd, addr);
|
||||
if (etags.blockBad) {
|
||||
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
|
||||
"block %d is marked bad", blockNo);
|
||||
"block %d is marked bad\n", blockNo);
|
||||
state = YAFFS_BLOCK_STATE_DEAD;
|
||||
}
|
||||
else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
/* bad tags, need to look more closely */
|
||||
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
}
|
||||
else if (etags.chunkUsed) {
|
||||
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
seqnum = etags.sequenceNumber;
|
||||
|
@ -360,4 +366,4 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
|||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
#endif /*KERNEL_VERSION*/
|
||||
#endif /*MTD_VERSION*/
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
/* mtd interface for YAFFS2 */
|
||||
|
||||
const char *yaffs_mtdif2_c_version =
|
||||
"$Id: yaffs_mtdif2.c,v 1.17 2007-02-14 01:09:06 wookey Exp $";
|
||||
"$Id: yaffs_mtdif2.c,v 1.20 2008-05-05 07:58:58 charles Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
@ -27,19 +27,23 @@ const char *yaffs_mtdif2_c_version =
|
|||
|
||||
#include "yaffs_packedtags2.h"
|
||||
|
||||
/* NB For use with inband tags....
|
||||
* We assume that the data buffer is of size totalBytersPerChunk so that we can also
|
||||
* use it to load the tags.
|
||||
*/
|
||||
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data,
|
||||
const yaffs_ExtendedTags * tags)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
struct mtd_oob_ops ops;
|
||||
#else
|
||||
size_t dummy;
|
||||
#endif
|
||||
int retval = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||
loff_t addr;
|
||||
|
||||
yaffs_PackedTags2 pt;
|
||||
|
||||
|
@ -48,46 +52,41 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
|||
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
|
||||
TENDSTR), chunkInNAND, data, tags));
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
if (tags)
|
||||
yaffs_PackTags2(&pt, tags);
|
||||
else
|
||||
BUG(); /* both tags and data should always be present */
|
||||
|
||||
if (data) {
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.ooblen = sizeof(pt);
|
||||
ops.len = dev->nDataBytesPerChunk;
|
||||
ops.ooboffs = 0;
|
||||
ops.datbuf = (__u8 *)data;
|
||||
ops.oobbuf = (void *)&pt;
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
} else
|
||||
BUG(); /* both tags and data should always be present */
|
||||
#else
|
||||
if (tags) {
|
||||
yaffs_PackTags2(&pt, tags);
|
||||
addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
|
||||
|
||||
/* For yaffs2 writing there must be both data and tags.
|
||||
* If we're using inband tags, then the tags are stuffed into
|
||||
* the end of the data buffer.
|
||||
*/
|
||||
if(!data || !tags)
|
||||
BUG();
|
||||
else if(dev->inbandTags){
|
||||
yaffs_PackedTags2TagsPart *pt2tp;
|
||||
pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
|
||||
yaffs_PackTags2TagsPart(pt2tp,tags);
|
||||
}
|
||||
else
|
||||
yaffs_PackTags2(&pt, tags);
|
||||
|
||||
if (data && tags) {
|
||||
if (dev->useNANDECC)
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, (__u8 *) & pt, NULL);
|
||||
else
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, (__u8 *) & pt, NULL);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
|
||||
ops.len = dev->totalBytesPerChunk;
|
||||
ops.ooboffs = 0;
|
||||
ops.datbuf = (__u8 *)data;
|
||||
ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
|
||||
#else
|
||||
if (!dev->inbandTags) {
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, (__u8 *) & pt, NULL);
|
||||
} else {
|
||||
if (data)
|
||||
retval =
|
||||
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||
data);
|
||||
if (tags)
|
||||
retval =
|
||||
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||
(__u8 *) & pt);
|
||||
|
||||
retval =
|
||||
mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
|
||||
data);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -101,11 +100,12 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
|||
__u8 * data, yaffs_ExtendedTags * tags)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
struct mtd_oob_ops ops;
|
||||
#endif
|
||||
size_t dummy;
|
||||
int retval = 0;
|
||||
int localData = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||
|
||||
|
@ -116,9 +116,20 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
|||
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
|
||||
TENDSTR), chunkInNAND, data, tags));
|
||||
|
||||
if(dev->inbandTags){
|
||||
|
||||
if(!data) {
|
||||
localData = 1;
|
||||
data = yaffs_GetTempBuffer(dev,__LINE__);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
if (data && !tags)
|
||||
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
|
||||
if (dev->inbandTags || (data && !tags))
|
||||
retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
|
||||
&dummy, data);
|
||||
else if (tags) {
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
|
@ -130,38 +141,43 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
|||
retval = mtd->read_oob(mtd, addr, &ops);
|
||||
}
|
||||
#else
|
||||
if (data && tags) {
|
||||
if (dev->useNANDECC) {
|
||||
retval =
|
||||
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
if (!dev->inbandTags && data && tags) {
|
||||
|
||||
retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, dev->spareBuffer,
|
||||
NULL);
|
||||
} else {
|
||||
retval =
|
||||
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, dev->spareBuffer,
|
||||
NULL);
|
||||
}
|
||||
} else {
|
||||
if (data)
|
||||
retval =
|
||||
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||
data);
|
||||
if (tags)
|
||||
if (!dev->inbandTags && tags)
|
||||
retval =
|
||||
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||
dev->spareBuffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy(&pt, dev->spareBuffer, sizeof(pt));
|
||||
|
||||
if (tags)
|
||||
yaffs_UnpackTags2(tags, &pt);
|
||||
if(dev->inbandTags){
|
||||
if(tags){
|
||||
yaffs_PackedTags2TagsPart * pt2tp;
|
||||
pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
|
||||
yaffs_UnpackTags2TagsPart(tags,pt2tp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (tags){
|
||||
memcpy(&pt, dev->spareBuffer, sizeof(pt));
|
||||
yaffs_UnpackTags2(tags, &pt);
|
||||
}
|
||||
}
|
||||
|
||||
if(localData)
|
||||
yaffs_ReleaseTempBuffer(dev,data,__LINE__);
|
||||
|
||||
if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
|
||||
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
|
|
|
@ -12,12 +12,13 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_nand_c_version =
|
||||
"$Id: yaffs_nand.c,v 1.7 2007-02-14 01:09:06 wookey Exp $";
|
||||
"$Id: yaffs_nand.c,v 1.9 2008-05-05 07:58:58 charles Exp $";
|
||||
|
||||
#include "yaffs_nand.h"
|
||||
#include "yaffs_tagscompat.h"
|
||||
#include "yaffs_tagsvalidity.h"
|
||||
|
||||
#include "yaffs_getblockinfo.h"
|
||||
|
||||
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
__u8 * buffer,
|
||||
|
@ -98,7 +99,7 @@ int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
|
|||
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
|
||||
int blockNo,
|
||||
yaffs_BlockState * state,
|
||||
unsigned *sequenceNumber)
|
||||
__u32 *sequenceNumber)
|
||||
{
|
||||
blockNo -= dev->blockOffset;
|
||||
|
||||
|
|
|
@ -22,13 +22,13 @@
|
|||
|
||||
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND, const __u8 * data,
|
||||
yaffs_ExtendedTags * tags);
|
||||
const yaffs_ExtendedTags * tags);
|
||||
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND, __u8 * data,
|
||||
yaffs_ExtendedTags * tags);
|
||||
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState * state, int *sequenceNumber);
|
||||
yaffs_BlockState * state, __u32 *sequenceNumber);
|
||||
int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
||||
int blockInNAND);
|
||||
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
|
||||
|
|
|
@ -37,60 +37,70 @@
|
|||
#define EXTRA_OBJECT_TYPE_SHIFT (28)
|
||||
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
|
||||
|
||||
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
|
||||
|
||||
static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart * ptt)
|
||||
{
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
|
||||
pt->t.objectId, pt->t.chunkId, pt->t.byteCount,
|
||||
pt->t.sequenceNumber));
|
||||
ptt->objectId, ptt->chunkId, ptt->byteCount,
|
||||
ptt->sequenceNumber));
|
||||
}
|
||||
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
|
||||
{
|
||||
yaffs_DumpPackedTags2TagsPart(&pt->t);
|
||||
}
|
||||
|
||||
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
|
||||
{
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR
|
||||
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte "
|
||||
"%d del %d ser %d seq %d"
|
||||
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
|
||||
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
|
||||
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
|
||||
t->sequenceNumber));
|
||||
|
||||
}
|
||||
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
|
||||
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart * ptt, const yaffs_ExtendedTags * t)
|
||||
{
|
||||
pt->t.chunkId = t->chunkId;
|
||||
pt->t.sequenceNumber = t->sequenceNumber;
|
||||
pt->t.byteCount = t->byteCount;
|
||||
pt->t.objectId = t->objectId;
|
||||
ptt->chunkId = t->chunkId;
|
||||
ptt->sequenceNumber = t->sequenceNumber;
|
||||
ptt->byteCount = t->byteCount;
|
||||
ptt->objectId = t->objectId;
|
||||
|
||||
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
|
||||
/* Store the extra header info instead */
|
||||
/* We save the parent object in the chunkId */
|
||||
pt->t.chunkId = EXTRA_HEADER_INFO_FLAG
|
||||
ptt->chunkId = EXTRA_HEADER_INFO_FLAG
|
||||
| t->extraParentObjectId;
|
||||
if (t->extraIsShrinkHeader) {
|
||||
pt->t.chunkId |= EXTRA_SHRINK_FLAG;
|
||||
ptt->chunkId |= EXTRA_SHRINK_FLAG;
|
||||
}
|
||||
if (t->extraShadows) {
|
||||
pt->t.chunkId |= EXTRA_SHADOWS_FLAG;
|
||||
ptt->chunkId |= EXTRA_SHADOWS_FLAG;
|
||||
}
|
||||
|
||||
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
pt->t.objectId |=
|
||||
ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
ptt->objectId |=
|
||||
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||
pt->t.byteCount = t->extraEquivalentObjectId;
|
||||
ptt->byteCount = t->extraEquivalentObjectId;
|
||||
} else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
|
||||
pt->t.byteCount = t->extraFileLength;
|
||||
ptt->byteCount = t->extraFileLength;
|
||||
} else {
|
||||
pt->t.byteCount = 0;
|
||||
ptt->byteCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2(pt);
|
||||
yaffs_DumpPackedTags2TagsPart(ptt);
|
||||
yaffs_DumpTags2(t);
|
||||
}
|
||||
|
||||
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
|
||||
{
|
||||
yaffs_PackTags2TagsPart(&pt->t,t);
|
||||
|
||||
#ifndef YAFFS_IGNORE_TAGS_ECC
|
||||
{
|
||||
|
@ -101,13 +111,60 @@ void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
|
|||
#endif
|
||||
}
|
||||
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
|
||||
|
||||
void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags * t, yaffs_PackedTags2TagsPart * ptt)
|
||||
{
|
||||
|
||||
memset(t, 0, sizeof(yaffs_ExtendedTags));
|
||||
|
||||
yaffs_InitialiseTags(t);
|
||||
|
||||
if (ptt->sequenceNumber != 0xFFFFFFFF) {
|
||||
t->blockBad = 0;
|
||||
t->chunkUsed = 1;
|
||||
t->objectId = ptt->objectId;
|
||||
t->chunkId = ptt->chunkId;
|
||||
t->byteCount = ptt->byteCount;
|
||||
t->chunkDeleted = 0;
|
||||
t->serialNumber = 0;
|
||||
t->sequenceNumber = ptt->sequenceNumber;
|
||||
|
||||
/* Do extra header info stuff */
|
||||
|
||||
if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) {
|
||||
t->chunkId = 0;
|
||||
t->byteCount = 0;
|
||||
|
||||
t->extraHeaderInfoAvailable = 1;
|
||||
t->extraParentObjectId =
|
||||
ptt->chunkId & (~(ALL_EXTRA_FLAGS));
|
||||
t->extraIsShrinkHeader =
|
||||
(ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
|
||||
t->extraShadows =
|
||||
(ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
|
||||
t->extraObjectType =
|
||||
ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT;
|
||||
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||
t->extraEquivalentObjectId = ptt->byteCount;
|
||||
} else {
|
||||
t->extraFileLength = ptt->byteCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2TagsPart(ptt);
|
||||
yaffs_DumpTags2(t);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
|
||||
{
|
||||
|
||||
yaffs_UnpackTags2TagsPart(t,&pt->t);
|
||||
|
||||
if (pt->t.sequenceNumber != 0xFFFFFFFF) {
|
||||
/* Page is in use */
|
||||
#ifdef YAFFS_IGNORE_TAGS_ECC
|
||||
|
@ -142,41 +199,10 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
t->blockBad = 0;
|
||||
t->chunkUsed = 1;
|
||||
t->objectId = pt->t.objectId;
|
||||
t->chunkId = pt->t.chunkId;
|
||||
t->byteCount = pt->t.byteCount;
|
||||
t->chunkDeleted = 0;
|
||||
t->serialNumber = 0;
|
||||
t->sequenceNumber = pt->t.sequenceNumber;
|
||||
|
||||
/* Do extra header info stuff */
|
||||
|
||||
if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) {
|
||||
t->chunkId = 0;
|
||||
t->byteCount = 0;
|
||||
|
||||
t->extraHeaderInfoAvailable = 1;
|
||||
t->extraParentObjectId =
|
||||
pt->t.chunkId & (~(ALL_EXTRA_FLAGS));
|
||||
t->extraIsShrinkHeader =
|
||||
(pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
|
||||
t->extraShadows =
|
||||
(pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
|
||||
t->extraObjectType =
|
||||
pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT;
|
||||
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||
t->extraEquivalentObjectId = pt->t.byteCount;
|
||||
} else {
|
||||
t->extraFileLength = pt->t.byteCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2(pt);
|
||||
yaffs_DumpTags2(t);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ typedef struct {
|
|||
yaffs_ECCOther ecc;
|
||||
} yaffs_PackedTags2;
|
||||
|
||||
/* Full packed tags with ECC, used for oob tags */
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt);
|
||||
|
||||
/* Only the tags part (no ECC for use with inband tags */
|
||||
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart * pt, const yaffs_ExtendedTags * t);
|
||||
void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags * t, yaffs_PackedTags2TagsPart * pt);
|
||||
#endif
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "yaffs_guts.h"
|
||||
#include "yaffs_tagscompat.h"
|
||||
#include "yaffs_ecc.h"
|
||||
#include "yaffs_getblockinfo.h"
|
||||
|
||||
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
|
||||
#ifdef NOTYET
|
||||
|
@ -438,7 +439,7 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
|
|||
yaffs_ECCResult eccResult;
|
||||
|
||||
static yaffs_Spare spareFF;
|
||||
static int init;
|
||||
static int init = 0;
|
||||
|
||||
if (!init) {
|
||||
memset(&spareFF, 0xFF, sizeof(spareFF));
|
||||
|
@ -497,9 +498,9 @@ int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
|||
}
|
||||
|
||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo, yaffs_BlockState *
|
||||
state,
|
||||
int *sequenceNumber)
|
||||
int blockNo,
|
||||
yaffs_BlockState *state,
|
||||
__u32 *sequenceNumber)
|
||||
{
|
||||
|
||||
yaffs_Spare spare0, spare1;
|
||||
|
|
|
@ -30,8 +30,9 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
|
|||
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo);
|
||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo, yaffs_BlockState *
|
||||
state, int *sequenceNumber);
|
||||
int blockNo,
|
||||
yaffs_BlockState *state,
|
||||
__u32 *sequenceNumber);
|
||||
|
||||
void yaffs_CalcTagsECC(yaffs_Tags * tags);
|
||||
int yaffs_CheckECCOnTags(yaffs_Tags * tags);
|
||||
|
|
|
@ -17,6 +17,14 @@
|
|||
#ifndef __YPORTENV_H__
|
||||
#define __YPORTENV_H__
|
||||
|
||||
/*
|
||||
* Define the MTD version in terms of Linux Kernel versions
|
||||
* This allows yaffs to be used independantly of the kernel
|
||||
* as well as with it.
|
||||
*/
|
||||
|
||||
#define MTD_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
|
||||
|
||||
#if defined CONFIG_YAFFS_WINCE
|
||||
|
||||
#include "ywinceenv.h"
|
||||
|
@ -26,7 +34,10 @@
|
|||
#include "moduleconfig.h"
|
||||
|
||||
/* Linux kernel */
|
||||
|
||||
#include <linux/version.h>
|
||||
#define MTD_VERSION_CODE LINUX_VERSION_CODE
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
|
||||
#include <linux/config.h>
|
||||
#endif
|
||||
|
@ -90,6 +101,8 @@
|
|||
|
||||
#elif defined CONFIG_YAFFS_DIRECT
|
||||
|
||||
#define MTD_VERSION_CODE MTD_VERSION(2,6,22)
|
||||
|
||||
/* Direct interface */
|
||||
#include "ydirectenv.h"
|
||||
|
||||
|
@ -180,8 +193,8 @@ extern unsigned int yaffs_wr_attempts;
|
|||
|
||||
#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
|
||||
|
||||
#ifndef CONFIG_YAFFS_WINCE
|
||||
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))
|
||||
#ifndef YBUG
|
||||
#define YBUG() do {T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__));} while(0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,7 +43,8 @@ config YAFFS_9BYTE_TAGS
|
|||
format that you need to continue to support. New data written
|
||||
also uses the older-style format. Note: Use of this option
|
||||
generally requires that MTD's oob layout be adjusted to use the
|
||||
older-style format. See notes on tags formats and MTD versions.
|
||||
older-style format. See notes on tags formats and MTD versions
|
||||
in yaffs_mtdif1.c.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
|
@ -109,26 +110,6 @@ config YAFFS_DISABLE_LAZY_LOAD
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config YAFFS_CHECKPOINT_RESERVED_BLOCKS
|
||||
int "Reserved blocks for checkpointing"
|
||||
depends on YAFFS_YAFFS2
|
||||
default 10
|
||||
help
|
||||
Give the number of Blocks to reserve for checkpointing.
|
||||
Checkpointing saves the state at unmount so that mounting is
|
||||
much faster as a scan of all the flash to regenerate this state
|
||||
is not needed. These Blocks are reserved per partition, so if
|
||||
you have very small partitions the default (10) may be a mess
|
||||
for you. You can set this value to 0, but that does not mean
|
||||
checkpointing is disabled at all. There only won't be any
|
||||
specially reserved blocks for checkpointing, so if there is
|
||||
enough free space on the filesystem, it will be used for
|
||||
checkpointing.
|
||||
|
||||
If unsure, leave at default (10), but don't wonder if there are
|
||||
always 2MB used on your large page device partition (10 x 2k
|
||||
pagesize). When using small partitions or when being very small
|
||||
on space, you probably want to set this to zero.
|
||||
|
||||
config YAFFS_DISABLE_WIDE_TNODES
|
||||
bool "Turn off wide tnodes"
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
obj-$(CONFIG_YAFFS_FS) += yaffs.o
|
||||
|
||||
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
|
||||
yaffs-y += yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
|
||||
yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
|
||||
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
|
||||
yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o
|
||||
yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o
|
||||
yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
|
||||
|
|
|
@ -14,194 +14,117 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* This file is just holds extra declarations used during development.
|
||||
* Most of these are from kernel includes placed here so we can use them in
|
||||
* applications.
|
||||
* 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 __EXTRAS_H__
|
||||
#define __EXTRAS_H__
|
||||
|
||||
#if defined WIN32
|
||||
#define __inline__ __inline
|
||||
#define new newHack
|
||||
#endif
|
||||
|
||||
#if !(defined __KERNEL__) || (defined WIN32)
|
||||
|
||||
/* User space defines */
|
||||
#if !(defined __KERNEL__)
|
||||
|
||||
/* Definition of types */
|
||||
typedef unsigned char __u8;
|
||||
typedef unsigned short __u16;
|
||||
typedef unsigned __u32;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
* This is a simple doubly linked list implementation that matches the
|
||||
* way the Linux kernel doubly linked list implementation works.
|
||||
*/
|
||||
|
||||
#define prefetch(x) 1
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
struct ylist_head {
|
||||
struct ylist_head *next; /* next in chain */
|
||||
struct ylist_head *prev; /* previous in chain */
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
/* Initialise a list head to an empty list */
|
||||
#define YINIT_LIST_HEAD(p) \
|
||||
do { \
|
||||
(p)->next = (p);\
|
||||
(p)->prev = (p); \
|
||||
} while(0)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
/* Add an element to a list */
|
||||
static __inline__ void ylist_add(struct ylist_head *newEntry,
|
||||
struct ylist_head *list)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
struct ylist_head *listNext = list->next;
|
||||
|
||||
list->next = newEntry;
|
||||
newEntry->prev = list;
|
||||
newEntry->next = listNext;
|
||||
listNext->prev = newEntry;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static __inline__ void list_add(struct list_head *new, struct list_head *head)
|
||||
|
||||
/* 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)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
struct ylist_head *listNext = entry->next;
|
||||
struct ylist_head *listPrev = entry->prev;
|
||||
|
||||
listNext->prev = listPrev;
|
||||
listPrev->next = listNext;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static __inline__ void list_add_tail(struct list_head *new,
|
||||
struct list_head *head)
|
||||
static __inline__ void ylist_del_init(struct ylist_head *entry)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
ylist_del(entry);
|
||||
entry->next = entry->prev = entry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_del(struct list_head *prev,
|
||||
struct list_head *next)
|
||||
|
||||
/* Test if the list is empty */
|
||||
static __inline__ int ylist_empty(struct ylist_head *entry)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
return (entry->next == entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
static __inline__ void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
|
||||
#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
|
||||
*/
|
||||
static __inline__ void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static __inline__ int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
#define ylist_for_each(itervar, list) \
|
||||
for (itervar = (list)->next; itervar != (list); itervar = itervar->next )
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static __inline__ void list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
#define ylist_for_each_safe(itervar,saveVar, list) \
|
||||
for (itervar = (list)->next, saveVar = (list)->next->next; itervar != (list); \
|
||||
itervar = saveVar, saveVar = saveVar->next)
|
||||
|
||||
if (first != list) {
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
#if !(defined __KERNEL__)
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||
#ifndef WIN32
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
|
||||
pos = pos->next, prefetch(pos->next))
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal
|
||||
* of list entry
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
#ifdef CONFIG_YAFFS_PROVIDE_DEFS
|
||||
/* File types */
|
||||
|
||||
|
||||
/*
|
||||
* File types
|
||||
*/
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_FIFO 1
|
||||
#define DT_CHR 2
|
||||
|
@ -212,13 +135,13 @@ static __inline__ void list_splice(struct list_head *list,
|
|||
#define DT_SOCK 12
|
||||
#define DT_WHT 14
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Attribute flags. These should be or-ed together to figure out what
|
||||
* has been changed!
|
||||
* Attribute flags.
|
||||
*/
|
||||
#define ATTR_MODE 1
|
||||
#define ATTR_UID 2
|
||||
|
@ -227,10 +150,7 @@ static __inline__ void list_splice(struct list_head *list,
|
|||
#define ATTR_ATIME 16
|
||||
#define ATTR_MTIME 32
|
||||
#define ATTR_CTIME 64
|
||||
#define ATTR_ATIME_SET 128
|
||||
#define ATTR_MTIME_SET 256
|
||||
#define ATTR_FORCE 512 /* Not a change, but a change it */
|
||||
#define ATTR_ATTR_FLAG 1024
|
||||
|
||||
|
||||
struct iattr {
|
||||
unsigned int ia_valid;
|
||||
|
@ -244,21 +164,18 @@ struct iattr {
|
|||
unsigned int ia_attr_flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define KERN_DEBUG
|
||||
|
||||
#else
|
||||
|
||||
#ifndef WIN32
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/stat.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined WIN32
|
||||
#undef new
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,11 +54,11 @@ that you need to continue to support. New data written also uses the
|
|||
older-style format.
|
||||
Note: Use of this option generally requires that MTD's oob layout be
|
||||
adjusted to use the older-style format. See notes on tags formats and
|
||||
MTD versions.
|
||||
MTD versions in yaffs_mtdif1.c.
|
||||
*/
|
||||
/* Default: Not selected */
|
||||
/* Meaning: Use older-style on-NAND data format with pageStatus byte */
|
||||
#define CONFIG_YAFFS_9BYTE_TAGS
|
||||
//#define CONFIG_YAFFS_9BYTE_TAGS
|
||||
|
||||
#endif /* YAFFS_OUT_OF_TREE */
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_checkptrw_c_version =
|
||||
"$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $";
|
||||
"$Id: yaffs_checkptrw.c,v 1.16 2008-05-05 07:58:58 charles Exp $";
|
||||
|
||||
|
||||
#include "yaffs_checkptrw.h"
|
||||
|
||||
#include "yaffs_getblockinfo.h"
|
||||
|
||||
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
|
||||
{
|
||||
|
@ -142,7 +142,7 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
|
|||
return 0;
|
||||
|
||||
if(!dev->checkpointBuffer)
|
||||
dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
|
||||
dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
|
||||
if(!dev->checkpointBuffer)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_ecc_c_version =
|
||||
"$Id: yaffs_ecc.c,v 1.9 2007-02-14 01:09:06 wookey Exp $";
|
||||
"$Id: yaffs_ecc.c,v 1.10 2007-12-13 15:35:17 wookey Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_fs_c_version =
|
||||
"$Id: yaffs_fs.c,v 1.63 2007-09-19 20:35:40 imcd Exp $";
|
||||
"$Id: yaffs_fs.c,v 1.66 2008-05-05 07:58:58 charles Exp $";
|
||||
extern const char *yaffs_guts_c_version;
|
||||
|
||||
#include <linux/version.h>
|
||||
|
@ -53,6 +53,8 @@ extern const char *yaffs_guts_c_version;
|
|||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include "asm/div64.h"
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
|
||||
|
||||
#include <linux/statfs.h> /* Added NCB 15-8-2003 */
|
||||
|
@ -753,6 +755,8 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
|
|||
break;
|
||||
}
|
||||
|
||||
inode->i_flags |= S_NOATIME;
|
||||
|
||||
inode->i_ino = obj->objectId;
|
||||
inode->i_mode = obj->yst_mode;
|
||||
inode->i_uid = obj->yst_uid;
|
||||
|
@ -1350,25 +1354,47 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
|
|||
buf->f_type = YAFFS_MAGIC;
|
||||
buf->f_bsize = sb->s_blocksize;
|
||||
buf->f_namelen = 255;
|
||||
if (sb->s_blocksize > dev->nDataBytesPerChunk) {
|
||||
|
||||
if(dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)){
|
||||
/* Do this if chunk size is not a power of 2 */
|
||||
|
||||
uint64_t bytesInDev;
|
||||
uint64_t bytesFree;
|
||||
|
||||
bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock +1))) *
|
||||
((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
|
||||
|
||||
do_div(bytesInDev,sb->s_blocksize); /* bytesInDev becomes the number of blocks */
|
||||
buf->f_blocks = bytesInDev;
|
||||
|
||||
bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
|
||||
((uint64_t)(dev->nDataBytesPerChunk));
|
||||
|
||||
do_div(bytesFree,sb->s_blocksize);
|
||||
|
||||
buf->f_bfree = bytesFree;
|
||||
|
||||
} else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
|
||||
|
||||
buf->f_blocks =
|
||||
(dev->endBlock - dev->startBlock +
|
||||
1) * dev->nChunksPerBlock / (sb->s_blocksize /
|
||||
dev->nDataBytesPerChunk);
|
||||
buf->f_bfree =
|
||||
yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize /
|
||||
dev->nDataBytesPerChunk);
|
||||
(dev->endBlock - dev->startBlock + 1) *
|
||||
dev->nChunksPerBlock /
|
||||
(sb->s_blocksize / dev->nDataBytesPerChunk);
|
||||
buf->f_bfree =
|
||||
yaffs_GetNumberOfFreeChunks(dev) /
|
||||
(sb->s_blocksize / dev->nDataBytesPerChunk);
|
||||
} else {
|
||||
buf->f_blocks =
|
||||
(dev->endBlock - dev->startBlock + 1) *
|
||||
dev->nChunksPerBlock *
|
||||
(dev->nDataBytesPerChunk / sb->s_blocksize);
|
||||
|
||||
buf->f_blocks =
|
||||
(dev->endBlock - dev->startBlock +
|
||||
1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk /
|
||||
sb->s_blocksize);
|
||||
buf->f_bfree =
|
||||
yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk /
|
||||
sb->s_blocksize);
|
||||
buf->f_bfree =
|
||||
yaffs_GetNumberOfFreeChunks(dev) *
|
||||
(dev->nDataBytesPerChunk / sb->s_blocksize);
|
||||
}
|
||||
|
||||
|
||||
buf->f_files = 0;
|
||||
buf->f_ffree = 0;
|
||||
buf->f_bavail = buf->f_bfree;
|
||||
|
@ -1602,6 +1628,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
|
||||
sb->s_magic = YAFFS_MAGIC;
|
||||
sb->s_op = &yaffs_super_ops;
|
||||
sb->s_flags |= MS_NOATIME;
|
||||
|
||||
if (!sb)
|
||||
printk(KERN_INFO "yaffs: sb is NULL\n");
|
||||
|
@ -1678,22 +1705,15 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
#ifdef CONFIG_YAFFS_AUTO_YAFFS2
|
||||
|
||||
if (yaffsVersion == 1 &&
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
mtd->writesize >= 2048) {
|
||||
#else
|
||||
mtd->oobblock >= 2048) {
|
||||
#endif
|
||||
WRITE_SIZE(mtd) >= 2048) {
|
||||
T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
|
||||
yaffsVersion = 2;
|
||||
}
|
||||
|
||||
/* Added NCB 26/5/2006 for completeness */
|
||||
if (yaffsVersion == 2 &&
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
mtd->writesize == 512) {
|
||||
#else
|
||||
mtd->oobblock == 512) {
|
||||
#endif
|
||||
!options.inband_tags &&
|
||||
WRITE_SIZE(mtd) == 512){
|
||||
T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
|
||||
yaffsVersion = 1;
|
||||
}
|
||||
|
@ -1719,12 +1739,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
|
||||
#else
|
||||
if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
|
||||
#endif
|
||||
mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) {
|
||||
if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
|
||||
mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
|
||||
!options.inband_tags) {
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
("yaffs: MTD device does not have the "
|
||||
"right page sizes\n"));
|
||||
|
@ -1784,9 +1801,10 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
dev->startBlock = 0;
|
||||
dev->endBlock = nBlocks - 1;
|
||||
dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
|
||||
dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
|
||||
dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
|
||||
dev->nReservedBlocks = 5;
|
||||
dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
|
||||
dev->inbandTags = options.inband_tags;
|
||||
|
||||
/* ... and the functions. */
|
||||
if (yaffsVersion == 2) {
|
||||
|
@ -1799,15 +1817,14 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
|
|||
dev->spareBuffer = YMALLOC(mtd->oobsize);
|
||||
dev->isYaffs2 = 1;
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
dev->nDataBytesPerChunk = mtd->writesize;
|
||||
dev->totalBytesPerChunk = mtd->writesize;
|
||||
dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
|
||||
#else
|
||||
dev->nDataBytesPerChunk = mtd->oobblock;
|
||||
dev->totalBytesPerChunk = mtd->oobblock;
|
||||
dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
|
||||
#endif
|
||||
nBlocks = mtd->size / mtd->erasesize;
|
||||
|
||||
dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS;
|
||||
dev->startBlock = 0;
|
||||
dev->endBlock = nBlocks - 1;
|
||||
} else {
|
||||
|
@ -1990,12 +2007,12 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
|
|||
{
|
||||
buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
|
||||
buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
|
||||
buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
|
||||
buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
|
||||
buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
|
||||
buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
|
||||
buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
|
||||
buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
|
||||
buf += sprintf(buf, "nCheckptResBlocks.. %d\n", dev->nCheckpointReservedBlocks);
|
||||
buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
|
||||
buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
|
||||
buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
|
||||
|
@ -2006,10 +2023,8 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
|
|||
buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
|
||||
buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
|
||||
buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
|
||||
buf +=
|
||||
sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
|
||||
buf +=
|
||||
sprintf(buf, "passiveGCs......... %d\n",
|
||||
buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
|
||||
buf += sprintf(buf, "passiveGCs......... %d\n",
|
||||
dev->passiveGarbageCollections);
|
||||
buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
|
||||
buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
|
||||
|
@ -2025,6 +2040,7 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
|
|||
sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
|
||||
buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
|
||||
buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
|
||||
buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_GETBLOCKINFO_H__
|
||||
#define __YAFFS_GETBLOCKINFO_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
/* Function to manipulate block info */
|
||||
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
|
||||
{
|
||||
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
|
||||
blk));
|
||||
YBUG();
|
||||
}
|
||||
return &dev->blockInfo[blk - dev->internalStartBlock];
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -90,7 +90,7 @@
|
|||
|
||||
#define YAFFS_MAX_SHORT_OP_CACHES 20
|
||||
|
||||
#define YAFFS_N_TEMP_BUFFERS 4
|
||||
#define YAFFS_N_TEMP_BUFFERS 6
|
||||
|
||||
/* We limit the number attempts at sucessfully saving a chunk of data.
|
||||
* Small-page devices have 32 pages per block; large-page devices have 64.
|
||||
|
@ -277,7 +277,7 @@ typedef struct {
|
|||
|
||||
int softDeletions:10; /* number of soft deleted pages */
|
||||
int pagesInUse:10; /* number of pages in use */
|
||||
yaffs_BlockState blockState:4; /* One of the above block states */
|
||||
unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
|
||||
__u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
|
||||
/* and retire the block. */
|
||||
__u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */
|
||||
|
@ -303,7 +303,7 @@ typedef struct {
|
|||
__u16 sum__NoLongerUsed; /* checksum of name. No longer used */
|
||||
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
|
||||
|
||||
/* Thes following apply to directories, files, symlinks - not hard links */
|
||||
/* The following apply to directories, files, symlinks - not hard links */
|
||||
__u32 yst_mode; /* protection */
|
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE
|
||||
|
@ -331,11 +331,14 @@ typedef struct {
|
|||
__u32 win_ctime[2];
|
||||
__u32 win_atime[2];
|
||||
__u32 win_mtime[2];
|
||||
__u32 roomToGrow[4];
|
||||
#else
|
||||
__u32 roomToGrow[10];
|
||||
#endif
|
||||
__u32 roomToGrow[6];
|
||||
|
||||
#endif
|
||||
__u32 inbandShadowsObject;
|
||||
__u32 inbandIsShrink;
|
||||
|
||||
__u32 reservedSpace[2];
|
||||
int shadowsObject; /* This object header shadows the specified object if > 0 */
|
||||
|
||||
/* isShrink applies to object headers written when we shrink the file (ie resize) */
|
||||
|
@ -381,7 +384,7 @@ typedef struct {
|
|||
} yaffs_FileStructure;
|
||||
|
||||
typedef struct {
|
||||
struct list_head children; /* list of child links */
|
||||
struct ylist_head children; /* list of child links */
|
||||
} yaffs_DirectoryStructure;
|
||||
|
||||
typedef struct {
|
||||
|
@ -424,14 +427,14 @@ struct yaffs_ObjectStruct {
|
|||
|
||||
struct yaffs_DeviceStruct *myDev; /* The device I'm on */
|
||||
|
||||
struct list_head hashLink; /* list of objects in this hash bucket */
|
||||
struct ylist_head hashLink; /* list of objects in this hash bucket */
|
||||
|
||||
struct list_head hardLinks; /* all the equivalent hard linked objects */
|
||||
struct ylist_head hardLinks; /* all the equivalent hard linked objects */
|
||||
|
||||
/* directory structure stuff */
|
||||
/* also used for linking up the free list */
|
||||
struct yaffs_ObjectStruct *parent;
|
||||
struct list_head siblings;
|
||||
struct ylist_head siblings;
|
||||
|
||||
/* Where's my object header in NAND? */
|
||||
int chunkId;
|
||||
|
@ -485,7 +488,7 @@ struct yaffs_ObjectList_struct {
|
|||
typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
|
||||
|
||||
typedef struct {
|
||||
struct list_head list;
|
||||
struct ylist_head list;
|
||||
int count;
|
||||
} yaffs_ObjectBucket;
|
||||
|
||||
|
@ -528,7 +531,7 @@ typedef struct {
|
|||
/*----------------- Device ---------------------------------*/
|
||||
|
||||
struct yaffs_DeviceStruct {
|
||||
struct list_head devList;
|
||||
struct ylist_head devList;
|
||||
const char *name;
|
||||
|
||||
/* Entry parameters set up way early. Yaffs sets up the rest.*/
|
||||
|
@ -544,7 +547,7 @@ struct yaffs_DeviceStruct {
|
|||
/* Stuff used by the shared space checkpointing mechanism */
|
||||
/* If this value is zero, then this mechanism is disabled */
|
||||
|
||||
int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */
|
||||
// int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */
|
||||
|
||||
|
||||
|
||||
|
@ -583,7 +586,7 @@ struct yaffs_DeviceStruct {
|
|||
yaffs_ExtendedTags * tags);
|
||||
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
|
||||
int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,
|
||||
yaffs_BlockState * state, int *sequenceNumber);
|
||||
yaffs_BlockState * state, __u32 *sequenceNumber);
|
||||
#endif
|
||||
|
||||
int isYaffs2;
|
||||
|
@ -599,6 +602,7 @@ struct yaffs_DeviceStruct {
|
|||
|
||||
int wideTnodesDisabled; /* Set to disable wide tnodes */
|
||||
|
||||
YCHAR *pathDividers; /* String of legal path dividers */
|
||||
|
||||
/* End of stuff that must be set before initialisation. */
|
||||
|
||||
|
@ -615,16 +619,14 @@ struct yaffs_DeviceStruct {
|
|||
__u32 tnodeWidth;
|
||||
__u32 tnodeMask;
|
||||
|
||||
/* Stuff to support various file offses to chunk/offset translations */
|
||||
/* "Crumbs" for nDataBytesPerChunk not being a power of 2 */
|
||||
__u32 crumbMask;
|
||||
__u32 crumbShift;
|
||||
__u32 crumbsPerChunk;
|
||||
|
||||
/* Straight shifting for nDataBytesPerChunk being a power of 2 */
|
||||
__u32 chunkShift;
|
||||
__u32 chunkMask;
|
||||
/* Stuff for figuring out file offset to chunk conversions */
|
||||
__u32 chunkShift; /* Shift value */
|
||||
__u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
|
||||
__u32 chunkMask; /* Mask to use for power-of-2 case */
|
||||
|
||||
/* Stuff to handle inband tags */
|
||||
int inbandTags;
|
||||
__u32 totalBytesPerChunk;
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
|
@ -663,6 +665,8 @@ struct yaffs_DeviceStruct {
|
|||
__u32 checkpointSum;
|
||||
__u32 checkpointXor;
|
||||
|
||||
int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */
|
||||
|
||||
/* Block Info */
|
||||
yaffs_BlockInfo *blockInfo;
|
||||
__u8 *chunkBits; /* bitmap of chunks in use */
|
||||
|
@ -745,8 +749,10 @@ struct yaffs_DeviceStruct {
|
|||
int nBackgroundDeletions; /* Count of background deletions. */
|
||||
|
||||
|
||||
/* Temporary buffer management */
|
||||
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
|
||||
int maxTemp;
|
||||
int tempInUse;
|
||||
int unmanagedTempAllocations;
|
||||
int unmanagedTempDeallocations;
|
||||
|
||||
|
@ -758,7 +764,7 @@ struct yaffs_DeviceStruct {
|
|||
|
||||
typedef struct yaffs_DeviceStruct yaffs_Device;
|
||||
|
||||
/* The static layout of bllock usage etc is stored in the super block header */
|
||||
/* The static layout of block usage etc is stored in the super block header */
|
||||
typedef struct {
|
||||
int StructType;
|
||||
int version;
|
||||
|
@ -797,18 +803,6 @@ typedef struct {
|
|||
__u32 head;
|
||||
} yaffs_CheckpointValidity;
|
||||
|
||||
/* Function to manipulate block info */
|
||||
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
|
||||
{
|
||||
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
|
||||
blk));
|
||||
YBUG();
|
||||
}
|
||||
return &dev->blockInfo[blk - dev->internalStartBlock];
|
||||
}
|
||||
|
||||
/*----------------------- YAFFS Functions -----------------------*/
|
||||
|
||||
|
@ -899,4 +893,7 @@ void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn);
|
|||
int yaffs_CheckFF(__u8 * buffer, int nBytes);
|
||||
void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
|
||||
|
||||
__u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo);
|
||||
void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, int lineNo);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_mtdif_c_version =
|
||||
"$Id: yaffs_mtdif.c,v 1.19 2007-02-14 01:09:06 wookey Exp $";
|
||||
"$Id: yaffs_mtdif.c,v 1.21 2007-12-13 15:35:18 wookey Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
@ -24,7 +24,7 @@ const char *yaffs_mtdif_c_version =
|
|||
#include "linux/time.h"
|
||||
#include "linux/mtd/nand.h"
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
|
||||
#if (MTD_VERSION_CODE < MTD_VERSION(2,6,18))
|
||||
static struct nand_oobinfo yaffs_oobinfo = {
|
||||
.useecc = 1,
|
||||
.eccbytes = 6,
|
||||
|
@ -36,7 +36,7 @@ static struct nand_oobinfo yaffs_noeccinfo = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
|
||||
{
|
||||
oob[0] = spare->tagByte0;
|
||||
|
@ -75,14 +75,14 @@ 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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
__u8 spareAsBytes[8]; /* OOB */
|
||||
|
||||
if (data && !spare)
|
||||
|
@ -139,14 +139,14 @@ int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
|
|||
yaffs_Spare * spare)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
__u8 spareAsBytes[8]; /* OOB */
|
||||
|
||||
if (data && !spare)
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
#if (MTD_VERSION_CODE < MTD_VERSION(2,6,18))
|
||||
extern struct nand_oobinfo yaffs_oobinfo;
|
||||
extern struct nand_oobinfo yaffs_noeccinfo;
|
||||
#endif
|
||||
|
||||
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data, const yaffs_Spare * spare);
|
||||
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
|
||||
|
|
|
@ -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: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $";
|
||||
|
||||
#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--
|
||||
|
||||
|
||||
|
|
@ -34,9 +34,9 @@
|
|||
#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))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
|
||||
const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $";
|
||||
const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.7 2007-12-13 15:35:18 wookey Exp $";
|
||||
|
||||
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||
# define YTAG1_SIZE 8
|
||||
|
@ -189,7 +189,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
|||
ops.datbuf = data;
|
||||
ops.oobbuf = (__u8 *)&pt1;
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
|
||||
#if (MTD_VERSION_CODE < MTD_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.
|
||||
*/
|
||||
|
@ -288,7 +288,7 @@ int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
|||
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
|
||||
int retval;
|
||||
|
||||
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
|
||||
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
|
||||
|
||||
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
|
||||
return (retval) ? YAFFS_FAIL : YAFFS_OK;
|
||||
|
@ -327,6 +327,7 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
|||
{
|
||||
struct mtd_info * mtd = dev->genericDevice;
|
||||
int chunkNo = blockNo * dev->nChunksPerBlock;
|
||||
loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
|
||||
yaffs_ExtendedTags etags;
|
||||
int state = YAFFS_BLOCK_STATE_DEAD;
|
||||
int seqnum = 0;
|
||||
|
@ -340,11 +341,16 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
|||
}
|
||||
|
||||
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
|
||||
etags.blockBad = (mtd->block_isbad)(mtd, addr);
|
||||
if (etags.blockBad) {
|
||||
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
|
||||
"block %d is marked bad", blockNo);
|
||||
"block %d is marked bad\n", blockNo);
|
||||
state = YAFFS_BLOCK_STATE_DEAD;
|
||||
}
|
||||
else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
/* bad tags, need to look more closely */
|
||||
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
}
|
||||
else if (etags.chunkUsed) {
|
||||
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
seqnum = etags.sequenceNumber;
|
||||
|
@ -360,4 +366,4 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
|||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
#endif /*KERNEL_VERSION*/
|
||||
#endif /*MTD_VERSION*/
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
/* mtd interface for YAFFS2 */
|
||||
|
||||
const char *yaffs_mtdif2_c_version =
|
||||
"$Id: yaffs_mtdif2.c,v 1.17 2007-02-14 01:09:06 wookey Exp $";
|
||||
"$Id: yaffs_mtdif2.c,v 1.20 2008-05-05 07:58:58 charles Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
@ -27,19 +27,23 @@ const char *yaffs_mtdif2_c_version =
|
|||
|
||||
#include "yaffs_packedtags2.h"
|
||||
|
||||
/* NB For use with inband tags....
|
||||
* We assume that the data buffer is of size totalBytersPerChunk so that we can also
|
||||
* use it to load the tags.
|
||||
*/
|
||||
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data,
|
||||
const yaffs_ExtendedTags * tags)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
struct mtd_oob_ops ops;
|
||||
#else
|
||||
size_t dummy;
|
||||
#endif
|
||||
int retval = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||
loff_t addr;
|
||||
|
||||
yaffs_PackedTags2 pt;
|
||||
|
||||
|
@ -48,46 +52,41 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
|||
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
|
||||
TENDSTR), chunkInNAND, data, tags));
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
if (tags)
|
||||
yaffs_PackTags2(&pt, tags);
|
||||
else
|
||||
BUG(); /* both tags and data should always be present */
|
||||
|
||||
if (data) {
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.ooblen = sizeof(pt);
|
||||
ops.len = dev->nDataBytesPerChunk;
|
||||
ops.ooboffs = 0;
|
||||
ops.datbuf = (__u8 *)data;
|
||||
ops.oobbuf = (void *)&pt;
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
} else
|
||||
BUG(); /* both tags and data should always be present */
|
||||
#else
|
||||
if (tags) {
|
||||
yaffs_PackTags2(&pt, tags);
|
||||
addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
|
||||
|
||||
/* For yaffs2 writing there must be both data and tags.
|
||||
* If we're using inband tags, then the tags are stuffed into
|
||||
* the end of the data buffer.
|
||||
*/
|
||||
if(!data || !tags)
|
||||
BUG();
|
||||
else if(dev->inbandTags){
|
||||
yaffs_PackedTags2TagsPart *pt2tp;
|
||||
pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
|
||||
yaffs_PackTags2TagsPart(pt2tp,tags);
|
||||
}
|
||||
else
|
||||
yaffs_PackTags2(&pt, tags);
|
||||
|
||||
if (data && tags) {
|
||||
if (dev->useNANDECC)
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, (__u8 *) & pt, NULL);
|
||||
else
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, (__u8 *) & pt, NULL);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
|
||||
ops.len = dev->totalBytesPerChunk;
|
||||
ops.ooboffs = 0;
|
||||
ops.datbuf = (__u8 *)data;
|
||||
ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
|
||||
#else
|
||||
if (!dev->inbandTags) {
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, (__u8 *) & pt, NULL);
|
||||
} else {
|
||||
if (data)
|
||||
retval =
|
||||
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||
data);
|
||||
if (tags)
|
||||
retval =
|
||||
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||
(__u8 *) & pt);
|
||||
|
||||
retval =
|
||||
mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
|
||||
data);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -101,11 +100,12 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
|||
__u8 * data, yaffs_ExtendedTags * tags)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
|
||||
struct mtd_oob_ops ops;
|
||||
#endif
|
||||
size_t dummy;
|
||||
int retval = 0;
|
||||
int localData = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||
|
||||
|
@ -116,9 +116,20 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
|||
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
|
||||
TENDSTR), chunkInNAND, data, tags));
|
||||
|
||||
if(dev->inbandTags){
|
||||
|
||||
if(!data) {
|
||||
localData = 1;
|
||||
data = yaffs_GetTempBuffer(dev,__LINE__);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
if (data && !tags)
|
||||
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
|
||||
if (dev->inbandTags || (data && !tags))
|
||||
retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
|
||||
&dummy, data);
|
||||
else if (tags) {
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
|
@ -130,38 +141,43 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
|||
retval = mtd->read_oob(mtd, addr, &ops);
|
||||
}
|
||||
#else
|
||||
if (data && tags) {
|
||||
if (dev->useNANDECC) {
|
||||
retval =
|
||||
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
if (!dev->inbandTags && data && tags) {
|
||||
|
||||
retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, dev->spareBuffer,
|
||||
NULL);
|
||||
} else {
|
||||
retval =
|
||||
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, dev->spareBuffer,
|
||||
NULL);
|
||||
}
|
||||
} else {
|
||||
if (data)
|
||||
retval =
|
||||
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||
data);
|
||||
if (tags)
|
||||
if (!dev->inbandTags && tags)
|
||||
retval =
|
||||
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||
dev->spareBuffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy(&pt, dev->spareBuffer, sizeof(pt));
|
||||
|
||||
if (tags)
|
||||
yaffs_UnpackTags2(tags, &pt);
|
||||
if(dev->inbandTags){
|
||||
if(tags){
|
||||
yaffs_PackedTags2TagsPart * pt2tp;
|
||||
pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
|
||||
yaffs_UnpackTags2TagsPart(tags,pt2tp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (tags){
|
||||
memcpy(&pt, dev->spareBuffer, sizeof(pt));
|
||||
yaffs_UnpackTags2(tags, &pt);
|
||||
}
|
||||
}
|
||||
|
||||
if(localData)
|
||||
yaffs_ReleaseTempBuffer(dev,data,__LINE__);
|
||||
|
||||
if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
|
||||
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
|
|
|
@ -12,12 +12,13 @@
|
|||
*/
|
||||
|
||||
const char *yaffs_nand_c_version =
|
||||
"$Id: yaffs_nand.c,v 1.7 2007-02-14 01:09:06 wookey Exp $";
|
||||
"$Id: yaffs_nand.c,v 1.9 2008-05-05 07:58:58 charles Exp $";
|
||||
|
||||
#include "yaffs_nand.h"
|
||||
#include "yaffs_tagscompat.h"
|
||||
#include "yaffs_tagsvalidity.h"
|
||||
|
||||
#include "yaffs_getblockinfo.h"
|
||||
|
||||
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
__u8 * buffer,
|
||||
|
@ -98,7 +99,7 @@ int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
|
|||
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
|
||||
int blockNo,
|
||||
yaffs_BlockState * state,
|
||||
unsigned *sequenceNumber)
|
||||
__u32 *sequenceNumber)
|
||||
{
|
||||
blockNo -= dev->blockOffset;
|
||||
|
||||
|
|
|
@ -22,13 +22,13 @@
|
|||
|
||||
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND, const __u8 * data,
|
||||
yaffs_ExtendedTags * tags);
|
||||
const yaffs_ExtendedTags * tags);
|
||||
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND, __u8 * data,
|
||||
yaffs_ExtendedTags * tags);
|
||||
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState * state, int *sequenceNumber);
|
||||
yaffs_BlockState * state, __u32 *sequenceNumber);
|
||||
int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
||||
int blockInNAND);
|
||||
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
|
||||
|
|
|
@ -37,60 +37,70 @@
|
|||
#define EXTRA_OBJECT_TYPE_SHIFT (28)
|
||||
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
|
||||
|
||||
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
|
||||
|
||||
static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart * ptt)
|
||||
{
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
|
||||
pt->t.objectId, pt->t.chunkId, pt->t.byteCount,
|
||||
pt->t.sequenceNumber));
|
||||
ptt->objectId, ptt->chunkId, ptt->byteCount,
|
||||
ptt->sequenceNumber));
|
||||
}
|
||||
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
|
||||
{
|
||||
yaffs_DumpPackedTags2TagsPart(&pt->t);
|
||||
}
|
||||
|
||||
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
|
||||
{
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR
|
||||
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte "
|
||||
"%d del %d ser %d seq %d"
|
||||
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
|
||||
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
|
||||
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
|
||||
t->sequenceNumber));
|
||||
|
||||
}
|
||||
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
|
||||
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart * ptt, const yaffs_ExtendedTags * t)
|
||||
{
|
||||
pt->t.chunkId = t->chunkId;
|
||||
pt->t.sequenceNumber = t->sequenceNumber;
|
||||
pt->t.byteCount = t->byteCount;
|
||||
pt->t.objectId = t->objectId;
|
||||
ptt->chunkId = t->chunkId;
|
||||
ptt->sequenceNumber = t->sequenceNumber;
|
||||
ptt->byteCount = t->byteCount;
|
||||
ptt->objectId = t->objectId;
|
||||
|
||||
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
|
||||
/* Store the extra header info instead */
|
||||
/* We save the parent object in the chunkId */
|
||||
pt->t.chunkId = EXTRA_HEADER_INFO_FLAG
|
||||
ptt->chunkId = EXTRA_HEADER_INFO_FLAG
|
||||
| t->extraParentObjectId;
|
||||
if (t->extraIsShrinkHeader) {
|
||||
pt->t.chunkId |= EXTRA_SHRINK_FLAG;
|
||||
ptt->chunkId |= EXTRA_SHRINK_FLAG;
|
||||
}
|
||||
if (t->extraShadows) {
|
||||
pt->t.chunkId |= EXTRA_SHADOWS_FLAG;
|
||||
ptt->chunkId |= EXTRA_SHADOWS_FLAG;
|
||||
}
|
||||
|
||||
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
pt->t.objectId |=
|
||||
ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
ptt->objectId |=
|
||||
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||
pt->t.byteCount = t->extraEquivalentObjectId;
|
||||
ptt->byteCount = t->extraEquivalentObjectId;
|
||||
} else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
|
||||
pt->t.byteCount = t->extraFileLength;
|
||||
ptt->byteCount = t->extraFileLength;
|
||||
} else {
|
||||
pt->t.byteCount = 0;
|
||||
ptt->byteCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2(pt);
|
||||
yaffs_DumpPackedTags2TagsPart(ptt);
|
||||
yaffs_DumpTags2(t);
|
||||
}
|
||||
|
||||
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
|
||||
{
|
||||
yaffs_PackTags2TagsPart(&pt->t,t);
|
||||
|
||||
#ifndef YAFFS_IGNORE_TAGS_ECC
|
||||
{
|
||||
|
@ -101,13 +111,60 @@ void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
|
|||
#endif
|
||||
}
|
||||
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
|
||||
|
||||
void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags * t, yaffs_PackedTags2TagsPart * ptt)
|
||||
{
|
||||
|
||||
memset(t, 0, sizeof(yaffs_ExtendedTags));
|
||||
|
||||
yaffs_InitialiseTags(t);
|
||||
|
||||
if (ptt->sequenceNumber != 0xFFFFFFFF) {
|
||||
t->blockBad = 0;
|
||||
t->chunkUsed = 1;
|
||||
t->objectId = ptt->objectId;
|
||||
t->chunkId = ptt->chunkId;
|
||||
t->byteCount = ptt->byteCount;
|
||||
t->chunkDeleted = 0;
|
||||
t->serialNumber = 0;
|
||||
t->sequenceNumber = ptt->sequenceNumber;
|
||||
|
||||
/* Do extra header info stuff */
|
||||
|
||||
if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) {
|
||||
t->chunkId = 0;
|
||||
t->byteCount = 0;
|
||||
|
||||
t->extraHeaderInfoAvailable = 1;
|
||||
t->extraParentObjectId =
|
||||
ptt->chunkId & (~(ALL_EXTRA_FLAGS));
|
||||
t->extraIsShrinkHeader =
|
||||
(ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
|
||||
t->extraShadows =
|
||||
(ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
|
||||
t->extraObjectType =
|
||||
ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT;
|
||||
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||
t->extraEquivalentObjectId = ptt->byteCount;
|
||||
} else {
|
||||
t->extraFileLength = ptt->byteCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2TagsPart(ptt);
|
||||
yaffs_DumpTags2(t);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
|
||||
{
|
||||
|
||||
yaffs_UnpackTags2TagsPart(t,&pt->t);
|
||||
|
||||
if (pt->t.sequenceNumber != 0xFFFFFFFF) {
|
||||
/* Page is in use */
|
||||
#ifdef YAFFS_IGNORE_TAGS_ECC
|
||||
|
@ -142,41 +199,10 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
t->blockBad = 0;
|
||||
t->chunkUsed = 1;
|
||||
t->objectId = pt->t.objectId;
|
||||
t->chunkId = pt->t.chunkId;
|
||||
t->byteCount = pt->t.byteCount;
|
||||
t->chunkDeleted = 0;
|
||||
t->serialNumber = 0;
|
||||
t->sequenceNumber = pt->t.sequenceNumber;
|
||||
|
||||
/* Do extra header info stuff */
|
||||
|
||||
if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) {
|
||||
t->chunkId = 0;
|
||||
t->byteCount = 0;
|
||||
|
||||
t->extraHeaderInfoAvailable = 1;
|
||||
t->extraParentObjectId =
|
||||
pt->t.chunkId & (~(ALL_EXTRA_FLAGS));
|
||||
t->extraIsShrinkHeader =
|
||||
(pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
|
||||
t->extraShadows =
|
||||
(pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
|
||||
t->extraObjectType =
|
||||
pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT;
|
||||
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||
t->extraEquivalentObjectId = pt->t.byteCount;
|
||||
} else {
|
||||
t->extraFileLength = pt->t.byteCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2(pt);
|
||||
yaffs_DumpTags2(t);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ typedef struct {
|
|||
yaffs_ECCOther ecc;
|
||||
} yaffs_PackedTags2;
|
||||
|
||||
/* Full packed tags with ECC, used for oob tags */
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt);
|
||||
|
||||
/* Only the tags part (no ECC for use with inband tags */
|
||||
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart * pt, const yaffs_ExtendedTags * t);
|
||||
void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags * t, yaffs_PackedTags2TagsPart * pt);
|
||||
#endif
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "yaffs_guts.h"
|
||||
#include "yaffs_tagscompat.h"
|
||||
#include "yaffs_ecc.h"
|
||||
#include "yaffs_getblockinfo.h"
|
||||
|
||||
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
|
||||
#ifdef NOTYET
|
||||
|
@ -438,7 +439,7 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
|
|||
yaffs_ECCResult eccResult;
|
||||
|
||||
static yaffs_Spare spareFF;
|
||||
static int init;
|
||||
static int init = 0;
|
||||
|
||||
if (!init) {
|
||||
memset(&spareFF, 0xFF, sizeof(spareFF));
|
||||
|
@ -497,9 +498,9 @@ int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
|||
}
|
||||
|
||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo, yaffs_BlockState *
|
||||
state,
|
||||
int *sequenceNumber)
|
||||
int blockNo,
|
||||
yaffs_BlockState *state,
|
||||
__u32 *sequenceNumber)
|
||||
{
|
||||
|
||||
yaffs_Spare spare0, spare1;
|
||||
|
|
|
@ -30,8 +30,9 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
|
|||
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo);
|
||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo, yaffs_BlockState *
|
||||
state, int *sequenceNumber);
|
||||
int blockNo,
|
||||
yaffs_BlockState *state,
|
||||
__u32 *sequenceNumber);
|
||||
|
||||
void yaffs_CalcTagsECC(yaffs_Tags * tags);
|
||||
int yaffs_CheckECCOnTags(yaffs_Tags * tags);
|
||||
|
|
|
@ -17,6 +17,14 @@
|
|||
#ifndef __YPORTENV_H__
|
||||
#define __YPORTENV_H__
|
||||
|
||||
/*
|
||||
* Define the MTD version in terms of Linux Kernel versions
|
||||
* This allows yaffs to be used independantly of the kernel
|
||||
* as well as with it.
|
||||
*/
|
||||
|
||||
#define MTD_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
|
||||
|
||||
#if defined CONFIG_YAFFS_WINCE
|
||||
|
||||
#include "ywinceenv.h"
|
||||
|
@ -26,7 +34,10 @@
|
|||
#include "moduleconfig.h"
|
||||
|
||||
/* Linux kernel */
|
||||
|
||||
#include <linux/version.h>
|
||||
#define MTD_VERSION_CODE LINUX_VERSION_CODE
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
|
||||
#include <linux/config.h>
|
||||
#endif
|
||||
|
@ -90,6 +101,8 @@
|
|||
|
||||
#elif defined CONFIG_YAFFS_DIRECT
|
||||
|
||||
#define MTD_VERSION_CODE MTD_VERSION(2,6,22)
|
||||
|
||||
/* Direct interface */
|
||||
#include "ydirectenv.h"
|
||||
|
||||
|
@ -180,8 +193,8 @@ extern unsigned int yaffs_wr_attempts;
|
|||
|
||||
#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
|
||||
|
||||
#ifndef CONFIG_YAFFS_WINCE
|
||||
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))
|
||||
#ifndef YBUG
|
||||
#define YBUG() do {T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__));} while(0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue