generic-2.6: sync yaffs code with the official CVS tree

SVN-Revision: 11378
This commit is contained in:
Gabor Juhos 2008-06-06 12:52:39 +00:00
parent 306f3677ec
commit 477d43b281
66 changed files with 1983 additions and 2964 deletions

View file

@ -43,7 +43,8 @@ config YAFFS_9BYTE_TAGS
format that you need to continue to support. New data written format that you need to continue to support. New data written
also uses the older-style format. Note: Use of this option also uses the older-style format. Note: Use of this option
generally requires that MTD's oob layout be adjusted to use the 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. If unsure, say N.
@ -109,26 +110,6 @@ config YAFFS_DISABLE_LAZY_LOAD
If unsure, say N. 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 config YAFFS_DISABLE_WIDE_TNODES
bool "Turn off wide tnodes" bool "Turn off wide tnodes"

View file

@ -5,7 +5,6 @@
obj-$(CONFIG_YAFFS_FS) += yaffs.o obj-$(CONFIG_YAFFS_FS) += yaffs.o
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o yaffs-y := yaffs_ecc.o yaffs_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_tagscompat.o yaffs_tagsvalidity.o
yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o

View file

@ -14,194 +14,117 @@
*/ */
/* /*
* This file is just holds extra declarations used during development. * This file is just holds extra declarations of macros that would normally
* Most of these are from kernel includes placed here so we can use them in * be providesd in the Linux kernel. These macros have been written from
* applications. * scratch but are functionally equivalent to the Linux ones.
* *
*/ */
#ifndef __EXTRAS_H__ #ifndef __EXTRAS_H__
#define __EXTRAS_H__ #define __EXTRAS_H__
#if defined WIN32
#define __inline__ __inline
#define new newHack
#endif
#if !(defined __KERNEL__) || (defined WIN32) #if !(defined __KERNEL__)
/* User space defines */
/* Definition of types */
typedef unsigned char __u8; typedef unsigned char __u8;
typedef unsigned short __u16; typedef unsigned short __u16;
typedef unsigned __u32; typedef unsigned __u32;
#endif
/* /*
* Simple doubly linked list implementation. * This is a simple doubly linked list implementation that matches the
* * way the Linux kernel doubly linked list implementation works.
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/ */
#define prefetch(x) 1 struct ylist_head {
struct ylist_head *next; /* next in chain */
struct list_head { struct ylist_head *prev; /* previous in chain */
struct list_head *next, *prev;
}; };
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \ /* Initialise a list head to an empty list */
struct list_head name = LIST_HEAD_INIT(name) #define YINIT_LIST_HEAD(p) \
do { \
#define INIT_LIST_HEAD(ptr) do { \ (p)->next = (p);\
(ptr)->next = (ptr); (ptr)->prev = (ptr); \ (p)->prev = (p); \
} while(0) } while(0)
/*
* Insert a new entry between two known consecutive entries. /* Add an element to a list */
* static __inline__ void ylist_add(struct ylist_head *newEntry,
* This is only for internal list manipulation where we know struct ylist_head *list)
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{ {
next->prev = new; struct ylist_head *listNext = list->next;
new->next = next;
new->prev = prev; list->next = newEntry;
prev->next = new; newEntry->prev = list;
newEntry->next = listNext;
listNext->prev = newEntry;
} }
/**
* list_add - add a new entry /* Take an element out of its current list, with or without
* @new: new entry to be added * reinitialising the links.of the entry*/
* @head: list head to add it after static __inline__ void ylist_del(struct ylist_head *entry)
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{ {
__list_add(new, head, head->next); struct ylist_head *listNext = entry->next;
struct ylist_head *listPrev = entry->prev;
listNext->prev = listPrev;
listPrev->next = listNext;
} }
/** static __inline__ void ylist_del_init(struct ylist_head *entry)
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *new,
struct list_head *head)
{ {
__list_add(new, head->prev, head); ylist_del(entry);
entry->next = entry->prev = entry;
} }
/*
* Delete a list entry by making the prev/next entries /* Test if the list is empty */
* point to each other. static __inline__ int ylist_empty(struct ylist_head *entry)
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head *prev,
struct list_head *next)
{ {
next->prev = prev; return (entry->next == entry);
prev->next = next;
} }
/**
* list_del - deletes entry from list. /* ylist_entry takes a pointer to a list entry and offsets it to that
* @entry: the element to delete from the list. * we can find a pointer to the object it is embedded in.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/ */
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it. #define ylist_entry(entry, type, member) \
* @entry: the element to delete from the list. ((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);
}
/** #define ylist_for_each(itervar, list) \
* list_empty - tests whether a list is empty for (itervar = (list)->next; itervar != (list); itervar = itervar->next )
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
/** #define ylist_for_each_safe(itervar,saveVar, list) \
* list_splice - join two lists for (itervar = (list)->next, saveVar = (list)->next->next; itervar != (list); \
* @list: the new list to add. itervar = saveVar, saveVar = saveVar->next)
* @head: the place to add it in the first list.
*/
static __inline__ void list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
if (first != list) {
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head; #if !(defined __KERNEL__)
head->next = first;
last->next = at;
at->prev = last;
}
}
/** #ifndef WIN32
* list_entry - get the struct for this entry #include <sys/stat.h>
* @ptr: the &struct list_head pointer. #endif
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
pos = pos->next, prefetch(pos->next))
/** #ifdef CONFIG_YAFFS_PROVIDE_DEFS
* list_for_each_safe - iterate over a list safe against removal /* File types */
* of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/*
* File types
*/
#define DT_UNKNOWN 0 #define DT_UNKNOWN 0
#define DT_FIFO 1 #define DT_FIFO 1
#define DT_CHR 2 #define DT_CHR 2
@ -212,13 +135,13 @@ static __inline__ void list_splice(struct list_head *list,
#define DT_SOCK 12 #define DT_SOCK 12
#define DT_WHT 14 #define DT_WHT 14
#ifndef WIN32 #ifndef WIN32
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
/* /*
* Attribute flags. These should be or-ed together to figure out what * Attribute flags.
* has been changed!
*/ */
#define ATTR_MODE 1 #define ATTR_MODE 1
#define ATTR_UID 2 #define ATTR_UID 2
@ -227,10 +150,7 @@ static __inline__ void list_splice(struct list_head *list,
#define ATTR_ATIME 16 #define ATTR_ATIME 16
#define ATTR_MTIME 32 #define ATTR_MTIME 32
#define ATTR_CTIME 64 #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 { struct iattr {
unsigned int ia_valid; unsigned int ia_valid;
@ -244,21 +164,18 @@ struct iattr {
unsigned int ia_attr_flags; unsigned int ia_attr_flags;
}; };
#endif
#define KERN_DEBUG #define KERN_DEBUG
#else #else
#ifndef WIN32
#include <linux/types.h> #include <linux/types.h>
#include <linux/list.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/stat.h> #include <linux/stat.h>
#endif
#endif #endif
#if defined WIN32
#undef new
#endif
#endif #endif

View file

@ -54,11 +54,11 @@ that you need to continue to support. New data written also uses the
older-style format. older-style format.
Note: Use of this option generally requires that MTD's oob layout be 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 adjusted to use the older-style format. See notes on tags formats and
MTD versions. MTD versions in yaffs_mtdif1.c.
*/ */
/* Default: Not selected */ /* Default: Not selected */
/* Meaning: Use older-style on-NAND data format with pageStatus byte */ /* Meaning: Use older-style on-NAND data format with pageStatus byte */
#define CONFIG_YAFFS_9BYTE_TAGS //#define CONFIG_YAFFS_9BYTE_TAGS
#endif /* YAFFS_OUT_OF_TREE */ #endif /* YAFFS_OUT_OF_TREE */

View file

@ -12,11 +12,11 @@
*/ */
const char *yaffs_checkptrw_c_version = 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_checkptrw.h"
#include "yaffs_getblockinfo.h"
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
{ {
@ -142,7 +142,7 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
return 0; return 0;
if(!dev->checkpointBuffer) if(!dev->checkpointBuffer)
dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk); dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
if(!dev->checkpointBuffer) if(!dev->checkpointBuffer)
return 0; return 0;

View file

@ -29,7 +29,7 @@
*/ */
const char *yaffs_ecc_c_version = 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" #include "yportenv.h"

View file

@ -32,7 +32,7 @@
*/ */
const char *yaffs_fs_c_version = 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; extern const char *yaffs_guts_c_version;
#include <linux/version.h> #include <linux/version.h>
@ -53,6 +53,8 @@ extern const char *yaffs_guts_c_version;
#include <linux/string.h> #include <linux/string.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include "asm/div64.h"
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
#include <linux/statfs.h> /* Added NCB 15-8-2003 */ #include <linux/statfs.h> /* Added NCB 15-8-2003 */
@ -753,6 +755,8 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
break; break;
} }
inode->i_flags |= S_NOATIME;
inode->i_ino = obj->objectId; inode->i_ino = obj->objectId;
inode->i_mode = obj->yst_mode; inode->i_mode = obj->yst_mode;
inode->i_uid = obj->yst_uid; 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_type = YAFFS_MAGIC;
buf->f_bsize = sb->s_blocksize; buf->f_bsize = sb->s_blocksize;
buf->f_namelen = 255; 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 = buf->f_blocks =
(dev->endBlock - dev->startBlock + (dev->endBlock - dev->startBlock + 1) *
1) * dev->nChunksPerBlock / (sb->s_blocksize / dev->nChunksPerBlock /
dev->nDataBytesPerChunk); (sb->s_blocksize / dev->nDataBytesPerChunk);
buf->f_bfree = buf->f_bfree =
yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize / yaffs_GetNumberOfFreeChunks(dev) /
dev->nDataBytesPerChunk); (sb->s_blocksize / dev->nDataBytesPerChunk);
} else { } else {
buf->f_blocks = buf->f_blocks =
(dev->endBlock - dev->startBlock + (dev->endBlock - dev->startBlock + 1) *
1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk / dev->nChunksPerBlock *
sb->s_blocksize); (dev->nDataBytesPerChunk / sb->s_blocksize);
buf->f_bfree = buf->f_bfree =
yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk / yaffs_GetNumberOfFreeChunks(dev) *
sb->s_blocksize); (dev->nDataBytesPerChunk / sb->s_blocksize);
} }
buf->f_files = 0; buf->f_files = 0;
buf->f_ffree = 0; buf->f_ffree = 0;
buf->f_bavail = buf->f_bfree; 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_magic = YAFFS_MAGIC;
sb->s_op = &yaffs_super_ops; sb->s_op = &yaffs_super_ops;
sb->s_flags |= MS_NOATIME;
if (!sb) if (!sb)
printk(KERN_INFO "yaffs: sb is NULL\n"); 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 #ifdef CONFIG_YAFFS_AUTO_YAFFS2
if (yaffsVersion == 1 && if (yaffsVersion == 1 &&
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) WRITE_SIZE(mtd) >= 2048) {
mtd->writesize >= 2048) {
#else
mtd->oobblock >= 2048) {
#endif
T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n")); T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
yaffsVersion = 2; yaffsVersion = 2;
} }
/* Added NCB 26/5/2006 for completeness */ /* Added NCB 26/5/2006 for completeness */
if (yaffsVersion == 2 && if (yaffsVersion == 2 &&
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) !options.inband_tags &&
mtd->writesize == 512) { WRITE_SIZE(mtd) == 512){
#else
mtd->oobblock == 512) {
#endif
T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n")); T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
yaffsVersion = 1; yaffsVersion = 1;
} }
@ -1719,12 +1739,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
return NULL; return NULL;
} }
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE || mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
#else !options.inband_tags) {
if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
#endif
mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) {
T(YAFFS_TRACE_ALWAYS, T(YAFFS_TRACE_ALWAYS,
("yaffs: MTD device does not have the " ("yaffs: MTD device does not have the "
"right page sizes\n")); "right page sizes\n"));
@ -1784,9 +1801,10 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
dev->startBlock = 0; dev->startBlock = 0;
dev->endBlock = nBlocks - 1; dev->endBlock = nBlocks - 1;
dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK; dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
dev->nReservedBlocks = 5; dev->nReservedBlocks = 5;
dev->nShortOpCaches = (options.no_cache) ? 0 : 10; dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
dev->inbandTags = options.inband_tags;
/* ... and the functions. */ /* ... and the functions. */
if (yaffsVersion == 2) { if (yaffsVersion == 2) {
@ -1799,15 +1817,14 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
dev->spareBuffer = YMALLOC(mtd->oobsize); dev->spareBuffer = YMALLOC(mtd->oobsize);
dev->isYaffs2 = 1; dev->isYaffs2 = 1;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
dev->nDataBytesPerChunk = mtd->writesize; dev->totalBytesPerChunk = mtd->writesize;
dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
#else #else
dev->nDataBytesPerChunk = mtd->oobblock; dev->totalBytesPerChunk = mtd->oobblock;
dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
#endif #endif
nBlocks = mtd->size / mtd->erasesize; nBlocks = mtd->size / mtd->erasesize;
dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS;
dev->startBlock = 0; dev->startBlock = 0;
dev->endBlock = nBlocks - 1; dev->endBlock = nBlocks - 1;
} else { } 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, "startBlock......... %d\n", dev->startBlock);
buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); 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, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits); buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize); buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks); buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks); 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, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated); buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes); 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, "nPageReads......... %d\n", dev->nPageReads);
buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures); buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies); buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
buf += buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections); buf += sprintf(buf, "passiveGCs......... %d\n",
buf +=
sprintf(buf, "passiveGCs......... %d\n",
dev->passiveGarbageCollections); dev->passiveGarbageCollections);
buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites); buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches); 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); sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC); buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2); buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
return buf; return buf;
} }

View file

@ -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

View file

@ -90,7 +90,7 @@
#define YAFFS_MAX_SHORT_OP_CACHES 20 #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. /* 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. * 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 softDeletions:10; /* number of soft deleted pages */
int pagesInUse:10; /* number of pages in use */ 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 */ __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
/* and retire the block. */ /* and retire the block. */
__u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this 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 */ __u16 sum__NoLongerUsed; /* checksum of name. No longer used */
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; 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 */ __u32 yst_mode; /* protection */
#ifdef CONFIG_YAFFS_WINCE #ifdef CONFIG_YAFFS_WINCE
@ -331,11 +331,14 @@ typedef struct {
__u32 win_ctime[2]; __u32 win_ctime[2];
__u32 win_atime[2]; __u32 win_atime[2];
__u32 win_mtime[2]; __u32 win_mtime[2];
__u32 roomToGrow[4];
#else #else
__u32 roomToGrow[10]; __u32 roomToGrow[6];
#endif
#endif
__u32 inbandShadowsObject;
__u32 inbandIsShrink;
__u32 reservedSpace[2];
int shadowsObject; /* This object header shadows the specified object if > 0 */ int shadowsObject; /* This object header shadows the specified object if > 0 */
/* isShrink applies to object headers written when we shrink the file (ie resize) */ /* isShrink applies to object headers written when we shrink the file (ie resize) */
@ -381,7 +384,7 @@ typedef struct {
} yaffs_FileStructure; } yaffs_FileStructure;
typedef struct { typedef struct {
struct list_head children; /* list of child links */ struct ylist_head children; /* list of child links */
} yaffs_DirectoryStructure; } yaffs_DirectoryStructure;
typedef struct { typedef struct {
@ -424,14 +427,14 @@ struct yaffs_ObjectStruct {
struct yaffs_DeviceStruct *myDev; /* The device I'm on */ 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 */ /* directory structure stuff */
/* also used for linking up the free list */ /* also used for linking up the free list */
struct yaffs_ObjectStruct *parent; struct yaffs_ObjectStruct *parent;
struct list_head siblings; struct ylist_head siblings;
/* Where's my object header in NAND? */ /* Where's my object header in NAND? */
int chunkId; int chunkId;
@ -485,7 +488,7 @@ struct yaffs_ObjectList_struct {
typedef struct yaffs_ObjectList_struct yaffs_ObjectList; typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
typedef struct { typedef struct {
struct list_head list; struct ylist_head list;
int count; int count;
} yaffs_ObjectBucket; } yaffs_ObjectBucket;
@ -528,7 +531,7 @@ typedef struct {
/*----------------- Device ---------------------------------*/ /*----------------- Device ---------------------------------*/
struct yaffs_DeviceStruct { struct yaffs_DeviceStruct {
struct list_head devList; struct ylist_head devList;
const char *name; const char *name;
/* Entry parameters set up way early. Yaffs sets up the rest.*/ /* 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 */ /* Stuff used by the shared space checkpointing mechanism */
/* If this value is zero, then this mechanism is disabled */ /* 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); yaffs_ExtendedTags * tags);
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo); int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
int (*queryNANDBlock) (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 #endif
int isYaffs2; int isYaffs2;
@ -599,6 +602,7 @@ struct yaffs_DeviceStruct {
int wideTnodesDisabled; /* Set to disable wide tnodes */ int wideTnodesDisabled; /* Set to disable wide tnodes */
YCHAR *pathDividers; /* String of legal path dividers */
/* End of stuff that must be set before initialisation. */ /* End of stuff that must be set before initialisation. */
@ -615,16 +619,14 @@ struct yaffs_DeviceStruct {
__u32 tnodeWidth; __u32 tnodeWidth;
__u32 tnodeMask; __u32 tnodeMask;
/* Stuff to support various file offses to chunk/offset translations */ /* Stuff for figuring out file offset to chunk conversions */
/* "Crumbs" for nDataBytesPerChunk not being a power of 2 */ __u32 chunkShift; /* Shift value */
__u32 crumbMask; __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
__u32 crumbShift; __u32 chunkMask; /* Mask to use for power-of-2 case */
__u32 crumbsPerChunk;
/* Straight shifting for nDataBytesPerChunk being a power of 2 */
__u32 chunkShift;
__u32 chunkMask;
/* Stuff to handle inband tags */
int inbandTags;
__u32 totalBytesPerChunk;
#ifdef __KERNEL__ #ifdef __KERNEL__
@ -663,6 +665,8 @@ struct yaffs_DeviceStruct {
__u32 checkpointSum; __u32 checkpointSum;
__u32 checkpointXor; __u32 checkpointXor;
int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */
/* Block Info */ /* Block Info */
yaffs_BlockInfo *blockInfo; yaffs_BlockInfo *blockInfo;
__u8 *chunkBits; /* bitmap of chunks in use */ __u8 *chunkBits; /* bitmap of chunks in use */
@ -745,8 +749,10 @@ struct yaffs_DeviceStruct {
int nBackgroundDeletions; /* Count of background deletions. */ int nBackgroundDeletions; /* Count of background deletions. */
/* Temporary buffer management */
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS]; yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
int maxTemp; int maxTemp;
int tempInUse;
int unmanagedTempAllocations; int unmanagedTempAllocations;
int unmanagedTempDeallocations; int unmanagedTempDeallocations;
@ -758,7 +764,7 @@ struct yaffs_DeviceStruct {
typedef struct yaffs_DeviceStruct yaffs_Device; 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 { typedef struct {
int StructType; int StructType;
int version; int version;
@ -797,18 +803,6 @@ typedef struct {
__u32 head; __u32 head;
} yaffs_CheckpointValidity; } 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 -----------------------*/ /*----------------------- 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); int yaffs_CheckFF(__u8 * buffer, int nBytes);
void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi); 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 #endif

View file

@ -12,7 +12,7 @@
*/ */
const char *yaffs_mtdif_c_version = 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" #include "yportenv.h"
@ -24,7 +24,7 @@ const char *yaffs_mtdif_c_version =
#include "linux/time.h" #include "linux/time.h"
#include "linux/mtd/nand.h" #include "linux/mtd/nand.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) #if (MTD_VERSION_CODE < MTD_VERSION(2,6,18))
static struct nand_oobinfo yaffs_oobinfo = { static struct nand_oobinfo yaffs_oobinfo = {
.useecc = 1, .useecc = 1,
.eccbytes = 6, .eccbytes = 6,
@ -36,7 +36,7 @@ static struct nand_oobinfo yaffs_noeccinfo = {
}; };
#endif #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) static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
{ {
oob[0] = spare->tagByte0; oob[0] = spare->tagByte0;
@ -75,14 +75,14 @@ int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare) const __u8 * data, const yaffs_Spare * spare)
{ {
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 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; struct mtd_oob_ops ops;
#endif #endif
size_t dummy; size_t dummy;
int retval = 0; int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; 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 */ __u8 spareAsBytes[8]; /* OOB */
if (data && !spare) if (data && !spare)
@ -139,14 +139,14 @@ int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
yaffs_Spare * spare) yaffs_Spare * spare)
{ {
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 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; struct mtd_oob_ops ops;
#endif #endif
size_t dummy; size_t dummy;
int retval = 0; int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; 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 */ __u8 spareAsBytes[8]; /* OOB */
if (data && !spare) if (data && !spare)

View file

@ -18,6 +18,11 @@
#include "yaffs_guts.h" #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, int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare); const __u8 * data, const yaffs_Spare * spare);
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data, int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,

View file

@ -1,434 +0,0 @@
From ian@brightstareng.com Fri May 18 15:06:49 2007
From ian@brightstareng.com Fri May 18 15:08:21 2007
Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
(envelope-from <ian@brightstareng.com>)
id 1Hp380-00011e-T6
for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
Received: from localhost (localhost.localdomain [127.0.0.1])
by zebra.brightstareng.com (Postfix) with ESMTP
id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
Received: from zebra.brightstareng.com ([127.0.0.1])
by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
Received: from pippin (unknown [192.168.1.25])
by zebra.brightstareng.com (Postfix) with ESMTP
id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
From: Ian McDonnell <ian@brightstareng.com>
To: David Goodenough <david.goodenough@linkchoose.co.uk>
Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
Date: Fri, 18 May 2007 10:06:49 -0400
User-Agent: KMail/1.9.1
References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
Cc: Andrea Conti <alyf@alyf.net>,
Charles Manning <manningc2@actrix.gen.nz>
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
boundary="Boundary-00=_5LbTGmt62YoutxM"
Message-Id: <200705181006.49860.ian@brightstareng.com>
X-Virus-Scanned: by amavisd-new at brightstareng.com
Status: R
X-Status: NT
X-KMail-EncryptionState:
X-KMail-SignatureState:
X-KMail-MDN-Sent:
--Boundary-00=_5LbTGmt62YoutxM
Content-Type: text/plain;
charset="iso-8859-15"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
David, Andrea,
On Friday 18 May 2007 08:34, you wrote:
> Yea team. With this fix in place (I put it in the wrong place
> at first) I can now mount and ls the Yaffs partition without
> an error messages!
Good news!
Attached is a newer yaffs_mtdif1.c with a bandaid to help the
2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
See the LINUX_VERSION_CODE conditional in
nandmtd1_ReadChunkWithTagsFromNAND.
-imcd
--Boundary-00=_5LbTGmt62YoutxM
Content-Type: text/x-csrc;
charset="iso-8859-15";
name="yaffs_mtdif1.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="yaffs_mtdif1.c"
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
*
* Copyright (C) 2002 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This module provides the interface between yaffs_nand.c and the
* MTD API. This version is used when the MTD interface supports the
* 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
* and we have small-page NAND device.
*
* These functions are invoked via function pointers in yaffs_nand.c.
* This replaces functionality provided by functions in yaffs_mtdif.c
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
* called in yaffs_mtdif.c when the function pointers are NULL.
* We assume the MTD layer is performing ECC (useNANDECC is true).
*/
#include "yportenv.h"
#include "yaffs_guts.h"
#include "yaffs_packedtags1.h"
#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
#include "linux/kernel.h"
#include "linux/version.h"
#include "linux/types.h"
#include "linux/mtd/mtd.h"
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
const char *yaffs_mtdif1_c_version = "$Id: 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--

View file

@ -34,9 +34,9 @@
#include "linux/mtd/mtd.h" #include "linux/mtd/mtd.h"
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
#if (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 #ifndef CONFIG_YAFFS_9BYTE_TAGS
# define YTAG1_SIZE 8 # define YTAG1_SIZE 8
@ -189,7 +189,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
ops.datbuf = data; ops.datbuf = data;
ops.oobbuf = (__u8 *)&pt1; 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; /* 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. * 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 blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
int retval; 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); retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
return (retval) ? YAFFS_FAIL : YAFFS_OK; 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; struct mtd_info * mtd = dev->genericDevice;
int chunkNo = blockNo * dev->nChunksPerBlock; int chunkNo = blockNo * dev->nChunksPerBlock;
loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
yaffs_ExtendedTags etags; yaffs_ExtendedTags etags;
int state = YAFFS_BLOCK_STATE_DEAD; int state = YAFFS_BLOCK_STATE_DEAD;
int seqnum = 0; int seqnum = 0;
@ -340,11 +341,16 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
} }
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
etags.blockBad = (mtd->block_isbad)(mtd, addr);
if (etags.blockBad) { if (etags.blockBad) {
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
"block %d is marked bad", blockNo); "block %d is marked bad\n", blockNo);
state = YAFFS_BLOCK_STATE_DEAD; 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) { else if (etags.chunkUsed) {
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
seqnum = etags.sequenceNumber; seqnum = etags.sequenceNumber;
@ -360,4 +366,4 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
return YAFFS_OK; return YAFFS_OK;
} }
#endif /*KERNEL_VERSION*/ #endif /*MTD_VERSION*/

View file

@ -14,7 +14,7 @@
/* mtd interface for YAFFS2 */ /* mtd interface for YAFFS2 */
const char *yaffs_mtdif2_c_version = 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" #include "yportenv.h"
@ -27,19 +27,23 @@ const char *yaffs_mtdif2_c_version =
#include "yaffs_packedtags2.h" #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, int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const __u8 * data,
const yaffs_ExtendedTags * tags) const yaffs_ExtendedTags * tags)
{ {
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 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; struct mtd_oob_ops ops;
#else #else
size_t dummy; size_t dummy;
#endif #endif
int retval = 0; int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; loff_t addr;
yaffs_PackedTags2 pt; yaffs_PackedTags2 pt;
@ -48,46 +52,41 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags)); 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) { 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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
ops.mode = MTD_OOB_AUTO; ops.mode = MTD_OOB_AUTO;
ops.ooblen = sizeof(pt); ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
ops.len = dev->nDataBytesPerChunk; ops.len = dev->totalBytesPerChunk;
ops.ooboffs = 0; ops.ooboffs = 0;
ops.datbuf = (__u8 *)data; ops.datbuf = (__u8 *)data;
ops.oobbuf = (void *)&pt; ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
retval = mtd->write_oob(mtd, addr, &ops); retval = mtd->write_oob(mtd, addr, &ops);
} else
BUG(); /* both tags and data should always be present */
#else
if (tags) {
yaffs_PackTags2(&pt, tags);
}
if (data && tags) { #else
if (dev->useNANDECC) if (!dev->inbandTags) {
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) & pt, NULL);
else
retval = retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) & pt, NULL); &dummy, data, (__u8 *) & pt, NULL);
} else { } else {
if (data)
retval = retval =
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
data); data);
if (tags)
retval =
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
(__u8 *) & pt);
} }
#endif #endif
@ -101,11 +100,12 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags) __u8 * data, yaffs_ExtendedTags * tags)
{ {
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 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; struct mtd_oob_ops ops;
#endif #endif
size_t dummy; size_t dummy;
int retval = 0; int retval = 0;
int localData = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; 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" ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags)); 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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
if (data && !tags) if (dev->inbandTags || (data && !tags))
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
&dummy, data); &dummy, data);
else if (tags) { else if (tags) {
ops.mode = MTD_OOB_AUTO; ops.mode = MTD_OOB_AUTO;
@ -130,38 +141,43 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
retval = mtd->read_oob(mtd, addr, &ops); retval = mtd->read_oob(mtd, addr, &ops);
} }
#else #else
if (data && tags) { if (!dev->inbandTags && data && tags) {
if (dev->useNANDECC) {
retval = retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, dev->spareBuffer, &dummy, data, dev->spareBuffer,
NULL); NULL);
} else {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, dev->spareBuffer,
NULL);
}
} else { } else {
if (data) if (data)
retval = retval =
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data); data);
if (tags) if (!dev->inbandTags && tags)
retval = retval =
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
dev->spareBuffer); dev->spareBuffer);
} }
#endif #endif
memcpy(&pt, dev->spareBuffer, sizeof(pt));
if (tags) 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); yaffs_UnpackTags2(tags, &pt);
}
}
if(localData)
yaffs_ReleaseTempBuffer(dev,data,__LINE__);
if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
if (retval == 0) if (retval == 0)
return YAFFS_OK; return YAFFS_OK;
else else

View file

@ -12,12 +12,13 @@
*/ */
const char *yaffs_nand_c_version = 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_nand.h"
#include "yaffs_tagscompat.h" #include "yaffs_tagscompat.h"
#include "yaffs_tagsvalidity.h" #include "yaffs_tagsvalidity.h"
#include "yaffs_getblockinfo.h"
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer, __u8 * buffer,
@ -98,7 +99,7 @@ int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
int yaffs_QueryInitialBlockState(yaffs_Device * dev, int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo, int blockNo,
yaffs_BlockState * state, yaffs_BlockState * state,
unsigned *sequenceNumber) __u32 *sequenceNumber)
{ {
blockNo -= dev->blockOffset; blockNo -= dev->blockOffset;

View file

@ -22,13 +22,13 @@
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, const __u8 * data, int chunkInNAND, const __u8 * data,
yaffs_ExtendedTags * tags); const yaffs_ExtendedTags * tags);
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev, int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, __u8 * data, int chunkInNAND, __u8 * data,
yaffs_ExtendedTags * tags); yaffs_ExtendedTags * tags);
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandemul2k_QueryNANDBlock(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 nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND); int blockInNAND);
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev); int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);

View file

@ -37,60 +37,70 @@
#define EXTRA_OBJECT_TYPE_SHIFT (28) #define EXTRA_OBJECT_TYPE_SHIFT (28)
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) #define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart * ptt)
{ {
T(YAFFS_TRACE_MTD, T(YAFFS_TRACE_MTD,
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
pt->t.objectId, pt->t.chunkId, pt->t.byteCount, ptt->objectId, ptt->chunkId, ptt->byteCount,
pt->t.sequenceNumber)); ptt->sequenceNumber));
}
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
{
yaffs_DumpPackedTags2TagsPart(&pt->t);
} }
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t) static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
{ {
T(YAFFS_TRACE_MTD, T(YAFFS_TRACE_MTD,
(TSTR (TSTR
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte " ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
"%d del %d ser %d seq %d"
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId, TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
t->sequenceNumber)); 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; ptt->chunkId = t->chunkId;
pt->t.sequenceNumber = t->sequenceNumber; ptt->sequenceNumber = t->sequenceNumber;
pt->t.byteCount = t->byteCount; ptt->byteCount = t->byteCount;
pt->t.objectId = t->objectId; ptt->objectId = t->objectId;
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) { if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
/* Store the extra header info instead */ /* Store the extra header info instead */
/* We save the parent object in the chunkId */ /* We save the parent object in the chunkId */
pt->t.chunkId = EXTRA_HEADER_INFO_FLAG ptt->chunkId = EXTRA_HEADER_INFO_FLAG
| t->extraParentObjectId; | t->extraParentObjectId;
if (t->extraIsShrinkHeader) { if (t->extraIsShrinkHeader) {
pt->t.chunkId |= EXTRA_SHRINK_FLAG; ptt->chunkId |= EXTRA_SHRINK_FLAG;
} }
if (t->extraShadows) { if (t->extraShadows) {
pt->t.chunkId |= EXTRA_SHADOWS_FLAG; ptt->chunkId |= EXTRA_SHADOWS_FLAG;
} }
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK; ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
pt->t.objectId |= ptt->objectId |=
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT); (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
pt->t.byteCount = t->extraEquivalentObjectId; ptt->byteCount = t->extraEquivalentObjectId;
} else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) { } else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
pt->t.byteCount = t->extraFileLength; ptt->byteCount = t->extraFileLength;
} else { } else {
pt->t.byteCount = 0; ptt->byteCount = 0;
} }
} }
yaffs_DumpPackedTags2(pt); yaffs_DumpPackedTags2TagsPart(ptt);
yaffs_DumpTags2(t); yaffs_DumpTags2(t);
}
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
{
yaffs_PackTags2TagsPart(&pt->t,t);
#ifndef YAFFS_IGNORE_TAGS_ECC #ifndef YAFFS_IGNORE_TAGS_ECC
{ {
@ -101,13 +111,60 @@ void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
#endif #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)); memset(t, 0, sizeof(yaffs_ExtendedTags));
yaffs_InitialiseTags(t); 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) { if (pt->t.sequenceNumber != 0xFFFFFFFF) {
/* Page is in use */ /* Page is in use */
#ifdef YAFFS_IGNORE_TAGS_ECC #ifdef YAFFS_IGNORE_TAGS_ECC
@ -142,41 +199,10 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
} }
} }
#endif #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_DumpPackedTags2(pt);
yaffs_DumpTags2(t); yaffs_DumpTags2(t);
} }

View file

@ -33,6 +33,11 @@ typedef struct {
yaffs_ECCOther ecc; yaffs_ECCOther ecc;
} yaffs_PackedTags2; } yaffs_PackedTags2;
/* Full packed tags with ECC, used for oob tags */
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t); void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt); 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 #endif

View file

@ -14,6 +14,7 @@
#include "yaffs_guts.h" #include "yaffs_guts.h"
#include "yaffs_tagscompat.h" #include "yaffs_tagscompat.h"
#include "yaffs_ecc.h" #include "yaffs_ecc.h"
#include "yaffs_getblockinfo.h"
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND); static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
#ifdef NOTYET #ifdef NOTYET
@ -438,7 +439,7 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
yaffs_ECCResult eccResult; yaffs_ECCResult eccResult;
static yaffs_Spare spareFF; static yaffs_Spare spareFF;
static int init; static int init = 0;
if (!init) { if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF)); memset(&spareFF, 0xFF, sizeof(spareFF));
@ -497,9 +498,9 @@ int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
} }
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState * int blockNo,
state, yaffs_BlockState *state,
int *sequenceNumber) __u32 *sequenceNumber)
{ {
yaffs_Spare spare0, spare1; yaffs_Spare spare0, spare1;

View file

@ -30,8 +30,9 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int blockNo); int blockNo);
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState * int blockNo,
state, int *sequenceNumber); yaffs_BlockState *state,
__u32 *sequenceNumber);
void yaffs_CalcTagsECC(yaffs_Tags * tags); void yaffs_CalcTagsECC(yaffs_Tags * tags);
int yaffs_CheckECCOnTags(yaffs_Tags * tags); int yaffs_CheckECCOnTags(yaffs_Tags * tags);

View file

@ -17,6 +17,14 @@
#ifndef __YPORTENV_H__ #ifndef __YPORTENV_H__
#define __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 #if defined CONFIG_YAFFS_WINCE
#include "ywinceenv.h" #include "ywinceenv.h"
@ -26,7 +34,10 @@
#include "moduleconfig.h" #include "moduleconfig.h"
/* Linux kernel */ /* Linux kernel */
#include <linux/version.h> #include <linux/version.h>
#define MTD_VERSION_CODE LINUX_VERSION_CODE
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
#include <linux/config.h> #include <linux/config.h>
#endif #endif
@ -90,6 +101,8 @@
#elif defined CONFIG_YAFFS_DIRECT #elif defined CONFIG_YAFFS_DIRECT
#define MTD_VERSION_CODE MTD_VERSION(2,6,22)
/* Direct interface */ /* Direct interface */
#include "ydirectenv.h" #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) #define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
#ifndef CONFIG_YAFFS_WINCE #ifndef YBUG
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__)) #define YBUG() do {T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__));} while(0)
#endif #endif
#endif #endif

View file

@ -43,7 +43,8 @@ config YAFFS_9BYTE_TAGS
format that you need to continue to support. New data written format that you need to continue to support. New data written
also uses the older-style format. Note: Use of this option also uses the older-style format. Note: Use of this option
generally requires that MTD's oob layout be adjusted to use the 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. If unsure, say N.
@ -109,26 +110,6 @@ config YAFFS_DISABLE_LAZY_LOAD
If unsure, say N. 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 config YAFFS_DISABLE_WIDE_TNODES
bool "Turn off wide tnodes" bool "Turn off wide tnodes"

View file

@ -5,7 +5,6 @@
obj-$(CONFIG_YAFFS_FS) += yaffs.o obj-$(CONFIG_YAFFS_FS) += yaffs.o
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o yaffs-y := yaffs_ecc.o yaffs_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_tagscompat.o yaffs_tagsvalidity.o
yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o

View file

@ -14,194 +14,117 @@
*/ */
/* /*
* This file is just holds extra declarations used during development. * This file is just holds extra declarations of macros that would normally
* Most of these are from kernel includes placed here so we can use them in * be providesd in the Linux kernel. These macros have been written from
* applications. * scratch but are functionally equivalent to the Linux ones.
* *
*/ */
#ifndef __EXTRAS_H__ #ifndef __EXTRAS_H__
#define __EXTRAS_H__ #define __EXTRAS_H__
#if defined WIN32
#define __inline__ __inline
#define new newHack
#endif
#if !(defined __KERNEL__) || (defined WIN32) #if !(defined __KERNEL__)
/* User space defines */
/* Definition of types */
typedef unsigned char __u8; typedef unsigned char __u8;
typedef unsigned short __u16; typedef unsigned short __u16;
typedef unsigned __u32; typedef unsigned __u32;
#endif
/* /*
* Simple doubly linked list implementation. * This is a simple doubly linked list implementation that matches the
* * way the Linux kernel doubly linked list implementation works.
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/ */
#define prefetch(x) 1 struct ylist_head {
struct ylist_head *next; /* next in chain */
struct list_head { struct ylist_head *prev; /* previous in chain */
struct list_head *next, *prev;
}; };
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \ /* Initialise a list head to an empty list */
struct list_head name = LIST_HEAD_INIT(name) #define YINIT_LIST_HEAD(p) \
do { \
#define INIT_LIST_HEAD(ptr) do { \ (p)->next = (p);\
(ptr)->next = (ptr); (ptr)->prev = (ptr); \ (p)->prev = (p); \
} while(0) } while(0)
/*
* Insert a new entry between two known consecutive entries. /* Add an element to a list */
* static __inline__ void ylist_add(struct ylist_head *newEntry,
* This is only for internal list manipulation where we know struct ylist_head *list)
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{ {
next->prev = new; struct ylist_head *listNext = list->next;
new->next = next;
new->prev = prev; list->next = newEntry;
prev->next = new; newEntry->prev = list;
newEntry->next = listNext;
listNext->prev = newEntry;
} }
/**
* list_add - add a new entry /* Take an element out of its current list, with or without
* @new: new entry to be added * reinitialising the links.of the entry*/
* @head: list head to add it after static __inline__ void ylist_del(struct ylist_head *entry)
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{ {
__list_add(new, head, head->next); struct ylist_head *listNext = entry->next;
struct ylist_head *listPrev = entry->prev;
listNext->prev = listPrev;
listPrev->next = listNext;
} }
/** static __inline__ void ylist_del_init(struct ylist_head *entry)
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *new,
struct list_head *head)
{ {
__list_add(new, head->prev, head); ylist_del(entry);
entry->next = entry->prev = entry;
} }
/*
* Delete a list entry by making the prev/next entries /* Test if the list is empty */
* point to each other. static __inline__ int ylist_empty(struct ylist_head *entry)
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head *prev,
struct list_head *next)
{ {
next->prev = prev; return (entry->next == entry);
prev->next = next;
} }
/**
* list_del - deletes entry from list. /* ylist_entry takes a pointer to a list entry and offsets it to that
* @entry: the element to delete from the list. * we can find a pointer to the object it is embedded in.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/ */
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it. #define ylist_entry(entry, type, member) \
* @entry: the element to delete from the list. ((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);
}
/** #define ylist_for_each(itervar, list) \
* list_empty - tests whether a list is empty for (itervar = (list)->next; itervar != (list); itervar = itervar->next )
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
/** #define ylist_for_each_safe(itervar,saveVar, list) \
* list_splice - join two lists for (itervar = (list)->next, saveVar = (list)->next->next; itervar != (list); \
* @list: the new list to add. itervar = saveVar, saveVar = saveVar->next)
* @head: the place to add it in the first list.
*/
static __inline__ void list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
if (first != list) {
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head; #if !(defined __KERNEL__)
head->next = first;
last->next = at;
at->prev = last;
}
}
/** #ifndef WIN32
* list_entry - get the struct for this entry #include <sys/stat.h>
* @ptr: the &struct list_head pointer. #endif
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
pos = pos->next, prefetch(pos->next))
/** #ifdef CONFIG_YAFFS_PROVIDE_DEFS
* list_for_each_safe - iterate over a list safe against removal /* File types */
* of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/*
* File types
*/
#define DT_UNKNOWN 0 #define DT_UNKNOWN 0
#define DT_FIFO 1 #define DT_FIFO 1
#define DT_CHR 2 #define DT_CHR 2
@ -212,13 +135,13 @@ static __inline__ void list_splice(struct list_head *list,
#define DT_SOCK 12 #define DT_SOCK 12
#define DT_WHT 14 #define DT_WHT 14
#ifndef WIN32 #ifndef WIN32
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
/* /*
* Attribute flags. These should be or-ed together to figure out what * Attribute flags.
* has been changed!
*/ */
#define ATTR_MODE 1 #define ATTR_MODE 1
#define ATTR_UID 2 #define ATTR_UID 2
@ -227,10 +150,7 @@ static __inline__ void list_splice(struct list_head *list,
#define ATTR_ATIME 16 #define ATTR_ATIME 16
#define ATTR_MTIME 32 #define ATTR_MTIME 32
#define ATTR_CTIME 64 #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 { struct iattr {
unsigned int ia_valid; unsigned int ia_valid;
@ -244,21 +164,18 @@ struct iattr {
unsigned int ia_attr_flags; unsigned int ia_attr_flags;
}; };
#endif
#define KERN_DEBUG #define KERN_DEBUG
#else #else
#ifndef WIN32
#include <linux/types.h> #include <linux/types.h>
#include <linux/list.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/stat.h> #include <linux/stat.h>
#endif
#endif #endif
#if defined WIN32
#undef new
#endif
#endif #endif

View file

@ -54,11 +54,11 @@ that you need to continue to support. New data written also uses the
older-style format. older-style format.
Note: Use of this option generally requires that MTD's oob layout be 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 adjusted to use the older-style format. See notes on tags formats and
MTD versions. MTD versions in yaffs_mtdif1.c.
*/ */
/* Default: Not selected */ /* Default: Not selected */
/* Meaning: Use older-style on-NAND data format with pageStatus byte */ /* Meaning: Use older-style on-NAND data format with pageStatus byte */
#define CONFIG_YAFFS_9BYTE_TAGS //#define CONFIG_YAFFS_9BYTE_TAGS
#endif /* YAFFS_OUT_OF_TREE */ #endif /* YAFFS_OUT_OF_TREE */

View file

@ -12,11 +12,11 @@
*/ */
const char *yaffs_checkptrw_c_version = 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_checkptrw.h"
#include "yaffs_getblockinfo.h"
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
{ {
@ -142,7 +142,7 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
return 0; return 0;
if(!dev->checkpointBuffer) if(!dev->checkpointBuffer)
dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk); dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
if(!dev->checkpointBuffer) if(!dev->checkpointBuffer)
return 0; return 0;

View file

@ -29,7 +29,7 @@
*/ */
const char *yaffs_ecc_c_version = 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" #include "yportenv.h"

View file

@ -32,7 +32,7 @@
*/ */
const char *yaffs_fs_c_version = 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; extern const char *yaffs_guts_c_version;
#include <linux/version.h> #include <linux/version.h>
@ -53,6 +53,8 @@ extern const char *yaffs_guts_c_version;
#include <linux/string.h> #include <linux/string.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include "asm/div64.h"
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
#include <linux/statfs.h> /* Added NCB 15-8-2003 */ #include <linux/statfs.h> /* Added NCB 15-8-2003 */
@ -753,6 +755,8 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
break; break;
} }
inode->i_flags |= S_NOATIME;
inode->i_ino = obj->objectId; inode->i_ino = obj->objectId;
inode->i_mode = obj->yst_mode; inode->i_mode = obj->yst_mode;
inode->i_uid = obj->yst_uid; 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_type = YAFFS_MAGIC;
buf->f_bsize = sb->s_blocksize; buf->f_bsize = sb->s_blocksize;
buf->f_namelen = 255; 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 = buf->f_blocks =
(dev->endBlock - dev->startBlock + (dev->endBlock - dev->startBlock + 1) *
1) * dev->nChunksPerBlock / (sb->s_blocksize / dev->nChunksPerBlock /
dev->nDataBytesPerChunk); (sb->s_blocksize / dev->nDataBytesPerChunk);
buf->f_bfree = buf->f_bfree =
yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize / yaffs_GetNumberOfFreeChunks(dev) /
dev->nDataBytesPerChunk); (sb->s_blocksize / dev->nDataBytesPerChunk);
} else { } else {
buf->f_blocks = buf->f_blocks =
(dev->endBlock - dev->startBlock + (dev->endBlock - dev->startBlock + 1) *
1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk / dev->nChunksPerBlock *
sb->s_blocksize); (dev->nDataBytesPerChunk / sb->s_blocksize);
buf->f_bfree = buf->f_bfree =
yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk / yaffs_GetNumberOfFreeChunks(dev) *
sb->s_blocksize); (dev->nDataBytesPerChunk / sb->s_blocksize);
} }
buf->f_files = 0; buf->f_files = 0;
buf->f_ffree = 0; buf->f_ffree = 0;
buf->f_bavail = buf->f_bfree; 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_magic = YAFFS_MAGIC;
sb->s_op = &yaffs_super_ops; sb->s_op = &yaffs_super_ops;
sb->s_flags |= MS_NOATIME;
if (!sb) if (!sb)
printk(KERN_INFO "yaffs: sb is NULL\n"); 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 #ifdef CONFIG_YAFFS_AUTO_YAFFS2
if (yaffsVersion == 1 && if (yaffsVersion == 1 &&
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) WRITE_SIZE(mtd) >= 2048) {
mtd->writesize >= 2048) {
#else
mtd->oobblock >= 2048) {
#endif
T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n")); T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
yaffsVersion = 2; yaffsVersion = 2;
} }
/* Added NCB 26/5/2006 for completeness */ /* Added NCB 26/5/2006 for completeness */
if (yaffsVersion == 2 && if (yaffsVersion == 2 &&
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) !options.inband_tags &&
mtd->writesize == 512) { WRITE_SIZE(mtd) == 512){
#else
mtd->oobblock == 512) {
#endif
T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n")); T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
yaffsVersion = 1; yaffsVersion = 1;
} }
@ -1719,12 +1739,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
return NULL; return NULL;
} }
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE || mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
#else !options.inband_tags) {
if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
#endif
mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) {
T(YAFFS_TRACE_ALWAYS, T(YAFFS_TRACE_ALWAYS,
("yaffs: MTD device does not have the " ("yaffs: MTD device does not have the "
"right page sizes\n")); "right page sizes\n"));
@ -1784,9 +1801,10 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
dev->startBlock = 0; dev->startBlock = 0;
dev->endBlock = nBlocks - 1; dev->endBlock = nBlocks - 1;
dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK; dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
dev->nReservedBlocks = 5; dev->nReservedBlocks = 5;
dev->nShortOpCaches = (options.no_cache) ? 0 : 10; dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
dev->inbandTags = options.inband_tags;
/* ... and the functions. */ /* ... and the functions. */
if (yaffsVersion == 2) { if (yaffsVersion == 2) {
@ -1799,15 +1817,14 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
dev->spareBuffer = YMALLOC(mtd->oobsize); dev->spareBuffer = YMALLOC(mtd->oobsize);
dev->isYaffs2 = 1; dev->isYaffs2 = 1;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
dev->nDataBytesPerChunk = mtd->writesize; dev->totalBytesPerChunk = mtd->writesize;
dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
#else #else
dev->nDataBytesPerChunk = mtd->oobblock; dev->totalBytesPerChunk = mtd->oobblock;
dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
#endif #endif
nBlocks = mtd->size / mtd->erasesize; nBlocks = mtd->size / mtd->erasesize;
dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS;
dev->startBlock = 0; dev->startBlock = 0;
dev->endBlock = nBlocks - 1; dev->endBlock = nBlocks - 1;
} else { } 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, "startBlock......... %d\n", dev->startBlock);
buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); 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, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits); buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize); buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks); buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks); 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, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated); buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes); 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, "nPageReads......... %d\n", dev->nPageReads);
buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures); buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies); buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
buf += buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections); buf += sprintf(buf, "passiveGCs......... %d\n",
buf +=
sprintf(buf, "passiveGCs......... %d\n",
dev->passiveGarbageCollections); dev->passiveGarbageCollections);
buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites); buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches); 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); sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC); buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2); buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
return buf; return buf;
} }

View file

@ -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

View file

@ -90,7 +90,7 @@
#define YAFFS_MAX_SHORT_OP_CACHES 20 #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. /* 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. * 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 softDeletions:10; /* number of soft deleted pages */
int pagesInUse:10; /* number of pages in use */ 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 */ __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
/* and retire the block. */ /* and retire the block. */
__u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this 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 */ __u16 sum__NoLongerUsed; /* checksum of name. No longer used */
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; 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 */ __u32 yst_mode; /* protection */
#ifdef CONFIG_YAFFS_WINCE #ifdef CONFIG_YAFFS_WINCE
@ -331,11 +331,14 @@ typedef struct {
__u32 win_ctime[2]; __u32 win_ctime[2];
__u32 win_atime[2]; __u32 win_atime[2];
__u32 win_mtime[2]; __u32 win_mtime[2];
__u32 roomToGrow[4];
#else #else
__u32 roomToGrow[10]; __u32 roomToGrow[6];
#endif
#endif
__u32 inbandShadowsObject;
__u32 inbandIsShrink;
__u32 reservedSpace[2];
int shadowsObject; /* This object header shadows the specified object if > 0 */ int shadowsObject; /* This object header shadows the specified object if > 0 */
/* isShrink applies to object headers written when we shrink the file (ie resize) */ /* isShrink applies to object headers written when we shrink the file (ie resize) */
@ -381,7 +384,7 @@ typedef struct {
} yaffs_FileStructure; } yaffs_FileStructure;
typedef struct { typedef struct {
struct list_head children; /* list of child links */ struct ylist_head children; /* list of child links */
} yaffs_DirectoryStructure; } yaffs_DirectoryStructure;
typedef struct { typedef struct {
@ -424,14 +427,14 @@ struct yaffs_ObjectStruct {
struct yaffs_DeviceStruct *myDev; /* The device I'm on */ 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 */ /* directory structure stuff */
/* also used for linking up the free list */ /* also used for linking up the free list */
struct yaffs_ObjectStruct *parent; struct yaffs_ObjectStruct *parent;
struct list_head siblings; struct ylist_head siblings;
/* Where's my object header in NAND? */ /* Where's my object header in NAND? */
int chunkId; int chunkId;
@ -485,7 +488,7 @@ struct yaffs_ObjectList_struct {
typedef struct yaffs_ObjectList_struct yaffs_ObjectList; typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
typedef struct { typedef struct {
struct list_head list; struct ylist_head list;
int count; int count;
} yaffs_ObjectBucket; } yaffs_ObjectBucket;
@ -528,7 +531,7 @@ typedef struct {
/*----------------- Device ---------------------------------*/ /*----------------- Device ---------------------------------*/
struct yaffs_DeviceStruct { struct yaffs_DeviceStruct {
struct list_head devList; struct ylist_head devList;
const char *name; const char *name;
/* Entry parameters set up way early. Yaffs sets up the rest.*/ /* 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 */ /* Stuff used by the shared space checkpointing mechanism */
/* If this value is zero, then this mechanism is disabled */ /* 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); yaffs_ExtendedTags * tags);
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo); int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
int (*queryNANDBlock) (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 #endif
int isYaffs2; int isYaffs2;
@ -599,6 +602,7 @@ struct yaffs_DeviceStruct {
int wideTnodesDisabled; /* Set to disable wide tnodes */ int wideTnodesDisabled; /* Set to disable wide tnodes */
YCHAR *pathDividers; /* String of legal path dividers */
/* End of stuff that must be set before initialisation. */ /* End of stuff that must be set before initialisation. */
@ -615,16 +619,14 @@ struct yaffs_DeviceStruct {
__u32 tnodeWidth; __u32 tnodeWidth;
__u32 tnodeMask; __u32 tnodeMask;
/* Stuff to support various file offses to chunk/offset translations */ /* Stuff for figuring out file offset to chunk conversions */
/* "Crumbs" for nDataBytesPerChunk not being a power of 2 */ __u32 chunkShift; /* Shift value */
__u32 crumbMask; __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
__u32 crumbShift; __u32 chunkMask; /* Mask to use for power-of-2 case */
__u32 crumbsPerChunk;
/* Straight shifting for nDataBytesPerChunk being a power of 2 */
__u32 chunkShift;
__u32 chunkMask;
/* Stuff to handle inband tags */
int inbandTags;
__u32 totalBytesPerChunk;
#ifdef __KERNEL__ #ifdef __KERNEL__
@ -663,6 +665,8 @@ struct yaffs_DeviceStruct {
__u32 checkpointSum; __u32 checkpointSum;
__u32 checkpointXor; __u32 checkpointXor;
int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */
/* Block Info */ /* Block Info */
yaffs_BlockInfo *blockInfo; yaffs_BlockInfo *blockInfo;
__u8 *chunkBits; /* bitmap of chunks in use */ __u8 *chunkBits; /* bitmap of chunks in use */
@ -745,8 +749,10 @@ struct yaffs_DeviceStruct {
int nBackgroundDeletions; /* Count of background deletions. */ int nBackgroundDeletions; /* Count of background deletions. */
/* Temporary buffer management */
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS]; yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
int maxTemp; int maxTemp;
int tempInUse;
int unmanagedTempAllocations; int unmanagedTempAllocations;
int unmanagedTempDeallocations; int unmanagedTempDeallocations;
@ -758,7 +764,7 @@ struct yaffs_DeviceStruct {
typedef struct yaffs_DeviceStruct yaffs_Device; 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 { typedef struct {
int StructType; int StructType;
int version; int version;
@ -797,18 +803,6 @@ typedef struct {
__u32 head; __u32 head;
} yaffs_CheckpointValidity; } 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 -----------------------*/ /*----------------------- 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); int yaffs_CheckFF(__u8 * buffer, int nBytes);
void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi); 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 #endif

View file

@ -12,7 +12,7 @@
*/ */
const char *yaffs_mtdif_c_version = 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" #include "yportenv.h"
@ -24,7 +24,7 @@ const char *yaffs_mtdif_c_version =
#include "linux/time.h" #include "linux/time.h"
#include "linux/mtd/nand.h" #include "linux/mtd/nand.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) #if (MTD_VERSION_CODE < MTD_VERSION(2,6,18))
static struct nand_oobinfo yaffs_oobinfo = { static struct nand_oobinfo yaffs_oobinfo = {
.useecc = 1, .useecc = 1,
.eccbytes = 6, .eccbytes = 6,
@ -36,7 +36,7 @@ static struct nand_oobinfo yaffs_noeccinfo = {
}; };
#endif #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) static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
{ {
oob[0] = spare->tagByte0; oob[0] = spare->tagByte0;
@ -75,14 +75,14 @@ int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare) const __u8 * data, const yaffs_Spare * spare)
{ {
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 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; struct mtd_oob_ops ops;
#endif #endif
size_t dummy; size_t dummy;
int retval = 0; int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; 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 */ __u8 spareAsBytes[8]; /* OOB */
if (data && !spare) if (data && !spare)
@ -139,14 +139,14 @@ int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
yaffs_Spare * spare) yaffs_Spare * spare)
{ {
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 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; struct mtd_oob_ops ops;
#endif #endif
size_t dummy; size_t dummy;
int retval = 0; int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; 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 */ __u8 spareAsBytes[8]; /* OOB */
if (data && !spare) if (data && !spare)

View file

@ -18,6 +18,11 @@
#include "yaffs_guts.h" #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, int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare); const __u8 * data, const yaffs_Spare * spare);
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data, int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,

View file

@ -1,434 +0,0 @@
From ian@brightstareng.com Fri May 18 15:06:49 2007
From ian@brightstareng.com Fri May 18 15:08:21 2007
Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
(envelope-from <ian@brightstareng.com>)
id 1Hp380-00011e-T6
for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
Received: from localhost (localhost.localdomain [127.0.0.1])
by zebra.brightstareng.com (Postfix) with ESMTP
id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
Received: from zebra.brightstareng.com ([127.0.0.1])
by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
Received: from pippin (unknown [192.168.1.25])
by zebra.brightstareng.com (Postfix) with ESMTP
id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
From: Ian McDonnell <ian@brightstareng.com>
To: David Goodenough <david.goodenough@linkchoose.co.uk>
Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
Date: Fri, 18 May 2007 10:06:49 -0400
User-Agent: KMail/1.9.1
References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
Cc: Andrea Conti <alyf@alyf.net>,
Charles Manning <manningc2@actrix.gen.nz>
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
boundary="Boundary-00=_5LbTGmt62YoutxM"
Message-Id: <200705181006.49860.ian@brightstareng.com>
X-Virus-Scanned: by amavisd-new at brightstareng.com
Status: R
X-Status: NT
X-KMail-EncryptionState:
X-KMail-SignatureState:
X-KMail-MDN-Sent:
--Boundary-00=_5LbTGmt62YoutxM
Content-Type: text/plain;
charset="iso-8859-15"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
David, Andrea,
On Friday 18 May 2007 08:34, you wrote:
> Yea team. With this fix in place (I put it in the wrong place
> at first) I can now mount and ls the Yaffs partition without
> an error messages!
Good news!
Attached is a newer yaffs_mtdif1.c with a bandaid to help the
2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
See the LINUX_VERSION_CODE conditional in
nandmtd1_ReadChunkWithTagsFromNAND.
-imcd
--Boundary-00=_5LbTGmt62YoutxM
Content-Type: text/x-csrc;
charset="iso-8859-15";
name="yaffs_mtdif1.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="yaffs_mtdif1.c"
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
*
* Copyright (C) 2002 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This module provides the interface between yaffs_nand.c and the
* MTD API. This version is used when the MTD interface supports the
* 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
* and we have small-page NAND device.
*
* These functions are invoked via function pointers in yaffs_nand.c.
* This replaces functionality provided by functions in yaffs_mtdif.c
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
* called in yaffs_mtdif.c when the function pointers are NULL.
* We assume the MTD layer is performing ECC (useNANDECC is true).
*/
#include "yportenv.h"
#include "yaffs_guts.h"
#include "yaffs_packedtags1.h"
#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
#include "linux/kernel.h"
#include "linux/version.h"
#include "linux/types.h"
#include "linux/mtd/mtd.h"
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
const char *yaffs_mtdif1_c_version = "$Id: 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--

View file

@ -34,9 +34,9 @@
#include "linux/mtd/mtd.h" #include "linux/mtd/mtd.h"
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
#if (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 #ifndef CONFIG_YAFFS_9BYTE_TAGS
# define YTAG1_SIZE 8 # define YTAG1_SIZE 8
@ -189,7 +189,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
ops.datbuf = data; ops.datbuf = data;
ops.oobbuf = (__u8 *)&pt1; 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; /* 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. * 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 blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
int retval; 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); retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
return (retval) ? YAFFS_FAIL : YAFFS_OK; 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; struct mtd_info * mtd = dev->genericDevice;
int chunkNo = blockNo * dev->nChunksPerBlock; int chunkNo = blockNo * dev->nChunksPerBlock;
loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
yaffs_ExtendedTags etags; yaffs_ExtendedTags etags;
int state = YAFFS_BLOCK_STATE_DEAD; int state = YAFFS_BLOCK_STATE_DEAD;
int seqnum = 0; int seqnum = 0;
@ -340,11 +341,16 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
} }
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
etags.blockBad = (mtd->block_isbad)(mtd, addr);
if (etags.blockBad) { if (etags.blockBad) {
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
"block %d is marked bad", blockNo); "block %d is marked bad\n", blockNo);
state = YAFFS_BLOCK_STATE_DEAD; 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) { else if (etags.chunkUsed) {
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
seqnum = etags.sequenceNumber; seqnum = etags.sequenceNumber;
@ -360,4 +366,4 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
return YAFFS_OK; return YAFFS_OK;
} }
#endif /*KERNEL_VERSION*/ #endif /*MTD_VERSION*/

View file

@ -14,7 +14,7 @@
/* mtd interface for YAFFS2 */ /* mtd interface for YAFFS2 */
const char *yaffs_mtdif2_c_version = 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" #include "yportenv.h"
@ -27,19 +27,23 @@ const char *yaffs_mtdif2_c_version =
#include "yaffs_packedtags2.h" #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, int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const __u8 * data,
const yaffs_ExtendedTags * tags) const yaffs_ExtendedTags * tags)
{ {
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 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; struct mtd_oob_ops ops;
#else #else
size_t dummy; size_t dummy;
#endif #endif
int retval = 0; int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; loff_t addr;
yaffs_PackedTags2 pt; yaffs_PackedTags2 pt;
@ -48,46 +52,41 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags)); 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) { 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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
ops.mode = MTD_OOB_AUTO; ops.mode = MTD_OOB_AUTO;
ops.ooblen = sizeof(pt); ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
ops.len = dev->nDataBytesPerChunk; ops.len = dev->totalBytesPerChunk;
ops.ooboffs = 0; ops.ooboffs = 0;
ops.datbuf = (__u8 *)data; ops.datbuf = (__u8 *)data;
ops.oobbuf = (void *)&pt; ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
retval = mtd->write_oob(mtd, addr, &ops); retval = mtd->write_oob(mtd, addr, &ops);
} else
BUG(); /* both tags and data should always be present */
#else
if (tags) {
yaffs_PackTags2(&pt, tags);
}
if (data && tags) { #else
if (dev->useNANDECC) if (!dev->inbandTags) {
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) & pt, NULL);
else
retval = retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) & pt, NULL); &dummy, data, (__u8 *) & pt, NULL);
} else { } else {
if (data)
retval = retval =
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
data); data);
if (tags)
retval =
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
(__u8 *) & pt);
} }
#endif #endif
@ -101,11 +100,12 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags) __u8 * data, yaffs_ExtendedTags * tags)
{ {
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 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; struct mtd_oob_ops ops;
#endif #endif
size_t dummy; size_t dummy;
int retval = 0; int retval = 0;
int localData = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; 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" ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags)); 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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
if (data && !tags) if (dev->inbandTags || (data && !tags))
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
&dummy, data); &dummy, data);
else if (tags) { else if (tags) {
ops.mode = MTD_OOB_AUTO; ops.mode = MTD_OOB_AUTO;
@ -130,38 +141,43 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
retval = mtd->read_oob(mtd, addr, &ops); retval = mtd->read_oob(mtd, addr, &ops);
} }
#else #else
if (data && tags) { if (!dev->inbandTags && data && tags) {
if (dev->useNANDECC) {
retval = retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, dev->spareBuffer, &dummy, data, dev->spareBuffer,
NULL); NULL);
} else {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, dev->spareBuffer,
NULL);
}
} else { } else {
if (data) if (data)
retval = retval =
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data); data);
if (tags) if (!dev->inbandTags && tags)
retval = retval =
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
dev->spareBuffer); dev->spareBuffer);
} }
#endif #endif
memcpy(&pt, dev->spareBuffer, sizeof(pt));
if (tags) 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); yaffs_UnpackTags2(tags, &pt);
}
}
if(localData)
yaffs_ReleaseTempBuffer(dev,data,__LINE__);
if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
if (retval == 0) if (retval == 0)
return YAFFS_OK; return YAFFS_OK;
else else

View file

@ -12,12 +12,13 @@
*/ */
const char *yaffs_nand_c_version = 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_nand.h"
#include "yaffs_tagscompat.h" #include "yaffs_tagscompat.h"
#include "yaffs_tagsvalidity.h" #include "yaffs_tagsvalidity.h"
#include "yaffs_getblockinfo.h"
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer, __u8 * buffer,
@ -98,7 +99,7 @@ int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
int yaffs_QueryInitialBlockState(yaffs_Device * dev, int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo, int blockNo,
yaffs_BlockState * state, yaffs_BlockState * state,
unsigned *sequenceNumber) __u32 *sequenceNumber)
{ {
blockNo -= dev->blockOffset; blockNo -= dev->blockOffset;

View file

@ -22,13 +22,13 @@
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, const __u8 * data, int chunkInNAND, const __u8 * data,
yaffs_ExtendedTags * tags); const yaffs_ExtendedTags * tags);
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev, int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, __u8 * data, int chunkInNAND, __u8 * data,
yaffs_ExtendedTags * tags); yaffs_ExtendedTags * tags);
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandemul2k_QueryNANDBlock(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 nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND); int blockInNAND);
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev); int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);

View file

@ -37,60 +37,70 @@
#define EXTRA_OBJECT_TYPE_SHIFT (28) #define EXTRA_OBJECT_TYPE_SHIFT (28)
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) #define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart * ptt)
{ {
T(YAFFS_TRACE_MTD, T(YAFFS_TRACE_MTD,
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
pt->t.objectId, pt->t.chunkId, pt->t.byteCount, ptt->objectId, ptt->chunkId, ptt->byteCount,
pt->t.sequenceNumber)); ptt->sequenceNumber));
}
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
{
yaffs_DumpPackedTags2TagsPart(&pt->t);
} }
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t) static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
{ {
T(YAFFS_TRACE_MTD, T(YAFFS_TRACE_MTD,
(TSTR (TSTR
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte " ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
"%d del %d ser %d seq %d"
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId, TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
t->sequenceNumber)); 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; ptt->chunkId = t->chunkId;
pt->t.sequenceNumber = t->sequenceNumber; ptt->sequenceNumber = t->sequenceNumber;
pt->t.byteCount = t->byteCount; ptt->byteCount = t->byteCount;
pt->t.objectId = t->objectId; ptt->objectId = t->objectId;
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) { if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
/* Store the extra header info instead */ /* Store the extra header info instead */
/* We save the parent object in the chunkId */ /* We save the parent object in the chunkId */
pt->t.chunkId = EXTRA_HEADER_INFO_FLAG ptt->chunkId = EXTRA_HEADER_INFO_FLAG
| t->extraParentObjectId; | t->extraParentObjectId;
if (t->extraIsShrinkHeader) { if (t->extraIsShrinkHeader) {
pt->t.chunkId |= EXTRA_SHRINK_FLAG; ptt->chunkId |= EXTRA_SHRINK_FLAG;
} }
if (t->extraShadows) { if (t->extraShadows) {
pt->t.chunkId |= EXTRA_SHADOWS_FLAG; ptt->chunkId |= EXTRA_SHADOWS_FLAG;
} }
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK; ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
pt->t.objectId |= ptt->objectId |=
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT); (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
pt->t.byteCount = t->extraEquivalentObjectId; ptt->byteCount = t->extraEquivalentObjectId;
} else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) { } else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
pt->t.byteCount = t->extraFileLength; ptt->byteCount = t->extraFileLength;
} else { } else {
pt->t.byteCount = 0; ptt->byteCount = 0;
} }
} }
yaffs_DumpPackedTags2(pt); yaffs_DumpPackedTags2TagsPart(ptt);
yaffs_DumpTags2(t); yaffs_DumpTags2(t);
}
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
{
yaffs_PackTags2TagsPart(&pt->t,t);
#ifndef YAFFS_IGNORE_TAGS_ECC #ifndef YAFFS_IGNORE_TAGS_ECC
{ {
@ -101,13 +111,60 @@ void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
#endif #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)); memset(t, 0, sizeof(yaffs_ExtendedTags));
yaffs_InitialiseTags(t); 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) { if (pt->t.sequenceNumber != 0xFFFFFFFF) {
/* Page is in use */ /* Page is in use */
#ifdef YAFFS_IGNORE_TAGS_ECC #ifdef YAFFS_IGNORE_TAGS_ECC
@ -142,41 +199,10 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
} }
} }
#endif #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_DumpPackedTags2(pt);
yaffs_DumpTags2(t); yaffs_DumpTags2(t);
} }

View file

@ -33,6 +33,11 @@ typedef struct {
yaffs_ECCOther ecc; yaffs_ECCOther ecc;
} yaffs_PackedTags2; } yaffs_PackedTags2;
/* Full packed tags with ECC, used for oob tags */
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t); void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt); 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 #endif

View file

@ -14,6 +14,7 @@
#include "yaffs_guts.h" #include "yaffs_guts.h"
#include "yaffs_tagscompat.h" #include "yaffs_tagscompat.h"
#include "yaffs_ecc.h" #include "yaffs_ecc.h"
#include "yaffs_getblockinfo.h"
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND); static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
#ifdef NOTYET #ifdef NOTYET
@ -438,7 +439,7 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
yaffs_ECCResult eccResult; yaffs_ECCResult eccResult;
static yaffs_Spare spareFF; static yaffs_Spare spareFF;
static int init; static int init = 0;
if (!init) { if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF)); memset(&spareFF, 0xFF, sizeof(spareFF));
@ -497,9 +498,9 @@ int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
} }
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState * int blockNo,
state, yaffs_BlockState *state,
int *sequenceNumber) __u32 *sequenceNumber)
{ {
yaffs_Spare spare0, spare1; yaffs_Spare spare0, spare1;

View file

@ -30,8 +30,9 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int blockNo); int blockNo);
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState * int blockNo,
state, int *sequenceNumber); yaffs_BlockState *state,
__u32 *sequenceNumber);
void yaffs_CalcTagsECC(yaffs_Tags * tags); void yaffs_CalcTagsECC(yaffs_Tags * tags);
int yaffs_CheckECCOnTags(yaffs_Tags * tags); int yaffs_CheckECCOnTags(yaffs_Tags * tags);

View file

@ -17,6 +17,14 @@
#ifndef __YPORTENV_H__ #ifndef __YPORTENV_H__
#define __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 #if defined CONFIG_YAFFS_WINCE
#include "ywinceenv.h" #include "ywinceenv.h"
@ -26,7 +34,10 @@
#include "moduleconfig.h" #include "moduleconfig.h"
/* Linux kernel */ /* Linux kernel */
#include <linux/version.h> #include <linux/version.h>
#define MTD_VERSION_CODE LINUX_VERSION_CODE
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
#include <linux/config.h> #include <linux/config.h>
#endif #endif
@ -90,6 +101,8 @@
#elif defined CONFIG_YAFFS_DIRECT #elif defined CONFIG_YAFFS_DIRECT
#define MTD_VERSION_CODE MTD_VERSION(2,6,22)
/* Direct interface */ /* Direct interface */
#include "ydirectenv.h" #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) #define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
#ifndef CONFIG_YAFFS_WINCE #ifndef YBUG
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__)) #define YBUG() do {T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__));} while(0)
#endif #endif
#endif #endif

View file

@ -43,7 +43,8 @@ config YAFFS_9BYTE_TAGS
format that you need to continue to support. New data written format that you need to continue to support. New data written
also uses the older-style format. Note: Use of this option also uses the older-style format. Note: Use of this option
generally requires that MTD's oob layout be adjusted to use the 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. If unsure, say N.
@ -109,26 +110,6 @@ config YAFFS_DISABLE_LAZY_LOAD
If unsure, say N. 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 config YAFFS_DISABLE_WIDE_TNODES
bool "Turn off wide tnodes" bool "Turn off wide tnodes"

View file

@ -5,7 +5,6 @@
obj-$(CONFIG_YAFFS_FS) += yaffs.o obj-$(CONFIG_YAFFS_FS) += yaffs.o
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o yaffs-y := yaffs_ecc.o yaffs_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_tagscompat.o yaffs_tagsvalidity.o
yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o

View file

@ -14,194 +14,117 @@
*/ */
/* /*
* This file is just holds extra declarations used during development. * This file is just holds extra declarations of macros that would normally
* Most of these are from kernel includes placed here so we can use them in * be providesd in the Linux kernel. These macros have been written from
* applications. * scratch but are functionally equivalent to the Linux ones.
* *
*/ */
#ifndef __EXTRAS_H__ #ifndef __EXTRAS_H__
#define __EXTRAS_H__ #define __EXTRAS_H__
#if defined WIN32
#define __inline__ __inline
#define new newHack
#endif
#if !(defined __KERNEL__) || (defined WIN32) #if !(defined __KERNEL__)
/* User space defines */
/* Definition of types */
typedef unsigned char __u8; typedef unsigned char __u8;
typedef unsigned short __u16; typedef unsigned short __u16;
typedef unsigned __u32; typedef unsigned __u32;
#endif
/* /*
* Simple doubly linked list implementation. * This is a simple doubly linked list implementation that matches the
* * way the Linux kernel doubly linked list implementation works.
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/ */
#define prefetch(x) 1 struct ylist_head {
struct ylist_head *next; /* next in chain */
struct list_head { struct ylist_head *prev; /* previous in chain */
struct list_head *next, *prev;
}; };
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \ /* Initialise a list head to an empty list */
struct list_head name = LIST_HEAD_INIT(name) #define YINIT_LIST_HEAD(p) \
do { \
#define INIT_LIST_HEAD(ptr) do { \ (p)->next = (p);\
(ptr)->next = (ptr); (ptr)->prev = (ptr); \ (p)->prev = (p); \
} while(0) } while(0)
/*
* Insert a new entry between two known consecutive entries. /* Add an element to a list */
* static __inline__ void ylist_add(struct ylist_head *newEntry,
* This is only for internal list manipulation where we know struct ylist_head *list)
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{ {
next->prev = new; struct ylist_head *listNext = list->next;
new->next = next;
new->prev = prev; list->next = newEntry;
prev->next = new; newEntry->prev = list;
newEntry->next = listNext;
listNext->prev = newEntry;
} }
/**
* list_add - add a new entry /* Take an element out of its current list, with or without
* @new: new entry to be added * reinitialising the links.of the entry*/
* @head: list head to add it after static __inline__ void ylist_del(struct ylist_head *entry)
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{ {
__list_add(new, head, head->next); struct ylist_head *listNext = entry->next;
struct ylist_head *listPrev = entry->prev;
listNext->prev = listPrev;
listPrev->next = listNext;
} }
/** static __inline__ void ylist_del_init(struct ylist_head *entry)
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *new,
struct list_head *head)
{ {
__list_add(new, head->prev, head); ylist_del(entry);
entry->next = entry->prev = entry;
} }
/*
* Delete a list entry by making the prev/next entries /* Test if the list is empty */
* point to each other. static __inline__ int ylist_empty(struct ylist_head *entry)
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head *prev,
struct list_head *next)
{ {
next->prev = prev; return (entry->next == entry);
prev->next = next;
} }
/**
* list_del - deletes entry from list. /* ylist_entry takes a pointer to a list entry and offsets it to that
* @entry: the element to delete from the list. * we can find a pointer to the object it is embedded in.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/ */
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it. #define ylist_entry(entry, type, member) \
* @entry: the element to delete from the list. ((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);
}
/** #define ylist_for_each(itervar, list) \
* list_empty - tests whether a list is empty for (itervar = (list)->next; itervar != (list); itervar = itervar->next )
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
/** #define ylist_for_each_safe(itervar,saveVar, list) \
* list_splice - join two lists for (itervar = (list)->next, saveVar = (list)->next->next; itervar != (list); \
* @list: the new list to add. itervar = saveVar, saveVar = saveVar->next)
* @head: the place to add it in the first list.
*/
static __inline__ void list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
if (first != list) {
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head; #if !(defined __KERNEL__)
head->next = first;
last->next = at;
at->prev = last;
}
}
/** #ifndef WIN32
* list_entry - get the struct for this entry #include <sys/stat.h>
* @ptr: the &struct list_head pointer. #endif
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
pos = pos->next, prefetch(pos->next))
/** #ifdef CONFIG_YAFFS_PROVIDE_DEFS
* list_for_each_safe - iterate over a list safe against removal /* File types */
* of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/*
* File types
*/
#define DT_UNKNOWN 0 #define DT_UNKNOWN 0
#define DT_FIFO 1 #define DT_FIFO 1
#define DT_CHR 2 #define DT_CHR 2
@ -212,13 +135,13 @@ static __inline__ void list_splice(struct list_head *list,
#define DT_SOCK 12 #define DT_SOCK 12
#define DT_WHT 14 #define DT_WHT 14
#ifndef WIN32 #ifndef WIN32
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
/* /*
* Attribute flags. These should be or-ed together to figure out what * Attribute flags.
* has been changed!
*/ */
#define ATTR_MODE 1 #define ATTR_MODE 1
#define ATTR_UID 2 #define ATTR_UID 2
@ -227,10 +150,7 @@ static __inline__ void list_splice(struct list_head *list,
#define ATTR_ATIME 16 #define ATTR_ATIME 16
#define ATTR_MTIME 32 #define ATTR_MTIME 32
#define ATTR_CTIME 64 #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 { struct iattr {
unsigned int ia_valid; unsigned int ia_valid;
@ -244,21 +164,18 @@ struct iattr {
unsigned int ia_attr_flags; unsigned int ia_attr_flags;
}; };
#endif
#define KERN_DEBUG #define KERN_DEBUG
#else #else
#ifndef WIN32
#include <linux/types.h> #include <linux/types.h>
#include <linux/list.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/stat.h> #include <linux/stat.h>
#endif
#endif #endif
#if defined WIN32
#undef new
#endif
#endif #endif

View file

@ -54,11 +54,11 @@ that you need to continue to support. New data written also uses the
older-style format. older-style format.
Note: Use of this option generally requires that MTD's oob layout be 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 adjusted to use the older-style format. See notes on tags formats and
MTD versions. MTD versions in yaffs_mtdif1.c.
*/ */
/* Default: Not selected */ /* Default: Not selected */
/* Meaning: Use older-style on-NAND data format with pageStatus byte */ /* Meaning: Use older-style on-NAND data format with pageStatus byte */
#define CONFIG_YAFFS_9BYTE_TAGS //#define CONFIG_YAFFS_9BYTE_TAGS
#endif /* YAFFS_OUT_OF_TREE */ #endif /* YAFFS_OUT_OF_TREE */

View file

@ -12,11 +12,11 @@
*/ */
const char *yaffs_checkptrw_c_version = 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_checkptrw.h"
#include "yaffs_getblockinfo.h"
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
{ {
@ -142,7 +142,7 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
return 0; return 0;
if(!dev->checkpointBuffer) if(!dev->checkpointBuffer)
dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk); dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
if(!dev->checkpointBuffer) if(!dev->checkpointBuffer)
return 0; return 0;

View file

@ -29,7 +29,7 @@
*/ */
const char *yaffs_ecc_c_version = 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" #include "yportenv.h"

View file

@ -32,7 +32,7 @@
*/ */
const char *yaffs_fs_c_version = 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; extern const char *yaffs_guts_c_version;
#include <linux/version.h> #include <linux/version.h>
@ -53,6 +53,8 @@ extern const char *yaffs_guts_c_version;
#include <linux/string.h> #include <linux/string.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include "asm/div64.h"
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
#include <linux/statfs.h> /* Added NCB 15-8-2003 */ #include <linux/statfs.h> /* Added NCB 15-8-2003 */
@ -753,6 +755,8 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
break; break;
} }
inode->i_flags |= S_NOATIME;
inode->i_ino = obj->objectId; inode->i_ino = obj->objectId;
inode->i_mode = obj->yst_mode; inode->i_mode = obj->yst_mode;
inode->i_uid = obj->yst_uid; 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_type = YAFFS_MAGIC;
buf->f_bsize = sb->s_blocksize; buf->f_bsize = sb->s_blocksize;
buf->f_namelen = 255; 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 = buf->f_blocks =
(dev->endBlock - dev->startBlock + (dev->endBlock - dev->startBlock + 1) *
1) * dev->nChunksPerBlock / (sb->s_blocksize / dev->nChunksPerBlock /
dev->nDataBytesPerChunk); (sb->s_blocksize / dev->nDataBytesPerChunk);
buf->f_bfree = buf->f_bfree =
yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize / yaffs_GetNumberOfFreeChunks(dev) /
dev->nDataBytesPerChunk); (sb->s_blocksize / dev->nDataBytesPerChunk);
} else { } else {
buf->f_blocks = buf->f_blocks =
(dev->endBlock - dev->startBlock + (dev->endBlock - dev->startBlock + 1) *
1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk / dev->nChunksPerBlock *
sb->s_blocksize); (dev->nDataBytesPerChunk / sb->s_blocksize);
buf->f_bfree = buf->f_bfree =
yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk / yaffs_GetNumberOfFreeChunks(dev) *
sb->s_blocksize); (dev->nDataBytesPerChunk / sb->s_blocksize);
} }
buf->f_files = 0; buf->f_files = 0;
buf->f_ffree = 0; buf->f_ffree = 0;
buf->f_bavail = buf->f_bfree; 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_magic = YAFFS_MAGIC;
sb->s_op = &yaffs_super_ops; sb->s_op = &yaffs_super_ops;
sb->s_flags |= MS_NOATIME;
if (!sb) if (!sb)
printk(KERN_INFO "yaffs: sb is NULL\n"); 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 #ifdef CONFIG_YAFFS_AUTO_YAFFS2
if (yaffsVersion == 1 && if (yaffsVersion == 1 &&
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) WRITE_SIZE(mtd) >= 2048) {
mtd->writesize >= 2048) {
#else
mtd->oobblock >= 2048) {
#endif
T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n")); T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
yaffsVersion = 2; yaffsVersion = 2;
} }
/* Added NCB 26/5/2006 for completeness */ /* Added NCB 26/5/2006 for completeness */
if (yaffsVersion == 2 && if (yaffsVersion == 2 &&
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) !options.inband_tags &&
mtd->writesize == 512) { WRITE_SIZE(mtd) == 512){
#else
mtd->oobblock == 512) {
#endif
T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n")); T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
yaffsVersion = 1; yaffsVersion = 1;
} }
@ -1719,12 +1739,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
return NULL; return NULL;
} }
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE || mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
#else !options.inband_tags) {
if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
#endif
mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) {
T(YAFFS_TRACE_ALWAYS, T(YAFFS_TRACE_ALWAYS,
("yaffs: MTD device does not have the " ("yaffs: MTD device does not have the "
"right page sizes\n")); "right page sizes\n"));
@ -1784,9 +1801,10 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
dev->startBlock = 0; dev->startBlock = 0;
dev->endBlock = nBlocks - 1; dev->endBlock = nBlocks - 1;
dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK; dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
dev->nReservedBlocks = 5; dev->nReservedBlocks = 5;
dev->nShortOpCaches = (options.no_cache) ? 0 : 10; dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
dev->inbandTags = options.inband_tags;
/* ... and the functions. */ /* ... and the functions. */
if (yaffsVersion == 2) { if (yaffsVersion == 2) {
@ -1799,15 +1817,14 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
dev->spareBuffer = YMALLOC(mtd->oobsize); dev->spareBuffer = YMALLOC(mtd->oobsize);
dev->isYaffs2 = 1; dev->isYaffs2 = 1;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
dev->nDataBytesPerChunk = mtd->writesize; dev->totalBytesPerChunk = mtd->writesize;
dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
#else #else
dev->nDataBytesPerChunk = mtd->oobblock; dev->totalBytesPerChunk = mtd->oobblock;
dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
#endif #endif
nBlocks = mtd->size / mtd->erasesize; nBlocks = mtd->size / mtd->erasesize;
dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS;
dev->startBlock = 0; dev->startBlock = 0;
dev->endBlock = nBlocks - 1; dev->endBlock = nBlocks - 1;
} else { } 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, "startBlock......... %d\n", dev->startBlock);
buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); 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, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits); buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize); buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks); buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks); 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, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated); buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes); 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, "nPageReads......... %d\n", dev->nPageReads);
buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures); buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies); buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
buf += buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections); buf += sprintf(buf, "passiveGCs......... %d\n",
buf +=
sprintf(buf, "passiveGCs......... %d\n",
dev->passiveGarbageCollections); dev->passiveGarbageCollections);
buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites); buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches); 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); sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC); buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2); buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
return buf; return buf;
} }

View file

@ -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

View file

@ -90,7 +90,7 @@
#define YAFFS_MAX_SHORT_OP_CACHES 20 #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. /* 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. * 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 softDeletions:10; /* number of soft deleted pages */
int pagesInUse:10; /* number of pages in use */ 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 */ __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
/* and retire the block. */ /* and retire the block. */
__u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this 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 */ __u16 sum__NoLongerUsed; /* checksum of name. No longer used */
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; 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 */ __u32 yst_mode; /* protection */
#ifdef CONFIG_YAFFS_WINCE #ifdef CONFIG_YAFFS_WINCE
@ -331,11 +331,14 @@ typedef struct {
__u32 win_ctime[2]; __u32 win_ctime[2];
__u32 win_atime[2]; __u32 win_atime[2];
__u32 win_mtime[2]; __u32 win_mtime[2];
__u32 roomToGrow[4];
#else #else
__u32 roomToGrow[10]; __u32 roomToGrow[6];
#endif
#endif
__u32 inbandShadowsObject;
__u32 inbandIsShrink;
__u32 reservedSpace[2];
int shadowsObject; /* This object header shadows the specified object if > 0 */ int shadowsObject; /* This object header shadows the specified object if > 0 */
/* isShrink applies to object headers written when we shrink the file (ie resize) */ /* isShrink applies to object headers written when we shrink the file (ie resize) */
@ -381,7 +384,7 @@ typedef struct {
} yaffs_FileStructure; } yaffs_FileStructure;
typedef struct { typedef struct {
struct list_head children; /* list of child links */ struct ylist_head children; /* list of child links */
} yaffs_DirectoryStructure; } yaffs_DirectoryStructure;
typedef struct { typedef struct {
@ -424,14 +427,14 @@ struct yaffs_ObjectStruct {
struct yaffs_DeviceStruct *myDev; /* The device I'm on */ 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 */ /* directory structure stuff */
/* also used for linking up the free list */ /* also used for linking up the free list */
struct yaffs_ObjectStruct *parent; struct yaffs_ObjectStruct *parent;
struct list_head siblings; struct ylist_head siblings;
/* Where's my object header in NAND? */ /* Where's my object header in NAND? */
int chunkId; int chunkId;
@ -485,7 +488,7 @@ struct yaffs_ObjectList_struct {
typedef struct yaffs_ObjectList_struct yaffs_ObjectList; typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
typedef struct { typedef struct {
struct list_head list; struct ylist_head list;
int count; int count;
} yaffs_ObjectBucket; } yaffs_ObjectBucket;
@ -528,7 +531,7 @@ typedef struct {
/*----------------- Device ---------------------------------*/ /*----------------- Device ---------------------------------*/
struct yaffs_DeviceStruct { struct yaffs_DeviceStruct {
struct list_head devList; struct ylist_head devList;
const char *name; const char *name;
/* Entry parameters set up way early. Yaffs sets up the rest.*/ /* 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 */ /* Stuff used by the shared space checkpointing mechanism */
/* If this value is zero, then this mechanism is disabled */ /* 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); yaffs_ExtendedTags * tags);
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo); int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
int (*queryNANDBlock) (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 #endif
int isYaffs2; int isYaffs2;
@ -599,6 +602,7 @@ struct yaffs_DeviceStruct {
int wideTnodesDisabled; /* Set to disable wide tnodes */ int wideTnodesDisabled; /* Set to disable wide tnodes */
YCHAR *pathDividers; /* String of legal path dividers */
/* End of stuff that must be set before initialisation. */ /* End of stuff that must be set before initialisation. */
@ -615,16 +619,14 @@ struct yaffs_DeviceStruct {
__u32 tnodeWidth; __u32 tnodeWidth;
__u32 tnodeMask; __u32 tnodeMask;
/* Stuff to support various file offses to chunk/offset translations */ /* Stuff for figuring out file offset to chunk conversions */
/* "Crumbs" for nDataBytesPerChunk not being a power of 2 */ __u32 chunkShift; /* Shift value */
__u32 crumbMask; __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
__u32 crumbShift; __u32 chunkMask; /* Mask to use for power-of-2 case */
__u32 crumbsPerChunk;
/* Straight shifting for nDataBytesPerChunk being a power of 2 */
__u32 chunkShift;
__u32 chunkMask;
/* Stuff to handle inband tags */
int inbandTags;
__u32 totalBytesPerChunk;
#ifdef __KERNEL__ #ifdef __KERNEL__
@ -663,6 +665,8 @@ struct yaffs_DeviceStruct {
__u32 checkpointSum; __u32 checkpointSum;
__u32 checkpointXor; __u32 checkpointXor;
int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */
/* Block Info */ /* Block Info */
yaffs_BlockInfo *blockInfo; yaffs_BlockInfo *blockInfo;
__u8 *chunkBits; /* bitmap of chunks in use */ __u8 *chunkBits; /* bitmap of chunks in use */
@ -745,8 +749,10 @@ struct yaffs_DeviceStruct {
int nBackgroundDeletions; /* Count of background deletions. */ int nBackgroundDeletions; /* Count of background deletions. */
/* Temporary buffer management */
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS]; yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
int maxTemp; int maxTemp;
int tempInUse;
int unmanagedTempAllocations; int unmanagedTempAllocations;
int unmanagedTempDeallocations; int unmanagedTempDeallocations;
@ -758,7 +764,7 @@ struct yaffs_DeviceStruct {
typedef struct yaffs_DeviceStruct yaffs_Device; 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 { typedef struct {
int StructType; int StructType;
int version; int version;
@ -797,18 +803,6 @@ typedef struct {
__u32 head; __u32 head;
} yaffs_CheckpointValidity; } 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 -----------------------*/ /*----------------------- 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); int yaffs_CheckFF(__u8 * buffer, int nBytes);
void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi); 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 #endif

View file

@ -12,7 +12,7 @@
*/ */
const char *yaffs_mtdif_c_version = 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" #include "yportenv.h"
@ -24,7 +24,7 @@ const char *yaffs_mtdif_c_version =
#include "linux/time.h" #include "linux/time.h"
#include "linux/mtd/nand.h" #include "linux/mtd/nand.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) #if (MTD_VERSION_CODE < MTD_VERSION(2,6,18))
static struct nand_oobinfo yaffs_oobinfo = { static struct nand_oobinfo yaffs_oobinfo = {
.useecc = 1, .useecc = 1,
.eccbytes = 6, .eccbytes = 6,
@ -36,7 +36,7 @@ static struct nand_oobinfo yaffs_noeccinfo = {
}; };
#endif #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) static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
{ {
oob[0] = spare->tagByte0; oob[0] = spare->tagByte0;
@ -75,14 +75,14 @@ int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare) const __u8 * data, const yaffs_Spare * spare)
{ {
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 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; struct mtd_oob_ops ops;
#endif #endif
size_t dummy; size_t dummy;
int retval = 0; int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; 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 */ __u8 spareAsBytes[8]; /* OOB */
if (data && !spare) if (data && !spare)
@ -139,14 +139,14 @@ int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
yaffs_Spare * spare) yaffs_Spare * spare)
{ {
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 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; struct mtd_oob_ops ops;
#endif #endif
size_t dummy; size_t dummy;
int retval = 0; int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; 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 */ __u8 spareAsBytes[8]; /* OOB */
if (data && !spare) if (data && !spare)

View file

@ -18,6 +18,11 @@
#include "yaffs_guts.h" #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, int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare); const __u8 * data, const yaffs_Spare * spare);
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data, int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,

View file

@ -1,434 +0,0 @@
From ian@brightstareng.com Fri May 18 15:06:49 2007
From ian@brightstareng.com Fri May 18 15:08:21 2007
Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
(envelope-from <ian@brightstareng.com>)
id 1Hp380-00011e-T6
for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
Received: from localhost (localhost.localdomain [127.0.0.1])
by zebra.brightstareng.com (Postfix) with ESMTP
id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
Received: from zebra.brightstareng.com ([127.0.0.1])
by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
Received: from pippin (unknown [192.168.1.25])
by zebra.brightstareng.com (Postfix) with ESMTP
id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
From: Ian McDonnell <ian@brightstareng.com>
To: David Goodenough <david.goodenough@linkchoose.co.uk>
Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
Date: Fri, 18 May 2007 10:06:49 -0400
User-Agent: KMail/1.9.1
References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
Cc: Andrea Conti <alyf@alyf.net>,
Charles Manning <manningc2@actrix.gen.nz>
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
boundary="Boundary-00=_5LbTGmt62YoutxM"
Message-Id: <200705181006.49860.ian@brightstareng.com>
X-Virus-Scanned: by amavisd-new at brightstareng.com
Status: R
X-Status: NT
X-KMail-EncryptionState:
X-KMail-SignatureState:
X-KMail-MDN-Sent:
--Boundary-00=_5LbTGmt62YoutxM
Content-Type: text/plain;
charset="iso-8859-15"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
David, Andrea,
On Friday 18 May 2007 08:34, you wrote:
> Yea team. With this fix in place (I put it in the wrong place
> at first) I can now mount and ls the Yaffs partition without
> an error messages!
Good news!
Attached is a newer yaffs_mtdif1.c with a bandaid to help the
2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
See the LINUX_VERSION_CODE conditional in
nandmtd1_ReadChunkWithTagsFromNAND.
-imcd
--Boundary-00=_5LbTGmt62YoutxM
Content-Type: text/x-csrc;
charset="iso-8859-15";
name="yaffs_mtdif1.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="yaffs_mtdif1.c"
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
*
* Copyright (C) 2002 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This module provides the interface between yaffs_nand.c and the
* MTD API. This version is used when the MTD interface supports the
* 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
* and we have small-page NAND device.
*
* These functions are invoked via function pointers in yaffs_nand.c.
* This replaces functionality provided by functions in yaffs_mtdif.c
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
* called in yaffs_mtdif.c when the function pointers are NULL.
* We assume the MTD layer is performing ECC (useNANDECC is true).
*/
#include "yportenv.h"
#include "yaffs_guts.h"
#include "yaffs_packedtags1.h"
#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
#include "linux/kernel.h"
#include "linux/version.h"
#include "linux/types.h"
#include "linux/mtd/mtd.h"
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
const char *yaffs_mtdif1_c_version = "$Id: 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--

View file

@ -34,9 +34,9 @@
#include "linux/mtd/mtd.h" #include "linux/mtd/mtd.h"
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
#if (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 #ifndef CONFIG_YAFFS_9BYTE_TAGS
# define YTAG1_SIZE 8 # define YTAG1_SIZE 8
@ -189,7 +189,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
ops.datbuf = data; ops.datbuf = data;
ops.oobbuf = (__u8 *)&pt1; 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; /* 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. * 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 blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
int retval; 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); retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
return (retval) ? YAFFS_FAIL : YAFFS_OK; 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; struct mtd_info * mtd = dev->genericDevice;
int chunkNo = blockNo * dev->nChunksPerBlock; int chunkNo = blockNo * dev->nChunksPerBlock;
loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
yaffs_ExtendedTags etags; yaffs_ExtendedTags etags;
int state = YAFFS_BLOCK_STATE_DEAD; int state = YAFFS_BLOCK_STATE_DEAD;
int seqnum = 0; int seqnum = 0;
@ -340,11 +341,16 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
} }
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
etags.blockBad = (mtd->block_isbad)(mtd, addr);
if (etags.blockBad) { if (etags.blockBad) {
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
"block %d is marked bad", blockNo); "block %d is marked bad\n", blockNo);
state = YAFFS_BLOCK_STATE_DEAD; 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) { else if (etags.chunkUsed) {
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
seqnum = etags.sequenceNumber; seqnum = etags.sequenceNumber;
@ -360,4 +366,4 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
return YAFFS_OK; return YAFFS_OK;
} }
#endif /*KERNEL_VERSION*/ #endif /*MTD_VERSION*/

View file

@ -14,7 +14,7 @@
/* mtd interface for YAFFS2 */ /* mtd interface for YAFFS2 */
const char *yaffs_mtdif2_c_version = 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" #include "yportenv.h"
@ -27,19 +27,23 @@ const char *yaffs_mtdif2_c_version =
#include "yaffs_packedtags2.h" #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, int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const __u8 * data,
const yaffs_ExtendedTags * tags) const yaffs_ExtendedTags * tags)
{ {
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 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; struct mtd_oob_ops ops;
#else #else
size_t dummy; size_t dummy;
#endif #endif
int retval = 0; int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; loff_t addr;
yaffs_PackedTags2 pt; yaffs_PackedTags2 pt;
@ -48,46 +52,41 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags)); 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) { 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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
ops.mode = MTD_OOB_AUTO; ops.mode = MTD_OOB_AUTO;
ops.ooblen = sizeof(pt); ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
ops.len = dev->nDataBytesPerChunk; ops.len = dev->totalBytesPerChunk;
ops.ooboffs = 0; ops.ooboffs = 0;
ops.datbuf = (__u8 *)data; ops.datbuf = (__u8 *)data;
ops.oobbuf = (void *)&pt; ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
retval = mtd->write_oob(mtd, addr, &ops); retval = mtd->write_oob(mtd, addr, &ops);
} else
BUG(); /* both tags and data should always be present */
#else
if (tags) {
yaffs_PackTags2(&pt, tags);
}
if (data && tags) { #else
if (dev->useNANDECC) if (!dev->inbandTags) {
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) & pt, NULL);
else
retval = retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) & pt, NULL); &dummy, data, (__u8 *) & pt, NULL);
} else { } else {
if (data)
retval = retval =
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
data); data);
if (tags)
retval =
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
(__u8 *) & pt);
} }
#endif #endif
@ -101,11 +100,12 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags) __u8 * data, yaffs_ExtendedTags * tags)
{ {
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 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; struct mtd_oob_ops ops;
#endif #endif
size_t dummy; size_t dummy;
int retval = 0; int retval = 0;
int localData = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; 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" ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags)); 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 (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
if (data && !tags) if (dev->inbandTags || (data && !tags))
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
&dummy, data); &dummy, data);
else if (tags) { else if (tags) {
ops.mode = MTD_OOB_AUTO; ops.mode = MTD_OOB_AUTO;
@ -130,38 +141,43 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
retval = mtd->read_oob(mtd, addr, &ops); retval = mtd->read_oob(mtd, addr, &ops);
} }
#else #else
if (data && tags) { if (!dev->inbandTags && data && tags) {
if (dev->useNANDECC) {
retval = retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, dev->spareBuffer, &dummy, data, dev->spareBuffer,
NULL); NULL);
} else {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, dev->spareBuffer,
NULL);
}
} else { } else {
if (data) if (data)
retval = retval =
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data); data);
if (tags) if (!dev->inbandTags && tags)
retval = retval =
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
dev->spareBuffer); dev->spareBuffer);
} }
#endif #endif
memcpy(&pt, dev->spareBuffer, sizeof(pt));
if (tags) 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); yaffs_UnpackTags2(tags, &pt);
}
}
if(localData)
yaffs_ReleaseTempBuffer(dev,data,__LINE__);
if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
if (retval == 0) if (retval == 0)
return YAFFS_OK; return YAFFS_OK;
else else

View file

@ -12,12 +12,13 @@
*/ */
const char *yaffs_nand_c_version = 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_nand.h"
#include "yaffs_tagscompat.h" #include "yaffs_tagscompat.h"
#include "yaffs_tagsvalidity.h" #include "yaffs_tagsvalidity.h"
#include "yaffs_getblockinfo.h"
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer, __u8 * buffer,
@ -98,7 +99,7 @@ int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
int yaffs_QueryInitialBlockState(yaffs_Device * dev, int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo, int blockNo,
yaffs_BlockState * state, yaffs_BlockState * state,
unsigned *sequenceNumber) __u32 *sequenceNumber)
{ {
blockNo -= dev->blockOffset; blockNo -= dev->blockOffset;

View file

@ -22,13 +22,13 @@
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, const __u8 * data, int chunkInNAND, const __u8 * data,
yaffs_ExtendedTags * tags); const yaffs_ExtendedTags * tags);
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev, int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, __u8 * data, int chunkInNAND, __u8 * data,
yaffs_ExtendedTags * tags); yaffs_ExtendedTags * tags);
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandemul2k_QueryNANDBlock(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 nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND); int blockInNAND);
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev); int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);

View file

@ -37,60 +37,70 @@
#define EXTRA_OBJECT_TYPE_SHIFT (28) #define EXTRA_OBJECT_TYPE_SHIFT (28)
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) #define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart * ptt)
{ {
T(YAFFS_TRACE_MTD, T(YAFFS_TRACE_MTD,
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
pt->t.objectId, pt->t.chunkId, pt->t.byteCount, ptt->objectId, ptt->chunkId, ptt->byteCount,
pt->t.sequenceNumber)); ptt->sequenceNumber));
}
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
{
yaffs_DumpPackedTags2TagsPart(&pt->t);
} }
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t) static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
{ {
T(YAFFS_TRACE_MTD, T(YAFFS_TRACE_MTD,
(TSTR (TSTR
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte " ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
"%d del %d ser %d seq %d"
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId, TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
t->sequenceNumber)); 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; ptt->chunkId = t->chunkId;
pt->t.sequenceNumber = t->sequenceNumber; ptt->sequenceNumber = t->sequenceNumber;
pt->t.byteCount = t->byteCount; ptt->byteCount = t->byteCount;
pt->t.objectId = t->objectId; ptt->objectId = t->objectId;
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) { if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
/* Store the extra header info instead */ /* Store the extra header info instead */
/* We save the parent object in the chunkId */ /* We save the parent object in the chunkId */
pt->t.chunkId = EXTRA_HEADER_INFO_FLAG ptt->chunkId = EXTRA_HEADER_INFO_FLAG
| t->extraParentObjectId; | t->extraParentObjectId;
if (t->extraIsShrinkHeader) { if (t->extraIsShrinkHeader) {
pt->t.chunkId |= EXTRA_SHRINK_FLAG; ptt->chunkId |= EXTRA_SHRINK_FLAG;
} }
if (t->extraShadows) { if (t->extraShadows) {
pt->t.chunkId |= EXTRA_SHADOWS_FLAG; ptt->chunkId |= EXTRA_SHADOWS_FLAG;
} }
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK; ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
pt->t.objectId |= ptt->objectId |=
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT); (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
pt->t.byteCount = t->extraEquivalentObjectId; ptt->byteCount = t->extraEquivalentObjectId;
} else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) { } else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
pt->t.byteCount = t->extraFileLength; ptt->byteCount = t->extraFileLength;
} else { } else {
pt->t.byteCount = 0; ptt->byteCount = 0;
} }
} }
yaffs_DumpPackedTags2(pt); yaffs_DumpPackedTags2TagsPart(ptt);
yaffs_DumpTags2(t); yaffs_DumpTags2(t);
}
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
{
yaffs_PackTags2TagsPart(&pt->t,t);
#ifndef YAFFS_IGNORE_TAGS_ECC #ifndef YAFFS_IGNORE_TAGS_ECC
{ {
@ -101,13 +111,60 @@ void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
#endif #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)); memset(t, 0, sizeof(yaffs_ExtendedTags));
yaffs_InitialiseTags(t); 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) { if (pt->t.sequenceNumber != 0xFFFFFFFF) {
/* Page is in use */ /* Page is in use */
#ifdef YAFFS_IGNORE_TAGS_ECC #ifdef YAFFS_IGNORE_TAGS_ECC
@ -142,41 +199,10 @@ void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
} }
} }
#endif #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_DumpPackedTags2(pt);
yaffs_DumpTags2(t); yaffs_DumpTags2(t);
} }

View file

@ -33,6 +33,11 @@ typedef struct {
yaffs_ECCOther ecc; yaffs_ECCOther ecc;
} yaffs_PackedTags2; } yaffs_PackedTags2;
/* Full packed tags with ECC, used for oob tags */
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t); void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt); 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 #endif

View file

@ -14,6 +14,7 @@
#include "yaffs_guts.h" #include "yaffs_guts.h"
#include "yaffs_tagscompat.h" #include "yaffs_tagscompat.h"
#include "yaffs_ecc.h" #include "yaffs_ecc.h"
#include "yaffs_getblockinfo.h"
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND); static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
#ifdef NOTYET #ifdef NOTYET
@ -438,7 +439,7 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
yaffs_ECCResult eccResult; yaffs_ECCResult eccResult;
static yaffs_Spare spareFF; static yaffs_Spare spareFF;
static int init; static int init = 0;
if (!init) { if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF)); memset(&spareFF, 0xFF, sizeof(spareFF));
@ -497,9 +498,9 @@ int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
} }
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState * int blockNo,
state, yaffs_BlockState *state,
int *sequenceNumber) __u32 *sequenceNumber)
{ {
yaffs_Spare spare0, spare1; yaffs_Spare spare0, spare1;

View file

@ -30,8 +30,9 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int blockNo); int blockNo);
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState * int blockNo,
state, int *sequenceNumber); yaffs_BlockState *state,
__u32 *sequenceNumber);
void yaffs_CalcTagsECC(yaffs_Tags * tags); void yaffs_CalcTagsECC(yaffs_Tags * tags);
int yaffs_CheckECCOnTags(yaffs_Tags * tags); int yaffs_CheckECCOnTags(yaffs_Tags * tags);

View file

@ -17,6 +17,14 @@
#ifndef __YPORTENV_H__ #ifndef __YPORTENV_H__
#define __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 #if defined CONFIG_YAFFS_WINCE
#include "ywinceenv.h" #include "ywinceenv.h"
@ -26,7 +34,10 @@
#include "moduleconfig.h" #include "moduleconfig.h"
/* Linux kernel */ /* Linux kernel */
#include <linux/version.h> #include <linux/version.h>
#define MTD_VERSION_CODE LINUX_VERSION_CODE
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
#include <linux/config.h> #include <linux/config.h>
#endif #endif
@ -90,6 +101,8 @@
#elif defined CONFIG_YAFFS_DIRECT #elif defined CONFIG_YAFFS_DIRECT
#define MTD_VERSION_CODE MTD_VERSION(2,6,22)
/* Direct interface */ /* Direct interface */
#include "ydirectenv.h" #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) #define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
#ifndef CONFIG_YAFFS_WINCE #ifndef YBUG
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__)) #define YBUG() do {T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__));} while(0)
#endif #endif
#endif #endif