mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-29 18:19:02 +00:00
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:
parent
85755deaf6
commit
7e3644d3cf
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
|
@ -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__ */
|
|
@ -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
|
|
||||||
|
@ -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
|
||||||
|
124
target/linux/generic/files/fs/yaffs2/yaffs_attribs.c
Normal file
124
target/linux/generic/files/fs/yaffs2/yaffs_attribs.c
Normal 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;
|
||||||
|
}
|
28
target/linux/generic/files/fs/yaffs2/yaffs_attribs.h
Normal file
28
target/linux/generic/files/fs/yaffs2/yaffs_attribs.h
Normal 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
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 */
|
||||||
|
@ -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
|
||||||
|
@ -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
@ -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
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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*/
|
|
@ -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
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);*/
|
|
||||||
}
|
|
@ -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
|
|
313
target/linux/generic/files/fs/yaffs2/yaffs_summary.c
Normal file
313
target/linux/generic/files/fs/yaffs2/yaffs_summary.c
Normal 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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
target/linux/generic/files/fs/yaffs2/yaffs_summary.h
Normal file
37
target/linux/generic/files/fs/yaffs2/yaffs_summary.h
Normal 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
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
199
target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.c
Normal file
199
target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.c
Normal 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;
|
||||||
|
|
||||||
|
}
|
@ -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
|
@ -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);
|
|
||||||
|
|
||||||
}
|
|
@ -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
|
|
@ -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
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2002-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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
@ -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);
|
|
@ -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;
|
||||||
|
|
@ -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",
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
|
@ -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
|
|
@ -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;
|
|
@ -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")));
|
|
@ -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")));
|
|
||||||
|
|
@ -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;
|
|
@ -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
|
|
@ -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))
|
|
@ -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
|
|
@ -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;
|
|
||||||
|
|
@ -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;
|
@ -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);
|
|
@ -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;
|
||||||
|
|
@ -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",
|
|
@ -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,
|
||||||
|
};
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
|
@ -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
|
|
@ -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;
|
|
@ -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")));
|
|
@ -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")));
|
|
||||||
|
|
@ -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;
|
|
@ -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
|
|
@ -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))
|
|
@ -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
|
|
@ -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;
|
|
||||||
|
|
@ -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;
|
@ -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);
|
|
@ -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",
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -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
Loading…
Reference in New Issue
Block a user