kernel: update yaffs code

Use the latest version of the yaffs code. Fetched from the
yaffs2 git tree and it is based on the following commit:

  commit bc76682d93955cfb33051beb503ad9f8a5450578
  Merge: 3a8580e ffa781d
  Author: Charles Manning <cdhmanning@gmail.com>
  Date:   Thu Jul 11 17:46:25 2013 +1200

      Merge branch 'master' of ssh://www.aleph1.co.uk/home/aleph1/git/yaffs2

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

SVN-Revision: 39084
This commit is contained in:
Gabor Juhos 2013-12-16 07:51:19 +00:00
parent 85755deaf6
commit 7e3644d3cf
108 changed files with 10427 additions and 16358 deletions

View File

@ -3994,6 +3994,7 @@ CONFIG_XZ_DEC=y
# CONFIG_XZ_DEC_SPARC is not set # CONFIG_XZ_DEC_SPARC is not set
# CONFIG_XZ_DEC_TEST is not set # CONFIG_XZ_DEC_TEST is not set
# CONFIG_XZ_DEC_X86 is not set # CONFIG_XZ_DEC_X86 is not set
# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
# CONFIG_YAFFS_FS is not set # CONFIG_YAFFS_FS is not set
# CONFIG_YAM is not set # CONFIG_YAM is not set
# CONFIG_YELLOWFIN is not set # CONFIG_YELLOWFIN is not set

View File

@ -4140,6 +4140,7 @@ CONFIG_XZ_DEC=y
# CONFIG_XZ_DEC_SPARC is not set # CONFIG_XZ_DEC_SPARC is not set
# CONFIG_XZ_DEC_TEST is not set # CONFIG_XZ_DEC_TEST is not set
# CONFIG_XZ_DEC_X86 is not set # CONFIG_XZ_DEC_X86 is not set
# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
# CONFIG_YAFFS_FS is not set # CONFIG_YAFFS_FS is not set
# CONFIG_YAM is not set # CONFIG_YAM is not set
# CONFIG_YELLOWFIN is not set # CONFIG_YELLOWFIN is not set

View File

@ -3862,6 +3862,7 @@ CONFIG_XZ_DEC=y
# CONFIG_XZ_DEC_SPARC is not set # CONFIG_XZ_DEC_SPARC is not set
# CONFIG_XZ_DEC_TEST is not set # CONFIG_XZ_DEC_TEST is not set
# CONFIG_XZ_DEC_X86 is not set # CONFIG_XZ_DEC_X86 is not set
# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
# CONFIG_YAFFS_FS is not set # CONFIG_YAFFS_FS is not set
# CONFIG_YAM is not set # CONFIG_YAM is not set
# CONFIG_YELLOWFIN is not set # CONFIG_YELLOWFIN is not set

View File

@ -1,23 +1,23 @@
# #
# YAFFS file system configurations # yaffs file system configurations
# #
config YAFFS_FS config YAFFS_FS
tristate "YAFFS2 file system support" tristate "yaffs2 file system support"
default n default n
depends on MTD_BLOCK depends on MTD_BLOCK
select YAFFS_YAFFS1 select YAFFS_YAFFS1
select YAFFS_YAFFS2 select YAFFS_YAFFS2
help help
YAFFS2, or Yet Another Flash Filing System, is a filing system yaffs2, or Yet Another Flash File System, is a file system
optimised for NAND Flash chips. optimised for NAND Flash chips.
To compile the YAFFS2 file system support as a module, choose M To compile the yaffs2 file system support as a module, choose M
here: the module will be called yaffs2. here: the module will be called yaffs2.
If unsure, say N. If unsure, say N.
Further information on YAFFS2 is available at Further information on yaffs2 is available at
<http://www.aleph1.co.uk/yaffs/>. <http://www.aleph1.co.uk/yaffs/>.
config YAFFS_YAFFS1 config YAFFS_YAFFS1
@ -25,7 +25,7 @@ config YAFFS_YAFFS1
depends on YAFFS_FS depends on YAFFS_FS
default y default y
help help
Enable YAFFS1 support -- yaffs for 512 byte / page devices Enable yaffs1 support -- yaffs for 512 byte / page devices
Not needed for 2K-page devices. Not needed for 2K-page devices.
@ -49,11 +49,11 @@ config YAFFS_9BYTE_TAGS
If unsure, say N. If unsure, say N.
config YAFFS_DOES_ECC config YAFFS_DOES_ECC
bool "Lets Yaffs do its own ECC" bool "Lets yaffs do its own ECC"
depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
default n default n
help help
This enables Yaffs to use its own ECC functions instead of using This enables yaffs to use its own ECC functions instead of using
the ones from the generic MTD-NAND driver. the ones from the generic MTD-NAND driver.
If unsure, say N. If unsure, say N.
@ -74,7 +74,7 @@ config YAFFS_YAFFS2
depends on YAFFS_FS depends on YAFFS_FS
default y default y
help help
Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices Enable yaffs2 support -- yaffs for >= 2K bytes per page devices
If unsure, say Y. If unsure, say Y.
@ -91,39 +91,23 @@ config YAFFS_AUTO_YAFFS2
If unsure, say Y. If unsure, say Y.
config YAFFS_DISABLE_TAGS_ECC config YAFFS_DISABLE_TAGS_ECC
bool "Disable YAFFS from doing ECC on tags by default" bool "Disable yaffs from doing ECC on tags by default"
depends on YAFFS_FS && YAFFS_YAFFS2 depends on YAFFS_FS && YAFFS_YAFFS2
default n default n
help help
This defaults Yaffs to using its own ECC calculations on tags instead of This defaults yaffs to using its own ECC calculations on tags instead of
just relying on the MTD. just relying on the MTD.
This behavior can also be overridden with tags_ecc_on and This behavior can also be overridden with tags_ecc_on and
tags_ecc_off mount options. tags_ecc_off mount options.
If unsure, say N. If unsure, say N.
config YAFFS_DISABLE_WIDE_TNODES
bool "Turn off wide tnodes"
depends on YAFFS_FS
default n
help
Wide tnodes are only used for NAND arrays >=32MB for 512-byte
page devices and >=128MB for 2k page devices. They use slightly
more RAM but are faster since they eliminate chunk group
searching.
Setting this to 'y' will force tnode width to 16 bits and save
memory but make large arrays slower.
If unsure, say N.
config YAFFS_ALWAYS_CHECK_CHUNK_ERASED config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
bool "Force chunk erase check" bool "Force chunk erase check"
depends on YAFFS_FS depends on YAFFS_FS
default n default n
help help
Normally YAFFS only checks chunks before writing until an erased Normally yaffs only checks chunks before writing until an erased
chunk is found. This helps to detect any partially written chunk is found. This helps to detect any partially written
chunks that might have happened due to power loss. chunks that might have happened due to power loss.
@ -136,17 +120,6 @@ config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
If unsure, say Y. If unsure, say Y.
config YAFFS_SHORT_NAMES_IN_RAM
bool "Cache short names in RAM"
depends on YAFFS_FS
default y
help
If this config is set, then short names are stored with the
yaffs_Object. This costs an extra 16 bytes of RAM per object,
but makes look-ups faster.
If unsure, say Y.
config YAFFS_EMPTY_LOST_AND_FOUND config YAFFS_EMPTY_LOST_AND_FOUND
bool "Empty lost and found on boot" bool "Empty lost and found on boot"
depends on YAFFS_FS depends on YAFFS_FS
@ -177,7 +150,17 @@ config YAFFS_DISABLE_BACKGROUND
If this is set, then background processing is disabled. If this is set, then background processing is disabled.
Background processing makes many foreground activities faster. Background processing makes many foreground activities faster.
If unsure, say N. If unsure, say N.
config YAFFS_DISABLE_BAD_BLOCK_MARKING
bool "Disable yaffs2 bad block marking"
depends on YAFFS_FS
default n
help
Useful during early flash bring up to prevent problems causing
lots of bad block marking.
If unsure, say N.
config YAFFS_XATTR config YAFFS_XATTR
bool "Enable yaffs2 xattr support" bool "Enable yaffs2 xattr support"
@ -186,5 +169,3 @@ config YAFFS_XATTR
help help
If this is set then yaffs2 will provide xattr support. If this is set then yaffs2 will provide xattr support.
If unsure, say Y. If unsure, say Y.

View File

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

View File

@ -1,4 +1,4 @@
The yaffs2 source has been fetched from the yaffs2 GIT tree. The yaffs2 source has been fetched from the yaffs2 GIT tree.
URL: git://www.aleph1.co.uk/yaffs2 URL: git://www.aleph1.co.uk/yaffs2
Version: 7396445d7d0d13469b9505791114b9dc6b76ffe4 (2010-10-20) Version: bc76682d93955cfb33051beb503ad9f8a5450578 (2013-12-03)

View File

@ -1,101 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* This file is just holds extra declarations of macros that would normally
* be providesd in the Linux kernel. These macros have been written from
* scratch but are functionally equivalent to the Linux ones.
*
*/
#ifndef __EXTRAS_H__
#define __EXTRAS_H__
#include "yportenv.h"
#if !(defined __KERNEL__)
/* Definition of types */
typedef unsigned char __u8;
typedef unsigned short __u16;
typedef unsigned __u32;
#endif
#if !(defined __KERNEL__)
#ifndef WIN32
#include <sys/stat.h>
#endif
#ifdef CONFIG_YAFFS_PROVIDE_DEFS
/* File types */
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
#ifndef WIN32
#include <sys/stat.h>
#endif
/*
* Attribute flags. These should be or-ed together to figure out what
* has been changed!
*/
#define ATTR_MODE 1
#define ATTR_UID 2
#define ATTR_GID 4
#define ATTR_SIZE 8
#define ATTR_ATIME 16
#define ATTR_MTIME 32
#define ATTR_CTIME 64
struct iattr {
unsigned int ia_valid;
unsigned ia_mode;
unsigned ia_uid;
unsigned ia_gid;
unsigned ia_size;
unsigned ia_atime;
unsigned ia_mtime;
unsigned ia_ctime;
unsigned int ia_attr_flags;
};
#endif
#else
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/stat.h>
#endif
#endif

View File

@ -1,86 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Martin Fouts <Martin.Fouts@palmsource.com>
*
* 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_CONFIG_H__
#define __YAFFS_CONFIG_H__
#ifdef YAFFS_OUT_OF_TREE
/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */
#define CONFIG_YAFFS_FS
#define CONFIG_YAFFS_YAFFS1
#define CONFIG_YAFFS_YAFFS2
/* These options are independent of each other. Select those that matter. */
/* Default: Not selected */
/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
/* #define CONFIG_YAFFS_DOES_ECC */
/* Default: Selected */
/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */
#define CONFIG_YAFFS_DOES_TAGS_ECC
/* Default: Not selected */
/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
/* CONFIG_YAFFS_DOES_ECC is set */
/* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
/* Default: Not selected */
/* Meaning: Always test whether chunks are erased before writing to them.
Use during mtd debugging and init. */
/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */
/* Default: Not Selected */
/* Meaning: At mount automatically empty all files from lost and found. */
/* This is done to fix an old problem where rmdir was not checking for an */
/* empty directory. This can also be achieved with a mount option. */
#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
/* Default: Selected */
/* Meaning: Cache short names, taking more RAM, but faster look-ups */
#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
/* Default: Unselected */
/* Meaning: Select to disable block refreshing. */
/* Block Refreshing periodically rewrites the oldest block. */
/* #define CONFIG_DISABLE_BLOCK_REFRESHING */
/* Default: Unselected */
/* Meaning: Select to disable background processing */
/* #define CONFIG_DISABLE_BACKGROUND */
/* Default: Selected */
/* Meaning: Enable XATTR support */
#define CONFIG_YAFFS_XATTR
/*
Older-style on-NAND data format has a "page_status" byte to record
chunk/page state. This byte is zeroed when the page is discarded.
Choose this option if you have existing on-NAND data in this format
that you need to continue to support. New data written also uses the
older-style format.
Note: Use of this option generally requires that MTD's oob layout be
adjusted to use the older-style format. See notes on tags formats and
MTD versions in yaffs_mtdif1.c.
*/
/* Default: Not selected */
/* Meaning: Use older-style on-NAND data format with page_status byte */
/* #define CONFIG_YAFFS_9BYTE_TAGS */
#endif /* YAFFS_OUT_OF_TREE */
#endif /* __YAFFS_CONFIG_H__ */

View File

@ -1,299 +1,253 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/ */
#include "yaffs_allocator.h" #include "yaffs_allocator.h"
#include "yaffs_guts.h" #include "yaffs_guts.h"
#include "yaffs_trace.h" #include "yaffs_trace.h"
#include "yportenv.h" #include "yportenv.h"
#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR /*
* Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev) * of approx 100 objects that are themn allocated singly.
{ * This is basically a simplified slab allocator.
dev = dev; *
} * We don't use the Linux slab allocator because slab does not allow
* us to dump all the objects in one hit when we do a umount and tear
void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev) * down all the tnodes and objects. slab requires that we first free
{ * the individual objects.
dev = dev; *
} * Once yaffs has been mainlined I shall try to motivate for a change
* to slab to provide the extra features we need here.
yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev) */
{
return (yaffs_tnode_t *)YMALLOC(dev->tnode_size);
}
void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
{
dev = dev;
YFREE(tn);
}
void yaffs_init_raw_objs(yaffs_dev_t *dev)
{
dev = dev;
}
void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
{
dev = dev;
}
yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
{
dev = dev;
return (yaffs_obj_t *) YMALLOC(sizeof(yaffs_obj_t));
}
void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
{
dev = dev;
YFREE(obj);
}
#else
struct yaffs_tnode_list { struct yaffs_tnode_list {
struct yaffs_tnode_list *next; struct yaffs_tnode_list *next;
yaffs_tnode_t *tnodes; struct yaffs_tnode *tnodes;
}; };
typedef struct yaffs_tnode_list yaffs_tnodelist_t; struct yaffs_obj_list {
struct yaffs_obj_list *next;
struct yaffs_obj_tList_struct { struct yaffs_obj *objects;
yaffs_obj_t *objects;
struct yaffs_obj_tList_struct *next;
}; };
typedef struct yaffs_obj_tList_struct yaffs_obj_tList; struct yaffs_allocator {
int n_tnodes_created;
struct yaffs_tnode *free_tnodes;
int n_free_tnodes;
struct yaffs_tnode_list *alloc_tnode_list;
int n_obj_created;
struct list_head free_objs;
int n_free_objects;
struct yaffs_AllocatorStruct { struct yaffs_obj_list *allocated_obj_list;
int n_tnodesCreated;
yaffs_tnode_t *freeTnodes;
int nFreeTnodes;
yaffs_tnodelist_t *allocatedTnodeList;
int n_objCreated;
yaffs_obj_t *freeObjects;
int nFreeObjects;
yaffs_obj_tList *allocatedObjectList;
}; };
typedef struct yaffs_AllocatorStruct yaffs_Allocator; static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
static void yaffs_deinit_raw_tnodes(yaffs_dev_t *dev)
{ {
struct yaffs_allocator *allocator =
(struct yaffs_allocator *)dev->allocator;
struct yaffs_tnode_list *tmp;
yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; if (!allocator) {
BUG();
yaffs_tnodelist_t *tmp;
if(!allocator){
YBUG();
return; return;
} }
while (allocator->allocatedTnodeList) { while (allocator->alloc_tnode_list) {
tmp = allocator->allocatedTnodeList->next; tmp = allocator->alloc_tnode_list->next;
YFREE(allocator->allocatedTnodeList->tnodes);
YFREE(allocator->allocatedTnodeList);
allocator->allocatedTnodeList = tmp;
kfree(allocator->alloc_tnode_list->tnodes);
kfree(allocator->alloc_tnode_list);
allocator->alloc_tnode_list = tmp;
} }
allocator->freeTnodes = NULL; allocator->free_tnodes = NULL;
allocator->nFreeTnodes = 0; allocator->n_free_tnodes = 0;
allocator->n_tnodesCreated = 0; allocator->n_tnodes_created = 0;
} }
static void yaffs_init_raw_tnodes(yaffs_dev_t *dev) static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
{ {
yaffs_Allocator *allocator = dev->allocator; struct yaffs_allocator *allocator = dev->allocator;
if(allocator){ if (!allocator) {
allocator->allocatedTnodeList = NULL; BUG();
allocator->freeTnodes = NULL; return;
allocator->nFreeTnodes = 0; }
allocator->n_tnodesCreated = 0;
} else allocator->alloc_tnode_list = NULL;
YBUG(); allocator->free_tnodes = NULL;
allocator->n_free_tnodes = 0;
allocator->n_tnodes_created = 0;
} }
static int yaffs_create_tnodes(yaffs_dev_t *dev, int n_tnodes) static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
{ {
yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; struct yaffs_allocator *allocator =
(struct yaffs_allocator *)dev->allocator;
int i; int i;
yaffs_tnode_t *newTnodes; struct yaffs_tnode *new_tnodes;
__u8 *mem; u8 *mem;
yaffs_tnode_t *curr; struct yaffs_tnode *curr;
yaffs_tnode_t *next; struct yaffs_tnode *next;
yaffs_tnodelist_t *tnl; struct yaffs_tnode_list *tnl;
if(!allocator){ if (!allocator) {
YBUG(); BUG();
return YAFFS_FAIL; return YAFFS_FAIL;
} }
if (n_tnodes < 1) if (n_tnodes < 1)
return YAFFS_OK; return YAFFS_OK;
/* make these things */ /* make these things */
new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
mem = (u8 *) new_tnodes;
newTnodes = YMALLOC(n_tnodes * dev->tnode_size); if (!new_tnodes) {
mem = (__u8 *)newTnodes; yaffs_trace(YAFFS_TRACE_ERROR,
"yaffs: Could not allocate Tnodes");
if (!newTnodes) {
T(YAFFS_TRACE_ERROR,
(TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
return YAFFS_FAIL; return YAFFS_FAIL;
} }
/* New hookup for wide tnodes */ /* New hookup for wide tnodes */
for (i = 0; i < n_tnodes - 1; i++) { for (i = 0; i < n_tnodes - 1; i++) {
curr = (yaffs_tnode_t *) &mem[i * dev->tnode_size]; curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
next = (yaffs_tnode_t *) &mem[(i+1) * dev->tnode_size]; next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
curr->internal[0] = next; curr->internal[0] = next;
} }
curr = (yaffs_tnode_t *) &mem[(n_tnodes - 1) * dev->tnode_size]; curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
curr->internal[0] = allocator->freeTnodes; curr->internal[0] = allocator->free_tnodes;
allocator->freeTnodes = (yaffs_tnode_t *)mem; allocator->free_tnodes = (struct yaffs_tnode *)mem;
allocator->nFreeTnodes += n_tnodes; allocator->n_free_tnodes += n_tnodes;
allocator->n_tnodesCreated += n_tnodes; allocator->n_tnodes_created += n_tnodes;
/* Now add this bunch of tnodes to a list for freeing up. /* Now add this bunch of tnodes to a list for freeing up.
* NB If we can't add this to the management list it isn't fatal * NB If we can't add this to the management list it isn't fatal
* but it just means we can't free this bunch of tnodes later. * but it just means we can't free this bunch of tnodes later.
*/ */
tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
tnl = YMALLOC(sizeof(yaffs_tnodelist_t));
if (!tnl) { if (!tnl) {
T(YAFFS_TRACE_ERROR, yaffs_trace(YAFFS_TRACE_ERROR,
(TSTR "Could not add tnodes to management list");
("yaffs: Could not add tnodes to management list" TENDSTR))); return YAFFS_FAIL;
return YAFFS_FAIL;
} else { } else {
tnl->tnodes = newTnodes; tnl->tnodes = new_tnodes;
tnl->next = allocator->allocatedTnodeList; tnl->next = allocator->alloc_tnode_list;
allocator->allocatedTnodeList = tnl; allocator->alloc_tnode_list = tnl;
} }
T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR))); yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
return YAFFS_OK; return YAFFS_OK;
} }
struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
{ {
yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; struct yaffs_allocator *allocator =
yaffs_tnode_t *tn = NULL; (struct yaffs_allocator *)dev->allocator;
struct yaffs_tnode *tn = NULL;
if(!allocator){ if (!allocator) {
YBUG(); BUG();
return NULL; return NULL;
} }
/* If there are none left make more */ /* If there are none left make more */
if (!allocator->freeTnodes) if (!allocator->free_tnodes)
yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES); yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
if (allocator->freeTnodes) { if (allocator->free_tnodes) {
tn = allocator->freeTnodes; tn = allocator->free_tnodes;
allocator->freeTnodes = allocator->freeTnodes->internal[0]; allocator->free_tnodes = allocator->free_tnodes->internal[0];
allocator->nFreeTnodes--; allocator->n_free_tnodes--;
} }
return tn; return tn;
} }
/* FreeTnode frees up a tnode and puts it back on the free list */ /* FreeTnode frees up a tnode and puts it back on the free list */
void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn) void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
{ {
yaffs_Allocator *allocator = dev->allocator; struct yaffs_allocator *allocator = dev->allocator;
if(!allocator){ if (!allocator) {
YBUG(); BUG();
return; return;
} }
if (tn) { if (tn) {
tn->internal[0] = allocator->freeTnodes; tn->internal[0] = allocator->free_tnodes;
allocator->freeTnodes = tn; allocator->free_tnodes = tn;
allocator->nFreeTnodes++; allocator->n_free_tnodes++;
} }
dev->checkpoint_blocks_required = 0; /* force recalculation*/ dev->checkpoint_blocks_required = 0; /* force recalculation */
} }
/*--------------- yaffs_obj alloaction ------------------------
*
* Free yaffs_objs are stored in a list using obj->siblings.
* The blocks of allocated objects are stored in a linked list.
*/
static void yaffs_init_raw_objs(struct yaffs_dev *dev)
static void yaffs_init_raw_objs(yaffs_dev_t *dev)
{ {
yaffs_Allocator *allocator = dev->allocator; struct yaffs_allocator *allocator = dev->allocator;
if(allocator) { if (!allocator) {
allocator->allocatedObjectList = NULL; BUG();
allocator->freeObjects = NULL;
allocator->nFreeObjects = 0;
} else
YBUG();
}
static void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator = dev->allocator;
yaffs_obj_tList *tmp;
if(!allocator){
YBUG();
return; return;
} }
while (allocator->allocatedObjectList) { allocator->allocated_obj_list = NULL;
tmp = allocator->allocatedObjectList->next; INIT_LIST_HEAD(&allocator->free_objs);
YFREE(allocator->allocatedObjectList->objects); allocator->n_free_objects = 0;
YFREE(allocator->allocatedObjectList);
allocator->allocatedObjectList = tmp;
}
allocator->freeObjects = NULL;
allocator->nFreeObjects = 0;
allocator->n_objCreated = 0;
} }
static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
static int yaffs_create_free_objs(yaffs_dev_t *dev, int n_obj)
{ {
yaffs_Allocator *allocator = dev->allocator; struct yaffs_allocator *allocator = dev->allocator;
struct yaffs_obj_list *tmp;
if (!allocator) {
BUG();
return;
}
while (allocator->allocated_obj_list) {
tmp = allocator->allocated_obj_list->next;
kfree(allocator->allocated_obj_list->objects);
kfree(allocator->allocated_obj_list);
allocator->allocated_obj_list = tmp;
}
INIT_LIST_HEAD(&allocator->free_objs);
allocator->n_free_objects = 0;
allocator->n_obj_created = 0;
}
static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
{
struct yaffs_allocator *allocator = dev->allocator;
int i; int i;
yaffs_obj_t *newObjects; struct yaffs_obj *new_objs;
yaffs_obj_tList *list; struct yaffs_obj_list *list;
if(!allocator){ if (!allocator) {
YBUG(); BUG();
return YAFFS_FAIL; return YAFFS_FAIL;
} }
@ -301,109 +255,103 @@ static int yaffs_create_free_objs(yaffs_dev_t *dev, int n_obj)
return YAFFS_OK; return YAFFS_OK;
/* make these things */ /* make these things */
newObjects = YMALLOC(n_obj * sizeof(yaffs_obj_t)); new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
list = YMALLOC(sizeof(yaffs_obj_tList)); list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
if (!newObjects || !list) { if (!new_objs || !list) {
if (newObjects){ kfree(new_objs);
YFREE(newObjects); new_objs = NULL;
newObjects = NULL; kfree(list);
} list = NULL;
if (list){ yaffs_trace(YAFFS_TRACE_ALLOCATE,
YFREE(list); "Could not allocate more objects");
list = NULL;
}
T(YAFFS_TRACE_ALLOCATE,
(TSTR("yaffs: Could not allocate more objects" TENDSTR)));
return YAFFS_FAIL; return YAFFS_FAIL;
} }
/* Hook them into the free list */ /* Hook them into the free list */
for (i = 0; i < n_obj - 1; i++) { for (i = 0; i < n_obj; i++)
newObjects[i].siblings.next = list_add(&new_objs[i].siblings, &allocator->free_objs);
(struct ylist_head *)(&newObjects[i + 1]);
}
newObjects[n_obj - 1].siblings.next = (void *)allocator->freeObjects; allocator->n_free_objects += n_obj;
allocator->freeObjects = newObjects; allocator->n_obj_created += n_obj;
allocator->nFreeObjects += n_obj;
allocator->n_objCreated += n_obj;
/* Now add this bunch of Objects to a list for freeing up. */ /* Now add this bunch of Objects to a list for freeing up. */
list->objects = newObjects; list->objects = new_objs;
list->next = allocator->allocatedObjectList; list->next = allocator->allocated_obj_list;
allocator->allocatedObjectList = list; allocator->allocated_obj_list = list;
return YAFFS_OK; return YAFFS_OK;
} }
yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev) struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
{ {
yaffs_obj_t *obj = NULL; struct yaffs_obj *obj = NULL;
yaffs_Allocator *allocator = dev->allocator; struct list_head *lh;
struct yaffs_allocator *allocator = dev->allocator;
if(!allocator) { if (!allocator) {
YBUG(); BUG();
return obj; return obj;
} }
/* If there are none left make more */ /* If there are none left make more */
if (!allocator->freeObjects) if (list_empty(&allocator->free_objs))
yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS); yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
if (allocator->freeObjects) { if (!list_empty(&allocator->free_objs)) {
obj = allocator->freeObjects; lh = allocator->free_objs.next;
allocator->freeObjects = obj = list_entry(lh, struct yaffs_obj, siblings);
(yaffs_obj_t *) (allocator->freeObjects->siblings.next); list_del_init(lh);
allocator->nFreeObjects--; allocator->n_free_objects--;
} }
return obj; return obj;
} }
void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
{ {
yaffs_Allocator *allocator = dev->allocator; struct yaffs_allocator *allocator = dev->allocator;
if(!allocator) if (!allocator) {
YBUG(); BUG();
else { return;
/* Link into the free list. */ }
obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
allocator->freeObjects = obj; /* Link into the free list. */
allocator->nFreeObjects++; list_add(&obj->siblings, &allocator->free_objs);
allocator->n_free_objects++;
}
void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
{
if (!dev->allocator) {
BUG();
return;
}
yaffs_deinit_raw_tnodes(dev);
yaffs_deinit_raw_objs(dev);
kfree(dev->allocator);
dev->allocator = NULL;
}
void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator;
if (dev->allocator) {
BUG();
return;
}
allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
if (allocator) {
dev->allocator = allocator;
yaffs_init_raw_tnodes(dev);
yaffs_init_raw_objs(dev);
} }
} }
void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
{
if(dev->allocator){
yaffs_deinit_raw_tnodes(dev);
yaffs_deinit_raw_objs(dev);
YFREE(dev->allocator);
dev->allocator=NULL;
} else
YBUG();
}
void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator;
if(!dev->allocator){
allocator = YMALLOC(sizeof(yaffs_Allocator));
if(allocator){
dev->allocator = allocator;
yaffs_init_raw_tnodes(dev);
yaffs_init_raw_objs(dev);
}
} else
YBUG();
}
#endif

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -18,13 +18,13 @@
#include "yaffs_guts.h" #include "yaffs_guts.h"
void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev); void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev); void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev); struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn); void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev); struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj); void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
#endif #endif

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -17,89 +17,81 @@
* Chunk bitmap manipulations * Chunk bitmap manipulations
*/ */
static Y_INLINE __u8 *yaffs_BlockBits(yaffs_dev_t *dev, int blk) static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
{ {
if (blk < dev->internal_start_block || blk > dev->internal_end_block) { if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
T(YAFFS_TRACE_ERROR, yaffs_trace(YAFFS_TRACE_ERROR,
(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR), "BlockBits block %d is not valid",
blk)); blk);
YBUG(); BUG();
} }
return dev->chunk_bits + return dev->chunk_bits +
(dev->chunk_bit_stride * (blk - dev->internal_start_block)); (dev->chunk_bit_stride * (blk - dev->internal_start_block));
} }
void yaffs_verify_chunk_bit_id(yaffs_dev_t *dev, int blk, int chunk) void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
{ {
if (blk < dev->internal_start_block || blk > dev->internal_end_block || if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
chunk < 0 || chunk >= dev->param.chunks_per_block) { chunk < 0 || chunk >= dev->param.chunks_per_block) {
T(YAFFS_TRACE_ERROR, yaffs_trace(YAFFS_TRACE_ERROR,
(TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR), "Chunk Id (%d:%d) invalid",
blk, chunk)); blk, chunk);
YBUG(); BUG();
} }
} }
void yaffs_clear_chunk_bits(yaffs_dev_t *dev, int blk) void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
{ {
__u8 *blkBits = yaffs_BlockBits(dev, blk); u8 *blk_bits = yaffs_block_bits(dev, blk);
memset(blkBits, 0, dev->chunk_bit_stride); memset(blk_bits, 0, dev->chunk_bit_stride);
} }
void yaffs_clear_chunk_bit(yaffs_dev_t *dev, int blk, int chunk) void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{ {
__u8 *blkBits = yaffs_BlockBits(dev, blk); u8 *blk_bits = yaffs_block_bits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk); yaffs_verify_chunk_bit_id(dev, blk, chunk);
blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
blkBits[chunk / 8] &= ~(1 << (chunk & 7));
} }
void yaffs_set_chunk_bit(yaffs_dev_t *dev, int blk, int chunk) void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{ {
__u8 *blkBits = yaffs_BlockBits(dev, blk); u8 *blk_bits = yaffs_block_bits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk); yaffs_verify_chunk_bit_id(dev, blk, chunk);
blk_bits[chunk / 8] |= (1 << (chunk & 7));
blkBits[chunk / 8] |= (1 << (chunk & 7));
} }
int yaffs_check_chunk_bit(yaffs_dev_t *dev, int blk, int chunk) int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{ {
__u8 *blkBits = yaffs_BlockBits(dev, blk); u8 *blk_bits = yaffs_block_bits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk); yaffs_verify_chunk_bit_id(dev, blk, chunk);
return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
} }
int yaffs_still_some_chunks(yaffs_dev_t *dev, int blk) int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
{ {
__u8 *blkBits = yaffs_BlockBits(dev, blk); u8 *blk_bits = yaffs_block_bits(dev, blk);
int i; int i;
for (i = 0; i < dev->chunk_bit_stride; i++) { for (i = 0; i < dev->chunk_bit_stride; i++) {
if (*blkBits) if (*blk_bits)
return 1; return 1;
blkBits++; blk_bits++;
} }
return 0; return 0;
} }
int yaffs_count_chunk_bits(yaffs_dev_t *dev, int blk) int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
{ {
__u8 *blkBits = yaffs_BlockBits(dev, blk); u8 *blk_bits = yaffs_block_bits(dev, blk);
int i; int i;
int n = 0; int n = 0;
for (i = 0; i < dev->chunk_bit_stride; i++) {
__u8 x = *blkBits;
while (x) {
if (x & 1)
n++;
x >>= 1;
}
blkBits++; for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
} n += hweight8(*blk_bits);
return n; return n;
} }

View File

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

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -14,40 +14,91 @@
#include "yaffs_checkptrw.h" #include "yaffs_checkptrw.h"
#include "yaffs_getblockinfo.h" #include "yaffs_getblockinfo.h"
static int yaffs2_checkpt_space_ok(yaffs_dev_t *dev) struct yaffs_checkpt_chunk_hdr {
int version;
int seq;
u32 sum;
u32 xor;
} ;
static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
{ {
int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks; return chunk - dev->chunk_offset;
T(YAFFS_TRACE_CHECKPOINT,
(TSTR("checkpt blocks available = %d" TENDSTR),
blocksAvailable));
return (blocksAvailable <= 0) ? 0 : 1;
} }
static int apply_block_offset(struct yaffs_dev *dev, int block)
{
return block - dev->block_offset;
}
static int yaffs_checkpt_erase(yaffs_dev_t *dev) static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
{
struct yaffs_checkpt_chunk_hdr hdr;
hdr.version = YAFFS_CHECKPOINT_VERSION;
hdr.seq = dev->checkpt_page_seq;
hdr.sum = dev->checkpt_sum;
hdr.xor = dev->checkpt_xor;
dev->checkpt_byte_offs = sizeof(hdr);
memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
}
static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)
{
struct yaffs_checkpt_chunk_hdr hdr;
memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
dev->checkpt_byte_offs = sizeof(hdr);
return hdr.version == YAFFS_CHECKPOINT_VERSION &&
hdr.seq == dev->checkpt_page_seq &&
hdr.sum == dev->checkpt_sum &&
hdr.xor == dev->checkpt_xor;
}
static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
{
int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"checkpt blocks_avail = %d", blocks_avail);
return (blocks_avail <= 0) ? 0 : 1;
}
static int yaffs_checkpt_erase(struct yaffs_dev *dev)
{ {
int i; int i;
if (!dev->param.erase_fn) if (!dev->drv.drv_erase_fn)
return 0; return 0;
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR), yaffs_trace(YAFFS_TRACE_CHECKPOINT,
dev->internal_start_block, dev->internal_end_block)); "checking blocks %d to %d",
dev->internal_start_block, dev->internal_end_block);
for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
yaffs_block_info_t *bi = yaffs_get_block_info(dev, i); struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
int offset_i = apply_block_offset(dev, i);
int result;
if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i)); yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"erasing checkpt block %d", i);
dev->n_erasures++; dev->n_erasures++;
if (dev->param.erase_fn(dev, i - dev->block_offset /* realign */)) { result = dev->drv.drv_erase_fn(dev, offset_i);
if(result) {
bi->block_state = YAFFS_BLOCK_STATE_EMPTY; bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
dev->n_erased_blocks++; dev->n_erased_blocks++;
dev->n_free_chunks += dev->param.chunks_per_block; dev->n_free_chunks +=
dev->param.chunks_per_block;
} else { } else {
dev->param.bad_block_fn(dev, i); dev->drv.drv_mark_bad_fn(dev, offset_i);
bi->block_state = YAFFS_BLOCK_STATE_DEAD; bi->block_state = YAFFS_BLOCK_STATE_DEAD;
} }
} }
@ -58,93 +109,112 @@ static int yaffs_checkpt_erase(yaffs_dev_t *dev)
return 1; return 1;
} }
static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
static void yaffs2_checkpt_find_erased_block(yaffs_dev_t *dev)
{ {
int i; int i;
int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks; int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
T(YAFFS_TRACE_CHECKPOINT,
(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), yaffs_trace(YAFFS_TRACE_CHECKPOINT,
dev->n_erased_blocks, dev->param.n_reserved_blocks, blocksAvailable, dev->checkpt_next_block)); "allocating checkpt block: erased %d reserved %d avail %d next %d ",
dev->n_erased_blocks, dev->param.n_reserved_blocks,
blocks_avail, dev->checkpt_next_block);
if (dev->checkpt_next_block >= 0 && if (dev->checkpt_next_block >= 0 &&
dev->checkpt_next_block <= dev->internal_end_block && dev->checkpt_next_block <= dev->internal_end_block &&
blocksAvailable > 0) { blocks_avail > 0) {
for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) { for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
yaffs_block_info_t *bi = yaffs_get_block_info(dev, i); i++) {
struct yaffs_block_info *bi;
bi = yaffs_get_block_info(dev, i);
if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
dev->checkpt_next_block = i + 1; dev->checkpt_next_block = i + 1;
dev->checkpt_cur_block = i; dev->checkpt_cur_block = i;
T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i)); yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"allocating checkpt block %d", i);
return; return;
} }
} }
} }
T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR))); yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
dev->checkpt_next_block = -1; dev->checkpt_next_block = -1;
dev->checkpt_cur_block = -1; dev->checkpt_cur_block = -1;
} }
static void yaffs2_checkpt_find_block(yaffs_dev_t *dev) static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
{ {
int i; int i;
yaffs_ext_tags tags; struct yaffs_ext_tags tags;
T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR), yaffs_trace(YAFFS_TRACE_CHECKPOINT,
dev->blocks_in_checkpt, dev->checkpt_next_block)); "find next checkpt block: start: blocks %d next %d",
dev->blocks_in_checkpt, dev->checkpt_next_block);
if (dev->blocks_in_checkpt < dev->checkpt_max_blocks) if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) { for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
i++) {
int chunk = i * dev->param.chunks_per_block; int chunk = i * dev->param.chunks_per_block;
int realignedChunk = chunk - dev->chunk_offset; enum yaffs_block_state state;
u32 seq;
dev->param.read_chunk_tags_fn(dev, realignedChunk, dev->tagger.read_chunk_tags_fn(dev,
apply_chunk_offset(dev, chunk),
NULL, &tags); NULL, &tags);
T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR), yaffs_trace(YAFFS_TRACE_CHECKPOINT,
i, tags.obj_id, tags.seq_number, tags.ecc_result)); "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d",
i, (int) state,
tags.obj_id, tags.seq_number,
tags.ecc_result);
if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) { if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
/* Right kind of block */ continue;
dev->checkpt_next_block = tags.obj_id;
dev->checkpt_cur_block = i; dev->tagger.query_block_fn(dev,
dev->checkpt_block_list[dev->blocks_in_checkpt] = i; apply_block_offset(dev, i),
dev->blocks_in_checkpt++; &state, &seq);
T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i)); if (state == YAFFS_BLOCK_STATE_DEAD)
return; continue;
}
/* Right kind of block */
dev->checkpt_next_block = tags.obj_id;
dev->checkpt_cur_block = i;
dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
dev->blocks_in_checkpt++;
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"found checkpt block %d", i);
return;
} }
T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR))); yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
dev->checkpt_next_block = -1; dev->checkpt_next_block = -1;
dev->checkpt_cur_block = -1; dev->checkpt_cur_block = -1;
} }
int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
int yaffs2_checkpt_open(yaffs_dev_t *dev, int forWriting)
{ {
int i;
dev->checkpt_open_write = writing;
dev->checkpt_open_write = forWriting;
/* Got the functions we need? */ /* Got the functions we need? */
if (!dev->param.write_chunk_tags_fn || if (!dev->tagger.write_chunk_tags_fn ||
!dev->param.read_chunk_tags_fn || !dev->tagger.read_chunk_tags_fn ||
!dev->param.erase_fn || !dev->drv.drv_erase_fn ||
!dev->param.bad_block_fn) !dev->drv.drv_mark_bad_fn)
return 0; return 0;
if (forWriting && !yaffs2_checkpt_space_ok(dev)) if (writing && !yaffs2_checkpt_space_ok(dev))
return 0; return 0;
if (!dev->checkpt_buffer) if (!dev->checkpt_buffer)
dev->checkpt_buffer = YMALLOC_DMA(dev->param.total_bytes_per_chunk); dev->checkpt_buffer =
kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
if (!dev->checkpt_buffer) if (!dev->checkpt_buffer)
return 0; return 0;
dev->checkpt_page_seq = 0; dev->checkpt_page_seq = 0;
dev->checkpt_byte_count = 0; dev->checkpt_byte_count = 0;
dev->checkpt_sum = 0; dev->checkpt_sum = 0;
@ -153,44 +223,46 @@ int yaffs2_checkpt_open(yaffs_dev_t *dev, int forWriting)
dev->checkpt_cur_chunk = -1; dev->checkpt_cur_chunk = -1;
dev->checkpt_next_block = dev->internal_start_block; dev->checkpt_next_block = dev->internal_start_block;
/* Erase all the blocks in the checkpoint area */ if (writing) {
if (forWriting) {
memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
dev->checkpt_byte_offs = 0; yaffs2_checkpt_init_chunk_hdr(dev);
return yaffs_checkpt_erase(dev); return yaffs_checkpt_erase(dev);
} else {
int i;
/* Set to a value that will kick off a read */
dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
* going to be way more than we need */
dev->blocks_in_checkpt = 0;
dev->checkpt_max_blocks = (dev->internal_end_block - dev->internal_start_block)/16 + 2;
dev->checkpt_block_list = YMALLOC(sizeof(int) * dev->checkpt_max_blocks);
if(!dev->checkpt_block_list)
return 0;
for (i = 0; i < dev->checkpt_max_blocks; i++)
dev->checkpt_block_list[i] = -1;
} }
/* Opening for a read */
/* Set to a value that will kick off a read */
dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
/* A checkpoint block list of 1 checkpoint block per 16 block is
* (hopefully) going to be way more than we need */
dev->blocks_in_checkpt = 0;
dev->checkpt_max_blocks =
(dev->internal_end_block - dev->internal_start_block) / 16 + 2;
dev->checkpt_block_list =
kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
if (!dev->checkpt_block_list)
return 0;
for (i = 0; i < dev->checkpt_max_blocks; i++)
dev->checkpt_block_list[i] = -1;
return 1; return 1;
} }
int yaffs2_get_checkpt_sum(yaffs_dev_t *dev, __u32 *sum) int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
{ {
__u32 compositeSum; u32 composite_sum;
compositeSum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xFF);
*sum = compositeSum; composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
*sum = composite_sum;
return 1; return 1;
} }
static int yaffs2_checkpt_flush_buffer(yaffs_dev_t *dev) static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
{ {
int chunk; int chunk;
int realignedChunk; int offset_chunk;
struct yaffs_ext_tags tags;
yaffs_ext_tags tags;
if (dev->checkpt_cur_block < 0) { if (dev->checkpt_cur_block < 0) {
yaffs2_checkpt_find_erased_block(dev); yaffs2_checkpt_find_erased_block(dev);
@ -201,31 +273,34 @@ static int yaffs2_checkpt_flush_buffer(yaffs_dev_t *dev)
return 0; return 0;
tags.is_deleted = 0; tags.is_deleted = 0;
tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */ tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
tags.chunk_id = dev->checkpt_page_seq + 1; tags.chunk_id = dev->checkpt_page_seq + 1;
tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA; tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
tags.n_bytes = dev->data_bytes_per_chunk; tags.n_bytes = dev->data_bytes_per_chunk;
if (dev->checkpt_cur_chunk == 0) { if (dev->checkpt_cur_chunk == 0) {
/* First chunk we write for the block? Set block state to /* First chunk we write for the block? Set block state to
checkpoint */ checkpoint */
yaffs_block_info_t *bi = yaffs_get_block_info(dev, dev->checkpt_cur_block); struct yaffs_block_info *bi =
yaffs_get_block_info(dev, dev->checkpt_cur_block);
bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
dev->blocks_in_checkpt++; dev->blocks_in_checkpt++;
} }
chunk = dev->checkpt_cur_block * dev->param.chunks_per_block + dev->checkpt_cur_chunk; chunk =
dev->checkpt_cur_block * dev->param.chunks_per_block +
dev->checkpt_cur_chunk;
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
tags.obj_id, tags.chunk_id);
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), offset_chunk = apply_chunk_offset(dev, chunk);
chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, tags.obj_id, tags.chunk_id));
realignedChunk = chunk - dev->chunk_offset;
dev->n_page_writes++; dev->n_page_writes++;
dev->param.write_chunk_tags_fn(dev, realignedChunk, dev->tagger.write_chunk_tags_fn(dev, offset_chunk,
dev->checkpt_buffer, &tags); dev->checkpt_buffer, &tags);
dev->checkpt_byte_offs = 0;
dev->checkpt_page_seq++; dev->checkpt_page_seq++;
dev->checkpt_cur_chunk++; dev->checkpt_cur_chunk++;
if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) { if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
@ -234,19 +309,17 @@ static int yaffs2_checkpt_flush_buffer(yaffs_dev_t *dev)
} }
memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
yaffs2_checkpt_init_chunk_hdr(dev);
return 1; return 1;
} }
int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
int yaffs2_checkpt_wr(yaffs_dev_t *dev, const void *data, int n_bytes)
{ {
int i = 0; int i = 0;
int ok = 1; int ok = 1;
u8 *data_bytes = (u8 *) data;
__u8 * dataBytes = (__u8 *)data;
if (!dev->checkpt_buffer) if (!dev->checkpt_buffer)
return 0; return 0;
@ -255,35 +328,31 @@ int yaffs2_checkpt_wr(yaffs_dev_t *dev, const void *data, int n_bytes)
return -1; return -1;
while (i < n_bytes && ok) { while (i < n_bytes && ok) {
dev->checkpt_buffer[dev->checkpt_byte_offs] = *dataBytes; dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
dev->checkpt_sum += *dataBytes; dev->checkpt_sum += *data_bytes;
dev->checkpt_xor ^= *dataBytes; dev->checkpt_xor ^= *data_bytes;
dev->checkpt_byte_offs++; dev->checkpt_byte_offs++;
i++; i++;
dataBytes++; data_bytes++;
dev->checkpt_byte_count++; dev->checkpt_byte_count++;
if (dev->checkpt_byte_offs < 0 || if (dev->checkpt_byte_offs < 0 ||
dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
ok = yaffs2_checkpt_flush_buffer(dev); ok = yaffs2_checkpt_flush_buffer(dev);
} }
return i; return i;
} }
int yaffs2_checkpt_rd(yaffs_dev_t *dev, void *data, int n_bytes) int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
{ {
int i = 0; int i = 0;
int ok = 1; int ok = 1;
yaffs_ext_tags tags; struct yaffs_ext_tags tags;
int chunk; int chunk;
int realignedChunk; int offset_chunk;
u8 *data_bytes = (u8 *) data;
__u8 *dataBytes = (__u8 *)data;
if (!dev->checkpt_buffer) if (!dev->checkpt_buffer)
return 0; return 0;
@ -293,109 +362,113 @@ int yaffs2_checkpt_rd(yaffs_dev_t *dev, void *data, int n_bytes)
while (i < n_bytes && ok) { while (i < n_bytes && ok) {
if (dev->checkpt_byte_offs < 0 || if (dev->checkpt_byte_offs < 0 ||
dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) { dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
if (dev->checkpt_cur_block < 0) { if (dev->checkpt_cur_block < 0) {
yaffs2_checkpt_find_block(dev); yaffs2_checkpt_find_block(dev);
dev->checkpt_cur_chunk = 0; dev->checkpt_cur_chunk = 0;
} }
if (dev->checkpt_cur_block < 0) if (dev->checkpt_cur_block < 0) {
ok = 0; ok = 0;
else { break;
chunk = dev->checkpt_cur_block * }
dev->param.chunks_per_block +
dev->checkpt_cur_chunk;
realignedChunk = chunk - dev->chunk_offset; chunk = dev->checkpt_cur_block *
dev->param.chunks_per_block +
dev->n_page_reads++; dev->checkpt_cur_chunk;
/* read in the next chunk */ offset_chunk = apply_chunk_offset(dev, chunk);
/* printf("read checkpoint page %d\n",dev->checkpointPage); */ dev->n_page_reads++;
dev->param.read_chunk_tags_fn(dev,
realignedChunk, /* read in the next chunk */
dev->tagger.read_chunk_tags_fn(dev,
offset_chunk,
dev->checkpt_buffer, dev->checkpt_buffer,
&tags); &tags);
if (tags.chunk_id != (dev->checkpt_page_seq + 1) || if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
tags.ecc_result > YAFFS_ECC_RESULT_FIXED || tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {
ok = 0; ok = 0;
break;
dev->checkpt_byte_offs = 0;
dev->checkpt_page_seq++;
dev->checkpt_cur_chunk++;
if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block)
dev->checkpt_cur_block = -1;
} }
if(!yaffs2_checkpt_check_chunk_hdr(dev)) {
ok = 0;
break;
}
dev->checkpt_page_seq++;
dev->checkpt_cur_chunk++;
if (dev->checkpt_cur_chunk >=
dev->param.chunks_per_block)
dev->checkpt_cur_block = -1;
} }
if (ok) { *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
*dataBytes = dev->checkpt_buffer[dev->checkpt_byte_offs]; dev->checkpt_sum += *data_bytes;
dev->checkpt_sum += *dataBytes; dev->checkpt_xor ^= *data_bytes;
dev->checkpt_xor ^= *dataBytes; dev->checkpt_byte_offs++;
dev->checkpt_byte_offs++; i++;
i++; data_bytes++;
dataBytes++; dev->checkpt_byte_count++;
dev->checkpt_byte_count++;
}
} }
return i; return i;
} }
int yaffs_checkpt_close(yaffs_dev_t *dev) int yaffs_checkpt_close(struct yaffs_dev *dev)
{ {
int i;
if (dev->checkpt_open_write) { if (dev->checkpt_open_write) {
if (dev->checkpt_byte_offs != 0) if (dev->checkpt_byte_offs !=
sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))
yaffs2_checkpt_flush_buffer(dev); yaffs2_checkpt_flush_buffer(dev);
} else if(dev->checkpt_block_list){ } else if (dev->checkpt_block_list) {
int i; for (i = 0;
for (i = 0; i < dev->blocks_in_checkpt && dev->checkpt_block_list[i] >= 0; i++) { i < dev->blocks_in_checkpt &&
dev->checkpt_block_list[i] >= 0; i++) {
int blk = dev->checkpt_block_list[i]; int blk = dev->checkpt_block_list[i];
yaffs_block_info_t *bi = NULL; struct yaffs_block_info *bi = NULL;
if( dev->internal_start_block <= blk && blk <= dev->internal_end_block)
if (dev->internal_start_block <= blk &&
blk <= dev->internal_end_block)
bi = yaffs_get_block_info(dev, blk); bi = yaffs_get_block_info(dev, blk);
if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY) if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
else {
/* Todo this looks odd... */
}
} }
YFREE(dev->checkpt_block_list); kfree(dev->checkpt_block_list);
dev->checkpt_block_list = NULL; dev->checkpt_block_list = NULL;
} }
dev->n_free_chunks -= dev->blocks_in_checkpt * dev->param.chunks_per_block; dev->n_free_chunks -=
dev->blocks_in_checkpt * dev->param.chunks_per_block;
dev->n_erased_blocks -= dev->blocks_in_checkpt; dev->n_erased_blocks -= dev->blocks_in_checkpt;
yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR), dev->checkpt_byte_count);
dev->checkpt_byte_count));
if (dev->checkpt_buffer) { if (dev->checkpt_buffer) {
/* free the buffer */ /* free the buffer */
YFREE(dev->checkpt_buffer); kfree(dev->checkpt_buffer);
dev->checkpt_buffer = NULL; dev->checkpt_buffer = NULL;
return 1; return 1;
} else } else {
return 0; return 0;
}
} }
int yaffs2_checkpt_invalidate_stream(yaffs_dev_t *dev) int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
{ {
/* Erase the checkpoint data */ /* Erase the checkpoint data */
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR), yaffs_trace(YAFFS_TRACE_CHECKPOINT,
dev->blocks_in_checkpt)); "checkpoint invalidate of %d blocks",
dev->blocks_in_checkpt);
return yaffs_checkpt_erase(dev); return yaffs_checkpt_erase(dev);
} }

View File

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

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -16,22 +16,22 @@
* *
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
* The two unused bit are set to 1. * The two unused bit are set to 1.
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
* blocks are used on a 512-byte NAND page. * such ECC blocks are used on a 512-byte NAND page.
* *
*/ */
/* Table generated by gen-ecc.c
* Using a table means we do not have to calculate p1..p4 and p1'..p4'
* for each byte of data. These are instead provided in a table in bits7..2.
* Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
* this bytes influence on the line parity.
*/
#include "yportenv.h" #include "yportenv.h"
#include "yaffs_ecc.h" #include "yaffs_ecc.h"
/* Table generated by gen-ecc.c
* Using a table means we do not have to calculate p1..p4 and p1'..p4'
* for each byte of data. These are instead provided in a table in bits7..2.
* Bit 0 of each entry indicates whether the entry has an odd or even parity,
* and therefore this bytes influence on the line parity.
*/
static const unsigned char column_parity_table[] = { static const unsigned char column_parity_table[] = {
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
@ -67,35 +67,11 @@ static const unsigned char column_parity_table[] = {
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
}; };
/* Count the bits in an unsigned char or a U32 */
static int yaffs_count_bits(unsigned char x)
{
int r = 0;
while (x) {
if (x & 1)
r++;
x >>= 1;
}
return r;
}
static int yaffs_count_bits32(unsigned x)
{
int r = 0;
while (x) {
if (x & 1)
r++;
x >>= 1;
}
return r;
}
/* Calculate the ECC for a 256-byte block of data */ /* Calculate the ECC for a 256-byte block of data */
void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc) void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
{ {
unsigned int i; unsigned int i;
unsigned char col_parity = 0; unsigned char col_parity = 0;
unsigned char line_parity = 0; unsigned char line_parity = 0;
unsigned char line_parity_prime = 0; unsigned char line_parity_prime = 0;
@ -106,7 +82,7 @@ void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc)
b = column_parity_table[*data++]; b = column_parity_table[*data++];
col_parity ^= b; col_parity ^= b;
if (b & 0x01) { /* odd number of bits in the byte */ if (b & 0x01) { /* odd number of bits in the byte */
line_parity ^= i; line_parity ^= i;
line_parity_prime ^= ~i; line_parity_prime ^= ~i;
} }
@ -152,19 +128,12 @@ void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc)
t |= 0x01; t |= 0x01;
ecc[0] = ~t; ecc[0] = ~t;
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
/* Swap the bytes into the wrong order */
t = ecc[0];
ecc[0] = ecc[1];
ecc[1] = t;
#endif
} }
/* Correct the ECC on a 256 byte block of data */ /* Correct the ECC on a 256 byte block of data */
int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc) const unsigned char *test_ecc)
{ {
unsigned char d0, d1, d2; /* deltas */ unsigned char d0, d1, d2; /* deltas */
@ -173,7 +142,7 @@ int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
d2 = read_ecc[2] ^ test_ecc[2]; d2 = read_ecc[2] ^ test_ecc[2];
if ((d0 | d1 | d2) == 0) if ((d0 | d1 | d2) == 0)
return 0; /* no error */ return 0; /* no error */
if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
@ -183,15 +152,6 @@ int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
unsigned byte; unsigned byte;
unsigned bit; unsigned bit;
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
/* swap the bytes to correct for the wrong order */
unsigned char t;
t = d0;
d0 = d1;
d1 = t;
#endif
bit = byte = 0; bit = byte = 0;
if (d1 & 0x80) if (d1 & 0x80)
@ -220,19 +180,17 @@ int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
data[byte] ^= (1 << bit); data[byte] ^= (1 << bit);
return 1; /* Corrected the error */ return 1; /* Corrected the error */
} }
if ((yaffs_count_bits(d0) + if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
yaffs_count_bits(d1) +
yaffs_count_bits(d2)) == 1) {
/* Reccoverable error in ecc */ /* Reccoverable error in ecc */
read_ecc[0] = test_ecc[0]; read_ecc[0] = test_ecc[0];
read_ecc[1] = test_ecc[1]; read_ecc[1] = test_ecc[1];
read_ecc[2] = test_ecc[2]; read_ecc[2] = test_ecc[2];
return 1; /* Corrected the error */ return 1; /* Corrected the error */
} }
/* Unrecoverable error */ /* Unrecoverable error */
@ -241,15 +199,13 @@ int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
} }
/* /*
* ECCxxxOther does ECC calcs on arbitrary n bytes of data * ECCxxxOther does ECC calcs on arbitrary n bytes of data
*/ */
void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
yaffs_ECCOther *eccOther) struct yaffs_ecc_other *ecc_other)
{ {
unsigned int i; unsigned int i;
unsigned char col_parity = 0; unsigned char col_parity = 0;
unsigned line_parity = 0; unsigned line_parity = 0;
unsigned line_parity_prime = 0; unsigned line_parity_prime = 0;
@ -259,7 +215,7 @@ void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
b = column_parity_table[*data++]; b = column_parity_table[*data++];
col_parity ^= b; col_parity ^= b;
if (b & 0x01) { if (b & 0x01) {
/* odd number of bits in the byte */ /* odd number of bits in the byte */
line_parity ^= i; line_parity ^= i;
line_parity_prime ^= ~i; line_parity_prime ^= ~i;
@ -267,54 +223,56 @@ void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
} }
eccOther->colParity = (col_parity >> 2) & 0x3f; ecc_other->col_parity = (col_parity >> 2) & 0x3f;
eccOther->lineParity = line_parity; ecc_other->line_parity = line_parity;
eccOther->lineParityPrime = line_parity_prime; ecc_other->line_parity_prime = line_parity_prime;
} }
int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
yaffs_ECCOther *read_ecc, struct yaffs_ecc_other *read_ecc,
const yaffs_ECCOther *test_ecc) const struct yaffs_ecc_other *test_ecc)
{ {
unsigned char cDelta; /* column parity delta */ unsigned char delta_col; /* column parity delta */
unsigned lDelta; /* line parity delta */ unsigned delta_line; /* line parity delta */
unsigned lDeltaPrime; /* line parity delta */ unsigned delta_line_prime; /* line parity delta */
unsigned bit; unsigned bit;
cDelta = read_ecc->colParity ^ test_ecc->colParity; delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
lDelta = read_ecc->lineParity ^ test_ecc->lineParity; delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime; delta_line_prime =
read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
if ((cDelta | lDelta | lDeltaPrime) == 0) if ((delta_col | delta_line | delta_line_prime) == 0)
return 0; /* no error */ return 0; /* no error */
if (lDelta == ~lDeltaPrime && if (delta_line == ~delta_line_prime &&
(((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) { (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
/* Single bit (recoverable) error in data */ /* Single bit (recoverable) error in data */
bit = 0; bit = 0;
if (cDelta & 0x20) if (delta_col & 0x20)
bit |= 0x04; bit |= 0x04;
if (cDelta & 0x08) if (delta_col & 0x08)
bit |= 0x02; bit |= 0x02;
if (cDelta & 0x02) if (delta_col & 0x02)
bit |= 0x01; bit |= 0x01;
if (lDelta >= n_bytes) if (delta_line >= n_bytes)
return -1; return -1;
data[lDelta] ^= (1 << bit); data[delta_line] ^= (1 << bit);
return 1; /* corrected */ return 1; /* corrected */
} }
if ((yaffs_count_bits32(lDelta) + yaffs_count_bits32(lDeltaPrime) + if ((hweight32(delta_line) +
yaffs_count_bits(cDelta)) == 1) { hweight32(delta_line_prime) +
hweight8(delta_col)) == 1) {
/* Reccoverable error in ecc */ /* Reccoverable error in ecc */
*read_ecc = *test_ecc; *read_ecc = *test_ecc;
return 1; /* corrected */ return 1; /* corrected */
} }
/* Unrecoverable error */ /* Unrecoverable error */

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -18,27 +18,27 @@
* *
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
* The two unused bit are set to 1. * The two unused bit are set to 1.
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC * The ECC can correct single bit errors in a 256-byte page of data.
* blocks are used on a 512-byte NAND page. * Thus, two such ECC blocks are used on a 512-byte NAND page.
* *
*/ */
#ifndef __YAFFS_ECC_H__ #ifndef __YAFFS_ECC_H__
#define __YAFFS_ECC_H__ #define __YAFFS_ECC_H__
typedef struct { struct yaffs_ecc_other {
unsigned char colParity; unsigned char col_parity;
unsigned lineParity; unsigned line_parity;
unsigned lineParityPrime; unsigned line_parity_prime;
} yaffs_ECCOther; };
void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc); void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc); const unsigned char *test_ecc);
void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
yaffs_ECCOther *ecc); struct yaffs_ecc_other *ecc);
int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
yaffs_ECCOther *read_ecc, struct yaffs_ecc_other *read_ecc,
const yaffs_ECCOther *test_ecc); const struct yaffs_ecc_other *test_ecc);
#endif #endif

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -20,14 +20,14 @@
#include "yaffs_trace.h" #include "yaffs_trace.h"
/* Function to manipulate block info */ /* Function to manipulate block info */
static Y_INLINE yaffs_block_info_t *yaffs_get_block_info(yaffs_dev_t * dev, int blk) static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
*dev, int blk)
{ {
if (blk < dev->internal_start_block || blk > dev->internal_end_block) { if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
T(YAFFS_TRACE_ERROR, yaffs_trace(YAFFS_TRACE_ERROR,
(TSTR "**>> yaffs: get_block_info block %d is not valid",
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR), blk);
blk)); BUG();
YBUG();
} }
return &dev->block_info[blk - dev->internal_start_block]; return &dev->block_info[blk - dev->internal_start_block];
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -16,28 +16,33 @@
#ifndef __YAFFS_LINUX_H__ #ifndef __YAFFS_LINUX_H__
#define __YAFFS_LINUX_H__ #define __YAFFS_LINUX_H__
#include "devextras.h"
#include "yportenv.h" #include "yportenv.h"
struct yaffs_LinuxContext { struct yaffs_linux_context {
struct ylist_head contextList; /* List of these we have mounted */ struct list_head context_list; /* List of these we have mounted */
struct yaffs_dev_s *dev; struct yaffs_dev *dev;
struct super_block * superBlock; struct super_block *super;
struct task_struct *bgThread; /* Background thread for this device */ struct task_struct *bg_thread; /* Background thread for this device */
int bgRunning; int bg_running;
struct semaphore grossLock; /* Gross locking semaphore */ struct mutex gross_lock; /* Gross locking mutex*/
__u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer u8 *spare_buffer; /* For mtdif2 use. Don't know the buffer size
* at compile time so we have to allocate it. * at compile time so we have to allocate it.
*/ */
struct ylist_head searchContexts; struct list_head search_contexts;
void (*putSuperFunc)(struct super_block *sb); struct task_struct *readdir_process;
struct task_struct *readdirProcess;
unsigned mount_id; unsigned mount_id;
int dirty;
}; };
#define yaffs_dev_to_lc(dev) ((struct yaffs_LinuxContext *)((dev)->os_context)) #define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context)) #define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
#define WRITE_SIZE_STR "writesize"
#define WRITE_SIZE(mtd) ((mtd)->writesize)
#else
#define WRITE_SIZE_STR "oobblock"
#define WRITE_SIZE(mtd) ((mtd)->oobblock)
#endif #endif
#endif

View File

@ -1,200 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*
* Note: Tis code is currently unused. Being checked in in case it becomes useful.
*/
#include "yaffs_allocator.h"
#include "yaffs_guts.h"
#include "yaffs_trace.h"
#include "yportenv.h"
#include "yaffs_linux.h"
/*
* Start out with the same allocator as yaffs direct.
* Todo: Change to Linux slab allocator.
*/
#define NAMELEN 20
struct yaffs_AllocatorStruct {
char tnode_name[NAMELEN+1];
char object_name[NAMELEN+1];
struct kmem_cache *tnode_cache;
struct kmem_cache *object_cache;
};
typedef struct yaffs_AllocatorStruct yaffs_Allocator;
int mount_id;
void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n")));
if(allocator){
if(allocator->tnode_cache){
kmem_cache_destroy(allocator->tnode_cache);
allocator->tnode_cache = NULL;
} else {
T(YAFFS_TRACE_ALWAYS,
(TSTR("NULL tnode cache\n")));
YBUG();
}
if(allocator->object_cache){
kmem_cache_destroy(allocator->object_cache);
allocator->object_cache = NULL;
} else {
T(YAFFS_TRACE_ALWAYS,
(TSTR("NULL object cache\n")));
YBUG();
}
YFREE(allocator);
} else {
T(YAFFS_TRACE_ALWAYS,
(TSTR("Deinitialising NULL allocator\n")));
YBUG();
}
dev->allocator = NULL;
}
static void fake_ctor0(void *data){data = data;}
static void fake_ctor1(void *data){data = data;}
static void fake_ctor2(void *data){data = data;}
static void fake_ctor3(void *data){data = data;}
static void fake_ctor4(void *data){data = data;}
static void fake_ctor5(void *data){data = data;}
static void fake_ctor6(void *data){data = data;}
static void fake_ctor7(void *data){data = data;}
static void fake_ctor8(void *data){data = data;}
static void fake_ctor9(void *data){data = data;}
static void (*fake_ctor_list[10]) (void *) = {
fake_ctor0,
fake_ctor1,
fake_ctor2,
fake_ctor3,
fake_ctor4,
fake_ctor5,
fake_ctor6,
fake_ctor7,
fake_ctor8,
fake_ctor9,
};
void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator;
unsigned mount_id = yaffs_dev_to_lc(dev)->mount_id;
T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n")));
if(dev->allocator)
YBUG();
else if(mount_id >= 10){
T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id));
} else {
allocator = YMALLOC(sizeof(yaffs_Allocator));
memset(allocator,0,sizeof(yaffs_Allocator));
dev->allocator = allocator;
if(!dev->allocator){
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs allocator creation failed\n")));
YBUG();
return;
}
sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id);
sprintf(allocator->object_name,"yaffs_o_%u",mount_id);
allocator->tnode_cache =
kmem_cache_create(allocator->tnode_name,
dev->tnode_size,
0, 0,
fake_ctor_list[mount_id]);
if(allocator->tnode_cache)
T(YAFFS_TRACE_ALLOCATE,
(TSTR("tnode cache \"%s\" %p\n"),
allocator->tnode_name,allocator->tnode_cache));
else {
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs cache creation failed\n")));
YBUG();
}
allocator->object_cache =
kmem_cache_create(allocator->object_name,
sizeof(yaffs_obj_t),
0, 0,
fake_ctor_list[mount_id]);
if(allocator->object_cache)
T(YAFFS_TRACE_ALLOCATE,
(TSTR("object cache \"%s\" %p\n"),
allocator->object_name,allocator->object_cache));
else {
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs cache creation failed\n")));
YBUG();
}
}
}
yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator = dev->allocator;
if(!allocator || !allocator->tnode_cache){
YBUG();
return NULL;
}
return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS);
}
void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
{
yaffs_Allocator *allocator = dev->allocator;
kmem_cache_free(allocator->tnode_cache,tn);
}
yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
{
yaffs_Allocator *allocator = dev->allocator;
if(!allocator){
YBUG();
return NULL;
}
if(!allocator->object_cache){
YBUG();
return NULL;
}
return kmem_cache_alloc(allocator->object_cache, GFP_NOFS);
}
void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
{
yaffs_Allocator *allocator = dev->allocator;
kmem_cache_free(allocator->object_cache,obj);
}

View File

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

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -13,24 +13,43 @@
#include "yportenv.h" #include "yportenv.h"
#include "yaffs_mtdif.h" #include "yaffs_mtdif.h"
#include "linux/mtd/mtd.h" #include "linux/mtd/mtd.h"
#include "linux/types.h" #include "linux/types.h"
#include "linux/time.h" #include "linux/time.h"
#include "linux/mtd/nand.h" #include "linux/mtd/nand.h"
#include "linux/kernel.h"
#include "linux/version.h"
#include "linux/types.h"
#include "yaffs_trace.h"
#include "yaffs_guts.h"
#include "yaffs_linux.h" #include "yaffs_linux.h"
int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber)
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
#define mtd_erase(m, ei) (m)->erase(m, ei)
#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops)
#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops)
#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs)
#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs)
#endif
int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
{ {
struct mtd_info *mtd = yaffs_dev_to_mtd(dev); struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
__u32 addr = u32 addr =
((loff_t) blockNumber) * dev->param.total_bytes_per_chunk ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
* dev->param.chunks_per_block; dev->param.chunks_per_block;
struct erase_info ei; struct erase_info ei;
int retval = 0; int retval = 0;
ei.mtd = mtd; ei.mtd = mtd;
@ -41,16 +60,249 @@ int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber)
ei.callback = NULL; ei.callback = NULL;
ei.priv = (u_long) dev; ei.priv = (u_long) dev;
retval = mtd->erase(mtd, &ei); retval = mtd_erase(mtd, &ei);
if (retval == 0) if (retval == 0)
return YAFFS_OK; return YAFFS_OK;
else
return YAFFS_FAIL; return YAFFS_FAIL;
} }
int nandmtd_InitialiseNAND(yaffs_dev_t *dev)
static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
const u8 *data, int data_len,
const u8 *oob, int oob_len)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
loff_t addr;
struct mtd_oob_ops ops;
int retval;
yaffs_trace(YAFFS_TRACE_MTD,
"yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n",
dev, nand_chunk, data, data_len, oob, oob_len);
if (!data || !data_len) {
data = NULL;
data_len = 0;
}
if (!oob || !oob_len) {
oob = NULL;
oob_len = 0;
}
addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = (data) ? data_len : 0;
ops.ooblen = oob_len;
ops.datbuf = (u8 *)data;
ops.oobbuf = (u8 *)oob;
retval = mtd_write_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"write_oob failed, chunk %d, mtd error %d",
nand_chunk, retval);
}
return retval ? YAFFS_FAIL : YAFFS_OK;
}
static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
u8 *data, int data_len,
u8 *oob, int oob_len,
enum yaffs_ecc_result *ecc_result)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
loff_t addr;
struct mtd_oob_ops ops;
int retval;
addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = (data) ? data_len : 0;
ops.ooblen = oob_len;
ops.datbuf = data;
ops.oobbuf = oob;
#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
* help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
*/
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",
nand_chunk, retval);
switch (retval) {
case 0:
/* no error */
if(ecc_result)
*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
break;
case -EUCLEAN:
/* MTD's ECC fixed the data */
if(ecc_result)
*ecc_result = YAFFS_ECC_RESULT_FIXED;
dev->n_ecc_fixed++;
break;
case -EBADMSG:
default:
/* MTD's ECC could not fix the data */
dev->n_ecc_unfixed++;
if(ecc_result)
*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
return YAFFS_FAIL;
}
return YAFFS_OK;
}
static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
loff_t addr;
struct erase_info ei;
int retval = 0;
u32 block_size;
block_size = dev->param.total_bytes_per_chunk *
dev->param.chunks_per_block;
addr = ((loff_t) block_no) * block_size;
ei.mtd = mtd;
ei.addr = addr;
ei.len = block_size;
ei.time = 1000;
ei.retries = 2;
ei.callback = NULL;
ei.priv = (u_long) dev;
retval = mtd_erase(mtd, &ei);
if (retval == 0)
return YAFFS_OK;
return YAFFS_FAIL;
}
static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
int retval;
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no);
return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
int retval;
yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no);
retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no);
return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
static int yaffs_mtd_initialise(struct yaffs_dev *dev)
{ {
return YAFFS_OK; return YAFFS_OK;
} }
static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
{
return YAFFS_OK;
}
void yaffs_mtd_drv_install(struct yaffs_dev *dev)
{
struct yaffs_driver *drv = &dev->drv;
drv->drv_write_chunk_fn = yaffs_mtd_write;
drv->drv_read_chunk_fn = yaffs_mtd_read;
drv->drv_erase_fn = yaffs_mtd_erase;
drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;
drv->drv_check_bad_fn = yaffs_mtd_check_bad;
drv->drv_initialise_fn = yaffs_mtd_initialise;
drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;
}
struct mtd_info * yaffs_get_mtd_device(dev_t sdev)
{
struct mtd_info *mtd;
mtd = yaffs_get_mtd_device(sdev);
/* Check it's an mtd device..... */
if (MAJOR(sdev) != MTD_BLOCK_MAJOR)
return NULL; /* This isn't an mtd device */
/* Check it's NAND */
if (mtd->type != MTD_NANDFLASH) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs: MTD device is not NAND it's type %d",
mtd->type);
return NULL;
}
yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd));
yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize);
yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size);
#else
yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size);
#endif
return mtd;
}
int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
{
if (yaffs_version == 2) {
if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
!inband_tags) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
"MTD device does not have the right page sizes"
);
return -1;
}
} else {
if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
"MTD device does not support have the right page sizes"
);
return -1;
}
}
return 0;
}
void yaffs_put_mtd_device(struct mtd_info *mtd)
{
if(mtd)
put_mtd_device(mtd);
}

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -18,10 +18,8 @@
#include "yaffs_guts.h" #include "yaffs_guts.h"
#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18)) void yaffs_mtd_drv_install(struct yaffs_dev *dev);
extern struct nand_oobinfo yaffs_oobinfo; struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
extern struct nand_oobinfo yaffs_noeccinfo; void yaffs_put_mtd_device(struct mtd_info *mtd);
#endif int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber);
int nandmtd_InitialiseNAND(yaffs_dev_t *dev);
#endif #endif

View File

@ -1,361 +0,0 @@
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
*
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
* 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_tags_tCompatability functions in yaffs_tagscompat.c that are
* called in yaffs_mtdif.c when the function pointers are NULL.
* We assume the MTD layer is performing ECC (use_nand_ecc is true).
*/
#include "yportenv.h"
#include "yaffs_trace.h"
#include "yaffs_guts.h"
#include "yaffs_packedtags1.h"
#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */
#include "yaffs_linux.h"
#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 (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
#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
* page_status byte (at NAND spare offset 4) scattered/gathered from/to
* the 9th byte.
*
* Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
* We have/need PackedTags1 plus page_status: T0,T1,T2,T3,T4,T5,T6,T7,P
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the page_status
* byte and B is the small-page bad-block indicator byte.
*/
static struct nand_ecclayout nand_oob_16 = {
.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_dev_t *dev,
int nand_chunk, const __u8 *data, const yaffs_ext_tags *etags)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int chunkBytes = dev->data_bytes_per_chunk;
loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
/* we assume that PackedTags1 and yaffs_tags_t are compatible */
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
compile_time_assertion(sizeof(yaffs_tags_t) == 8);
yaffs_PackTags1(&pt1, etags);
yaffs_calc_tags_ecc((yaffs_tags_t *)&pt1);
/* When deleting a chunk, the upper layer provides only skeletal
* etags, one with is_deleted set. However, we need to update the
* tags, not erase them completely. So we use the NAND write property
* that only zeroed-bits stick and set tag bytes to all-ones and
* zero just the (not) deleted bit.
*/
#ifndef CONFIG_YAFFS_9BYTE_TAGS
if (etags->is_deleted) {
memset(&pt1, 0xff, 8);
/* clear delete status bit to indicate deleted */
pt1.deleted = 0;
}
#else
((__u8 *)&pt1)[8] = 0xff;
if (etags->is_deleted) {
memset(&pt1, 0xff, 8);
/* zero page_status 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) {
T(YAFFS_TRACE_MTD,
(TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
nand_chunk, retval));
}
return retval ? YAFFS_FAIL : YAFFS_OK;
}
/* Return with empty ExtendedTags but add ecc_result.
*/
static int rettags(yaffs_ext_tags *etags, int ecc_result, int retval)
{
if (etags) {
memset(etags, 0, sizeof(*etags));
etags->ecc_result = ecc_result;
}
return retval;
}
/* Read a chunk (page) from NAND.
*
* Caller expects ExtendedTags data to be usable even on error; that is,
* all members except ecc_result and block_bad are zeroed.
*
* - Check ECC results for data (if applicable)
* - Check for blank/erased block (return empty ExtendedTags if blank)
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
* - Convert PackedTags1 to ExtendedTags
* - Update ecc_result and block_bad members to refect state.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev,
int nand_chunk, __u8 *data, yaffs_ext_tags *etags)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int chunkBytes = dev->data_bytes_per_chunk;
loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
int deleted;
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 (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
* help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
*/
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) {
T(YAFFS_TRACE_MTD,
(TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
nand_chunk, retval));
}
switch (retval) {
case 0:
/* no error */
break;
case -EUCLEAN:
/* MTD's ECC fixed the data */
eccres = YAFFS_ECC_RESULT_FIXED;
dev->n_ecc_fixed++;
break;
case -EBADMSG:
/* MTD's ECC could not fix the data */
dev->n_ecc_unfixed++;
/* fall into... */
default:
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
etags->block_bad = (mtd->block_isbad)(mtd, addr);
return YAFFS_FAIL;
}
/* Check for a blank/erased chunk.
*/
if (yaffs_check_ff((__u8 *)&pt1, 8)) {
/* when blank, upper layers want ecc_result to be <= NO_ERROR */
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
}
#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
deleted = (yaffs_count_bits(((__u8 *)&pt1)[8]) < 7);
#endif
/* Check the packed tags mini-ECC and correct if necessary/possible.
*/
retval = yaffs_check_tags_ecc((yaffs_tags_t *)&pt1);
switch (retval) {
case 0:
/* no tags error, use MTD result */
break;
case 1:
/* recovered tags-ECC error */
dev->n_tags_ecc_fixed++;
if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
eccres = YAFFS_ECC_RESULT_FIXED;
break;
default:
/* unrecovered tags-ECC error */
dev->n_tags_ecc_unfixed++;
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
}
/* Unpack the tags to extended form and set ECC result.
* [set shouldBeFF just to keep yaffs_unpack_tags1 happy]
*/
pt1.shouldBeFF = 0xFFFFFFFF;
yaffs_unpack_tags1(etags, &pt1);
etags->ecc_result = eccres;
/* Set deleted state */
etags->is_deleted = deleted;
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_dev_s *dev, int block_no)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
int retval;
T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), block_no));
retval = mtd->block_markbad(mtd, (loff_t)blocksize * block_no);
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) {
T(YAFFS_TRACE_ERROR,
(TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR),
oobavail, YTAG1_SIZE));
return YAFFS_FAIL;
}
return YAFFS_OK;
}
/* 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_dev_s *dev, int block_no,
yaffs_block_state_t *pState, __u32 *pSequenceNumber)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int chunkNo = block_no * dev->param.chunks_per_block;
loff_t addr = (loff_t)chunkNo * dev->data_bytes_per_chunk;
yaffs_ext_tags etags;
int state = YAFFS_BLOCK_STATE_DEAD;
int seqnum = 0;
int retval;
/* 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);
etags.block_bad = (mtd->block_isbad)(mtd, addr);
if (etags.block_bad) {
T(YAFFS_TRACE_BAD_BLOCKS,
(TSTR("block %d is marked bad"TENDSTR), block_no));
state = YAFFS_BLOCK_STATE_DEAD;
} else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
/* bad tags, need to look more closely */
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
} else if (etags.chunk_used) {
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
seqnum = etags.seq_number;
} else {
state = YAFFS_BLOCK_STATE_EMPTY;
}
*pState = state;
*pSequenceNumber = seqnum;
/* query always succeeds */
return YAFFS_OK;
}
#endif /*MTD_VERSION*/

View File

@ -1,28 +0,0 @@
/*
* YAFFS: Yet another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* 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_MTDIF1_H__
#define __YAFFS_MTDIF1_H__
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
const __u8 *data, const yaffs_ext_tags *tags);
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
__u8 *data, yaffs_ext_tags *tags);
int nandmtd1_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
yaffs_block_state_t *state, __u32 *seq_number);
#endif

View File

@ -1,257 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* mtd interface for YAFFS2 */
#include "yportenv.h"
#include "yaffs_trace.h"
#include "yaffs_mtdif2.h"
#include "linux/mtd/mtd.h"
#include "linux/types.h"
#include "linux/time.h"
#include "yaffs_packedtags2.h"
#include "yaffs_linux.h"
/* NB For use with inband tags....
* We assume that the data buffer is of size totalBytersPerChunk so that we can also
* use it to load the tags.
*/
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
const __u8 *data,
const yaffs_ext_tags *tags)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
struct mtd_oob_ops ops;
#else
size_t dummy;
#endif
int retval = 0;
loff_t addr;
yaffs_PackedTags2 pt;
int packed_tags_size = dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
void * packed_tags_ptr = dev->param.no_tags_ecc ? (void *) &pt.t : (void *)&pt;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
TENDSTR), nand_chunk, data, tags));
addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
/* For yaffs2 writing there must be both data and tags.
* If we're using inband tags, then the tags are stuffed into
* the end of the data buffer.
*/
if (!data || !tags)
BUG();
else if (dev->param.inband_tags) {
yaffs_PackedTags2TagsPart *pt2tp;
pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->data_bytes_per_chunk);
yaffs_PackTags2TagsPart(pt2tp, tags);
} else
yaffs_PackTags2(&pt, tags, !dev->param.no_tags_ecc);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
ops.mode = MTD_OOB_AUTO;
ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
ops.len = dev->param.total_bytes_per_chunk;
ops.ooboffs = 0;
ops.datbuf = (__u8 *)data;
ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
retval = mtd->write_oob(mtd, addr, &ops);
#else
if (!dev->param.inband_tags) {
retval =
mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
&dummy, data, (__u8 *) packed_tags_ptr, NULL);
} else {
retval =
mtd->write(mtd, addr, dev->param.total_bytes_per_chunk, &dummy,
data);
}
#endif
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
__u8 *data, yaffs_ext_tags *tags)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
int localData = 0;
loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
yaffs_PackedTags2 pt;
int packed_tags_size = dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
void * packed_tags_ptr = dev->param.no_tags_ecc ? (void *) &pt.t: (void *)&pt;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
TENDSTR), nand_chunk, data, tags));
if (dev->param.inband_tags) {
if (!data) {
localData = 1;
data = yaffs_get_temp_buffer(dev, __LINE__);
}
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
if (dev->param.inband_tags || (data && !tags))
retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
&dummy, data);
else if (tags) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = packed_tags_size;
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
ops.ooboffs = 0;
ops.datbuf = data;
ops.oobbuf = yaffs_dev_to_lc(dev)->spareBuffer;
retval = mtd->read_oob(mtd, addr, &ops);
}
#else
if (!dev->param.inband_tags && data && tags) {
retval = mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk,
&dummy, data, dev->spareBuffer,
NULL);
} else {
if (data)
retval =
mtd->read(mtd, addr, dev->data_bytes_per_chunk, &dummy,
data);
if (!dev->param.inband_tags && tags)
retval =
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
dev->spareBuffer);
}
#endif
if (dev->param.inband_tags) {
if (tags) {
yaffs_PackedTags2TagsPart *pt2tp;
pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->data_bytes_per_chunk];
yaffs_unpack_tags2tags_part(tags, pt2tp);
}
} else {
if (tags) {
memcpy(packed_tags_ptr, yaffs_dev_to_lc(dev)->spareBuffer, packed_tags_size);
yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
}
}
if (localData)
yaffs_release_temp_buffer(dev, data, __LINE__);
if (tags && retval == -EBADMSG && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
dev->n_ecc_unfixed++;
}
if(tags && retval == -EUCLEAN && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
dev->n_ecc_fixed++;
}
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), block_no));
retval =
mtd->block_markbad(mtd,
block_no * dev->param.chunks_per_block *
dev->param.total_bytes_per_chunk);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
yaffs_block_state_t *state, __u32 *seq_number)
{
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), block_no));
retval =
mtd->block_isbad(mtd,
block_no * dev->param.chunks_per_block *
dev->param.total_bytes_per_chunk);
if (retval) {
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
*state = YAFFS_BLOCK_STATE_DEAD;
*seq_number = 0;
} else {
yaffs_ext_tags t;
nandmtd2_ReadChunkWithTagsFromNAND(dev,
block_no *
dev->param.chunks_per_block, NULL,
&t);
if (t.chunk_used) {
*seq_number = t.seq_number;
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
} else {
*seq_number = 0;
*state = YAFFS_BLOCK_STATE_EMPTY;
}
}
T(YAFFS_TRACE_MTD,
(TSTR("block is bad seq %d state %d" TENDSTR), *seq_number,
*state));
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}

View File

@ -1,29 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_MTDIF2_H__
#define __YAFFS_MTDIF2_H__
#include "yaffs_guts.h"
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk,
const __u8 *data,
const yaffs_ext_tags *tags);
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk,
__u8 *data, yaffs_ext_tags *tags);
int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
yaffs_block_state_t *state, __u32 *seq_number);
#endif

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -12,58 +12,58 @@
*/ */
/* /*
* This simple implementation of a name-value store assumes a small number of values and fits * This simple implementation of a name-value store assumes a small number of
* into a small finite buffer. * values and fits into a small finite buffer.
* *
* Each attribute is stored as a record: * Each attribute is stored as a record:
* sizeof(int) bytes record size. * sizeof(int) bytes record size.
* strnlen+1 bytes name null terminated. * strnlen+1 bytes name null terminated.
* nbytes value. * nbytes value.
* ---------- * ----------
* total size stored in record size * total size stored in record size
* *
* This code has not been tested with unicode yet. * This code has not been tested with unicode yet.
*/ */
#include "yaffs_nameval.h" #include "yaffs_nameval.h"
#include "yportenv.h" #include "yportenv.h"
static int nval_find(const char *xb, int xb_size, const YCHAR *name, static int nval_find(const char *xb, int xb_size, const YCHAR *name,
int *exist_size) int *exist_size)
{ {
int pos=0; int pos = 0;
int size; int size;
memcpy(&size,xb,sizeof(int)); memcpy(&size, xb, sizeof(int));
while(size > 0 && (size < xb_size) && (pos + size < xb_size)){ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){ if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),
if(exist_size) name, size)) {
if (exist_size)
*exist_size = size; *exist_size = size;
return pos; return pos;
} }
pos += size; pos += size;
if(pos < xb_size -sizeof(int)) if (pos < xb_size - sizeof(int))
memcpy(&size,xb + pos,sizeof(int)); memcpy(&size, xb + pos, sizeof(int));
else else
size = 0; size = 0;
} }
if(exist_size) if (exist_size)
*exist_size = 0; *exist_size = 0;
return -1; return -ENODATA;
} }
static int nval_used(const char *xb, int xb_size) static int nval_used(const char *xb, int xb_size)
{ {
int pos=0; int pos = 0;
int size; int size;
memcpy(&size,xb + pos,sizeof(int)); memcpy(&size, xb + pos, sizeof(int));
while(size > 0 && (size < xb_size) && (pos + size < xb_size)){ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
pos += size; pos += size;
if(pos < xb_size -sizeof(int)) if (pos < xb_size - sizeof(int))
memcpy(&size,xb + pos,sizeof(int)); memcpy(&size, xb + pos, sizeof(int));
else else
size = 0; size = 0;
} }
@ -72,71 +72,74 @@ static int nval_used(const char *xb, int xb_size)
int nval_del(char *xb, int xb_size, const YCHAR *name) int nval_del(char *xb, int xb_size, const YCHAR *name)
{ {
int pos = nval_find(xb, xb_size, name, NULL); int pos = nval_find(xb, xb_size, name, NULL);
int size; int size;
if(pos >= 0 && pos < xb_size){ if (pos < 0 || pos >= xb_size)
/* Find size, shift rest over this record, then zero out the rest of buffer */
memcpy(&size,xb+pos,sizeof(int));
memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
memset(xb + (xb_size - size),0,size);
return 0;
} else
return -ENODATA; return -ENODATA;
/* Find size, shift rest over this record,
* then zero out the rest of buffer */
memcpy(&size, xb + pos, sizeof(int));
memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
memset(xb + (xb_size - size), 0, size);
return 0;
} }
int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags) int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
int bsize, int flags)
{ {
int pos; int pos;
int namelen = yaffs_strnlen(name,xb_size); int namelen = strnlen(name, xb_size);
int reclen; int reclen;
int size_exist = 0; int size_exist = 0;
int space; int space;
int start; int start;
pos = nval_find(xb,xb_size,name, &size_exist); pos = nval_find(xb, xb_size, name, &size_exist);
if(flags & XATTR_CREATE && pos >= 0) if (flags & XATTR_CREATE && pos >= 0)
return -EEXIST; return -EEXIST;
if(flags & XATTR_REPLACE && pos < 0) if (flags & XATTR_REPLACE && pos < 0)
return -ENODATA; return -ENODATA;
start = nval_used(xb,xb_size); start = nval_used(xb, xb_size);
space = xb_size - start + size_exist; space = xb_size - start + size_exist;
reclen = (sizeof(int) + namelen + 1 + bsize); reclen = (sizeof(int) + namelen + 1 + bsize);
if(reclen > space) if (reclen > space)
return -ENOSPC; return -ENOSPC;
if(pos >= 0){ if (pos >= 0) {
nval_del(xb,xb_size,name); nval_del(xb, xb_size, name);
start = nval_used(xb, xb_size); start = nval_used(xb, xb_size);
} }
pos = start; pos = start;
memcpy(xb + pos,&reclen,sizeof(int)); memcpy(xb + pos, &reclen, sizeof(int));
pos +=sizeof(int); pos += sizeof(int);
yaffs_strncpy((YCHAR *)(xb + pos), name, reclen); strncpy((YCHAR *) (xb + pos), name, reclen);
pos+= (namelen+1); pos += (namelen + 1);
memcpy(xb + pos,buf,bsize); memcpy(xb + pos, buf, bsize);
return 0; return 0;
} }
int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize) int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
int bsize)
{ {
int pos = nval_find(xb,xb_size,name,NULL); int pos = nval_find(xb, xb_size, name, NULL);
int size; int size;
if(pos >= 0 && pos< xb_size){ if (pos >= 0 && pos < xb_size) {
memcpy(&size,xb +pos,sizeof(int)); memcpy(&size, xb + pos, sizeof(int));
pos+=sizeof(int); /* advance past record length */ pos += sizeof(int); /* advance past record length */
size -= sizeof(int); size -= sizeof(int);
/* Advance over name string */ /* Advance over name string */
while(xb[pos] && size > 0 && pos < xb_size){ while (xb[pos] && size > 0 && pos < xb_size) {
pos++; pos++;
size--; size--;
} }
@ -144,16 +147,21 @@ int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsiz
pos++; pos++;
size--; size--;
if(size <= bsize){ /* If bsize is zero then this is a size query.
memcpy(buf,xb + pos,size); * Return the size, but don't copy.
*/
if (!bsize)
return size;
if (size <= bsize) {
memcpy(buf, xb + pos, size);
return size; return size;
} }
} }
if(pos >= 0) if (pos >= 0)
return -ERANGE; return -ERANGE;
else
return -ENODATA; return -ENODATA;
} }
int nval_list(const char *xb, int xb_size, char *buf, int bsize) int nval_list(const char *xb, int xb_size, char *buf, int bsize)
@ -164,33 +172,36 @@ int nval_list(const char *xb, int xb_size, char *buf, int bsize)
int ncopied = 0; int ncopied = 0;
int filled = 0; int filled = 0;
memcpy(&size,xb + pos,sizeof(int)); memcpy(&size, xb + pos, sizeof(int));
while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){ while (size > sizeof(int) &&
pos+= sizeof(int); size <= xb_size &&
size-=sizeof(int); (pos + size) < xb_size &&
name_len = yaffs_strnlen((YCHAR *)(xb + pos), size); !filled) {
if(ncopied + name_len + 1 < bsize){ pos += sizeof(int);
memcpy(buf,xb+pos,name_len * sizeof(YCHAR)); size -= sizeof(int);
buf+= name_len; name_len = strnlen((YCHAR *) (xb + pos), size);
if (ncopied + name_len + 1 < bsize) {
memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
buf += name_len;
*buf = '\0'; *buf = '\0';
buf++; buf++;
if(sizeof(YCHAR) > 1){ if (sizeof(YCHAR) > 1) {
*buf = '\0'; *buf = '\0';
buf++; buf++;
} }
ncopied += (name_len+1); ncopied += (name_len + 1);
} else } else {
filled = 1; filled = 1;
pos+=size; }
if(pos < xb_size -sizeof(int)) pos += size;
memcpy(&size,xb + pos,sizeof(int)); if (pos < xb_size - sizeof(int))
memcpy(&size, xb + pos, sizeof(int));
else else
size = 0; size = 0;
} }
return ncopied; return ncopied;
} }
int nval_hasvalues(const char *xb, int xb_size) int nval_hasvalues(const char *xb, int xb_size)
{ {
return nval_used(xb, xb_size) > 0; return nval_used(xb, xb_size) > 0;

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -12,14 +12,17 @@
* *
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/ */
#ifndef __NAMEVAL_H__ #ifndef __NAMEVAL_H__
#define __NAMEVAL_H__ #define __NAMEVAL_H__
#include "yportenv.h" #include "yportenv.h"
int nval_del(char *xb, int xb_size, const YCHAR *name); int nval_del(char *xb, int xb_size, const YCHAR * name);
int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags); int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize); int bsize, int flags);
int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
int bsize);
int nval_list(const char *xb, int xb_size, char *buf, int bsize); int nval_list(const char *xb, int xb_size, char *buf, int bsize);
int nval_hasvalues(const char *xb, int xb_size); int nval_hasvalues(const char *xb, int xb_size);
#endif #endif

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -13,128 +13,110 @@
#include "yaffs_nand.h" #include "yaffs_nand.h"
#include "yaffs_tagscompat.h" #include "yaffs_tagscompat.h"
#include "yaffs_tagsvalidity.h"
#include "yaffs_getblockinfo.h" #include "yaffs_getblockinfo.h"
#include "yaffs_summary.h"
int yaffs_rd_chunk_tags_nand(yaffs_dev_t *dev, int nand_chunk, static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
__u8 *buffer, {
yaffs_ext_tags *tags) return chunk - dev->chunk_offset;
}
int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
u8 *buffer, struct yaffs_ext_tags *tags)
{ {
int result; int result;
yaffs_ext_tags localTags; struct yaffs_ext_tags local_tags;
int flash_chunk = apply_chunk_offset(dev, nand_chunk);
int realignedChunkInNAND = nand_chunk - dev->chunk_offset;
dev->n_page_reads++; dev->n_page_reads++;
/* If there are no tags provided, use local tags to get prioritised gc working */ /* If there are no tags provided use local tags. */
if (!tags) if (!tags)
tags = &localTags; tags = &local_tags;
if (dev->param.read_chunk_tags_fn) result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);
result = dev->param.read_chunk_tags_fn(dev, realignedChunkInNAND, buffer, if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
tags);
else
result = yaffs_tags_compat_rd(dev,
realignedChunkInNAND,
buffer,
tags);
if (tags &&
tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
yaffs_block_info_t *bi; struct yaffs_block_info *bi;
bi = yaffs_get_block_info(dev, nand_chunk/dev->param.chunks_per_block); bi = yaffs_get_block_info(dev,
nand_chunk /
dev->param.chunks_per_block);
yaffs_handle_chunk_error(dev, bi); yaffs_handle_chunk_error(dev, bi);
} }
return result; return result;
} }
int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev, int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
int nand_chunk, int nand_chunk,
const __u8 *buffer, const u8 *buffer, struct yaffs_ext_tags *tags)
yaffs_ext_tags *tags)
{ {
int result;
int flash_chunk = apply_chunk_offset(dev, nand_chunk);
dev->n_page_writes++; dev->n_page_writes++;
nand_chunk -= dev->chunk_offset; if (!tags) {
yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
BUG();
if (tags) { return YAFFS_FAIL;
tags->seq_number = dev->seq_number;
tags->chunk_used = 1;
if (!yaffs_validate_tags(tags)) {
T(YAFFS_TRACE_ERROR,
(TSTR("Writing uninitialised tags" TENDSTR)));
YBUG();
}
T(YAFFS_TRACE_WRITE,
(TSTR("Writing chunk %d tags %d %d" TENDSTR), nand_chunk,
tags->obj_id, tags->chunk_id));
} else {
T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
YBUG();
} }
if (dev->param.write_chunk_tags_fn) tags->seq_number = dev->seq_number;
return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer, tags->chunk_used = 1;
tags); yaffs_trace(YAFFS_TRACE_WRITE,
else "Writing chunk %d tags %d %d",
return yaffs_tags_compat_wr(dev, nand_chunk, tags->obj_id, tags->chunk_id);
nand_chunk,
buffer,
tags);
}
int yaffs_mark_bad(yaffs_dev_t *dev, int block_no) result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk,
{ buffer, tags);
block_no -= dev->block_offset;
yaffs_summary_add(dev, tags, nand_chunk);
if (dev->param.bad_block_fn)
return dev->param.bad_block_fn(dev, block_no);
else
return yaffs_tags_compat_mark_bad(dev, block_no);
}
int yaffs_query_init_block_state(yaffs_dev_t *dev,
int block_no,
yaffs_block_state_t *state,
__u32 *seq_number)
{
block_no -= dev->block_offset;
if (dev->param.query_block_fn)
return dev->param.query_block_fn(dev, block_no, state, seq_number);
else
return yaffs_tags_compat_query_block(dev, block_no,
state,
seq_number);
}
int yaffs_erase_block(struct yaffs_dev_s *dev,
int flash_block)
{
int result;
flash_block -= dev->block_offset;
dev->n_erasures++;
result = dev->param.erase_fn(dev, flash_block);
return result; return result;
} }
int yaffs_init_nand(struct yaffs_dev_s *dev) int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
{ {
if(dev->param.initialise_flash_fn) block_no -= dev->block_offset;
return dev->param.initialise_flash_fn(dev); dev->n_bad_markings++;
return YAFFS_OK;
if (dev->param.disable_bad_block_marking)
return YAFFS_OK;
return dev->tagger.mark_bad_fn(dev, block_no);
} }
int yaffs_query_init_block_state(struct yaffs_dev *dev,
int block_no,
enum yaffs_block_state *state,
u32 *seq_number)
{
block_no -= dev->block_offset;
return dev->tagger.query_block_fn(dev, block_no, state, seq_number);
}
int yaffs_erase_block(struct yaffs_dev *dev, int block_no)
{
int result;
block_no -= dev->block_offset;
dev->n_erasures++;
result = dev->drv.drv_erase_fn(dev, block_no);
return result;
}
int yaffs_init_nand(struct yaffs_dev *dev)
{
if (dev->drv.drv_initialise_fn)
return dev->drv.drv_initialise_fn(dev);
return YAFFS_OK;
}
int yaffs_deinit_nand(struct yaffs_dev *dev)
{
if (dev->drv.drv_deinitialise_fn)
return dev->drv.drv_deinitialise_fn(dev);
return YAFFS_OK;
}

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -17,28 +17,23 @@
#define __YAFFS_NAND_H__ #define __YAFFS_NAND_H__
#include "yaffs_guts.h" #include "yaffs_guts.h"
int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
u8 *buffer, struct yaffs_ext_tags *tags);
int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
int nand_chunk,
const u8 *buffer, struct yaffs_ext_tags *tags);
int yaffs_rd_chunk_tags_nand(yaffs_dev_t *dev, int nand_chunk, int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
__u8 *buffer,
yaffs_ext_tags *tags);
int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev, int yaffs_query_init_block_state(struct yaffs_dev *dev,
int nand_chunk, int block_no,
const __u8 *buffer, enum yaffs_block_state *state,
yaffs_ext_tags *tags); unsigned *seq_number);
int yaffs_mark_bad(yaffs_dev_t *dev, int block_no); int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
int yaffs_query_init_block_state(yaffs_dev_t *dev, int yaffs_init_nand(struct yaffs_dev *dev);
int block_no, int yaffs_deinit_nand(struct yaffs_dev *dev);
yaffs_block_state_t *state,
unsigned *seq_number);
int yaffs_erase_block(struct yaffs_dev_s *dev,
int flash_block);
int yaffs_init_nand(struct yaffs_dev_s *dev);
#endif #endif

View File

@ -1,39 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/* Interface to emulated NAND functions (2k page size) */
#ifndef __YAFFS_NANDEMUL2K_H__
#define __YAFFS_NANDEMUL2K_H__
#include "yaffs_guts.h"
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_dev_s *dev,
int nand_chunk, const __u8 *data,
const yaffs_ext_tags *tags);
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_dev_s *dev,
int nand_chunk, __u8 *data,
yaffs_ext_tags *tags);
int nandemul2k_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no);
int nandemul2k_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
yaffs_block_state_t *state, __u32 *seq_number);
int nandemul2k_EraseBlockInNAND(struct yaffs_dev_s *dev,
int flash_block);
int nandemul2k_InitialiseNAND(struct yaffs_dev_s *dev);
int nandemul2k_GetBytesPerChunk(void);
int nandemul2k_GetChunksPerBlock(void);
int nandemul2k_GetNumberOfBlocks(void);
#endif

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -14,7 +14,16 @@
#include "yaffs_packedtags1.h" #include "yaffs_packedtags1.h"
#include "yportenv.h" #include "yportenv.h"
void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t) static const u8 all_ff[20] = {
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff
};
void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
const struct yaffs_ext_tags *t)
{ {
pt->chunk_id = t->chunk_id; pt->chunk_id = t->chunk_id;
pt->serial_number = t->serial_number; pt->serial_number = t->serial_number;
@ -22,20 +31,17 @@ void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t)
pt->obj_id = t->obj_id; pt->obj_id = t->obj_id;
pt->ecc = 0; pt->ecc = 0;
pt->deleted = (t->is_deleted) ? 0 : 1; pt->deleted = (t->is_deleted) ? 0 : 1;
pt->unusedStuff = 0; pt->unused_stuff = 0;
pt->shouldBeFF = 0xFFFFFFFF; pt->should_be_ff = 0xffffffff;
} }
void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt) void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
const struct yaffs_packed_tags1 *pt)
{ {
static const __u8 allFF[] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff };
if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) { if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
t->block_bad = 0; t->block_bad = 0;
if (pt->shouldBeFF != 0xFFFFFFFF) if (pt->should_be_ff != 0xffffffff)
t->block_bad = 1; t->block_bad = 1;
t->chunk_used = 1; t->chunk_used = 1;
t->obj_id = pt->obj_id; t->obj_id = pt->obj_id;
@ -45,6 +51,6 @@ void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt)
t->is_deleted = (pt->deleted) ? 0 : 1; t->is_deleted = (pt->deleted) ? 0 : 1;
t->serial_number = pt->serial_number; t->serial_number = pt->serial_number;
} else { } else {
memset(t, 0, sizeof(yaffs_ext_tags)); memset(t, 0, sizeof(struct yaffs_ext_tags));
} }
} }

View File

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

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -14,7 +14,6 @@
#include "yaffs_packedtags2.h" #include "yaffs_packedtags2.h"
#include "yportenv.h" #include "yportenv.h"
#include "yaffs_trace.h" #include "yaffs_trace.h"
#include "yaffs_tagsvalidity.h"
/* This code packs a set of extended tags into a binary structure for /* This code packs a set of extended tags into a binary structure for
* NAND storage * NAND storage
@ -32,167 +31,167 @@
#define EXTRA_SHADOWS_FLAG 0x20000000 #define EXTRA_SHADOWS_FLAG 0x20000000
#define EXTRA_SPARE_FLAGS 0x10000000 #define EXTRA_SPARE_FLAGS 0x10000000
#define ALL_EXTRA_FLAGS 0xF0000000 #define ALL_EXTRA_FLAGS 0xf0000000
/* Also, the top 4 bits of the object Id are set to the object type. */ /* Also, the top 4 bits of the object Id are set to the object type. */
#define EXTRA_OBJECT_TYPE_SHIFT (28) #define EXTRA_OBJECT_TYPE_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_dump_packed_tags2_tags_only(
static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt) const struct yaffs_packed_tags2_tags_only *ptt)
{ {
T(YAFFS_TRACE_MTD, yaffs_trace(YAFFS_TRACE_MTD,
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), "packed tags obj %d chunk %d byte %d seq %d",
ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
ptt->seq_number));
}
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
{
yaffs_DumpPackedTags2TagsPart(&pt->t);
} }
static void yaffs_DumpTags2(const yaffs_ext_tags *t) static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
{ {
T(YAFFS_TRACE_MTD, yaffs_dump_packed_tags2_tags_only(&pt->t);
(TSTR }
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
TENDSTR), t->ecc_result, t->block_bad, t->chunk_used, t->obj_id, static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number, {
t->seq_number)); yaffs_trace(YAFFS_TRACE_MTD,
"ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
t->seq_number);
} }
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt, static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
const yaffs_ext_tags *t) {
if (t->chunk_id != 0 || !t->extra_available)
return 0;
/* Check if the file size is too long to store */
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
(t->extra_file_size >> 31) != 0)
return 0;
return 1;
}
void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
const struct yaffs_ext_tags *t)
{ {
ptt->chunk_id = t->chunk_id; ptt->chunk_id = t->chunk_id;
ptt->seq_number = t->seq_number; ptt->seq_number = t->seq_number;
ptt->n_bytes = t->n_bytes; ptt->n_bytes = t->n_bytes;
ptt->obj_id = t->obj_id; ptt->obj_id = t->obj_id;
if (t->chunk_id == 0 && t->extra_available) { /* Only store extra tags for object headers.
* If it is a file then only store if the file size is short\
* enough to fit.
*/
if (yaffs_check_tags_extra_packable(t)) {
/* Store the extra header info instead */ /* Store the extra header info instead */
/* We save the parent object in the chunk_id */ /* We save the parent object in the chunk_id */
ptt->chunk_id = EXTRA_HEADER_INFO_FLAG ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
| t->extra_parent_id;
if (t->extra_is_shrink) if (t->extra_is_shrink)
ptt->chunk_id |= EXTRA_SHRINK_FLAG; ptt->chunk_id |= EXTRA_SHRINK_FLAG;
if (t->extra_shadows) if (t->extra_shadows)
ptt->chunk_id |= EXTRA_SHADOWS_FLAG; ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
ptt->obj_id |= ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
(t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
ptt->n_bytes = t->extra_equiv_id; ptt->n_bytes = t->extra_equiv_id;
else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE) else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
ptt->n_bytes = t->extra_length; ptt->n_bytes = (unsigned) t->extra_file_size;
else else
ptt->n_bytes = 0; ptt->n_bytes = 0;
} }
yaffs_DumpPackedTags2TagsPart(ptt); yaffs_dump_packed_tags2_tags_only(ptt);
yaffs_DumpTags2(t); yaffs_dump_tags2(t);
} }
void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC) const struct yaffs_ext_tags *t, int tags_ecc)
{ {
yaffs_PackTags2TagsPart(&pt->t, t); yaffs_pack_tags2_tags_only(&pt->t, t);
if(tagsECC) if (tags_ecc)
yaffs_ecc_calc_other((unsigned char *)&pt->t, yaffs_ecc_calc_other((unsigned char *)&pt->t,
sizeof(yaffs_PackedTags2TagsPart), sizeof(struct yaffs_packed_tags2_tags_only),
&pt->ecc); &pt->ecc);
} }
void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t, struct yaffs_packed_tags2_tags_only *ptt)
yaffs_PackedTags2TagsPart *ptt)
{ {
memset(t, 0, sizeof(struct yaffs_ext_tags));
memset(t, 0, sizeof(yaffs_ext_tags)); if (ptt->seq_number == 0xffffffff)
return;
yaffs_init_tags(t); t->block_bad = 0;
t->chunk_used = 1;
t->obj_id = ptt->obj_id;
t->chunk_id = ptt->chunk_id;
t->n_bytes = ptt->n_bytes;
t->is_deleted = 0;
t->serial_number = 0;
t->seq_number = ptt->seq_number;
if (ptt->seq_number != 0xFFFFFFFF) { /* Do extra header info stuff */
t->block_bad = 0; if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
t->chunk_used = 1; t->chunk_id = 0;
t->obj_id = ptt->obj_id; t->n_bytes = 0;
t->chunk_id = ptt->chunk_id;
t->n_bytes = ptt->n_bytes;
t->is_deleted = 0;
t->serial_number = 0;
t->seq_number = ptt->seq_number;
/* Do extra header info stuff */ t->extra_available = 1;
t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) { if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
t->chunk_id = 0; t->extra_equiv_id = ptt->n_bytes;
t->n_bytes = 0; else
t->extra_file_size = ptt->n_bytes;
t->extra_available = 1;
t->extra_parent_id =
ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
t->extra_is_shrink =
(ptt->chunk_id & EXTRA_SHRINK_FLAG) ? 1 : 0;
t->extra_shadows =
(ptt->chunk_id & EXTRA_SHADOWS_FLAG) ? 1 : 0;
t->extra_obj_type =
ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
t->extra_equiv_id = ptt->n_bytes;
else
t->extra_length = ptt->n_bytes;
}
} }
yaffs_dump_packed_tags2_tags_only(ptt);
yaffs_DumpPackedTags2TagsPart(ptt); yaffs_dump_tags2(t);
yaffs_DumpTags2(t);
} }
void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC) int tags_ecc)
{ {
enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR; if (pt->t.seq_number != 0xffffffff && tags_ecc) {
if (pt->t.seq_number != 0xFFFFFFFF &&
tagsECC){
/* Chunk is in use and we need to do ECC */ /* Chunk is in use and we need to do ECC */
yaffs_ECCOther ecc; struct yaffs_ecc_other ecc;
int result; int result;
yaffs_ecc_calc_other((unsigned char *)&pt->t, yaffs_ecc_calc_other((unsigned char *)&pt->t,
sizeof(yaffs_PackedTags2TagsPart), sizeof(struct yaffs_packed_tags2_tags_only),
&ecc); &ecc);
result = yaffs_ecc_correct_other((unsigned char *)&pt->t, result =
sizeof(yaffs_PackedTags2TagsPart), yaffs_ecc_correct_other((unsigned char *)&pt->t,
&pt->ecc, &ecc); sizeof(struct yaffs_packed_tags2_tags_only),
&pt->ecc, &ecc);
switch (result) { switch (result) {
case 0: case 0:
ecc_result = YAFFS_ECC_RESULT_NO_ERROR; ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
break; break;
case 1: case 1:
ecc_result = YAFFS_ECC_RESULT_FIXED; ecc_result = YAFFS_ECC_RESULT_FIXED;
break; break;
case -1: case -1:
ecc_result = YAFFS_ECC_RESULT_UNFIXED; ecc_result = YAFFS_ECC_RESULT_UNFIXED;
break; break;
default: default:
ecc_result = YAFFS_ECC_RESULT_UNKNOWN; ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
} }
} }
yaffs_unpack_tags2_tags_only(t, &pt->t);
yaffs_unpack_tags2tags_part(t, &pt->t);
t->ecc_result = ecc_result; t->ecc_result = ecc_result;
yaffs_DumpPackedTags2(pt); yaffs_dump_packed_tags2(pt);
yaffs_DumpTags2(t); yaffs_dump_tags2(t);
} }

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -21,23 +21,27 @@
#include "yaffs_guts.h" #include "yaffs_guts.h"
#include "yaffs_ecc.h" #include "yaffs_ecc.h"
typedef struct { struct yaffs_packed_tags2_tags_only {
unsigned seq_number; unsigned seq_number;
unsigned obj_id; unsigned obj_id;
unsigned chunk_id; unsigned chunk_id;
unsigned n_bytes; unsigned n_bytes;
} yaffs_PackedTags2TagsPart; };
typedef struct { struct yaffs_packed_tags2 {
yaffs_PackedTags2TagsPart t; struct yaffs_packed_tags2_tags_only t;
yaffs_ECCOther ecc; struct yaffs_ecc_other ecc;
} yaffs_PackedTags2; };
/* Full packed tags with ECC, used for oob tags */ /* Full packed tags with ECC, used for oob tags */
void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC); void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC); const struct yaffs_ext_tags *t, int tags_ecc);
void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
int tags_ecc);
/* Only the tags part (no ECC for use with inband tags */ /* Only the tags part (no ECC for use with inband tags */
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ext_tags *t); void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t, yaffs_PackedTags2TagsPart *pt); const struct yaffs_ext_tags *t);
void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
struct yaffs_packed_tags2_tags_only *pt);
#endif #endif

View File

@ -1,163 +0,0 @@
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "yportenv.h"
/* #include <linux/string.h> */
/*
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*/
#define swapcode(TYPE, parmi, parmj, n) do { \
long i = (n) / sizeof (TYPE); \
register TYPE *pi = (TYPE *) (parmi); \
register TYPE *pj = (TYPE *) (parmj); \
do { \
register TYPE t = *pi; \
*pi++ = *pj; \
*pj++ = t; \
} while (--i > 0); \
} while (0)
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1;
static __inline void
swapfunc(char *a, char *b, int n, int swaptype)
{
if (swaptype <= 1)
swapcode(long, a, b, n);
else
swapcode(char, a, b, n);
}
#define yswap(a, b) do { \
if (swaptype == 0) { \
long t = *(long *)(a); \
*(long *)(a) = *(long *)(b); \
*(long *)(b) = t; \
} else \
swapfunc(a, b, es, swaptype); \
} while (0)
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
static __inline char *
med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
{
return cmp(a, b) < 0 ?
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a))
: (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c));
}
#ifndef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
void
yaffs_qsort(void *aa, size_t n, size_t es,
int (*cmp)(const void *, const void *))
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
int d, r, swaptype, swap_cnt;
register char *a = aa;
loop: SWAPINIT(a, es);
swap_cnt = 0;
if (n < 7) {
for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
pl -= es)
yswap(pl, pl - es);
return;
}
pm = (char *)a + (n / 2) * es;
if (n > 7) {
pl = (char *)a;
pn = (char *)a + (n - 1) * es;
if (n > 40) {
d = (n / 8) * es;
pl = med3(pl, pl + d, pl + 2 * d, cmp);
pm = med3(pm - d, pm, pm + d, cmp);
pn = med3(pn - 2 * d, pn - d, pn, cmp);
}
pm = med3(pl, pm, pn, cmp);
}
yswap(a, pm);
pa = pb = (char *)a + es;
pc = pd = (char *)a + (n - 1) * es;
for (;;) {
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
if (r == 0) {
swap_cnt = 1;
yswap(pa, pb);
pa += es;
}
pb += es;
}
while (pb <= pc && (r = cmp(pc, a)) >= 0) {
if (r == 0) {
swap_cnt = 1;
yswap(pc, pd);
pd -= es;
}
pc -= es;
}
if (pb > pc)
break;
yswap(pb, pc);
swap_cnt = 1;
pb += es;
pc -= es;
}
if (swap_cnt == 0) { /* Switch to insertion sort */
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
pl -= es)
yswap(pl, pl - es);
return;
}
pn = (char *)a + n * es;
r = min(pa - (char *)a, pb - pa);
vecswap(a, pb - r, r);
r = min((long)(pd - pc), (long)(pn - pd - es));
vecswap(pb, pn - r, r);
r = pb - pa;
if (r > es)
yaffs_qsort(a, r / es, es, cmp);
r = pd - pc;
if (r > es) {
/* Iterate rather than recurse to save stack space */
a = pn - r;
n = r / es;
goto loop;
}
/* yaffs_qsort(pn - r, r / es, es, cmp);*/
}

View File

@ -1,34 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_QSORT_H__
#define __YAFFS_QSORT_H__
#ifdef __KERNEL__
#include <linux/sort.h>
extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
int (*cmp)(const void *, const void *)){
sort(base, total_elems, size, cmp, NULL);
}
#else
extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
int (*cmp)(const void *, const void *));
#endif
#endif

View File

@ -0,0 +1,313 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* Summaries write the useful part of the tags for the chunks in a block into an
* an array which is written to the last n chunks of the block.
* Reading the summaries gives all the tags for the block in one read. Much
* faster.
*
* Chunks holding summaries are marked with tags making it look like
* they are part of a fake file.
*
* The summary could also be used during gc.
*
*/
#include "yaffs_summary.h"
#include "yaffs_packedtags2.h"
#include "yaffs_nand.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_bitmap.h"
/*
* The summary is built up in an array of summary tags.
* This gets written to the last one or two (maybe more) chunks in a block.
* A summary header is written as the first part of each chunk of summary data.
* The summary header must match or the summary is rejected.
*/
/* Summary tags don't need the sequence number because that is redundant. */
struct yaffs_summary_tags {
unsigned obj_id;
unsigned chunk_id;
unsigned n_bytes;
};
/* Summary header */
struct yaffs_summary_header {
unsigned version; /* Must match current version */
unsigned block; /* Must be this block */
unsigned seq; /* Must be this sequence number */
unsigned sum; /* Just add up all the bytes in the tags */
};
static void yaffs_summary_clear(struct yaffs_dev *dev)
{
if (!dev->sum_tags)
return;
memset(dev->sum_tags, 0, dev->chunks_per_summary *
sizeof(struct yaffs_summary_tags));
}
void yaffs_summary_deinit(struct yaffs_dev *dev)
{
kfree(dev->sum_tags);
dev->sum_tags = NULL;
kfree(dev->gc_sum_tags);
dev->gc_sum_tags = NULL;
dev->chunks_per_summary = 0;
}
int yaffs_summary_init(struct yaffs_dev *dev)
{
int sum_bytes;
int chunks_used; /* Number of chunks used by summary */
int sum_tags_bytes;
sum_bytes = dev->param.chunks_per_block *
sizeof(struct yaffs_summary_tags);
chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/
(dev->data_bytes_per_chunk -
sizeof(struct yaffs_summary_header));
dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;
sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
dev->chunks_per_summary;
dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
if (!dev->sum_tags || !dev->gc_sum_tags) {
yaffs_summary_deinit(dev);
return YAFFS_FAIL;
}
yaffs_summary_clear(dev);
return YAFFS_OK;
}
static unsigned yaffs_summary_sum(struct yaffs_dev *dev)
{
u8 *sum_buffer = (u8 *)dev->sum_tags;
int i;
unsigned sum = 0;
i = sizeof(struct yaffs_summary_tags) *
dev->chunks_per_summary;
while (i > 0) {
sum += *sum_buffer;
sum_buffer++;
i--;
}
return sum;
}
static int yaffs_summary_write(struct yaffs_dev *dev, int blk)
{
struct yaffs_ext_tags tags;
u8 *buffer;
u8 *sum_buffer = (u8 *)dev->sum_tags;
int n_bytes;
int chunk_in_nand;
int chunk_in_block;
int result;
int this_tx;
struct yaffs_summary_header hdr;
int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
buffer = yaffs_get_temp_buffer(dev);
n_bytes = sizeof(struct yaffs_summary_tags) *
dev->chunks_per_summary;
memset(&tags, 0, sizeof(struct yaffs_ext_tags));
tags.obj_id = YAFFS_OBJECTID_SUMMARY;
tags.chunk_id = 1;
chunk_in_block = dev->chunks_per_summary;
chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block +
dev->chunks_per_summary;
hdr.version = YAFFS_SUMMARY_VERSION;
hdr.block = blk;
hdr.seq = bi->seq_number;
hdr.sum = yaffs_summary_sum(dev);
do {
this_tx = n_bytes;
if (this_tx > sum_bytes_per_chunk)
this_tx = sum_bytes_per_chunk;
memcpy(buffer, &hdr, sizeof(hdr));
memcpy(buffer + sizeof(hdr), sum_buffer, this_tx);
tags.n_bytes = this_tx + sizeof(hdr);
result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,
buffer, &tags);
if (result != YAFFS_OK)
break;
yaffs_set_chunk_bit(dev, blk, chunk_in_block);
bi->pages_in_use++;
dev->n_free_chunks--;
n_bytes -= this_tx;
sum_buffer += this_tx;
chunk_in_nand++;
chunk_in_block++;
tags.chunk_id++;
} while (result == YAFFS_OK && n_bytes > 0);
yaffs_release_temp_buffer(dev, buffer);
if (result == YAFFS_OK)
bi->has_summary = 1;
return result;
}
int yaffs_summary_read(struct yaffs_dev *dev,
struct yaffs_summary_tags *st,
int blk)
{
struct yaffs_ext_tags tags;
u8 *buffer;
u8 *sum_buffer = (u8 *)st;
int n_bytes;
int chunk_id;
int chunk_in_nand;
int chunk_in_block;
int result;
int this_tx;
struct yaffs_summary_header hdr;
struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
int sum_tags_bytes;
sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
dev->chunks_per_summary;
buffer = yaffs_get_temp_buffer(dev);
n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
chunk_in_block = dev->chunks_per_summary;
chunk_in_nand = blk * dev->param.chunks_per_block +
dev->chunks_per_summary;
chunk_id = 1;
do {
this_tx = n_bytes;
if (this_tx > sum_bytes_per_chunk)
this_tx = sum_bytes_per_chunk;
result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,
buffer, &tags);
if (tags.chunk_id != chunk_id ||
tags.obj_id != YAFFS_OBJECTID_SUMMARY ||
tags.chunk_used == 0 ||
tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
tags.n_bytes != (this_tx + sizeof(hdr)))
result = YAFFS_FAIL;
if (result != YAFFS_OK)
break;
if (st == dev->sum_tags) {
/* If we're scanning then update the block info */
yaffs_set_chunk_bit(dev, blk, chunk_in_block);
bi->pages_in_use++;
}
memcpy(&hdr, buffer, sizeof(hdr));
memcpy(sum_buffer, buffer + sizeof(hdr), this_tx);
n_bytes -= this_tx;
sum_buffer += this_tx;
chunk_in_nand++;
chunk_in_block++;
chunk_id++;
} while (result == YAFFS_OK && n_bytes > 0);
yaffs_release_temp_buffer(dev, buffer);
if (result == YAFFS_OK) {
/* Verify header */
if (hdr.version != YAFFS_SUMMARY_VERSION ||
hdr.block != blk ||
hdr.seq != bi->seq_number ||
hdr.sum != yaffs_summary_sum(dev))
result = YAFFS_FAIL;
}
if (st == dev->sum_tags && result == YAFFS_OK)
bi->has_summary = 1;
return result;
}
int yaffs_summary_add(struct yaffs_dev *dev,
struct yaffs_ext_tags *tags,
int chunk_in_nand)
{
struct yaffs_packed_tags2_tags_only tags_only;
struct yaffs_summary_tags *sum_tags;
int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
if (!dev->sum_tags)
return YAFFS_OK;
if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
yaffs_pack_tags2_tags_only(&tags_only, tags);
sum_tags = &dev->sum_tags[chunk_in_block];
sum_tags->chunk_id = tags_only.chunk_id;
sum_tags->n_bytes = tags_only.n_bytes;
sum_tags->obj_id = tags_only.obj_id;
if (chunk_in_block == dev->chunks_per_summary - 1) {
/* Time to write out the summary */
yaffs_summary_write(dev, block_in_nand);
yaffs_summary_clear(dev);
yaffs_skip_rest_of_block(dev);
}
}
return YAFFS_OK;
}
int yaffs_summary_fetch(struct yaffs_dev *dev,
struct yaffs_ext_tags *tags,
int chunk_in_block)
{
struct yaffs_packed_tags2_tags_only tags_only;
struct yaffs_summary_tags *sum_tags;
if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
sum_tags = &dev->sum_tags[chunk_in_block];
tags_only.chunk_id = sum_tags->chunk_id;
tags_only.n_bytes = sum_tags->n_bytes;
tags_only.obj_id = sum_tags->obj_id;
yaffs_unpack_tags2_tags_only(tags, &tags_only);
return YAFFS_OK;
}
return YAFFS_FAIL;
}
void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
{
struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
int i;
if (!bi->has_summary)
return;
for (i = dev->chunks_per_summary;
i < dev->param.chunks_per_block;
i++) {
if (yaffs_check_chunk_bit(dev, blk, i)) {
yaffs_clear_chunk_bit(dev, blk, i);
bi->pages_in_use--;
dev->n_free_chunks++;
}
}
}

View File

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

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -17,56 +17,16 @@
#include "yaffs_getblockinfo.h" #include "yaffs_getblockinfo.h"
#include "yaffs_trace.h" #include "yaffs_trace.h"
static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk); static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
#ifdef NOTYET
static void yaffs_check_written_block(yaffs_dev_t *dev, int nand_chunk);
static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
const __u8 *data,
const yaffs_spare *spare);
static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
const yaffs_spare *spare);
static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk);
#endif
static const char yaffs_count_bits_table[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
int yaffs_count_bits(__u8 x)
{
int retVal;
retVal = yaffs_count_bits_table[x];
return retVal;
}
/********** Tags ECC calculations *********/ /********** Tags ECC calculations *********/
void yaffs_calc_ecc(const __u8 *data, yaffs_spare *spare)
{
yaffs_ecc_cacl(data, spare->ecc1);
yaffs_ecc_cacl(&data[256], spare->ecc2);
}
void yaffs_calc_tags_ecc(yaffs_tags_t *tags) void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
{ {
/* Calculate an ecc */ /* Calculate an ecc */
unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes;
unsigned i, j; unsigned i, j;
unsigned ecc = 0; unsigned ecc = 0;
unsigned bit = 0; unsigned bit = 0;
@ -80,12 +40,10 @@ void yaffs_calc_tags_ecc(yaffs_tags_t *tags)
ecc ^= bit; ecc ^= bit;
} }
} }
tags->ecc = ecc; tags->ecc = ecc;
} }
int yaffs_check_tags_ecc(yaffs_tags_t *tags) int yaffs_check_tags_ecc(struct yaffs_tags *tags)
{ {
unsigned ecc = tags->ecc; unsigned ecc = tags->ecc;
@ -95,7 +53,7 @@ int yaffs_check_tags_ecc(yaffs_tags_t *tags)
if (ecc && ecc <= 64) { if (ecc && ecc <= 64) {
/* TODO: Handle the failure better. Retire? */ /* TODO: Handle the failure better. Retire? */
unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes; unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
ecc--; ecc--;
@ -110,233 +68,164 @@ int yaffs_check_tags_ecc(yaffs_tags_t *tags)
/* TODO Need to do somethiong here */ /* TODO Need to do somethiong here */
return -1; /* unrecovered error */ return -1; /* unrecovered error */
} }
return 0; return 0;
} }
/********** Tags **********/ /********** Tags **********/
static void yaffs_load_tags_to_spare(yaffs_spare *sparePtr, static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
yaffs_tags_t *tagsPtr) struct yaffs_tags *tags_ptr)
{ {
yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr; union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
yaffs_calc_tags_ecc(tagsPtr); yaffs_calc_tags_ecc(tags_ptr);
sparePtr->tb0 = tu->as_bytes[0]; spare_ptr->tb0 = tu->as_bytes[0];
sparePtr->tb1 = tu->as_bytes[1]; spare_ptr->tb1 = tu->as_bytes[1];
sparePtr->tb2 = tu->as_bytes[2]; spare_ptr->tb2 = tu->as_bytes[2];
sparePtr->tb3 = tu->as_bytes[3]; spare_ptr->tb3 = tu->as_bytes[3];
sparePtr->tb4 = tu->as_bytes[4]; spare_ptr->tb4 = tu->as_bytes[4];
sparePtr->tb5 = tu->as_bytes[5]; spare_ptr->tb5 = tu->as_bytes[5];
sparePtr->tb6 = tu->as_bytes[6]; spare_ptr->tb6 = tu->as_bytes[6];
sparePtr->tb7 = tu->as_bytes[7]; spare_ptr->tb7 = tu->as_bytes[7];
} }
static void yaffs_get_tags_from_spare(yaffs_dev_t *dev, yaffs_spare *sparePtr, static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
yaffs_tags_t *tagsPtr) struct yaffs_spare *spare_ptr,
struct yaffs_tags *tags_ptr)
{ {
yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr; union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
int result; int result;
tu->as_bytes[0] = sparePtr->tb0; tu->as_bytes[0] = spare_ptr->tb0;
tu->as_bytes[1] = sparePtr->tb1; tu->as_bytes[1] = spare_ptr->tb1;
tu->as_bytes[2] = sparePtr->tb2; tu->as_bytes[2] = spare_ptr->tb2;
tu->as_bytes[3] = sparePtr->tb3; tu->as_bytes[3] = spare_ptr->tb3;
tu->as_bytes[4] = sparePtr->tb4; tu->as_bytes[4] = spare_ptr->tb4;
tu->as_bytes[5] = sparePtr->tb5; tu->as_bytes[5] = spare_ptr->tb5;
tu->as_bytes[6] = sparePtr->tb6; tu->as_bytes[6] = spare_ptr->tb6;
tu->as_bytes[7] = sparePtr->tb7; tu->as_bytes[7] = spare_ptr->tb7;
result = yaffs_check_tags_ecc(tagsPtr); result = yaffs_check_tags_ecc(tags_ptr);
if (result > 0) if (result > 0)
dev->n_tags_ecc_fixed++; dev->n_tags_ecc_fixed++;
else if (result < 0) else if (result < 0)
dev->n_tags_ecc_unfixed++; dev->n_tags_ecc_unfixed++;
} }
static void yaffs_spare_init(yaffs_spare *spare) static void yaffs_spare_init(struct yaffs_spare *spare)
{ {
memset(spare, 0xFF, sizeof(yaffs_spare)); memset(spare, 0xff, sizeof(struct yaffs_spare));
} }
static int yaffs_wr_nand(struct yaffs_dev_s *dev, static int yaffs_wr_nand(struct yaffs_dev *dev,
int nand_chunk, const __u8 *data, int nand_chunk, const u8 *data,
yaffs_spare *spare) struct yaffs_spare *spare)
{ {
if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) { int data_size = dev->data_bytes_per_chunk;
T(YAFFS_TRACE_ERROR,
(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
nand_chunk));
return YAFFS_FAIL;
}
return dev->param.write_chunk_fn(dev, nand_chunk, data, spare); return dev->drv.drv_write_chunk_fn(dev, nand_chunk,
data, data_size,
(u8 *) spare, sizeof(*spare));
} }
static int yaffs_rd_chunk_nand(struct yaffs_dev_s *dev, static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
int nand_chunk, int nand_chunk,
__u8 *data, u8 *data,
yaffs_spare *spare, struct yaffs_spare *spare,
yaffs_ecc_result *ecc_result, enum yaffs_ecc_result *ecc_result,
int doErrorCorrection) int correct_errors)
{ {
int retVal; int ret_val;
yaffs_spare localSpare; struct yaffs_spare local_spare;
int data_size;
int spare_size;
int ecc_result1, ecc_result2;
u8 calc_ecc[3];
if (!spare && data) { if (!spare) {
/* If we don't have a real spare, then we use a local one. */ /* If we don't have a real spare, then we use a local one. */
/* Need this for the calculation of the ecc */ /* Need this for the calculation of the ecc */
spare = &localSpare; spare = &local_spare;
}
data_size = dev->data_bytes_per_chunk;
spare_size = sizeof(struct yaffs_spare);
if (dev->param.use_nand_ecc)
return dev->drv.drv_read_chunk_fn(dev, nand_chunk,
data, data_size,
(u8 *) spare, spare_size,
ecc_result);
/* Handle the ECC at this level. */
ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
data, data_size,
(u8 *)spare, spare_size,
NULL);
if (!data || !correct_errors)
return ret_val;
/* Do ECC correction if needed. */
yaffs_ecc_calc(data, calc_ecc);
ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
yaffs_ecc_calc(&data[256], calc_ecc);
ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc);
if (ecc_result1 > 0) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>yaffs ecc error fix performed on chunk %d:0",
nand_chunk);
dev->n_ecc_fixed++;
} else if (ecc_result1 < 0) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>>yaffs ecc error unfixed on chunk %d:0",
nand_chunk);
dev->n_ecc_unfixed++;
} }
if (!dev->param.use_nand_ecc) { if (ecc_result2 > 0) {
retVal = dev->param.read_chunk_fn(dev, nand_chunk, data, spare); yaffs_trace(YAFFS_TRACE_ERROR,
if (data && doErrorCorrection) { "**>>yaffs ecc error fix performed on chunk %d:1",
/* Do ECC correction */ nand_chunk);
/* Todo handle any errors */ dev->n_ecc_fixed++;
int ecc_result1, ecc_result2; } else if (ecc_result2 < 0) {
__u8 calcEcc[3]; yaffs_trace(YAFFS_TRACE_ERROR,
"**>>yaffs ecc error unfixed on chunk %d:1",
yaffs_ecc_cacl(data, calcEcc); nand_chunk);
ecc_result1 = dev->n_ecc_unfixed++;
yaffs_ecc_correct(data, spare->ecc1, calcEcc);
yaffs_ecc_cacl(&data[256], calcEcc);
ecc_result2 =
yaffs_ecc_correct(&data[256], spare->ecc2, calcEcc);
if (ecc_result1 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error fix performed on chunk %d:0"
TENDSTR), nand_chunk));
dev->n_ecc_fixed++;
} else if (ecc_result1 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error unfixed on chunk %d:0"
TENDSTR), nand_chunk));
dev->n_ecc_unfixed++;
}
if (ecc_result2 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error fix performed on chunk %d:1"
TENDSTR), nand_chunk));
dev->n_ecc_fixed++;
} else if (ecc_result2 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error unfixed on chunk %d:1"
TENDSTR), nand_chunk));
dev->n_ecc_unfixed++;
}
if (ecc_result1 || ecc_result2) {
/* We had a data problem on this page */
yaffs_handle_rd_data_error(dev, nand_chunk);
}
if (ecc_result1 < 0 || ecc_result2 < 0)
*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
else if (ecc_result1 > 0 || ecc_result2 > 0)
*ecc_result = YAFFS_ECC_RESULT_FIXED;
else
*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
}
} else {
/* Must allocate enough memory for spare+2*sizeof(int) */
/* for ecc results from device. */
struct yaffs_nand_spare nspare;
memset(&nspare, 0, sizeof(nspare));
retVal = dev->param.read_chunk_fn(dev, nand_chunk, data,
(yaffs_spare *) &nspare);
memcpy(spare, &nspare, sizeof(yaffs_spare));
if (data && doErrorCorrection) {
if (nspare.eccres1 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error fix performed on chunk %d:0"
TENDSTR), nand_chunk));
} else if (nspare.eccres1 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error unfixed on chunk %d:0"
TENDSTR), nand_chunk));
}
if (nspare.eccres2 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error fix performed on chunk %d:1"
TENDSTR), nand_chunk));
} else if (nspare.eccres2 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error unfixed on chunk %d:1"
TENDSTR), nand_chunk));
}
if (nspare.eccres1 || nspare.eccres2) {
/* We had a data problem on this page */
yaffs_handle_rd_data_error(dev, nand_chunk);
}
if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
*ecc_result = YAFFS_ECC_RESULT_FIXED;
else
*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
}
} }
return retVal;
if (ecc_result1 || ecc_result2) {
/* We had a data problem on this page */
yaffs_handle_rd_data_error(dev, nand_chunk);
}
if (ecc_result1 < 0 || ecc_result2 < 0)
*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
else if (ecc_result1 > 0 || ecc_result2 > 0)
*ecc_result = YAFFS_ECC_RESULT_FIXED;
else
*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
return ret_val;
} }
#ifdef NOTYET
static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
int nand_chunk)
{
static int init;
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
static __u8 data[YAFFS_BYTES_PER_CHUNK];
/* Might as well always allocate the larger size for */
/* dev->param.use_nand_ecc == true; */
static __u8 spare[sizeof(struct yaffs_nand_spare)];
dev->param.read_chunk_fn(dev, nand_chunk, data, (yaffs_spare *) spare);
if (!init) {
memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
init = 1;
}
if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
return YAFFS_FAIL;
if (memcmp(cmpbuf, spare, 16))
return YAFFS_FAIL;
return YAFFS_OK;
}
#endif
/* /*
* Functions for robustisizing * Functions for robustisizing
*/ */
static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk) static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
{ {
int flash_block = nand_chunk / dev->param.chunks_per_block; int flash_block = nand_chunk / dev->param.chunks_per_block;
/* Mark the block for retirement */ /* Mark the block for retirement */
yaffs_get_block_info(dev, flash_block + dev->block_offset)->needs_retiring = 1; yaffs_get_block_info(dev, flash_block + dev->block_offset)->
T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, needs_retiring = 1;
(TSTR("**>>Block %d marked for retirement" TENDSTR), flash_block)); yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
"**>>Block %d marked for retirement",
flash_block);
/* TODO: /* TODO:
* Just do a garbage collection on the affected block * Just do a garbage collection on the affected block
@ -345,195 +234,148 @@ static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk)
*/ */
} }
#ifdef NOTYET static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
static void yaffs_check_written_block(yaffs_dev_t *dev, int nand_chunk) int nand_chunk,
const u8 *data, const struct yaffs_ext_tags *ext_tags)
{ {
} struct yaffs_spare spare;
struct yaffs_tags tags;
static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
const __u8 *data,
const yaffs_spare *spare)
{
}
static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
const yaffs_spare *spare)
{
}
static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk)
{
int flash_block = nand_chunk / dev->param.chunks_per_block;
/* Mark the block for retirement */
yaffs_get_block_info(dev, flash_block)->needs_retiring = 1;
/* Delete the chunk */
yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
}
static int yaffs_verify_cmp(const __u8 *d0, const __u8 *d1,
const yaffs_spare *s0, const yaffs_spare *s1)
{
if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
s0->tb0 != s1->tb0 ||
s0->tb1 != s1->tb1 ||
s0->tb2 != s1->tb2 ||
s0->tb3 != s1->tb3 ||
s0->tb4 != s1->tb4 ||
s0->tb5 != s1->tb5 ||
s0->tb6 != s1->tb6 ||
s0->tb7 != s1->tb7 ||
s0->ecc1[0] != s1->ecc1[0] ||
s0->ecc1[1] != s1->ecc1[1] ||
s0->ecc1[2] != s1->ecc1[2] ||
s0->ecc2[0] != s1->ecc2[0] ||
s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
return 0;
}
return 1;
}
#endif /* NOTYET */
int yaffs_tags_compat_wr(yaffs_dev_t *dev,
int nand_chunk,
const __u8 *data,
const yaffs_ext_tags *eTags)
{
yaffs_spare spare;
yaffs_tags_t tags;
yaffs_spare_init(&spare); yaffs_spare_init(&spare);
if (eTags->is_deleted) if (ext_tags->is_deleted)
spare.page_status = 0; spare.page_status = 0;
else { else {
tags.obj_id = eTags->obj_id; tags.obj_id = ext_tags->obj_id;
tags.chunk_id = eTags->chunk_id; tags.chunk_id = ext_tags->chunk_id;
tags.n_bytes_lsb = eTags->n_bytes & 0x3ff; tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
if (dev->data_bytes_per_chunk >= 1024) if (dev->data_bytes_per_chunk >= 1024)
tags.n_bytes_msb = (eTags->n_bytes >> 10) & 3; tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
else else
tags.n_bytes_msb = 3; tags.n_bytes_msb = 3;
tags.serial_number = ext_tags->serial_number;
tags.serial_number = eTags->serial_number; if (!dev->param.use_nand_ecc && data) {
yaffs_ecc_calc(data, spare.ecc1);
if (!dev->param.use_nand_ecc && data) yaffs_ecc_calc(&data[256], spare.ecc2);
yaffs_calc_ecc(data, &spare); }
yaffs_load_tags_to_spare(&spare, &tags); yaffs_load_tags_to_spare(&spare, &tags);
} }
return yaffs_wr_nand(dev, nand_chunk, data, &spare); return yaffs_wr_nand(dev, nand_chunk, data, &spare);
} }
int yaffs_tags_compat_rd(yaffs_dev_t *dev, static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
int nand_chunk, int nand_chunk,
__u8 *data, u8 *data, struct yaffs_ext_tags *ext_tags)
yaffs_ext_tags *eTags)
{ {
struct yaffs_spare spare;
yaffs_spare spare; struct yaffs_tags tags;
yaffs_tags_t tags; enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN; static struct yaffs_spare spare_ff;
static yaffs_spare spareFF;
static int init; static int init;
int deleted;
if (!init) { if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF)); memset(&spare_ff, 0xff, sizeof(spare_ff));
init = 1; init = 1;
} }
if (yaffs_rd_chunk_nand if (!yaffs_rd_chunk_nand(dev, nand_chunk,
(dev, nand_chunk, data, &spare, &ecc_result, 1)) { data, &spare, &ecc_result, 1))
/* eTags may be NULL */
if (eTags) {
int deleted =
(yaffs_count_bits(spare.page_status) < 7) ? 1 : 0;
eTags->is_deleted = deleted;
eTags->ecc_result = ecc_result;
eTags->block_bad = 0; /* We're reading it */
/* therefore it is not a bad block */
eTags->chunk_used =
(memcmp(&spareFF, &spare, sizeof(spareFF)) !=
0) ? 1 : 0;
if (eTags->chunk_used) {
yaffs_get_tags_from_spare(dev, &spare, &tags);
eTags->obj_id = tags.obj_id;
eTags->chunk_id = tags.chunk_id;
eTags->n_bytes = tags.n_bytes_lsb;
if (dev->data_bytes_per_chunk >= 1024)
eTags->n_bytes |= (((unsigned) tags.n_bytes_msb) << 10);
eTags->serial_number = tags.serial_number;
}
}
return YAFFS_OK;
} else {
return YAFFS_FAIL; return YAFFS_FAIL;
/* ext_tags may be NULL */
if (!ext_tags)
return YAFFS_OK;
deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
ext_tags->is_deleted = deleted;
ext_tags->ecc_result = ecc_result;
ext_tags->block_bad = 0; /* We're reading it */
/* therefore it is not a bad block */
ext_tags->chunk_used =
memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;
if (ext_tags->chunk_used) {
yaffs_get_tags_from_spare(dev, &spare, &tags);
ext_tags->obj_id = tags.obj_id;
ext_tags->chunk_id = tags.chunk_id;
ext_tags->n_bytes = tags.n_bytes_lsb;
if (dev->data_bytes_per_chunk >= 1024)
ext_tags->n_bytes |=
(((unsigned)tags.n_bytes_msb) << 10);
ext_tags->serial_number = tags.serial_number;
} }
return YAFFS_OK;
} }
int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev, static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
int flash_block)
{ {
struct yaffs_spare spare;
yaffs_spare spare; memset(&spare, 0xff, sizeof(struct yaffs_spare));
memset(&spare, 0xff, sizeof(yaffs_spare));
spare.block_status = 'Y'; spare.block_status = 'Y';
yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL, yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
&spare); &spare);
yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1, yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
NULL, &spare); NULL, &spare);
return YAFFS_OK; return YAFFS_OK;
} }
int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev, static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
int block_no, int block_no,
yaffs_block_state_t *state, enum yaffs_block_state *state,
__u32 *seq_number) u32 *seq_number)
{ {
struct yaffs_spare spare0, spare1;
yaffs_spare spare0, spare1; static struct yaffs_spare spare_ff;
static yaffs_spare spareFF;
static int init; static int init;
yaffs_ecc_result dummy; enum yaffs_ecc_result dummy;
if (!init) { if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF)); memset(&spare_ff, 0xff, sizeof(spare_ff));
init = 1; init = 1;
} }
*seq_number = 0; *seq_number = 0;
yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL, /* Look for bad block markers in the first two chunks */
&spare0, &dummy, 1); yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block,
yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, NULL, NULL, &spare0, &dummy, 0);
&spare1, &dummy, 1); yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
NULL, &spare1, &dummy, 0);
if (yaffs_count_bits(spare0.block_status & spare1.block_status) < 7) if (hweight8(spare0.block_status & spare1.block_status) < 7)
*state = YAFFS_BLOCK_STATE_DEAD; *state = YAFFS_BLOCK_STATE_DEAD;
else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0) else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
*state = YAFFS_BLOCK_STATE_EMPTY; *state = YAFFS_BLOCK_STATE_EMPTY;
else else
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
return YAFFS_OK; return YAFFS_OK;
} }
void yaffs_tags_compat_install(struct yaffs_dev *dev)
{
if(dev->param.is_yaffs2)
return;
if(!dev->tagger.write_chunk_tags_fn)
dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr;
if(!dev->tagger.read_chunk_tags_fn)
dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd;
if(!dev->tagger.query_block_fn)
dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
if(!dev->tagger.mark_bad_fn)
dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
}

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -16,24 +16,29 @@
#ifndef __YAFFS_TAGSCOMPAT_H__ #ifndef __YAFFS_TAGSCOMPAT_H__
#define __YAFFS_TAGSCOMPAT_H__ #define __YAFFS_TAGSCOMPAT_H__
#include "yaffs_guts.h"
int yaffs_tags_compat_wr(yaffs_dev_t *dev,
int nand_chunk,
const __u8 *data,
const yaffs_ext_tags *tags);
int yaffs_tags_compat_rd(yaffs_dev_t *dev,
int nand_chunk,
__u8 *data,
yaffs_ext_tags *tags);
int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev,
int block_no);
int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev,
int block_no,
yaffs_block_state_t *state,
__u32 *seq_number);
void yaffs_calc_tags_ecc(yaffs_tags_t *tags); #include "yaffs_guts.h"
int yaffs_check_tags_ecc(yaffs_tags_t *tags);
int yaffs_count_bits(__u8 byte); #if 0
int yaffs_tags_compat_wr(struct yaffs_dev *dev,
int nand_chunk,
const u8 *data, const struct yaffs_ext_tags *tags);
int yaffs_tags_compat_rd(struct yaffs_dev *dev,
int nand_chunk,
u8 *data, struct yaffs_ext_tags *tags);
int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
int block_no,
enum yaffs_block_state *state,
u32 *seq_number);
#endif
void yaffs_tags_compat_install(struct yaffs_dev *dev);
void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
int yaffs_check_tags_ecc(struct yaffs_tags *tags);
#endif #endif

View File

@ -0,0 +1,199 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_guts.h"
#include "yaffs_trace.h"
#include "yaffs_packedtags2.h"
static int yaffs_tags_marshall_write(struct yaffs_dev *dev,
int nand_chunk, const u8 *data,
const struct yaffs_ext_tags *tags)
{
struct yaffs_packed_tags2 pt;
int retval;
int packed_tags_size =
dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
void *packed_tags_ptr =
dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
yaffs_trace(YAFFS_TRACE_MTD,
"yaffs_tags_marshall_write chunk %d data %p tags %p",
nand_chunk, data, tags);
/* For yaffs2 writing there must be both data and tags.
* If we're using inband tags, then the tags are stuffed into
* the end of the data buffer.
*/
if (!data || !tags)
BUG();
else if (dev->param.inband_tags) {
struct yaffs_packed_tags2_tags_only *pt2tp;
pt2tp =
(struct yaffs_packed_tags2_tags_only *)(data +
dev->
data_bytes_per_chunk);
yaffs_pack_tags2_tags_only(pt2tp, tags);
} else {
yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
}
retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
data, dev->param.total_bytes_per_chunk,
(dev->param.inband_tags) ? NULL : packed_tags_ptr,
(dev->param.inband_tags) ? 0 : packed_tags_size);
return retval;
}
static int yaffs_tags_marshall_read(struct yaffs_dev *dev,
int nand_chunk, u8 *data,
struct yaffs_ext_tags *tags)
{
int retval = 0;
int local_data = 0;
u8 spare_buffer[100];
enum yaffs_ecc_result ecc_result;
struct yaffs_packed_tags2 pt;
int packed_tags_size =
dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
void *packed_tags_ptr =
dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
yaffs_trace(YAFFS_TRACE_MTD,
"yaffs_tags_marshall_read chunk %d data %p tags %p",
nand_chunk, data, tags);
if (dev->param.inband_tags) {
if (!data) {
local_data = 1;
data = yaffs_get_temp_buffer(dev);
}
}
if (dev->param.inband_tags || (data && !tags))
retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
data, dev->param.total_bytes_per_chunk,
NULL, 0,
&ecc_result);
else if (tags)
retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
data, dev->param.total_bytes_per_chunk,
spare_buffer, packed_tags_size,
&ecc_result);
else
BUG();
if (dev->param.inband_tags) {
if (tags) {
struct yaffs_packed_tags2_tags_only *pt2tp;
pt2tp =
(struct yaffs_packed_tags2_tags_only *)
&data[dev->data_bytes_per_chunk];
yaffs_unpack_tags2_tags_only(tags, pt2tp);
}
} else if (tags) {
memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);
yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
}
if (local_data)
yaffs_release_temp_buffer(dev, data);
if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
dev->n_ecc_unfixed++;
}
if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) {
if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR)
tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
dev->n_ecc_fixed++;
}
if (ecc_result < YAFFS_ECC_RESULT_UNFIXED)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no,
enum yaffs_block_state *state,
u32 *seq_number)
{
int retval;
yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d",
block_no);
retval = dev->drv.drv_check_bad_fn(dev, block_no);
if (retval== YAFFS_FAIL) {
yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
*state = YAFFS_BLOCK_STATE_DEAD;
*seq_number = 0;
} else {
struct yaffs_ext_tags t;
yaffs_tags_marshall_read(dev,
block_no * dev->param.chunks_per_block,
NULL, &t);
if (t.chunk_used) {
*seq_number = t.seq_number;
*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
} else {
*seq_number = 0;
*state = YAFFS_BLOCK_STATE_EMPTY;
}
}
yaffs_trace(YAFFS_TRACE_MTD,
"block query returns seq %d state %d",
*seq_number, *state);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no)
{
return dev->drv.drv_mark_bad_fn(dev, block_no);
}
void yaffs_tags_marshall_install(struct yaffs_dev *dev)
{
if (!dev->param.is_yaffs2)
return;
if (!dev->tagger.write_chunk_tags_fn)
dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write;
if (!dev->tagger.read_chunk_tags_fn)
dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read;
if (!dev->tagger.query_block_fn)
dev->tagger.query_block_fn = yaffs_tags_marshall_query_block;
if (!dev->tagger.mark_bad_fn)
dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad;
}

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -13,9 +13,10 @@
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/ */
#ifndef __YAFFSINTERFACE_H__ #ifndef __YAFFS_TAGSMARSHALL_H__
#define __YAFFSINTERFACE_H__ #define __YAFFS_TAGSMARSHALL_H__
int yaffs_initialise(unsigned nBlocks); #include "yaffs_guts.h"
void yaffs_tags_marshall_install(struct yaffs_dev *dev);
#endif #endif

View File

@ -1,28 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2010 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_tagsvalidity.h"
void yaffs_init_tags(yaffs_ext_tags *tags)
{
memset(tags, 0, sizeof(yaffs_ext_tags));
tags->validity1 = 0xAAAAAAAA;
tags->validty1 = 0x55555555;
}
int yaffs_validate_tags(yaffs_ext_tags *tags)
{
return (tags->validity1 == 0xAAAAAAAA &&
tags->validty1 == 0x55555555);
}

View File

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

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -13,7 +13,6 @@
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/ */
#ifndef __YTRACE_H__ #ifndef __YTRACE_H__
#define __YTRACE_H__ #define __YTRACE_H__
@ -44,17 +43,15 @@ extern unsigned int yaffs_wr_attempts;
#define YAFFS_TRACE_VERIFY 0x00010000 #define YAFFS_TRACE_VERIFY 0x00010000
#define YAFFS_TRACE_VERIFY_NAND 0x00020000 #define YAFFS_TRACE_VERIFY_NAND 0x00020000
#define YAFFS_TRACE_VERIFY_FULL 0x00040000 #define YAFFS_TRACE_VERIFY_FULL 0x00040000
#define YAFFS_TRACE_VERIFY_ALL 0x000F0000 #define YAFFS_TRACE_VERIFY_ALL 0x000f0000
#define YAFFS_TRACE_SYNC 0x00100000 #define YAFFS_TRACE_SYNC 0x00100000
#define YAFFS_TRACE_BACKGROUND 0x00200000 #define YAFFS_TRACE_BACKGROUND 0x00200000
#define YAFFS_TRACE_LOCK 0x00400000 #define YAFFS_TRACE_LOCK 0x00400000
#define YAFFS_TRACE_MOUNT 0x00800000
#define YAFFS_TRACE_ERROR 0x40000000 #define YAFFS_TRACE_ERROR 0x40000000
#define YAFFS_TRACE_BUG 0x80000000 #define YAFFS_TRACE_BUG 0x80000000
#define YAFFS_TRACE_ALWAYS 0xF0000000 #define YAFFS_TRACE_ALWAYS 0xf0000000
#define T(mask, p) do { if ((mask) & (yaffs_trace_mask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
#endif #endif

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -11,271 +11,229 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include "yaffs_verify.h" #include "yaffs_verify.h"
#include "yaffs_trace.h" #include "yaffs_trace.h"
#include "yaffs_bitmap.h" #include "yaffs_bitmap.h"
#include "yaffs_getblockinfo.h" #include "yaffs_getblockinfo.h"
#include "yaffs_nand.h" #include "yaffs_nand.h"
int yaffs_skip_verification(yaffs_dev_t *dev) int yaffs_skip_verification(struct yaffs_dev *dev)
{ {
dev=dev; (void) dev;
return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); return !(yaffs_trace_mask &
(YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
} }
static int yaffs_skip_full_verification(yaffs_dev_t *dev) static int yaffs_skip_full_verification(struct yaffs_dev *dev)
{ {
dev=dev; (void) dev;
return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL)); return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
} }
static int yaffs_skip_nand_verification(yaffs_dev_t *dev) static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
{ {
dev=dev; (void) dev;
return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND)); return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
} }
static const char * const block_state_name[] = {
static const char *block_stateName[] = { "Unknown",
"Unknown", "Needs scan",
"Needs scanning", "Scanning",
"Scanning", "Empty",
"Empty", "Allocating",
"Allocating", "Full",
"Full", "Dirty",
"Dirty", "Checkpoint",
"Checkpoint", "Collecting",
"Collecting", "Dead"
"Dead"
}; };
void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
void yaffs_verify_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n)
{ {
int actuallyUsed; int actually_used;
int inUse; int in_use;
if (yaffs_skip_verification(dev)) if (yaffs_skip_verification(dev))
return; return;
/* Report illegal runtime states */ /* Report illegal runtime states */
if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES) if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->block_state)); yaffs_trace(YAFFS_TRACE_VERIFY,
"Block %d has undefined state %d",
n, bi->block_state);
switch (bi->block_state) { switch (bi->block_state) {
case YAFFS_BLOCK_STATE_UNKNOWN: case YAFFS_BLOCK_STATE_UNKNOWN:
case YAFFS_BLOCK_STATE_SCANNING: case YAFFS_BLOCK_STATE_SCANNING:
case YAFFS_BLOCK_STATE_NEEDS_SCANNING: case YAFFS_BLOCK_STATE_NEEDS_SCAN:
T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR), yaffs_trace(YAFFS_TRACE_VERIFY,
n, block_stateName[bi->block_state])); "Block %d has bad run-state %s",
n, block_state_name[bi->block_state]);
} }
/* Check pages in use and soft deletions are legal */ /* Check pages in use and soft deletions are legal */
actuallyUsed = bi->pages_in_use - bi->soft_del_pages; actually_used = bi->pages_in_use - bi->soft_del_pages;
if (bi->pages_in_use < 0 || bi->pages_in_use > dev->param.chunks_per_block ||
bi->soft_del_pages < 0 || bi->soft_del_pages > dev->param.chunks_per_block ||
actuallyUsed < 0 || actuallyUsed > dev->param.chunks_per_block)
T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pages_in_used %d soft_del_pages %d"TENDSTR),
n, bi->pages_in_use, bi->soft_del_pages));
if (bi->pages_in_use < 0 ||
bi->pages_in_use > dev->param.chunks_per_block ||
bi->soft_del_pages < 0 ||
bi->soft_del_pages > dev->param.chunks_per_block ||
actually_used < 0 || actually_used > dev->param.chunks_per_block)
yaffs_trace(YAFFS_TRACE_VERIFY,
"Block %d has illegal values pages_in_used %d soft_del_pages %d",
n, bi->pages_in_use, bi->soft_del_pages);
/* Check chunk bitmap legal */ /* Check chunk bitmap legal */
inUse = yaffs_count_chunk_bits(dev, n); in_use = yaffs_count_chunk_bits(dev, n);
if (inUse != bi->pages_in_use) if (in_use != bi->pages_in_use)
T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pages_in_use %d counted chunk bits %d"TENDSTR), yaffs_trace(YAFFS_TRACE_VERIFY,
n, bi->pages_in_use, inUse)); "Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
n, bi->pages_in_use, in_use);
} }
void yaffs_verify_collected_blk(struct yaffs_dev *dev,
struct yaffs_block_info *bi, int n)
void yaffs_verify_collected_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n)
{ {
yaffs_verify_blk(dev, bi, n); yaffs_verify_blk(dev, bi, n);
/* After collection the block should be in the erased state */ /* After collection the block should be in the erased state */
if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING && if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
bi->block_state != YAFFS_BLOCK_STATE_EMPTY) { bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), yaffs_trace(YAFFS_TRACE_ERROR,
n, bi->block_state)); "Block %d is in state %d after gc, should be erased",
n, bi->block_state);
} }
} }
void yaffs_verify_blocks(yaffs_dev_t *dev) void yaffs_verify_blocks(struct yaffs_dev *dev)
{ {
int i; int i;
int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
int nIllegalBlockStates = 0; int illegal_states = 0;
if (yaffs_skip_verification(dev)) if (yaffs_skip_verification(dev))
return; return;
memset(nBlocksPerState, 0, sizeof(nBlocksPerState)); memset(state_count, 0, sizeof(state_count));
for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
yaffs_block_info_t *bi = yaffs_get_block_info(dev, i); struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
yaffs_verify_blk(dev, bi, i); yaffs_verify_blk(dev, bi, i);
if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES) if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
nBlocksPerState[bi->block_state]++; state_count[bi->block_state]++;
else else
nIllegalBlockStates++; illegal_states++;
} }
T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary");
T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates)); yaffs_trace(YAFFS_TRACE_VERIFY,
if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) "%d blocks have illegal states",
T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR))); illegal_states);
if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
yaffs_trace(YAFFS_TRACE_VERIFY,
"Too many allocating blocks");
for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
T(YAFFS_TRACE_VERIFY, yaffs_trace(YAFFS_TRACE_VERIFY,
(TSTR("%s %d blocks"TENDSTR), "%s %d blocks",
block_stateName[i], nBlocksPerState[i])); block_state_name[i], state_count[i]);
if (dev->blocks_in_checkpt != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
T(YAFFS_TRACE_VERIFY, yaffs_trace(YAFFS_TRACE_VERIFY,
(TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), "Checkpoint block count wrong dev %d count %d",
dev->blocks_in_checkpt, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); dev->blocks_in_checkpt,
state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
if (dev->n_erased_blocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
T(YAFFS_TRACE_VERIFY, yaffs_trace(YAFFS_TRACE_VERIFY,
(TSTR("Erased block count wrong dev %d count %d"TENDSTR), "Erased block count wrong dev %d count %d",
dev->n_erased_blocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); dev->n_erased_blocks,
state_count[YAFFS_BLOCK_STATE_EMPTY]);
if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
T(YAFFS_TRACE_VERIFY,
(TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
yaffs_trace(YAFFS_TRACE_VERIFY,
"Too many collecting blocks %d (max is 1)",
state_count[YAFFS_BLOCK_STATE_COLLECTING]);
} }
/* /*
* Verify the object header. oh must be valid, but obj and tags may be NULL in which * Verify the object header. oh must be valid, but obj and tags may be NULL in
* case those tests will not be performed. * which case those tests will not be performed.
*/ */
void yaffs_verify_oh(yaffs_obj_t *obj, yaffs_obj_header *oh, yaffs_ext_tags *tags, int parentCheck) void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
struct yaffs_ext_tags *tags, int parent_check)
{ {
if (obj && yaffs_skip_verification(obj->my_dev)) if (obj && yaffs_skip_verification(obj->my_dev))
return; return;
if (!(tags && obj && oh)) { if (!(tags && obj && oh)) {
T(YAFFS_TRACE_VERIFY, yaffs_trace(YAFFS_TRACE_VERIFY,
(TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR), "Verifying object header tags %p obj %p oh %p",
tags, obj, oh)); tags, obj, oh);
return; return;
} }
if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
oh->type > YAFFS_OBJECT_TYPE_MAX) oh->type > YAFFS_OBJECT_TYPE_MAX)
T(YAFFS_TRACE_VERIFY, yaffs_trace(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), "Obj %d header type is illegal value 0x%x",
tags->obj_id, oh->type)); tags->obj_id, oh->type);
if (tags->obj_id != obj->obj_id) if (tags->obj_id != obj->obj_id)
T(YAFFS_TRACE_VERIFY, yaffs_trace(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d header mismatch obj_id %d"TENDSTR), "Obj %d header mismatch obj_id %d",
tags->obj_id, obj->obj_id)); tags->obj_id, obj->obj_id);
/* /*
* Check that the object's parent ids match if parentCheck requested. * Check that the object's parent ids match if parent_check requested.
* *
* Tests do not apply to the root object. * Tests do not apply to the root object.
*/ */
if (parentCheck && tags->obj_id > 1 && !obj->parent) if (parent_check && tags->obj_id > 1 && !obj->parent)
T(YAFFS_TRACE_VERIFY, yaffs_trace(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d header mismatch parent_id %d obj->parent is NULL"TENDSTR), "Obj %d header mismatch parent_id %d obj->parent is NULL",
tags->obj_id, oh->parent_obj_id)); tags->obj_id, oh->parent_obj_id);
if (parentCheck && obj->parent && if (parent_check && obj->parent &&
oh->parent_obj_id != obj->parent->obj_id && oh->parent_obj_id != obj->parent->obj_id &&
(oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED || (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
obj->parent->obj_id != YAFFS_OBJECTID_DELETED)) obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
T(YAFFS_TRACE_VERIFY, yaffs_trace(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d header mismatch parent_id %d parent_obj_id %d"TENDSTR), "Obj %d header mismatch parent_id %d parent_obj_id %d",
tags->obj_id, oh->parent_obj_id, obj->parent->obj_id)); tags->obj_id, oh->parent_obj_id,
obj->parent->obj_id);
if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */ if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
T(YAFFS_TRACE_VERIFY, yaffs_trace(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d header name is NULL"TENDSTR), "Obj %d header name is NULL",
obj->obj_id)); obj->obj_id);
if (tags->obj_id > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */
T(YAFFS_TRACE_VERIFY, yaffs_trace(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d header name is 0xFF"TENDSTR), "Obj %d header name is 0xff",
obj->obj_id)); obj->obj_id);
} }
void yaffs_verify_file(struct yaffs_obj *obj)
#if 0
/* Not being used, but don't want to throw away yet */
int yaffs_verify_tnode_worker(yaffs_obj_t *obj, yaffs_tnode_t *tn,
__u32 level, int chunk_offset)
{ {
int i; u32 x;
yaffs_dev_t *dev = obj->my_dev; int required_depth;
int ok = 1; int actual_depth;
int last_chunk;
u32 offset_in_chunk;
u32 the_chunk;
if (tn) { u32 i;
if (level > 0) { struct yaffs_dev *dev;
struct yaffs_ext_tags tags;
for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { struct yaffs_tnode *tn;
if (tn->internal[i]) { u32 obj_id;
ok = yaffs_verify_tnode_worker(obj,
tn->internal[i],
level - 1,
(chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i);
}
}
} else if (level == 0) {
yaffs_ext_tags tags;
__u32 obj_id = obj->obj_id;
chunk_offset <<= YAFFS_TNODES_LEVEL0_BITS;
for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
__u32 theChunk = yaffs_get_group_base(dev, tn, i);
if (theChunk > 0) {
/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.obj_id,tags.chunk_id,theChunk)); */
yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags);
if (tags.obj_id != obj_id || tags.chunk_id != chunk_offset) {
T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
obj_id, chunk_offset, theChunk,
tags.obj_id, tags.chunk_id));
}
}
chunk_offset++;
}
}
}
return ok;
}
#endif
void yaffs_verify_file(yaffs_obj_t *obj)
{
int requiredTallness;
int actualTallness;
__u32 lastChunk;
__u32 x;
__u32 i;
yaffs_dev_t *dev;
yaffs_ext_tags tags;
yaffs_tnode_t *tn;
__u32 obj_id;
if (!obj) if (!obj)
return; return;
@ -286,16 +244,19 @@ void yaffs_verify_file(yaffs_obj_t *obj)
dev = obj->my_dev; dev = obj->my_dev;
obj_id = obj->obj_id; obj_id = obj->obj_id;
/* Check file size is consistent with tnode depth */ /* Check file size is consistent with tnode depth */
lastChunk = obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1; yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; &last_chunk, &offset_in_chunk);
requiredTallness = 0; last_chunk++;
x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
required_depth = 0;
while (x > 0) { while (x > 0) {
x >>= YAFFS_TNODES_INTERNAL_BITS; x >>= YAFFS_TNODES_INTERNAL_BITS;
requiredTallness++; required_depth++;
} }
actualTallness = obj->variant.file_variant.top_level; actual_depth = obj->variant.file_variant.top_level;
/* Check that the chunks in the tnode tree are all correct. /* Check that the chunks in the tnode tree are all correct.
* We do this by scanning through the tnode tree and * We do this by scanning through the tnode tree and
@ -305,26 +266,26 @@ void yaffs_verify_file(yaffs_obj_t *obj)
if (yaffs_skip_nand_verification(dev)) if (yaffs_skip_nand_verification(dev))
return; return;
for (i = 1; i <= lastChunk; i++) { for (i = 1; i <= last_chunk; i++) {
tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i); tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
if (tn) { if (!tn)
__u32 theChunk = yaffs_get_group_base(dev, tn, i); continue;
if (theChunk > 0) {
/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),obj_id,i,theChunk)); */ the_chunk = yaffs_get_group_base(dev, tn, i);
yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags); if (the_chunk > 0) {
if (tags.obj_id != obj_id || tags.chunk_id != i) { yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), &tags);
obj_id, i, theChunk, if (tags.obj_id != obj_id || tags.chunk_id != i)
tags.obj_id, tags.chunk_id)); yaffs_trace(YAFFS_TRACE_VERIFY,
} "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
} obj_id, i, the_chunk,
tags.obj_id, tags.chunk_id);
} }
} }
} }
void yaffs_verify_link(struct yaffs_obj *obj)
void yaffs_verify_link(yaffs_obj_t *obj)
{ {
if (obj && yaffs_skip_verification(obj->my_dev)) if (obj && yaffs_skip_verification(obj->my_dev))
return; return;
@ -332,7 +293,7 @@ void yaffs_verify_link(yaffs_obj_t *obj)
/* Verify sane equivalent object */ /* Verify sane equivalent object */
} }
void yaffs_verify_symlink(yaffs_obj_t *obj) void yaffs_verify_symlink(struct yaffs_obj *obj)
{ {
if (obj && yaffs_skip_verification(obj->my_dev)) if (obj && yaffs_skip_verification(obj->my_dev))
return; return;
@ -340,23 +301,21 @@ void yaffs_verify_symlink(yaffs_obj_t *obj)
/* Verify symlink string */ /* Verify symlink string */
} }
void yaffs_verify_special(yaffs_obj_t *obj) void yaffs_verify_special(struct yaffs_obj *obj)
{ {
if (obj && yaffs_skip_verification(obj->my_dev)) if (obj && yaffs_skip_verification(obj->my_dev))
return; return;
} }
void yaffs_verify_obj(yaffs_obj_t *obj) void yaffs_verify_obj(struct yaffs_obj *obj)
{ {
yaffs_dev_t *dev; struct yaffs_dev *dev;
u32 chunk_min;
__u32 chunkMin; u32 chunk_max;
__u32 chunkMax; u32 chunk_id_ok;
u32 chunk_in_range;
__u32 chunk_idOk; u32 chunk_wrongly_deleted;
__u32 chunkInRange; u32 chunk_valid;
__u32 chunkShouldNotBeDeleted;
__u32 chunkValid;
if (!obj) if (!obj)
return; return;
@ -371,54 +330,53 @@ void yaffs_verify_obj(yaffs_obj_t *obj)
/* Check sane object header chunk */ /* Check sane object header chunk */
chunkMin = dev->internal_start_block * dev->param.chunks_per_block; chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
chunkMax = (dev->internal_end_block+1) * dev->param.chunks_per_block - 1; chunk_max =
(dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
chunkInRange = (((unsigned)(obj->hdr_chunk)) >= chunkMin && ((unsigned)(obj->hdr_chunk)) <= chunkMax); chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
chunk_idOk = chunkInRange || (obj->hdr_chunk == 0); ((unsigned)(obj->hdr_chunk)) <= chunk_max);
chunkValid = chunkInRange && chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
yaffs_check_chunk_bit(dev, chunk_valid = chunk_in_range &&
obj->hdr_chunk / dev->param.chunks_per_block, yaffs_check_chunk_bit(dev,
obj->hdr_chunk % dev->param.chunks_per_block); obj->hdr_chunk / dev->param.chunks_per_block,
chunkShouldNotBeDeleted = chunkInRange && !chunkValid; obj->hdr_chunk % dev->param.chunks_per_block);
chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
if (!obj->fake && if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
(!chunk_idOk || chunkShouldNotBeDeleted)) { yaffs_trace(YAFFS_TRACE_VERIFY,
T(YAFFS_TRACE_VERIFY, "Obj %d has chunk_id %d %s %s",
(TSTR("Obj %d has chunk_id %d %s %s"TENDSTR),
obj->obj_id, obj->hdr_chunk, obj->obj_id, obj->hdr_chunk,
chunk_idOk ? "" : ",out of range", chunk_id_ok ? "" : ",out of range",
chunkShouldNotBeDeleted ? ",marked as deleted" : "")); chunk_wrongly_deleted ? ",marked as deleted" : "");
}
if (chunkValid && !yaffs_skip_nand_verification(dev)) { if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
yaffs_ext_tags tags; struct yaffs_ext_tags tags;
yaffs_obj_header *oh; struct yaffs_obj_hdr *oh;
__u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__); u8 *buffer = yaffs_get_temp_buffer(dev);
oh = (yaffs_obj_header *)buffer; oh = (struct yaffs_obj_hdr *)buffer;
yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
&tags);
yaffs_verify_oh(obj, oh, &tags, 1); yaffs_verify_oh(obj, oh, &tags, 1);
yaffs_release_temp_buffer(dev, buffer, __LINE__); yaffs_release_temp_buffer(dev, buffer);
} }
/* Verify it has a parent */ /* Verify it has a parent */
if (obj && !obj->fake && if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
(!obj->parent || obj->parent->my_dev != dev)) { yaffs_trace(YAFFS_TRACE_VERIFY,
T(YAFFS_TRACE_VERIFY, "Obj %d has parent pointer %p which does not look like an object",
(TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), obj->obj_id, obj->parent);
obj->obj_id, obj->parent));
} }
/* Verify parent is a directory */ /* Verify parent is a directory */
if (obj->parent && obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { if (obj->parent &&
T(YAFFS_TRACE_VERIFY, obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
(TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), yaffs_trace(YAFFS_TRACE_VERIFY,
obj->obj_id, obj->parent->variant_type)); "Obj %d's parent is not a directory (type %d)",
obj->obj_id, obj->parent->variant_type);
} }
switch (obj->variant_type) { switch (obj->variant_type) {
@ -439,45 +397,41 @@ void yaffs_verify_obj(yaffs_obj_t *obj)
break; break;
case YAFFS_OBJECT_TYPE_UNKNOWN: case YAFFS_OBJECT_TYPE_UNKNOWN:
default: default:
T(YAFFS_TRACE_VERIFY, yaffs_trace(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d has illegaltype %d"TENDSTR), "Obj %d has illegaltype %d",
obj->obj_id, obj->variant_type)); obj->obj_id, obj->variant_type);
break; break;
} }
} }
void yaffs_verify_objects(yaffs_dev_t *dev) void yaffs_verify_objects(struct yaffs_dev *dev)
{ {
yaffs_obj_t *obj; struct yaffs_obj *obj;
int i; int i;
struct ylist_head *lh; struct list_head *lh;
if (yaffs_skip_verification(dev)) if (yaffs_skip_verification(dev))
return; return;
/* Iterate through the objects in each hash entry */ /* Iterate through the objects in each hash entry */
for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
ylist_for_each(lh, &dev->obj_bucket[i].list) { list_for_each(lh, &dev->obj_bucket[i].list) {
if (lh) { obj = list_entry(lh, struct yaffs_obj, hash_link);
obj = ylist_entry(lh, yaffs_obj_t, hash_link); yaffs_verify_obj(obj);
yaffs_verify_obj(obj);
}
} }
} }
} }
void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
void yaffs_verify_obj_in_dir(yaffs_obj_t *obj)
{ {
struct ylist_head *lh; struct list_head *lh;
yaffs_obj_t *listObj; struct yaffs_obj *list_obj;
int count = 0; int count = 0;
if (!obj) { if (!obj) {
T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR))); yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
YBUG(); BUG();
return; return;
} }
@ -485,40 +439,40 @@ void yaffs_verify_obj_in_dir(yaffs_obj_t *obj)
return; return;
if (!obj->parent) { if (!obj->parent) {
T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR))); yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
YBUG(); BUG();
return; return;
} }
if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR))); yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
YBUG(); BUG();
} }
/* Iterate through the objects in each hash entry */ /* Iterate through the objects in each hash entry */
ylist_for_each(lh, &obj->parent->variant.dir_variant.children) { list_for_each(lh, &obj->parent->variant.dir_variant.children) {
if (lh) { list_obj = list_entry(lh, struct yaffs_obj, siblings);
listObj = ylist_entry(lh, yaffs_obj_t, siblings); yaffs_verify_obj(list_obj);
yaffs_verify_obj(listObj); if (obj == list_obj)
if (obj == listObj) count++;
count++; }
}
}
if (count != 1) { if (count != 1) {
T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count)); yaffs_trace(YAFFS_TRACE_ALWAYS,
YBUG(); "Object in directory %d times",
count);
BUG();
} }
} }
void yaffs_verify_dir(yaffs_obj_t *directory) void yaffs_verify_dir(struct yaffs_obj *directory)
{ {
struct ylist_head *lh; struct list_head *lh;
yaffs_obj_t *listObj; struct yaffs_obj *list_obj;
if (!directory) { if (!directory) {
YBUG(); BUG();
return; return;
} }
@ -526,27 +480,29 @@ void yaffs_verify_dir(yaffs_obj_t *directory)
return; return;
if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variant_type)); yaffs_trace(YAFFS_TRACE_ALWAYS,
YBUG(); "Directory has wrong type: %d",
directory->variant_type);
BUG();
} }
/* Iterate through the objects in each hash entry */ /* Iterate through the objects in each hash entry */
ylist_for_each(lh, &directory->variant.dir_variant.children) { list_for_each(lh, &directory->variant.dir_variant.children) {
if (lh) { list_obj = list_entry(lh, struct yaffs_obj, siblings);
listObj = ylist_entry(lh, yaffs_obj_t, siblings); if (list_obj->parent != directory) {
if (listObj->parent != directory) { yaffs_trace(YAFFS_TRACE_ALWAYS,
T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent)); "Object in directory list has wrong parent %p",
YBUG(); list_obj->parent);
} BUG();
yaffs_verify_obj_in_dir(listObj);
} }
yaffs_verify_obj_in_dir(list_obj);
} }
} }
static int yaffs_free_verification_failures; static int yaffs_free_verification_failures;
void yaffs_verify_free_chunks(yaffs_dev_t *dev) void yaffs_verify_free_chunks(struct yaffs_dev *dev)
{ {
int counted; int counted;
int difference; int difference;
@ -559,68 +515,15 @@ void yaffs_verify_free_chunks(yaffs_dev_t *dev)
difference = dev->n_free_chunks - counted; difference = dev->n_free_chunks - counted;
if (difference) { if (difference) {
T(YAFFS_TRACE_ALWAYS, yaffs_trace(YAFFS_TRACE_ALWAYS,
(TSTR("Freechunks verification failure %d %d %d" TENDSTR), "Freechunks verification failure %d %d %d",
dev->n_free_chunks, counted, difference)); dev->n_free_chunks, counted, difference);
yaffs_free_verification_failures++; yaffs_free_verification_failures++;
} }
} }
int yaffs_verify_file_sane(yaffs_obj_t *in) int yaffs_verify_file_sane(struct yaffs_obj *in)
{ {
#if 0 (void) in;
int chunk;
int n_chunks;
int fSize;
int failed = 0;
int obj_id;
yaffs_tnode_t *tn;
yaffs_tags_t localTags;
yaffs_tags_t *tags = &localTags;
int theChunk;
int is_deleted;
if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
return YAFFS_FAIL;
obj_id = in->obj_id;
fSize = in->variant.file_variant.file_size;
n_chunks =
(fSize + in->my_dev->data_bytes_per_chunk - 1) / in->my_dev->data_bytes_per_chunk;
for (chunk = 1; chunk <= n_chunks; chunk++) {
tn = yaffs_find_tnode_0(in->my_dev, &in->variant.file_variant,
chunk);
if (tn) {
theChunk = yaffs_get_group_base(dev, tn, chunk);
if (yaffs_check_chunk_bits
(dev, theChunk / dev->param.chunks_per_block,
theChunk % dev->param.chunks_per_block)) {
yaffs_rd_chunk_tags_nand(in->my_dev, theChunk,
tags,
&is_deleted);
if (yaffs_tags_match
(tags, in->obj_id, chunk, is_deleted)) {
/* found it; */
}
} else {
failed = 1;
}
} else {
/* T(("No level 0 found for %d\n", chunk)); */
}
}
return failed ? YAFFS_FAIL : YAFFS_OK;
#else
in=in;
return YAFFS_OK; return YAFFS_OK;
#endif
} }

View File

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

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -10,54 +10,46 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include "yaffs_yaffs1.h" #include "yaffs_yaffs1.h"
#include "yportenv.h" #include "yportenv.h"
#include "yaffs_trace.h" #include "yaffs_trace.h"
#include "yaffs_bitmap.h" #include "yaffs_bitmap.h"
#include "yaffs_getblockinfo.h" #include "yaffs_getblockinfo.h"
#include "yaffs_nand.h" #include "yaffs_nand.h"
#include "yaffs_attribs.h"
int yaffs1_scan(struct yaffs_dev *dev)
int yaffs1_scan(yaffs_dev_t *dev)
{ {
yaffs_ext_tags tags; struct yaffs_ext_tags tags;
int blk; int blk;
int blockIterator;
int startIterator;
int endIterator;
int result; int result;
int chunk; int chunk;
int c; int c;
int deleted; int deleted;
yaffs_block_state_t state; enum yaffs_block_state state;
yaffs_obj_t *hard_list = NULL; LIST_HEAD(hard_list);
yaffs_block_info_t *bi; struct yaffs_block_info *bi;
__u32 seq_number; u32 seq_number;
yaffs_obj_header *oh; struct yaffs_obj_hdr *oh;
yaffs_obj_t *in; struct yaffs_obj *in;
yaffs_obj_t *parent; struct yaffs_obj *parent;
int alloc_failed = 0; int alloc_failed = 0;
struct yaffs_shadow_fixer *shadow_fixers = NULL;
u8 *chunk_data;
struct yaffs_shadow_fixer_s *shadowFixerList = NULL; yaffs_trace(YAFFS_TRACE_SCAN,
"yaffs1_scan starts intstartblk %d intendblk %d...",
dev->internal_start_block, dev->internal_end_block);
chunk_data = yaffs_get_temp_buffer(dev);
__u8 *chunkData;
T(YAFFS_TRACE_SCAN,
(TSTR("yaffs1_scan starts intstartblk %d intendblk %d..." TENDSTR),
dev->internal_start_block, dev->internal_end_block));
chunkData = yaffs_get_temp_buffer(dev, __LINE__);
dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
/* Scan all the blocks to determine their state */ /* Scan all the blocks to determine their state */
bi = dev->block_info; bi = dev->block_info;
for (blk = dev->internal_start_block; blk <= dev->internal_end_block; blk++) { for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
blk++) {
yaffs_clear_chunk_bits(dev, blk); yaffs_clear_chunk_bits(dev, blk);
bi->pages_in_use = 0; bi->pages_in_use = 0;
bi->soft_del_pages = 0; bi->soft_del_pages = 0;
@ -70,58 +62,51 @@ int yaffs1_scan(yaffs_dev_t *dev)
if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
bi->block_state = state = YAFFS_BLOCK_STATE_DEAD; bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
T(YAFFS_TRACE_SCAN_DEBUG, yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
(TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, "Block scanning block %d state %d seq %d",
state, seq_number)); blk, state, seq_number);
if (state == YAFFS_BLOCK_STATE_DEAD) { if (state == YAFFS_BLOCK_STATE_DEAD) {
T(YAFFS_TRACE_BAD_BLOCKS, yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
(TSTR("block %d is bad" TENDSTR), blk)); "block %d is bad", blk);
} else if (state == YAFFS_BLOCK_STATE_EMPTY) { } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
T(YAFFS_TRACE_SCAN_DEBUG, yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
(TSTR("Block empty " TENDSTR)));
dev->n_erased_blocks++; dev->n_erased_blocks++;
dev->n_free_chunks += dev->param.chunks_per_block; dev->n_free_chunks += dev->param.chunks_per_block;
} }
bi++; bi++;
} }
startIterator = dev->internal_start_block;
endIterator = dev->internal_end_block;
/* For each block.... */ /* For each block.... */
for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; for (blk = dev->internal_start_block;
blockIterator++) { !alloc_failed && blk <= dev->internal_end_block; blk++) {
YYIELD(); cond_resched();
YYIELD();
blk = blockIterator;
bi = yaffs_get_block_info(dev, blk); bi = yaffs_get_block_info(dev, blk);
state = bi->block_state; state = bi->block_state;
deleted = 0; deleted = 0;
/* For each chunk in each block that needs scanning....*/ /* For each chunk in each block that needs scanning.... */
for (c = 0; !alloc_failed && c < dev->param.chunks_per_block && for (c = 0;
state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { !alloc_failed && c < dev->param.chunks_per_block &&
state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
/* Read the tags and decide what to do */ /* Read the tags and decide what to do */
chunk = blk * dev->param.chunks_per_block + c; chunk = blk * dev->param.chunks_per_block + c;
result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
&tags); &tags);
/* Let's have a good look at this chunk... */ /* Let's have a good look at this chunk... */
if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED || tags.is_deleted) { if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
tags.is_deleted) {
/* YAFFS1 only... /* YAFFS1 only...
* A deleted chunk * A deleted chunk
*/ */
deleted++; deleted++;
dev->n_free_chunks++; dev->n_free_chunks++;
/*T((" %d %d deleted\n",blk,c)); */
} else if (!tags.chunk_used) { } else if (!tags.chunk_used) {
/* An unassigned chunk in the block /* An unassigned chunk in the block
* This means that either the block is empty or * This means that either the block is empty or
@ -129,24 +114,24 @@ int yaffs1_scan(yaffs_dev_t *dev)
*/ */
if (c == 0) { if (c == 0) {
/* We're looking at the first chunk in the block so the block is unused */ /* We're looking at the first chunk in
*the block so the block is unused */
state = YAFFS_BLOCK_STATE_EMPTY; state = YAFFS_BLOCK_STATE_EMPTY;
dev->n_erased_blocks++; dev->n_erased_blocks++;
} else { } else {
/* this is the block being allocated from */ /* this is the block being allocated */
T(YAFFS_TRACE_SCAN, yaffs_trace(YAFFS_TRACE_SCAN,
(TSTR " Allocating from %d %d",
(" Allocating from %d %d" TENDSTR), blk, c);
blk, c));
state = YAFFS_BLOCK_STATE_ALLOCATING; state = YAFFS_BLOCK_STATE_ALLOCATING;
dev->alloc_block = blk; dev->alloc_block = blk;
dev->alloc_page = c; dev->alloc_page = c;
dev->alloc_block_finder = blk; dev->alloc_block_finder = blk;
/* Set block finder here to encourage the allocator to go forth from here. */
} }
dev->n_free_chunks += (dev->param.chunks_per_block - c); dev->n_free_chunks +=
(dev->param.chunks_per_block - c);
} else if (tags.chunk_id > 0) { } else if (tags.chunk_id > 0) {
/* chunk_id > 0 so it is a data chunk... */ /* chunk_id > 0 so it is a data chunk... */
unsigned int endpos; unsigned int endpos;
@ -155,133 +140,131 @@ int yaffs1_scan(yaffs_dev_t *dev)
bi->pages_in_use++; bi->pages_in_use++;
in = yaffs_find_or_create_by_number(dev, in = yaffs_find_or_create_by_number(dev,
tags. tags.obj_id,
obj_id, YAFFS_OBJECT_TYPE_FILE);
YAFFS_OBJECT_TYPE_FILE); /* PutChunkIntoFile checks for a clash
/* PutChunkIntoFile checks for a clash (two data chunks with * (two data chunks with the same chunk_id).
* the same chunk_id).
*/ */
if (!in) if (!in)
alloc_failed = 1; alloc_failed = 1;
if (in) { if (in) {
if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, 1)) if (!yaffs_put_chunk_in_file
(in, tags.chunk_id, chunk, 1))
alloc_failed = 1; alloc_failed = 1;
} }
endpos = endpos =
(tags.chunk_id - 1) * dev->data_bytes_per_chunk + (tags.chunk_id - 1) *
dev->data_bytes_per_chunk +
tags.n_bytes; tags.n_bytes;
if (in && if (in &&
in->variant_type == YAFFS_OBJECT_TYPE_FILE in->variant_type ==
&& in->variant.file_variant.scanned_size < YAFFS_OBJECT_TYPE_FILE &&
endpos) { in->variant.file_variant.scanned_size <
in->variant.file_variant. endpos) {
scanned_size = endpos; in->variant.file_variant.scanned_size =
endpos;
if (!dev->param.use_header_file_size) { if (!dev->param.use_header_file_size) {
in->variant.file_variant. in->variant.
file_size = file_variant.file_size =
in->variant.file_variant. in->variant.
scanned_size; file_variant.scanned_size;
} }
} }
/* T((" %d %d data %d %d\n",blk,c,tags.obj_id,tags.chunk_id)); */
} else { } else {
/* chunk_id == 0, so it is an ObjectHeader. /* chunk_id == 0, so it is an ObjectHeader.
* Thus, we read in the object header and make the object * Make the object
*/ */
yaffs_set_chunk_bit(dev, blk, c); yaffs_set_chunk_bit(dev, blk, c);
bi->pages_in_use++; bi->pages_in_use++;
result = yaffs_rd_chunk_tags_nand(dev, chunk, result = yaffs_rd_chunk_tags_nand(dev, chunk,
chunkData, chunk_data,
NULL); NULL);
oh = (yaffs_obj_header *) chunkData; oh = (struct yaffs_obj_hdr *)chunk_data;
in = yaffs_find_by_number(dev, in = yaffs_find_by_number(dev, tags.obj_id);
tags.obj_id);
if (in && in->variant_type != oh->type) { if (in && in->variant_type != oh->type) {
/* This should not happen, but somehow /* This should not happen, but somehow
* Wev'e ended up with an obj_id that has been reused but not yet * Wev'e ended up with an obj_id that
* deleted, and worse still it has changed type. Delete the old object. * has been reused but not yet deleted,
* and worse still it has changed type.
* Delete the old object.
*/ */
yaffs_del_obj(in); yaffs_del_obj(in);
in = NULL;
in = 0;
} }
in = yaffs_find_or_create_by_number(dev, in = yaffs_find_or_create_by_number(dev,
tags. tags.obj_id,
obj_id, oh->type);
oh->type);
if (!in) if (!in)
alloc_failed = 1; alloc_failed = 1;
if (in && oh->shadows_obj > 0) { if (in && oh->shadows_obj > 0) {
struct yaffs_shadow_fixer_s *fixer; struct yaffs_shadow_fixer *fixer;
fixer = YMALLOC(sizeof(struct yaffs_shadow_fixer_s)); fixer =
kmalloc(sizeof
(struct yaffs_shadow_fixer),
GFP_NOFS);
if (fixer) { if (fixer) {
fixer->next = shadowFixerList; fixer->next = shadow_fixers;
shadowFixerList = fixer; shadow_fixers = fixer;
fixer->obj_id = tags.obj_id; fixer->obj_id = tags.obj_id;
fixer->shadowed_id = oh->shadows_obj; fixer->shadowed_id =
T(YAFFS_TRACE_SCAN, oh->shadows_obj;
(TSTR yaffs_trace(YAFFS_TRACE_SCAN,
(" Shadow fixer: %d shadows %d" TENDSTR), " Shadow fixer: %d shadows %d",
fixer->obj_id, fixer->shadowed_id)); fixer->obj_id,
fixer->shadowed_id);
} }
} }
if (in && in->valid) { if (in && in->valid) {
/* We have already filled this one. We have a duplicate and need to resolve it. */ /* We have already filled this one.
* We have a duplicate and need to
* resolve it. */
unsigned existingSerial = in->serial; unsigned existing_serial = in->serial;
unsigned newSerial = tags.serial_number; unsigned new_serial =
tags.serial_number;
if (((existingSerial + 1) & 3) == newSerial) { if (((existing_serial + 1) & 3) ==
/* Use new one - destroy the exisiting one */ new_serial) {
/* Use new one - destroy the
* exisiting one */
yaffs_chunk_del(dev, yaffs_chunk_del(dev,
in->hdr_chunk, in->hdr_chunk,
1, __LINE__); 1, __LINE__);
in->valid = 0; in->valid = 0;
} else { } else {
/* Use existing - destroy this one. */ /* Use existing - destroy
* this one. */
yaffs_chunk_del(dev, chunk, 1, yaffs_chunk_del(dev, chunk, 1,
__LINE__); __LINE__);
} }
} }
if (in && !in->valid && if (in && !in->valid &&
(tags.obj_id == YAFFS_OBJECTID_ROOT || (tags.obj_id == YAFFS_OBJECTID_ROOT ||
tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) { tags.obj_id ==
/* We only load some info, don't fiddle with directory structure */ YAFFS_OBJECTID_LOSTNFOUND)) {
/* We only load some info, don't fiddle
* with directory structure */
in->valid = 1; in->valid = 1;
in->variant_type = oh->type; in->variant_type = oh->type;
in->yst_mode = oh->yst_mode; in->yst_mode = oh->yst_mode;
#ifdef CONFIG_YAFFS_WINCE yaffs_load_attribs(in, oh);
in->win_atime[0] = oh->win_atime[0];
in->win_ctime[0] = oh->win_ctime[0];
in->win_mtime[0] = oh->win_mtime[0];
in->win_atime[1] = oh->win_atime[1];
in->win_ctime[1] = oh->win_ctime[1];
in->win_mtime[1] = oh->win_mtime[1];
#else
in->yst_uid = oh->yst_uid;
in->yst_gid = oh->yst_gid;
in->yst_atime = oh->yst_atime;
in->yst_mtime = oh->yst_mtime;
in->yst_ctime = oh->yst_ctime;
in->yst_rdev = oh->yst_rdev;
#endif
in->hdr_chunk = chunk; in->hdr_chunk = chunk;
in->serial = tags.serial_number; in->serial = tags.serial_number;
@ -292,21 +275,7 @@ int yaffs1_scan(yaffs_dev_t *dev)
in->variant_type = oh->type; in->variant_type = oh->type;
in->yst_mode = oh->yst_mode; in->yst_mode = oh->yst_mode;
#ifdef CONFIG_YAFFS_WINCE yaffs_load_attribs(in, oh);
in->win_atime[0] = oh->win_atime[0];
in->win_ctime[0] = oh->win_ctime[0];
in->win_mtime[0] = oh->win_mtime[0];
in->win_atime[1] = oh->win_atime[1];
in->win_ctime[1] = oh->win_ctime[1];
in->win_mtime[1] = oh->win_mtime[1];
#else
in->yst_uid = oh->yst_uid;
in->yst_gid = oh->yst_gid;
in->yst_atime = oh->yst_atime;
in->yst_mtime = oh->yst_mtime;
in->yst_ctime = oh->yst_ctime;
in->yst_rdev = oh->yst_rdev;
#endif
in->hdr_chunk = chunk; in->hdr_chunk = chunk;
in->serial = tags.serial_number; in->serial = tags.serial_number;
@ -327,57 +296,43 @@ int yaffs1_scan(yaffs_dev_t *dev)
YAFFS_OBJECT_TYPE_UNKNOWN) { YAFFS_OBJECT_TYPE_UNKNOWN) {
/* Set up as a directory */ /* Set up as a directory */
parent->variant_type = parent->variant_type =
YAFFS_OBJECT_TYPE_DIRECTORY; YAFFS_OBJECT_TYPE_DIRECTORY;
YINIT_LIST_HEAD(&parent->variant. INIT_LIST_HEAD(&parent->
dir_variant. variant.dir_variant.
children); children);
} else if (!parent || parent->variant_type != } else if (!parent ||
YAFFS_OBJECT_TYPE_DIRECTORY) { parent->variant_type !=
/* Hoosterman, another problem.... YAFFS_OBJECT_TYPE_DIRECTORY) {
* We're trying to use a non-directory as a directory /* Hoosterman, a problem....
* We're trying to use a
* non-directory as a directory
*/ */
T(YAFFS_TRACE_ERROR, yaffs_trace(YAFFS_TRACE_ERROR,
(TSTR "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." );
TENDSTR)));
parent = dev->lost_n_found; parent = dev->lost_n_found;
} }
yaffs_add_obj_to_dir(parent, in); yaffs_add_obj_to_dir(parent, in);
if (0 && (parent == dev->del_dir ||
parent == dev->unlinked_dir)) {
in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
dev->n_deleted_files++;
}
/* Note re hardlinks.
* Since we might scan a hardlink before its equivalent object is scanned
* we put them all in a list.
* After scanning is complete, we should have all the objects, so we run through this
* list and fix up all the chains.
*/
switch (in->variant_type) { switch (in->variant_type) {
case YAFFS_OBJECT_TYPE_UNKNOWN: case YAFFS_OBJECT_TYPE_UNKNOWN:
/* Todo got a problem */ /* Todo got a problem */
break; break;
case YAFFS_OBJECT_TYPE_FILE: case YAFFS_OBJECT_TYPE_FILE:
if (dev->param.use_header_file_size) if (dev->param.
use_header_file_size)
in->variant.file_variant. in->variant.
file_size = file_variant.file_size
oh->file_size; = yaffs_oh_to_size(oh);
break; break;
case YAFFS_OBJECT_TYPE_HARDLINK: case YAFFS_OBJECT_TYPE_HARDLINK:
in->variant.hardlink_variant. in->variant.
equiv_id = hardlink_variant.equiv_id =
oh->equiv_id; oh->equiv_id;
in->hard_links.next = list_add(&in->hard_links,
(struct ylist_head *) &hard_list);
hard_list;
hard_list = in;
break; break;
case YAFFS_OBJECT_TYPE_DIRECTORY: case YAFFS_OBJECT_TYPE_DIRECTORY:
/* Do nothing */ /* Do nothing */
@ -386,24 +341,27 @@ int yaffs1_scan(yaffs_dev_t *dev)
/* Do nothing */ /* Do nothing */
break; break;
case YAFFS_OBJECT_TYPE_SYMLINK: case YAFFS_OBJECT_TYPE_SYMLINK:
in->variant.symlink_variant.alias = in->variant.symlink_variant.
alias =
yaffs_clone_str(oh->alias); yaffs_clone_str(oh->alias);
if (!in->variant.symlink_variant.alias) if (!in->variant.
symlink_variant.alias)
alloc_failed = 1; alloc_failed = 1;
break; break;
} }
} }
} }
} }
if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
/* If we got this far while scanning, then the block is fully allocated.*/ /* If we got this far while scanning,
* then the block is fully allocated. */
state = YAFFS_BLOCK_STATE_FULL; state = YAFFS_BLOCK_STATE_FULL;
} }
if (state == YAFFS_BLOCK_STATE_ALLOCATING) { if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
/* If the block was partially allocated then treat it as fully allocated.*/ /* If the block was partially allocated then
* treat it as fully allocated. */
state = YAFFS_BLOCK_STATE_FULL; state = YAFFS_BLOCK_STATE_FULL;
dev->alloc_block = -1; dev->alloc_block = -1;
} }
@ -413,31 +371,32 @@ int yaffs1_scan(yaffs_dev_t *dev)
/* Now let's see if it was dirty */ /* Now let's see if it was dirty */
if (bi->pages_in_use == 0 && if (bi->pages_in_use == 0 &&
!bi->has_shrink_hdr && !bi->has_shrink_hdr &&
bi->block_state == YAFFS_BLOCK_STATE_FULL) { bi->block_state == YAFFS_BLOCK_STATE_FULL)
yaffs_block_became_dirty(dev, blk); yaffs_block_became_dirty(dev, blk);
}
} }
/* Ok, we've done all the scanning. /* Ok, we've done all the scanning.
* Fix up the hard link chains. * Fix up the hard link chains.
* We should now have scanned all the objects, now it's time to add these * We should now have scanned all the objects, now it's time to add
* hardlinks. * these hardlinks.
*/ */
yaffs_link_fixup(dev, hard_list); yaffs_link_fixup(dev, &hard_list);
/* Fix up any shadowed objects */ /*
* Fix up any shadowed objects.
* There should not be more than one of these.
*/
{ {
struct yaffs_shadow_fixer_s *fixer; struct yaffs_shadow_fixer *fixer;
yaffs_obj_t *obj; struct yaffs_obj *obj;
while (shadowFixerList) { while (shadow_fixers) {
fixer = shadowFixerList; fixer = shadow_fixers;
shadowFixerList = fixer->next; shadow_fixers = fixer->next;
/* Complete the rename transaction by deleting the shadowed object /* Complete the rename transaction by deleting the
* then setting the object header to unshadowed. * shadowed object then setting the object header
to unshadowed.
*/ */
obj = yaffs_find_by_number(dev, fixer->shadowed_id); obj = yaffs_find_by_number(dev, fixer->shadowed_id);
if (obj) if (obj)
@ -448,18 +407,16 @@ int yaffs1_scan(yaffs_dev_t *dev)
if (obj) if (obj)
yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
YFREE(fixer); kfree(fixer);
} }
} }
yaffs_release_temp_buffer(dev, chunkData, __LINE__); yaffs_release_temp_buffer(dev, chunk_data);
if (alloc_failed) if (alloc_failed)
return YAFFS_FAIL; return YAFFS_FAIL;
T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_scan ends" TENDSTR))); yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
return YAFFS_OK; return YAFFS_OK;
} }

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -17,6 +17,6 @@
#define __YAFFS_YAFFS1_H__ #define __YAFFS_YAFFS1_H__
#include "yaffs_guts.h" #include "yaffs_guts.h"
int yaffs1_scan(yaffs_dev_t *dev); int yaffs1_scan(struct yaffs_dev *dev);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,7 +1,7 @@
/* /*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system. * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
* *
* Copyright (C) 2002-2010 Aleph One Ltd. * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering * for Toby Churchill Ltd and Brightstar Engineering
* *
* Created by Charles Manning <charles@aleph1.co.uk> * Created by Charles Manning <charles@aleph1.co.uk>
@ -13,7 +13,6 @@
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/ */
#ifndef __YPORTENV_H__ #ifndef __YPORTENV_H__
#define __YPORTENV_H__ #define __YPORTENV_H__
@ -25,15 +24,9 @@
#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) #define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
#if defined CONFIG_YAFFS_WINCE #ifdef YAFFS_OUT_OF_TREE
#include "ywinceenv.h"
#elif defined __KERNEL__
#include "moduleconfig.h" #include "moduleconfig.h"
#endif
/* Linux kernel */
#include <linux/version.h> #include <linux/version.h>
#define MTD_VERSION_CODE LINUX_VERSION_CODE #define MTD_VERSION_CODE LINUX_VERSION_CODE
@ -41,7 +34,7 @@
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
#include <linux/config.h> #include <linux/config.h>
#endif #endif
#include <linux/version.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/sched.h> #include <linux/sched.h>
@ -49,32 +42,21 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/sort.h>
#include <linux/bitops.h>
/* These type wrappings are used to support Unicode names in WinCE. */
#define YCHAR char #define YCHAR char
#define YUCHAR unsigned char #define YUCHAR unsigned char
#define _Y(x) x #define _Y(x) x
#define yaffs_strcat(a, b) strcat(a, b)
#define yaffs_strcpy(a, b) strcpy(a, b)
#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
#define yaffs_strncmp(a, b, c) strncmp(a, b, c)
#define yaffs_strnlen(s,m) strnlen(s,m)
#define yaffs_sprintf sprintf
#define yaffs_toupper(a) toupper(a)
#define Y_INLINE __inline__
#define YAFFS_LOSTNFOUND_NAME "lost+found" #define YAFFS_LOSTNFOUND_NAME "lost+found"
#define YAFFS_LOSTNFOUND_PREFIX "obj" #define YAFFS_LOSTNFOUND_PREFIX "obj"
/* #define YPRINTF(x) printk x */
#define YMALLOC(x) kmalloc(x, GFP_NOFS)
#define YFREE(x) kfree(x)
#define YMALLOC_ALT(x) vmalloc(x)
#define YFREE_ALT(x) vfree(x)
#define YMALLOC_DMA(x) YMALLOC(x)
#define YYIELD() schedule()
#define Y_DUMP_STACK() dump_stack()
#define YAFFS_ROOT_MODE 0755 #define YAFFS_ROOT_MODE 0755
#define YAFFS_LOSTNFOUND_MODE 0700 #define YAFFS_LOSTNFOUND_MODE 0700
@ -87,247 +69,17 @@
#define Y_TIME_CONVERT(x) (x) #define Y_TIME_CONVERT(x) (x)
#endif #endif
#define yaffs_sum_cmp(x, y) ((x) == (y))
#define yaffs_strcmp(a, b) strcmp(a, b)
#define TENDSTR "\n"
#define TSTR(x) KERN_DEBUG x
#define TCONT(x) x
#define TOUT(p) printk p
#define compile_time_assertion(assertion) \ #define compile_time_assertion(assertion) \
({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
#elif defined CONFIG_YAFFS_DIRECT
#define MTD_VERSION_CODE MTD_VERSION(2, 6, 22) #define yaffs_printf(msk, fmt, ...) \
printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__)
/* Direct interface */ #define yaffs_trace(msk, fmt, ...) do { \
#include "ydirectenv.h" if (yaffs_trace_mask & (msk)) \
printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \
#elif defined CONFIG_YAFFS_UTIL
/* Stuff for YAFFS utilities */
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#define YMALLOC(x) malloc(x)
#define YFREE(x) free(x)
#define YMALLOC_ALT(x) malloc(x)
#define YFREE_ALT(x) free(x)
#define YCHAR char
#define YUCHAR unsigned char
#define _Y(x) x
#define yaffs_strcat(a, b) strcat(a, b)
#define yaffs_strcpy(a, b) strcpy(a, b)
#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
#define yaffs_strnlen(s,m) strnlen(s,m)
#define yaffs_sprintf sprintf
#define yaffs_toupper(a) toupper(a)
#define Y_INLINE inline
/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */
/* #define YALERT(s) YINFO(s) */
#define TENDSTR "\n"
#define TSTR(x) x
#define TOUT(p) printf p
#define YAFFS_LOSTNFOUND_NAME "lost+found"
#define YAFFS_LOSTNFOUND_PREFIX "obj"
/* #define YPRINTF(x) printf x */
#define YAFFS_ROOT_MODE 0755
#define YAFFS_LOSTNFOUND_MODE 0700
#define yaffs_sum_cmp(x, y) ((x) == (y))
#define yaffs_strcmp(a, b) strcmp(a, b)
#else
/* Should have specified a configuration type */
#error Unknown configuration
#endif
#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
#ifndef O_RDONLY
#define O_RDONLY 00
#endif
#ifndef O_WRONLY
#define O_WRONLY 01
#endif
#ifndef O_RDWR
#define O_RDWR 02
#endif
#ifndef O_CREAT
#define O_CREAT 0100
#endif
#ifndef O_EXCL
#define O_EXCL 0200
#endif
#ifndef O_TRUNC
#define O_TRUNC 01000
#endif
#ifndef O_APPEND
#define O_APPEND 02000
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
#ifndef EBUSY
#define EBUSY 16
#endif
#ifndef ENODEV
#define ENODEV 19
#endif
#ifndef EINVAL
#define EINVAL 22
#endif
#ifndef EBADF
#define EBADF 9
#endif
#ifndef EACCES
#define EACCES 13
#endif
#ifndef EXDEV
#define EXDEV 18
#endif
#ifndef ENOENT
#define ENOENT 2
#endif
#ifndef ENOSPC
#define ENOSPC 28
#endif
#ifndef ERANGE
#define ERANGE 34
#endif
#ifndef ENODATA
#define ENODATA 61
#endif
#ifndef ENOTEMPTY
#define ENOTEMPTY 39
#endif
#ifndef ENAMETOOLONG
#define ENAMETOOLONG 36
#endif
#ifndef ENOMEM
#define ENOMEM 12
#endif
#ifndef EEXIST
#define EEXIST 17
#endif
#ifndef ENOTDIR
#define ENOTDIR 20
#endif
#ifndef EISDIR
#define EISDIR 21
#endif
// Mode flags
#ifndef S_IFMT
#define S_IFMT 0170000
#endif
#ifndef S_IFLNK
#define S_IFLNK 0120000
#endif
#ifndef S_IFDIR
#define S_IFDIR 0040000
#endif
#ifndef S_IFREG
#define S_IFREG 0100000
#endif
#ifndef S_IREAD
#define S_IREAD 0000400
#endif
#ifndef S_IWRITE
#define S_IWRITE 0000200
#endif
#ifndef S_IEXEC
#define S_IEXEC 0000100
#endif
#ifndef XATTR_CREATE
#define XATTR_CREATE 1
#endif
#ifndef XATTR_REPLACE
#define XATTR_REPLACE 2
#endif
#ifndef R_OK
#define R_OK 4
#define W_OK 2
#define X_OK 1
#define F_OK 0
#endif
#else
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
#endif
#ifndef Y_DUMP_STACK
#define Y_DUMP_STACK() do { } while (0)
#endif
#ifndef YBUG
#define YBUG() do {\
T(YAFFS_TRACE_BUG,\
(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\
__LINE__));\
Y_DUMP_STACK();\
} while (0) } while (0)
#endif
#endif #endif

View File

@ -0,0 +1,155 @@
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -329,6 +329,33 @@ static int yaffs_readpage(struct file *f
return ret;
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid())
+#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid())
+#else
+#define YCRED_FSUID() YCRED(current)->fsuid
+#define YCRED_FSGID() YCRED(current)->fsgid
+
+static inline uid_t i_uid_read(const struct inode *inode)
+{
+ return inode->i_uid;
+}
+
+static inline gid_t i_gid_read(const struct inode *inode)
+{
+ return inode->i_gid;
+}
+
+static inline void i_uid_write(struct inode *inode, uid_t uid)
+{
+ inode->i_uid = uid;
+}
+
+static inline void i_gid_write(struct inode *inode, gid_t gid)
+{
+ inode->i_gid = gid;
+}
+#endif
static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)
{
@@ -1225,9 +1252,9 @@ static int yaffs_mknod(struct inode *dir
struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
int error = -ENOSPC;
- uid_t uid = YCRED(current)->fsuid;
+ uid_t uid = YCRED_FSUID();
gid_t gid =
- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
mode |= S_ISGID;
@@ -1424,9 +1451,9 @@ static int yaffs_symlink(struct inode *d
{
struct yaffs_obj *obj;
struct yaffs_dev *dev;
- uid_t uid = YCRED(current)->fsuid;
+ uid_t uid = YCRED_FSUID();
gid_t gid =
- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
@@ -1829,8 +1856,8 @@ static void yaffs_fill_inode_from_obj(st
inode->i_ino = obj->obj_id;
inode->i_mode = obj->yst_mode;
- inode->i_uid = obj->yst_uid;
- inode->i_gid = obj->yst_gid;
+ i_uid_write(inode, obj->yst_uid);
+ i_gid_write(inode, obj->yst_gid);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
inode->i_blksize = inode->i_sb->s_blocksize;
#endif
@@ -1856,7 +1883,7 @@ static void yaffs_fill_inode_from_obj(st
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
- inode->i_mode, inode->i_uid, inode->i_gid,
+ inode->i_mode, i_uid_read(inode), i_gid_read(inode),
inode->i_size, atomic_read(&inode->i_count));
switch (obj->yst_mode & S_IFMT) {
--- a/fs/yaffs2/yaffs_attribs.c
+++ b/fs/yaffs2/yaffs_attribs.c
@@ -14,6 +14,48 @@
#include "yaffs_guts.h"
#include "yaffs_attribs.h"
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+static inline uid_t ia_uid_read(const struct iattr *iattr)
+{
+ return from_kuid(&init_user_ns, iattr->ia_uid);
+}
+
+static inline gid_t ia_gid_read(const struct iattr *iattr)
+{
+ return from_kgid(&init_user_ns, iattr->ia_gid);
+}
+
+static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
+{
+ iattr->ia_uid = make_kuid(&init_user_ns, uid);
+}
+
+static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
+{
+ iattr->ia_gid = make_kgid(&init_user_ns, gid);
+}
+#else
+static inline uid_t ia_uid_read(const struct iattr *iattr)
+{
+ return iattr->ia_uid;
+}
+
+static inline gid_t ia_gid_read(const struct iattr *inode)
+{
+ return iattr->ia_gid;
+}
+
+static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
+{
+ iattr->ia_uid = uid;
+}
+
+static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
+{
+ iattr->ia_gid = gid;
+}
+#endif
+
void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
{
obj->yst_uid = oh->yst_uid;
@@ -77,9 +119,9 @@ int yaffs_set_attribs(struct yaffs_obj *
if (valid & ATTR_MODE)
obj->yst_mode = attr->ia_mode;
if (valid & ATTR_UID)
- obj->yst_uid = attr->ia_uid;
+ obj->yst_uid = ia_uid_read(attr);
if (valid & ATTR_GID)
- obj->yst_gid = attr->ia_gid;
+ obj->yst_gid = ia_gid_read(attr);
if (valid & ATTR_ATIME)
obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
@@ -103,9 +145,9 @@ int yaffs_get_attribs(struct yaffs_obj *
attr->ia_mode = obj->yst_mode;
valid |= ATTR_MODE;
- attr->ia_uid = obj->yst_uid;
+ ia_uid_write(attr, obj->yst_uid);
valid |= ATTR_UID;
- attr->ia_gid = obj->yst_gid;
+ ia_gid_write(attr, obj->yst_gid);
valid |= ATTR_GID;
Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;

View File

@ -1,31 +0,0 @@
From 2505e8b0a13d3d5c5bbeaaae4eb889864f44c9df Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Thu, 3 Feb 2011 05:55:30 +1300
Subject: [PATCH] yaffs: Fix directory unlinking in yaffs1 mode
commit 964b3425a71890e6701c830e38b04d8557c04f49 upstream.
Treat both yaffs2 and yaffs1 paths the same.
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
yaffs_guts.c | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
--- a/fs/yaffs2/yaffs_guts.c
+++ b/fs/yaffs2/yaffs_guts.c
@@ -1708,13 +1708,7 @@ static int yaffs_change_obj_name(yaffs_o
YBUG();
}
- /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
- if (obj->my_dev->param.is_yaffs2)
- unlinkOp = (new_dir == obj->my_dev->unlinked_dir);
- else
- unlinkOp = (new_dir == obj->my_dev->unlinked_dir
- && obj->variant_type == YAFFS_OBJECT_TYPE_FILE);
-
+ unlinkOp = (new_dir == obj->my_dev->unlinked_dir);
deleteOp = (new_dir == obj->my_dev->del_dir);
existingTarget = yaffs_find_by_name(new_dir, new_name);

View File

@ -0,0 +1,44 @@
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -3025,6 +3025,7 @@ static DECLARE_FSTYPE(yaffs2_fs_type, "y
#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
static struct proc_dir_entry *my_proc_entry;
static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
@@ -3398,6 +3399,7 @@ static int yaffs_proc_write(struct file
return yaffs_proc_debug_write(file, buf, count, data);
return yaffs_proc_write_trace_options(file, buf, count, data);
}
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */
/* Stuff to handle installation of file systems */
struct file_system_to_install {
@@ -3421,6 +3423,7 @@ static int __init init_yaffs_fs(void)
mutex_init(&yaffs_context_lock);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
/* Install the proc_fs entries */
my_proc_entry = create_proc_entry("yaffs",
S_IRUGO | S_IFREG, YPROC_ROOT);
@@ -3432,6 +3435,7 @@ static int __init init_yaffs_fs(void)
} else {
return -ENOMEM;
}
+#endif
/* Now add the file system entries */
@@ -3468,7 +3472,9 @@ static void __exit exit_yaffs_fs(void)
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs built " __DATE__ " " __TIME__ " removing.");
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
remove_proc_entry("yaffs", YPROC_ROOT);
+#endif
fsinst = fs_to_install;

View File

@ -1,138 +0,0 @@
From c0c289363e84c53b5872f7c0c5069045096dca07 Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Wed, 3 Nov 2010 16:01:12 +1300
Subject: [PATCH] yaffs: Switch from semaphores to mutexes
commit 73c54aa8c1de3f61a4c211cd47431293a6092f18 upstream.
Mutex is faster and init_MUTEX has been deprecated, so we'll just switch
to mutexes.
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
yaffs_linux.h | 2 +-
yaffs_vfs.c | 24 ++++++++++++------------
yaffs_vfs_multi.c | 26 +++++++++++++-------------
3 files changed, 26 insertions(+), 26 deletions(-)
--- a/fs/yaffs2/yaffs_linux.h
+++ b/fs/yaffs2/yaffs_linux.h
@@ -25,7 +25,7 @@ struct yaffs_LinuxContext {
struct super_block * superBlock;
struct task_struct *bgThread; /* Background thread for this device */
int bgRunning;
- struct semaphore grossLock; /* Gross locking semaphore */
+ struct mutex grossLock; /* Gross locking mutex*/
__u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
* at compile time so we have to allocate it.
*/
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -515,14 +515,14 @@ static unsigned yaffs_gc_control_callbac
static void yaffs_gross_lock(yaffs_dev_t *dev)
{
T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
- down(&(yaffs_dev_to_lc(dev)->grossLock));
+ mutex_lock(&(yaffs_dev_to_lc(dev)->grossLock));
T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
}
static void yaffs_gross_unlock(yaffs_dev_t *dev)
{
T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
- up(&(yaffs_dev_to_lc(dev)->grossLock));
+ mutex_unlock(&(yaffs_dev_to_lc(dev)->grossLock));
}
#ifdef YAFFS_COMPILE_EXPORTFS
@@ -2542,7 +2542,7 @@ static void yaffs_read_inode(struct inod
#endif
static YLIST_HEAD(yaffs_context_list);
-struct semaphore yaffs_context_lock;
+struct mutex yaffs_context_lock;
static void yaffs_put_super(struct super_block *sb)
{
@@ -2568,9 +2568,9 @@ static void yaffs_put_super(struct super
yaffs_gross_unlock(dev);
- down(&yaffs_context_lock);
+ mutex_lock(&yaffs_context_lock);
ylist_del_init(&(yaffs_dev_to_lc(dev)->contextList));
- up(&yaffs_context_lock);
+ mutex_unlock(&yaffs_context_lock);
if (yaffs_dev_to_lc(dev)->spareBuffer) {
YFREE(yaffs_dev_to_lc(dev)->spareBuffer);
@@ -3016,7 +3016,7 @@ static struct super_block *yaffs_interna
param->skip_checkpt_rd = options.skip_checkpoint_read;
param->skip_checkpt_wr = options.skip_checkpoint_write;
- down(&yaffs_context_lock);
+ mutex_lock(&yaffs_context_lock);
/* Get a mount id */
found = 0;
for(mount_id=0; ! found; mount_id++){
@@ -3030,13 +3030,13 @@ static struct super_block *yaffs_interna
context->mount_id = mount_id;
ylist_add_tail(&(yaffs_dev_to_lc(dev)->contextList), &yaffs_context_list);
- up(&yaffs_context_lock);
+ mutex_unlock(&yaffs_context_lock);
/* Directory search handling...*/
YINIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->searchContexts));
param->remove_obj_fn = yaffs_remove_obj_callback;
- init_MUTEX(&(yaffs_dev_to_lc(dev)->grossLock));
+ mutex_init(&(yaffs_dev_to_lc(dev)->grossLock));
yaffs_gross_lock(dev);
@@ -3268,7 +3268,7 @@ static int yaffs_proc_read(char *page,
else {
step-=2;
- down(&yaffs_context_lock);
+ mutex_lock(&yaffs_context_lock);
/* Locate and print the Nth entry. Order N-squared but N is small. */
ylist_for_each(item, &yaffs_context_list) {
@@ -3287,7 +3287,7 @@ static int yaffs_proc_read(char *page,
break;
}
- up(&yaffs_context_lock);
+ mutex_unlock(&yaffs_context_lock);
}
return buf - page < count ? buf - page : count;
@@ -3301,7 +3301,7 @@ static int yaffs_stats_proc_read(char *p
char *buf = page;
int n = 0;
- down(&yaffs_context_lock);
+ mutex_lock(&yaffs_context_lock);
/* Locate and print the Nth entry. Order N-squared but N is small. */
ylist_for_each(item, &yaffs_context_list) {
@@ -3317,7 +3317,7 @@ static int yaffs_stats_proc_read(char *p
dev->bg_gcs, dev->oldest_dirty_gc_count,
dev->n_obj, dev->n_tnodes);
}
- up(&yaffs_context_lock);
+ mutex_unlock(&yaffs_context_lock);
return buf - page < count ? buf - page : count;
@@ -3494,7 +3494,7 @@ static int __init init_yaffs_fs(void)
- init_MUTEX(&yaffs_context_lock);
+ mutex_init(&yaffs_context_lock);
/* Install the proc_fs entries */
my_proc_entry = create_proc_entry("yaffs",

View File

@ -1,72 +0,0 @@
From cd6657c4bde20886b0805ea9f2cbac7ec25ac2e5 Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Tue, 30 Nov 2010 16:01:28 +1300
Subject: [PATCH 1/2] yaffs: Replace yaffs_dir_llseek with Linux generic
llseek
commit ed8188fb7659cfb65b5adbe154d143190ade0324 upstream.
There was not much point in having the yaffs version as it is
functionally equivalent to the kernel one.
This also gets rid of using BKL in yaffs2.
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
yaffs_vfs.c | 30 +-----------------------------
yaffs_vfs_multi.c | 30 +-----------------------------
2 files changed, 2 insertions(+), 58 deletions(-)
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -342,8 +342,6 @@ static int yaffs_follow_link(struct dent
static void yaffs_touch_super(yaffs_dev_t *dev);
-static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
-
static int yaffs_vfs_setattr(struct inode *, struct iattr *);
@@ -460,7 +458,7 @@ static const struct file_operations yaff
.read = generic_read_dir,
.readdir = yaffs_readdir,
.fsync = yaffs_sync_object,
- .llseek = yaffs_dir_llseek,
+ .llseek = generic_file_llseek,
};
static const struct super_operations yaffs_super_ops = {
@@ -1534,32 +1532,6 @@ static void yaffs_release_space(struct f
}
-static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
-{
- long long retval;
-
- lock_kernel();
-
- switch (origin){
- case 2:
- offset += i_size_read(file->f_path.dentry->d_inode);
- break;
- case 1:
- offset += file->f_pos;
- }
- retval = -EINVAL;
-
- if (offset >= 0){
- if (offset != file->f_pos)
- file->f_pos = offset;
-
- retval = offset;
- }
- unlock_kernel();
- return retval;
-}
-
-
static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
{
yaffs_obj_t *obj;

View File

@ -1,110 +0,0 @@
From e1537a700c2e750c5eacc5ad93f30821f1e94424 Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Mon, 15 Aug 2011 11:40:30 +1200
Subject: [PATCH 2/2] Mods for Linux 3.0 and fix a typo
commit a7b5dcf904ba6f7890e4b77ce1f56388b855d0f6 upstream.
Roll in NCB's patch and some other changes for Linux 3.0.
Also fix a dumb type retired_writes->retried_writes
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
patch-ker.sh | 2 +-
yaffs_vfs_glue.c | 42 ++++++++++++++++++++++++++++++++++--------
2 files changed, 35 insertions(+), 9 deletions(-)
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -72,7 +72,9 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
#include <linux/smp_lock.h>
+#endif
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
@@ -236,7 +238,9 @@ static int yaffs_file_flush(struct file
static int yaffs_file_flush(struct file *file);
#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
static int yaffs_sync_object(struct file *file, int datasync);
#else
static int yaffs_sync_object(struct file *file, struct dentry *dentry,
@@ -1864,7 +1868,9 @@ static int yaffs_symlink(struct inode *d
return -ENOMEM;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
static int yaffs_sync_object(struct file *file, int datasync)
#else
static int yaffs_sync_object(struct file *file, struct dentry *dentry,
@@ -3067,7 +3073,13 @@ static int yaffs_internal_read_super_mtd
return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
+{
+ return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd);
+}
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
static int yaffs_read_super(struct file_system_type *fs,
int flags, const char *dev_name,
void *data, struct vfsmount *mnt)
@@ -3090,8 +3102,12 @@ static struct super_block *yaffs_read_su
static struct file_system_type yaffs_fs_type = {
.owner = THIS_MODULE,
.name = "yaffs",
- .get_sb = yaffs_read_super,
- .kill_sb = kill_block_super,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+ .mount = yaffs_mount,
+#else
+ .get_sb = yaffs_read_super,
+#endif
+ .kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
#else
@@ -3115,7 +3131,13 @@ static int yaffs2_internal_read_super_mt
return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
+{
+ return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd);
+}
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
static int yaffs2_read_super(struct file_system_type *fs,
int flags, const char *dev_name, void *data,
struct vfsmount *mnt)
@@ -3137,8 +3159,12 @@ static struct super_block *yaffs2_read_s
static struct file_system_type yaffs2_fs_type = {
.owner = THIS_MODULE,
.name = "yaffs2",
- .get_sb = yaffs2_read_super,
- .kill_sb = kill_block_super,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+ .mount = yaffs2_mount,
+#else
+ .get_sb = yaffs2_read_super,
+#endif
+ .kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
#else

View File

@ -1,54 +0,0 @@
--- a/fs/yaffs2/yaffs_mtdif1.c
+++ b/fs/yaffs2/yaffs_mtdif1.c
@@ -127,7 +127,7 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
#endif
memset(&ops, 0, sizeof(ops));
- ops.mode = MTD_OOB_AUTO;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = (__u8 *)data;
@@ -179,7 +179,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
int deleted;
memset(&ops, 0, sizeof(ops));
- ops.mode = MTD_OOB_AUTO;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = data;
--- a/fs/yaffs2/yaffs_mtdif2.c
+++ b/fs/yaffs2/yaffs_mtdif2.c
@@ -71,7 +71,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
yaffs_PackTags2(&pt, tags, !dev->param.no_tags_ecc);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
- ops.mode = MTD_OOB_AUTO;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
ops.len = dev->param.total_bytes_per_chunk;
ops.ooboffs = 0;
@@ -136,7 +136,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
&dummy, data);
else if (tags) {
- ops.mode = MTD_OOB_AUTO;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.ooblen = packed_tags_size;
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
ops.ooboffs = 0;
--- a/fs/yaffs2/yaffs_mtdif.h
+++ b/fs/yaffs2/yaffs_mtdif.h
@@ -24,4 +24,11 @@ extern struct nand_oobinfo yaffs_noeccin
#endif
int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber);
int nandmtd_InitialiseNAND(yaffs_dev_t *dev);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+#include <mtd/mtd-abi.h>
+#else
+#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
+#endif
+
#endif

View File

@ -1,78 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -220,6 +220,29 @@ static struct inode *yaffs_iget(struct s
#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->u.generic_sbp)
#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0))
+static inline void yaffs_set_nlink(struct inode *inode, unsigned int nlink)
+{
+ set_nlink(inode, nlink);
+}
+
+static inline void yaffs_dec_link_count(struct inode *inode)
+{
+ inode_dec_link_count(inode);
+}
+#else
+static inline void yaffs_set_nlink(struct inode *inode, unsigned int nlink)
+{
+ inode->i_nlink = nlink;
+}
+
+static inline void yaffs_dec_link_count(struct inode *inode)
+{
+ inode->i_nlink--;
+ mark_inode_dirty(inode)
+}
+#endif
+
#define update_dir_time(dir) do {\
(dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
@@ -1362,7 +1385,7 @@ static void yaffs_fill_inode_from_obj(st
inode->i_size = yaffs_get_obj_length(obj);
inode->i_blocks = (inode->i_size + 511) >> 9;
- inode->i_nlink = yaffs_get_obj_link_count(obj);
+ yaffs_set_nlink(inode, yaffs_get_obj_link_count(obj));
T(YAFFS_TRACE_OS,
(TSTR("yaffs_fill_inode mode %x uid %d gid %d size %d count %d\n"),
@@ -1784,10 +1807,9 @@ static int yaffs_unlink(struct inode *di
retVal = yaffs_unlinker(obj, dentry->d_name.name);
if (retVal == YAFFS_OK) {
- dentry->d_inode->i_nlink--;
+ yaffs_dec_link_count(dentry->d_inode);
dir->i_version++;
yaffs_gross_unlock(dev);
- mark_inode_dirty(dentry->d_inode);
update_dir_time(dir);
return 0;
}
@@ -1818,7 +1840,8 @@ static int yaffs_link(struct dentry *old
obj);
if (link) {
- old_dentry->d_inode->i_nlink = yaffs_get_obj_link_count(obj);
+ yaffs_set_nlink(old_dentry->d_inode,
+ yaffs_get_obj_link_count(obj));
d_instantiate(dentry, old_dentry->d_inode);
atomic_inc(&old_dentry->d_inode->i_count);
T(YAFFS_TRACE_OS,
@@ -1937,11 +1960,9 @@ static int yaffs_rename(struct inode *ol
yaffs_gross_unlock(dev);
if (retVal == YAFFS_OK) {
- if (target) {
- new_dentry->d_inode->i_nlink--;
- mark_inode_dirty(new_dentry->d_inode);
- }
-
+ if (target)
+ yaffs_dec_link_count(new_dentry->d_inode);
+
update_dir_time(old_dir);
if(old_dir != new_dir)
update_dir_time(new_dir);

View File

@ -1,71 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -273,8 +273,13 @@ static int yaffs_sync_object(struct file
static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+ struct nameidata *n);
+#else
static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *n);
+#endif
static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *n);
#else
@@ -286,9 +291,17 @@ static int yaffs_link(struct dentry *old
static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
const char *symname);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
+#else
static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+ dev_t dev);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
dev_t dev);
#else
@@ -1679,7 +1692,10 @@ out:
#define YCRED(x) (x->cred)
#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+ dev_t rdev)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
dev_t rdev)
#else
@@ -1769,7 +1785,11 @@ static int yaffs_mknod(struct inode *dir
return error;
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+#else
static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+#endif
{
int retVal;
T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
@@ -1777,7 +1797,10 @@ static int yaffs_mkdir(struct inode *dir
return retVal;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+ struct nameidata *n)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *n)
#else

View File

@ -1,160 +0,0 @@
--- a/fs/yaffs2/yaffs_mtdif1.c
+++ b/fs/yaffs2/yaffs_mtdif1.c
@@ -133,7 +133,7 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
ops.datbuf = (__u8 *)data;
ops.oobbuf = (__u8 *)&pt1;
- retval = mtd->write_oob(mtd, addr, &ops);
+ retval = mtd_write_oob(mtd, addr, &ops);
if (retval) {
T(YAFFS_TRACE_MTD,
(TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
@@ -194,7 +194,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
/* Read page and oob using MTD.
* Check status and determine ECC result.
*/
- retval = mtd->read_oob(mtd, addr, &ops);
+ retval = mtd_read_oob(mtd, addr, &ops);
if (retval) {
T(YAFFS_TRACE_MTD,
(TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
@@ -218,7 +218,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
/* fall into... */
default:
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
- etags->block_bad = (mtd->block_isbad)(mtd, addr);
+ etags->block_bad = mtd_block_isbad(mtd, addr);
return YAFFS_FAIL;
}
@@ -286,7 +286,7 @@ int nandmtd1_MarkNANDBlockBad(struct yaf
T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), block_no));
- retval = mtd->block_markbad(mtd, (loff_t)blocksize * block_no);
+ retval = mtd_block_markbad(mtd, (loff_t)blocksize * block_no);
return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
@@ -336,7 +336,7 @@ int nandmtd1_QueryNANDBlock(struct yaffs
return YAFFS_FAIL;
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
- etags.block_bad = (mtd->block_isbad)(mtd, addr);
+ etags.block_bad = mtd_block_isbad(mtd, addr);
if (etags.block_bad) {
T(YAFFS_TRACE_BAD_BLOCKS,
(TSTR("block %d is marked bad"TENDSTR), block_no));
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -2607,8 +2607,8 @@ static void yaffs_MTDPutSuper(struct sup
{
struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_SuperToDevice(sb));
- if (mtd->sync)
- mtd->sync(mtd);
+ if (mtd)
+ mtd_sync(mtd);
put_mtd_device(mtd);
}
--- a/fs/yaffs2/yaffs_mtdif2.c
+++ b/fs/yaffs2/yaffs_mtdif2.c
@@ -77,7 +77,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
ops.ooboffs = 0;
ops.datbuf = (__u8 *)data;
ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
- retval = mtd->write_oob(mtd, addr, &ops);
+ retval = mtd_write_oob(mtd, addr, &ops);
#else
if (!dev->param.inband_tags) {
@@ -133,7 +133,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
if (dev->param.inband_tags || (data && !tags))
- retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
+ retval = mtd_read(mtd, addr, dev->param.total_bytes_per_chunk,
&dummy, data);
else if (tags) {
ops.mode = MTD_OPS_AUTO_OOB;
@@ -142,7 +142,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
ops.ooboffs = 0;
ops.datbuf = data;
ops.oobbuf = yaffs_dev_to_lc(dev)->spareBuffer;
- retval = mtd->read_oob(mtd, addr, &ops);
+ retval = mtd_read_oob(mtd, addr, &ops);
}
#else
if (!dev->param.inband_tags && data && tags) {
@@ -201,7 +201,7 @@ int nandmtd2_MarkNANDBlockBad(struct yaf
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), block_no));
retval =
- mtd->block_markbad(mtd,
+ mtd_block_markbad(mtd,
block_no * dev->param.chunks_per_block *
dev->param.total_bytes_per_chunk);
@@ -221,7 +221,7 @@ int nandmtd2_QueryNANDBlock(struct yaffs
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), block_no));
retval =
- mtd->block_isbad(mtd,
+ mtd_block_isbad(mtd,
block_no * dev->param.chunks_per_block *
dev->param.total_bytes_per_chunk);
--- a/fs/yaffs2/yaffs_mtdif.h
+++ b/fs/yaffs2/yaffs_mtdif.h
@@ -31,4 +31,39 @@ int nandmtd_InitialiseNAND(yaffs_dev_t *
#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0))
+static inline int mtd_erase(struct mdt_info *mtd, struct erase_info *ei)
+{
+ return mtd->erase(mtd, ei);
+}
+
+static inline int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+ return mtd->block_mark_bad(mtd, ofs);
+}
+
+static inline int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+ return mtd->block_is_bad(mtd, ofs);
+}
+
+static inline int mtd_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+{
+ return mtd->read_oob(mtd, from, ops);
+}
+
+static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+{
+ return mtd->write_oob(mtd, to, ops);
+}
+
+static inline void mtd_sync(struct mtd_info *mtd)
+{
+ if (mtd->sync)
+ mtd->sync(mtd);
+}
+#endif
+
#endif
--- a/fs/yaffs2/yaffs_mtdif.c
+++ b/fs/yaffs2/yaffs_mtdif.c
@@ -41,7 +41,7 @@ int nandmtd_EraseBlockInNAND(yaffs_dev_t
ei.callback = NULL;
ei.priv = (u_long) dev;
- retval = mtd->erase(mtd, &ei);
+ retval = mtd_erase(mtd, &ei);
if (retval == 0)
return YAFFS_OK;

View File

@ -1,72 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -2793,6 +2793,15 @@ static struct super_block *yaffs_interna
return NULL;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->_erase));
+ T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->_read));
+ T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->_write));
+ T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->_read_oob));
+ T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->_write_oob));
+ T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->_block_isbad));
+ T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->_block_markbad));
+#else
T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
@@ -2800,6 +2809,7 @@ static struct super_block *yaffs_interna
T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
+#endif
T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
@@ -2828,6 +2838,15 @@ static struct super_block *yaffs_interna
if (yaffs_version == 2) {
/* Check for version 2 style functions */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+ if (!mtd->_erase ||
+ !mtd->_block_isbad ||
+ !mtd->_block_markbad ||
+ !mtd->_read ||
+ !mtd->_write ||
+ !mtd->_read_oob ||
+ !mtd->_write_oob) {
+#else
if (!mtd->erase ||
!mtd->block_isbad ||
!mtd->block_markbad ||
@@ -2839,6 +2858,7 @@ static struct super_block *yaffs_interna
!mtd->write_ecc ||
!mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
#endif
+#endif
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs: MTD device does not support required "
"functions\n")));
@@ -2855,6 +2875,13 @@ static struct super_block *yaffs_interna
}
} else {
/* Check for V1 style functions */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+ if (!mtd->_erase ||
+ !mtd->_read ||
+ !mtd->_write ||
+ !mtd->_read_oob ||
+ !mtd->_write_oob) {
+#else
if (!mtd->erase ||
!mtd->read ||
!mtd->write ||
@@ -2864,6 +2891,7 @@ static struct super_block *yaffs_interna
!mtd->write_ecc ||
!mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
#endif
+#endif
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs: MTD device does not support required "
"functions\n")));

View File

@ -1,14 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -3119,7 +3119,11 @@ static struct super_block *yaffs_interna
T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+ root = d_make_root(inode);
+#else
root = d_alloc_root(inode);
+#endif
T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));

View File

@ -1,15 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -924,7 +924,11 @@ static void yaffs_evict_inode( struct in
if (!inode->i_nlink && !is_bad_inode(inode))
deleteme = 1;
truncate_inode_pages(&inode->i_data,0);
- end_writeback(inode);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ clear_inode(inode);
+#else
+ end_writeback(inode);
+#endif
if(deleteme && obj){
dev = obj->my_dev;

View File

@ -1,570 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -243,11 +243,10 @@ static inline void yaffs_dec_link_count(
}
#endif
-
#define update_dir_time(dir) do {\
(dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
} while(0)
-
+
static void yaffs_put_super(struct super_block *sb);
static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
@@ -397,6 +396,33 @@ static struct address_space_operations y
#endif
};
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid())
+#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid())
+#else
+#define YCRED_FSUID() YCRED(current)->fsuid
+#define YCRED_FSGID() YCRED(current)->fsgid
+
+static inline uid_t i_uid_read(const struct inode *inode)
+{
+ return inode->i_uid;
+}
+
+static inline gid_t i_gid_read(const struct inode *inode)
+{
+ return inode->i_gid;
+}
+
+static inline void i_uid_write(struct inode *inode, uid_t uid)
+{
+ inode->i_uid = uid;
+}
+
+static inline void i_gid_write(struct inode *inode, gid_t gid)
+{
+ inode->i_gid = gid;
+}
+#endif
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
static const struct file_operations yaffs_file_operations = {
@@ -549,7 +575,7 @@ static unsigned yaffs_gc_control_callbac
{
return yaffs_gc_control;
}
-
+
static void yaffs_gross_lock(yaffs_dev_t *dev)
{
T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
@@ -1379,8 +1405,8 @@ static void yaffs_fill_inode_from_obj(st
inode->i_ino = obj->obj_id;
inode->i_mode = obj->yst_mode;
- inode->i_uid = obj->yst_uid;
- inode->i_gid = obj->yst_gid;
+ i_uid_write(inode, obj->yst_uid);
+ i_gid_write(inode, obj->yst_gid);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
inode->i_blksize = inode->i_sb->s_blocksize;
#endif
@@ -1406,7 +1432,7 @@ static void yaffs_fill_inode_from_obj(st
T(YAFFS_TRACE_OS,
(TSTR("yaffs_fill_inode mode %x uid %d gid %d size %d count %d\n"),
- inode->i_mode, inode->i_uid, inode->i_gid,
+ inode->i_mode, i_uid_read(inode), i_gid_read(inode),
(int)inode->i_size, atomic_read(&inode->i_count)));
switch (obj->yst_mode & S_IFMT) {
@@ -1715,8 +1741,8 @@ static int yaffs_mknod(struct inode *dir
yaffs_obj_t *parent = yaffs_InodeToObject(dir);
int error = -ENOSPC;
- uid_t uid = YCRED(current)->fsuid;
- gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ uid_t uid = YCRED_FSUID();
+ gid_t gid = (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
mode |= S_ISGID;
@@ -1892,8 +1918,8 @@ static int yaffs_symlink(struct inode *d
{
yaffs_obj_t *obj;
yaffs_dev_t *dev;
- uid_t uid = YCRED(current)->fsuid;
- gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ uid_t uid = YCRED_FSUID();
+ gid_t gid = (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
@@ -2009,7 +2035,7 @@ static int yaffs_setattr(struct dentry *
(TSTR("yaffs_setattr of object %d\n"),
yaffs_InodeToObject(inode)->obj_id));
- /* Fail if a requested resize >= 2GB */
+ /* Fail if a requested resize >= 2GB */
if (attr->ia_valid & ATTR_SIZE &&
(attr->ia_size >> 31))
error = -EINVAL;
@@ -2240,7 +2266,7 @@ static void yaffs_flush_inodes(struct su
{
struct inode *iptr;
yaffs_obj_t *obj;
-
+
list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
obj = yaffs_InodeToObject(iptr);
if(obj){
@@ -2254,10 +2280,10 @@ static void yaffs_flush_inodes(struct su
static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
{
- yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
+ yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
if(!dev)
return;
-
+
yaffs_flush_inodes(sb);
yaffs_update_dirty_dirs(dev);
yaffs_flush_whole_cache(dev);
@@ -2325,7 +2351,7 @@ static int yaffs_do_sync_fs(struct super
* yaffs_bg_start() launches the background thread.
* yaffs_bg_stop() cleans up the background thread.
*
- * NB:
+ * NB:
* The thread should only run after the yaffs is initialised
* The thread should be stopped before yaffs is unmounted.
* The thread should not do any writing while the fs is in read only.
@@ -2924,7 +2950,7 @@ static struct super_block *yaffs_interna
dev = kmalloc(sizeof(yaffs_dev_t), GFP_KERNEL);
context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
-
+
if(!dev || !context ){
if(dev)
kfree(dev);
@@ -2957,7 +2983,7 @@ static struct super_block *yaffs_interna
#else
sb->u.generic_sbp = dev;
#endif
-
+
dev->driver_context = mtd;
param->name = mtd->name;
@@ -3057,7 +3083,7 @@ static struct super_block *yaffs_interna
param->gc_control = yaffs_gc_control_callback;
yaffs_dev_to_lc(dev)->superBlock= sb;
-
+
#ifndef CONFIG_YAFFS_DOES_ECC
param->use_nand_ecc = 1;
@@ -3099,10 +3125,10 @@ static struct super_block *yaffs_interna
T(YAFFS_TRACE_OS,
(TSTR("yaffs_read_super: guts initialised %s\n"),
(err == YAFFS_OK) ? "OK" : "FAILED"));
-
+
if(err == YAFFS_OK)
yaffs_bg_start(dev);
-
+
if(!context->bgThread)
param->defered_dir_update = 0;
@@ -3345,7 +3371,7 @@ static int yaffs_proc_read(char *page,
buf += sprintf(buf,"\n");
else {
step-=2;
-
+
mutex_lock(&yaffs_context_lock);
/* Locate and print the Nth entry. Order N-squared but N is small. */
@@ -3362,7 +3388,7 @@ static int yaffs_proc_read(char *page,
buf = yaffs_dump_dev_part0(buf, dev);
} else
buf = yaffs_dump_dev_part1(buf, dev);
-
+
break;
}
mutex_unlock(&yaffs_context_lock);
@@ -3389,7 +3415,7 @@ static int yaffs_stats_proc_read(char *p
int erasedChunks;
erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
-
+
buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n",
n, dev->n_free_chunks, erasedChunks,
dev->bg_gcs, dev->oldest_dirty_gc_count,
--- a/fs/yaffs2/yaffs_guts.c
+++ b/fs/yaffs2/yaffs_guts.c
@@ -370,7 +370,7 @@ static int yaffs_verify_chunk_written(ya
yaffs_ext_tags tempTags;
__u8 *buffer = yaffs_get_temp_buffer(dev,__LINE__);
int result;
-
+
result = yaffs_rd_chunk_tags_nand(dev,nand_chunk,buffer,&tempTags);
if(memcmp(buffer,data,dev->data_bytes_per_chunk) ||
tempTags.obj_id != tags->obj_id ||
@@ -424,7 +424,7 @@ static int yaffs_write_new_chunk(struct
* lot of checks that are most likely not needed.
*
* Mods to the above
- * If an erase check fails or the write fails we skip the
+ * If an erase check fails or the write fails we skip the
* rest of the block.
*/
@@ -486,7 +486,7 @@ static int yaffs_write_new_chunk(struct
}
-
+
/*
* Block retiring for handling a broken block.
*/
@@ -496,7 +496,7 @@ static void yaffs_retire_block(yaffs_dev
yaffs_block_info_t *bi = yaffs_get_block_info(dev, flash_block);
yaffs2_checkpt_invalidate(dev);
-
+
yaffs2_clear_oldest_dirty_seq(dev,bi);
if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
@@ -899,7 +899,7 @@ static int yaffs_find_chunk_in_group(yaf
for (j = 0; theChunk && j < dev->chunk_grp_size; j++) {
if (yaffs_check_chunk_bit(dev, theChunk / dev->param.chunks_per_block,
theChunk % dev->param.chunks_per_block)) {
-
+
if(dev->chunk_grp_size == 1)
return theChunk;
else {
@@ -1802,7 +1802,7 @@ int yaffs_rename_obj(yaffs_obj_t *old_di
yaffs_update_parent(old_dir);
if(new_dir != old_dir)
yaffs_update_parent(new_dir);
-
+
return result;
}
return YAFFS_FAIL;
@@ -2125,7 +2125,7 @@ static int yaffs_gc_block(yaffs_dev_t *d
if(bi->block_state == YAFFS_BLOCK_STATE_FULL)
bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
-
+
bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
dev->gc_disable = 1;
@@ -2207,7 +2207,7 @@ static int yaffs_gc_block(yaffs_dev_t *d
* No need to copy this, just forget about it and
* fix up the object.
*/
-
+
/* Free chunks already includes softdeleted chunks.
* How ever this chunk is going to soon be really deleted
* which will increment free chunks.
@@ -2752,7 +2752,7 @@ int yaffs_put_chunk_in_file(yaffs_obj_t
NULL);
if (!tn)
return YAFFS_FAIL;
-
+
if(!nand_chunk)
/* Dummy insert, bail now */
return YAFFS_OK;
@@ -2881,7 +2881,7 @@ void yaffs_chunk_del(yaffs_dev_t *dev, i
chunk_id));
bi = yaffs_get_block_info(dev, block);
-
+
yaffs2_update_oldest_dirty_seq(dev, block, bi);
T(YAFFS_TRACE_DELETION,
@@ -2966,8 +2966,8 @@ static int yaffs_wr_data_obj(yaffs_obj_t
(TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), n_bytes));
YBUG();
}
-
-
+
+
newChunkId =
yaffs_write_new_chunk(dev, buffer, &newTags,
useReserve);
@@ -3795,14 +3795,14 @@ int yaffs_resize_file(yaffs_obj_t *in, l
if (new_size == oldFileSize)
return YAFFS_OK;
-
+
if(new_size > oldFileSize){
yaffs2_handle_hole(in,new_size);
in->variant.file_variant.file_size = new_size;
} else {
- /* new_size < oldFileSize */
+ /* new_size < oldFileSize */
yaffs_resize_file_down(in, new_size);
- }
+ }
/* Write a new object header to reflect the resize.
* show we've shrunk the file, if need be
@@ -4231,7 +4231,7 @@ static void yaffs_strip_deleted_objs(yaf
* This fixes the problem where directories might have inadvertently been deleted
* leaving the object "hanging" without being rooted in the directory tree.
*/
-
+
static int yaffs_has_null_parent(yaffs_dev_t *dev, yaffs_obj_t *obj)
{
return (obj == dev->del_dir ||
@@ -4262,7 +4262,7 @@ static void yaffs_fix_hanging_objs(yaffs
if (lh) {
obj = ylist_entry(lh, yaffs_obj_t, hash_link);
parent= obj->parent;
-
+
if(yaffs_has_null_parent(dev,obj)){
/* These directories are not hanging */
hanging = 0;
@@ -4311,7 +4311,7 @@ static void yaffs_del_dir_contents(yaffs
if(dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
YBUG();
-
+
ylist_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
if (lh) {
obj = ylist_entry(lh, yaffs_obj_t, siblings);
@@ -4325,10 +4325,10 @@ static void yaffs_del_dir_contents(yaffs
/* Need to use UnlinkObject since Delete would not handle
* hardlinked objects correctly.
*/
- yaffs_unlink_obj(obj);
+ yaffs_unlink_obj(obj);
}
}
-
+
}
static void yaffs_empty_l_n_f(yaffs_dev_t *dev)
@@ -4410,7 +4410,7 @@ static void yaffs_check_obj_details_load
* If the directory updating is defered then yaffs_update_dirty_dirs must be
* called periodically.
*/
-
+
static void yaffs_update_parent(yaffs_obj_t *obj)
{
yaffs_dev_t *dev;
@@ -4422,8 +4422,8 @@ static void yaffs_update_parent(yaffs_ob
obj->dirty = 1;
obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
if(dev->param.defered_dir_update){
- struct ylist_head *link = &obj->variant.dir_variant.dirty;
-
+ struct ylist_head *link = &obj->variant.dir_variant.dirty;
+
if(ylist_empty(link)){
ylist_add(link,&dev->dirty_dirs);
T(YAFFS_TRACE_BACKGROUND, (TSTR("Added object %d to dirty directories" TENDSTR),obj->obj_id));
@@ -4446,7 +4446,7 @@ void yaffs_update_dirty_dirs(yaffs_dev_t
while(!ylist_empty(&dev->dirty_dirs)){
link = dev->dirty_dirs.next;
ylist_del_init(link);
-
+
dS=ylist_entry(link,yaffs_dir_s,dirty);
oV = ylist_entry(dS,yaffs_obj_variant,dir_variant);
obj = ylist_entry(oV,yaffs_obj_t,variant);
@@ -4474,7 +4474,7 @@ static void yaffs_remove_obj_from_dir(ya
ylist_del_init(&obj->siblings);
obj->parent = NULL;
-
+
yaffs_verify_dir(parent);
}
@@ -4645,7 +4645,7 @@ yaffs_obj_t *yaffs_get_equivalent_obj(ya
* system to share files.
*
* These automatic unicode are stored slightly differently...
- * - If the name can fit in the ASCII character space then they are saved as
+ * - If the name can fit in the ASCII character space then they are saved as
* ascii names as per above.
* - If the name needs Unicode then the name is saved in Unicode
* starting at oh->name[1].
@@ -4686,7 +4686,7 @@ static void yaffs_load_name_from_oh(yaff
asciiOhName++;
n--;
}
- } else
+ } else
yaffs_strncpy(name,ohName+1, bufferSize -1);
} else
#endif
@@ -4705,7 +4705,7 @@ static void yaffs_load_oh_from_name(yaff
isAscii = 1;
w = name;
-
+
/* Figure out if the name will fit in ascii character set */
while(isAscii && *w){
if((*w) & 0xff00)
@@ -4729,7 +4729,7 @@ static void yaffs_load_oh_from_name(yaff
yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2);
}
}
- else
+ else
#endif
yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1);
@@ -4738,12 +4738,12 @@ static void yaffs_load_oh_from_name(yaff
int yaffs_get_obj_name(yaffs_obj_t * obj, YCHAR * name, int buffer_size)
{
memset(name, 0, buffer_size * sizeof(YCHAR));
-
+
yaffs_check_obj_details_loaded(obj);
if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
- }
+ }
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
else if (obj->short_name[0]) {
yaffs_strcpy(name, obj->short_name);
@@ -4861,9 +4861,9 @@ int yaffs_set_attribs(yaffs_obj_t *obj,
if (valid & ATTR_MODE)
obj->yst_mode = attr->ia_mode;
if (valid & ATTR_UID)
- obj->yst_uid = attr->ia_uid;
+ obj->yst_uid = ia_uid_read(attr);
if (valid & ATTR_GID)
- obj->yst_gid = attr->ia_gid;
+ obj->yst_gid = ia_gid_read(attr);
if (valid & ATTR_ATIME)
obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
@@ -4886,9 +4886,9 @@ int yaffs_get_attribs(yaffs_obj_t *obj,
attr->ia_mode = obj->yst_mode;
valid |= ATTR_MODE;
- attr->ia_uid = obj->yst_uid;
+ ia_uid_write(attr, obj->yst_uid);
valid |= ATTR_UID;
- attr->ia_gid = obj->yst_gid;
+ ia_gid_write(attr, obj->yst_gid);
valid |= ATTR_GID;
Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
--- a/fs/yaffs2/yportenv.h
+++ b/fs/yaffs2/yportenv.h
@@ -170,7 +170,7 @@
#define O_RDWR 02
#endif
-#ifndef O_CREAT
+#ifndef O_CREAT
#define O_CREAT 0100
#endif
@@ -218,7 +218,7 @@
#define EACCES 13
#endif
-#ifndef EXDEV
+#ifndef EXDEV
#define EXDEV 18
#endif
@@ -281,7 +281,7 @@
#define S_IFREG 0100000
#endif
-#ifndef S_IREAD
+#ifndef S_IREAD
#define S_IREAD 0000400
#endif
--- a/fs/yaffs2/devextras.h
+++ b/fs/yaffs2/devextras.h
@@ -87,6 +87,8 @@ struct iattr {
unsigned int ia_attr_flags;
};
+/* TODO: add ia_* functions */
+
#endif
#else
@@ -95,7 +97,48 @@ struct iattr {
#include <linux/fs.h>
#include <linux/stat.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+static inline uid_t ia_uid_read(const struct iattr *iattr)
+{
+ return from_kuid(&init_user_ns, iattr->ia_uid);
+}
+
+static inline gid_t ia_gid_read(const struct iattr *iattr)
+{
+ return from_kgid(&init_user_ns, iattr->ia_gid);
+}
+
+static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
+{
+ iattr->ia_uid = make_kuid(&init_user_ns, uid);
+}
+
+static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
+{
+ iattr->ia_gid = make_kgid(&init_user_ns, gid);
+}
+#else
+static inline uid_t ia_uid_read(const struct iattr *iattr)
+{
+ return iattr->ia_uid;
+}
+
+static inline gid_t ia_gid_read(const struct iattr *inode)
+{
+ return iattr->ia_gid;
+}
+
+static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
+{
+ iattr->ia_uid = uid;
+}
+
+static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
+{
+ iattr->ia_gid = gid;
+}
#endif
+#endif
#endif

View File

@ -1,60 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -271,20 +271,29 @@ static int yaffs_sync_object(struct file
static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+ bool excl);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
struct nameidata *n);
-#else
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *n);
+#else
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *n);
#else
-static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
#endif
+
static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *dentry);
static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
@@ -837,7 +846,10 @@ struct inode *yaffs_get_inode(struct sup
/*
* Lookup is used to find objects in the fs
*/
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *n)
@@ -1827,7 +1839,10 @@ static int yaffs_mkdir(struct inode *dir
return retVal;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+ bool excl)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
struct nameidata *n)
#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))

View File

@ -1,180 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -393,6 +393,84 @@ static void yaffs_touch_super(yaffs_dev_
static int yaffs_vfs_setattr(struct inode *, struct iattr *);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+
+#define yaffs_super_to_dev(sb) ((struct yaffs_dev_s *)sb->s_fs_info)
+
+static inline struct yaffs_LinuxContext *
+yaffs_sb_to_ylc(struct super_block *sb)
+{
+ struct yaffs_dev_s *ydev;
+ struct yaffs_LinuxContext *ylc;
+
+ ydev = yaffs_super_to_dev(sb);
+ ylc = yaffs_dev_to_lc(ydev);
+ return ylc;
+}
+
+static inline struct super_block *yaffs_work_to_sb(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct yaffs_LinuxContext *ylc;
+
+ dwork = container_of(work, struct delayed_work, work);
+ ylc = container_of(dwork, struct yaffs_LinuxContext, sb_sync_dwork);
+ return ylc->superBlock;
+}
+
+static void yaffs_sb_sync_dwork_func(struct work_struct *work)
+{
+ struct super_block *sb = yaffs_work_to_sb(work);
+
+ yaffs_write_super(sb);
+}
+
+static void yaffs_init_sb_sync_dwork(struct yaffs_LinuxContext *ylc)
+{
+ INIT_DELAYED_WORK(&ylc->sb_sync_dwork, yaffs_sb_sync_dwork_func);
+}
+
+static void yaffs_cancel_sb_sync_dwork(struct super_block *sb)
+{
+ struct yaffs_LinuxContext *ylc = yaffs_sb_to_ylc(sb);
+
+ cancel_delayed_work_sync(&ylc->sb_sync_dwork);
+}
+
+static inline bool yaffs_sb_is_dirty(struct super_block *sb)
+{
+ struct yaffs_LinuxContext *ylc = yaffs_sb_to_ylc(sb);
+
+ return !!ylc->sb_dirty;
+}
+
+static inline void yaffs_sb_set_dirty(struct super_block *sb, int dirty)
+{
+ struct yaffs_LinuxContext *ylc = yaffs_sb_to_ylc(sb);
+
+ if (ylc->sb_dirty == dirty)
+ return;
+
+ ylc->sb_dirty = dirty;
+ if (dirty)
+ queue_delayed_work(system_long_wq, &ylc->sb_sync_dwork,
+ msecs_to_jiffies(5000));
+}
+#else
+static inline bool yaffs_sb_is_dirty(struct super_block *sb)
+{
+ return !!sb->s_dirt;
+}
+
+static inline void yaffs_sb_set_dirty(struct super_block *sb, int dirty)
+{
+ sb->s_dirt = dirty;
+}
+
+static inline void yaffs_init_sb_sync_dwork(struct yaffs_LinuxContext *ylc) {}
+static inline void yaffs_cancel_sb_sync_dwork(struct super_block *sb) {}
+#endif /* >= 3.6.0 */
+
static struct address_space_operations yaffs_file_address_operations = {
.readpage = yaffs_readpage,
.writepage = yaffs_writepage,
@@ -553,7 +631,9 @@ static const struct super_operations yaf
.clear_inode = yaffs_clear_inode,
#endif
.sync_fs = yaffs_sync_fs,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
.write_super = yaffs_write_super,
+#endif
};
@@ -2340,7 +2420,7 @@ static int yaffs_do_sync_fs(struct super
T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
(TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
gc_urgent,
- sb->s_dirt ? "dirty" : "clean",
+ yaffs_sb_is_dirty(sb) ? "dirty" : "clean",
request_checkpoint ? "checkpoint requested" : "no checkpoint",
oneshot_checkpoint ? " one-shot" : "" ));
@@ -2349,9 +2429,9 @@ static int yaffs_do_sync_fs(struct super
oneshot_checkpoint) &&
!dev->is_checkpointed;
- if (sb->s_dirt || do_checkpoint) {
+ if (yaffs_sb_is_dirty(sb) || do_checkpoint) {
yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
- sb->s_dirt = 0;
+ yaffs_sb_set_dirty(sb, 0);
if(oneshot_checkpoint)
yaffs_auto_checkpoint &= ~4;
}
@@ -2627,6 +2707,8 @@ static void yaffs_put_super(struct super
yaffs_flush_super(sb,1);
+ yaffs_cancel_sb_sync_dwork(sb);
+
if (yaffs_dev_to_lc(dev)->putSuperFunc)
yaffs_dev_to_lc(dev)->putSuperFunc(sb);
@@ -2665,7 +2747,7 @@ static void yaffs_touch_super(yaffs_dev_
T(YAFFS_TRACE_OS, (TSTR("yaffs_touch_super() sb = %p\n"), sb));
if (sb)
- sb->s_dirt = 1;
+ yaffs_sb_set_dirty(sb, 1);
}
typedef struct {
@@ -2991,6 +3073,8 @@ static struct super_block *yaffs_interna
context->dev = dev;
context->superBlock = sb;
+ yaffs_init_sb_sync_dwork(context);
+
dev->read_only = read_only;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
@@ -3177,7 +3261,7 @@ static struct super_block *yaffs_interna
return NULL;
}
sb->s_root = root;
- sb->s_dirt = !dev->is_checkpointed;
+ yaffs_sb_set_dirty(sb, !dev->is_checkpointed);
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs_read_super: is_checkpointed %d\n"),
dev->is_checkpointed));
--- a/fs/yaffs2/yaffs_linux.h
+++ b/fs/yaffs2/yaffs_linux.h
@@ -34,6 +34,11 @@ struct yaffs_LinuxContext {
struct task_struct *readdirProcess;
unsigned mount_id;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ struct delayed_work sb_sync_dwork; /* superblock write-out work */
+ int sb_dirty; /* superblock is dirty */
+#endif
};
#define yaffs_dev_to_lc(dev) ((struct yaffs_LinuxContext *)((dev)->os_context))
--- a/fs/yaffs2/yportenv.h
+++ b/fs/yaffs2/yportenv.h
@@ -49,6 +49,9 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/xattr.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+#include <linux/workqueue.h>
+#endif
#define YCHAR char
#define YUCHAR unsigned char

View File

@ -1,45 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -3385,6 +3385,7 @@ static DECLARE_FSTYPE(yaffs2_fs_type, "y
#endif /* CONFIG_YAFFS_YAFFS2 */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
static struct proc_dir_entry *my_proc_entry;
static struct proc_dir_entry *debug_proc_entry;
@@ -3668,6 +3669,7 @@ static int yaffs_proc_write(struct file
{
return yaffs_proc_write_trace_options(file, buf, count, data);
}
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */
/* Stuff to handle installation of file systems */
struct file_system_to_install {
@@ -3699,6 +3701,7 @@ static int __init init_yaffs_fs(void)
mutex_init(&yaffs_context_lock);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
/* Install the proc_fs entries */
my_proc_entry = create_proc_entry("yaffs",
S_IRUGO | S_IFREG,
@@ -3721,6 +3724,7 @@ static int __init init_yaffs_fs(void)
debug_proc_entry->data = NULL;
} else
return -ENOMEM;
+#endif
/* Now add the file system entries */
@@ -3757,8 +3761,10 @@ static void __exit exit_yaffs_fs(void)
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
remove_proc_entry("yaffs", YPROC_ROOT);
remove_proc_entry("yaffs_stats", YPROC_ROOT);
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */
fsinst = fs_to_install;

View File

@ -0,0 +1,155 @@
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -329,6 +329,33 @@ static int yaffs_readpage(struct file *f
return ret;
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid())
+#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid())
+#else
+#define YCRED_FSUID() YCRED(current)->fsuid
+#define YCRED_FSGID() YCRED(current)->fsgid
+
+static inline uid_t i_uid_read(const struct inode *inode)
+{
+ return inode->i_uid;
+}
+
+static inline gid_t i_gid_read(const struct inode *inode)
+{
+ return inode->i_gid;
+}
+
+static inline void i_uid_write(struct inode *inode, uid_t uid)
+{
+ inode->i_uid = uid;
+}
+
+static inline void i_gid_write(struct inode *inode, gid_t gid)
+{
+ inode->i_gid = gid;
+}
+#endif
static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)
{
@@ -1225,9 +1252,9 @@ static int yaffs_mknod(struct inode *dir
struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
int error = -ENOSPC;
- uid_t uid = YCRED(current)->fsuid;
+ uid_t uid = YCRED_FSUID();
gid_t gid =
- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
mode |= S_ISGID;
@@ -1424,9 +1451,9 @@ static int yaffs_symlink(struct inode *d
{
struct yaffs_obj *obj;
struct yaffs_dev *dev;
- uid_t uid = YCRED(current)->fsuid;
+ uid_t uid = YCRED_FSUID();
gid_t gid =
- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
@@ -1829,8 +1856,8 @@ static void yaffs_fill_inode_from_obj(st
inode->i_ino = obj->obj_id;
inode->i_mode = obj->yst_mode;
- inode->i_uid = obj->yst_uid;
- inode->i_gid = obj->yst_gid;
+ i_uid_write(inode, obj->yst_uid);
+ i_gid_write(inode, obj->yst_gid);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
inode->i_blksize = inode->i_sb->s_blocksize;
#endif
@@ -1856,7 +1883,7 @@ static void yaffs_fill_inode_from_obj(st
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
- inode->i_mode, inode->i_uid, inode->i_gid,
+ inode->i_mode, i_uid_read(inode), i_gid_read(inode),
inode->i_size, atomic_read(&inode->i_count));
switch (obj->yst_mode & S_IFMT) {
--- a/fs/yaffs2/yaffs_attribs.c
+++ b/fs/yaffs2/yaffs_attribs.c
@@ -14,6 +14,48 @@
#include "yaffs_guts.h"
#include "yaffs_attribs.h"
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+static inline uid_t ia_uid_read(const struct iattr *iattr)
+{
+ return from_kuid(&init_user_ns, iattr->ia_uid);
+}
+
+static inline gid_t ia_gid_read(const struct iattr *iattr)
+{
+ return from_kgid(&init_user_ns, iattr->ia_gid);
+}
+
+static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
+{
+ iattr->ia_uid = make_kuid(&init_user_ns, uid);
+}
+
+static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
+{
+ iattr->ia_gid = make_kgid(&init_user_ns, gid);
+}
+#else
+static inline uid_t ia_uid_read(const struct iattr *iattr)
+{
+ return iattr->ia_uid;
+}
+
+static inline gid_t ia_gid_read(const struct iattr *inode)
+{
+ return iattr->ia_gid;
+}
+
+static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
+{
+ iattr->ia_uid = uid;
+}
+
+static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
+{
+ iattr->ia_gid = gid;
+}
+#endif
+
void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
{
obj->yst_uid = oh->yst_uid;
@@ -77,9 +119,9 @@ int yaffs_set_attribs(struct yaffs_obj *
if (valid & ATTR_MODE)
obj->yst_mode = attr->ia_mode;
if (valid & ATTR_UID)
- obj->yst_uid = attr->ia_uid;
+ obj->yst_uid = ia_uid_read(attr);
if (valid & ATTR_GID)
- obj->yst_gid = attr->ia_gid;
+ obj->yst_gid = ia_gid_read(attr);
if (valid & ATTR_ATIME)
obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
@@ -103,9 +145,9 @@ int yaffs_get_attribs(struct yaffs_obj *
attr->ia_mode = obj->yst_mode;
valid |= ATTR_MODE;
- attr->ia_uid = obj->yst_uid;
+ ia_uid_write(attr, obj->yst_uid);
valid |= ATTR_UID;
- attr->ia_gid = obj->yst_gid;
+ ia_gid_write(attr, obj->yst_gid);
valid |= ATTR_GID;
Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;

View File

@ -1,31 +0,0 @@
From 2505e8b0a13d3d5c5bbeaaae4eb889864f44c9df Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Thu, 3 Feb 2011 05:55:30 +1300
Subject: [PATCH] yaffs: Fix directory unlinking in yaffs1 mode
commit 964b3425a71890e6701c830e38b04d8557c04f49 upstream.
Treat both yaffs2 and yaffs1 paths the same.
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
yaffs_guts.c | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
--- a/fs/yaffs2/yaffs_guts.c
+++ b/fs/yaffs2/yaffs_guts.c
@@ -1708,13 +1708,7 @@ static int yaffs_change_obj_name(yaffs_o
YBUG();
}
- /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
- if (obj->my_dev->param.is_yaffs2)
- unlinkOp = (new_dir == obj->my_dev->unlinked_dir);
- else
- unlinkOp = (new_dir == obj->my_dev->unlinked_dir
- && obj->variant_type == YAFFS_OBJECT_TYPE_FILE);
-
+ unlinkOp = (new_dir == obj->my_dev->unlinked_dir);
deleteOp = (new_dir == obj->my_dev->del_dir);
existingTarget = yaffs_find_by_name(new_dir, new_name);

View File

@ -0,0 +1,44 @@
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -3025,6 +3025,7 @@ static DECLARE_FSTYPE(yaffs2_fs_type, "y
#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
static struct proc_dir_entry *my_proc_entry;
static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
@@ -3398,6 +3399,7 @@ static int yaffs_proc_write(struct file
return yaffs_proc_debug_write(file, buf, count, data);
return yaffs_proc_write_trace_options(file, buf, count, data);
}
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */
/* Stuff to handle installation of file systems */
struct file_system_to_install {
@@ -3421,6 +3423,7 @@ static int __init init_yaffs_fs(void)
mutex_init(&yaffs_context_lock);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
/* Install the proc_fs entries */
my_proc_entry = create_proc_entry("yaffs",
S_IRUGO | S_IFREG, YPROC_ROOT);
@@ -3432,6 +3435,7 @@ static int __init init_yaffs_fs(void)
} else {
return -ENOMEM;
}
+#endif
/* Now add the file system entries */
@@ -3468,7 +3472,9 @@ static void __exit exit_yaffs_fs(void)
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs built " __DATE__ " " __TIME__ " removing.");
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
remove_proc_entry("yaffs", YPROC_ROOT);
+#endif
fsinst = fs_to_install;

View File

@ -1,138 +0,0 @@
From c0c289363e84c53b5872f7c0c5069045096dca07 Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Wed, 3 Nov 2010 16:01:12 +1300
Subject: [PATCH] yaffs: Switch from semaphores to mutexes
commit 73c54aa8c1de3f61a4c211cd47431293a6092f18 upstream.
Mutex is faster and init_MUTEX has been deprecated, so we'll just switch
to mutexes.
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
yaffs_linux.h | 2 +-
yaffs_vfs.c | 24 ++++++++++++------------
yaffs_vfs_multi.c | 26 +++++++++++++-------------
3 files changed, 26 insertions(+), 26 deletions(-)
--- a/fs/yaffs2/yaffs_linux.h
+++ b/fs/yaffs2/yaffs_linux.h
@@ -25,7 +25,7 @@ struct yaffs_LinuxContext {
struct super_block * superBlock;
struct task_struct *bgThread; /* Background thread for this device */
int bgRunning;
- struct semaphore grossLock; /* Gross locking semaphore */
+ struct mutex grossLock; /* Gross locking mutex*/
__u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
* at compile time so we have to allocate it.
*/
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -515,14 +515,14 @@ static unsigned yaffs_gc_control_callbac
static void yaffs_gross_lock(yaffs_dev_t *dev)
{
T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
- down(&(yaffs_dev_to_lc(dev)->grossLock));
+ mutex_lock(&(yaffs_dev_to_lc(dev)->grossLock));
T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
}
static void yaffs_gross_unlock(yaffs_dev_t *dev)
{
T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
- up(&(yaffs_dev_to_lc(dev)->grossLock));
+ mutex_unlock(&(yaffs_dev_to_lc(dev)->grossLock));
}
#ifdef YAFFS_COMPILE_EXPORTFS
@@ -2542,7 +2542,7 @@ static void yaffs_read_inode(struct inod
#endif
static YLIST_HEAD(yaffs_context_list);
-struct semaphore yaffs_context_lock;
+struct mutex yaffs_context_lock;
static void yaffs_put_super(struct super_block *sb)
{
@@ -2568,9 +2568,9 @@ static void yaffs_put_super(struct super
yaffs_gross_unlock(dev);
- down(&yaffs_context_lock);
+ mutex_lock(&yaffs_context_lock);
ylist_del_init(&(yaffs_dev_to_lc(dev)->contextList));
- up(&yaffs_context_lock);
+ mutex_unlock(&yaffs_context_lock);
if (yaffs_dev_to_lc(dev)->spareBuffer) {
YFREE(yaffs_dev_to_lc(dev)->spareBuffer);
@@ -3016,7 +3016,7 @@ static struct super_block *yaffs_interna
param->skip_checkpt_rd = options.skip_checkpoint_read;
param->skip_checkpt_wr = options.skip_checkpoint_write;
- down(&yaffs_context_lock);
+ mutex_lock(&yaffs_context_lock);
/* Get a mount id */
found = 0;
for(mount_id=0; ! found; mount_id++){
@@ -3030,13 +3030,13 @@ static struct super_block *yaffs_interna
context->mount_id = mount_id;
ylist_add_tail(&(yaffs_dev_to_lc(dev)->contextList), &yaffs_context_list);
- up(&yaffs_context_lock);
+ mutex_unlock(&yaffs_context_lock);
/* Directory search handling...*/
YINIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->searchContexts));
param->remove_obj_fn = yaffs_remove_obj_callback;
- init_MUTEX(&(yaffs_dev_to_lc(dev)->grossLock));
+ mutex_init(&(yaffs_dev_to_lc(dev)->grossLock));
yaffs_gross_lock(dev);
@@ -3268,7 +3268,7 @@ static int yaffs_proc_read(char *page,
else {
step-=2;
- down(&yaffs_context_lock);
+ mutex_lock(&yaffs_context_lock);
/* Locate and print the Nth entry. Order N-squared but N is small. */
ylist_for_each(item, &yaffs_context_list) {
@@ -3287,7 +3287,7 @@ static int yaffs_proc_read(char *page,
break;
}
- up(&yaffs_context_lock);
+ mutex_unlock(&yaffs_context_lock);
}
return buf - page < count ? buf - page : count;
@@ -3301,7 +3301,7 @@ static int yaffs_stats_proc_read(char *p
char *buf = page;
int n = 0;
- down(&yaffs_context_lock);
+ mutex_lock(&yaffs_context_lock);
/* Locate and print the Nth entry. Order N-squared but N is small. */
ylist_for_each(item, &yaffs_context_list) {
@@ -3317,7 +3317,7 @@ static int yaffs_stats_proc_read(char *p
dev->bg_gcs, dev->oldest_dirty_gc_count,
dev->n_obj, dev->n_tnodes);
}
- up(&yaffs_context_lock);
+ mutex_unlock(&yaffs_context_lock);
return buf - page < count ? buf - page : count;
@@ -3494,7 +3494,7 @@ static int __init init_yaffs_fs(void)
- init_MUTEX(&yaffs_context_lock);
+ mutex_init(&yaffs_context_lock);
/* Install the proc_fs entries */
my_proc_entry = create_proc_entry("yaffs",

View File

@ -0,0 +1,129 @@
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -1701,6 +1701,110 @@ static void yaffs_remove_obj_callback(st
/*-----------------------------------------------------------------*/
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+static int yaffs_readdir(struct file *file, struct dir_context *ctx)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_dev *dev;
+ struct yaffs_search_context *sc;
+ struct inode *inode = file->f_dentry->d_inode;
+ unsigned long offset, curoffs;
+ struct yaffs_obj *l;
+ int ret_val = 0;
+
+ char name[YAFFS_MAX_NAME_LENGTH + 1];
+
+ obj = yaffs_dentry_to_obj(file->f_dentry);
+ dev = obj->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ yaffs_dev_to_lc(dev)->readdir_process = current;
+
+ offset = ctx->pos;
+
+ sc = yaffs_new_search(obj);
+ if (!sc) {
+ ret_val = -ENOMEM;
+ goto out;
+ }
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_readdir: starting at %d", (int)offset);
+
+ if (offset == 0) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_readdir: entry . ino %d",
+ (int)inode->i_ino);
+ yaffs_gross_unlock(dev);
+ if (!dir_emit_dot(file, ctx)) {
+ yaffs_gross_lock(dev);
+ goto out;
+ }
+ yaffs_gross_lock(dev);
+ offset++;
+ ctx->pos++;
+ }
+ if (offset == 1) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_readdir: entry .. ino %d",
+ (int)file->f_dentry->d_parent->d_inode->i_ino);
+ yaffs_gross_unlock(dev);
+ if (!dir_emit_dotdot(file, ctx)) {
+ yaffs_gross_lock(dev);
+ goto out;
+ }
+ yaffs_gross_lock(dev);
+ offset++;
+ ctx->pos++;
+ }
+
+ curoffs = 1;
+
+ /* If the directory has changed since the open or last call to
+ readdir, rewind to after the 2 canned entries. */
+ if (file->f_version != inode->i_version) {
+ offset = 2;
+ ctx->pos = offset;
+ file->f_version = inode->i_version;
+ }
+
+ while (sc->next_return) {
+ curoffs++;
+ l = sc->next_return;
+ if (curoffs >= offset) {
+ int this_inode = yaffs_get_obj_inode(l);
+ int this_type = yaffs_get_obj_type(l);
+
+ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_readdir: %s inode %d",
+ name, yaffs_get_obj_inode(l));
+
+ yaffs_gross_unlock(dev);
+
+ if (!dir_emit(ctx, name, strlen(name),
+ this_inode, this_type) < 0) {
+ yaffs_gross_lock(dev);
+ goto out;
+ }
+
+ yaffs_gross_lock(dev);
+
+ offset++;
+ ctx->pos++;
+ }
+ yaffs_search_advance(sc);
+ }
+
+out:
+ yaffs_search_end(sc);
+ yaffs_dev_to_lc(dev)->readdir_process = NULL;
+ yaffs_gross_unlock(dev);
+
+ return ret_val;
+}
+#else
static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
{
struct yaffs_obj *obj;
@@ -1807,10 +1911,15 @@ out:
return ret_val;
}
+#endif
static const struct file_operations yaffs_dir_operations = {
.read = generic_read_dir,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+ .iterate = yaffs_readdir,
+#else
.readdir = yaffs_readdir,
+#endif
.fsync = yaffs_sync_object,
.llseek = generic_file_llseek,
};

View File

@ -1,72 +0,0 @@
From cd6657c4bde20886b0805ea9f2cbac7ec25ac2e5 Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Tue, 30 Nov 2010 16:01:28 +1300
Subject: [PATCH 1/2] yaffs: Replace yaffs_dir_llseek with Linux generic
llseek
commit ed8188fb7659cfb65b5adbe154d143190ade0324 upstream.
There was not much point in having the yaffs version as it is
functionally equivalent to the kernel one.
This also gets rid of using BKL in yaffs2.
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
yaffs_vfs.c | 30 +-----------------------------
yaffs_vfs_multi.c | 30 +-----------------------------
2 files changed, 2 insertions(+), 58 deletions(-)
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -342,8 +342,6 @@ static int yaffs_follow_link(struct dent
static void yaffs_touch_super(yaffs_dev_t *dev);
-static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
-
static int yaffs_vfs_setattr(struct inode *, struct iattr *);
@@ -460,7 +458,7 @@ static const struct file_operations yaff
.read = generic_read_dir,
.readdir = yaffs_readdir,
.fsync = yaffs_sync_object,
- .llseek = yaffs_dir_llseek,
+ .llseek = generic_file_llseek,
};
static const struct super_operations yaffs_super_ops = {
@@ -1534,32 +1532,6 @@ static void yaffs_release_space(struct f
}
-static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
-{
- long long retval;
-
- lock_kernel();
-
- switch (origin){
- case 2:
- offset += i_size_read(file->f_path.dentry->d_inode);
- break;
- case 1:
- offset += file->f_pos;
- }
- retval = -EINVAL;
-
- if (offset >= 0){
- if (offset != file->f_pos)
- file->f_pos = offset;
-
- retval = offset;
- }
- unlock_kernel();
- return retval;
-}
-
-
static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
{
yaffs_obj_t *obj;

View File

@ -1,110 +0,0 @@
From e1537a700c2e750c5eacc5ad93f30821f1e94424 Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Mon, 15 Aug 2011 11:40:30 +1200
Subject: [PATCH 2/2] Mods for Linux 3.0 and fix a typo
commit a7b5dcf904ba6f7890e4b77ce1f56388b855d0f6 upstream.
Roll in NCB's patch and some other changes for Linux 3.0.
Also fix a dumb type retired_writes->retried_writes
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
patch-ker.sh | 2 +-
yaffs_vfs_glue.c | 42 ++++++++++++++++++++++++++++++++++--------
2 files changed, 35 insertions(+), 9 deletions(-)
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -72,7 +72,9 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
#include <linux/smp_lock.h>
+#endif
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
@@ -236,7 +238,9 @@ static int yaffs_file_flush(struct file
static int yaffs_file_flush(struct file *file);
#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
static int yaffs_sync_object(struct file *file, int datasync);
#else
static int yaffs_sync_object(struct file *file, struct dentry *dentry,
@@ -1864,7 +1868,9 @@ static int yaffs_symlink(struct inode *d
return -ENOMEM;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
static int yaffs_sync_object(struct file *file, int datasync)
#else
static int yaffs_sync_object(struct file *file, struct dentry *dentry,
@@ -3067,7 +3073,13 @@ static int yaffs_internal_read_super_mtd
return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
+{
+ return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd);
+}
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
static int yaffs_read_super(struct file_system_type *fs,
int flags, const char *dev_name,
void *data, struct vfsmount *mnt)
@@ -3090,8 +3102,12 @@ static struct super_block *yaffs_read_su
static struct file_system_type yaffs_fs_type = {
.owner = THIS_MODULE,
.name = "yaffs",
- .get_sb = yaffs_read_super,
- .kill_sb = kill_block_super,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+ .mount = yaffs_mount,
+#else
+ .get_sb = yaffs_read_super,
+#endif
+ .kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
#else
@@ -3115,7 +3131,13 @@ static int yaffs2_internal_read_super_mt
return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
+{
+ return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd);
+}
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
static int yaffs2_read_super(struct file_system_type *fs,
int flags, const char *dev_name, void *data,
struct vfsmount *mnt)
@@ -3137,8 +3159,12 @@ static struct super_block *yaffs2_read_s
static struct file_system_type yaffs2_fs_type = {
.owner = THIS_MODULE,
.name = "yaffs2",
- .get_sb = yaffs2_read_super,
- .kill_sb = kill_block_super,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+ .mount = yaffs2_mount,
+#else
+ .get_sb = yaffs2_read_super,
+#endif
+ .kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
#else

View File

@ -1,54 +0,0 @@
--- a/fs/yaffs2/yaffs_mtdif1.c
+++ b/fs/yaffs2/yaffs_mtdif1.c
@@ -127,7 +127,7 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
#endif
memset(&ops, 0, sizeof(ops));
- ops.mode = MTD_OOB_AUTO;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = (__u8 *)data;
@@ -179,7 +179,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
int deleted;
memset(&ops, 0, sizeof(ops));
- ops.mode = MTD_OOB_AUTO;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = data;
--- a/fs/yaffs2/yaffs_mtdif2.c
+++ b/fs/yaffs2/yaffs_mtdif2.c
@@ -71,7 +71,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
yaffs_PackTags2(&pt, tags, !dev->param.no_tags_ecc);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
- ops.mode = MTD_OOB_AUTO;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
ops.len = dev->param.total_bytes_per_chunk;
ops.ooboffs = 0;
@@ -136,7 +136,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
&dummy, data);
else if (tags) {
- ops.mode = MTD_OOB_AUTO;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.ooblen = packed_tags_size;
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
ops.ooboffs = 0;
--- a/fs/yaffs2/yaffs_mtdif.h
+++ b/fs/yaffs2/yaffs_mtdif.h
@@ -24,4 +24,11 @@ extern struct nand_oobinfo yaffs_noeccin
#endif
int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber);
int nandmtd_InitialiseNAND(yaffs_dev_t *dev);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+#include <mtd/mtd-abi.h>
+#else
+#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
+#endif
+
#endif

View File

@ -1,78 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -220,6 +220,29 @@ static struct inode *yaffs_iget(struct s
#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->u.generic_sbp)
#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0))
+static inline void yaffs_set_nlink(struct inode *inode, unsigned int nlink)
+{
+ set_nlink(inode, nlink);
+}
+
+static inline void yaffs_dec_link_count(struct inode *inode)
+{
+ inode_dec_link_count(inode);
+}
+#else
+static inline void yaffs_set_nlink(struct inode *inode, unsigned int nlink)
+{
+ inode->i_nlink = nlink;
+}
+
+static inline void yaffs_dec_link_count(struct inode *inode)
+{
+ inode->i_nlink--;
+ mark_inode_dirty(inode)
+}
+#endif
+
#define update_dir_time(dir) do {\
(dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
@@ -1362,7 +1385,7 @@ static void yaffs_fill_inode_from_obj(st
inode->i_size = yaffs_get_obj_length(obj);
inode->i_blocks = (inode->i_size + 511) >> 9;
- inode->i_nlink = yaffs_get_obj_link_count(obj);
+ yaffs_set_nlink(inode, yaffs_get_obj_link_count(obj));
T(YAFFS_TRACE_OS,
(TSTR("yaffs_fill_inode mode %x uid %d gid %d size %d count %d\n"),
@@ -1784,10 +1807,9 @@ static int yaffs_unlink(struct inode *di
retVal = yaffs_unlinker(obj, dentry->d_name.name);
if (retVal == YAFFS_OK) {
- dentry->d_inode->i_nlink--;
+ yaffs_dec_link_count(dentry->d_inode);
dir->i_version++;
yaffs_gross_unlock(dev);
- mark_inode_dirty(dentry->d_inode);
update_dir_time(dir);
return 0;
}
@@ -1818,7 +1840,8 @@ static int yaffs_link(struct dentry *old
obj);
if (link) {
- old_dentry->d_inode->i_nlink = yaffs_get_obj_link_count(obj);
+ yaffs_set_nlink(old_dentry->d_inode,
+ yaffs_get_obj_link_count(obj));
d_instantiate(dentry, old_dentry->d_inode);
atomic_inc(&old_dentry->d_inode->i_count);
T(YAFFS_TRACE_OS,
@@ -1937,11 +1960,9 @@ static int yaffs_rename(struct inode *ol
yaffs_gross_unlock(dev);
if (retVal == YAFFS_OK) {
- if (target) {
- new_dentry->d_inode->i_nlink--;
- mark_inode_dirty(new_dentry->d_inode);
- }
-
+ if (target)
+ yaffs_dec_link_count(new_dentry->d_inode);
+
update_dir_time(old_dir);
if(old_dir != new_dir)
update_dir_time(new_dir);

View File

@ -1,71 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -273,8 +273,13 @@ static int yaffs_sync_object(struct file
static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+ struct nameidata *n);
+#else
static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *n);
+#endif
static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *n);
#else
@@ -286,9 +291,17 @@ static int yaffs_link(struct dentry *old
static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
const char *symname);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
+#else
static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+ dev_t dev);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
dev_t dev);
#else
@@ -1679,7 +1692,10 @@ out:
#define YCRED(x) (x->cred)
#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+ dev_t rdev)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
dev_t rdev)
#else
@@ -1769,7 +1785,11 @@ static int yaffs_mknod(struct inode *dir
return error;
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+#else
static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+#endif
{
int retVal;
T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
@@ -1777,7 +1797,10 @@ static int yaffs_mkdir(struct inode *dir
return retVal;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+ struct nameidata *n)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *n)
#else

View File

@ -1,160 +0,0 @@
--- a/fs/yaffs2/yaffs_mtdif1.c
+++ b/fs/yaffs2/yaffs_mtdif1.c
@@ -133,7 +133,7 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
ops.datbuf = (__u8 *)data;
ops.oobbuf = (__u8 *)&pt1;
- retval = mtd->write_oob(mtd, addr, &ops);
+ retval = mtd_write_oob(mtd, addr, &ops);
if (retval) {
T(YAFFS_TRACE_MTD,
(TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
@@ -194,7 +194,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
/* Read page and oob using MTD.
* Check status and determine ECC result.
*/
- retval = mtd->read_oob(mtd, addr, &ops);
+ retval = mtd_read_oob(mtd, addr, &ops);
if (retval) {
T(YAFFS_TRACE_MTD,
(TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
@@ -218,7 +218,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
/* fall into... */
default:
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
- etags->block_bad = (mtd->block_isbad)(mtd, addr);
+ etags->block_bad = mtd_block_isbad(mtd, addr);
return YAFFS_FAIL;
}
@@ -286,7 +286,7 @@ int nandmtd1_MarkNANDBlockBad(struct yaf
T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), block_no));
- retval = mtd->block_markbad(mtd, (loff_t)blocksize * block_no);
+ retval = mtd_block_markbad(mtd, (loff_t)blocksize * block_no);
return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
@@ -336,7 +336,7 @@ int nandmtd1_QueryNANDBlock(struct yaffs
return YAFFS_FAIL;
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
- etags.block_bad = (mtd->block_isbad)(mtd, addr);
+ etags.block_bad = mtd_block_isbad(mtd, addr);
if (etags.block_bad) {
T(YAFFS_TRACE_BAD_BLOCKS,
(TSTR("block %d is marked bad"TENDSTR), block_no));
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -2607,8 +2607,8 @@ static void yaffs_MTDPutSuper(struct sup
{
struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_SuperToDevice(sb));
- if (mtd->sync)
- mtd->sync(mtd);
+ if (mtd)
+ mtd_sync(mtd);
put_mtd_device(mtd);
}
--- a/fs/yaffs2/yaffs_mtdif2.c
+++ b/fs/yaffs2/yaffs_mtdif2.c
@@ -77,7 +77,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
ops.ooboffs = 0;
ops.datbuf = (__u8 *)data;
ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
- retval = mtd->write_oob(mtd, addr, &ops);
+ retval = mtd_write_oob(mtd, addr, &ops);
#else
if (!dev->param.inband_tags) {
@@ -133,7 +133,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
if (dev->param.inband_tags || (data && !tags))
- retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
+ retval = mtd_read(mtd, addr, dev->param.total_bytes_per_chunk,
&dummy, data);
else if (tags) {
ops.mode = MTD_OPS_AUTO_OOB;
@@ -142,7 +142,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
ops.ooboffs = 0;
ops.datbuf = data;
ops.oobbuf = yaffs_dev_to_lc(dev)->spareBuffer;
- retval = mtd->read_oob(mtd, addr, &ops);
+ retval = mtd_read_oob(mtd, addr, &ops);
}
#else
if (!dev->param.inband_tags && data && tags) {
@@ -201,7 +201,7 @@ int nandmtd2_MarkNANDBlockBad(struct yaf
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), block_no));
retval =
- mtd->block_markbad(mtd,
+ mtd_block_markbad(mtd,
block_no * dev->param.chunks_per_block *
dev->param.total_bytes_per_chunk);
@@ -221,7 +221,7 @@ int nandmtd2_QueryNANDBlock(struct yaffs
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), block_no));
retval =
- mtd->block_isbad(mtd,
+ mtd_block_isbad(mtd,
block_no * dev->param.chunks_per_block *
dev->param.total_bytes_per_chunk);
--- a/fs/yaffs2/yaffs_mtdif.h
+++ b/fs/yaffs2/yaffs_mtdif.h
@@ -31,4 +31,39 @@ int nandmtd_InitialiseNAND(yaffs_dev_t *
#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0))
+static inline int mtd_erase(struct mdt_info *mtd, struct erase_info *ei)
+{
+ return mtd->erase(mtd, ei);
+}
+
+static inline int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+ return mtd->block_mark_bad(mtd, ofs);
+}
+
+static inline int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+ return mtd->block_is_bad(mtd, ofs);
+}
+
+static inline int mtd_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+{
+ return mtd->read_oob(mtd, from, ops);
+}
+
+static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+{
+ return mtd->write_oob(mtd, to, ops);
+}
+
+static inline void mtd_sync(struct mtd_info *mtd)
+{
+ if (mtd->sync)
+ mtd->sync(mtd);
+}
+#endif
+
#endif
--- a/fs/yaffs2/yaffs_mtdif.c
+++ b/fs/yaffs2/yaffs_mtdif.c
@@ -41,7 +41,7 @@ int nandmtd_EraseBlockInNAND(yaffs_dev_t
ei.callback = NULL;
ei.priv = (u_long) dev;
- retval = mtd->erase(mtd, &ei);
+ retval = mtd_erase(mtd, &ei);
if (retval == 0)
return YAFFS_OK;

View File

@ -1,72 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -2793,6 +2793,15 @@ static struct super_block *yaffs_interna
return NULL;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->_erase));
+ T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->_read));
+ T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->_write));
+ T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->_read_oob));
+ T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->_write_oob));
+ T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->_block_isbad));
+ T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->_block_markbad));
+#else
T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
@@ -2800,6 +2809,7 @@ static struct super_block *yaffs_interna
T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
+#endif
T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
@@ -2828,6 +2838,15 @@ static struct super_block *yaffs_interna
if (yaffs_version == 2) {
/* Check for version 2 style functions */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+ if (!mtd->_erase ||
+ !mtd->_block_isbad ||
+ !mtd->_block_markbad ||
+ !mtd->_read ||
+ !mtd->_write ||
+ !mtd->_read_oob ||
+ !mtd->_write_oob) {
+#else
if (!mtd->erase ||
!mtd->block_isbad ||
!mtd->block_markbad ||
@@ -2839,6 +2858,7 @@ static struct super_block *yaffs_interna
!mtd->write_ecc ||
!mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
#endif
+#endif
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs: MTD device does not support required "
"functions\n")));
@@ -2855,6 +2875,13 @@ static struct super_block *yaffs_interna
}
} else {
/* Check for V1 style functions */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+ if (!mtd->_erase ||
+ !mtd->_read ||
+ !mtd->_write ||
+ !mtd->_read_oob ||
+ !mtd->_write_oob) {
+#else
if (!mtd->erase ||
!mtd->read ||
!mtd->write ||
@@ -2864,6 +2891,7 @@ static struct super_block *yaffs_interna
!mtd->write_ecc ||
!mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
#endif
+#endif
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs: MTD device does not support required "
"functions\n")));

View File

@ -1,14 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -3119,7 +3119,11 @@ static struct super_block *yaffs_interna
T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+ root = d_make_root(inode);
+#else
root = d_alloc_root(inode);
+#endif
T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));

View File

@ -1,15 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -924,7 +924,11 @@ static void yaffs_evict_inode( struct in
if (!inode->i_nlink && !is_bad_inode(inode))
deleteme = 1;
truncate_inode_pages(&inode->i_data,0);
- end_writeback(inode);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ clear_inode(inode);
+#else
+ end_writeback(inode);
+#endif
if(deleteme && obj){
dev = obj->my_dev;

View File

@ -1,570 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -243,11 +243,10 @@ static inline void yaffs_dec_link_count(
}
#endif
-
#define update_dir_time(dir) do {\
(dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
} while(0)
-
+
static void yaffs_put_super(struct super_block *sb);
static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
@@ -397,6 +396,33 @@ static struct address_space_operations y
#endif
};
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid())
+#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid())
+#else
+#define YCRED_FSUID() YCRED(current)->fsuid
+#define YCRED_FSGID() YCRED(current)->fsgid
+
+static inline uid_t i_uid_read(const struct inode *inode)
+{
+ return inode->i_uid;
+}
+
+static inline gid_t i_gid_read(const struct inode *inode)
+{
+ return inode->i_gid;
+}
+
+static inline void i_uid_write(struct inode *inode, uid_t uid)
+{
+ inode->i_uid = uid;
+}
+
+static inline void i_gid_write(struct inode *inode, gid_t gid)
+{
+ inode->i_gid = gid;
+}
+#endif
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
static const struct file_operations yaffs_file_operations = {
@@ -549,7 +575,7 @@ static unsigned yaffs_gc_control_callbac
{
return yaffs_gc_control;
}
-
+
static void yaffs_gross_lock(yaffs_dev_t *dev)
{
T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
@@ -1379,8 +1405,8 @@ static void yaffs_fill_inode_from_obj(st
inode->i_ino = obj->obj_id;
inode->i_mode = obj->yst_mode;
- inode->i_uid = obj->yst_uid;
- inode->i_gid = obj->yst_gid;
+ i_uid_write(inode, obj->yst_uid);
+ i_gid_write(inode, obj->yst_gid);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
inode->i_blksize = inode->i_sb->s_blocksize;
#endif
@@ -1406,7 +1432,7 @@ static void yaffs_fill_inode_from_obj(st
T(YAFFS_TRACE_OS,
(TSTR("yaffs_fill_inode mode %x uid %d gid %d size %d count %d\n"),
- inode->i_mode, inode->i_uid, inode->i_gid,
+ inode->i_mode, i_uid_read(inode), i_gid_read(inode),
(int)inode->i_size, atomic_read(&inode->i_count)));
switch (obj->yst_mode & S_IFMT) {
@@ -1715,8 +1741,8 @@ static int yaffs_mknod(struct inode *dir
yaffs_obj_t *parent = yaffs_InodeToObject(dir);
int error = -ENOSPC;
- uid_t uid = YCRED(current)->fsuid;
- gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ uid_t uid = YCRED_FSUID();
+ gid_t gid = (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
mode |= S_ISGID;
@@ -1892,8 +1918,8 @@ static int yaffs_symlink(struct inode *d
{
yaffs_obj_t *obj;
yaffs_dev_t *dev;
- uid_t uid = YCRED(current)->fsuid;
- gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ uid_t uid = YCRED_FSUID();
+ gid_t gid = (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
@@ -2009,7 +2035,7 @@ static int yaffs_setattr(struct dentry *
(TSTR("yaffs_setattr of object %d\n"),
yaffs_InodeToObject(inode)->obj_id));
- /* Fail if a requested resize >= 2GB */
+ /* Fail if a requested resize >= 2GB */
if (attr->ia_valid & ATTR_SIZE &&
(attr->ia_size >> 31))
error = -EINVAL;
@@ -2240,7 +2266,7 @@ static void yaffs_flush_inodes(struct su
{
struct inode *iptr;
yaffs_obj_t *obj;
-
+
list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
obj = yaffs_InodeToObject(iptr);
if(obj){
@@ -2254,10 +2280,10 @@ static void yaffs_flush_inodes(struct su
static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
{
- yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
+ yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
if(!dev)
return;
-
+
yaffs_flush_inodes(sb);
yaffs_update_dirty_dirs(dev);
yaffs_flush_whole_cache(dev);
@@ -2325,7 +2351,7 @@ static int yaffs_do_sync_fs(struct super
* yaffs_bg_start() launches the background thread.
* yaffs_bg_stop() cleans up the background thread.
*
- * NB:
+ * NB:
* The thread should only run after the yaffs is initialised
* The thread should be stopped before yaffs is unmounted.
* The thread should not do any writing while the fs is in read only.
@@ -2924,7 +2950,7 @@ static struct super_block *yaffs_interna
dev = kmalloc(sizeof(yaffs_dev_t), GFP_KERNEL);
context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
-
+
if(!dev || !context ){
if(dev)
kfree(dev);
@@ -2957,7 +2983,7 @@ static struct super_block *yaffs_interna
#else
sb->u.generic_sbp = dev;
#endif
-
+
dev->driver_context = mtd;
param->name = mtd->name;
@@ -3057,7 +3083,7 @@ static struct super_block *yaffs_interna
param->gc_control = yaffs_gc_control_callback;
yaffs_dev_to_lc(dev)->superBlock= sb;
-
+
#ifndef CONFIG_YAFFS_DOES_ECC
param->use_nand_ecc = 1;
@@ -3099,10 +3125,10 @@ static struct super_block *yaffs_interna
T(YAFFS_TRACE_OS,
(TSTR("yaffs_read_super: guts initialised %s\n"),
(err == YAFFS_OK) ? "OK" : "FAILED"));
-
+
if(err == YAFFS_OK)
yaffs_bg_start(dev);
-
+
if(!context->bgThread)
param->defered_dir_update = 0;
@@ -3345,7 +3371,7 @@ static int yaffs_proc_read(char *page,
buf += sprintf(buf,"\n");
else {
step-=2;
-
+
mutex_lock(&yaffs_context_lock);
/* Locate and print the Nth entry. Order N-squared but N is small. */
@@ -3362,7 +3388,7 @@ static int yaffs_proc_read(char *page,
buf = yaffs_dump_dev_part0(buf, dev);
} else
buf = yaffs_dump_dev_part1(buf, dev);
-
+
break;
}
mutex_unlock(&yaffs_context_lock);
@@ -3389,7 +3415,7 @@ static int yaffs_stats_proc_read(char *p
int erasedChunks;
erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
-
+
buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n",
n, dev->n_free_chunks, erasedChunks,
dev->bg_gcs, dev->oldest_dirty_gc_count,
--- a/fs/yaffs2/yaffs_guts.c
+++ b/fs/yaffs2/yaffs_guts.c
@@ -370,7 +370,7 @@ static int yaffs_verify_chunk_written(ya
yaffs_ext_tags tempTags;
__u8 *buffer = yaffs_get_temp_buffer(dev,__LINE__);
int result;
-
+
result = yaffs_rd_chunk_tags_nand(dev,nand_chunk,buffer,&tempTags);
if(memcmp(buffer,data,dev->data_bytes_per_chunk) ||
tempTags.obj_id != tags->obj_id ||
@@ -424,7 +424,7 @@ static int yaffs_write_new_chunk(struct
* lot of checks that are most likely not needed.
*
* Mods to the above
- * If an erase check fails or the write fails we skip the
+ * If an erase check fails or the write fails we skip the
* rest of the block.
*/
@@ -486,7 +486,7 @@ static int yaffs_write_new_chunk(struct
}
-
+
/*
* Block retiring for handling a broken block.
*/
@@ -496,7 +496,7 @@ static void yaffs_retire_block(yaffs_dev
yaffs_block_info_t *bi = yaffs_get_block_info(dev, flash_block);
yaffs2_checkpt_invalidate(dev);
-
+
yaffs2_clear_oldest_dirty_seq(dev,bi);
if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
@@ -899,7 +899,7 @@ static int yaffs_find_chunk_in_group(yaf
for (j = 0; theChunk && j < dev->chunk_grp_size; j++) {
if (yaffs_check_chunk_bit(dev, theChunk / dev->param.chunks_per_block,
theChunk % dev->param.chunks_per_block)) {
-
+
if(dev->chunk_grp_size == 1)
return theChunk;
else {
@@ -1802,7 +1802,7 @@ int yaffs_rename_obj(yaffs_obj_t *old_di
yaffs_update_parent(old_dir);
if(new_dir != old_dir)
yaffs_update_parent(new_dir);
-
+
return result;
}
return YAFFS_FAIL;
@@ -2125,7 +2125,7 @@ static int yaffs_gc_block(yaffs_dev_t *d
if(bi->block_state == YAFFS_BLOCK_STATE_FULL)
bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
-
+
bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
dev->gc_disable = 1;
@@ -2207,7 +2207,7 @@ static int yaffs_gc_block(yaffs_dev_t *d
* No need to copy this, just forget about it and
* fix up the object.
*/
-
+
/* Free chunks already includes softdeleted chunks.
* How ever this chunk is going to soon be really deleted
* which will increment free chunks.
@@ -2752,7 +2752,7 @@ int yaffs_put_chunk_in_file(yaffs_obj_t
NULL);
if (!tn)
return YAFFS_FAIL;
-
+
if(!nand_chunk)
/* Dummy insert, bail now */
return YAFFS_OK;
@@ -2881,7 +2881,7 @@ void yaffs_chunk_del(yaffs_dev_t *dev, i
chunk_id));
bi = yaffs_get_block_info(dev, block);
-
+
yaffs2_update_oldest_dirty_seq(dev, block, bi);
T(YAFFS_TRACE_DELETION,
@@ -2966,8 +2966,8 @@ static int yaffs_wr_data_obj(yaffs_obj_t
(TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), n_bytes));
YBUG();
}
-
-
+
+
newChunkId =
yaffs_write_new_chunk(dev, buffer, &newTags,
useReserve);
@@ -3795,14 +3795,14 @@ int yaffs_resize_file(yaffs_obj_t *in, l
if (new_size == oldFileSize)
return YAFFS_OK;
-
+
if(new_size > oldFileSize){
yaffs2_handle_hole(in,new_size);
in->variant.file_variant.file_size = new_size;
} else {
- /* new_size < oldFileSize */
+ /* new_size < oldFileSize */
yaffs_resize_file_down(in, new_size);
- }
+ }
/* Write a new object header to reflect the resize.
* show we've shrunk the file, if need be
@@ -4231,7 +4231,7 @@ static void yaffs_strip_deleted_objs(yaf
* This fixes the problem where directories might have inadvertently been deleted
* leaving the object "hanging" without being rooted in the directory tree.
*/
-
+
static int yaffs_has_null_parent(yaffs_dev_t *dev, yaffs_obj_t *obj)
{
return (obj == dev->del_dir ||
@@ -4262,7 +4262,7 @@ static void yaffs_fix_hanging_objs(yaffs
if (lh) {
obj = ylist_entry(lh, yaffs_obj_t, hash_link);
parent= obj->parent;
-
+
if(yaffs_has_null_parent(dev,obj)){
/* These directories are not hanging */
hanging = 0;
@@ -4311,7 +4311,7 @@ static void yaffs_del_dir_contents(yaffs
if(dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
YBUG();
-
+
ylist_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
if (lh) {
obj = ylist_entry(lh, yaffs_obj_t, siblings);
@@ -4325,10 +4325,10 @@ static void yaffs_del_dir_contents(yaffs
/* Need to use UnlinkObject since Delete would not handle
* hardlinked objects correctly.
*/
- yaffs_unlink_obj(obj);
+ yaffs_unlink_obj(obj);
}
}
-
+
}
static void yaffs_empty_l_n_f(yaffs_dev_t *dev)
@@ -4410,7 +4410,7 @@ static void yaffs_check_obj_details_load
* If the directory updating is defered then yaffs_update_dirty_dirs must be
* called periodically.
*/
-
+
static void yaffs_update_parent(yaffs_obj_t *obj)
{
yaffs_dev_t *dev;
@@ -4422,8 +4422,8 @@ static void yaffs_update_parent(yaffs_ob
obj->dirty = 1;
obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
if(dev->param.defered_dir_update){
- struct ylist_head *link = &obj->variant.dir_variant.dirty;
-
+ struct ylist_head *link = &obj->variant.dir_variant.dirty;
+
if(ylist_empty(link)){
ylist_add(link,&dev->dirty_dirs);
T(YAFFS_TRACE_BACKGROUND, (TSTR("Added object %d to dirty directories" TENDSTR),obj->obj_id));
@@ -4446,7 +4446,7 @@ void yaffs_update_dirty_dirs(yaffs_dev_t
while(!ylist_empty(&dev->dirty_dirs)){
link = dev->dirty_dirs.next;
ylist_del_init(link);
-
+
dS=ylist_entry(link,yaffs_dir_s,dirty);
oV = ylist_entry(dS,yaffs_obj_variant,dir_variant);
obj = ylist_entry(oV,yaffs_obj_t,variant);
@@ -4474,7 +4474,7 @@ static void yaffs_remove_obj_from_dir(ya
ylist_del_init(&obj->siblings);
obj->parent = NULL;
-
+
yaffs_verify_dir(parent);
}
@@ -4645,7 +4645,7 @@ yaffs_obj_t *yaffs_get_equivalent_obj(ya
* system to share files.
*
* These automatic unicode are stored slightly differently...
- * - If the name can fit in the ASCII character space then they are saved as
+ * - If the name can fit in the ASCII character space then they are saved as
* ascii names as per above.
* - If the name needs Unicode then the name is saved in Unicode
* starting at oh->name[1].
@@ -4686,7 +4686,7 @@ static void yaffs_load_name_from_oh(yaff
asciiOhName++;
n--;
}
- } else
+ } else
yaffs_strncpy(name,ohName+1, bufferSize -1);
} else
#endif
@@ -4705,7 +4705,7 @@ static void yaffs_load_oh_from_name(yaff
isAscii = 1;
w = name;
-
+
/* Figure out if the name will fit in ascii character set */
while(isAscii && *w){
if((*w) & 0xff00)
@@ -4729,7 +4729,7 @@ static void yaffs_load_oh_from_name(yaff
yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2);
}
}
- else
+ else
#endif
yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1);
@@ -4738,12 +4738,12 @@ static void yaffs_load_oh_from_name(yaff
int yaffs_get_obj_name(yaffs_obj_t * obj, YCHAR * name, int buffer_size)
{
memset(name, 0, buffer_size * sizeof(YCHAR));
-
+
yaffs_check_obj_details_loaded(obj);
if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
- }
+ }
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
else if (obj->short_name[0]) {
yaffs_strcpy(name, obj->short_name);
@@ -4861,9 +4861,9 @@ int yaffs_set_attribs(yaffs_obj_t *obj,
if (valid & ATTR_MODE)
obj->yst_mode = attr->ia_mode;
if (valid & ATTR_UID)
- obj->yst_uid = attr->ia_uid;
+ obj->yst_uid = ia_uid_read(attr);
if (valid & ATTR_GID)
- obj->yst_gid = attr->ia_gid;
+ obj->yst_gid = ia_gid_read(attr);
if (valid & ATTR_ATIME)
obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
@@ -4886,9 +4886,9 @@ int yaffs_get_attribs(yaffs_obj_t *obj,
attr->ia_mode = obj->yst_mode;
valid |= ATTR_MODE;
- attr->ia_uid = obj->yst_uid;
+ ia_uid_write(attr, obj->yst_uid);
valid |= ATTR_UID;
- attr->ia_gid = obj->yst_gid;
+ ia_gid_write(attr, obj->yst_gid);
valid |= ATTR_GID;
Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
--- a/fs/yaffs2/yportenv.h
+++ b/fs/yaffs2/yportenv.h
@@ -170,7 +170,7 @@
#define O_RDWR 02
#endif
-#ifndef O_CREAT
+#ifndef O_CREAT
#define O_CREAT 0100
#endif
@@ -218,7 +218,7 @@
#define EACCES 13
#endif
-#ifndef EXDEV
+#ifndef EXDEV
#define EXDEV 18
#endif
@@ -281,7 +281,7 @@
#define S_IFREG 0100000
#endif
-#ifndef S_IREAD
+#ifndef S_IREAD
#define S_IREAD 0000400
#endif
--- a/fs/yaffs2/devextras.h
+++ b/fs/yaffs2/devextras.h
@@ -87,6 +87,8 @@ struct iattr {
unsigned int ia_attr_flags;
};
+/* TODO: add ia_* functions */
+
#endif
#else
@@ -95,7 +97,48 @@ struct iattr {
#include <linux/fs.h>
#include <linux/stat.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+static inline uid_t ia_uid_read(const struct iattr *iattr)
+{
+ return from_kuid(&init_user_ns, iattr->ia_uid);
+}
+
+static inline gid_t ia_gid_read(const struct iattr *iattr)
+{
+ return from_kgid(&init_user_ns, iattr->ia_gid);
+}
+
+static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
+{
+ iattr->ia_uid = make_kuid(&init_user_ns, uid);
+}
+
+static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
+{
+ iattr->ia_gid = make_kgid(&init_user_ns, gid);
+}
+#else
+static inline uid_t ia_uid_read(const struct iattr *iattr)
+{
+ return iattr->ia_uid;
+}
+
+static inline gid_t ia_gid_read(const struct iattr *inode)
+{
+ return iattr->ia_gid;
+}
+
+static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
+{
+ iattr->ia_uid = uid;
+}
+
+static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
+{
+ iattr->ia_gid = gid;
+}
#endif
+#endif
#endif

View File

@ -1,60 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -271,20 +271,29 @@ static int yaffs_sync_object(struct file
static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+ bool excl);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
struct nameidata *n);
-#else
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *n);
+#else
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *n);
#else
-static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
#endif
+
static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *dentry);
static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
@@ -837,7 +846,10 @@ struct inode *yaffs_get_inode(struct sup
/*
* Lookup is used to find objects in the fs
*/
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *n)
@@ -1827,7 +1839,10 @@ static int yaffs_mkdir(struct inode *dir
return retVal;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+ bool excl)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
struct nameidata *n)
#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))

View File

@ -1,180 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -393,6 +393,84 @@ static void yaffs_touch_super(yaffs_dev_
static int yaffs_vfs_setattr(struct inode *, struct iattr *);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+
+#define yaffs_super_to_dev(sb) ((struct yaffs_dev_s *)sb->s_fs_info)
+
+static inline struct yaffs_LinuxContext *
+yaffs_sb_to_ylc(struct super_block *sb)
+{
+ struct yaffs_dev_s *ydev;
+ struct yaffs_LinuxContext *ylc;
+
+ ydev = yaffs_super_to_dev(sb);
+ ylc = yaffs_dev_to_lc(ydev);
+ return ylc;
+}
+
+static inline struct super_block *yaffs_work_to_sb(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct yaffs_LinuxContext *ylc;
+
+ dwork = container_of(work, struct delayed_work, work);
+ ylc = container_of(dwork, struct yaffs_LinuxContext, sb_sync_dwork);
+ return ylc->superBlock;
+}
+
+static void yaffs_sb_sync_dwork_func(struct work_struct *work)
+{
+ struct super_block *sb = yaffs_work_to_sb(work);
+
+ yaffs_write_super(sb);
+}
+
+static void yaffs_init_sb_sync_dwork(struct yaffs_LinuxContext *ylc)
+{
+ INIT_DELAYED_WORK(&ylc->sb_sync_dwork, yaffs_sb_sync_dwork_func);
+}
+
+static void yaffs_cancel_sb_sync_dwork(struct super_block *sb)
+{
+ struct yaffs_LinuxContext *ylc = yaffs_sb_to_ylc(sb);
+
+ cancel_delayed_work_sync(&ylc->sb_sync_dwork);
+}
+
+static inline bool yaffs_sb_is_dirty(struct super_block *sb)
+{
+ struct yaffs_LinuxContext *ylc = yaffs_sb_to_ylc(sb);
+
+ return !!ylc->sb_dirty;
+}
+
+static inline void yaffs_sb_set_dirty(struct super_block *sb, int dirty)
+{
+ struct yaffs_LinuxContext *ylc = yaffs_sb_to_ylc(sb);
+
+ if (ylc->sb_dirty == dirty)
+ return;
+
+ ylc->sb_dirty = dirty;
+ if (dirty)
+ queue_delayed_work(system_long_wq, &ylc->sb_sync_dwork,
+ msecs_to_jiffies(5000));
+}
+#else
+static inline bool yaffs_sb_is_dirty(struct super_block *sb)
+{
+ return !!sb->s_dirt;
+}
+
+static inline void yaffs_sb_set_dirty(struct super_block *sb, int dirty)
+{
+ sb->s_dirt = dirty;
+}
+
+static inline void yaffs_init_sb_sync_dwork(struct yaffs_LinuxContext *ylc) {}
+static inline void yaffs_cancel_sb_sync_dwork(struct super_block *sb) {}
+#endif /* >= 3.6.0 */
+
static struct address_space_operations yaffs_file_address_operations = {
.readpage = yaffs_readpage,
.writepage = yaffs_writepage,
@@ -553,7 +631,9 @@ static const struct super_operations yaf
.clear_inode = yaffs_clear_inode,
#endif
.sync_fs = yaffs_sync_fs,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
.write_super = yaffs_write_super,
+#endif
};
@@ -2340,7 +2420,7 @@ static int yaffs_do_sync_fs(struct super
T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
(TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
gc_urgent,
- sb->s_dirt ? "dirty" : "clean",
+ yaffs_sb_is_dirty(sb) ? "dirty" : "clean",
request_checkpoint ? "checkpoint requested" : "no checkpoint",
oneshot_checkpoint ? " one-shot" : "" ));
@@ -2349,9 +2429,9 @@ static int yaffs_do_sync_fs(struct super
oneshot_checkpoint) &&
!dev->is_checkpointed;
- if (sb->s_dirt || do_checkpoint) {
+ if (yaffs_sb_is_dirty(sb) || do_checkpoint) {
yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
- sb->s_dirt = 0;
+ yaffs_sb_set_dirty(sb, 0);
if(oneshot_checkpoint)
yaffs_auto_checkpoint &= ~4;
}
@@ -2627,6 +2707,8 @@ static void yaffs_put_super(struct super
yaffs_flush_super(sb,1);
+ yaffs_cancel_sb_sync_dwork(sb);
+
if (yaffs_dev_to_lc(dev)->putSuperFunc)
yaffs_dev_to_lc(dev)->putSuperFunc(sb);
@@ -2665,7 +2747,7 @@ static void yaffs_touch_super(yaffs_dev_
T(YAFFS_TRACE_OS, (TSTR("yaffs_touch_super() sb = %p\n"), sb));
if (sb)
- sb->s_dirt = 1;
+ yaffs_sb_set_dirty(sb, 1);
}
typedef struct {
@@ -2991,6 +3073,8 @@ static struct super_block *yaffs_interna
context->dev = dev;
context->superBlock = sb;
+ yaffs_init_sb_sync_dwork(context);
+
dev->read_only = read_only;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
@@ -3177,7 +3261,7 @@ static struct super_block *yaffs_interna
return NULL;
}
sb->s_root = root;
- sb->s_dirt = !dev->is_checkpointed;
+ yaffs_sb_set_dirty(sb, !dev->is_checkpointed);
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs_read_super: is_checkpointed %d\n"),
dev->is_checkpointed));
--- a/fs/yaffs2/yaffs_linux.h
+++ b/fs/yaffs2/yaffs_linux.h
@@ -34,6 +34,11 @@ struct yaffs_LinuxContext {
struct task_struct *readdirProcess;
unsigned mount_id;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ struct delayed_work sb_sync_dwork; /* superblock write-out work */
+ int sb_dirty; /* superblock is dirty */
+#endif
};
#define yaffs_dev_to_lc(dev) ((struct yaffs_LinuxContext *)((dev)->os_context))
--- a/fs/yaffs2/yportenv.h
+++ b/fs/yaffs2/yportenv.h
@@ -49,6 +49,9 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/xattr.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+#include <linux/workqueue.h>
+#endif
#define YCHAR char
#define YUCHAR unsigned char

View File

@ -1,45 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -3385,6 +3385,7 @@ static DECLARE_FSTYPE(yaffs2_fs_type, "y
#endif /* CONFIG_YAFFS_YAFFS2 */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
static struct proc_dir_entry *my_proc_entry;
static struct proc_dir_entry *debug_proc_entry;
@@ -3668,6 +3669,7 @@ static int yaffs_proc_write(struct file
{
return yaffs_proc_write_trace_options(file, buf, count, data);
}
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */
/* Stuff to handle installation of file systems */
struct file_system_to_install {
@@ -3699,6 +3701,7 @@ static int __init init_yaffs_fs(void)
mutex_init(&yaffs_context_lock);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
/* Install the proc_fs entries */
my_proc_entry = create_proc_entry("yaffs",
S_IRUGO | S_IFREG,
@@ -3721,6 +3724,7 @@ static int __init init_yaffs_fs(void)
debug_proc_entry->data = NULL;
} else
return -ENOMEM;
+#endif
/* Now add the file system entries */
@@ -3757,8 +3761,10 @@ static void __exit exit_yaffs_fs(void)
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
remove_proc_entry("yaffs", YPROC_ROOT);
remove_proc_entry("yaffs_stats", YPROC_ROOT);
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */
fsinst = fs_to_install;

View File

@ -0,0 +1,155 @@
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -329,6 +329,33 @@ static int yaffs_readpage(struct file *f
return ret;
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid())
+#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid())
+#else
+#define YCRED_FSUID() YCRED(current)->fsuid
+#define YCRED_FSGID() YCRED(current)->fsgid
+
+static inline uid_t i_uid_read(const struct inode *inode)
+{
+ return inode->i_uid;
+}
+
+static inline gid_t i_gid_read(const struct inode *inode)
+{
+ return inode->i_gid;
+}
+
+static inline void i_uid_write(struct inode *inode, uid_t uid)
+{
+ inode->i_uid = uid;
+}
+
+static inline void i_gid_write(struct inode *inode, gid_t gid)
+{
+ inode->i_gid = gid;
+}
+#endif
static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)
{
@@ -1225,9 +1252,9 @@ static int yaffs_mknod(struct inode *dir
struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
int error = -ENOSPC;
- uid_t uid = YCRED(current)->fsuid;
+ uid_t uid = YCRED_FSUID();
gid_t gid =
- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
mode |= S_ISGID;
@@ -1424,9 +1451,9 @@ static int yaffs_symlink(struct inode *d
{
struct yaffs_obj *obj;
struct yaffs_dev *dev;
- uid_t uid = YCRED(current)->fsuid;
+ uid_t uid = YCRED_FSUID();
gid_t gid =
- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
@@ -1829,8 +1856,8 @@ static void yaffs_fill_inode_from_obj(st
inode->i_ino = obj->obj_id;
inode->i_mode = obj->yst_mode;
- inode->i_uid = obj->yst_uid;
- inode->i_gid = obj->yst_gid;
+ i_uid_write(inode, obj->yst_uid);
+ i_gid_write(inode, obj->yst_gid);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
inode->i_blksize = inode->i_sb->s_blocksize;
#endif
@@ -1856,7 +1883,7 @@ static void yaffs_fill_inode_from_obj(st
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
- inode->i_mode, inode->i_uid, inode->i_gid,
+ inode->i_mode, i_uid_read(inode), i_gid_read(inode),
inode->i_size, atomic_read(&inode->i_count));
switch (obj->yst_mode & S_IFMT) {
--- a/fs/yaffs2/yaffs_attribs.c
+++ b/fs/yaffs2/yaffs_attribs.c
@@ -14,6 +14,48 @@
#include "yaffs_guts.h"
#include "yaffs_attribs.h"
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+static inline uid_t ia_uid_read(const struct iattr *iattr)
+{
+ return from_kuid(&init_user_ns, iattr->ia_uid);
+}
+
+static inline gid_t ia_gid_read(const struct iattr *iattr)
+{
+ return from_kgid(&init_user_ns, iattr->ia_gid);
+}
+
+static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
+{
+ iattr->ia_uid = make_kuid(&init_user_ns, uid);
+}
+
+static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
+{
+ iattr->ia_gid = make_kgid(&init_user_ns, gid);
+}
+#else
+static inline uid_t ia_uid_read(const struct iattr *iattr)
+{
+ return iattr->ia_uid;
+}
+
+static inline gid_t ia_gid_read(const struct iattr *inode)
+{
+ return iattr->ia_gid;
+}
+
+static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
+{
+ iattr->ia_uid = uid;
+}
+
+static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
+{
+ iattr->ia_gid = gid;
+}
+#endif
+
void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
{
obj->yst_uid = oh->yst_uid;
@@ -77,9 +119,9 @@ int yaffs_set_attribs(struct yaffs_obj *
if (valid & ATTR_MODE)
obj->yst_mode = attr->ia_mode;
if (valid & ATTR_UID)
- obj->yst_uid = attr->ia_uid;
+ obj->yst_uid = ia_uid_read(attr);
if (valid & ATTR_GID)
- obj->yst_gid = attr->ia_gid;
+ obj->yst_gid = ia_gid_read(attr);
if (valid & ATTR_ATIME)
obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
@@ -103,9 +145,9 @@ int yaffs_get_attribs(struct yaffs_obj *
attr->ia_mode = obj->yst_mode;
valid |= ATTR_MODE;
- attr->ia_uid = obj->yst_uid;
+ ia_uid_write(attr, obj->yst_uid);
valid |= ATTR_UID;
- attr->ia_gid = obj->yst_gid;
+ ia_gid_write(attr, obj->yst_gid);
valid |= ATTR_GID;
Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;

View File

@ -1,31 +0,0 @@
From 2505e8b0a13d3d5c5bbeaaae4eb889864f44c9df Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Thu, 3 Feb 2011 05:55:30 +1300
Subject: [PATCH] yaffs: Fix directory unlinking in yaffs1 mode
commit 964b3425a71890e6701c830e38b04d8557c04f49 upstream.
Treat both yaffs2 and yaffs1 paths the same.
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
yaffs_guts.c | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
--- a/fs/yaffs2/yaffs_guts.c
+++ b/fs/yaffs2/yaffs_guts.c
@@ -1708,13 +1708,7 @@ static int yaffs_change_obj_name(yaffs_o
YBUG();
}
- /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
- if (obj->my_dev->param.is_yaffs2)
- unlinkOp = (new_dir == obj->my_dev->unlinked_dir);
- else
- unlinkOp = (new_dir == obj->my_dev->unlinked_dir
- && obj->variant_type == YAFFS_OBJECT_TYPE_FILE);
-
+ unlinkOp = (new_dir == obj->my_dev->unlinked_dir);
deleteOp = (new_dir == obj->my_dev->del_dir);
existingTarget = yaffs_find_by_name(new_dir, new_name);

View File

@ -1,138 +0,0 @@
From c0c289363e84c53b5872f7c0c5069045096dca07 Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Wed, 3 Nov 2010 16:01:12 +1300
Subject: [PATCH] yaffs: Switch from semaphores to mutexes
commit 73c54aa8c1de3f61a4c211cd47431293a6092f18 upstream.
Mutex is faster and init_MUTEX has been deprecated, so we'll just switch
to mutexes.
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
yaffs_linux.h | 2 +-
yaffs_vfs.c | 24 ++++++++++++------------
yaffs_vfs_multi.c | 26 +++++++++++++-------------
3 files changed, 26 insertions(+), 26 deletions(-)
--- a/fs/yaffs2/yaffs_linux.h
+++ b/fs/yaffs2/yaffs_linux.h
@@ -25,7 +25,7 @@ struct yaffs_LinuxContext {
struct super_block * superBlock;
struct task_struct *bgThread; /* Background thread for this device */
int bgRunning;
- struct semaphore grossLock; /* Gross locking semaphore */
+ struct mutex grossLock; /* Gross locking mutex*/
__u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
* at compile time so we have to allocate it.
*/
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -515,14 +515,14 @@ static unsigned yaffs_gc_control_callbac
static void yaffs_gross_lock(yaffs_dev_t *dev)
{
T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
- down(&(yaffs_dev_to_lc(dev)->grossLock));
+ mutex_lock(&(yaffs_dev_to_lc(dev)->grossLock));
T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
}
static void yaffs_gross_unlock(yaffs_dev_t *dev)
{
T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
- up(&(yaffs_dev_to_lc(dev)->grossLock));
+ mutex_unlock(&(yaffs_dev_to_lc(dev)->grossLock));
}
#ifdef YAFFS_COMPILE_EXPORTFS
@@ -2542,7 +2542,7 @@ static void yaffs_read_inode(struct inod
#endif
static YLIST_HEAD(yaffs_context_list);
-struct semaphore yaffs_context_lock;
+struct mutex yaffs_context_lock;
static void yaffs_put_super(struct super_block *sb)
{
@@ -2568,9 +2568,9 @@ static void yaffs_put_super(struct super
yaffs_gross_unlock(dev);
- down(&yaffs_context_lock);
+ mutex_lock(&yaffs_context_lock);
ylist_del_init(&(yaffs_dev_to_lc(dev)->contextList));
- up(&yaffs_context_lock);
+ mutex_unlock(&yaffs_context_lock);
if (yaffs_dev_to_lc(dev)->spareBuffer) {
YFREE(yaffs_dev_to_lc(dev)->spareBuffer);
@@ -3016,7 +3016,7 @@ static struct super_block *yaffs_interna
param->skip_checkpt_rd = options.skip_checkpoint_read;
param->skip_checkpt_wr = options.skip_checkpoint_write;
- down(&yaffs_context_lock);
+ mutex_lock(&yaffs_context_lock);
/* Get a mount id */
found = 0;
for(mount_id=0; ! found; mount_id++){
@@ -3030,13 +3030,13 @@ static struct super_block *yaffs_interna
context->mount_id = mount_id;
ylist_add_tail(&(yaffs_dev_to_lc(dev)->contextList), &yaffs_context_list);
- up(&yaffs_context_lock);
+ mutex_unlock(&yaffs_context_lock);
/* Directory search handling...*/
YINIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->searchContexts));
param->remove_obj_fn = yaffs_remove_obj_callback;
- init_MUTEX(&(yaffs_dev_to_lc(dev)->grossLock));
+ mutex_init(&(yaffs_dev_to_lc(dev)->grossLock));
yaffs_gross_lock(dev);
@@ -3268,7 +3268,7 @@ static int yaffs_proc_read(char *page,
else {
step-=2;
- down(&yaffs_context_lock);
+ mutex_lock(&yaffs_context_lock);
/* Locate and print the Nth entry. Order N-squared but N is small. */
ylist_for_each(item, &yaffs_context_list) {
@@ -3287,7 +3287,7 @@ static int yaffs_proc_read(char *page,
break;
}
- up(&yaffs_context_lock);
+ mutex_unlock(&yaffs_context_lock);
}
return buf - page < count ? buf - page : count;
@@ -3301,7 +3301,7 @@ static int yaffs_stats_proc_read(char *p
char *buf = page;
int n = 0;
- down(&yaffs_context_lock);
+ mutex_lock(&yaffs_context_lock);
/* Locate and print the Nth entry. Order N-squared but N is small. */
ylist_for_each(item, &yaffs_context_list) {
@@ -3317,7 +3317,7 @@ static int yaffs_stats_proc_read(char *p
dev->bg_gcs, dev->oldest_dirty_gc_count,
dev->n_obj, dev->n_tnodes);
}
- up(&yaffs_context_lock);
+ mutex_unlock(&yaffs_context_lock);
return buf - page < count ? buf - page : count;
@@ -3494,7 +3494,7 @@ static int __init init_yaffs_fs(void)
- init_MUTEX(&yaffs_context_lock);
+ mutex_init(&yaffs_context_lock);
/* Install the proc_fs entries */
my_proc_entry = create_proc_entry("yaffs",

View File

@ -1,72 +0,0 @@
From cd6657c4bde20886b0805ea9f2cbac7ec25ac2e5 Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Tue, 30 Nov 2010 16:01:28 +1300
Subject: [PATCH 1/2] yaffs: Replace yaffs_dir_llseek with Linux generic
llseek
commit ed8188fb7659cfb65b5adbe154d143190ade0324 upstream.
There was not much point in having the yaffs version as it is
functionally equivalent to the kernel one.
This also gets rid of using BKL in yaffs2.
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
yaffs_vfs.c | 30 +-----------------------------
yaffs_vfs_multi.c | 30 +-----------------------------
2 files changed, 2 insertions(+), 58 deletions(-)
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -342,8 +342,6 @@ static int yaffs_follow_link(struct dent
static void yaffs_touch_super(yaffs_dev_t *dev);
-static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
-
static int yaffs_vfs_setattr(struct inode *, struct iattr *);
@@ -460,7 +458,7 @@ static const struct file_operations yaff
.read = generic_read_dir,
.readdir = yaffs_readdir,
.fsync = yaffs_sync_object,
- .llseek = yaffs_dir_llseek,
+ .llseek = generic_file_llseek,
};
static const struct super_operations yaffs_super_ops = {
@@ -1534,32 +1532,6 @@ static void yaffs_release_space(struct f
}
-static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
-{
- long long retval;
-
- lock_kernel();
-
- switch (origin){
- case 2:
- offset += i_size_read(file->f_path.dentry->d_inode);
- break;
- case 1:
- offset += file->f_pos;
- }
- retval = -EINVAL;
-
- if (offset >= 0){
- if (offset != file->f_pos)
- file->f_pos = offset;
-
- retval = offset;
- }
- unlock_kernel();
- return retval;
-}
-
-
static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
{
yaffs_obj_t *obj;

View File

@ -1,110 +0,0 @@
From e1537a700c2e750c5eacc5ad93f30821f1e94424 Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Mon, 15 Aug 2011 11:40:30 +1200
Subject: [PATCH 2/2] Mods for Linux 3.0 and fix a typo
commit a7b5dcf904ba6f7890e4b77ce1f56388b855d0f6 upstream.
Roll in NCB's patch and some other changes for Linux 3.0.
Also fix a dumb type retired_writes->retried_writes
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
patch-ker.sh | 2 +-
yaffs_vfs_glue.c | 42 ++++++++++++++++++++++++++++++++++--------
2 files changed, 35 insertions(+), 9 deletions(-)
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -72,7 +72,9 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
#include <linux/smp_lock.h>
+#endif
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
@@ -236,7 +238,9 @@ static int yaffs_file_flush(struct file
static int yaffs_file_flush(struct file *file);
#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
static int yaffs_sync_object(struct file *file, int datasync);
#else
static int yaffs_sync_object(struct file *file, struct dentry *dentry,
@@ -1864,7 +1868,9 @@ static int yaffs_symlink(struct inode *d
return -ENOMEM;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
static int yaffs_sync_object(struct file *file, int datasync)
#else
static int yaffs_sync_object(struct file *file, struct dentry *dentry,
@@ -3067,7 +3073,13 @@ static int yaffs_internal_read_super_mtd
return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
+{
+ return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd);
+}
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
static int yaffs_read_super(struct file_system_type *fs,
int flags, const char *dev_name,
void *data, struct vfsmount *mnt)
@@ -3090,8 +3102,12 @@ static struct super_block *yaffs_read_su
static struct file_system_type yaffs_fs_type = {
.owner = THIS_MODULE,
.name = "yaffs",
- .get_sb = yaffs_read_super,
- .kill_sb = kill_block_super,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+ .mount = yaffs_mount,
+#else
+ .get_sb = yaffs_read_super,
+#endif
+ .kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
#else
@@ -3115,7 +3131,13 @@ static int yaffs2_internal_read_super_mt
return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
+{
+ return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd);
+}
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
static int yaffs2_read_super(struct file_system_type *fs,
int flags, const char *dev_name, void *data,
struct vfsmount *mnt)
@@ -3137,8 +3159,12 @@ static struct super_block *yaffs2_read_s
static struct file_system_type yaffs2_fs_type = {
.owner = THIS_MODULE,
.name = "yaffs2",
- .get_sb = yaffs2_read_super,
- .kill_sb = kill_block_super,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+ .mount = yaffs2_mount,
+#else
+ .get_sb = yaffs2_read_super,
+#endif
+ .kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
#else

View File

@ -1,54 +0,0 @@
--- a/fs/yaffs2/yaffs_mtdif1.c
+++ b/fs/yaffs2/yaffs_mtdif1.c
@@ -127,7 +127,7 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya
#endif
memset(&ops, 0, sizeof(ops));
- ops.mode = MTD_OOB_AUTO;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = (__u8 *)data;
@@ -179,7 +179,7 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y
int deleted;
memset(&ops, 0, sizeof(ops));
- ops.mode = MTD_OOB_AUTO;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = data;
--- a/fs/yaffs2/yaffs_mtdif2.c
+++ b/fs/yaffs2/yaffs_mtdif2.c
@@ -71,7 +71,7 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya
yaffs_PackTags2(&pt, tags, !dev->param.no_tags_ecc);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
- ops.mode = MTD_OOB_AUTO;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
ops.len = dev->param.total_bytes_per_chunk;
ops.ooboffs = 0;
@@ -136,7 +136,7 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y
retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
&dummy, data);
else if (tags) {
- ops.mode = MTD_OOB_AUTO;
+ ops.mode = MTD_OPS_AUTO_OOB;
ops.ooblen = packed_tags_size;
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
ops.ooboffs = 0;
--- a/fs/yaffs2/yaffs_mtdif.h
+++ b/fs/yaffs2/yaffs_mtdif.h
@@ -24,4 +24,11 @@ extern struct nand_oobinfo yaffs_noeccin
#endif
int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber);
int nandmtd_InitialiseNAND(yaffs_dev_t *dev);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+#include <mtd/mtd-abi.h>
+#else
+#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
+#endif
+
#endif

View File

@ -1,78 +0,0 @@
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -220,6 +220,29 @@ static struct inode *yaffs_iget(struct s
#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->u.generic_sbp)
#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0))
+static inline void yaffs_set_nlink(struct inode *inode, unsigned int nlink)
+{
+ set_nlink(inode, nlink);
+}
+
+static inline void yaffs_dec_link_count(struct inode *inode)
+{
+ inode_dec_link_count(inode);
+}
+#else
+static inline void yaffs_set_nlink(struct inode *inode, unsigned int nlink)
+{
+ inode->i_nlink = nlink;
+}
+
+static inline void yaffs_dec_link_count(struct inode *inode)
+{
+ inode->i_nlink--;
+ mark_inode_dirty(inode)
+}
+#endif
+
#define update_dir_time(dir) do {\
(dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
@@ -1362,7 +1385,7 @@ static void yaffs_fill_inode_from_obj(st
inode->i_size = yaffs_get_obj_length(obj);
inode->i_blocks = (inode->i_size + 511) >> 9;
- inode->i_nlink = yaffs_get_obj_link_count(obj);
+ yaffs_set_nlink(inode, yaffs_get_obj_link_count(obj));
T(YAFFS_TRACE_OS,
(TSTR("yaffs_fill_inode mode %x uid %d gid %d size %d count %d\n"),
@@ -1784,10 +1807,9 @@ static int yaffs_unlink(struct inode *di
retVal = yaffs_unlinker(obj, dentry->d_name.name);
if (retVal == YAFFS_OK) {
- dentry->d_inode->i_nlink--;
+ yaffs_dec_link_count(dentry->d_inode);
dir->i_version++;
yaffs_gross_unlock(dev);
- mark_inode_dirty(dentry->d_inode);
update_dir_time(dir);
return 0;
}
@@ -1818,7 +1840,8 @@ static int yaffs_link(struct dentry *old
obj);
if (link) {
- old_dentry->d_inode->i_nlink = yaffs_get_obj_link_count(obj);
+ yaffs_set_nlink(old_dentry->d_inode,
+ yaffs_get_obj_link_count(obj));
d_instantiate(dentry, old_dentry->d_inode);
atomic_inc(&old_dentry->d_inode->i_count);
T(YAFFS_TRACE_OS,
@@ -1937,11 +1960,9 @@ static int yaffs_rename(struct inode *ol
yaffs_gross_unlock(dev);
if (retVal == YAFFS_OK) {
- if (target) {
- new_dentry->d_inode->i_nlink--;
- mark_inode_dirty(new_dentry->d_inode);
- }
-
+ if (target)
+ yaffs_dec_link_count(new_dentry->d_inode);
+
update_dir_time(old_dir);
if(old_dir != new_dir)
update_dir_time(new_dir);

Some files were not shown because too many files have changed in this diff Show More