# CONFIG_XZ_DEC_SPARC is not set
# CONFIG_XZ_DEC_TEST 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_YAM is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_XZ_DEC_SPARC is not set
# CONFIG_XZ_DEC_TEST 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_YAM is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_XZ_DEC_SPARC is not set
# CONFIG_XZ_DEC_TEST 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_YAM is not set
# CONFIG_YELLOWFIN is not set
#
-# YAFFS file system configurations
+# yaffs file system configurations
#
config YAFFS_FS
- tristate "YAFFS2 file system support"
+ tristate "yaffs2 file system support"
default n
depends on MTD_BLOCK
select YAFFS_YAFFS1
select YAFFS_YAFFS2
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.
- 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.
If unsure, say N.
- Further information on YAFFS2 is available at
+ Further information on yaffs2 is available at
<http://www.aleph1.co.uk/yaffs/>.
config YAFFS_YAFFS1
depends on YAFFS_FS
default y
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.
If unsure, say N.
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
default n
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.
If unsure, say N.
depends on YAFFS_FS
default y
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.
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
default n
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.
This behavior can also be overridden with tags_ecc_on and
tags_ecc_off mount options.
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
bool "Force chunk erase check"
depends on YAFFS_FS
default n
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
chunks that might have happened due to power loss.
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
bool "Empty lost and found on boot"
depends on YAFFS_FS
If this is set, then background processing is disabled.
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
bool "Enable yaffs2 xattr support"
help
If this is set then yaffs2 will provide xattr support.
If unsure, say Y.
-
-
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_tagscompat.o yaffs_tagsvalidity.o
-yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
-yaffs-y += yaffs_nameval.o
+yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o
+yaffs-y += yaffs_mtdif.o
+yaffs-y += yaffs_nameval.o yaffs_attribs.o
yaffs-y += yaffs_allocator.o
yaffs-y += yaffs_yaffs1.o
yaffs-y += yaffs_yaffs2.o
yaffs-y += yaffs_bitmap.o
+yaffs-y += yaffs_summary.o
yaffs-y += yaffs_verify.o
The yaffs2 source has been fetched from the yaffs2 GIT tree.
URL: git://www.aleph1.co.uk/yaffs2
-Version: 7396445d7d0d13469b9505791114b9dc6b76ffe4 (2010-10-20)
+Version: bc76682d93955cfb33051beb503ad9f8a5450578 (2013-12-03)
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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__ */
/*
- * 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
*
* 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
+ * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
-
#include "yaffs_allocator.h"
#include "yaffs_guts.h"
#include "yaffs_trace.h"
#include "yportenv.h"
-#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
-
-void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
-{
- dev = dev;
-}
-
-void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
-{
- dev = dev;
-}
-
-yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
-{
- return (yaffs_tnode_t *)YMALLOC(dev->tnode_size);
-}
-
-void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
-{
- dev = dev;
- YFREE(tn);
-}
-
-void yaffs_init_raw_objs(yaffs_dev_t *dev)
-{
- dev = dev;
-}
-
-void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
-{
- dev = dev;
-}
-
-yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
-{
- dev = dev;
- return (yaffs_obj_t *) YMALLOC(sizeof(yaffs_obj_t));
-}
-
-
-void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
-{
-
- dev = dev;
- YFREE(obj);
-}
-
-#else
+/*
+ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
+ * of approx 100 objects that are themn allocated singly.
+ * This is basically a simplified slab allocator.
+ *
+ * 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
+ * down all the tnodes and objects. slab requires that we first free
+ * the individual objects.
+ *
+ * Once yaffs has been mainlined I shall try to motivate for a change
+ * to slab to provide the extra features we need here.
+ */
struct yaffs_tnode_list {
struct yaffs_tnode_list *next;
- yaffs_tnode_t *tnodes;
+ struct yaffs_tnode *tnodes;
};
-typedef struct yaffs_tnode_list yaffs_tnodelist_t;
-
-struct yaffs_obj_tList_struct {
- yaffs_obj_t *objects;
- struct yaffs_obj_tList_struct *next;
+struct yaffs_obj_list {
+ struct yaffs_obj_list *next;
+ struct yaffs_obj *objects;
};
-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;
-struct yaffs_AllocatorStruct {
- int n_tnodesCreated;
- yaffs_tnode_t *freeTnodes;
- int nFreeTnodes;
- yaffs_tnodelist_t *allocatedTnodeList;
+ int n_obj_created;
+ struct list_head free_objs;
+ int n_free_objects;
- int n_objCreated;
- yaffs_obj_t *freeObjects;
- int nFreeObjects;
-
- yaffs_obj_tList *allocatedObjectList;
+ struct yaffs_obj_list *allocated_obj_list;
};
-typedef struct yaffs_AllocatorStruct yaffs_Allocator;
-
-
-static void yaffs_deinit_raw_tnodes(yaffs_dev_t *dev)
+static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
{
+ struct yaffs_allocator *allocator =
+ (struct yaffs_allocator *)dev->allocator;
+ struct yaffs_tnode_list *tmp;
- yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
-
- yaffs_tnodelist_t *tmp;
-
- if(!allocator){
- YBUG();
+ if (!allocator) {
+ BUG();
return;
}
- while (allocator->allocatedTnodeList) {
- tmp = allocator->allocatedTnodeList->next;
-
- YFREE(allocator->allocatedTnodeList->tnodes);
- YFREE(allocator->allocatedTnodeList);
- allocator->allocatedTnodeList = tmp;
+ while (allocator->alloc_tnode_list) {
+ tmp = allocator->alloc_tnode_list->next;
+ kfree(allocator->alloc_tnode_list->tnodes);
+ kfree(allocator->alloc_tnode_list);
+ allocator->alloc_tnode_list = tmp;
}
- allocator->freeTnodes = NULL;
- allocator->nFreeTnodes = 0;
- allocator->n_tnodesCreated = 0;
+ allocator->free_tnodes = NULL;
+ allocator->n_free_tnodes = 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;
-
- if(allocator){
- allocator->allocatedTnodeList = NULL;
- allocator->freeTnodes = NULL;
- allocator->nFreeTnodes = 0;
- allocator->n_tnodesCreated = 0;
- } else
- YBUG();
+ struct yaffs_allocator *allocator = dev->allocator;
+
+ if (!allocator) {
+ BUG();
+ return;
+ }
+
+ allocator->alloc_tnode_list = NULL;
+ 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;
- yaffs_tnode_t *newTnodes;
- __u8 *mem;
- yaffs_tnode_t *curr;
- yaffs_tnode_t *next;
- yaffs_tnodelist_t *tnl;
-
- if(!allocator){
- YBUG();
+ struct yaffs_tnode *new_tnodes;
+ u8 *mem;
+ struct yaffs_tnode *curr;
+ struct yaffs_tnode *next;
+ struct yaffs_tnode_list *tnl;
+
+ if (!allocator) {
+ BUG();
return YAFFS_FAIL;
}
if (n_tnodes < 1)
return YAFFS_OK;
-
/* make these things */
+ new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
+ mem = (u8 *) new_tnodes;
- newTnodes = YMALLOC(n_tnodes * dev->tnode_size);
- mem = (__u8 *)newTnodes;
-
- if (!newTnodes) {
- T(YAFFS_TRACE_ERROR,
- (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
+ if (!new_tnodes) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs: Could not allocate Tnodes");
return YAFFS_FAIL;
}
/* New hookup for wide tnodes */
for (i = 0; i < n_tnodes - 1; i++) {
- curr = (yaffs_tnode_t *) &mem[i * dev->tnode_size];
- next = (yaffs_tnode_t *) &mem[(i+1) * dev->tnode_size];
+ curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
+ next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
curr->internal[0] = next;
}
- curr = (yaffs_tnode_t *) &mem[(n_tnodes - 1) * dev->tnode_size];
- curr->internal[0] = allocator->freeTnodes;
- allocator->freeTnodes = (yaffs_tnode_t *)mem;
+ curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
+ curr->internal[0] = allocator->free_tnodes;
+ allocator->free_tnodes = (struct yaffs_tnode *)mem;
- allocator->nFreeTnodes += n_tnodes;
- allocator->n_tnodesCreated += n_tnodes;
+ allocator->n_free_tnodes += n_tnodes;
+ allocator->n_tnodes_created += n_tnodes;
/* Now add this bunch of tnodes to a list for freeing up.
* NB If we can't add this to the management list it isn't fatal
* but it just means we can't free this bunch of tnodes later.
*/
-
- tnl = YMALLOC(sizeof(yaffs_tnodelist_t));
+ tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
if (!tnl) {
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs: Could not add tnodes to management list" TENDSTR)));
- return YAFFS_FAIL;
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "Could not add tnodes to management list");
+ return YAFFS_FAIL;
} else {
- tnl->tnodes = newTnodes;
- tnl->next = allocator->allocatedTnodeList;
- allocator->allocatedTnodeList = tnl;
+ tnl->tnodes = new_tnodes;
+ tnl->next = allocator->alloc_tnode_list;
+ allocator->alloc_tnode_list = tnl;
}
- T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
return YAFFS_OK;
}
-
-yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
+struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
{
- yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
- yaffs_tnode_t *tn = NULL;
+ struct yaffs_allocator *allocator =
+ (struct yaffs_allocator *)dev->allocator;
+ struct yaffs_tnode *tn = NULL;
- if(!allocator){
- YBUG();
+ if (!allocator) {
+ BUG();
return NULL;
}
/* If there are none left make more */
- if (!allocator->freeTnodes)
+ if (!allocator->free_tnodes)
yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
- if (allocator->freeTnodes) {
- tn = allocator->freeTnodes;
- allocator->freeTnodes = allocator->freeTnodes->internal[0];
- allocator->nFreeTnodes--;
+ if (allocator->free_tnodes) {
+ tn = allocator->free_tnodes;
+ allocator->free_tnodes = allocator->free_tnodes->internal[0];
+ allocator->n_free_tnodes--;
}
return tn;
}
/* FreeTnode frees up a tnode and puts it back on the free list */
-void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
+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){
- YBUG();
+ if (!allocator) {
+ BUG();
return;
}
if (tn) {
- tn->internal[0] = allocator->freeTnodes;
- allocator->freeTnodes = tn;
- allocator->nFreeTnodes++;
+ tn->internal[0] = allocator->free_tnodes;
+ allocator->free_tnodes = tn;
+ 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(yaffs_dev_t *dev)
+static void yaffs_init_raw_objs(struct yaffs_dev *dev)
{
- yaffs_Allocator *allocator = dev->allocator;
-
- if(allocator) {
- allocator->allocatedObjectList = NULL;
- allocator->freeObjects = NULL;
- allocator->nFreeObjects = 0;
- } else
- YBUG();
+ struct yaffs_allocator *allocator = dev->allocator;
+
+ if (!allocator) {
+ BUG();
+ return;
+ }
+
+ allocator->allocated_obj_list = NULL;
+ INIT_LIST_HEAD(&allocator->free_objs);
+ allocator->n_free_objects = 0;
}
-static void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
+static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
{
- yaffs_Allocator *allocator = dev->allocator;
- yaffs_obj_tList *tmp;
+ struct yaffs_allocator *allocator = dev->allocator;
+ struct yaffs_obj_list *tmp;
- if(!allocator){
- YBUG();
+ if (!allocator) {
+ BUG();
return;
}
- while (allocator->allocatedObjectList) {
- tmp = allocator->allocatedObjectList->next;
- YFREE(allocator->allocatedObjectList->objects);
- YFREE(allocator->allocatedObjectList);
-
- allocator->allocatedObjectList = tmp;
+ 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;
}
- allocator->freeObjects = NULL;
- allocator->nFreeObjects = 0;
- allocator->n_objCreated = 0;
+ INIT_LIST_HEAD(&allocator->free_objs);
+ allocator->n_free_objects = 0;
+ allocator->n_obj_created = 0;
}
-
-static int yaffs_create_free_objs(yaffs_dev_t *dev, int n_obj)
+static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
{
- yaffs_Allocator *allocator = dev->allocator;
-
+ struct yaffs_allocator *allocator = dev->allocator;
int i;
- yaffs_obj_t *newObjects;
- yaffs_obj_tList *list;
+ struct yaffs_obj *new_objs;
+ struct yaffs_obj_list *list;
- if(!allocator){
- YBUG();
+ if (!allocator) {
+ BUG();
return YAFFS_FAIL;
}
return YAFFS_OK;
/* make these things */
- newObjects = YMALLOC(n_obj * sizeof(yaffs_obj_t));
- list = YMALLOC(sizeof(yaffs_obj_tList));
-
- if (!newObjects || !list) {
- if (newObjects){
- YFREE(newObjects);
- newObjects = NULL;
- }
- if (list){
- YFREE(list);
- list = NULL;
- }
- T(YAFFS_TRACE_ALLOCATE,
- (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
+ new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
+ list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
+
+ if (!new_objs || !list) {
+ kfree(new_objs);
+ new_objs = NULL;
+ kfree(list);
+ list = NULL;
+ yaffs_trace(YAFFS_TRACE_ALLOCATE,
+ "Could not allocate more objects");
return YAFFS_FAIL;
}
/* Hook them into the free list */
- for (i = 0; i < n_obj - 1; i++) {
- newObjects[i].siblings.next =
- (struct ylist_head *)(&newObjects[i + 1]);
- }
+ for (i = 0; i < n_obj; i++)
+ list_add(&new_objs[i].siblings, &allocator->free_objs);
- newObjects[n_obj - 1].siblings.next = (void *)allocator->freeObjects;
- allocator->freeObjects = newObjects;
- allocator->nFreeObjects += n_obj;
- allocator->n_objCreated += n_obj;
+ allocator->n_free_objects += n_obj;
+ allocator->n_obj_created += n_obj;
/* Now add this bunch of Objects to a list for freeing up. */
- list->objects = newObjects;
- list->next = allocator->allocatedObjectList;
- allocator->allocatedObjectList = list;
+ list->objects = new_objs;
+ list->next = allocator->allocated_obj_list;
+ allocator->allocated_obj_list = list;
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;
- yaffs_Allocator *allocator = dev->allocator;
+ struct yaffs_obj *obj = NULL;
+ struct list_head *lh;
+ struct yaffs_allocator *allocator = dev->allocator;
- if(!allocator) {
- YBUG();
+ if (!allocator) {
+ BUG();
return obj;
}
/* If there are none left make more */
- if (!allocator->freeObjects)
+ if (list_empty(&allocator->free_objs))
yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
- if (allocator->freeObjects) {
- obj = allocator->freeObjects;
- allocator->freeObjects =
- (yaffs_obj_t *) (allocator->freeObjects->siblings.next);
- allocator->nFreeObjects--;
+ if (!list_empty(&allocator->free_objs)) {
+ lh = allocator->free_objs.next;
+ obj = list_entry(lh, struct yaffs_obj, siblings);
+ list_del_init(lh);
+ allocator->n_free_objects--;
}
return obj;
}
-
-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)
{
- yaffs_Allocator *allocator = dev->allocator;
+ struct yaffs_allocator *allocator = dev->allocator;
- if(!allocator)
- YBUG();
- else {
- /* Link into the free list. */
- obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
- allocator->freeObjects = obj;
- allocator->nFreeObjects++;
+ if (!allocator) {
+ BUG();
+ return;
}
+
+ /* Link into the free list. */
+ list_add(&obj->siblings, &allocator->free_objs);
+ allocator->n_free_objects++;
}
-void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
+void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
{
- if(dev->allocator){
- yaffs_deinit_raw_tnodes(dev);
- yaffs_deinit_raw_objs(dev);
-
- YFREE(dev->allocator);
- dev->allocator=NULL;
- } else
- YBUG();
+
+ 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(yaffs_dev_t *dev)
+void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *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();
-}
+ 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);
+ }
+}
-#endif
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#include "yaffs_guts.h"
-void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev);
-void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev);
+void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
+void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
-yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev);
-void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn);
+struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
+void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
-yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev);
-void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj);
+struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
+void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
#endif
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
* 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) {
- T(YAFFS_TRACE_ERROR,
- (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
- blk));
- YBUG();
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "BlockBits block %d is not valid",
+ blk);
+ BUG();
}
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 ||
- chunk < 0 || chunk >= dev->param.chunks_per_block) {
- T(YAFFS_TRACE_ERROR,
- (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
- blk, chunk));
- YBUG();
+ chunk < 0 || chunk >= dev->param.chunks_per_block) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "Chunk Id (%d:%d) invalid",
+ blk, chunk);
+ 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);
-
- blkBits[chunk / 8] &= ~(1 << (chunk & 7));
+ blk_bits[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);
-
- blkBits[chunk / 8] |= (1 << (chunk & 7));
+ blk_bits[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);
- yaffs_verify_chunk_bit_id(dev, blk, chunk);
+ u8 *blk_bits = yaffs_block_bits(dev, blk);
- return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
+ yaffs_verify_chunk_bit_id(dev, blk, chunk);
+ return (blk_bits[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;
+
for (i = 0; i < dev->chunk_bit_stride; i++) {
- if (*blkBits)
+ if (*blk_bits)
return 1;
- blkBits++;
+ blk_bits++;
}
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 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;
}
-
/*
- * 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
*
* 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
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
#include "yaffs_guts.h"
-void yaffs_verify_chunk_bit_id(yaffs_dev_t *dev, int blk, int chunk);
-void yaffs_clear_chunk_bits(yaffs_dev_t *dev, int blk);
-void yaffs_clear_chunk_bit(yaffs_dev_t *dev, int blk, int chunk);
-void yaffs_set_chunk_bit(yaffs_dev_t *dev, int blk, int chunk);
-int yaffs_check_chunk_bit(yaffs_dev_t *dev, int blk, int chunk);
-int yaffs_still_some_chunks(yaffs_dev_t *dev, int blk);
-int yaffs_count_chunk_bits(yaffs_dev_t *dev, int blk);
+void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
+void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
+void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
+void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
+int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
+int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
+int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
#endif
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#include "yaffs_checkptrw.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)
+{
+ return chunk - dev->chunk_offset;
+}
+
+static int apply_block_offset(struct yaffs_dev *dev, int block)
+{
+ return block - dev->block_offset;
+}
+
+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)
{
- int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks;
+ struct yaffs_checkpt_chunk_hdr hdr;
+
+ memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
- T(YAFFS_TRACE_CHECKPOINT,
- (TSTR("checkpt blocks available = %d" TENDSTR),
- blocksAvailable));
+ dev->checkpt_byte_offs = sizeof(hdr);
- return (blocksAvailable <= 0) ? 0 : 1;
+ 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);
-static int yaffs_checkpt_erase(yaffs_dev_t *dev)
+ return (blocks_avail <= 0) ? 0 : 1;
+}
+
+static int yaffs_checkpt_erase(struct yaffs_dev *dev)
{
int i;
- if (!dev->param.erase_fn)
+ if (!dev->drv.drv_erase_fn)
return 0;
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
- dev->internal_start_block, dev->internal_end_block));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "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++) {
- 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) {
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "erasing checkpt block %d", i);
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;
dev->n_erased_blocks++;
- dev->n_free_chunks += dev->param.chunks_per_block;
+ dev->n_free_chunks +=
+ dev->param.chunks_per_block;
} else {
- dev->param.bad_block_fn(dev, i);
+ dev->drv.drv_mark_bad_fn(dev, offset_i);
bi->block_state = YAFFS_BLOCK_STATE_DEAD;
}
}
return 1;
}
-
-static void yaffs2_checkpt_find_erased_block(yaffs_dev_t *dev)
+static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
{
- int i;
- int blocksAvailable = 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),
- dev->n_erased_blocks, dev->param.n_reserved_blocks, blocksAvailable, dev->checkpt_next_block));
+ int i;
+ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "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 &&
- dev->checkpt_next_block <= dev->internal_end_block &&
- blocksAvailable > 0) {
+ dev->checkpt_next_block <= dev->internal_end_block &&
+ blocks_avail > 0) {
- for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) {
- yaffs_block_info_t *bi = yaffs_get_block_info(dev, i);
+ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
+ i++) {
+ struct yaffs_block_info *bi;
+
+ bi = yaffs_get_block_info(dev, i);
if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
dev->checkpt_next_block = i + 1;
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;
}
}
}
- 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_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;
- yaffs_ext_tags tags;
+ int i;
+ struct yaffs_ext_tags tags;
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
- dev->blocks_in_checkpt, dev->checkpt_next_block));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "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)
- 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 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);
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
- i, tags.obj_id, tags.seq_number, tags.ecc_result));
-
- if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
- /* 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++;
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i));
- return;
- }
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "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)
+ continue;
+
+ dev->tagger.query_block_fn(dev,
+ apply_block_offset(dev, i),
+ &state, &seq);
+ if (state == YAFFS_BLOCK_STATE_DEAD)
+ 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_cur_block = -1;
}
-
-int yaffs2_checkpt_open(yaffs_dev_t *dev, int forWriting)
+int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
{
+ int i;
-
- dev->checkpt_open_write = forWriting;
+ dev->checkpt_open_write = writing;
/* Got the functions we need? */
- if (!dev->param.write_chunk_tags_fn ||
- !dev->param.read_chunk_tags_fn ||
- !dev->param.erase_fn ||
- !dev->param.bad_block_fn)
+ if (!dev->tagger.write_chunk_tags_fn ||
+ !dev->tagger.read_chunk_tags_fn ||
+ !dev->drv.drv_erase_fn ||
+ !dev->drv.drv_mark_bad_fn)
return 0;
- if (forWriting && !yaffs2_checkpt_space_ok(dev))
+ if (writing && !yaffs2_checkpt_space_ok(dev))
return 0;
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)
return 0;
-
dev->checkpt_page_seq = 0;
dev->checkpt_byte_count = 0;
dev->checkpt_sum = 0;
dev->checkpt_cur_chunk = -1;
dev->checkpt_next_block = dev->internal_start_block;
- /* Erase all the blocks in the checkpoint area */
- if (forWriting) {
+ if (writing) {
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);
- } 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;
}
-int yaffs2_get_checkpt_sum(yaffs_dev_t *dev, __u32 *sum)
+int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
{
- __u32 compositeSum;
- compositeSum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xFF);
- *sum = compositeSum;
+ u32 composite_sum;
+
+ composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
+ *sum = composite_sum;
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 realignedChunk;
-
- yaffs_ext_tags tags;
+ int offset_chunk;
+ struct yaffs_ext_tags tags;
if (dev->checkpt_cur_block < 0) {
yaffs2_checkpt_find_erased_block(dev);
return 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.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
+ tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
tags.n_bytes = dev->data_bytes_per_chunk;
if (dev->checkpt_cur_chunk == 0) {
/* First chunk we write for the block? Set block state to
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;
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;
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
- chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, tags.obj_id, tags.chunk_id));
+ 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);
- realignedChunk = chunk - dev->chunk_offset;
+ offset_chunk = apply_chunk_offset(dev, chunk);
dev->n_page_writes++;
- dev->param.write_chunk_tags_fn(dev, realignedChunk,
- dev->checkpt_buffer, &tags);
- dev->checkpt_byte_offs = 0;
+ dev->tagger.write_chunk_tags_fn(dev, offset_chunk,
+ dev->checkpt_buffer, &tags);
dev->checkpt_page_seq++;
dev->checkpt_cur_chunk++;
if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
}
memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
+ yaffs2_checkpt_init_chunk_hdr(dev);
+
+
return 1;
}
-
-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 i = 0;
int ok = 1;
-
-
- __u8 * dataBytes = (__u8 *)data;
-
-
+ u8 *data_bytes = (u8 *) data;
if (!dev->checkpt_buffer)
return 0;
return -1;
while (i < n_bytes && ok) {
- dev->checkpt_buffer[dev->checkpt_byte_offs] = *dataBytes;
- dev->checkpt_sum += *dataBytes;
- dev->checkpt_xor ^= *dataBytes;
+ dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
+ dev->checkpt_sum += *data_bytes;
+ dev->checkpt_xor ^= *data_bytes;
dev->checkpt_byte_offs++;
i++;
- dataBytes++;
+ data_bytes++;
dev->checkpt_byte_count++;
-
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);
}
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 ok = 1;
- yaffs_ext_tags tags;
-
-
+ struct yaffs_ext_tags tags;
int chunk;
- int realignedChunk;
-
- __u8 *dataBytes = (__u8 *)data;
+ int offset_chunk;
+ u8 *data_bytes = (u8 *) data;
if (!dev->checkpt_buffer)
return 0;
while (i < n_bytes && ok) {
-
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) {
yaffs2_checkpt_find_block(dev);
dev->checkpt_cur_chunk = 0;
}
- if (dev->checkpt_cur_block < 0)
+ if (dev->checkpt_cur_block < 0) {
ok = 0;
- else {
- chunk = dev->checkpt_cur_block *
- dev->param.chunks_per_block +
- dev->checkpt_cur_chunk;
-
- realignedChunk = chunk - dev->chunk_offset;
-
- dev->n_page_reads++;
-
- /* read in the next chunk */
- /* printf("read checkpoint page %d\n",dev->checkpointPage); */
- dev->param.read_chunk_tags_fn(dev,
- realignedChunk,
+ break;
+ }
+
+ chunk = dev->checkpt_cur_block *
+ dev->param.chunks_per_block +
+ dev->checkpt_cur_chunk;
+
+ offset_chunk = apply_chunk_offset(dev, chunk);
+ dev->n_page_reads++;
+
+ /* read in the next chunk */
+ dev->tagger.read_chunk_tags_fn(dev,
+ offset_chunk,
dev->checkpt_buffer,
&tags);
- if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
- tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
- tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
- ok = 0;
+ if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
+ tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
+ tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {
+ ok = 0;
+ break;
+ }
+ if(!yaffs2_checkpt_check_chunk_hdr(dev)) {
+ ok = 0;
+ break;
+ }
- dev->checkpt_byte_offs = 0;
- dev->checkpt_page_seq++;
- dev->checkpt_cur_chunk++;
+ dev->checkpt_page_seq++;
+ dev->checkpt_cur_chunk++;
- if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block)
- dev->checkpt_cur_block = -1;
- }
- }
+ if (dev->checkpt_cur_chunk >=
+ dev->param.chunks_per_block)
+ dev->checkpt_cur_block = -1;
- if (ok) {
- *dataBytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
- dev->checkpt_sum += *dataBytes;
- dev->checkpt_xor ^= *dataBytes;
- dev->checkpt_byte_offs++;
- i++;
- dataBytes++;
- dev->checkpt_byte_count++;
}
+
+ *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
+ dev->checkpt_sum += *data_bytes;
+ dev->checkpt_xor ^= *data_bytes;
+ dev->checkpt_byte_offs++;
+ i++;
+ data_bytes++;
+ 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_byte_offs != 0)
+ if (dev->checkpt_byte_offs !=
+ sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))
yaffs2_checkpt_flush_buffer(dev);
- } else if(dev->checkpt_block_list){
- int i;
- for (i = 0; i < dev->blocks_in_checkpt && dev->checkpt_block_list[i] >= 0; i++) {
+ } else if (dev->checkpt_block_list) {
+ for (i = 0;
+ i < dev->blocks_in_checkpt &&
+ dev->checkpt_block_list[i] >= 0; i++) {
int blk = dev->checkpt_block_list[i];
- yaffs_block_info_t *bi = NULL;
- if( dev->internal_start_block <= blk && blk <= dev->internal_end_block)
+ struct yaffs_block_info *bi = NULL;
+
+ if (dev->internal_start_block <= blk &&
+ blk <= dev->internal_end_block)
bi = yaffs_get_block_info(dev, blk);
if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
- else {
- /* Todo this looks odd... */
- }
}
- YFREE(dev->checkpt_block_list);
+ kfree(dev->checkpt_block_list);
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;
-
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR),
- dev->checkpt_byte_count));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
+ dev->checkpt_byte_count);
if (dev->checkpt_buffer) {
/* free the buffer */
- YFREE(dev->checkpt_buffer);
+ kfree(dev->checkpt_buffer);
dev->checkpt_buffer = NULL;
return 1;
- } else
+ } else {
return 0;
+ }
}
-int yaffs2_checkpt_invalidate_stream(yaffs_dev_t *dev)
+int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
{
/* Erase the checkpoint data */
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
- dev->blocks_in_checkpt));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "checkpoint invalidate of %d blocks",
+ dev->blocks_in_checkpt);
return yaffs_checkpt_erase(dev);
}
-
-
-
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#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 yaffs2_checkpt_invalidate_stream(yaffs_dev_t *dev);
+int yaffs_checkpt_close(struct yaffs_dev *dev);
+int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
#endif
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
* 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
- * blocks are used on a 512-byte NAND page.
+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
+ * such ECC blocks are used on a 512-byte NAND page.
*
*/
+#include "yportenv.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.
+ * 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 "yaffs_ecc.h"
-
static const unsigned char column_parity_table[] = {
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
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 */
-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 char col_parity = 0;
unsigned char line_parity = 0;
unsigned char line_parity_prime = 0;
b = column_parity_table[*data++];
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_prime ^= ~i;
}
t |= 0x01;
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 */
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 */
d2 = read_ecc[2] ^ test_ecc[2];
if ((d0 | d1 | d2) == 0)
- return 0; /* no error */
+ return 0; /* no error */
if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
unsigned byte;
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;
if (d1 & 0x80)
data[byte] ^= (1 << bit);
- return 1; /* Corrected the error */
+ return 1; /* Corrected the error */
}
- if ((yaffs_count_bits(d0) +
- yaffs_count_bits(d1) +
- yaffs_count_bits(d2)) == 1) {
+ if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
/* Reccoverable error in ecc */
read_ecc[0] = test_ecc[0];
read_ecc[1] = test_ecc[1];
read_ecc[2] = test_ecc[2];
- return 1; /* Corrected the error */
+ return 1; /* Corrected the error */
}
/* Unrecoverable error */
}
-
/*
* ECCxxxOther does ECC calcs on arbitrary n bytes of data
*/
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 char col_parity = 0;
unsigned line_parity = 0;
unsigned line_parity_prime = 0;
b = column_parity_table[*data++];
col_parity ^= b;
- if (b & 0x01) {
+ if (b & 0x01) {
/* odd number of bits in the byte */
line_parity ^= i;
line_parity_prime ^= ~i;
}
- eccOther->colParity = (col_parity >> 2) & 0x3f;
- eccOther->lineParity = line_parity;
- eccOther->lineParityPrime = line_parity_prime;
+ ecc_other->col_parity = (col_parity >> 2) & 0x3f;
+ ecc_other->line_parity = line_parity;
+ ecc_other->line_parity_prime = line_parity_prime;
}
int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
- yaffs_ECCOther *read_ecc,
- const yaffs_ECCOther *test_ecc)
+ struct yaffs_ecc_other *read_ecc,
+ const struct yaffs_ecc_other *test_ecc)
{
- unsigned char cDelta; /* column parity delta */
- unsigned lDelta; /* line parity delta */
- unsigned lDeltaPrime; /* line parity delta */
+ unsigned char delta_col; /* column parity delta */
+ unsigned delta_line; /* line parity delta */
+ unsigned delta_line_prime; /* line parity delta */
unsigned bit;
- cDelta = read_ecc->colParity ^ test_ecc->colParity;
- lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
- lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
+ delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
+ delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
+ delta_line_prime =
+ read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
- if ((cDelta | lDelta | lDeltaPrime) == 0)
- return 0; /* no error */
+ if ((delta_col | delta_line | delta_line_prime) == 0)
+ return 0; /* no error */
- if (lDelta == ~lDeltaPrime &&
- (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) {
+ if (delta_line == ~delta_line_prime &&
+ (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
/* Single bit (recoverable) error in data */
bit = 0;
- if (cDelta & 0x20)
+ if (delta_col & 0x20)
bit |= 0x04;
- if (cDelta & 0x08)
+ if (delta_col & 0x08)
bit |= 0x02;
- if (cDelta & 0x02)
+ if (delta_col & 0x02)
bit |= 0x01;
- if (lDelta >= n_bytes)
+ if (delta_line >= n_bytes)
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) +
- yaffs_count_bits(cDelta)) == 1) {
+ if ((hweight32(delta_line) +
+ hweight32(delta_line_prime) +
+ hweight8(delta_col)) == 1) {
/* Reccoverable error in ecc */
*read_ecc = *test_ecc;
- return 1; /* corrected */
+ return 1; /* corrected */
}
/* Unrecoverable error */
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
* 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
- * blocks are used on a 512-byte NAND page.
+ * The ECC can correct single bit errors in a 256-byte page of data.
+ * Thus, two such ECC blocks are used on a 512-byte NAND page.
*
*/
#ifndef __YAFFS_ECC_H__
#define __YAFFS_ECC_H__
-typedef struct {
- unsigned char colParity;
- unsigned lineParity;
- unsigned lineParityPrime;
-} yaffs_ECCOther;
+struct yaffs_ecc_other {
+ unsigned char col_parity;
+ unsigned line_parity;
+ unsigned line_parity_prime;
+};
-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,
- const unsigned char *test_ecc);
+ const unsigned char *test_ecc);
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,
- yaffs_ECCOther *read_ecc,
- const yaffs_ECCOther *test_ecc);
+ struct yaffs_ecc_other *read_ecc,
+ const struct yaffs_ecc_other *test_ecc);
#endif
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#include "yaffs_trace.h"
/* 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) {
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
- blk));
- YBUG();
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>> yaffs: get_block_info block %d is not valid",
+ blk);
+ BUG();
}
return &dev->block_info[blk - dev->internal_start_block];
}
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+
#include "yportenv.h"
#include "yaffs_trace.h"
-#include "yaffsinterface.h"
#include "yaffs_guts.h"
-#include "yaffs_tagsvalidity.h"
#include "yaffs_getblockinfo.h"
-
#include "yaffs_tagscompat.h"
-
+#include "yaffs_tagsmarshall.h"
#include "yaffs_nand.h"
-
#include "yaffs_yaffs1.h"
#include "yaffs_yaffs2.h"
#include "yaffs_bitmap.h"
#include "yaffs_verify.h"
-
#include "yaffs_nand.h"
#include "yaffs_packedtags2.h"
-
#include "yaffs_nameval.h"
#include "yaffs_allocator.h"
+#include "yaffs_attribs.h"
+#include "yaffs_summary.h"
/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
#define YAFFS_GC_GOOD_ENOUGH 2
#include "yaffs_ecc.h"
+/* Forward declarations */
+static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
+ const u8 *buffer, int n_bytes, int use_reserve);
-/* Robustification (if it ever comes about...) */
-static void yaffs_retire_block(yaffs_dev_t *dev, int flash_block);
-static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk,
- int erasedOk);
-static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
- const __u8 *data,
- const yaffs_ext_tags *tags);
-static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
- const yaffs_ext_tags *tags);
-
-/* Other local prototypes */
-static void yaffs_update_parent(yaffs_obj_t *obj);
-static int yaffs_unlink_obj(yaffs_obj_t *obj);
-static int yaffs_obj_cache_dirty(yaffs_obj_t *obj);
-
-static int yaffs_write_new_chunk(yaffs_dev_t *dev,
- const __u8 *buffer,
- yaffs_ext_tags *tags,
- int useReserve);
-
-
-static yaffs_obj_t *yaffs_new_obj(yaffs_dev_t *dev, int number,
- yaffs_obj_type type);
-
-
-static int yaffs_apply_xattrib_mod(yaffs_obj_t *obj, char *buffer, yaffs_xattr_mod *xmod);
-
-static void yaffs_remove_obj_from_dir(yaffs_obj_t *obj);
-static int yaffs_check_structures(void);
-static int yaffs_generic_obj_del(yaffs_obj_t *in);
-
-static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
- int nand_chunk);
-
-static int yaffs_unlink_worker(yaffs_obj_t *obj);
-
-static int yaffs_tags_match(const yaffs_ext_tags *tags, int obj_id,
- int chunkInObject);
-
-static int yaffs_alloc_chunk(yaffs_dev_t *dev, int useReserve,
- yaffs_block_info_t **blockUsedPtr);
-
-static void yaffs_check_obj_details_loaded(yaffs_obj_t *in);
-
-static void yaffs_invalidate_whole_cache(yaffs_obj_t *in);
-static void yaffs_invalidate_chunk_cache(yaffs_obj_t *object, int chunk_id);
-
-static int yaffs_find_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
- yaffs_ext_tags *tags);
-
-static int yaffs_verify_chunk_written(yaffs_dev_t *dev,
- int nand_chunk,
- const __u8 *data,
- yaffs_ext_tags *tags);
-
-
-static void yaffs_load_name_from_oh(yaffs_dev_t *dev,YCHAR *name, const YCHAR *ohName, int bufferSize);
-static void yaffs_load_oh_from_name(yaffs_dev_t *dev,YCHAR *ohName, const YCHAR *name);
-
+static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
+ int buffer_size);
/* Function to calculate chunk and offset */
-static void yaffs_addr_to_chunk(yaffs_dev_t *dev, loff_t addr, int *chunkOut,
- __u32 *offsetOut)
+void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
+ int *chunk_out, u32 *offset_out)
{
int chunk;
- __u32 offset;
+ u32 offset;
- chunk = (__u32)(addr >> dev->chunk_shift);
+ chunk = (u32) (addr >> dev->chunk_shift);
if (dev->chunk_div == 1) {
/* easy power of 2 case */
- offset = (__u32)(addr & dev->chunk_mask);
+ offset = (u32) (addr & dev->chunk_mask);
} else {
/* Non power-of-2 case */
- loff_t chunkBase;
+ loff_t chunk_base;
chunk /= dev->chunk_div;
- chunkBase = ((loff_t)chunk) * dev->data_bytes_per_chunk;
- offset = (__u32)(addr - chunkBase);
+ chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
+ offset = (u32) (addr - chunk_base);
}
- *chunkOut = chunk;
- *offsetOut = offset;
+ *chunk_out = chunk;
+ *offset_out = offset;
}
/* Function to return the number of shifts for a power of 2 greater than or
* be hellishly efficient.
*/
-static __u32 ShiftsGE(__u32 x)
+static inline u32 calc_shifts_ceiling(u32 x)
{
- int extraBits;
- int nShifts;
+ int extra_bits;
+ int shifts;
- nShifts = extraBits = 0;
+ shifts = extra_bits = 0;
while (x > 1) {
if (x & 1)
- extraBits++;
+ extra_bits++;
x >>= 1;
- nShifts++;
+ shifts++;
}
- if (extraBits)
- nShifts++;
+ if (extra_bits)
+ shifts++;
- return nShifts;
+ return shifts;
}
/* Function to return the number of shifts to get a 1 in bit 0
*/
-static __u32 Shifts(__u32 x)
+static inline u32 calc_shifts(u32 x)
{
- __u32 nShifts;
+ u32 shifts;
- nShifts = 0;
+ shifts = 0;
if (!x)
return 0;
- while (!(x&1)) {
+ while (!(x & 1)) {
x >>= 1;
- nShifts++;
+ shifts++;
}
- return nShifts;
+ return shifts;
}
-
-
/*
* Temporary buffer manipulations.
*/
-static int yaffs_init_tmp_buffers(yaffs_dev_t *dev)
+static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
{
int i;
- __u8 *buf = (__u8 *)1;
+ u8 *buf = (u8 *) 1;
memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
- dev->temp_buffer[i].line = 0; /* not in use */
- dev->temp_buffer[i].buffer = buf =
- YMALLOC_DMA(dev->param.total_bytes_per_chunk);
+ dev->temp_buffer[i].in_use = 0;
+ buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
+ dev->temp_buffer[i].buffer = buf;
}
return buf ? YAFFS_OK : YAFFS_FAIL;
}
-__u8 *yaffs_get_temp_buffer(yaffs_dev_t *dev, int line_no)
+u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
{
- int i, j;
+ int i;
dev->temp_in_use++;
if (dev->temp_in_use > dev->max_temp)
dev->max_temp = dev->temp_in_use;
for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
- if (dev->temp_buffer[i].line == 0) {
- dev->temp_buffer[i].line = line_no;
- if ((i + 1) > dev->max_temp) {
- dev->max_temp = i + 1;
- for (j = 0; j <= i; j++)
- dev->temp_buffer[j].max_line =
- dev->temp_buffer[j].line;
- }
-
+ if (dev->temp_buffer[i].in_use == 0) {
+ dev->temp_buffer[i].in_use = 1;
return dev->temp_buffer[i].buffer;
}
}
- T(YAFFS_TRACE_BUFFERS,
- (TSTR("Out of temp buffers at line %d, other held by lines:"),
- line_no));
- for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
- T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->temp_buffer[i].line));
-
- T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));
-
+ yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
/*
* If we got here then we have to allocate an unmanaged one
* This is not good.
*/
dev->unmanaged_buffer_allocs++;
- return YMALLOC(dev->data_bytes_per_chunk);
+ return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
}
-void yaffs_release_temp_buffer(yaffs_dev_t *dev, __u8 *buffer,
- int line_no)
+void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
{
int i;
for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
if (dev->temp_buffer[i].buffer == buffer) {
- dev->temp_buffer[i].line = 0;
+ dev->temp_buffer[i].in_use = 0;
return;
}
}
if (buffer) {
/* assume it is an unmanaged one. */
- T(YAFFS_TRACE_BUFFERS,
- (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),
- line_no));
- YFREE(buffer);
+ yaffs_trace(YAFFS_TRACE_BUFFERS,
+ "Releasing unmanaged temp buffer");
+ kfree(buffer);
dev->unmanaged_buffer_deallocs++;
}
}
/*
- * Determine if we have a managed buffer.
+ * Functions for robustisizing TODO
+ *
*/
-int yaffs_is_managed_tmp_buffer(yaffs_dev_t *dev, const __u8 *buffer)
+
+static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
+ const u8 *data,
+ const struct yaffs_ext_tags *tags)
{
- int i;
+ (void) dev;
+ (void) nand_chunk;
+ (void) data;
+ (void) tags;
+}
- for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
- if (dev->temp_buffer[i].buffer == buffer)
- return 1;
- }
+static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
+ const struct yaffs_ext_tags *tags)
+{
+ (void) dev;
+ (void) nand_chunk;
+ (void) tags;
+}
- for (i = 0; i < dev->param.n_caches; i++) {
- if (dev->cache[i].data == buffer)
- return 1;
+void yaffs_handle_chunk_error(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi)
+{
+ if (!bi->gc_prioritise) {
+ bi->gc_prioritise = 1;
+ dev->has_pending_prioritised_gc = 1;
+ bi->chunk_error_strikes++;
+
+ if (bi->chunk_error_strikes > 3) {
+ bi->needs_retiring = 1; /* Too many stikes, so retire */
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs: Block struck out");
+
+ }
}
+}
- if (buffer == dev->checkpt_buffer)
- return 1;
+static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
+ int erased_ok)
+{
+ int flash_block = nand_chunk / dev->param.chunks_per_block;
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR)));
- return 0;
+ yaffs_handle_chunk_error(dev, bi);
+
+ if (erased_ok) {
+ /* Was an actual write failure,
+ * so mark the block for retirement.*/
+ bi->needs_retiring = 1;
+ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+ "**>> Block %d needs retiring", flash_block);
+ }
+
+ /* Delete the chunk */
+ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
+ yaffs_skip_rest_of_block(dev);
}
/*
* Verification code
*/
-
-
-
/*
* Simple hash function. Needs to have a reasonable spread
*/
-static Y_INLINE int yaffs_hash_fn(int n)
+static inline int yaffs_hash_fn(int n)
{
- n = abs(n);
+ if (n < 0)
+ n = -n;
return n % YAFFS_NOBJECT_BUCKETS;
}
* Note that root might have a presence in NAND if permissions are set.
*/
-yaffs_obj_t *yaffs_root(yaffs_dev_t *dev)
+struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
{
return dev->root_dir;
}
-yaffs_obj_t *yaffs_lost_n_found(yaffs_dev_t *dev)
+struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
{
return dev->lost_n_found;
}
-
/*
* Erased NAND checking functions
*/
-int yaffs_check_ff(__u8 *buffer, int n_bytes)
+int yaffs_check_ff(u8 *buffer, int n_bytes)
{
/* Horrible, slow implementation */
while (n_bytes--) {
- if (*buffer != 0xFF)
+ if (*buffer != 0xff)
return 0;
buffer++;
}
return 1;
}
-static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev,
- int nand_chunk)
+static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
{
int retval = YAFFS_OK;
- __u8 *data = yaffs_get_temp_buffer(dev, __LINE__);
- yaffs_ext_tags tags;
+ u8 *data = yaffs_get_temp_buffer(dev);
+ struct yaffs_ext_tags tags;
int result;
result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
retval = YAFFS_FAIL;
- if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) || tags.chunk_used) {
- T(YAFFS_TRACE_NANDACCESS,
- (TSTR("Chunk %d not erased" TENDSTR), nand_chunk));
+ if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
+ tags.chunk_used) {
+ yaffs_trace(YAFFS_TRACE_NANDACCESS,
+ "Chunk %d not erased", nand_chunk);
retval = YAFFS_FAIL;
}
- yaffs_release_temp_buffer(dev, data, __LINE__);
+ yaffs_release_temp_buffer(dev, data);
return retval;
}
-
-static int yaffs_verify_chunk_written(yaffs_dev_t *dev,
- int nand_chunk,
- const __u8 *data,
- yaffs_ext_tags *tags)
+static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
+ int nand_chunk,
+ const u8 *data,
+ struct yaffs_ext_tags *tags)
{
int retval = YAFFS_OK;
- yaffs_ext_tags tempTags;
- __u8 *buffer = yaffs_get_temp_buffer(dev,__LINE__);
+ struct yaffs_ext_tags temp_tags;
+ u8 *buffer = yaffs_get_temp_buffer(dev);
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 ||
- tempTags.chunk_id != tags->chunk_id ||
- tempTags.n_bytes != tags->n_bytes)
+
+ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
+ if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
+ temp_tags.obj_id != tags->obj_id ||
+ temp_tags.chunk_id != tags->chunk_id ||
+ temp_tags.n_bytes != tags->n_bytes)
retval = YAFFS_FAIL;
- yaffs_release_temp_buffer(dev, buffer, __LINE__);
+ yaffs_release_temp_buffer(dev, buffer);
return retval;
}
-static int yaffs_write_new_chunk(struct yaffs_dev_s *dev,
- const __u8 *data,
- yaffs_ext_tags *tags,
- int useReserve)
+
+int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
+{
+ int reserved_chunks;
+ int reserved_blocks = dev->param.n_reserved_blocks;
+ int checkpt_blocks;
+
+ checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
+
+ reserved_chunks =
+ (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;
+
+ return (dev->n_free_chunks > (reserved_chunks + n_chunks));
+}
+
+static int yaffs_find_alloc_block(struct yaffs_dev *dev)
+{
+ int i;
+ struct yaffs_block_info *bi;
+
+ if (dev->n_erased_blocks < 1) {
+ /* Hoosterman we've got a problem.
+ * Can't get space to gc
+ */
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: no more erased blocks");
+
+ return -1;
+ }
+
+ /* Find an empty block. */
+
+ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+ dev->alloc_block_finder++;
+ if (dev->alloc_block_finder < dev->internal_start_block
+ || dev->alloc_block_finder > dev->internal_end_block) {
+ dev->alloc_block_finder = dev->internal_start_block;
+ }
+
+ bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
+
+ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
+ bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
+ dev->seq_number++;
+ bi->seq_number = dev->seq_number;
+ dev->n_erased_blocks--;
+ yaffs_trace(YAFFS_TRACE_ALLOCATE,
+ "Allocated block %d, seq %d, %d left" ,
+ dev->alloc_block_finder, dev->seq_number,
+ dev->n_erased_blocks);
+ return dev->alloc_block_finder;
+ }
+ }
+
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs tragedy: no more erased blocks, but there should have been %d",
+ dev->n_erased_blocks);
+
+ return -1;
+}
+
+static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
+ struct yaffs_block_info **block_ptr)
+{
+ int ret_val;
+ struct yaffs_block_info *bi;
+
+ if (dev->alloc_block < 0) {
+ /* Get next block to allocate off */
+ dev->alloc_block = yaffs_find_alloc_block(dev);
+ dev->alloc_page = 0;
+ }
+
+ if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
+ /* No space unless we're allowed to use the reserve. */
+ return -1;
+ }
+
+ if (dev->n_erased_blocks < dev->param.n_reserved_blocks
+ && dev->alloc_page == 0)
+ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
+
+ /* Next page please.... */
+ if (dev->alloc_block >= 0) {
+ bi = yaffs_get_block_info(dev, dev->alloc_block);
+
+ ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
+ dev->alloc_page;
+ bi->pages_in_use++;
+ yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
+
+ dev->alloc_page++;
+
+ dev->n_free_chunks--;
+
+ /* If the block is full set the state to full */
+ if (dev->alloc_page >= dev->param.chunks_per_block) {
+ bi->block_state = YAFFS_BLOCK_STATE_FULL;
+ dev->alloc_block = -1;
+ }
+
+ if (block_ptr)
+ *block_ptr = bi;
+
+ return ret_val;
+ }
+
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");
+
+ return -1;
+}
+
+static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
+{
+ int n;
+
+ n = dev->n_erased_blocks * dev->param.chunks_per_block;
+
+ if (dev->alloc_block > 0)
+ n += (dev->param.chunks_per_block - dev->alloc_page);
+
+ return n;
+
+}
+
+/*
+ * yaffs_skip_rest_of_block() skips over the rest of the allocation block
+ * if we don't want to write to it.
+ */
+void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
+{
+ struct yaffs_block_info *bi;
+
+ if (dev->alloc_block > 0) {
+ bi = yaffs_get_block_info(dev, dev->alloc_block);
+ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
+ bi->block_state = YAFFS_BLOCK_STATE_FULL;
+ dev->alloc_block = -1;
+ }
+ }
+}
+
+static int yaffs_write_new_chunk(struct yaffs_dev *dev,
+ const u8 *data,
+ struct yaffs_ext_tags *tags, int use_reserver)
{
int attempts = 0;
- int writeOk = 0;
+ int write_ok = 0;
int chunk;
yaffs2_checkpt_invalidate(dev);
do {
- yaffs_block_info_t *bi = 0;
- int erasedOk = 0;
+ struct yaffs_block_info *bi = 0;
+ int erased_ok = 0;
- chunk = yaffs_alloc_chunk(dev, useReserve, &bi);
+ chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
if (chunk < 0) {
/* no space */
break;
*
* Check the first page we try to write in a block.
* If the check passes then we don't need to check any
- * more. If the check fails, we check again...
+ * more. If the check fails, we check again...
* If the block has been erased, we don't need to check.
*
* However, if the block has been prioritised for gc,
* 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.
*/
/* let's give it a try */
attempts++;
- if(dev->param.always_check_erased)
+ if (dev->param.always_check_erased)
bi->skip_erased_check = 0;
if (!bi->skip_erased_check) {
- erasedOk = yaffs_check_chunk_erased(dev, chunk);
- if (erasedOk != YAFFS_OK) {
- T(YAFFS_TRACE_ERROR,
- (TSTR("**>> yaffs chunk %d was not erased"
- TENDSTR), chunk));
+ erased_ok = yaffs_check_chunk_erased(dev, chunk);
+ if (erased_ok != YAFFS_OK) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>> yaffs chunk %d was not erased",
+ chunk);
/* If not erased, delete this one,
* skip rest of block and
* try another chunk */
- yaffs_chunk_del(dev,chunk,1,__LINE__);
- yaffs_skip_rest_of_block(dev);
+ yaffs_chunk_del(dev, chunk, 1, __LINE__);
+ yaffs_skip_rest_of_block(dev);
continue;
}
}
- writeOk = yaffs_wr_chunk_tags_nand(dev, chunk,
- data, tags);
+ write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
- if(!bi->skip_erased_check)
- writeOk = yaffs_verify_chunk_written(dev, chunk, data, tags);
+ if (!bi->skip_erased_check)
+ write_ok =
+ yaffs_verify_chunk_written(dev, chunk, data, tags);
- if (writeOk != YAFFS_OK) {
+ if (write_ok != YAFFS_OK) {
/* Clean up aborted write, skip to next block and
* try another chunk */
- yaffs_handle_chunk_wr_error(dev, chunk, erasedOk);
+ yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
continue;
}
/* Copy the data into the robustification buffer */
yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
- } while (writeOk != YAFFS_OK &&
- (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
+ } while (write_ok != YAFFS_OK &&
+ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
- if (!writeOk)
+ if (!write_ok)
chunk = -1;
if (attempts > 1) {
- T(YAFFS_TRACE_ERROR,
- (TSTR("**>> yaffs write required %d attempts" TENDSTR),
- attempts));
-
- dev->n_retired_writes += (attempts - 1);
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>> yaffs write required %d attempts",
+ attempts);
+ dev->n_retried_writes += (attempts - 1);
}
return chunk;
}
-
-
/*
* Block retiring for handling a broken block.
*/
-static void yaffs_retire_block(yaffs_dev_t *dev, int flash_block)
+static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
{
- yaffs_block_info_t *bi = yaffs_get_block_info(dev, flash_block);
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
yaffs2_checkpt_invalidate(dev);
-
- yaffs2_clear_oldest_dirty_seq(dev,bi);
+
+ yaffs2_clear_oldest_dirty_seq(dev, bi);
if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
- T(YAFFS_TRACE_ALWAYS, (TSTR(
- "yaffs: Failed to mark bad and erase block %d"
- TENDSTR), flash_block));
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs: Failed to mark bad and erase block %d",
+ flash_block);
} else {
- yaffs_ext_tags tags;
- int chunk_id = flash_block * dev->param.chunks_per_block;
+ struct yaffs_ext_tags tags;
+ int chunk_id =
+ flash_block * dev->param.chunks_per_block;
- __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
+ u8 *buffer = yaffs_get_temp_buffer(dev);
memset(buffer, 0xff, dev->data_bytes_per_chunk);
- yaffs_init_tags(&tags);
+ memset(&tags, 0, sizeof(tags));
tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
- if (dev->param.write_chunk_tags_fn(dev, chunk_id -
- dev->chunk_offset, buffer, &tags) != YAFFS_OK)
- T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
- TCONT("write bad block marker to block %d")
- TENDSTR), flash_block));
-
- yaffs_release_temp_buffer(dev, buffer, __LINE__);
+ if (dev->tagger.write_chunk_tags_fn(dev, chunk_id -
+ dev->chunk_offset,
+ buffer,
+ &tags) != YAFFS_OK)
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs: Failed to write bad block marker to block %d",
+ flash_block);
+
+ yaffs_release_temp_buffer(dev, buffer);
}
}
dev->n_retired_blocks++;
}
-/*
- * Functions for robustisizing TODO
- *
- */
-
-static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk,
- const __u8 *data,
- const yaffs_ext_tags *tags)
-{
- dev=dev;
- nand_chunk=nand_chunk;
- data=data;
- tags=tags;
-}
+/*---------------- Name handling functions ------------*/
-static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk,
- const yaffs_ext_tags *tags)
+static u16 yaffs_calc_name_sum(const YCHAR *name)
{
- dev=dev;
- nand_chunk=nand_chunk;
- tags=tags;
-}
+ u16 sum = 0;
+ u16 i = 1;
-void yaffs_handle_chunk_error(yaffs_dev_t *dev, yaffs_block_info_t *bi)
-{
- if (!bi->gc_prioritise) {
- bi->gc_prioritise = 1;
- dev->has_pending_prioritised_gc = 1;
- bi->chunk_error_strikes++;
+ if (!name)
+ return 0;
- if (bi->chunk_error_strikes > 3) {
- bi->needs_retiring = 1; /* Too many stikes, so retire this */
- T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
+ while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {
- }
+ /* 0x1f mask is case insensitive */
+ sum += ((*name) & 0x1f) * i;
+ i++;
+ name++;
}
+ return sum;
}
-static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk,
- int erasedOk)
-{
- int flash_block = nand_chunk / dev->param.chunks_per_block;
- yaffs_block_info_t *bi = yaffs_get_block_info(dev, flash_block);
- yaffs_handle_chunk_error(dev, bi);
+void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
+{
+ memset(obj->short_name, 0, sizeof(obj->short_name));
- if (erasedOk) {
- /* Was an actual write failure, so mark the block for retirement */
- bi->needs_retiring = 1;
- T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
- (TSTR("**>> Block %d needs retiring" TENDSTR), flash_block));
+ if (name && !name[0]) {
+ yaffs_fix_null_name(obj, obj->short_name,
+ YAFFS_SHORT_NAME_LENGTH);
+ name = obj->short_name;
+ } else if (name &&
+ strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
+ YAFFS_SHORT_NAME_LENGTH) {
+ strcpy(obj->short_name, name);
}
- /* Delete the chunk */
- yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
- yaffs_skip_rest_of_block(dev);
+ obj->sum = yaffs_calc_name_sum(name);
}
-
-/*---------------- Name handling functions ------------*/
-
-static __u16 yaffs_calc_name_sum(const YCHAR *name)
+void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
+ const struct yaffs_obj_hdr *oh)
{
- __u16 sum = 0;
- __u16 i = 1;
-
- const YUCHAR *bname = (const YUCHAR *) name;
- if (bname) {
- while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
-
-#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
- sum += yaffs_toupper(*bname) * i;
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+ YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
+ memset(tmp_name, 0, sizeof(tmp_name));
+ yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
+ YAFFS_MAX_NAME_LENGTH + 1);
+ yaffs_set_obj_name(obj, tmp_name);
#else
- sum += (*bname) * i;
+ yaffs_set_obj_name(obj, oh->name);
#endif
- i++;
- bname++;
- }
- }
- return sum;
}
-void yaffs_set_obj_name(yaffs_obj_t *obj, const YCHAR *name)
+loff_t yaffs_max_file_size(struct yaffs_dev *dev)
{
-#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
- memset(obj->short_name, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
- if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH)
- yaffs_strcpy(obj->short_name, name);
+ if(sizeof(loff_t) < 8)
+ return YAFFS_MAX_FILE_SIZE_32;
else
- obj->short_name[0] = _Y('\0');
-#endif
- obj->sum = yaffs_calc_name_sum(name);
-}
-
-void yaffs_set_obj_name_from_oh(yaffs_obj_t *obj, const yaffs_obj_header *oh)
-{
-#ifdef CONFIG_YAFFS_AUTO_UNICODE
- YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1];
- memset(tmpName,0,sizeof(tmpName));
- yaffs_load_name_from_oh(obj->my_dev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1);
- yaffs_set_obj_name(obj,tmpName);
-#else
- yaffs_set_obj_name(obj,oh->name);
-#endif
+ return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
}
/*-------------------- TNODES -------------------
* in the tnode.
*/
-
-yaffs_tnode_t *yaffs_get_tnode(yaffs_dev_t *dev)
+struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
{
- yaffs_tnode_t *tn = yaffs_alloc_raw_tnode(dev);
- if (tn){
+ struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
+
+ if (tn) {
memset(tn, 0, dev->tnode_size);
dev->n_tnodes++;
}
- dev->checkpoint_blocks_required = 0; /* force recalculation*/
+ dev->checkpoint_blocks_required = 0; /* force recalculation */
return tn;
}
/* FreeTnode frees up a tnode and puts it back on the free list */
-static void yaffs_free_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
+static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
{
- yaffs_free_raw_tnode(dev,tn);
+ yaffs_free_raw_tnode(dev, tn);
dev->n_tnodes--;
- dev->checkpoint_blocks_required = 0; /* force recalculation*/
+ dev->checkpoint_blocks_required = 0; /* force recalculation */
}
-static void yaffs_deinit_tnodes_and_objs(yaffs_dev_t *dev)
+static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
{
yaffs_deinit_raw_tnodes_and_objs(dev);
dev->n_obj = 0;
dev->n_tnodes = 0;
}
-
-void yaffs_load_tnode_0(yaffs_dev_t *dev, yaffs_tnode_t *tn, unsigned pos,
- unsigned val)
+static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+ unsigned pos, unsigned val)
{
- __u32 *map = (__u32 *)tn;
- __u32 bitInMap;
- __u32 bitInWord;
- __u32 wordInMap;
- __u32 mask;
+ u32 *map = (u32 *) tn;
+ u32 bit_in_map;
+ u32 bit_in_word;
+ u32 word_in_map;
+ u32 mask;
pos &= YAFFS_TNODES_LEVEL0_MASK;
val >>= dev->chunk_grp_bits;
- bitInMap = pos * dev->tnode_width;
- wordInMap = bitInMap / 32;
- bitInWord = bitInMap & (32 - 1);
+ bit_in_map = pos * dev->tnode_width;
+ word_in_map = bit_in_map / 32;
+ bit_in_word = bit_in_map & (32 - 1);
- mask = dev->tnode_mask << bitInWord;
+ mask = dev->tnode_mask << bit_in_word;
- map[wordInMap] &= ~mask;
- map[wordInMap] |= (mask & (val << bitInWord));
+ map[word_in_map] &= ~mask;
+ map[word_in_map] |= (mask & (val << bit_in_word));
- if (dev->tnode_width > (32 - bitInWord)) {
- bitInWord = (32 - bitInWord);
- wordInMap++;;
- mask = dev->tnode_mask >> (/*dev->tnode_width -*/ bitInWord);
- map[wordInMap] &= ~mask;
- map[wordInMap] |= (mask & (val >> bitInWord));
+ if (dev->tnode_width > (32 - bit_in_word)) {
+ bit_in_word = (32 - bit_in_word);
+ word_in_map++;
+ mask =
+ dev->tnode_mask >> bit_in_word;
+ map[word_in_map] &= ~mask;
+ map[word_in_map] |= (mask & (val >> bit_in_word));
}
}
-__u32 yaffs_get_group_base(yaffs_dev_t *dev, yaffs_tnode_t *tn,
- unsigned pos)
+u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+ unsigned pos)
{
- __u32 *map = (__u32 *)tn;
- __u32 bitInMap;
- __u32 bitInWord;
- __u32 wordInMap;
- __u32 val;
+ u32 *map = (u32 *) tn;
+ u32 bit_in_map;
+ u32 bit_in_word;
+ u32 word_in_map;
+ u32 val;
pos &= YAFFS_TNODES_LEVEL0_MASK;
- bitInMap = pos * dev->tnode_width;
- wordInMap = bitInMap / 32;
- bitInWord = bitInMap & (32 - 1);
+ bit_in_map = pos * dev->tnode_width;
+ word_in_map = bit_in_map / 32;
+ bit_in_word = bit_in_map & (32 - 1);
- val = map[wordInMap] >> bitInWord;
+ val = map[word_in_map] >> bit_in_word;
- if (dev->tnode_width > (32 - bitInWord)) {
- bitInWord = (32 - bitInWord);
- wordInMap++;;
- val |= (map[wordInMap] << bitInWord);
+ if (dev->tnode_width > (32 - bit_in_word)) {
+ bit_in_word = (32 - bit_in_word);
+ word_in_map++;
+ val |= (map[word_in_map] << bit_in_word);
}
val &= dev->tnode_mask;
*/
/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
-yaffs_tnode_t *yaffs_find_tnode_0(yaffs_dev_t *dev,
- yaffs_file_s *file_struct,
- __u32 chunk_id)
+struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
+ struct yaffs_file_var *file_struct,
+ u32 chunk_id)
{
- yaffs_tnode_t *tn = file_struct->top;
- __u32 i;
- int requiredTallness;
+ struct yaffs_tnode *tn = file_struct->top;
+ u32 i;
+ int required_depth;
int level = file_struct->top_level;
- dev=dev;
+ (void) dev;
/* Check sane level and chunk Id */
if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
/* First check we're tall enough (ie enough top_level) */
i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
- requiredTallness = 0;
+ required_depth = 0;
while (i) {
i >>= YAFFS_TNODES_INTERNAL_BITS;
- requiredTallness++;
+ required_depth++;
}
- if (requiredTallness > file_struct->top_level)
- return NULL; /* Not tall enough, so we can't find it */
+ if (required_depth > file_struct->top_level)
+ return NULL; /* Not tall enough, so we can't find it */
/* Traverse down to level 0 */
while (level > 0 && tn) {
tn = tn->internal[(chunk_id >>
- (YAFFS_TNODES_LEVEL0_BITS +
- (level - 1) *
- YAFFS_TNODES_INTERNAL_BITS)) &
- YAFFS_TNODES_INTERNAL_MASK];
+ (YAFFS_TNODES_LEVEL0_BITS +
+ (level - 1) *
+ YAFFS_TNODES_INTERNAL_BITS)) &
+ YAFFS_TNODES_INTERNAL_MASK];
level--;
}
return tn;
}
-/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
+/* add_find_tnode_0 finds the level 0 tnode if it exists,
+ * otherwise first expands the tree.
* This happens in two steps:
* 1. If the tree isn't tall enough, then make it taller.
* 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
*
* Used when modifying the tree.
*
- * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
- * be plugged into the ttree.
+ * If the tn argument is NULL, then a fresh tnode will be added otherwise the
+ * specified tn will be plugged into the ttree.
*/
-yaffs_tnode_t *yaffs_add_find_tnode_0(yaffs_dev_t *dev,
- yaffs_file_s *file_struct,
- __u32 chunk_id,
- yaffs_tnode_t *passed_tn)
+struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
+ struct yaffs_file_var *file_struct,
+ u32 chunk_id,
+ struct yaffs_tnode *passed_tn)
{
- int requiredTallness;
+ int required_depth;
int i;
int l;
- yaffs_tnode_t *tn;
-
- __u32 x;
-
+ struct yaffs_tnode *tn;
+ u32 x;
/* Check sane level and page Id */
- if (file_struct->top_level < 0 || file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
+ if (file_struct->top_level < 0 ||
+ file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
return NULL;
if (chunk_id > YAFFS_MAX_CHUNK_ID)
/* First check we're tall enough (ie enough top_level) */
x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
- requiredTallness = 0;
+ required_depth = 0;
while (x) {
x >>= YAFFS_TNODES_INTERNAL_BITS;
- requiredTallness++;
+ required_depth++;
}
-
- if (requiredTallness > file_struct->top_level) {
+ if (required_depth > file_struct->top_level) {
/* Not tall enough, gotta make the tree taller */
- for (i = file_struct->top_level; i < requiredTallness; i++) {
+ for (i = file_struct->top_level; i < required_depth; i++) {
tn = yaffs_get_tnode(dev);
file_struct->top = tn;
file_struct->top_level++;
} else {
- T(YAFFS_TRACE_ERROR,
- (TSTR("yaffs: no more tnodes" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs: no more tnodes");
return NULL;
}
}
(l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
YAFFS_TNODES_INTERNAL_MASK;
-
if ((l > 1) && !tn->internal[x]) {
/* Add missing non-level-zero tnode */
tn->internal[x] = yaffs_get_tnode(dev);
- if(!tn->internal[x])
+ if (!tn->internal[x])
return NULL;
} else if (l == 1) {
/* Looking from level 1 at level 0 */
if (passed_tn) {
- /* If we already have one, then release it.*/
+ /* If we already have one, release it */
if (tn->internal[x])
- yaffs_free_tnode(dev, tn->internal[x]);
+ yaffs_free_tnode(dev,
+ tn->internal[x]);
tn->internal[x] = passed_tn;
} else if (!tn->internal[x]) {
/* Don't have one, none passed in */
tn->internal[x] = yaffs_get_tnode(dev);
- if(!tn->internal[x])
+ if (!tn->internal[x])
return NULL;
}
}
} else {
/* top is level 0 */
if (passed_tn) {
- memcpy(tn, passed_tn, (dev->tnode_width * YAFFS_NTNODES_LEVEL0)/8);
+ memcpy(tn, passed_tn,
+ (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
yaffs_free_tnode(dev, passed_tn);
}
}
return tn;
}
-static int yaffs_find_chunk_in_group(yaffs_dev_t *dev, int theChunk,
- yaffs_ext_tags *tags, int obj_id,
- int inode_chunk)
+static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
+ int chunk_obj)
+{
+ return (tags->chunk_id == chunk_obj &&
+ tags->obj_id == obj_id &&
+ !tags->is_deleted) ? 1 : 0;
+
+}
+
+static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
+ struct yaffs_ext_tags *tags, int obj_id,
+ int inode_chunk)
{
int j;
- 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;
+ for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
+ if (yaffs_check_chunk_bit
+ (dev, the_chunk / dev->param.chunks_per_block,
+ the_chunk % dev->param.chunks_per_block)) {
+
+ if (dev->chunk_grp_size == 1)
+ return the_chunk;
else {
- yaffs_rd_chunk_tags_nand(dev, theChunk, NULL,
- tags);
- if (yaffs_tags_match(tags, obj_id, inode_chunk)) {
+ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
+ tags);
+ if (yaffs_tags_match(tags,
+ obj_id, inode_chunk)) {
/* found it; */
- return theChunk;
+ return the_chunk;
}
}
}
- theChunk++;
+ the_chunk++;
}
return -1;
}
-#if 0
-/* Experimental code not being used yet. Might speed up file deletion */
-/* DeleteWorker scans backwards through the tnode tree and deletes all the
- * chunks and tnodes in the file.
- * Returns 1 if the tree was deleted.
- * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
- */
-
-static int yaffs_del_worker(yaffs_obj_t *in, yaffs_tnode_t *tn, __u32 level,
- int chunk_offset, int *limit)
+int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+ struct yaffs_ext_tags *tags)
{
- int i;
- int inode_chunk;
- int theChunk;
- yaffs_ext_tags tags;
- int foundChunk;
- yaffs_dev_t *dev = in->my_dev;
+ /*Get the Tnode, then get the level 0 offset chunk offset */
+ struct yaffs_tnode *tn;
+ int the_chunk = -1;
+ struct yaffs_ext_tags local_tags;
+ int ret_val = -1;
+ struct yaffs_dev *dev = in->my_dev;
- int allDone = 1;
+ if (!tags) {
+ /* Passed a NULL, so use our own tags space */
+ tags = &local_tags;
+ }
- if (tn) {
- if (level > 0) {
- for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
- i--) {
- if (tn->internal[i]) {
- if (limit && (*limit) < 0) {
- allDone = 0;
- } else {
- allDone =
- yaffs_del_worker(in,
- tn->
- internal
- [i],
- level -
- 1,
- (chunk_offset
- <<
- YAFFS_TNODES_INTERNAL_BITS)
- + i,
- limit);
- }
- if (allDone) {
- yaffs_free_tnode(dev,
- tn->
- internal[i]);
- tn->internal[i] = NULL;
- }
- }
- }
- return (allDone) ? 1 : 0;
- } else if (level == 0) {
- int hitLimit = 0;
-
- for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
- i--) {
- theChunk = yaffs_get_group_base(dev, tn, i);
- if (theChunk) {
-
- inode_chunk = (chunk_offset <<
- YAFFS_TNODES_LEVEL0_BITS) + i;
-
- foundChunk =
- yaffs_find_chunk_in_group(dev,
- theChunk,
- &tags,
- in->obj_id,
- inode_chunk);
-
- if (foundChunk > 0) {
- yaffs_chunk_del(dev,
- foundChunk, 1,
- __LINE__);
- in->n_data_chunks--;
- if (limit) {
- *limit = *limit - 1;
- if (*limit <= 0)
- hitLimit = 1;
- }
+ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
- }
+ if (!tn)
+ return ret_val;
- yaffs_load_tnode_0(dev, tn, i, 0);
- }
+ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
+ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
+ inode_chunk);
+ return ret_val;
+}
+
+static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
+ struct yaffs_ext_tags *tags)
+{
+ /* Get the Tnode, then get the level 0 offset chunk offset */
+ struct yaffs_tnode *tn;
+ int the_chunk = -1;
+ struct yaffs_ext_tags local_tags;
+ struct yaffs_dev *dev = in->my_dev;
+ int ret_val = -1;
+
+ if (!tags) {
+ /* Passed a NULL, so use our own tags space */
+ tags = &local_tags;
+ }
+
+ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
+
+ if (!tn)
+ return ret_val;
+
+ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
+
+ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
+ inode_chunk);
+
+ /* Delete the entry in the filestructure (if found) */
+ if (ret_val != -1)
+ yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
+
+ return ret_val;
+}
+
+int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+ int nand_chunk, int in_scan)
+{
+ /* NB in_scan is zero unless scanning.
+ * For forward scanning, in_scan is > 0;
+ * for backward scanning in_scan is < 0
+ *
+ * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
+ */
+
+ struct yaffs_tnode *tn;
+ struct yaffs_dev *dev = in->my_dev;
+ int existing_cunk;
+ struct yaffs_ext_tags existing_tags;
+ struct yaffs_ext_tags new_tags;
+ unsigned existing_serial, new_serial;
+
+ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
+ /* Just ignore an attempt at putting a chunk into a non-file
+ * during scanning.
+ * If it is not during Scanning then something went wrong!
+ */
+ if (!in_scan) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy:attempt to put data chunk into a non-file"
+ );
+ BUG();
+ }
+
+ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
+ return YAFFS_OK;
+ }
+
+ tn = yaffs_add_find_tnode_0(dev,
+ &in->variant.file_variant,
+ inode_chunk, NULL);
+ if (!tn)
+ return YAFFS_FAIL;
+
+ if (!nand_chunk)
+ /* Dummy insert, bail now */
+ return YAFFS_OK;
+
+ existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
+
+ if (in_scan != 0) {
+ /* If we're scanning then we need to test for duplicates
+ * NB This does not need to be efficient since it should only
+ * happen when the power fails during a write, then only one
+ * chunk should ever be affected.
+ *
+ * Correction for YAFFS2: This could happen quite a lot and we
+ * need to think about efficiency! TODO
+ * Update: For backward scanning we don't need to re-read tags
+ * so this is quite cheap.
+ */
+
+ if (existing_cunk > 0) {
+ /* NB Right now existing chunk will not be real
+ * chunk_id if the chunk group size > 1
+ * thus we have to do a FindChunkInFile to get the
+ * real chunk id.
+ *
+ * We have a duplicate now we need to decide which
+ * one to use:
+ *
+ * Backwards scanning YAFFS2: The old one is what
+ * we use, dump the new one.
+ * YAFFS1: Get both sets of tags and compare serial
+ * numbers.
+ */
+
+ if (in_scan > 0) {
+ /* Only do this for forward scanning */
+ yaffs_rd_chunk_tags_nand(dev,
+ nand_chunk,
+ NULL, &new_tags);
+
+ /* Do a proper find */
+ existing_cunk =
+ yaffs_find_chunk_in_file(in, inode_chunk,
+ &existing_tags);
+ }
+
+ if (existing_cunk <= 0) {
+ /*Hoosterman - how did this happen? */
+
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: existing chunk < 0 in scan"
+ );
+
+ }
+
+ /* NB The deleted flags should be false, otherwise
+ * the chunks will not be loaded during a scan
+ */
+
+ if (in_scan > 0) {
+ new_serial = new_tags.serial_number;
+ existing_serial = existing_tags.serial_number;
}
- return (i < 0) ? 1 : 0;
+ if ((in_scan > 0) &&
+ (existing_cunk <= 0 ||
+ ((existing_serial + 1) & 3) == new_serial)) {
+ /* Forward scanning.
+ * Use new
+ * Delete the old one and drop through to
+ * update the tnode
+ */
+ yaffs_chunk_del(dev, existing_cunk, 1,
+ __LINE__);
+ } else {
+ /* Backward scanning or we want to use the
+ * existing one
+ * Delete the new one and return early so that
+ * the tnode isn't changed
+ */
+ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
+ return YAFFS_OK;
+ }
}
}
- return 1;
+ if (existing_cunk == 0)
+ in->n_data_chunks++;
-}
+ yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
-#endif
+ return YAFFS_OK;
+}
-static void yaffs_soft_del_chunk(yaffs_dev_t *dev, int chunk)
+static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
{
- yaffs_block_info_t *theBlock;
+ struct yaffs_block_info *the_block;
unsigned block_no;
- T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
+ yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);
- block_no = chunk / dev->param.chunks_per_block;
- theBlock = yaffs_get_block_info(dev, block_no);
- if (theBlock) {
- theBlock->soft_del_pages++;
+ block_no = chunk / dev->param.chunks_per_block;
+ the_block = yaffs_get_block_info(dev, block_no);
+ if (the_block) {
+ the_block->soft_del_pages++;
dev->n_free_chunks++;
- yaffs2_update_oldest_dirty_seq(dev, block_no, theBlock);
+ yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
}
}
-/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
- * All soft deleting does is increment the block's softdelete count and pulls the chunk out
- * of the tnode.
- * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
+/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all
+ * the chunks in the file.
+ * All soft deleting does is increment the block's softdelete count and pulls
+ * the chunk out of the tnode.
+ * Thus, essentially this is the same as DeleteWorker except that the chunks
+ * are soft deleted.
*/
-static int yaffs_soft_del_worker(yaffs_obj_t *in, yaffs_tnode_t *tn,
- __u32 level, int chunk_offset)
+static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
+ u32 level, int chunk_offset)
{
int i;
- int theChunk;
- int allDone = 1;
- yaffs_dev_t *dev = in->my_dev;
+ int the_chunk;
+ int all_done = 1;
+ struct yaffs_dev *dev = in->my_dev;
- if (tn) {
- if (level > 0) {
-
- for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
- i--) {
- if (tn->internal[i]) {
- allDone =
- yaffs_soft_del_worker(in,
- tn->
- internal[i],
- level - 1,
- (chunk_offset
- <<
- YAFFS_TNODES_INTERNAL_BITS)
- + i);
- if (allDone) {
- yaffs_free_tnode(dev,
- tn->
- internal[i]);
- tn->internal[i] = NULL;
- } else {
- /* Hoosterman... how could this happen? */
- }
- }
- }
- return (allDone) ? 1 : 0;
- } else if (level == 0) {
-
- for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
- theChunk = yaffs_get_group_base(dev, tn, i);
- if (theChunk) {
- /* Note this does not find the real chunk, only the chunk group.
- * We make an assumption that a chunk group is not larger than
- * a block.
- */
- yaffs_soft_del_chunk(dev, theChunk);
- yaffs_load_tnode_0(dev, tn, i, 0);
- }
+ if (!tn)
+ return 1;
+ if (level > 0) {
+ for (i = YAFFS_NTNODES_INTERNAL - 1;
+ all_done && i >= 0;
+ i--) {
+ if (tn->internal[i]) {
+ all_done =
+ yaffs_soft_del_worker(in,
+ tn->internal[i],
+ level - 1,
+ (chunk_offset <<
+ YAFFS_TNODES_INTERNAL_BITS)
+ + i);
+ if (all_done) {
+ yaffs_free_tnode(dev,
+ tn->internal[i]);
+ tn->internal[i] = NULL;
+ } else {
+ /* Can this happen? */
+ }
}
- return 1;
+ }
+ return (all_done) ? 1 : 0;
+ }
+ /* level 0 */
+ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
+ the_chunk = yaffs_get_group_base(dev, tn, i);
+ if (the_chunk) {
+ yaffs_soft_del_chunk(dev, the_chunk);
+ yaffs_load_tnode_0(dev, tn, i, 0);
}
+ }
+ return 1;
+}
+
+static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
+{
+ struct yaffs_dev *dev = obj->my_dev;
+ struct yaffs_obj *parent;
+
+ yaffs_verify_obj_in_dir(obj);
+ parent = obj->parent;
+ yaffs_verify_dir(parent);
+
+ if (dev && dev->param.remove_obj_fn)
+ dev->param.remove_obj_fn(obj);
+
+ list_del_init(&obj->siblings);
+ obj->parent = NULL;
+
+ yaffs_verify_dir(parent);
+}
+
+void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
+{
+ if (!directory) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "tragedy: Trying to add an object to a null pointer directory"
+ );
+ BUG();
+ return;
+ }
+ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "tragedy: Trying to add an object to a non-directory"
+ );
+ BUG();
}
- return 1;
+ if (obj->siblings.prev == NULL) {
+ /* Not initialised */
+ BUG();
+ }
+
+ yaffs_verify_dir(directory);
+
+ yaffs_remove_obj_from_dir(obj);
+
+ /* Now add it */
+ list_add(&obj->siblings, &directory->variant.dir_variant.children);
+ obj->parent = directory;
+
+ if (directory == obj->my_dev->unlinked_dir
+ || directory == obj->my_dev->del_dir) {
+ obj->unlinked = 1;
+ obj->my_dev->n_unlinked_files++;
+ obj->rename_allowed = 0;
+ }
+ yaffs_verify_dir(directory);
+ yaffs_verify_obj_in_dir(obj);
}
-static void yaffs_soft_del_file(yaffs_obj_t *obj)
+static int yaffs_change_obj_name(struct yaffs_obj *obj,
+ struct yaffs_obj *new_dir,
+ const YCHAR *new_name, int force, int shadows)
{
- if (obj->deleted &&
- obj->variant_type == YAFFS_OBJECT_TYPE_FILE && !obj->soft_del) {
- if (obj->n_data_chunks <= 0) {
- /* Empty file with no duplicate object headers, just delete it immediately */
- yaffs_free_tnode(obj->my_dev,
- obj->variant.file_variant.top);
- obj->variant.file_variant.top = NULL;
- T(YAFFS_TRACE_TRACING,
- (TSTR("yaffs: Deleting empty file %d" TENDSTR),
- obj->obj_id));
- yaffs_generic_obj_del(obj);
- } else {
- yaffs_soft_del_worker(obj,
- obj->variant.file_variant.top,
- obj->variant.file_variant.
- top_level, 0);
- obj->soft_del = 1;
- }
+ int unlink_op;
+ int del_op;
+ struct yaffs_obj *existing_target;
+
+ if (new_dir == NULL)
+ new_dir = obj->parent; /* use the old directory */
+
+ if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "tragedy: yaffs_change_obj_name: new_dir is not a directory"
+ );
+ BUG();
}
+
+ unlink_op = (new_dir == obj->my_dev->unlinked_dir);
+ del_op = (new_dir == obj->my_dev->del_dir);
+
+ existing_target = yaffs_find_by_name(new_dir, new_name);
+
+ /* If the object is a file going into the unlinked directory,
+ * then it is OK to just stuff it in since duplicate names are OK.
+ * else only proceed if the new name does not exist and we're putting
+ * it into a directory.
+ */
+ if (!(unlink_op || del_op || force ||
+ shadows > 0 || !existing_target) ||
+ new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+ return YAFFS_FAIL;
+
+ yaffs_set_obj_name(obj, new_name);
+ obj->dirty = 1;
+ yaffs_add_obj_to_dir(new_dir, obj);
+
+ if (unlink_op)
+ obj->unlinked = 1;
+
+ /* If it is a deletion then we mark it as a shrink for gc */
+ if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0)
+ return YAFFS_OK;
+
+ return YAFFS_FAIL;
}
-/* Pruning removes any part of the file structure tree that is beyond the
- * bounds of the file (ie that does not point to chunks).
- *
- * A file should only get pruned when its size is reduced.
- *
- * Before pruning, the chunks must be pulled from the tree and the
- * level 0 tnode entries must be zeroed out.
- * Could also use this for file deletion, but that's probably better handled
- * by a special case.
+/*------------------------ Short Operations Cache ------------------------------
+ * In many situations where there is no high level buffering a lot of
+ * reads might be short sequential reads, and a lot of writes may be short
+ * sequential writes. eg. scanning/writing a jpeg file.
+ * In these cases, a short read/write cache can provide a huge perfomance
+ * benefit with dumb-as-a-rock code.
+ * In Linux, the page cache provides read buffering and the short op cache
+ * provides write buffering.
*
- * This function is recursive. For levels > 0 the function is called again on
- * any sub-tree. For level == 0 we just check if the sub-tree has data.
- * If there is no data in a subtree then it is pruned.
+ * There are a small number (~10) of cache chunks per device so that we don't
+ * need a very intelligent search.
*/
-static yaffs_tnode_t *yaffs_prune_worker(yaffs_dev_t *dev, yaffs_tnode_t *tn,
- __u32 level, int del0)
+static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
{
+ struct yaffs_dev *dev = obj->my_dev;
int i;
- int hasData;
+ struct yaffs_cache *cache;
+ int n_caches = obj->my_dev->param.n_caches;
- if (tn) {
- hasData = 0;
-
- if(level > 0){
- for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
- if (tn->internal[i]) {
- tn->internal[i] =
- yaffs_prune_worker(dev, tn->internal[i],
- level - 1,
- (i == 0) ? del0 : 1);
- }
+ for (i = 0; i < n_caches; i++) {
+ cache = &dev->cache[i];
+ if (cache->object == obj && cache->dirty)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void yaffs_flush_file_cache(struct yaffs_obj *obj)
+{
+ struct yaffs_dev *dev = obj->my_dev;
+ int lowest = -99; /* Stop compiler whining. */
+ int i;
+ struct yaffs_cache *cache;
+ int chunk_written = 0;
+ int n_caches = obj->my_dev->param.n_caches;
- if (tn->internal[i])
- hasData++;
+ if (n_caches < 1)
+ return;
+ do {
+ cache = NULL;
+
+ /* Find the lowest dirty chunk for this object */
+ for (i = 0; i < n_caches; i++) {
+ if (dev->cache[i].object == obj &&
+ dev->cache[i].dirty) {
+ if (!cache ||
+ dev->cache[i].chunk_id < lowest) {
+ cache = &dev->cache[i];
+ lowest = cache->chunk_id;
+ }
}
- } else {
- int tnode_size_u32 = dev->tnode_size/sizeof(__u32);
- __u32 *map = (__u32 *)tn;
+ }
+
+ if (cache && !cache->locked) {
+ /* Write it out and free it up */
+ chunk_written =
+ yaffs_wr_data_obj(cache->object,
+ cache->chunk_id,
+ cache->data,
+ cache->n_bytes, 1);
+ cache->dirty = 0;
+ cache->object = NULL;
+ }
+ } while (cache && chunk_written > 0);
- for(i = 0; !hasData && i < tnode_size_u32; i++){
- if(map[i])
- hasData++;
- }
- }
+ if (cache)
+ /* Hoosterman, disk full while writing cache out. */
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: no space during cache write");
+}
- if (hasData == 0 && del0) {
- /* Free and return NULL */
+/*yaffs_flush_whole_cache(dev)
+ *
+ *
+ */
- yaffs_free_tnode(dev, tn);
- tn = NULL;
+void yaffs_flush_whole_cache(struct yaffs_dev *dev)
+{
+ struct yaffs_obj *obj;
+ int n_caches = dev->param.n_caches;
+ int i;
+
+ /* Find a dirty object in the cache and flush it...
+ * until there are no further dirty objects.
+ */
+ do {
+ obj = NULL;
+ for (i = 0; i < n_caches && !obj; i++) {
+ if (dev->cache[i].object && dev->cache[i].dirty)
+ obj = dev->cache[i].object;
}
+ if (obj)
+ yaffs_flush_file_cache(obj);
+ } while (obj);
- }
+}
- return tn;
+/* Grab us a cache chunk for use.
+ * First look for an empty one.
+ * Then look for the least recently used non-dirty one.
+ * Then look for the least recently used dirty one...., flush and look again.
+ */
+static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
+{
+ int i;
+ if (dev->param.n_caches > 0) {
+ for (i = 0; i < dev->param.n_caches; i++) {
+ if (!dev->cache[i].object)
+ return &dev->cache[i];
+ }
+ }
+ return NULL;
}
-static int yaffs_prune_tree(yaffs_dev_t *dev,
- yaffs_file_s *file_struct)
+static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
{
+ struct yaffs_cache *cache;
+ struct yaffs_obj *the_obj;
+ int usage;
int i;
- int hasData;
- int done = 0;
- yaffs_tnode_t *tn;
+ int pushout;
+
+ if (dev->param.n_caches < 1)
+ return NULL;
+
+ /* Try find a non-dirty one... */
- if (file_struct->top_level > 0) {
- file_struct->top =
- yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
+ cache = yaffs_grab_chunk_worker(dev);
- /* Now we have a tree with all the non-zero branches NULL but the height
- * is the same as it was.
- * Let's see if we can trim internal tnodes to shorten the tree.
- * We can do this if only the 0th element in the tnode is in use
- * (ie all the non-zero are NULL)
+ if (!cache) {
+ /* They were all dirty, find the LRU object and flush
+ * its cache, then find again.
+ * NB what's here is not very accurate,
+ * we actually flush the object with the LRU chunk.
*/
- while (file_struct->top_level && !done) {
- tn = file_struct->top;
+ /* With locking we can't assume we can use entry zero,
+ * Set the_obj to a valid pointer for Coverity. */
+ the_obj = dev->cache[0].object;
+ usage = -1;
+ cache = NULL;
+ pushout = -1;
- hasData = 0;
- for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
- if (tn->internal[i])
- hasData++;
+ for (i = 0; i < dev->param.n_caches; i++) {
+ if (dev->cache[i].object &&
+ !dev->cache[i].locked &&
+ (dev->cache[i].last_use < usage ||
+ !cache)) {
+ usage = dev->cache[i].last_use;
+ the_obj = dev->cache[i].object;
+ cache = &dev->cache[i];
+ pushout = i;
}
+ }
- if (!hasData) {
- file_struct->top = tn->internal[0];
- file_struct->top_level--;
- yaffs_free_tnode(dev, tn);
- } else {
- done = 1;
- }
+ if (!cache || cache->dirty) {
+ /* Flush and try again */
+ yaffs_flush_file_cache(the_obj);
+ cache = yaffs_grab_chunk_worker(dev);
}
}
-
- return YAFFS_OK;
+ return cache;
}
-/*-------------------- End of File Structure functions.-------------------*/
-
-
-/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
-static yaffs_obj_t *yaffs_alloc_empty_obj(yaffs_dev_t *dev)
+/* Find a cached chunk */
+static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
+ int chunk_id)
{
- yaffs_obj_t *obj = yaffs_alloc_raw_obj(dev);
-
- if (obj) {
- dev->n_obj++;
+ struct yaffs_dev *dev = obj->my_dev;
+ int i;
- /* Now sweeten it up... */
+ if (dev->param.n_caches < 1)
+ return NULL;
- memset(obj, 0, sizeof(yaffs_obj_t));
- obj->being_created = 1;
+ for (i = 0; i < dev->param.n_caches; i++) {
+ if (dev->cache[i].object == obj &&
+ dev->cache[i].chunk_id == chunk_id) {
+ dev->cache_hits++;
- obj->my_dev = dev;
- obj->hdr_chunk = 0;
- obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
- YINIT_LIST_HEAD(&(obj->hard_links));
- YINIT_LIST_HEAD(&(obj->hash_link));
- YINIT_LIST_HEAD(&obj->siblings);
+ return &dev->cache[i];
+ }
+ }
+ return NULL;
+}
+/* Mark the chunk for the least recently used algorithym */
+static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
+ int is_write)
+{
+ int i;
- /* Now make the directory sane */
- if (dev->root_dir) {
- obj->parent = dev->root_dir;
- ylist_add(&(obj->siblings), &dev->root_dir->variant.dir_variant.children);
- }
+ if (dev->param.n_caches < 1)
+ return;
- /* Add it to the lost and found directory.
- * NB Can't put root or lostNFound in lostNFound so
- * check if lostNFound exists first
- */
- if (dev->lost_n_found)
- yaffs_add_obj_to_dir(dev->lost_n_found, obj);
+ if (dev->cache_last_use < 0 ||
+ dev->cache_last_use > 100000000) {
+ /* Reset the cache usages */
+ for (i = 1; i < dev->param.n_caches; i++)
+ dev->cache[i].last_use = 0;
- obj->being_created = 0;
+ dev->cache_last_use = 0;
}
+ dev->cache_last_use++;
+ cache->last_use = dev->cache_last_use;
- dev->checkpoint_blocks_required = 0; /* force recalculation*/
-
- return obj;
+ if (is_write)
+ cache->dirty = 1;
}
-static yaffs_obj_t *yaffs_create_fake_dir(yaffs_dev_t *dev, int number,
- __u32 mode)
+/* Invalidate a single cache page.
+ * Do this when a whole page gets written,
+ * ie the short cache for this page is no longer valid.
+ */
+static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
{
+ struct yaffs_cache *cache;
- yaffs_obj_t *obj =
- yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
- if (obj) {
- obj->fake = 1; /* it is fake so it might have no NAND presence... */
- obj->rename_allowed = 0; /* ... and we're not allowed to rename it... */
- obj->unlink_allowed = 0; /* ... or unlink it */
- obj->deleted = 0;
- obj->unlinked = 0;
- obj->yst_mode = mode;
- obj->my_dev = dev;
- obj->hdr_chunk = 0; /* Not a valid chunk. */
+ if (object->my_dev->param.n_caches > 0) {
+ cache = yaffs_find_chunk_cache(object, chunk_id);
+
+ if (cache)
+ cache->object = NULL;
}
+}
- return obj;
+/* Invalidate all the cache pages associated with this object
+ * Do this whenever ther file is deleted or resized.
+ */
+static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
+{
+ int i;
+ struct yaffs_dev *dev = in->my_dev;
+ if (dev->param.n_caches > 0) {
+ /* Invalidate it. */
+ for (i = 0; i < dev->param.n_caches; i++) {
+ if (dev->cache[i].object == in)
+ dev->cache[i].object = NULL;
+ }
+ }
}
-static void yaffs_unhash_obj(yaffs_obj_t *obj)
+static void yaffs_unhash_obj(struct yaffs_obj *obj)
{
int bucket;
- yaffs_dev_t *dev = obj->my_dev;
+ struct yaffs_dev *dev = obj->my_dev;
/* If it is still linked into the bucket list, free from the list */
- if (!ylist_empty(&obj->hash_link)) {
- ylist_del_init(&obj->hash_link);
+ if (!list_empty(&obj->hash_link)) {
+ list_del_init(&obj->hash_link);
bucket = yaffs_hash_fn(obj->obj_id);
dev->obj_bucket[bucket].count--;
}
}
/* FreeObject frees up a Object and puts it back on the free list */
-static void yaffs_free_obj(yaffs_obj_t *obj)
+static void yaffs_free_obj(struct yaffs_obj *obj)
{
- yaffs_dev_t *dev = obj->my_dev;
-
- T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->my_inode));
+ struct yaffs_dev *dev;
- if (!obj)
- YBUG();
+ if (!obj) {
+ BUG();
+ return;
+ }
+ dev = obj->my_dev;
+ yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",
+ obj, obj->my_inode);
if (obj->parent)
- YBUG();
- if (!ylist_empty(&obj->siblings))
- YBUG();
-
+ BUG();
+ if (!list_empty(&obj->siblings))
+ BUG();
if (obj->my_inode) {
/* We're still hooked up to a cached inode.
yaffs_unhash_obj(obj);
- yaffs_free_raw_obj(dev,obj);
+ yaffs_free_raw_obj(dev, obj);
dev->n_obj--;
- dev->checkpoint_blocks_required = 0; /* force recalculation*/
+ dev->checkpoint_blocks_required = 0; /* force recalculation */
}
-
-void yaffs_handle_defered_free(yaffs_obj_t *obj)
+void yaffs_handle_defered_free(struct yaffs_obj *obj)
{
if (obj->defered_free)
yaffs_free_obj(obj);
}
-static void yaffs_init_tnodes_and_objs(yaffs_dev_t *dev)
+static int yaffs_generic_obj_del(struct yaffs_obj *in)
+{
+ /* Iinvalidate the file's data in the cache, without flushing. */
+ yaffs_invalidate_whole_cache(in);
+
+ if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {
+ /* Move to unlinked directory so we have a deletion record */
+ yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
+ 0);
+ }
+
+ yaffs_remove_obj_from_dir(in);
+ yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
+ in->hdr_chunk = 0;
+
+ yaffs_free_obj(in);
+ return YAFFS_OK;
+
+}
+
+static void yaffs_soft_del_file(struct yaffs_obj *obj)
+{
+ if (!obj->deleted ||
+ obj->variant_type != YAFFS_OBJECT_TYPE_FILE ||
+ obj->soft_del)
+ return;
+
+ if (obj->n_data_chunks <= 0) {
+ /* Empty file with no duplicate object headers,
+ * just delete it immediately */
+ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
+ obj->variant.file_variant.top = NULL;
+ yaffs_trace(YAFFS_TRACE_TRACING,
+ "yaffs: Deleting empty file %d",
+ obj->obj_id);
+ yaffs_generic_obj_del(obj);
+ } else {
+ yaffs_soft_del_worker(obj,
+ obj->variant.file_variant.top,
+ obj->variant.
+ file_variant.top_level, 0);
+ obj->soft_del = 1;
+ }
+}
+
+/* Pruning removes any part of the file structure tree that is beyond the
+ * bounds of the file (ie that does not point to chunks).
+ *
+ * A file should only get pruned when its size is reduced.
+ *
+ * Before pruning, the chunks must be pulled from the tree and the
+ * level 0 tnode entries must be zeroed out.
+ * Could also use this for file deletion, but that's probably better handled
+ * by a special case.
+ *
+ * This function is recursive. For levels > 0 the function is called again on
+ * any sub-tree. For level == 0 we just check if the sub-tree has data.
+ * If there is no data in a subtree then it is pruned.
+ */
+
+static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
+ struct yaffs_tnode *tn, u32 level,
+ int del0)
+{
+ int i;
+ int has_data;
+
+ if (!tn)
+ return tn;
+
+ has_data = 0;
+
+ if (level > 0) {
+ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
+ if (tn->internal[i]) {
+ tn->internal[i] =
+ yaffs_prune_worker(dev,
+ tn->internal[i],
+ level - 1,
+ (i == 0) ? del0 : 1);
+ }
+
+ if (tn->internal[i])
+ has_data++;
+ }
+ } else {
+ int tnode_size_u32 = dev->tnode_size / sizeof(u32);
+ u32 *map = (u32 *) tn;
+
+ for (i = 0; !has_data && i < tnode_size_u32; i++) {
+ if (map[i])
+ has_data++;
+ }
+ }
+
+ if (has_data == 0 && del0) {
+ /* Free and return NULL */
+ yaffs_free_tnode(dev, tn);
+ tn = NULL;
+ }
+ return tn;
+}
+
+static int yaffs_prune_tree(struct yaffs_dev *dev,
+ struct yaffs_file_var *file_struct)
{
int i;
+ int has_data;
+ int done = 0;
+ struct yaffs_tnode *tn;
- dev->n_obj = 0;
- dev->n_tnodes = 0;
+ if (file_struct->top_level < 1)
+ return YAFFS_OK;
- yaffs_init_raw_tnodes_and_objs(dev);
+ file_struct->top =
+ yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
- for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
- YINIT_LIST_HEAD(&dev->obj_bucket[i].list);
- dev->obj_bucket[i].count = 0;
+ /* Now we have a tree with all the non-zero branches NULL but
+ * the height is the same as it was.
+ * Let's see if we can trim internal tnodes to shorten the tree.
+ * We can do this if only the 0th element in the tnode is in use
+ * (ie all the non-zero are NULL)
+ */
+
+ while (file_struct->top_level && !done) {
+ tn = file_struct->top;
+
+ has_data = 0;
+ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
+ if (tn->internal[i])
+ has_data++;
+ }
+
+ if (!has_data) {
+ file_struct->top = tn->internal[0];
+ file_struct->top_level--;
+ yaffs_free_tnode(dev, tn);
+ } else {
+ done = 1;
+ }
}
+
+ return YAFFS_OK;
}
-static int yaffs_find_nice_bucket(yaffs_dev_t *dev)
+/*-------------------- End of File Structure functions.-------------------*/
+
+/* alloc_empty_obj gets us a clean Object.*/
+static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
+{
+ struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
+
+ if (!obj)
+ return obj;
+
+ dev->n_obj++;
+
+ /* Now sweeten it up... */
+
+ memset(obj, 0, sizeof(struct yaffs_obj));
+ obj->being_created = 1;
+
+ obj->my_dev = dev;
+ obj->hdr_chunk = 0;
+ obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
+ INIT_LIST_HEAD(&(obj->hard_links));
+ INIT_LIST_HEAD(&(obj->hash_link));
+ INIT_LIST_HEAD(&obj->siblings);
+
+ /* Now make the directory sane */
+ if (dev->root_dir) {
+ obj->parent = dev->root_dir;
+ list_add(&(obj->siblings),
+ &dev->root_dir->variant.dir_variant.children);
+ }
+
+ /* Add it to the lost and found directory.
+ * NB Can't put root or lost-n-found in lost-n-found so
+ * check if lost-n-found exists first
+ */
+ if (dev->lost_n_found)
+ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
+
+ obj->being_created = 0;
+
+ dev->checkpoint_blocks_required = 0; /* force recalculation */
+
+ return obj;
+}
+
+static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
{
int i;
int l = 999;
int lowest = 999999;
-
/* Search for the shortest list or one that
* isn't too long.
*/
lowest = dev->obj_bucket[dev->bucket_finder].count;
l = dev->bucket_finder;
}
-
}
return l;
}
-static int yaffs_new_obj_id(yaffs_dev_t *dev)
+static int yaffs_new_obj_id(struct yaffs_dev *dev)
{
int bucket = yaffs_find_nice_bucket(dev);
+ int found = 0;
+ struct list_head *i;
+ u32 n = (u32) bucket;
/* Now find an object value that has not already been taken
* by scanning the list.
*/
- int found = 0;
- struct ylist_head *i;
-
- __u32 n = (__u32) bucket;
-
- /* yaffs_check_obj_hash_sane(); */
-
while (!found) {
found = 1;
n += YAFFS_NOBJECT_BUCKETS;
if (1 || dev->obj_bucket[bucket].count > 0) {
- ylist_for_each(i, &dev->obj_bucket[bucket].list) {
+ list_for_each(i, &dev->obj_bucket[bucket].list) {
/* If there is already one in the list */
- if (i && ylist_entry(i, yaffs_obj_t,
- hash_link)->obj_id == n) {
+ if (i && list_entry(i, struct yaffs_obj,
+ hash_link)->obj_id == n) {
found = 0;
}
}
}
}
-
return n;
}
-static void yaffs_hash_obj(yaffs_obj_t *in)
+static void yaffs_hash_obj(struct yaffs_obj *in)
{
int bucket = yaffs_hash_fn(in->obj_id);
- yaffs_dev_t *dev = in->my_dev;
+ struct yaffs_dev *dev = in->my_dev;
- ylist_add(&in->hash_link, &dev->obj_bucket[bucket].list);
+ list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
dev->obj_bucket[bucket].count++;
}
-yaffs_obj_t *yaffs_find_by_number(yaffs_dev_t *dev, __u32 number)
+struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
{
int bucket = yaffs_hash_fn(number);
- struct ylist_head *i;
- yaffs_obj_t *in;
+ struct list_head *i;
+ struct yaffs_obj *in;
- ylist_for_each(i, &dev->obj_bucket[bucket].list) {
+ list_for_each(i, &dev->obj_bucket[bucket].list) {
/* Look if it is in the list */
- if (i) {
- in = ylist_entry(i, yaffs_obj_t, hash_link);
- if (in->obj_id == number) {
-
- /* Don't tell the VFS about this one if it is defered free */
- if (in->defered_free)
- return NULL;
-
- return in;
- }
+ in = list_entry(i, struct yaffs_obj, hash_link);
+ if (in->obj_id == number) {
+ /* Don't show if it is defered free */
+ if (in->defered_free)
+ return NULL;
+ return in;
}
}
return NULL;
}
-yaffs_obj_t *yaffs_new_obj(yaffs_dev_t *dev, int number,
- yaffs_obj_type type)
+static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
+ enum yaffs_obj_type type)
{
- yaffs_obj_t *theObject=NULL;
- yaffs_tnode_t *tn = NULL;
+ struct yaffs_obj *the_obj = NULL;
+ struct yaffs_tnode *tn = NULL;
if (number < 0)
number = yaffs_new_obj_id(dev);
return NULL;
}
- theObject = yaffs_alloc_empty_obj(dev);
- if (!theObject){
- if(tn)
- yaffs_free_tnode(dev,tn);
+ the_obj = yaffs_alloc_empty_obj(dev);
+ if (!the_obj) {
+ if (tn)
+ yaffs_free_tnode(dev, tn);
return NULL;
}
+ the_obj->fake = 0;
+ the_obj->rename_allowed = 1;
+ the_obj->unlink_allowed = 1;
+ the_obj->obj_id = number;
+ yaffs_hash_obj(the_obj);
+ the_obj->variant_type = type;
+ yaffs_load_current_time(the_obj, 1, 1);
- if (theObject) {
- theObject->fake = 0;
- theObject->rename_allowed = 1;
- theObject->unlink_allowed = 1;
- theObject->obj_id = number;
- yaffs_hash_obj(theObject);
- theObject->variant_type = type;
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_win_file_time_now(theObject->win_atime);
- theObject->win_ctime[0] = theObject->win_mtime[0] =
- theObject->win_atime[0];
- theObject->win_ctime[1] = theObject->win_mtime[1] =
- theObject->win_atime[1];
+ switch (type) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ the_obj->variant.file_variant.file_size = 0;
+ the_obj->variant.file_variant.scanned_size = 0;
+ the_obj->variant.file_variant.shrink_size =
+ yaffs_max_file_size(dev);
+ the_obj->variant.file_variant.top_level = 0;
+ the_obj->variant.file_variant.top = tn;
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
+ INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* No action required */
+ break;
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* todo this should not happen */
+ break;
+ }
+ return the_obj;
+}
-#else
+static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
+ int number, u32 mode)
+{
- theObject->yst_atime = theObject->yst_mtime =
- theObject->yst_ctime = Y_CURRENT_TIME;
-#endif
- switch (type) {
- case YAFFS_OBJECT_TYPE_FILE:
- theObject->variant.file_variant.file_size = 0;
- theObject->variant.file_variant.scanned_size = 0;
- theObject->variant.file_variant.shrink_size = 0xFFFFFFFF; /* max __u32 */
- theObject->variant.file_variant.top_level = 0;
- theObject->variant.file_variant.top = tn;
- break;
- case YAFFS_OBJECT_TYPE_DIRECTORY:
- YINIT_LIST_HEAD(&theObject->variant.dir_variant.
- children);
- YINIT_LIST_HEAD(&theObject->variant.dir_variant.
- dirty);
- break;
- case YAFFS_OBJECT_TYPE_SYMLINK:
- case YAFFS_OBJECT_TYPE_HARDLINK:
- case YAFFS_OBJECT_TYPE_SPECIAL:
- /* No action required */
- break;
- case YAFFS_OBJECT_TYPE_UNKNOWN:
- /* todo this should not happen */
- break;
- }
- }
+ struct yaffs_obj *obj =
+ yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
+
+ if (!obj)
+ return NULL;
+
+ obj->fake = 1; /* it is fake so it might not use NAND */
+ obj->rename_allowed = 0;
+ obj->unlink_allowed = 0;
+ obj->deleted = 0;
+ obj->unlinked = 0;
+ obj->yst_mode = mode;
+ obj->my_dev = dev;
+ obj->hdr_chunk = 0; /* Not a valid chunk. */
+ return obj;
+
+}
+
+
+static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
+{
+ int i;
+
+ dev->n_obj = 0;
+ dev->n_tnodes = 0;
+ yaffs_init_raw_tnodes_and_objs(dev);
- return theObject;
+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+ INIT_LIST_HEAD(&dev->obj_bucket[i].list);
+ dev->obj_bucket[i].count = 0;
+ }
}
-yaffs_obj_t *yaffs_find_or_create_by_number(yaffs_dev_t *dev,
- int number,
- yaffs_obj_type type)
+struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
+ int number,
+ enum yaffs_obj_type type)
{
- yaffs_obj_t *theObject = NULL;
+ struct yaffs_obj *the_obj = NULL;
if (number > 0)
- theObject = yaffs_find_by_number(dev, number);
+ the_obj = yaffs_find_by_number(dev, number);
- if (!theObject)
- theObject = yaffs_new_obj(dev, number, type);
+ if (!the_obj)
+ the_obj = yaffs_new_obj(dev, number, type);
- return theObject;
+ return the_obj;
}
-
YCHAR *yaffs_clone_str(const YCHAR *str)
{
- YCHAR *newStr = NULL;
+ YCHAR *new_str = NULL;
int len;
if (!str)
str = _Y("");
- len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH);
- newStr = YMALLOC((len + 1) * sizeof(YCHAR));
- if (newStr){
- yaffs_strncpy(newStr, str,len);
- newStr[len] = 0;
+ len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
+ new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);
+ if (new_str) {
+ strncpy(new_str, str, len);
+ new_str[len] = 0;
+ }
+ return new_str;
+
+}
+/*
+ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
+ * link (ie. name) is created or deleted in the directory.
+ *
+ * ie.
+ * create dir/a : update dir's mtime/ctime
+ * rm dir/a: update dir's mtime/ctime
+ * modify dir/a: don't update dir's mtimme/ctime
+ *
+ * This can be handled immediately or defered. Defering helps reduce the number
+ * of updates when many files in a directory are changed within a brief period.
+ *
+ * If the directory updating is defered then yaffs_update_dirty_dirs must be
+ * called periodically.
+ */
+
+static void yaffs_update_parent(struct yaffs_obj *obj)
+{
+ struct yaffs_dev *dev;
+
+ if (!obj)
+ return;
+ dev = obj->my_dev;
+ obj->dirty = 1;
+ yaffs_load_current_time(obj, 0, 1);
+ if (dev->param.defered_dir_update) {
+ struct list_head *link = &obj->variant.dir_variant.dirty;
+
+ if (list_empty(link)) {
+ list_add(link, &dev->dirty_dirs);
+ yaffs_trace(YAFFS_TRACE_BACKGROUND,
+ "Added object %d to dirty directories",
+ obj->obj_id);
+ }
+
+ } else {
+ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
}
- return newStr;
+}
+
+void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
+{
+ struct list_head *link;
+ struct yaffs_obj *obj;
+ struct yaffs_dir_var *d_s;
+ union yaffs_obj_var *o_v;
+
+ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");
+ while (!list_empty(&dev->dirty_dirs)) {
+ link = dev->dirty_dirs.next;
+ list_del_init(link);
+
+ d_s = list_entry(link, struct yaffs_dir_var, dirty);
+ o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
+ obj = list_entry(o_v, struct yaffs_obj, variant);
+
+ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",
+ obj->obj_id);
+
+ if (obj->dirty)
+ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
+ }
}
/*
* Mknod (create) a new object.
* equiv_obj only has meaning for a hard link;
- * aliasString only has meaning for a symlink.
+ * alias_str only has meaning for a symlink.
* rdev only has meaning for devices (a subset of special objects)
*/
-static yaffs_obj_t *yaffs_create_obj(yaffs_obj_type type,
- yaffs_obj_t *parent,
- const YCHAR *name,
- __u32 mode,
- __u32 uid,
- __u32 gid,
- yaffs_obj_t *equiv_obj,
- const YCHAR *aliasString, __u32 rdev)
+static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
+ struct yaffs_obj *parent,
+ const YCHAR *name,
+ u32 mode,
+ u32 uid,
+ u32 gid,
+ struct yaffs_obj *equiv_obj,
+ const YCHAR *alias_str, u32 rdev)
{
- yaffs_obj_t *in;
+ struct yaffs_obj *in;
YCHAR *str = NULL;
+ struct yaffs_dev *dev = parent->my_dev;
- yaffs_dev_t *dev = parent->my_dev;
-
- /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
+ /* Check if the entry exists.
+ * If it does then fail the call since we don't want a dup. */
if (yaffs_find_by_name(parent, name))
return NULL;
if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
- str = yaffs_clone_str(aliasString);
+ str = yaffs_clone_str(alias_str);
if (!str)
return NULL;
}
in = yaffs_new_obj(dev, -1, type);
- if (!in){
- if(str)
- YFREE(str);
+ if (!in) {
+ kfree(str);
return NULL;
}
+ in->hdr_chunk = 0;
+ in->valid = 1;
+ in->variant_type = type;
+ in->yst_mode = mode;
+ yaffs_attribs_init(in, gid, uid, rdev);
+ in->n_data_chunks = 0;
- if (in) {
- in->hdr_chunk = 0;
- in->valid = 1;
- in->variant_type = type;
-
- in->yst_mode = mode;
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_win_file_time_now(in->win_atime);
- in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
- in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
-
-#else
- in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
-
- in->yst_rdev = rdev;
- in->yst_uid = uid;
- in->yst_gid = gid;
-#endif
- in->n_data_chunks = 0;
-
- yaffs_set_obj_name(in, name);
- in->dirty = 1;
+ yaffs_set_obj_name(in, name);
+ in->dirty = 1;
- yaffs_add_obj_to_dir(parent, in);
+ yaffs_add_obj_to_dir(parent, in);
- in->my_dev = parent->my_dev;
+ in->my_dev = parent->my_dev;
- switch (type) {
- case YAFFS_OBJECT_TYPE_SYMLINK:
- in->variant.symlink_variant.alias = str;
- break;
- case YAFFS_OBJECT_TYPE_HARDLINK:
- in->variant.hardlink_variant.equiv_obj =
- equiv_obj;
- in->variant.hardlink_variant.equiv_id =
- equiv_obj->obj_id;
- ylist_add(&in->hard_links, &equiv_obj->hard_links);
- break;
- case YAFFS_OBJECT_TYPE_FILE:
- case YAFFS_OBJECT_TYPE_DIRECTORY:
- case YAFFS_OBJECT_TYPE_SPECIAL:
- case YAFFS_OBJECT_TYPE_UNKNOWN:
- /* do nothing */
- break;
- }
+ switch (type) {
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ in->variant.symlink_variant.alias = str;
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ in->variant.hardlink_variant.equiv_obj = equiv_obj;
+ in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id;
+ list_add(&in->hard_links, &equiv_obj->hard_links);
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* do nothing */
+ break;
+ }
- if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
- /* Could not create the object header, fail the creation */
- yaffs_del_obj(in);
- in = NULL;
- }
+ if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
+ /* Could not create the object header, fail */
+ yaffs_del_obj(in);
+ in = NULL;
+ }
+ if (in)
yaffs_update_parent(parent);
- }
return in;
}
-yaffs_obj_t *yaffs_create_file(yaffs_obj_t *parent, const YCHAR *name,
- __u32 mode, __u32 uid, __u32 gid)
+struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
+ const YCHAR *name, u32 mode, u32 uid,
+ u32 gid)
{
return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
uid, gid, NULL, NULL, 0);
}
-yaffs_obj_t *yaffs_create_dir(yaffs_obj_t *parent, const YCHAR *name,
- __u32 mode, __u32 uid, __u32 gid)
+struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
+ u32 mode, u32 uid, u32 gid)
{
return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
- mode, uid, gid, NULL, NULL, 0);
+ mode, uid, gid, NULL, NULL, 0);
}
-yaffs_obj_t *yaffs_create_special(yaffs_obj_t *parent, const YCHAR *name,
- __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
+struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
+ const YCHAR *name, u32 mode, u32 uid,
+ u32 gid, u32 rdev)
{
return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
- uid, gid, NULL, NULL, rdev);
+ uid, gid, NULL, NULL, rdev);
}
-yaffs_obj_t *yaffs_create_symlink(yaffs_obj_t *parent, const YCHAR *name,
- __u32 mode, __u32 uid, __u32 gid,
- const YCHAR *alias)
+struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
+ const YCHAR *name, u32 mode, u32 uid,
+ u32 gid, const YCHAR *alias)
{
return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
uid, gid, NULL, alias, 0);
}
/* yaffs_link_obj returns the object id of the equivalent object.*/
-yaffs_obj_t *yaffs_link_obj(yaffs_obj_t *parent, const YCHAR *name,
- yaffs_obj_t *equiv_obj)
+struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
+ struct yaffs_obj *equiv_obj)
{
- /* Get the real object in case we were fed a hard link as an equivalent object */
+ /* Get the real object in case we were fed a hard link obj */
equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
- if (yaffs_create_obj
- (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
- equiv_obj, NULL, 0)) {
+ if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK,
+ parent, name, 0, 0, 0,
+ equiv_obj, NULL, 0))
return equiv_obj;
- } else {
- return NULL;
- }
-
-}
-
-static int yaffs_change_obj_name(yaffs_obj_t *obj, yaffs_obj_t *new_dir,
- const YCHAR *new_name, int force, int shadows)
-{
- int unlinkOp;
- int deleteOp;
-
- yaffs_obj_t *existingTarget;
-
- if (new_dir == NULL)
- new_dir = obj->parent; /* use the old directory */
-
- if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR
- ("tragedy: yaffs_change_obj_name: new_dir is not a directory"
- TENDSTR)));
- 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);
-
- deleteOp = (new_dir == obj->my_dev->del_dir);
- existingTarget = yaffs_find_by_name(new_dir, new_name);
-
- /* If the object is a file going into the unlinked directory,
- * then it is OK to just stuff it in since duplicate names are allowed.
- * else only proceed if the new name does not exist and if we're putting
- * it into a directory.
- */
- if ((unlinkOp ||
- deleteOp ||
- force ||
- (shadows > 0) ||
- !existingTarget) &&
- new_dir->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
- yaffs_set_obj_name(obj, new_name);
- obj->dirty = 1;
-
- yaffs_add_obj_to_dir(new_dir, obj);
-
- if (unlinkOp)
- obj->unlinked = 1;
-
- /* If it is a deletion then we mark it as a shrink for gc purposes. */
- if (yaffs_update_oh(obj, new_name, 0, deleteOp, shadows, NULL) >= 0)
- return YAFFS_OK;
- }
+ return NULL;
- return YAFFS_FAIL;
}
-int yaffs_rename_obj(yaffs_obj_t *old_dir, const YCHAR *old_name,
- yaffs_obj_t *new_dir, const YCHAR *new_name)
-{
- yaffs_obj_t *obj = NULL;
- yaffs_obj_t *existingTarget = NULL;
- int force = 0;
- int result;
- yaffs_dev_t *dev;
-
-
- if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
- YBUG();
- if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
- YBUG();
-
- dev = old_dir->my_dev;
-
-#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
- /* Special case for case insemsitive systems (eg. WinCE).
- * While look-up is case insensitive, the name isn't.
- * Therefore we might want to change x.txt to X.txt
- */
- if (old_dir == new_dir && yaffs_strcmp(old_name, new_name) == 0)
- force = 1;
-#endif
-
- if(yaffs_strnlen(new_name,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH)
- /* ENAMETOOLONG */
- return YAFFS_FAIL;
- obj = yaffs_find_by_name(old_dir, old_name);
- if (obj && obj->rename_allowed) {
+/*---------------------- Block Management and Page Allocation -------------*/
- /* Now do the handling for an existing target, if there is one */
+static void yaffs_deinit_blocks(struct yaffs_dev *dev)
+{
+ if (dev->block_info_alt && dev->block_info)
+ vfree(dev->block_info);
+ else
+ kfree(dev->block_info);
- existingTarget = yaffs_find_by_name(new_dir, new_name);
- if (existingTarget &&
- existingTarget->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
- !ylist_empty(&existingTarget->variant.dir_variant.children)) {
- /* There is a target that is a non-empty directory, so we fail */
- return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
- } else if (existingTarget && existingTarget != obj) {
- /* Nuke the target first, using shadowing,
- * but only if it isn't the same object.
- *
- * Note we must disable gc otherwise it can mess up the shadowing.
- *
- */
- dev->gc_disable=1;
- yaffs_change_obj_name(obj, new_dir, new_name, force,
- existingTarget->obj_id);
- existingTarget->is_shadowed = 1;
- yaffs_unlink_obj(existingTarget);
- dev->gc_disable=0;
- }
+ dev->block_info_alt = 0;
- result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
+ dev->block_info = NULL;
- yaffs_update_parent(old_dir);
- if(new_dir != old_dir)
- yaffs_update_parent(new_dir);
-
- return result;
- }
- return YAFFS_FAIL;
+ if (dev->chunk_bits_alt && dev->chunk_bits)
+ vfree(dev->chunk_bits);
+ else
+ kfree(dev->chunk_bits);
+ dev->chunk_bits_alt = 0;
+ dev->chunk_bits = NULL;
}
-/*------------------------- Block Management and Page Allocation ----------------*/
-
-static int yaffs_init_blocks(yaffs_dev_t *dev)
+static int yaffs_init_blocks(struct yaffs_dev *dev)
{
- int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
+ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
dev->block_info = NULL;
dev->chunk_bits = NULL;
-
dev->alloc_block = -1; /* force it to get a new one */
/* If the first allocation strategy fails, thry the alternate one */
- dev->block_info = YMALLOC(nBlocks * sizeof(yaffs_block_info_t));
+ dev->block_info =
+ kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);
if (!dev->block_info) {
- dev->block_info = YMALLOC_ALT(nBlocks * sizeof(yaffs_block_info_t));
+ dev->block_info =
+ vmalloc(n_blocks * sizeof(struct yaffs_block_info));
dev->block_info_alt = 1;
- } else
+ } else {
dev->block_info_alt = 0;
-
- if (dev->block_info) {
- /* Set up dynamic blockinfo stuff. */
- dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8; /* round up bytes */
- dev->chunk_bits = YMALLOC(dev->chunk_bit_stride * nBlocks);
- if (!dev->chunk_bits) {
- dev->chunk_bits = YMALLOC_ALT(dev->chunk_bit_stride * nBlocks);
- dev->chunk_bits_alt = 1;
- } else
- dev->chunk_bits_alt = 0;
- }
-
- if (dev->block_info && dev->chunk_bits) {
- memset(dev->block_info, 0, nBlocks * sizeof(yaffs_block_info_t));
- memset(dev->chunk_bits, 0, dev->chunk_bit_stride * nBlocks);
- return YAFFS_OK;
}
- return YAFFS_FAIL;
-}
+ if (!dev->block_info)
+ goto alloc_error;
-static void yaffs_deinit_blocks(yaffs_dev_t *dev)
-{
- if (dev->block_info_alt && dev->block_info)
- YFREE_ALT(dev->block_info);
- else if (dev->block_info)
- YFREE(dev->block_info);
+ /* Set up dynamic blockinfo stuff. Round up bytes. */
+ dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
+ dev->chunk_bits =
+ kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);
+ if (!dev->chunk_bits) {
+ dev->chunk_bits =
+ vmalloc(dev->chunk_bit_stride * n_blocks);
+ dev->chunk_bits_alt = 1;
+ } else {
+ dev->chunk_bits_alt = 0;
+ }
+ if (!dev->chunk_bits)
+ goto alloc_error;
- dev->block_info_alt = 0;
- dev->block_info = NULL;
+ memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info));
+ memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
+ return YAFFS_OK;
- if (dev->chunk_bits_alt && dev->chunk_bits)
- YFREE_ALT(dev->chunk_bits);
- else if (dev->chunk_bits)
- YFREE(dev->chunk_bits);
- dev->chunk_bits_alt = 0;
- dev->chunk_bits = NULL;
+alloc_error:
+ yaffs_deinit_blocks(dev);
+ return YAFFS_FAIL;
}
-void yaffs_block_became_dirty(yaffs_dev_t *dev, int block_no)
-{
- yaffs_block_info_t *bi = yaffs_get_block_info(dev, block_no);
- int erasedOk = 0;
+void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
+{
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
+ int erased_ok = 0;
+ int i;
/* If the block is still healthy erase it and mark as clean.
* If the block has had a data failure, then retire it.
*/
- T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
- (TSTR("yaffs_block_became_dirty block %d state %d %s"TENDSTR),
- block_no, bi->block_state, (bi->needs_retiring) ? "needs retiring" : ""));
+ yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
+ "yaffs_block_became_dirty block %d state %d %s",
+ block_no, bi->block_state,
+ (bi->needs_retiring) ? "needs retiring" : "");
- yaffs2_clear_oldest_dirty_seq(dev,bi);
+ yaffs2_clear_oldest_dirty_seq(dev, bi);
bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
- /* If this is the block being garbage collected then stop gc'ing this block */
- if(block_no == dev->gc_block)
+ /* If this is the block being garbage collected then stop gc'ing */
+ if (block_no == dev->gc_block)
dev->gc_block = 0;
- /* If this block is currently the best candidate for gc then drop as a candidate */
- if(block_no == dev->gc_dirtiest){
+ /* If this block is currently the best candidate for gc
+ * then drop as a candidate */
+ if (block_no == dev->gc_dirtiest) {
dev->gc_dirtiest = 0;
dev->gc_pages_in_use = 0;
}
- if (!bi->needs_retiring) {
- yaffs2_checkpt_invalidate(dev);
- erasedOk = yaffs_erase_block(dev, block_no);
- if (!erasedOk) {
- dev->n_erase_failures++;
- T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
- (TSTR("**>> Erasure failed %d" TENDSTR), block_no));
- }
- }
-
- if (erasedOk &&
- ((yaffs_trace_mask & YAFFS_TRACE_ERASE) || !yaffs_skip_verification(dev))) {
- int i;
- for (i = 0; i < dev->param.chunks_per_block; i++) {
- if (!yaffs_check_chunk_erased
- (dev, block_no * dev->param.chunks_per_block + i)) {
- T(YAFFS_TRACE_ERROR,
- (TSTR
- (">>Block %d erasure supposedly OK, but chunk %d not erased"
- TENDSTR), block_no, i));
- }
- }
- }
-
- if (erasedOk) {
- /* Clean it up... */
- bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
- bi->seq_number = 0;
- dev->n_erased_blocks++;
- bi->pages_in_use = 0;
- bi->soft_del_pages = 0;
- bi->has_shrink_hdr = 0;
- bi->skip_erased_check = 1; /* This is clean, so no need to check */
- bi->gc_prioritise = 0;
- yaffs_clear_chunk_bits(dev, block_no);
-
- T(YAFFS_TRACE_ERASE,
- (TSTR("Erased block %d" TENDSTR), block_no));
- } else {
- dev->n_free_chunks -= dev->param.chunks_per_block; /* We lost a block of free space */
-
- yaffs_retire_block(dev, block_no);
- T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
- (TSTR("**>> Block %d retired" TENDSTR), block_no));
- }
-}
-
-static int yaffs_find_alloc_block(yaffs_dev_t *dev)
-{
- int i;
-
- yaffs_block_info_t *bi;
-
- if (dev->n_erased_blocks < 1) {
- /* Hoosterman we've got a problem.
- * Can't get space to gc
- */
- T(YAFFS_TRACE_ERROR,
- (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
-
- return -1;
- }
-
- /* Find an empty block. */
-
- for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
- dev->alloc_block_finder++;
- if (dev->alloc_block_finder < dev->internal_start_block
- || dev->alloc_block_finder > dev->internal_end_block) {
- dev->alloc_block_finder = dev->internal_start_block;
- }
-
- bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
-
- if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
- bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
- dev->seq_number++;
- bi->seq_number = dev->seq_number;
- dev->n_erased_blocks--;
- T(YAFFS_TRACE_ALLOCATE,
- (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
- dev->alloc_block_finder, dev->seq_number,
- dev->n_erased_blocks));
- return dev->alloc_block_finder;
- }
- }
-
- T(YAFFS_TRACE_ALWAYS,
- (TSTR
- ("yaffs tragedy: no more erased blocks, but there should have been %d"
- TENDSTR), dev->n_erased_blocks));
-
- return -1;
-}
-
-
-/*
- * Check if there's space to allocate...
- * Thinks.... do we need top make this ths same as yaffs_get_free_chunks()?
- */
-int yaffs_check_alloc_available(yaffs_dev_t *dev, int n_chunks)
-{
- int reservedChunks;
- int reservedBlocks = dev->param.n_reserved_blocks;
- int checkpointBlocks;
-
- checkpointBlocks = yaffs_calc_checkpt_blocks_required(dev);
-
- reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.chunks_per_block);
-
- return (dev->n_free_chunks > (reservedChunks + n_chunks));
-}
-
-static int yaffs_alloc_chunk(yaffs_dev_t *dev, int useReserve,
- yaffs_block_info_t **blockUsedPtr)
-{
- int retVal;
- yaffs_block_info_t *bi;
-
- if (dev->alloc_block < 0) {
- /* Get next block to allocate off */
- dev->alloc_block = yaffs_find_alloc_block(dev);
- dev->alloc_page = 0;
- }
-
- if (!useReserve && !yaffs_check_alloc_available(dev, 1)) {
- /* Not enough space to allocate unless we're allowed to use the reserve. */
- return -1;
- }
-
- if (dev->n_erased_blocks < dev->param.n_reserved_blocks
- && dev->alloc_page == 0) {
- T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
- }
-
- /* Next page please.... */
- if (dev->alloc_block >= 0) {
- bi = yaffs_get_block_info(dev, dev->alloc_block);
-
- retVal = (dev->alloc_block * dev->param.chunks_per_block) +
- dev->alloc_page;
- bi->pages_in_use++;
- yaffs_set_chunk_bit(dev, dev->alloc_block,
- dev->alloc_page);
-
- dev->alloc_page++;
-
- dev->n_free_chunks--;
-
- /* If the block is full set the state to full */
- if (dev->alloc_page >= dev->param.chunks_per_block) {
- bi->block_state = YAFFS_BLOCK_STATE_FULL;
- dev->alloc_block = -1;
+ if (!bi->needs_retiring) {
+ yaffs2_checkpt_invalidate(dev);
+ erased_ok = yaffs_erase_block(dev, block_no);
+ if (!erased_ok) {
+ dev->n_erase_failures++;
+ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+ "**>> Erasure failed %d", block_no);
}
+ }
- if (blockUsedPtr)
- *blockUsedPtr = bi;
+ /* Verify erasure if needed */
+ if (erased_ok &&
+ ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
+ !yaffs_skip_verification(dev))) {
+ for (i = 0; i < dev->param.chunks_per_block; i++) {
+ if (!yaffs_check_chunk_erased(dev,
+ block_no * dev->param.chunks_per_block + i)) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ ">>Block %d erasure supposedly OK, but chunk %d not erased",
+ block_no, i);
+ }
+ }
+ }
- return retVal;
+ if (!erased_ok) {
+ /* We lost a block of free space */
+ dev->n_free_chunks -= dev->param.chunks_per_block;
+ yaffs_retire_block(dev, block_no);
+ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+ "**>> Block %d retired", block_no);
+ return;
}
- T(YAFFS_TRACE_ERROR,
- (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
+ /* Clean it up... */
+ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
+ bi->seq_number = 0;
+ dev->n_erased_blocks++;
+ bi->pages_in_use = 0;
+ bi->soft_del_pages = 0;
+ bi->has_shrink_hdr = 0;
+ bi->skip_erased_check = 1; /* Clean, so no need to check */
+ bi->gc_prioritise = 0;
+ bi->has_summary = 0;
- return -1;
+ yaffs_clear_chunk_bits(dev, block_no);
+
+ yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no);
}
-static int yaffs_get_erased_chunks(yaffs_dev_t *dev)
+static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi,
+ int old_chunk, u8 *buffer)
{
- int n;
+ int new_chunk;
+ int mark_flash = 1;
+ struct yaffs_ext_tags tags;
+ struct yaffs_obj *object;
+ int matching_chunk;
+ int ret_val = YAFFS_OK;
- n = dev->n_erased_blocks * dev->param.chunks_per_block;
+ memset(&tags, 0, sizeof(tags));
+ yaffs_rd_chunk_tags_nand(dev, old_chunk,
+ buffer, &tags);
+ object = yaffs_find_by_number(dev, tags.obj_id);
- if (dev->alloc_block > 0)
- n += (dev->param.chunks_per_block - dev->alloc_page);
+ yaffs_trace(YAFFS_TRACE_GC_DETAIL,
+ "Collecting chunk in block %d, %d %d %d ",
+ dev->gc_chunk, tags.obj_id,
+ tags.chunk_id, tags.n_bytes);
- return n;
+ if (object && !yaffs_skip_verification(dev)) {
+ if (tags.chunk_id == 0)
+ matching_chunk =
+ object->hdr_chunk;
+ else if (object->soft_del)
+ /* Defeat the test */
+ matching_chunk = old_chunk;
+ else
+ matching_chunk =
+ yaffs_find_chunk_in_file
+ (object, tags.chunk_id,
+ NULL);
+
+ if (old_chunk != matching_chunk)
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "gc: page in gc mismatch: %d %d %d %d",
+ old_chunk,
+ matching_chunk,
+ tags.obj_id,
+ tags.chunk_id);
+ }
+
+ if (!object) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "page %d in gc has no object: %d %d %d ",
+ old_chunk,
+ tags.obj_id, tags.chunk_id,
+ tags.n_bytes);
+ }
+
+ if (object &&
+ object->deleted &&
+ object->soft_del && tags.chunk_id != 0) {
+ /* Data chunk in a soft deleted file,
+ * throw it away.
+ * It's a soft deleted data chunk,
+ * 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. We have to decrement free
+ * chunks so this works out properly.
+ */
+ dev->n_free_chunks--;
+ bi->soft_del_pages--;
-/*
- * yaffs_skip_rest_of_block() skips over the rest of the allocation block
- * if we don't want to write to it.
- */
-void yaffs_skip_rest_of_block(yaffs_dev_t *dev)
-{
- if(dev->alloc_block > 0){
- yaffs_block_info_t *bi = yaffs_get_block_info(dev, dev->alloc_block);
- if(bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING){
- bi->block_state = YAFFS_BLOCK_STATE_FULL;
- dev->alloc_block = -1;
+ object->n_data_chunks--;
+ if (object->n_data_chunks <= 0) {
+ /* remeber to clean up obj */
+ dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id;
+ dev->n_clean_ups++;
}
- }
-}
-
-
-static int yaffs_gc_block(yaffs_dev_t *dev, int block,
- int wholeBlock)
-{
- int oldChunk;
- int newChunk;
- int mark_flash;
- int retVal = YAFFS_OK;
- int i;
- int isCheckpointBlock;
- int matchingChunk;
- int maxCopies;
+ mark_flash = 0;
+ } else if (object) {
+ /* It's either a data chunk in a live
+ * file or an ObjectHeader, so we're
+ * interested in it.
+ * NB Need to keep the ObjectHeaders of
+ * deleted files until the whole file
+ * has been deleted off
+ */
+ tags.serial_number++;
+ dev->n_gc_copies++;
+
+ if (tags.chunk_id == 0) {
+ /* It is an object Id,
+ * We need to nuke the
+ * shrinkheader flags since its
+ * work is done.
+ * Also need to clean up
+ * shadowing.
+ */
+ struct yaffs_obj_hdr *oh;
+ oh = (struct yaffs_obj_hdr *) buffer;
+
+ oh->is_shrink = 0;
+ tags.extra_is_shrink = 0;
+ oh->shadows_obj = 0;
+ oh->inband_shadowed_obj_id = 0;
+ tags.extra_shadows = 0;
+
+ /* Update file size */
+ if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
+ yaffs_oh_size_load(oh,
+ object->variant.file_variant.file_size);
+ tags.extra_file_size =
+ object->variant.file_variant.file_size;
+ }
- int chunksBefore = yaffs_get_erased_chunks(dev);
- int chunksAfter;
+ yaffs_verify_oh(object, oh, &tags, 1);
+ new_chunk =
+ yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1);
+ } else {
+ new_chunk =
+ yaffs_write_new_chunk(dev, buffer, &tags, 1);
+ }
- yaffs_ext_tags tags;
+ if (new_chunk < 0) {
+ ret_val = YAFFS_FAIL;
+ } else {
- yaffs_block_info_t *bi = yaffs_get_block_info(dev, block);
+ /* Now fix up the Tnodes etc. */
- yaffs_obj_t *object;
+ if (tags.chunk_id == 0) {
+ /* It's a header */
+ object->hdr_chunk = new_chunk;
+ object->serial = tags.serial_number;
+ } else {
+ /* It's a data chunk */
+ yaffs_put_chunk_in_file(object, tags.chunk_id,
+ new_chunk, 0);
+ }
+ }
+ }
+ if (ret_val == YAFFS_OK)
+ yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__);
+ return ret_val;
+}
- isCheckpointBlock = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
+static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
+{
+ int old_chunk;
+ int ret_val = YAFFS_OK;
+ int i;
+ int is_checkpt_block;
+ int max_copies;
+ int chunks_before = yaffs_get_erased_chunks(dev);
+ int chunks_after;
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
+ is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
- T(YAFFS_TRACE_TRACING,
- (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
- block,
- bi->pages_in_use,
- bi->has_shrink_hdr,
- wholeBlock));
+ yaffs_trace(YAFFS_TRACE_TRACING,
+ "Collecting block %d, in use %d, shrink %d, whole_block %d",
+ block, bi->pages_in_use, bi->has_shrink_hdr,
+ whole_block);
/*yaffs_verify_free_chunks(dev); */
- if(bi->block_state == YAFFS_BLOCK_STATE_FULL)
+ 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;
- if (isCheckpointBlock ||
- !yaffs_still_some_chunks(dev, block)) {
- T(YAFFS_TRACE_TRACING,
- (TSTR
- ("Collecting block %d that has no chunks in use" TENDSTR),
- block));
+ yaffs_summary_gc(dev, block);
+
+ if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
+ yaffs_trace(YAFFS_TRACE_TRACING,
+ "Collecting block %d that has no chunks in use",
+ block);
yaffs_block_became_dirty(dev, block);
} else {
- __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
+ u8 *buffer = yaffs_get_temp_buffer(dev);
yaffs_verify_blk(dev, bi, block);
- maxCopies = (wholeBlock) ? dev->param.chunks_per_block : 5;
- oldChunk = block * dev->param.chunks_per_block + dev->gc_chunk;
+ max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
+ old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
- for (/* init already done */;
- retVal == YAFFS_OK &&
+ for (/* init already done */ ;
+ ret_val == YAFFS_OK &&
dev->gc_chunk < dev->param.chunks_per_block &&
(bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
- maxCopies > 0;
- dev->gc_chunk++, oldChunk++) {
+ max_copies > 0;
+ dev->gc_chunk++, old_chunk++) {
if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
-
- /* This page is in use and might need to be copied off */
-
- maxCopies--;
-
- mark_flash = 1;
-
- yaffs_init_tags(&tags);
-
- yaffs_rd_chunk_tags_nand(dev, oldChunk,
- buffer, &tags);
-
- object =
- yaffs_find_by_number(dev,
- tags.obj_id);
-
- T(YAFFS_TRACE_GC_DETAIL,
- (TSTR
- ("Collecting chunk in block %d, %d %d %d " TENDSTR),
- dev->gc_chunk, tags.obj_id, tags.chunk_id,
- tags.n_bytes));
-
- if (object && !yaffs_skip_verification(dev)) {
- if (tags.chunk_id == 0)
- matchingChunk = object->hdr_chunk;
- else if (object->soft_del)
- matchingChunk = oldChunk; /* Defeat the test */
- else
- matchingChunk = yaffs_find_chunk_in_file(object, tags.chunk_id, NULL);
-
- if (oldChunk != matchingChunk)
- T(YAFFS_TRACE_ERROR,
- (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
- oldChunk, matchingChunk, tags.obj_id, tags.chunk_id));
-
- }
-
- if (!object) {
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("page %d in gc has no object: %d %d %d "
- TENDSTR), oldChunk,
- tags.obj_id, tags.chunk_id, tags.n_bytes));
- }
-
- if (object &&
- object->deleted &&
- object->soft_del &&
- tags.chunk_id != 0) {
- /* Data chunk in a soft deleted file, throw it away
- * It's a soft deleted data chunk,
- * 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.
- * We have to decrement free chunks so this works out properly.
- */
- dev->n_free_chunks--;
- bi->soft_del_pages--;
-
- object->n_data_chunks--;
-
- if (object->n_data_chunks <= 0) {
- /* remeber to clean up the object */
- dev->gc_cleanup_list[dev->n_clean_ups] =
- tags.obj_id;
- dev->n_clean_ups++;
- }
- mark_flash = 0;
- } else if (0) {
- /* Todo object && object->deleted && object->n_data_chunks == 0 */
- /* Deleted object header with no data chunks.
- * Can be discarded and the file deleted.
- */
- object->hdr_chunk = 0;
- yaffs_free_tnode(object->my_dev,
- object->variant.
- file_variant.top);
- object->variant.file_variant.top = NULL;
- yaffs_generic_obj_del(object);
-
- } else if (object) {
- /* It's either a data chunk in a live file or
- * an ObjectHeader, so we're interested in it.
- * NB Need to keep the ObjectHeaders of deleted files
- * until the whole file has been deleted off
- */
- tags.serial_number++;
-
- dev->n_gc_copies++;
-
- if (tags.chunk_id == 0) {
- /* It is an object Id,
- * We need to nuke the shrinkheader flags first
- * Also need to clean up shadowing.
- * We no longer want the shrinkHeader flag since its work is done
- * and if it is left in place it will mess up scanning.
- */
-
- yaffs_obj_header *oh;
- oh = (yaffs_obj_header *)buffer;
-
- oh->is_shrink = 0;
- tags.extra_is_shrink = 0;
-
- oh->shadows_obj = 0;
- oh->inband_shadowed_obj_id = 0;
- tags.extra_shadows = 0;
-
- /* Update file size */
- if(object->variant_type == YAFFS_OBJECT_TYPE_FILE){
- oh->file_size = object->variant.file_variant.file_size;
- tags.extra_length = oh->file_size;
- }
-
- yaffs_verify_oh(object, oh, &tags, 1);
- newChunk =
- yaffs_write_new_chunk(dev,(__u8 *) oh, &tags, 1);
- } else
- newChunk =
- yaffs_write_new_chunk(dev, buffer, &tags, 1);
-
- if (newChunk < 0) {
- retVal = YAFFS_FAIL;
- } else {
-
- /* Ok, now fix up the Tnodes etc. */
-
- if (tags.chunk_id == 0) {
- /* It's a header */
- object->hdr_chunk = newChunk;
- object->serial = tags.serial_number;
- } else {
- /* It's a data chunk */
- int ok;
- ok = yaffs_put_chunk_in_file
- (object,
- tags.chunk_id,
- newChunk, 0);
- }
- }
- }
-
- if (retVal == YAFFS_OK)
- yaffs_chunk_del(dev, oldChunk, mark_flash, __LINE__);
-
+ /* Page is in use and might need to be copied */
+ max_copies--;
+ ret_val = yaffs_gc_process_chunk(dev, bi,
+ old_chunk, buffer);
}
}
-
- yaffs_release_temp_buffer(dev, buffer, __LINE__);
-
-
-
+ yaffs_release_temp_buffer(dev, buffer);
}
yaffs_verify_collected_blk(dev, bi, block);
-
-
if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
/*
* The gc did not complete. Set block state back to FULL
/* Do any required cleanups */
for (i = 0; i < dev->n_clean_ups; i++) {
/* Time to delete the file too */
- object =
- yaffs_find_by_number(dev,
- dev->gc_cleanup_list[i]);
+ struct yaffs_obj *object =
+ yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
if (object) {
yaffs_free_tnode(dev,
- object->variant.file_variant.
- top);
+ object->variant.file_variant.top);
object->variant.file_variant.top = NULL;
- T(YAFFS_TRACE_GC,
- (TSTR
- ("yaffs: About to finally delete object %d"
- TENDSTR), object->obj_id));
+ yaffs_trace(YAFFS_TRACE_GC,
+ "yaffs: About to finally delete object %d",
+ object->obj_id);
yaffs_generic_obj_del(object);
object->my_dev->n_deleted_files--;
}
}
-
-
- chunksAfter = yaffs_get_erased_chunks(dev);
- if (chunksBefore >= chunksAfter) {
- T(YAFFS_TRACE_GC,
- (TSTR
- ("gc did not increase free chunks before %d after %d"
- TENDSTR), chunksBefore, chunksAfter));
- }
+ chunks_after = yaffs_get_erased_chunks(dev);
+ if (chunks_before >= chunks_after)
+ yaffs_trace(YAFFS_TRACE_GC,
+ "gc did not increase free chunks before %d after %d",
+ chunks_before, chunks_after);
dev->gc_block = 0;
dev->gc_chunk = 0;
dev->n_clean_ups = 0;
dev->gc_disable = 0;
- return retVal;
+ return ret_val;
}
/*
- * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough)
+ * find_gc_block() selects the dirtiest block (or close enough)
* for garbage collection.
*/
-static unsigned yaffs_find_gc_block(yaffs_dev_t *dev,
- int aggressive,
- int background)
+static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
+ int aggressive, int background)
{
int i;
int iterations;
unsigned selected = 0;
int prioritised = 0;
- int prioritisedExists = 0;
- yaffs_block_info_t *bi;
+ int prioritised_exist = 0;
+ struct yaffs_block_info *bi;
int threshold;
/* First let's see if we need to grab a prioritised block */
dev->gc_dirtiest = 0;
bi = dev->block_info;
for (i = dev->internal_start_block;
- i <= dev->internal_end_block && !selected;
- i++) {
+ i <= dev->internal_end_block && !selected; i++) {
if (bi->gc_prioritise) {
- prioritisedExists = 1;
+ prioritised_exist = 1;
if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
- yaffs_block_ok_for_gc(dev, bi)) {
+ yaffs_block_ok_for_gc(dev, bi)) {
selected = i;
prioritised = 1;
}
/*
* If there is a prioritised block and none was selected then
- * this happened because there is at least one old dirty block gumming
- * up the works. Let's gc the oldest dirty block.
+ * this happened because there is at least one old dirty block
+ * gumming up the works. Let's gc the oldest dirty block.
*/
- if(prioritisedExists &&
- !selected &&
- dev->oldest_dirty_block > 0)
+ if (prioritised_exist &&
+ !selected && dev->oldest_dirty_block > 0)
selected = dev->oldest_dirty_block;
- if (!prioritisedExists) /* None found, so we can clear this */
+ if (!prioritised_exist) /* None found, so we can clear this */
dev->has_pending_prioritised_gc = 0;
}
- /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
- * search harder.
- * else (we're doing a leasurely gc), then we only bother to do this if the
+ /* If we're doing aggressive GC then we are happy to take a less-dirty
+ * block, and search harder.
+ * else (leasurely gc), then we only bother to do this if the
* block has only a few pages in use.
*/
- if (!selected){
- int pagesUsed;
- int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
- if (aggressive){
+ if (!selected) {
+ int pages_used;
+ int n_blocks =
+ dev->internal_end_block - dev->internal_start_block + 1;
+ if (aggressive) {
threshold = dev->param.chunks_per_block;
- iterations = nBlocks;
+ iterations = n_blocks;
} else {
- int maxThreshold;
+ int max_threshold;
- if(background)
- maxThreshold = dev->param.chunks_per_block/2;
+ if (background)
+ max_threshold = dev->param.chunks_per_block / 2;
else
- maxThreshold = dev->param.chunks_per_block/8;
+ max_threshold = dev->param.chunks_per_block / 8;
- if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD)
- maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD;
+ if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
+ max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
- threshold = background ?
- (dev->gc_not_done + 2) * 2 : 0;
- if(threshold <YAFFS_GC_PASSIVE_THRESHOLD)
+ threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
+ if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
threshold = YAFFS_GC_PASSIVE_THRESHOLD;
- if(threshold > maxThreshold)
- threshold = maxThreshold;
+ if (threshold > max_threshold)
+ threshold = max_threshold;
- iterations = nBlocks / 16 + 1;
+ iterations = n_blocks / 16 + 1;
if (iterations > 100)
iterations = 100;
}
for (i = 0;
- i < iterations &&
- (dev->gc_dirtiest < 1 ||
- dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
- i++) {
+ i < iterations &&
+ (dev->gc_dirtiest < 1 ||
+ dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
+ i++) {
dev->gc_block_finder++;
if (dev->gc_block_finder < dev->internal_start_block ||
- dev->gc_block_finder > dev->internal_end_block)
- dev->gc_block_finder = dev->internal_start_block;
+ dev->gc_block_finder > dev->internal_end_block)
+ dev->gc_block_finder =
+ dev->internal_start_block;
bi = yaffs_get_block_info(dev, dev->gc_block_finder);
- pagesUsed = bi->pages_in_use - bi->soft_del_pages;
+ pages_used = bi->pages_in_use - bi->soft_del_pages;
if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
- pagesUsed < dev->param.chunks_per_block &&
- (dev->gc_dirtiest < 1 || pagesUsed < dev->gc_pages_in_use) &&
- yaffs_block_ok_for_gc(dev, bi)) {
+ pages_used < dev->param.chunks_per_block &&
+ (dev->gc_dirtiest < 1 ||
+ pages_used < dev->gc_pages_in_use) &&
+ yaffs_block_ok_for_gc(dev, bi)) {
dev->gc_dirtiest = dev->gc_block_finder;
- dev->gc_pages_in_use = pagesUsed;
+ dev->gc_pages_in_use = pages_used;
}
}
- if(dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
+ if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
selected = dev->gc_dirtiest;
}
/*
- * If nothing has been selected for a while, try selecting the oldest dirty
+ * If nothing has been selected for a while, try the oldest dirty
* because that's gumming up the works.
*/
- if(!selected && dev->param.is_yaffs2 &&
- dev->gc_not_done >= ( background ? 10 : 20)){
+ if (!selected && dev->param.is_yaffs2 &&
+ dev->gc_not_done >= (background ? 10 : 20)) {
yaffs2_find_oldest_dirty_seq(dev);
- if(dev->oldest_dirty_block > 0) {
+ if (dev->oldest_dirty_block > 0) {
selected = dev->oldest_dirty_block;
dev->gc_dirtiest = selected;
dev->oldest_dirty_gc_count++;
bi = yaffs_get_block_info(dev, selected);
- dev->gc_pages_in_use = bi->pages_in_use - bi->soft_del_pages;
- } else
+ dev->gc_pages_in_use =
+ bi->pages_in_use - bi->soft_del_pages;
+ } else {
dev->gc_not_done = 0;
+ }
}
- if(selected){
- T(YAFFS_TRACE_GC,
- (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR),
- selected,
- dev->param.chunks_per_block - dev->gc_pages_in_use,
- prioritised));
+ if (selected) {
+ yaffs_trace(YAFFS_TRACE_GC,
+ "GC Selected block %d with %d free, prioritised:%d",
+ selected,
+ dev->param.chunks_per_block - dev->gc_pages_in_use,
+ prioritised);
dev->n_gc_blocks++;
- if(background)
+ if (background)
dev->bg_gcs++;
dev->gc_dirtiest = 0;
dev->gc_pages_in_use = 0;
dev->gc_not_done = 0;
- if(dev->refresh_skip > 0)
+ if (dev->refresh_skip > 0)
dev->refresh_skip--;
- } else{
+ } else {
dev->gc_not_done++;
- T(YAFFS_TRACE_GC,
- (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR),
- dev->gc_block_finder, dev->gc_not_done,
- threshold,
- dev->gc_dirtiest, dev->gc_pages_in_use,
- dev->oldest_dirty_block,
- background ? " bg" : ""));
+ yaffs_trace(YAFFS_TRACE_GC,
+ "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",
+ dev->gc_block_finder, dev->gc_not_done, threshold,
+ dev->gc_dirtiest, dev->gc_pages_in_use,
+ dev->oldest_dirty_block, background ? " bg" : "");
}
return selected;
* If we're very low on erased blocks then we do aggressive garbage collection
* otherwise we do "leasurely" garbage collection.
* Aggressive gc looks further (whole array) and will accept less dirty blocks.
- * Passive gc only inspects smaller areas and will only accept more dirty blocks.
+ * Passive gc only inspects smaller areas and only accepts more dirty blocks.
*
* The idea is to help clear out space in a more spread-out manner.
* Dunno if it really does anything useful.
*/
-static int yaffs_check_gc(yaffs_dev_t *dev, int background)
+static int yaffs_check_gc(struct yaffs_dev *dev, int background)
{
int aggressive = 0;
- int gcOk = YAFFS_OK;
- int maxTries = 0;
- int minErased;
- int erasedChunks;
- int checkpointBlockAdjust;
-
- if(dev->param.gc_control &&
- (dev->param.gc_control(dev) & 1) == 0)
+ int gc_ok = YAFFS_OK;
+ int max_tries = 0;
+ int min_erased;
+ int erased_chunks;
+ int checkpt_block_adjust;
+
+ if (dev->param.gc_control_fn &&
+ (dev->param.gc_control_fn(dev) & 1) == 0)
return YAFFS_OK;
- if (dev->gc_disable) {
+ if (dev->gc_disable)
/* Bail out so we don't get recursive gc */
return YAFFS_OK;
- }
/* This loop should pass the first time.
- * We'll only see looping here if the collection does not increase space.
+ * Only loops here if the collection does not increase space.
*/
do {
- maxTries++;
+ max_tries++;
- checkpointBlockAdjust = yaffs_calc_checkpt_blocks_required(dev);
+ checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
- minErased = dev->param.n_reserved_blocks + checkpointBlockAdjust + 1;
- erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
+ min_erased =
+ dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
+ erased_chunks =
+ dev->n_erased_blocks * dev->param.chunks_per_block;
- /* If we need a block soon then do aggressive gc.*/
- if (dev->n_erased_blocks < minErased)
+ /* If we need a block soon then do aggressive gc. */
+ if (dev->n_erased_blocks < min_erased)
aggressive = 1;
else {
- if(!background && erasedChunks > (dev->n_free_chunks / 4))
+ if (!background
+ && erased_chunks > (dev->n_free_chunks / 4))
break;
- if(dev->gc_skip > 20)
+ if (dev->gc_skip > 20)
dev->gc_skip = 20;
- if(erasedChunks < dev->n_free_chunks/2 ||
- dev->gc_skip < 1 ||
- background)
+ if (erased_chunks < dev->n_free_chunks / 2 ||
+ dev->gc_skip < 1 || background)
aggressive = 0;
else {
dev->gc_skip--;
dev->gc_skip = 5;
- /* If we don't already have a block being gc'd then see if we should start another */
+ /* If we don't already have a block being gc'd then see if we
+ * should start another */
if (dev->gc_block < 1 && !aggressive) {
dev->gc_block = yaffs2_find_refresh_block(dev);
dev->gc_chunk = 0;
- dev->n_clean_ups=0;
+ dev->n_clean_ups = 0;
}
if (dev->gc_block < 1) {
- dev->gc_block = yaffs_find_gc_block(dev, aggressive, background);
+ dev->gc_block =
+ yaffs_find_gc_block(dev, aggressive, background);
dev->gc_chunk = 0;
- dev->n_clean_ups=0;
+ dev->n_clean_ups = 0;
}
if (dev->gc_block > 0) {
if (!aggressive)
dev->passive_gc_count++;
- T(YAFFS_TRACE_GC,
- (TSTR
- ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
- dev->n_erased_blocks, aggressive));
+ yaffs_trace(YAFFS_TRACE_GC,
+ "yaffs: GC n_erased_blocks %d aggressive %d",
+ dev->n_erased_blocks, aggressive);
- gcOk = yaffs_gc_block(dev, dev->gc_block, aggressive);
+ gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
}
- if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) && dev->gc_block > 0) {
- T(YAFFS_TRACE_GC,
- (TSTR
- ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
- TENDSTR), dev->n_erased_blocks, maxTries, dev->gc_block));
+ if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&
+ dev->gc_block > 0) {
+ yaffs_trace(YAFFS_TRACE_GC,
+ "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
+ dev->n_erased_blocks, max_tries,
+ dev->gc_block);
}
} while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
- (dev->gc_block > 0) &&
- (maxTries < 2));
+ (dev->gc_block > 0) && (max_tries < 2));
- return aggressive ? gcOk : YAFFS_OK;
+ return aggressive ? gc_ok : YAFFS_OK;
}
/*
* Garbage collects. Intended to be called from a background thread.
* Returns non-zero if at least half the free chunks are erased.
*/
-int yaffs_bg_gc(yaffs_dev_t *dev, unsigned urgency)
+int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
{
- int erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
+ int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
- T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency));
+ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
yaffs_check_gc(dev, 1);
- return erasedChunks > dev->n_free_chunks/2;
-}
-
-/*------------------------- TAGS --------------------------------*/
-
-static int yaffs_tags_match(const yaffs_ext_tags *tags, int obj_id,
- int chunkInObject)
-{
- return (tags->chunk_id == chunkInObject &&
- tags->obj_id == obj_id && !tags->is_deleted) ? 1 : 0;
-
+ return erased_chunks > dev->n_free_chunks / 2;
}
-
/*-------------------- Data file manipulation -----------------*/
-static int yaffs_find_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
- yaffs_ext_tags *tags)
-{
- /*Get the Tnode, then get the level 0 offset chunk offset */
- yaffs_tnode_t *tn;
- int theChunk = -1;
- yaffs_ext_tags localTags;
- int retVal = -1;
-
- yaffs_dev_t *dev = in->my_dev;
-
- if (!tags) {
- /* Passed a NULL, so use our own tags space */
- tags = &localTags;
- }
-
- tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
-
- if (tn) {
- theChunk = yaffs_get_group_base(dev, tn, inode_chunk);
-
- retVal =
- yaffs_find_chunk_in_group(dev, theChunk, tags, in->obj_id,
- inode_chunk);
- }
- return retVal;
-}
-
-static int yaffs_find_del_file_chunk(yaffs_obj_t *in, int inode_chunk,
- yaffs_ext_tags *tags)
-{
- /* Get the Tnode, then get the level 0 offset chunk offset */
- yaffs_tnode_t *tn;
- int theChunk = -1;
- yaffs_ext_tags localTags;
-
- yaffs_dev_t *dev = in->my_dev;
- int retVal = -1;
-
- if (!tags) {
- /* Passed a NULL, so use our own tags space */
- tags = &localTags;
- }
-
- tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
-
- if (tn) {
-
- theChunk = yaffs_get_group_base(dev, tn, inode_chunk);
-
- retVal =
- yaffs_find_chunk_in_group(dev, theChunk, tags, in->obj_id,
- inode_chunk);
-
- /* Delete the entry in the filestructure (if found) */
- if (retVal != -1)
- yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
- }
-
- return retVal;
-}
-
-
-int yaffs_put_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
- int nand_chunk, int in_scan)
-{
- /* NB in_scan is zero unless scanning.
- * For forward scanning, in_scan is > 0;
- * for backward scanning in_scan is < 0
- *
- * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
- */
-
- yaffs_tnode_t *tn;
- yaffs_dev_t *dev = in->my_dev;
- int existingChunk;
- yaffs_ext_tags existingTags;
- yaffs_ext_tags newTags;
- unsigned existingSerial, newSerial;
-
- if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
- /* Just ignore an attempt at putting a chunk into a non-file during scanning
- * If it is not during Scanning then something went wrong!
- */
- if (!in_scan) {
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs tragedy:attempt to put data chunk into a non-file"
- TENDSTR)));
- YBUG();
- }
-
- yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
- return YAFFS_OK;
- }
-
- tn = yaffs_add_find_tnode_0(dev,
- &in->variant.file_variant,
- inode_chunk,
- NULL);
- if (!tn)
- return YAFFS_FAIL;
-
- if(!nand_chunk)
- /* Dummy insert, bail now */
- return YAFFS_OK;
-
- existingChunk = yaffs_get_group_base(dev, tn, inode_chunk);
-
- if (in_scan != 0) {
- /* If we're scanning then we need to test for duplicates
- * NB This does not need to be efficient since it should only ever
- * happen when the power fails during a write, then only one
- * chunk should ever be affected.
- *
- * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
- * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
- */
-
- if (existingChunk > 0) {
- /* NB Right now existing chunk will not be real chunk_id if the chunk group size > 1
- * thus we have to do a FindChunkInFile to get the real chunk id.
- *
- * We have a duplicate now we need to decide which one to use:
- *
- * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
- * Forward scanning YAFFS2: The new one is what we use, dump the old one.
- * YAFFS1: Get both sets of tags and compare serial numbers.
- */
-
- if (in_scan > 0) {
- /* Only do this for forward scanning */
- yaffs_rd_chunk_tags_nand(dev,
- nand_chunk,
- NULL, &newTags);
-
- /* Do a proper find */
- existingChunk =
- yaffs_find_chunk_in_file(in, inode_chunk,
- &existingTags);
- }
-
- if (existingChunk <= 0) {
- /*Hoosterman - how did this happen? */
-
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs tragedy: existing chunk < 0 in scan"
- TENDSTR)));
-
- }
-
- /* NB The deleted flags should be false, otherwise the chunks will
- * not be loaded during a scan
- */
-
- if (in_scan > 0) {
- newSerial = newTags.serial_number;
- existingSerial = existingTags.serial_number;
- }
-
- if ((in_scan > 0) &&
- (existingChunk <= 0 ||
- ((existingSerial + 1) & 3) == newSerial)) {
- /* Forward scanning.
- * Use new
- * Delete the old one and drop through to update the tnode
- */
- yaffs_chunk_del(dev, existingChunk, 1,
- __LINE__);
- } else {
- /* Backward scanning or we want to use the existing one
- * Use existing.
- * Delete the new one and return early so that the tnode isn't changed
- */
- yaffs_chunk_del(dev, nand_chunk, 1,
- __LINE__);
- return YAFFS_OK;
- }
- }
-
- }
-
- if (existingChunk == 0)
- in->n_data_chunks++;
-
- yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
-
- return YAFFS_OK;
-}
-
-static int yaffs_rd_data_obj(yaffs_obj_t *in, int inode_chunk,
- __u8 *buffer)
+static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
{
int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
buffer, NULL);
else {
- T(YAFFS_TRACE_NANDACCESS,
- (TSTR("Chunk %d not found zero instead" TENDSTR),
- nand_chunk));
+ yaffs_trace(YAFFS_TRACE_NANDACCESS,
+ "Chunk %d not found zero instead",
+ nand_chunk);
/* get sane (zero) data if you read a hole */
memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
return 0;
}
-void yaffs_chunk_del(yaffs_dev_t *dev, int chunk_id, int mark_flash, int lyn)
+void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
+ int lyn)
{
int block;
int page;
- yaffs_ext_tags tags;
- yaffs_block_info_t *bi;
+ struct yaffs_ext_tags tags;
+ struct yaffs_block_info *bi;
if (chunk_id <= 0)
return;
block = chunk_id / dev->param.chunks_per_block;
page = chunk_id % dev->param.chunks_per_block;
-
if (!yaffs_check_chunk_bit(dev, block, page))
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Deleting invalid chunk %d"TENDSTR),
- chunk_id));
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Deleting invalid chunk %d", chunk_id);
bi = yaffs_get_block_info(dev, block);
-
+
yaffs2_update_oldest_dirty_seq(dev, block, bi);
- T(YAFFS_TRACE_DELETION,
- (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunk_id));
+ yaffs_trace(YAFFS_TRACE_DELETION,
+ "line %d delete of chunk %d",
+ lyn, chunk_id);
if (!dev->param.is_yaffs2 && mark_flash &&
bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
- yaffs_init_tags(&tags);
-
+ memset(&tags, 0, sizeof(tags));
tags.is_deleted = 1;
-
yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
yaffs_handle_chunk_update(dev, chunk_id, &tags);
} else {
*/
if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
bi->block_state == YAFFS_BLOCK_STATE_FULL ||
- bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+ bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
dev->n_free_chunks++;
-
yaffs_clear_chunk_bit(dev, block, page);
-
bi->pages_in_use--;
if (bi->pages_in_use == 0 &&
!bi->has_shrink_hdr &&
bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
- bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+ bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {
yaffs_block_became_dirty(dev, block);
}
-
- }
-
-}
-
-static int yaffs_wr_data_obj(yaffs_obj_t *in, int inode_chunk,
- const __u8 *buffer, int n_bytes,
- int useReserve)
-{
- /* Find old chunk Need to do this to get serial number
- * Write new one and patch into tree.
- * Invalidate old tags.
- */
-
- int prevChunkId;
- yaffs_ext_tags prevTags;
-
- int newChunkId;
- yaffs_ext_tags newTags;
-
- yaffs_dev_t *dev = in->my_dev;
-
- yaffs_check_gc(dev,0);
-
- /* Get the previous chunk at this location in the file if it exists.
- * If it does not exist then put a zero into the tree. This creates
- * the tnode now, rather than later when it is harder to clean up.
- */
- prevChunkId = yaffs_find_chunk_in_file(in, inode_chunk, &prevTags);
- if(prevChunkId < 1 &&
- !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
- return 0;
-
- /* Set up new tags */
- yaffs_init_tags(&newTags);
-
- newTags.chunk_id = inode_chunk;
- newTags.obj_id = in->obj_id;
- newTags.serial_number =
- (prevChunkId > 0) ? prevTags.serial_number + 1 : 1;
- newTags.n_bytes = n_bytes;
-
- if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
- T(YAFFS_TRACE_ERROR,
- (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), n_bytes));
- YBUG();
- }
-
-
- newChunkId =
- yaffs_write_new_chunk(dev, buffer, &newTags,
- useReserve);
-
- if (newChunkId > 0) {
- yaffs_put_chunk_in_file(in, inode_chunk, newChunkId, 0);
-
- if (prevChunkId > 0)
- yaffs_chunk_del(dev, prevChunkId, 1, __LINE__);
-
- yaffs_verify_file_sane(in);
}
- return newChunkId;
-
}
-/* UpdateObjectHeader updates the header on NAND for an object.
- * If name is not NULL, then that new name is used.
- */
-int yaffs_update_oh(yaffs_obj_t *in, const YCHAR *name, int force,
- int is_shrink, int shadows, yaffs_xattr_mod *xmod)
+static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
+ const u8 *buffer, int n_bytes, int use_reserve)
{
+ /* Find old chunk Need to do this to get serial number
+ * Write new one and patch into tree.
+ * Invalidate old tags.
+ */
- yaffs_block_info_t *bi;
-
- yaffs_dev_t *dev = in->my_dev;
-
- int prevChunkId;
- int retVal = 0;
- int result = 0;
-
- int newChunkId;
- yaffs_ext_tags newTags;
- yaffs_ext_tags oldTags;
- const YCHAR *alias = NULL;
-
- __u8 *buffer = NULL;
- YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
-
- yaffs_obj_header *oh = NULL;
-
- yaffs_strcpy(old_name, _Y("silly old name"));
+ int prev_chunk_id;
+ struct yaffs_ext_tags prev_tags;
+ int new_chunk_id;
+ struct yaffs_ext_tags new_tags;
+ struct yaffs_dev *dev = in->my_dev;
+ yaffs_check_gc(dev, 0);
- if (!in->fake ||
- in == dev->root_dir || /* The root_dir should also be saved */
- force || xmod) {
+ /* Get the previous chunk at this location in the file if it exists.
+ * If it does not exist then put a zero into the tree. This creates
+ * the tnode now, rather than later when it is harder to clean up.
+ */
+ prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
+ if (prev_chunk_id < 1 &&
+ !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
+ return 0;
- yaffs_check_gc(dev,0);
- yaffs_check_obj_details_loaded(in);
+ /* Set up new tags */
+ memset(&new_tags, 0, sizeof(new_tags));
- buffer = yaffs_get_temp_buffer(in->my_dev, __LINE__);
- oh = (yaffs_obj_header *) buffer;
+ new_tags.chunk_id = inode_chunk;
+ new_tags.obj_id = in->obj_id;
+ new_tags.serial_number =
+ (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
+ new_tags.n_bytes = n_bytes;
- prevChunkId = in->hdr_chunk;
+ if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "Writing %d bytes to chunk!!!!!!!!!",
+ n_bytes);
+ BUG();
+ }
- if (prevChunkId > 0) {
- result = yaffs_rd_chunk_tags_nand(dev, prevChunkId,
- buffer, &oldTags);
+ new_chunk_id =
+ yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
- yaffs_verify_oh(in, oh, &oldTags, 0);
+ if (new_chunk_id > 0) {
+ yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
- memcpy(old_name, oh->name, sizeof(oh->name));
- memset(buffer, 0xFF, sizeof(yaffs_obj_header));
- } else
- memset(buffer, 0xFF, dev->data_bytes_per_chunk);
+ if (prev_chunk_id > 0)
+ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
- oh->type = in->variant_type;
- oh->yst_mode = in->yst_mode;
- oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
+ yaffs_verify_file_sane(in);
+ }
+ return new_chunk_id;
-#ifdef CONFIG_YAFFS_WINCE
- oh->win_atime[0] = in->win_atime[0];
- oh->win_ctime[0] = in->win_ctime[0];
- oh->win_mtime[0] = in->win_mtime[0];
- oh->win_atime[1] = in->win_atime[1];
- oh->win_ctime[1] = in->win_ctime[1];
- oh->win_mtime[1] = in->win_mtime[1];
-#else
- oh->yst_uid = in->yst_uid;
- oh->yst_gid = in->yst_gid;
- oh->yst_atime = in->yst_atime;
- oh->yst_mtime = in->yst_mtime;
- oh->yst_ctime = in->yst_ctime;
- oh->yst_rdev = in->yst_rdev;
-#endif
- if (in->parent)
- oh->parent_obj_id = in->parent->obj_id;
- else
- oh->parent_obj_id = 0;
+}
- if (name && *name) {
- memset(oh->name, 0, sizeof(oh->name));
- yaffs_load_oh_from_name(dev,oh->name,name);
- } else if (prevChunkId > 0)
- memcpy(oh->name, old_name, sizeof(oh->name));
- else
- memset(oh->name, 0, sizeof(oh->name));
- oh->is_shrink = is_shrink;
- switch (in->variant_type) {
- case YAFFS_OBJECT_TYPE_UNKNOWN:
- /* Should not happen */
- break;
- case YAFFS_OBJECT_TYPE_FILE:
- oh->file_size =
- (oh->parent_obj_id == YAFFS_OBJECTID_DELETED
- || oh->parent_obj_id ==
- YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
- file_variant.file_size;
- break;
- case YAFFS_OBJECT_TYPE_HARDLINK:
- oh->equiv_id =
- in->variant.hardlink_variant.equiv_id;
- break;
- case YAFFS_OBJECT_TYPE_SPECIAL:
- /* Do nothing */
- break;
- case YAFFS_OBJECT_TYPE_DIRECTORY:
- /* Do nothing */
- break;
- case YAFFS_OBJECT_TYPE_SYMLINK:
- alias = in->variant.symlink_variant.alias;
- if(!alias)
- alias = _Y("no alias");
- yaffs_strncpy(oh->alias,
- alias,
- YAFFS_MAX_ALIAS_LENGTH);
- oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
- break;
- }
+static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
+ const YCHAR *name, const void *value, int size,
+ int flags)
+{
+ struct yaffs_xattr_mod xmod;
+ int result;
- /* process any xattrib modifications */
- if(xmod)
- yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
+ xmod.set = set;
+ xmod.name = name;
+ xmod.data = value;
+ xmod.size = size;
+ xmod.flags = flags;
+ xmod.result = -ENOSPC;
+ result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
- /* Tags */
- yaffs_init_tags(&newTags);
- in->serial++;
- newTags.chunk_id = 0;
- newTags.obj_id = in->obj_id;
- newTags.serial_number = in->serial;
+ if (result > 0)
+ return xmod.result;
+ else
+ return -ENOSPC;
+}
- /* Add extra info for file header */
+static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
+ struct yaffs_xattr_mod *xmod)
+{
+ int retval = 0;
+ int x_offs = sizeof(struct yaffs_obj_hdr);
+ struct yaffs_dev *dev = obj->my_dev;
+ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
+ char *x_buffer = buffer + x_offs;
+
+ if (xmod->set)
+ retval =
+ nval_set(x_buffer, x_size, xmod->name, xmod->data,
+ xmod->size, xmod->flags);
+ else
+ retval = nval_del(x_buffer, x_size, xmod->name);
- newTags.extra_available = 1;
- newTags.extra_parent_id = oh->parent_obj_id;
- newTags.extra_length = oh->file_size;
- newTags.extra_is_shrink = oh->is_shrink;
- newTags.extra_equiv_id = oh->equiv_id;
- newTags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
- newTags.extra_obj_type = in->variant_type;
+ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
+ obj->xattr_known = 1;
+ xmod->result = retval;
- yaffs_verify_oh(in, oh, &newTags, 1);
+ return retval;
+}
- /* Create new chunk in NAND */
- newChunkId =
- yaffs_write_new_chunk(dev, buffer, &newTags,
- (prevChunkId > 0) ? 1 : 0);
+static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,
+ void *value, int size)
+{
+ char *buffer = NULL;
+ int result;
+ struct yaffs_ext_tags tags;
+ struct yaffs_dev *dev = obj->my_dev;
+ int x_offs = sizeof(struct yaffs_obj_hdr);
+ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
+ char *x_buffer;
+ int retval = 0;
- if (newChunkId >= 0) {
+ if (obj->hdr_chunk < 1)
+ return -ENODATA;
- in->hdr_chunk = newChunkId;
+ /* If we know that the object has no xattribs then don't do all the
+ * reading and parsing.
+ */
+ if (obj->xattr_known && !obj->has_xattr) {
+ if (name)
+ return -ENODATA;
+ else
+ return 0;
+ }
- if (prevChunkId > 0) {
- yaffs_chunk_del(dev, prevChunkId, 1,
- __LINE__);
- }
+ buffer = (char *)yaffs_get_temp_buffer(dev);
+ if (!buffer)
+ return -ENOMEM;
- if (!yaffs_obj_cache_dirty(in))
- in->dirty = 0;
+ result =
+ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
- /* If this was a shrink, then mark the block that the chunk lives on */
- if (is_shrink) {
- bi = yaffs_get_block_info(in->my_dev,
- newChunkId / in->my_dev->param.chunks_per_block);
- bi->has_shrink_hdr = 1;
- }
+ if (result != YAFFS_OK)
+ retval = -ENOENT;
+ else {
+ x_buffer = buffer + x_offs;
+ if (!obj->xattr_known) {
+ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
+ obj->xattr_known = 1;
}
- retVal = newChunkId;
-
+ if (name)
+ retval = nval_get(x_buffer, x_size, name, value, size);
+ else
+ retval = nval_list(x_buffer, x_size, value, size);
}
-
- if (buffer)
- yaffs_release_temp_buffer(dev, buffer, __LINE__);
-
- return retVal;
+ yaffs_release_temp_buffer(dev, (u8 *) buffer);
+ return retval;
}
-/*------------------------ Short Operations Cache ----------------------------------------
- * In many situations where there is no high level buffering (eg WinCE) a lot of
- * reads might be short sequential reads, and a lot of writes may be short
- * sequential writes. eg. scanning/writing a jpeg file.
- * In these cases, a short read/write cache can provide a huge perfomance benefit
- * with dumb-as-a-rock code.
- * In Linux, the page cache provides read buffering aand the short op cache provides write
- * buffering.
- *
- * There are a limited number (~10) of cache chunks per device so that we don't
- * need a very intelligent search.
- */
-
-static int yaffs_obj_cache_dirty(yaffs_obj_t *obj)
+int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
+ const void *value, int size, int flags)
{
- yaffs_dev_t *dev = obj->my_dev;
- int i;
- yaffs_cache_t *cache;
- int nCaches = obj->my_dev->param.n_caches;
+ return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
+}
- for (i = 0; i < nCaches; i++) {
- cache = &dev->cache[i];
- if (cache->object == obj &&
- cache->dirty)
- return 1;
- }
+int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
+{
+ return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
+}
- return 0;
+int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
+ int size)
+{
+ return yaffs_do_xattrib_fetch(obj, name, value, size);
}
+int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
+{
+ return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
+}
-static void yaffs_flush_file_cache(yaffs_obj_t *obj)
+static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
{
- yaffs_dev_t *dev = obj->my_dev;
- int lowest = -99; /* Stop compiler whining. */
- int i;
- yaffs_cache_t *cache;
- int chunkWritten = 0;
- int nCaches = obj->my_dev->param.n_caches;
-
- if (nCaches > 0) {
- do {
- cache = NULL;
-
- /* Find the dirty cache for this object with the lowest chunk id. */
- for (i = 0; i < nCaches; i++) {
- if (dev->cache[i].object == obj &&
- dev->cache[i].dirty) {
- if (!cache
- || dev->cache[i].chunk_id <
- lowest) {
- cache = &dev->cache[i];
- lowest = cache->chunk_id;
- }
- }
- }
+ u8 *buf;
+ struct yaffs_obj_hdr *oh;
+ struct yaffs_dev *dev;
+ struct yaffs_ext_tags tags;
+ int result;
+ int alloc_failed = 0;
- if (cache && !cache->locked) {
- /* Write it out and free it up */
-
- chunkWritten =
- yaffs_wr_data_obj(cache->object,
- cache->chunk_id,
- cache->data,
- cache->n_bytes,
- 1);
- cache->dirty = 0;
- cache->object = NULL;
- }
+ if (!in || !in->lazy_loaded || in->hdr_chunk < 1)
+ return;
- } while (cache && chunkWritten > 0);
+ dev = in->my_dev;
+ in->lazy_loaded = 0;
+ buf = yaffs_get_temp_buffer(dev);
- if (cache) {
- /* Hoosterman, disk full while writing cache out. */
- T(YAFFS_TRACE_ERROR,
- (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
+ result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
+ oh = (struct yaffs_obj_hdr *)buf;
- }
- }
+ in->yst_mode = oh->yst_mode;
+ yaffs_load_attribs(in, oh);
+ yaffs_set_obj_name_from_oh(in, oh);
+ if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
+ in->variant.symlink_variant.alias =
+ yaffs_clone_str(oh->alias);
+ if (!in->variant.symlink_variant.alias)
+ alloc_failed = 1; /* Not returned */
+ }
+ yaffs_release_temp_buffer(dev, buf);
}
-/*yaffs_flush_whole_cache(dev)
- *
- *
- */
-
-void yaffs_flush_whole_cache(yaffs_dev_t *dev)
+static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
+ const YCHAR *oh_name, int buff_size)
{
- yaffs_obj_t *obj;
- int nCaches = dev->param.n_caches;
- int i;
-
- /* Find a dirty object in the cache and flush it...
- * until there are no further dirty objects.
- */
- do {
- obj = NULL;
- for (i = 0; i < nCaches && !obj; i++) {
- if (dev->cache[i].object &&
- dev->cache[i].dirty)
- obj = dev->cache[i].object;
-
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+ if (dev->param.auto_unicode) {
+ if (*oh_name) {
+ /* It is an ASCII name, do an ASCII to
+ * unicode conversion */
+ const char *ascii_oh_name = (const char *)oh_name;
+ int n = buff_size - 1;
+ while (n > 0 && *ascii_oh_name) {
+ *name = *ascii_oh_name;
+ name++;
+ ascii_oh_name++;
+ n--;
+ }
+ } else {
+ strncpy(name, oh_name + 1, buff_size - 1);
}
- if (obj)
- yaffs_flush_file_cache(obj);
+ } else {
+#else
+ (void) dev;
+ {
+#endif
+ strncpy(name, oh_name, buff_size - 1);
+ }
+}
- } while (obj);
+static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
+ const YCHAR *name)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
-}
+ int is_ascii;
+ YCHAR *w;
+ if (dev->param.auto_unicode) {
-/* Grab us a cache chunk for use.
- * First look for an empty one.
- * Then look for the least recently used non-dirty one.
- * Then look for the least recently used dirty one...., flush and look again.
- */
-static yaffs_cache_t *yaffs_grab_chunk_worker(yaffs_dev_t *dev)
-{
- int i;
+ is_ascii = 1;
+ w = name;
- if (dev->param.n_caches > 0) {
- for (i = 0; i < dev->param.n_caches; i++) {
- if (!dev->cache[i].object)
- return &dev->cache[i];
+ /* Figure out if the name will fit in ascii character set */
+ while (is_ascii && *w) {
+ if ((*w) & 0xff00)
+ is_ascii = 0;
+ w++;
}
- }
- return NULL;
+ if (is_ascii) {
+ /* It is an ASCII name, so convert unicode to ascii */
+ char *ascii_oh_name = (char *)oh_name;
+ int n = YAFFS_MAX_NAME_LENGTH - 1;
+ while (n > 0 && *name) {
+ *ascii_oh_name = *name;
+ name++;
+ ascii_oh_name++;
+ n--;
+ }
+ } else {
+ /* Unicode name, so save starting at the second YCHAR */
+ *oh_name = 0;
+ strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
+ }
+ } else {
+#else
+ dev = dev;
+ {
+#endif
+ strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
+ }
}
-static yaffs_cache_t *yaffs_grab_chunk_cache(yaffs_dev_t *dev)
+/* UpdateObjectHeader updates the header on NAND for an object.
+ * If name is not NULL, then that new name is used.
+ */
+int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
+ int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
{
- yaffs_cache_t *cache;
- yaffs_obj_t *theObj;
- int usage;
- int i;
- int pushout;
- if (dev->param.n_caches > 0) {
- /* Try find a non-dirty one... */
+ struct yaffs_block_info *bi;
+ struct yaffs_dev *dev = in->my_dev;
+ int prev_chunk_id;
+ int ret_val = 0;
+ int result = 0;
+ int new_chunk_id;
+ struct yaffs_ext_tags new_tags;
+ struct yaffs_ext_tags old_tags;
+ const YCHAR *alias = NULL;
+ u8 *buffer = NULL;
+ YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
+ struct yaffs_obj_hdr *oh = NULL;
+ loff_t file_size = 0;
- cache = yaffs_grab_chunk_worker(dev);
+ strcpy(old_name, _Y("silly old name"));
- if (!cache) {
- /* They were all dirty, find the last recently used object and flush
- * its cache, then find again.
- * NB what's here is not very accurate, we actually flush the object
- * the last recently used page.
- */
+ if (in->fake && in != dev->root_dir && !force && !xmod)
+ return ret_val;
- /* With locking we can't assume we can use entry zero */
+ yaffs_check_gc(dev, 0);
+ yaffs_check_obj_details_loaded(in);
- theObj = NULL;
- usage = -1;
- cache = NULL;
- pushout = -1;
+ buffer = yaffs_get_temp_buffer(in->my_dev);
+ oh = (struct yaffs_obj_hdr *)buffer;
- for (i = 0; i < dev->param.n_caches; i++) {
- if (dev->cache[i].object &&
- !dev->cache[i].locked &&
- (dev->cache[i].last_use < usage || !cache)) {
- usage = dev->cache[i].last_use;
- theObj = dev->cache[i].object;
- cache = &dev->cache[i];
- pushout = i;
- }
- }
+ prev_chunk_id = in->hdr_chunk;
- if (!cache || cache->dirty) {
- /* Flush and try again */
- yaffs_flush_file_cache(theObj);
- cache = yaffs_grab_chunk_worker(dev);
- }
+ if (prev_chunk_id > 0) {
+ result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
+ buffer, &old_tags);
- }
- return cache;
- } else
- return NULL;
+ yaffs_verify_oh(in, oh, &old_tags, 0);
+ memcpy(old_name, oh->name, sizeof(oh->name));
+ memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
+ } else {
+ memset(buffer, 0xff, dev->data_bytes_per_chunk);
+ }
-}
+ oh->type = in->variant_type;
+ oh->yst_mode = in->yst_mode;
+ oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
-/* Find a cached chunk */
-static yaffs_cache_t *yaffs_find_chunk_cache(const yaffs_obj_t *obj,
- int chunk_id)
-{
- yaffs_dev_t *dev = obj->my_dev;
- int i;
- if (dev->param.n_caches > 0) {
- for (i = 0; i < dev->param.n_caches; i++) {
- if (dev->cache[i].object == obj &&
- dev->cache[i].chunk_id == chunk_id) {
- dev->cache_hits++;
+ yaffs_load_attribs_oh(oh, in);
- return &dev->cache[i];
- }
- }
+ if (in->parent)
+ oh->parent_obj_id = in->parent->obj_id;
+ else
+ oh->parent_obj_id = 0;
+
+ if (name && *name) {
+ memset(oh->name, 0, sizeof(oh->name));
+ yaffs_load_oh_from_name(dev, oh->name, name);
+ } else if (prev_chunk_id > 0) {
+ memcpy(oh->name, old_name, sizeof(oh->name));
+ } else {
+ memset(oh->name, 0, sizeof(oh->name));
}
- return NULL;
-}
-/* Mark the chunk for the least recently used algorithym */
-static void yaffs_use_cache(yaffs_dev_t *dev, yaffs_cache_t *cache,
- int isAWrite)
-{
+ oh->is_shrink = is_shrink;
- if (dev->param.n_caches > 0) {
- if (dev->cache_last_use < 0 || dev->cache_last_use > 100000000) {
- /* Reset the cache usages */
- int i;
- for (i = 1; i < dev->param.n_caches; i++)
- dev->cache[i].last_use = 0;
+ switch (in->variant_type) {
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* Should not happen */
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+ if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
+ oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
+ file_size = in->variant.file_variant.file_size;
+ yaffs_oh_size_load(oh, file_size);
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ oh->equiv_id = in->variant.hardlink_variant.equiv_id;
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ alias = in->variant.symlink_variant.alias;
+ if (!alias)
+ alias = _Y("no alias");
+ strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
+ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
+ break;
+ }
- dev->cache_last_use = 0;
- }
+ /* process any xattrib modifications */
+ if (xmod)
+ yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
+
+ /* Tags */
+ memset(&new_tags, 0, sizeof(new_tags));
+ in->serial++;
+ new_tags.chunk_id = 0;
+ new_tags.obj_id = in->obj_id;
+ new_tags.serial_number = in->serial;
+
+ /* Add extra info for file header */
+ new_tags.extra_available = 1;
+ new_tags.extra_parent_id = oh->parent_obj_id;
+ new_tags.extra_file_size = file_size;
+ new_tags.extra_is_shrink = oh->is_shrink;
+ new_tags.extra_equiv_id = oh->equiv_id;
+ new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
+ new_tags.extra_obj_type = in->variant_type;
+ yaffs_verify_oh(in, oh, &new_tags, 1);
+
+ /* Create new chunk in NAND */
+ new_chunk_id =
+ yaffs_write_new_chunk(dev, buffer, &new_tags,
+ (prev_chunk_id > 0) ? 1 : 0);
- dev->cache_last_use++;
+ if (buffer)
+ yaffs_release_temp_buffer(dev, buffer);
- cache->last_use = dev->cache_last_use;
+ if (new_chunk_id < 0)
+ return new_chunk_id;
- if (isAWrite)
- cache->dirty = 1;
- }
-}
+ in->hdr_chunk = new_chunk_id;
-/* Invalidate a single cache page.
- * Do this when a whole page gets written,
- * ie the short cache for this page is no longer valid.
- */
-static void yaffs_invalidate_chunk_cache(yaffs_obj_t *object, int chunk_id)
-{
- if (object->my_dev->param.n_caches > 0) {
- yaffs_cache_t *cache = yaffs_find_chunk_cache(object, chunk_id);
+ if (prev_chunk_id > 0)
+ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
- if (cache)
- cache->object = NULL;
+ if (!yaffs_obj_cache_dirty(in))
+ in->dirty = 0;
+
+ /* If this was a shrink, then mark the block
+ * that the chunk lives on */
+ if (is_shrink) {
+ bi = yaffs_get_block_info(in->my_dev,
+ new_chunk_id /
+ in->my_dev->param.chunks_per_block);
+ bi->has_shrink_hdr = 1;
}
-}
-/* Invalidate all the cache pages associated with this object
- * Do this whenever ther file is deleted or resized.
- */
-static void yaffs_invalidate_whole_cache(yaffs_obj_t *in)
-{
- int i;
- yaffs_dev_t *dev = in->my_dev;
- if (dev->param.n_caches > 0) {
- /* Invalidate it. */
- for (i = 0; i < dev->param.n_caches; i++) {
- if (dev->cache[i].object == in)
- dev->cache[i].object = NULL;
- }
- }
+ return new_chunk_id;
}
-
/*--------------------- File read/write ------------------------
* Read and write have very similar structures.
* In general the read/write has three parts to it
* Curve-balls: the first chunk might also be the last chunk.
*/
-int yaffs_file_rd(yaffs_obj_t *in, __u8 *buffer, loff_t offset,
- int n_bytes)
+int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
{
-
int chunk;
- __u32 start;
- int nToCopy;
+ u32 start;
+ int n_copy;
int n = n_bytes;
- int nDone = 0;
- yaffs_cache_t *cache;
-
- yaffs_dev_t *dev;
+ int n_done = 0;
+ struct yaffs_cache *cache;
+ struct yaffs_dev *dev;
dev = in->my_dev;
while (n > 0) {
- /* chunk = offset / dev->data_bytes_per_chunk + 1; */
- /* start = offset % dev->data_bytes_per_chunk; */
yaffs_addr_to_chunk(dev, offset, &chunk, &start);
chunk++;
* the same chunk.
*/
if ((start + n) < dev->data_bytes_per_chunk)
- nToCopy = n;
+ n_copy = n;
else
- nToCopy = dev->data_bytes_per_chunk - start;
+ n_copy = dev->data_bytes_per_chunk - start;
cache = yaffs_find_chunk_cache(in, chunk);
- /* If the chunk is already in the cache or it is less than a whole chunk
- * or we're using inband tags then use the cache (if there is caching)
- * else bypass the cache.
+ /* If the chunk is already in the cache or it is less than
+ * a whole chunk or we're using inband tags then use the cache
+ * (if there is caching) else bypass the cache.
*/
- if (cache || nToCopy != dev->data_bytes_per_chunk || dev->param.inband_tags) {
+ if (cache || n_copy != dev->data_bytes_per_chunk ||
+ dev->param.inband_tags) {
if (dev->param.n_caches > 0) {
- /* If we can't find the data in the cache, then load it up. */
+ /* If we can't find the data in the cache,
+ * then load it up. */
if (!cache) {
- cache = yaffs_grab_chunk_cache(in->my_dev);
+ cache =
+ yaffs_grab_chunk_cache(in->my_dev);
cache->object = in;
cache->chunk_id = chunk;
cache->dirty = 0;
cache->locked = 0;
yaffs_rd_data_obj(in, chunk,
- cache->
- data);
+ cache->data);
cache->n_bytes = 0;
}
cache->locked = 1;
-
- memcpy(buffer, &cache->data[start], nToCopy);
+ memcpy(buffer, &cache->data[start], n_copy);
cache->locked = 0;
} else {
- /* Read into the local buffer then copy..*/
+ /* Read into the local buffer then copy.. */
- __u8 *localBuffer =
- yaffs_get_temp_buffer(dev, __LINE__);
- yaffs_rd_data_obj(in, chunk,
- localBuffer);
+ u8 *local_buffer =
+ yaffs_get_temp_buffer(dev);
+ yaffs_rd_data_obj(in, chunk, local_buffer);
- memcpy(buffer, &localBuffer[start], nToCopy);
+ memcpy(buffer, &local_buffer[start], n_copy);
-
- yaffs_release_temp_buffer(dev, localBuffer,
- __LINE__);
+ yaffs_release_temp_buffer(dev, local_buffer);
}
-
} else {
-
- /* A full chunk. Read directly into the supplied buffer. */
+ /* A full chunk. Read directly into the buffer. */
yaffs_rd_data_obj(in, chunk, buffer);
-
}
-
- n -= nToCopy;
- offset += nToCopy;
- buffer += nToCopy;
- nDone += nToCopy;
-
+ n -= n_copy;
+ offset += n_copy;
+ buffer += n_copy;
+ n_done += n_copy;
}
-
- return nDone;
+ return n_done;
}
-int yaffs_do_file_wr(yaffs_obj_t *in, const __u8 *buffer, loff_t offset,
- int n_bytes, int write_trhrough)
+int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
+ int n_bytes, int write_through)
{
int chunk;
- __u32 start;
- int nToCopy;
+ u32 start;
+ int n_copy;
int n = n_bytes;
- int nDone = 0;
- int nToWriteBack;
- int startOfWrite = offset;
- int chunkWritten = 0;
- __u32 n_bytesRead;
- __u32 chunkStart;
-
- yaffs_dev_t *dev;
+ int n_done = 0;
+ int n_writeback;
+ loff_t start_write = offset;
+ int chunk_written = 0;
+ u32 n_bytes_read;
+ loff_t chunk_start;
+ struct yaffs_dev *dev;
dev = in->my_dev;
- while (n > 0 && chunkWritten >= 0) {
+ while (n > 0 && chunk_written >= 0) {
yaffs_addr_to_chunk(dev, offset, &chunk, &start);
- if (chunk * dev->data_bytes_per_chunk + start != offset ||
- start >= dev->data_bytes_per_chunk) {
- T(YAFFS_TRACE_ERROR, (
- TSTR("AddrToChunk of offset %d gives chunk %d start %d"
- TENDSTR),
- (int)offset, chunk, start));
+ if (((loff_t)chunk) *
+ dev->data_bytes_per_chunk + start != offset ||
+ start >= dev->data_bytes_per_chunk) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "AddrToChunk of offset %lld gives chunk %d start %d",
+ offset, chunk, start);
}
- chunk++; /* File pos to chunk in file offset */
+ chunk++; /* File pos to chunk in file offset */
/* OK now check for the curveball where the start and end are in
* the same chunk.
*/
if ((start + n) < dev->data_bytes_per_chunk) {
- nToCopy = n;
+ n_copy = n;
- /* Now folks, to calculate how many bytes to write back....
- * If we're overwriting and not writing to then end of file then
- * we need to write back as much as was there before.
+ /* Now calculate how many bytes to write back....
+ * If we're overwriting and not writing to then end of
+ * file then we need to write back as much as was there
+ * before.
*/
- chunkStart = ((chunk - 1) * dev->data_bytes_per_chunk);
+ chunk_start = (((loff_t)(chunk - 1)) *
+ dev->data_bytes_per_chunk);
- if (chunkStart > in->variant.file_variant.file_size)
- n_bytesRead = 0; /* Past end of file */
+ if (chunk_start > in->variant.file_variant.file_size)
+ n_bytes_read = 0; /* Past end of file */
else
- n_bytesRead = in->variant.file_variant.file_size - chunkStart;
+ n_bytes_read =
+ in->variant.file_variant.file_size -
+ chunk_start;
- if (n_bytesRead > dev->data_bytes_per_chunk)
- n_bytesRead = dev->data_bytes_per_chunk;
+ if (n_bytes_read > dev->data_bytes_per_chunk)
+ n_bytes_read = dev->data_bytes_per_chunk;
- nToWriteBack =
- (n_bytesRead >
- (start + n)) ? n_bytesRead : (start + n);
+ n_writeback =
+ (n_bytes_read >
+ (start + n)) ? n_bytes_read : (start + n);
- if (nToWriteBack < 0 || nToWriteBack > dev->data_bytes_per_chunk)
- YBUG();
+ if (n_writeback < 0 ||
+ n_writeback > dev->data_bytes_per_chunk)
+ BUG();
} else {
- nToCopy = dev->data_bytes_per_chunk - start;
- nToWriteBack = dev->data_bytes_per_chunk;
+ n_copy = dev->data_bytes_per_chunk - start;
+ n_writeback = dev->data_bytes_per_chunk;
}
- if (nToCopy != dev->data_bytes_per_chunk || dev->param.inband_tags) {
- /* An incomplete start or end chunk (or maybe both start and end chunk),
- * or we're using inband tags, so we want to use the cache buffers.
+ if (n_copy != dev->data_bytes_per_chunk ||
+ !dev->param.cache_bypass_aligned ||
+ dev->param.inband_tags) {
+ /* An incomplete start or end chunk (or maybe both
+ * start and end chunk), or we're using inband tags,
+ * or we're forcing writes through the cache,
+ * so we want to use the cache buffers.
*/
if (dev->param.n_caches > 0) {
- yaffs_cache_t *cache;
- /* If we can't find the data in the cache, then load the cache */
+ struct yaffs_cache *cache;
+
+ /* If we can't find the data in the cache, then
+ * load the cache */
cache = yaffs_find_chunk_cache(in, chunk);
- if (!cache
- && yaffs_check_alloc_available(dev, 1)) {
+ if (!cache &&
+ yaffs_check_alloc_available(dev, 1)) {
cache = yaffs_grab_chunk_cache(dev);
cache->object = in;
cache->chunk_id = chunk;
cache->dirty = 0;
cache->locked = 0;
yaffs_rd_data_obj(in, chunk,
- cache->data);
+ cache->data);
} else if (cache &&
- !cache->dirty &&
- !yaffs_check_alloc_available(dev, 1)) {
- /* Drop the cache if it was a read cache item and
- * no space check has been made for it.
+ !cache->dirty &&
+ !yaffs_check_alloc_available(dev,
+ 1)) {
+ /* Drop the cache if it was a read cache
+ * item and no space check has been made
+ * for it.
*/
- cache = NULL;
+ cache = NULL;
}
if (cache) {
yaffs_use_cache(dev, cache, 1);
cache->locked = 1;
-
memcpy(&cache->data[start], buffer,
- nToCopy);
-
+ n_copy);
cache->locked = 0;
- cache->n_bytes = nToWriteBack;
+ cache->n_bytes = n_writeback;
- if (write_trhrough) {
- chunkWritten =
+ if (write_through) {
+ chunk_written =
yaffs_wr_data_obj
(cache->object,
cache->chunk_id,
- cache->data, cache->n_bytes,
- 1);
+ cache->data,
+ cache->n_bytes, 1);
cache->dirty = 0;
}
-
} else {
- chunkWritten = -1; /* fail the write */
+ chunk_written = -1; /* fail write */
}
} else {
- /* An incomplete start or end chunk (or maybe both start and end chunk)
- * Read into the local buffer then copy, then copy over and write back.
+ /* An incomplete start or end chunk (or maybe
+ * both start and end chunk). Read into the
+ * local buffer then copy over and write back.
*/
- __u8 *localBuffer =
- yaffs_get_temp_buffer(dev, __LINE__);
-
- yaffs_rd_data_obj(in, chunk,
- localBuffer);
-
+ u8 *local_buffer = yaffs_get_temp_buffer(dev);
+ yaffs_rd_data_obj(in, chunk, local_buffer);
+ memcpy(&local_buffer[start], buffer, n_copy);
- memcpy(&localBuffer[start], buffer, nToCopy);
-
- chunkWritten =
+ chunk_written =
yaffs_wr_data_obj(in, chunk,
- localBuffer,
- nToWriteBack,
- 0);
-
- yaffs_release_temp_buffer(dev, localBuffer,
- __LINE__);
+ local_buffer,
+ n_writeback, 0);
+ yaffs_release_temp_buffer(dev, local_buffer);
}
-
} else {
- /* A full chunk. Write directly from the supplied buffer. */
-
+ /* A full chunk. Write directly from the buffer. */
-
- chunkWritten =
+ chunk_written =
yaffs_wr_data_obj(in, chunk, buffer,
- dev->data_bytes_per_chunk,
- 0);
+ dev->data_bytes_per_chunk, 0);
- /* Since we've overwritten the cached data, we better invalidate it. */
+ /* Since we've overwritten the cached data,
+ * we better invalidate it. */
yaffs_invalidate_chunk_cache(in, chunk);
}
- if (chunkWritten >= 0) {
- n -= nToCopy;
- offset += nToCopy;
- buffer += nToCopy;
- nDone += nToCopy;
+ if (chunk_written >= 0) {
+ n -= n_copy;
+ offset += n_copy;
+ buffer += n_copy;
+ n_done += n_copy;
}
-
}
/* Update file object */
- if ((startOfWrite + nDone) > in->variant.file_variant.file_size)
- in->variant.file_variant.file_size = (startOfWrite + nDone);
+ if ((start_write + n_done) > in->variant.file_variant.file_size)
+ in->variant.file_variant.file_size = (start_write + n_done);
in->dirty = 1;
-
- return nDone;
+ return n_done;
}
-int yaffs_wr_file(yaffs_obj_t *in, const __u8 *buffer, loff_t offset,
- int n_bytes, int write_trhrough)
+int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
+ int n_bytes, int write_through)
{
- yaffs2_handle_hole(in,offset);
- return yaffs_do_file_wr(in,buffer,offset,n_bytes,write_trhrough);
+ yaffs2_handle_hole(in, offset);
+ return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through);
}
-
-
/* ---------------------- File resizing stuff ------------------ */
-static void yaffs_prune_chunks(yaffs_obj_t *in, int new_size)
+static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size)
{
- yaffs_dev_t *dev = in->my_dev;
- int oldFileSize = in->variant.file_variant.file_size;
-
- int lastDel = 1 + (oldFileSize - 1) / dev->data_bytes_per_chunk;
-
- int startDel = 1 + (new_size + dev->data_bytes_per_chunk - 1) /
- dev->data_bytes_per_chunk;
+ struct yaffs_dev *dev = in->my_dev;
+ loff_t old_size = in->variant.file_variant.file_size;
int i;
int chunk_id;
+ u32 dummy;
+ int last_del;
+ int start_del;
+
+ if (old_size > 0)
+ yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy);
+ else
+ last_del = 0;
+
+ yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1,
+ &start_del, &dummy);
+ last_del++;
+ start_del++;
/* Delete backwards so that we don't end up with holes if
* power is lost part-way through the operation.
*/
- for (i = lastDel; i >= startDel; i--) {
+ for (i = last_del; i >= start_del; i--) {
/* NB this could be optimised somewhat,
* eg. could retrieve the tags and write them without
* using yaffs_chunk_del
*/
chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
- if (chunk_id > 0) {
- if (chunk_id <
- (dev->internal_start_block * dev->param.chunks_per_block)
- || chunk_id >=
- ((dev->internal_end_block +
- 1) * dev->param.chunks_per_block)) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("Found daft chunk_id %d for %d" TENDSTR),
- chunk_id, i));
- } else {
- in->n_data_chunks--;
- yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
- }
+
+ if (chunk_id < 1)
+ continue;
+
+ if (chunk_id <
+ (dev->internal_start_block * dev->param.chunks_per_block) ||
+ chunk_id >=
+ ((dev->internal_end_block + 1) *
+ dev->param.chunks_per_block)) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "Found daft chunk_id %d for %d",
+ chunk_id, i);
+ } else {
+ in->n_data_chunks--;
+ yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
}
}
-
}
-
-void yaffs_resize_file_down( yaffs_obj_t *obj, loff_t new_size)
+void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
{
- int newFullChunks;
- __u32 new_sizeOfPartialChunk;
- yaffs_dev_t *dev = obj->my_dev;
+ int new_full;
+ u32 new_partial;
+ struct yaffs_dev *dev = obj->my_dev;
- yaffs_addr_to_chunk(dev, new_size, &newFullChunks, &new_sizeOfPartialChunk);
+ yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
yaffs_prune_chunks(obj, new_size);
- if (new_sizeOfPartialChunk != 0) {
- int lastChunk = 1 + newFullChunks;
- __u8 *localBuffer = yaffs_get_temp_buffer(dev, __LINE__);
+ if (new_partial != 0) {
+ int last_chunk = 1 + new_full;
+ u8 *local_buffer = yaffs_get_temp_buffer(dev);
- /* Got to read and rewrite the last chunk with its new size and zero pad */
- yaffs_rd_data_obj(obj, lastChunk, localBuffer);
- memset(localBuffer + new_sizeOfPartialChunk, 0,
- dev->data_bytes_per_chunk - new_sizeOfPartialChunk);
+ /* Rewrite the last chunk with its new size and zero pad */
+ yaffs_rd_data_obj(obj, last_chunk, local_buffer);
+ memset(local_buffer + new_partial, 0,
+ dev->data_bytes_per_chunk - new_partial);
- yaffs_wr_data_obj(obj, lastChunk, localBuffer,
- new_sizeOfPartialChunk, 1);
+ yaffs_wr_data_obj(obj, last_chunk, local_buffer,
+ new_partial, 1);
- yaffs_release_temp_buffer(dev, localBuffer, __LINE__);
+ yaffs_release_temp_buffer(dev, local_buffer);
}
obj->variant.file_variant.file_size = new_size;
yaffs_prune_tree(dev, &obj->variant.file_variant);
}
-
-int yaffs_resize_file(yaffs_obj_t *in, loff_t new_size)
+int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
{
- yaffs_dev_t *dev = in->my_dev;
- int oldFileSize = in->variant.file_variant.file_size;
+ struct yaffs_dev *dev = in->my_dev;
+ loff_t old_size = in->variant.file_variant.file_size;
yaffs_flush_file_cache(in);
yaffs_invalidate_whole_cache(in);
- yaffs_check_gc(dev,0);
+ yaffs_check_gc(dev, 0);
if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
return YAFFS_FAIL;
- if (new_size == oldFileSize)
+ if (new_size == old_size)
return YAFFS_OK;
-
- if(new_size > oldFileSize){
- yaffs2_handle_hole(in,new_size);
+
+ if (new_size > old_size) {
+ yaffs2_handle_hole(in, new_size);
in->variant.file_variant.file_size = new_size;
} else {
- /* new_size < oldFileSize */
+ /* new_size < old_size */
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
in->parent->obj_id != YAFFS_OBJECTID_DELETED)
yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
-
return YAFFS_OK;
}
-loff_t yaffs_get_file_size(yaffs_obj_t *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 yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH);
- default:
- return 0;
- }
-}
-
-
-
-int yaffs_flush_file(yaffs_obj_t *in, int update_time, int data_sync)
+int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)
{
- int retVal;
- if (in->dirty) {
- yaffs_flush_file_cache(in);
- if(data_sync) /* Only sync data */
- retVal=YAFFS_OK;
- else {
- if (update_time) {
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_win_file_time_now(in->win_mtime);
-#else
-
- in->yst_mtime = Y_CURRENT_TIME;
+ if (!in->dirty)
+ return YAFFS_OK;
-#endif
- }
+ yaffs_flush_file_cache(in);
- retVal = (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >=
- 0) ? YAFFS_OK : YAFFS_FAIL;
- }
- } else {
- retVal = YAFFS_OK;
- }
+ if (data_sync)
+ return YAFFS_OK;
- return retVal;
+ if (update_time)
+ yaffs_load_current_time(in, 0, 0);
+ return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ?
+ YAFFS_OK : YAFFS_FAIL;
}
-static int yaffs_generic_obj_del(yaffs_obj_t *in)
-{
-
- /* First off, invalidate the file's data in the cache, without flushing. */
- yaffs_invalidate_whole_cache(in);
-
- if (in->my_dev->param.is_yaffs2 && (in->parent != in->my_dev->del_dir)) {
- /* Move to the unlinked directory so we have a record that it was deleted. */
- yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0, 0);
-
- }
-
- yaffs_remove_obj_from_dir(in);
- yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
- in->hdr_chunk = 0;
-
- yaffs_free_obj(in);
- return YAFFS_OK;
-
-}
/* yaffs_del_file deletes the whole file data
* and the inode associated with the file.
* It does not delete the links associated with the file.
*/
-static int yaffs_unlink_file_if_needed(yaffs_obj_t *in)
+static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
{
-
- int retVal;
- int immediateDeletion = 0;
- yaffs_dev_t *dev = in->my_dev;
+ int ret_val;
+ int del_now = 0;
+ struct yaffs_dev *dev = in->my_dev;
if (!in->my_inode)
- immediateDeletion = 1;
+ del_now = 1;
- if (immediateDeletion) {
- retVal =
+ if (del_now) {
+ ret_val =
yaffs_change_obj_name(in, in->my_dev->del_dir,
- _Y("deleted"), 0, 0);
- T(YAFFS_TRACE_TRACING,
- (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
- in->obj_id));
+ _Y("deleted"), 0, 0);
+ yaffs_trace(YAFFS_TRACE_TRACING,
+ "yaffs: immediate deletion of file %d",
+ in->obj_id);
in->deleted = 1;
in->my_dev->n_deleted_files++;
if (dev->param.disable_soft_del || dev->param.is_yaffs2)
yaffs_resize_file(in, 0);
yaffs_soft_del_file(in);
} else {
- retVal =
+ ret_val =
yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
- _Y("unlinked"), 0, 0);
+ _Y("unlinked"), 0, 0);
}
-
-
- return retVal;
+ return ret_val;
}
-int yaffs_del_file(yaffs_obj_t *in)
+static int yaffs_del_file(struct yaffs_obj *in)
{
- int retVal = YAFFS_OK;
- int deleted; /* Need to cache value on stack if in is freed */
- yaffs_dev_t *dev = in->my_dev;
+ int ret_val = YAFFS_OK;
+ int deleted; /* Need to cache value on stack if in is freed */
+ struct yaffs_dev *dev = in->my_dev;
if (dev->param.disable_soft_del || dev->param.is_yaffs2)
yaffs_resize_file(in, 0);
* That won't be the case if it has been resized to zero.
*/
if (!in->unlinked)
- retVal = yaffs_unlink_file_if_needed(in);
+ ret_val = yaffs_unlink_file_if_needed(in);
deleted = in->deleted;
- if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
+ if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
in->deleted = 1;
deleted = 1;
in->my_dev->n_deleted_files++;
}
}
-static int yaffs_is_non_empty_dir(yaffs_obj_t *obj)
+int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
{
- return (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
- !(ylist_empty(&obj->variant.dir_variant.children));
+ return (obj &&
+ obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
+ !(list_empty(&obj->variant.dir_variant.children));
}
-static int yaffs_del_dir(yaffs_obj_t *obj)
+static int yaffs_del_dir(struct yaffs_obj *obj)
{
/* First check that the directory is empty. */
if (yaffs_is_non_empty_dir(obj))
return yaffs_generic_obj_del(obj);
}
-static int yaffs_del_symlink(yaffs_obj_t *in)
+static int yaffs_del_symlink(struct yaffs_obj *in)
{
- if(in->variant.symlink_variant.alias)
- YFREE(in->variant.symlink_variant.alias);
- in->variant.symlink_variant.alias=NULL;
+ kfree(in->variant.symlink_variant.alias);
+ in->variant.symlink_variant.alias = NULL;
return yaffs_generic_obj_del(in);
}
-static int yaffs_del_link(yaffs_obj_t *in)
+static int yaffs_del_link(struct yaffs_obj *in)
{
- /* remove this hardlink from the list assocaited with the equivalent
+ /* remove this hardlink from the list associated with the equivalent
* object
*/
- ylist_del_init(&in->hard_links);
+ list_del_init(&in->hard_links);
return yaffs_generic_obj_del(in);
}
-int yaffs_del_obj(yaffs_obj_t *obj)
+int yaffs_del_obj(struct yaffs_obj *obj)
{
-int retVal = -1;
+ int ret_val = -1;
+
switch (obj->variant_type) {
case YAFFS_OBJECT_TYPE_FILE:
- retVal = yaffs_del_file(obj);
+ ret_val = yaffs_del_file(obj);
break;
case YAFFS_OBJECT_TYPE_DIRECTORY:
- if(!ylist_empty(&obj->variant.dir_variant.dirty)){
- T(YAFFS_TRACE_BACKGROUND, (TSTR("Remove object %d from dirty directories" TENDSTR),obj->obj_id));
- ylist_del_init(&obj->variant.dir_variant.dirty);
+ if (!list_empty(&obj->variant.dir_variant.dirty)) {
+ yaffs_trace(YAFFS_TRACE_BACKGROUND,
+ "Remove object %d from dirty directories",
+ obj->obj_id);
+ list_del_init(&obj->variant.dir_variant.dirty);
}
return yaffs_del_dir(obj);
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
- retVal = yaffs_del_symlink(obj);
+ ret_val = yaffs_del_symlink(obj);
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
- retVal = yaffs_del_link(obj);
+ ret_val = yaffs_del_link(obj);
break;
case YAFFS_OBJECT_TYPE_SPECIAL:
- retVal = yaffs_generic_obj_del(obj);
+ ret_val = yaffs_generic_obj_del(obj);
break;
case YAFFS_OBJECT_TYPE_UNKNOWN:
- retVal = 0;
+ ret_val = 0;
break; /* should not happen. */
}
-
- return retVal;
+ return ret_val;
}
-static int yaffs_unlink_worker(yaffs_obj_t *obj)
+static int yaffs_unlink_worker(struct yaffs_obj *obj)
{
+ int del_now = 0;
- int immediateDeletion = 0;
+ if (!obj)
+ return YAFFS_FAIL;
if (!obj->my_inode)
- immediateDeletion = 1;
+ del_now = 1;
- if(obj)
- yaffs_update_parent(obj->parent);
+ yaffs_update_parent(obj->parent);
if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
return yaffs_del_link(obj);
- } else if (!ylist_empty(&obj->hard_links)) {
+ } else if (!list_empty(&obj->hard_links)) {
/* Curve ball: We're unlinking an object that has a hardlink.
*
* This problem arises because we are not strictly following
* Instead, we do the following:
* - Select a hardlink.
* - Unhook it from the hard links
- * - Move it from its parent directory (so that the rename can work)
+ * - Move it from its parent directory so that the rename works.
* - Rename the object to the hardlink's name.
* - Delete the hardlink
*/
- yaffs_obj_t *hl;
- yaffs_obj_t *parent;
- int retVal;
+ struct yaffs_obj *hl;
+ struct yaffs_obj *parent;
+ int ret_val;
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
- hl = ylist_entry(obj->hard_links.next, yaffs_obj_t, hard_links);
+ hl = list_entry(obj->hard_links.next, struct yaffs_obj,
+ hard_links);
yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
parent = hl->parent;
- ylist_del_init(&hl->hard_links);
+ list_del_init(&hl->hard_links);
- yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
+ yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
- retVal = yaffs_change_obj_name(obj,parent, name, 0, 0);
+ ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
- if (retVal == YAFFS_OK)
- retVal = yaffs_generic_obj_del(hl);
+ if (ret_val == YAFFS_OK)
+ ret_val = yaffs_generic_obj_del(hl);
- return retVal;
+ return ret_val;
- } else if (immediateDeletion) {
+ } else if (del_now) {
switch (obj->variant_type) {
case YAFFS_OBJECT_TYPE_FILE:
return yaffs_del_file(obj);
break;
case YAFFS_OBJECT_TYPE_DIRECTORY:
- ylist_del_init(&obj->variant.dir_variant.dirty);
+ list_del_init(&obj->variant.dir_variant.dirty);
return yaffs_del_dir(obj);
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
default:
return YAFFS_FAIL;
}
- } else if(yaffs_is_non_empty_dir(obj))
+ } else if (yaffs_is_non_empty_dir(obj)) {
return YAFFS_FAIL;
- else
+ } else {
return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
- _Y("unlinked"), 0, 0);
+ _Y("unlinked"), 0, 0);
+ }
}
-
-static int yaffs_unlink_obj(yaffs_obj_t *obj)
+static int yaffs_unlink_obj(struct yaffs_obj *obj)
{
-
if (obj && obj->unlink_allowed)
return yaffs_unlink_worker(obj);
return YAFFS_FAIL;
-
}
-int yaffs_unlinker(yaffs_obj_t *dir, const YCHAR *name)
+
+int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name)
{
- yaffs_obj_t *obj;
+ struct yaffs_obj *obj;
obj = yaffs_find_by_name(dir, name);
return yaffs_unlink_obj(obj);
}
+/* Note:
+ * If old_name is NULL then we take old_dir as the object to be renamed.
+ */
+int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name,
+ struct yaffs_obj *new_dir, const YCHAR *new_name)
+{
+ struct yaffs_obj *obj = NULL;
+ struct yaffs_obj *existing_target = NULL;
+ int force = 0;
+ int result;
+ struct yaffs_dev *dev;
+
+ if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ BUG();
+ return YAFFS_FAIL;
+ }
+ if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ BUG();
+ return YAFFS_FAIL;
+ }
+
+ dev = old_dir->my_dev;
+
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
+ /* Special case for case insemsitive systems.
+ * While look-up is case insensitive, the name isn't.
+ * Therefore we might want to change x.txt to X.txt
+ */
+ if (old_dir == new_dir &&
+ old_name && new_name &&
+ strcmp(old_name, new_name) == 0)
+ force = 1;
+#endif
+
+ if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
+ YAFFS_MAX_NAME_LENGTH)
+ /* ENAMETOOLONG */
+ return YAFFS_FAIL;
+
+ if (old_name)
+ obj = yaffs_find_by_name(old_dir, old_name);
+ else{
+ obj = old_dir;
+ old_dir = obj->parent;
+ }
+
+ if (obj && obj->rename_allowed) {
+ /* Now handle an existing target, if there is one */
+ existing_target = yaffs_find_by_name(new_dir, new_name);
+ if (yaffs_is_non_empty_dir(existing_target)) {
+ return YAFFS_FAIL; /* ENOTEMPTY */
+ } else if (existing_target && existing_target != obj) {
+ /* Nuke the target first, using shadowing,
+ * but only if it isn't the same object.
+ *
+ * Note we must disable gc here otherwise it can mess
+ * up the shadowing.
+ *
+ */
+ dev->gc_disable = 1;
+ yaffs_change_obj_name(obj, new_dir, new_name, force,
+ existing_target->obj_id);
+ existing_target->is_shadowed = 1;
+ yaffs_unlink_obj(existing_target);
+ dev->gc_disable = 0;
+ }
+
+ result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
+
+ yaffs_update_parent(old_dir);
+ if (new_dir != old_dir)
+ yaffs_update_parent(new_dir);
+
+ return result;
+ }
+ return YAFFS_FAIL;
+}
+
/*----------------------- Initialisation Scanning ---------------------- */
-void yaffs_handle_shadowed_obj(yaffs_dev_t *dev, int obj_id,
- int backward_scanning)
+void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
+ int backward_scanning)
{
- yaffs_obj_t *obj;
-
- if (!backward_scanning) {
- /* Handle YAFFS1 forward scanning case
- * For YAFFS1 we always do the deletion
- */
+ struct yaffs_obj *obj;
- } else {
+ if (backward_scanning) {
/* Handle YAFFS2 case (backward scanning)
* If the shadowed object exists then ignore.
*/
obj = yaffs_find_by_number(dev, obj_id);
- if(obj)
+ if (obj)
return;
}
- /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
+ /* Let's create it (if it does not exist) assuming it is a file so that
+ * it can do shrinking etc.
* We put it in unlinked dir to be cleaned up after the scanning
*/
obj =
- yaffs_find_or_create_by_number(dev, obj_id,
- YAFFS_OBJECT_TYPE_FILE);
+ yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
if (!obj)
return;
obj->is_shadowed = 1;
yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
obj->variant.file_variant.shrink_size = 0;
- obj->valid = 1; /* So that we don't read any other info for this file */
-
+ obj->valid = 1; /* So that we don't read any other info. */
}
-
-void yaffs_link_fixup(yaffs_dev_t *dev, yaffs_obj_t *hard_list)
+void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list)
{
- yaffs_obj_t *hl;
- yaffs_obj_t *in;
-
- while (hard_list) {
- hl = hard_list;
- hard_list = (yaffs_obj_t *) (hard_list->hard_links.next);
+ struct list_head *lh;
+ struct list_head *save;
+ struct yaffs_obj *hl;
+ struct yaffs_obj *in;
+ list_for_each_safe(lh, save, hard_list) {
+ hl = list_entry(lh, struct yaffs_obj, hard_links);
in = yaffs_find_by_number(dev,
- hl->variant.hardlink_variant.
- equiv_id);
+ hl->variant.hardlink_variant.equiv_id);
if (in) {
/* Add the hardlink pointers */
hl->variant.hardlink_variant.equiv_obj = in;
- ylist_add(&hl->hard_links, &in->hard_links);
+ list_add(&hl->hard_links, &in->hard_links);
} else {
/* Todo Need to report/handle this better.
* Got a problem... hardlink to a non-existant object
*/
hl->variant.hardlink_variant.equiv_obj = NULL;
- YINIT_LIST_HEAD(&hl->hard_links);
-
+ INIT_LIST_HEAD(&hl->hard_links);
}
}
}
-
-static void yaffs_strip_deleted_objs(yaffs_dev_t *dev)
+static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
{
/*
- * Sort out state of unlinked and deleted objects after scanning.
- */
- struct ylist_head *i;
- struct ylist_head *n;
- yaffs_obj_t *l;
+ * Sort out state of unlinked and deleted objects after scanning.
+ */
+ struct list_head *i;
+ struct list_head *n;
+ struct yaffs_obj *l;
if (dev->read_only)
return;
/* Soft delete all the unlinked files */
- ylist_for_each_safe(i, n,
- &dev->unlinked_dir->variant.dir_variant.children) {
- if (i) {
- l = ylist_entry(i, yaffs_obj_t, siblings);
- yaffs_del_obj(l);
- }
+ list_for_each_safe(i, n,
+ &dev->unlinked_dir->variant.dir_variant.children) {
+ l = list_entry(i, struct yaffs_obj, siblings);
+ yaffs_del_obj(l);
}
- ylist_for_each_safe(i, n,
- &dev->del_dir->variant.dir_variant.children) {
- if (i) {
- l = ylist_entry(i, yaffs_obj_t, siblings);
- yaffs_del_obj(l);
- }
+ list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
+ l = list_entry(i, struct yaffs_obj, siblings);
+ yaffs_del_obj(l);
}
-
}
/*
* - Directly or indirectly under root.
*
* Note:
- * This code assumes that we don't ever change the current relationships between
- * directories:
+ * This code assumes that we don't ever change the current relationships
+ * between directories:
* root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
- * lostNfound->parent == root_dir
+ * lost-n-found->parent == root_dir
*
- * This fixes the problem where directories might have inadvertently been deleted
- * leaving the object "hanging" without being rooted in the directory tree.
+ * 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)
+
+static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
{
return (obj == dev->del_dir ||
- obj == dev->unlinked_dir||
- obj == dev->root_dir);
+ obj == dev->unlinked_dir || obj == dev->root_dir);
}
-static void yaffs_fix_hanging_objs(yaffs_dev_t *dev)
+static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
{
- yaffs_obj_t *obj;
- yaffs_obj_t *parent;
+ struct yaffs_obj *obj;
+ struct yaffs_obj *parent;
int i;
- struct ylist_head *lh;
- struct ylist_head *n;
- int depthLimit;
+ struct list_head *lh;
+ struct list_head *n;
+ int depth_limit;
int hanging;
if (dev->read_only)
* Make sure it is rooted.
*/
- for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
- ylist_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
- 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;
+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+ list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
+ obj = list_entry(lh, struct yaffs_obj, hash_link);
+ parent = obj->parent;
+
+ if (yaffs_has_null_parent(dev, obj)) {
+ /* These directories are not hanging */
+ hanging = 0;
+ } else if (!parent ||
+ parent->variant_type !=
+ YAFFS_OBJECT_TYPE_DIRECTORY) {
+ hanging = 1;
+ } else if (yaffs_has_null_parent(dev, parent)) {
+ hanging = 0;
+ } else {
+ /*
+ * Need to follow the parent chain to
+ * see if it is hanging.
+ */
+ hanging = 0;
+ depth_limit = 100;
+
+ while (parent != dev->root_dir &&
+ parent->parent &&
+ parent->parent->variant_type ==
+ YAFFS_OBJECT_TYPE_DIRECTORY &&
+ depth_limit > 0) {
+ parent = parent->parent;
+ depth_limit--;
}
- else if(!parent || parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+ if (parent != dev->root_dir)
hanging = 1;
- else if(yaffs_has_null_parent(dev,parent))
- hanging = 0;
- else {
- /*
- * Need to follow the parent chain to see if it is hanging.
- */
- hanging = 0;
- depthLimit=100;
-
- while(parent != dev->root_dir &&
- parent->parent &&
- parent->parent->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
- depthLimit > 0){
- parent = parent->parent;
- depthLimit--;
- }
- if(parent != dev->root_dir)
- hanging = 1;
- }
- if(hanging){
- T(YAFFS_TRACE_SCAN,
- (TSTR("Hanging object %d moved to lost and found" TENDSTR),
- obj->obj_id));
- yaffs_add_obj_to_dir(dev->lost_n_found,obj);
- }
+ }
+ if (hanging) {
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "Hanging object %d moved to lost and found",
+ obj->obj_id);
+ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
}
}
}
}
-
/*
* Delete directory contents for cleaning up lost and found.
*/
-static void yaffs_del_dir_contents(yaffs_obj_t *dir)
-{
- yaffs_obj_t *obj;
- struct ylist_head *lh;
- struct ylist_head *n;
-
- 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);
- if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
- yaffs_del_dir_contents(obj);
-
- T(YAFFS_TRACE_SCAN,
- (TSTR("Deleting lost_found object %d" TENDSTR),
- obj->obj_id));
-
- /* Need to use UnlinkObject since Delete would not handle
- * hardlinked objects correctly.
- */
- yaffs_unlink_obj(obj);
- }
- }
-
-}
-
-static void yaffs_empty_l_n_f(yaffs_dev_t *dev)
-{
- yaffs_del_dir_contents(dev->lost_n_found);
-}
-
-static void yaffs_check_obj_details_loaded(yaffs_obj_t *in)
-{
- __u8 *chunkData;
- yaffs_obj_header *oh;
- yaffs_dev_t *dev;
- yaffs_ext_tags tags;
- int result;
- int alloc_failed = 0;
-
- if (!in)
- return;
-
- dev = in->my_dev;
-
-#if 0
- T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
- in->obj_id,
- in->lazy_loaded ? "not yet" : "already"));
-#endif
-
- if (in->lazy_loaded && in->hdr_chunk > 0) {
- in->lazy_loaded = 0;
- chunkData = yaffs_get_temp_buffer(dev, __LINE__);
-
- result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, chunkData, &tags);
- oh = (yaffs_obj_header *) chunkData;
-
- in->yst_mode = oh->yst_mode;
-#ifdef CONFIG_YAFFS_WINCE
- in->win_atime[0] = oh->win_atime[0];
- in->win_ctime[0] = oh->win_ctime[0];
- in->win_mtime[0] = oh->win_mtime[0];
- in->win_atime[1] = oh->win_atime[1];
- in->win_ctime[1] = oh->win_ctime[1];
- in->win_mtime[1] = oh->win_mtime[1];
-#else
- in->yst_uid = oh->yst_uid;
- in->yst_gid = oh->yst_gid;
- in->yst_atime = oh->yst_atime;
- in->yst_mtime = oh->yst_mtime;
- in->yst_ctime = oh->yst_ctime;
- in->yst_rdev = oh->yst_rdev;
-
-#endif
- yaffs_set_obj_name_from_oh(in, oh);
-
- if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
- in->variant.symlink_variant.alias =
- yaffs_clone_str(oh->alias);
- if (!in->variant.symlink_variant.alias)
- alloc_failed = 1; /* Not returned to caller */
- }
-
- yaffs_release_temp_buffer(dev, chunkData, __LINE__);
- }
-}
-
-/*------------------------------ Directory Functions ----------------------------- */
-
-/*
- *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
- * link (ie. name) is created or deleted in the directory.
- *
- * ie.
- * create dir/a : update dir's mtime/ctime
- * rm dir/a: update dir's mtime/ctime
- * modify dir/a: don't update dir's mtimme/ctime
- *
- * This can be handled immediately or defered. Defering helps reduce the number
- * of updates when many files in a directory are changed within a brief period.
- *
- * 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;
- if(!obj)
- return;
-#ifndef CONFIG_YAFFS_WINCE
-
- dev = obj->my_dev;
- 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;
-
- 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));
- }
-
- } else
- yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
-#endif
-}
-
-void yaffs_update_dirty_dirs(yaffs_dev_t *dev)
+static void yaffs_del_dir_contents(struct yaffs_obj *dir)
{
- struct ylist_head *link;
- yaffs_obj_t *obj;
- yaffs_dir_s *dS;
- yaffs_obj_variant *oV;
-
- T(YAFFS_TRACE_BACKGROUND, (TSTR("Update dirty directories" TENDSTR)));
+ struct yaffs_obj *obj;
+ struct list_head *lh;
+ struct list_head *n;
- 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);
-
- T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->obj_id));
+ if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+ BUG();
- if(obj->dirty)
- yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
+ list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
+ obj = list_entry(lh, struct yaffs_obj, siblings);
+ if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
+ yaffs_del_dir_contents(obj);
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "Deleting lost_found object %d",
+ obj->obj_id);
+ yaffs_unlink_obj(obj);
}
}
-static void yaffs_remove_obj_from_dir(yaffs_obj_t *obj)
-{
- yaffs_dev_t *dev = obj->my_dev;
- yaffs_obj_t *parent;
-
- yaffs_verify_obj_in_dir(obj);
- parent = obj->parent;
-
- yaffs_verify_dir(parent);
-
- if (dev && dev->param.remove_obj_fn)
- dev->param.remove_obj_fn(obj);
-
-
- ylist_del_init(&obj->siblings);
- obj->parent = NULL;
-
- yaffs_verify_dir(parent);
-}
-
-void yaffs_add_obj_to_dir(yaffs_obj_t *directory,
- yaffs_obj_t *obj)
-{
- if (!directory) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR
- ("tragedy: Trying to add an object to a null pointer directory"
- TENDSTR)));
- YBUG();
- return;
- }
- if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR
- ("tragedy: Trying to add an object to a non-directory"
- TENDSTR)));
- YBUG();
- }
-
- if (obj->siblings.prev == NULL) {
- /* Not initialised */
- YBUG();
- }
-
-
- yaffs_verify_dir(directory);
-
- yaffs_remove_obj_from_dir(obj);
-
-
- /* Now add it */
- ylist_add(&obj->siblings, &directory->variant.dir_variant.children);
- obj->parent = directory;
-
- if (directory == obj->my_dev->unlinked_dir
- || directory == obj->my_dev->del_dir) {
- obj->unlinked = 1;
- obj->my_dev->n_unlinked_files++;
- obj->rename_allowed = 0;
- }
-
- yaffs_verify_dir(directory);
- yaffs_verify_obj_in_dir(obj);
+static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
+{
+ yaffs_del_dir_contents(dev->lost_n_found);
}
-yaffs_obj_t *yaffs_find_by_name(yaffs_obj_t *directory,
+
+struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
const YCHAR *name)
{
int sum;
-
- struct ylist_head *i;
+ struct list_head *i;
YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
-
- yaffs_obj_t *l;
+ struct yaffs_obj *l;
if (!name)
return NULL;
if (!directory) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR
- ("tragedy: yaffs_find_by_name: null pointer directory"
- TENDSTR)));
- YBUG();
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "tragedy: yaffs_find_by_name: null pointer directory"
+ );
+ BUG();
return NULL;
}
if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR
- ("tragedy: yaffs_find_by_name: non-directory" TENDSTR)));
- YBUG();
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "tragedy: yaffs_find_by_name: non-directory"
+ );
+ BUG();
}
sum = yaffs_calc_name_sum(name);
- ylist_for_each(i, &directory->variant.dir_variant.children) {
- if (i) {
- l = ylist_entry(i, yaffs_obj_t, siblings);
+ list_for_each(i, &directory->variant.dir_variant.children) {
+ l = list_entry(i, struct yaffs_obj, siblings);
- if (l->parent != directory)
- YBUG();
+ if (l->parent != directory)
+ BUG();
- yaffs_check_obj_details_loaded(l);
+ yaffs_check_obj_details_loaded(l);
- /* Special case for lost-n-found */
- if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
- if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0)
- return l;
- } else if (yaffs_sum_cmp(l->sum, sum) || l->hdr_chunk <= 0) {
- /* LostnFound chunk called Objxxx
- * Do a real check
- */
- yaffs_get_obj_name(l, buffer,
- YAFFS_MAX_NAME_LENGTH + 1);
- if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
- return l;
- }
+ /* Special case for lost-n-found */
+ if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
+ if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))
+ return l;
+ } else if (l->sum == sum || l->hdr_chunk <= 0) {
+ /* LostnFound chunk called Objxxx
+ * Do a real check
+ */
+ yaffs_get_obj_name(l, buffer,
+ YAFFS_MAX_NAME_LENGTH + 1);
+ if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH))
+ return l;
}
}
-
return NULL;
}
-
-#if 0
-int yaffs_ApplyToDirectoryChildren(yaffs_obj_t *the_dir,
- int (*fn) (yaffs_obj_t *))
-{
- struct ylist_head *i;
- yaffs_obj_t *l;
-
- if (!the_dir) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR
- ("tragedy: yaffs_find_by_name: null pointer directory"
- TENDSTR)));
- YBUG();
- return YAFFS_FAIL;
- }
- if (the_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR
- ("tragedy: yaffs_find_by_name: non-directory" TENDSTR)));
- YBUG();
- return YAFFS_FAIL;
- }
-
- ylist_for_each(i, &the_dir->variant.dir_variant.children) {
- if (i) {
- l = ylist_entry(i, yaffs_obj_t, siblings);
- if (l && !fn(l))
- return YAFFS_FAIL;
- }
- }
-
- return YAFFS_OK;
-
-}
-#endif
-
/* GetEquivalentObject dereferences any hard links to get to the
* actual object.
*/
-yaffs_obj_t *yaffs_get_equivalent_obj(yaffs_obj_t *obj)
+struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
{
if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
- /* We want the object id of the equivalent object, not this one */
obj = obj->variant.hardlink_variant.equiv_obj;
yaffs_check_obj_details_loaded(obj);
}
* 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].
*/
-static void yaffs_fix_null_name(yaffs_obj_t * obj,YCHAR * name, int buffer_size)
+static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
+ int buffer_size)
{
/* Create an object name if we could not find one. */
- if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){
- YCHAR locName[20];
- YCHAR numString[20];
- YCHAR *x = &numString[19];
+ if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
+ YCHAR local_name[20];
+ YCHAR num_string[20];
+ YCHAR *x = &num_string[19];
unsigned v = obj->obj_id;
- numString[19] = 0;
- while(v>0){
+ num_string[19] = 0;
+ while (v > 0) {
x--;
*x = '0' + (v % 10);
v /= 10;
}
/* make up a name */
- yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
- yaffs_strcat(locName,x);
- yaffs_strncpy(name, locName, buffer_size - 1);
- }
-}
-
-static void yaffs_load_name_from_oh(yaffs_dev_t *dev,YCHAR *name, const YCHAR *ohName, int bufferSize)
-{
-#ifdef CONFIG_YAFFS_AUTO_UNICODE
- if(dev->param.auto_unicode){
- if(*ohName){
- /* It is an ASCII name, so do an ASCII to unicode conversion */
- const char *asciiOhName = (const char *)ohName;
- int n = bufferSize - 1;
- while(n > 0 && *asciiOhName){
- *name = *asciiOhName;
- name++;
- asciiOhName++;
- n--;
- }
- } else
- yaffs_strncpy(name,ohName+1, bufferSize -1);
- } else
-#endif
- yaffs_strncpy(name, ohName, bufferSize - 1);
-}
-
-
-static void yaffs_load_oh_from_name(yaffs_dev_t *dev, YCHAR *ohName, const YCHAR *name)
-{
-#ifdef CONFIG_YAFFS_AUTO_UNICODE
-
- int isAscii;
- YCHAR *w;
-
- if(dev->param.auto_unicode){
-
- isAscii = 1;
- w = name;
-
- /* Figure out if the name will fit in ascii character set */
- while(isAscii && *w){
- if((*w) & 0xff00)
- isAscii = 0;
- w++;
- }
-
- if(isAscii){
- /* It is an ASCII name, so do a unicode to ascii conversion */
- char *asciiOhName = (char *)ohName;
- int n = YAFFS_MAX_NAME_LENGTH - 1;
- while(n > 0 && *name){
- *asciiOhName= *name;
- name++;
- asciiOhName++;
- n--;
- }
- } else{
- /* It is a unicode name, so save starting at the second YCHAR */
- *ohName = 0;
- yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2);
- }
+ strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
+ strcat(local_name, x);
+ strncpy(name, local_name, buffer_size - 1);
}
- else
-#endif
- yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1);
-
}
-int yaffs_get_obj_name(yaffs_obj_t * obj, YCHAR * name, int buffer_size)
+int yaffs_get_obj_name(struct yaffs_obj *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);
- }
-#endif
- else if(obj->hdr_chunk > 0) {
+ strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
+ } else if (obj->short_name[0]) {
+ strcpy(name, obj->short_name);
+ } else if (obj->hdr_chunk > 0) {
int result;
- __u8 *buffer = yaffs_get_temp_buffer(obj->my_dev, __LINE__);
+ u8 *buffer = yaffs_get_temp_buffer(obj->my_dev);
- yaffs_obj_header *oh = (yaffs_obj_header *) buffer;
+ struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
if (obj->hdr_chunk > 0) {
result = yaffs_rd_chunk_tags_nand(obj->my_dev,
- obj->hdr_chunk, buffer,
- NULL);
+ obj->hdr_chunk,
+ buffer, NULL);
}
- yaffs_load_name_from_oh(obj->my_dev,name,oh->name,buffer_size);
+ yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
+ buffer_size);
- yaffs_release_temp_buffer(obj->my_dev, buffer, __LINE__);
+ yaffs_release_temp_buffer(obj->my_dev, buffer);
}
- yaffs_fix_null_name(obj,name,buffer_size);
+ yaffs_fix_null_name(obj, name, buffer_size);
- return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH);
+ return strnlen(name, YAFFS_MAX_NAME_LENGTH);
}
-
-int yaffs_get_obj_length(yaffs_obj_t *obj)
+loff_t yaffs_get_obj_length(struct yaffs_obj *obj)
{
/* Dereference any hard linking */
obj = yaffs_get_equivalent_obj(obj);
if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
return obj->variant.file_variant.file_size;
- if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK){
- if(!obj->variant.symlink_variant.alias)
+ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
+ if (!obj->variant.symlink_variant.alias)
return 0;
- return yaffs_strnlen(obj->variant.symlink_variant.alias,YAFFS_MAX_ALIAS_LENGTH);
+ return strnlen(obj->variant.symlink_variant.alias,
+ YAFFS_MAX_ALIAS_LENGTH);
} else {
/* Only a directory should drop through to here */
return obj->my_dev->data_bytes_per_chunk;
}
}
-int yaffs_get_obj_link_count(yaffs_obj_t *obj)
+int yaffs_get_obj_link_count(struct yaffs_obj *obj)
{
int count = 0;
- struct ylist_head *i;
+ struct list_head *i;
if (!obj->unlinked)
- count++; /* the object itself */
+ count++; /* the object itself */
- ylist_for_each(i, &obj->hard_links)
- count++; /* add the hard links; */
+ list_for_each(i, &obj->hard_links)
+ count++; /* add the hard links; */
return count;
}
-int yaffs_get_obj_inode(yaffs_obj_t *obj)
+int yaffs_get_obj_inode(struct yaffs_obj *obj)
{
obj = yaffs_get_equivalent_obj(obj);
return obj->obj_id;
}
-unsigned yaffs_get_obj_type(yaffs_obj_t *obj)
+unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
{
obj = yaffs_get_equivalent_obj(obj);
return DT_BLK;
if (S_ISSOCK(obj->yst_mode))
return DT_SOCK;
+ return DT_REG;
+ break;
default:
return DT_REG;
break;
}
}
-YCHAR *yaffs_get_symlink_alias(yaffs_obj_t *obj)
+YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
{
obj = yaffs_get_equivalent_obj(obj);
if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
return yaffs_clone_str(_Y(""));
}
-#ifndef CONFIG_YAFFS_WINCE
-
-int yaffs_set_attribs(yaffs_obj_t *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(yaffs_obj_t *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;
-}
-
-#endif
-
-
-static int yaffs_do_xattrib_mod(yaffs_obj_t *obj, int set, const YCHAR *name, const void *value, int size, int flags)
-{
- yaffs_xattr_mod xmod;
-
- int result;
-
- xmod.set = set;
- xmod.name = name;
- xmod.data = value;
- xmod.size = size;
- xmod.flags = flags;
- xmod.result = -ENOSPC;
-
- result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
-
- if(result > 0)
- return xmod.result;
- else
- return -ENOSPC;
-}
-
-static int yaffs_apply_xattrib_mod(yaffs_obj_t *obj, char *buffer, yaffs_xattr_mod *xmod)
-{
- int retval = 0;
- int x_offs = sizeof(yaffs_obj_header);
- yaffs_dev_t *dev = obj->my_dev;
- int x_size = dev->data_bytes_per_chunk - sizeof(yaffs_obj_header);
-
- char * x_buffer = buffer + x_offs;
-
- if(xmod->set)
- retval = nval_set(x_buffer, x_size, xmod->name, xmod->data, xmod->size, xmod->flags);
- else
- retval = nval_del(x_buffer, x_size, xmod->name);
-
- obj->has_xattr = nval_hasvalues(x_buffer, x_size);
- obj->xattr_known = 1;
-
- xmod->result = retval;
-
- return retval;
-}
-
-static int yaffs_do_xattrib_fetch(yaffs_obj_t *obj, const YCHAR *name, void *value, int size)
-{
- char *buffer = NULL;
- int result;
- yaffs_ext_tags tags;
- yaffs_dev_t *dev = obj->my_dev;
- int x_offs = sizeof(yaffs_obj_header);
- int x_size = dev->data_bytes_per_chunk - sizeof(yaffs_obj_header);
-
- char * x_buffer;
-
- int retval = 0;
-
- if(obj->hdr_chunk < 1)
- return -ENODATA;
-
- /* If we know that the object has no xattribs then don't do all the
- * reading and parsing.
- */
- if(obj->xattr_known && !obj->has_xattr){
- if(name)
- return -ENODATA;
- else
- return 0;
- }
-
- buffer = (char *) yaffs_get_temp_buffer(dev, __LINE__);
- if(!buffer)
- return -ENOMEM;
-
- result = yaffs_rd_chunk_tags_nand(dev,obj->hdr_chunk, (__u8 *)buffer, &tags);
-
- if(result != YAFFS_OK)
- retval = -ENOENT;
- else{
- x_buffer = buffer + x_offs;
-
- if (!obj->xattr_known){
- obj->has_xattr = nval_hasvalues(x_buffer, x_size);
- obj->xattr_known = 1;
- }
-
- if(name)
- retval = nval_get(x_buffer, x_size, name, value, size);
- else
- retval = nval_list(x_buffer, x_size, value,size);
- }
- yaffs_release_temp_buffer(dev,(__u8 *)buffer,__LINE__);
- return retval;
-}
-
-int yaffs_set_xattrib(yaffs_obj_t *obj, const YCHAR *name, const void * value, int size, int flags)
-{
- return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
-}
-
-int yaffs_remove_xattrib(yaffs_obj_t *obj, const YCHAR *name)
-{
- return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
-}
-
-int yaffs_get_xattrib(yaffs_obj_t *obj, const YCHAR *name, void *value, int size)
-{
- return yaffs_do_xattrib_fetch(obj, name, value, size);
-}
-
-int yaffs_list_xattrib(yaffs_obj_t *obj, char *buffer, int size)
-{
- return yaffs_do_xattrib_fetch(obj, NULL, buffer,size);
-}
-
-
-
-#if 0
-int yaffs_dump_obj(yaffs_obj_t *obj)
-{
- YCHAR name[257];
-
- yaffs_get_obj_name(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
-
- T(YAFFS_TRACE_ALWAYS,
- (TSTR
- ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d"
- " chunk %d type %d size %d\n"
- TENDSTR), obj->obj_id, yaffs_get_obj_inode(obj), name,
- obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdr_chunk,
- yaffs_get_obj_type(obj), yaffs_get_obj_length(obj)));
-
- return YAFFS_OK;
-}
-#endif
-
-/*---------------------------- Initialisation code -------------------------------------- */
+/*--------------------------- Initialisation code -------------------------- */
-static int yaffs_cehck_dev_fns(const yaffs_dev_t *dev)
+static int yaffs_check_dev_fns(struct yaffs_dev *dev)
{
+ struct yaffs_driver *drv = &dev->drv;
+ struct yaffs_tags_handler *tagger = &dev->tagger;
/* Common functions, gotta have */
- if (!dev->param.erase_fn || !dev->param.initialise_flash_fn)
+ if (!drv->drv_read_chunk_fn ||
+ !drv->drv_write_chunk_fn ||
+ !drv->drv_erase_fn)
return 0;
-#ifdef CONFIG_YAFFS_YAFFS2
+ if (dev->param.is_yaffs2 &&
+ (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn))
+ return 0;
- /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
- if (dev->param.write_chunk_tags_fn &&
- dev->param.read_chunk_tags_fn &&
- !dev->param.write_chunk_fn &&
- !dev->param.read_chunk_fn &&
- dev->param.bad_block_fn &&
- dev->param.query_block_fn)
- return 1;
-#endif
+ /* Install the default tags marshalling functions if needed. */
+ yaffs_tags_compat_install(dev);
+ yaffs_tags_marshall_install(dev);
- /* Can use the "spare" style interface for yaffs1 */
- if (!dev->param.is_yaffs2 &&
- !dev->param.write_chunk_tags_fn &&
- !dev->param.read_chunk_tags_fn &&
- dev->param.write_chunk_fn &&
- dev->param.read_chunk_fn &&
- !dev->param.bad_block_fn &&
- !dev->param.query_block_fn)
- return 1;
+ /* Check we now have the marshalling functions required. */
+ if (!tagger->write_chunk_tags_fn ||
+ !tagger->read_chunk_tags_fn ||
+ !tagger->query_block_fn ||
+ !tagger->mark_bad_fn)
+ return 0;
- return 0; /* bad */
+ return 1;
}
-
-static int yaffs_create_initial_dir(yaffs_dev_t *dev)
+static int yaffs_create_initial_dir(struct yaffs_dev *dev)
{
- /* Initialise the unlinked, deleted, root and lost and found directories */
-
- dev->lost_n_found = dev->root_dir = NULL;
+ /* Initialise the unlinked, deleted, root and lost+found directories */
+ dev->lost_n_found = dev->root_dir = NULL;
dev->unlinked_dir = dev->del_dir = NULL;
-
dev->unlinked_dir =
yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
-
dev->del_dir =
yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
-
dev->root_dir =
yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
- YAFFS_ROOT_MODE | S_IFDIR);
+ YAFFS_ROOT_MODE | S_IFDIR);
dev->lost_n_found =
yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
- YAFFS_LOSTNFOUND_MODE | S_IFDIR);
+ YAFFS_LOSTNFOUND_MODE | S_IFDIR);
- if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir && dev->del_dir) {
+ if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
+ && dev->del_dir) {
yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
return YAFFS_OK;
}
-
return YAFFS_FAIL;
}
-int yaffs_guts_initialise(yaffs_dev_t *dev)
+/* Low level init.
+ * Typically only used by yaffs_guts_initialise, but also used by the
+ * Low level yaffs driver tests.
+ */
+
+int yaffs_guts_ll_init(struct yaffs_dev *dev)
{
- int init_failed = 0;
- unsigned x;
- int bits;
- T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_guts_initialise()" TENDSTR)));
- /* Check stuff that must be set */
+ yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()");
if (!dev) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Need a device" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs: Need a device"
+ );
return YAFFS_FAIL;
}
+ if (dev->ll_init)
+ return YAFFS_OK;
+
dev->internal_start_block = dev->param.start_block;
dev->internal_end_block = dev->param.end_block;
dev->block_offset = 0;
/* Check geometry parameters. */
- if ((!dev->param.inband_tags && dev->param.is_yaffs2 && dev->param.total_bytes_per_chunk < 1024) ||
- (!dev->param.is_yaffs2 && dev->param.total_bytes_per_chunk < 512) ||
- (dev->param.inband_tags && !dev->param.is_yaffs2) ||
- dev->param.chunks_per_block < 2 ||
- dev->param.n_reserved_blocks < 2 ||
- dev->internal_start_block <= 0 ||
- dev->internal_end_block <= 0 ||
- dev->internal_end_block <= (dev->internal_start_block + dev->param.n_reserved_blocks + 2)) { /* otherwise it is too small */
- T(YAFFS_TRACE_ALWAYS,
- (TSTR
- ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d "
- TENDSTR), dev->param.total_bytes_per_chunk, dev->param.is_yaffs2 ? "2" : "", dev->param.inband_tags));
- return YAFFS_FAIL;
- }
-
- if (yaffs_init_nand(dev) != YAFFS_OK) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
+ if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&
+ dev->param.total_bytes_per_chunk < 1024) ||
+ (!dev->param.is_yaffs2 &&
+ dev->param.total_bytes_per_chunk < 512) ||
+ (dev->param.inband_tags && !dev->param.is_yaffs2) ||
+ dev->param.chunks_per_block < 2 ||
+ dev->param.n_reserved_blocks < 2 ||
+ dev->internal_start_block <= 0 ||
+ dev->internal_end_block <= 0 ||
+ dev->internal_end_block <=
+ (dev->internal_start_block + dev->param.n_reserved_blocks + 2)
+ ) {
+ /* otherwise it is too small */
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",
+ dev->param.total_bytes_per_chunk,
+ dev->param.is_yaffs2 ? "2" : "",
+ dev->param.inband_tags);
return YAFFS_FAIL;
}
/* Sort out space for inband tags, if required */
if (dev->param.inband_tags)
- dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk - sizeof(yaffs_PackedTags2TagsPart);
+ dev->data_bytes_per_chunk =
+ dev->param.total_bytes_per_chunk -
+ sizeof(struct yaffs_packed_tags2_tags_only);
else
dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
/* Got the right mix of functions? */
- if (!yaffs_cehck_dev_fns(dev)) {
+ if (!yaffs_check_dev_fns(dev)) {
/* Function missing */
- T(YAFFS_TRACE_ALWAYS,
- (TSTR
- ("yaffs: device function(s) missing or wrong\n" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "device function(s) missing or wrong");
return YAFFS_FAIL;
}
- /* This is really a compilation check. */
- if (!yaffs_check_structures()) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs_check_structures failed\n" TENDSTR)));
+ if (yaffs_init_nand(dev) != YAFFS_OK) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
return YAFFS_FAIL;
}
- if (dev->is_mounted) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: device already mounted\n" TENDSTR)));
+ return YAFFS_OK;
+}
+
+
+int yaffs_format_dev(struct yaffs_dev *dev)
+{
+ int i;
+ enum yaffs_block_state state;
+ u32 dummy;
+
+ if(yaffs_guts_ll_init(dev) != YAFFS_OK)
+ return YAFFS_FAIL;
+
+ if(dev->is_mounted)
return YAFFS_FAIL;
+
+ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+ yaffs_query_init_block_state(dev, i, &state, &dummy);
+ if (state != YAFFS_BLOCK_STATE_DEAD)
+ yaffs_erase_block(dev, i);
}
- /* Finished with most checks. One or two more checks happen later on too. */
+ return YAFFS_OK;
+}
+
+
+int yaffs_guts_initialise(struct yaffs_dev *dev)
+{
+ int init_failed = 0;
+ unsigned x;
+ int bits;
+
+ if(yaffs_guts_ll_init(dev) != YAFFS_OK)
+ return YAFFS_FAIL;
+
+ if (dev->is_mounted) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
+ return YAFFS_FAIL;
+ }
dev->is_mounted = 1;
*/
x = dev->data_bytes_per_chunk;
/* We always use dev->chunk_shift and dev->chunk_div */
- dev->chunk_shift = Shifts(x);
+ dev->chunk_shift = calc_shifts(x);
x >>= dev->chunk_shift;
dev->chunk_div = x;
/* We only use chunk mask if chunk_div is 1 */
- dev->chunk_mask = (1<<dev->chunk_shift) - 1;
+ dev->chunk_mask = (1 << dev->chunk_shift) - 1;
/*
* Calculate chunk_grp_bits.
x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
- bits = ShiftsGE(x);
+ bits = calc_shifts_ceiling(x);
/* Set up tnode width if wide tnodes are enabled. */
if (!dev->param.wide_tnodes_disabled) {
dev->tnode_width = 16;
else
dev->tnode_width = bits;
- } else
+ } else {
dev->tnode_width = 16;
+ }
- dev->tnode_mask = (1<<dev->tnode_width)-1;
+ dev->tnode_mask = (1 << dev->tnode_width) - 1;
/* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
* so if the bitwidth of the
else
dev->chunk_grp_bits = bits - dev->tnode_width;
- dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0)/8;
- if(dev->tnode_size < sizeof(yaffs_tnode_t))
- dev->tnode_size = sizeof(yaffs_tnode_t);
+ dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
+ if (dev->tnode_size < sizeof(struct yaffs_tnode))
+ dev->tnode_size = sizeof(struct yaffs_tnode);
dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
* the chunk group size > chunks per block.
* This can be remedied by using larger "virtual blocks".
*/
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: chunk group too large\n" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");
return YAFFS_FAIL;
}
- /* OK, we've finished verifying the device, lets continue with initialisation */
+ /* Finished verifying the device, continue with initialisation */
/* More device initialisation */
dev->all_gcs = 0;
dev->n_tags_ecc_unfixed = 0;
dev->n_erase_failures = 0;
dev->n_erased_blocks = 0;
- dev->gc_disable= 0;
- dev->has_pending_prioritised_gc = 1; /* Assume the worst for now, will get fixed on first GC */
- YINIT_LIST_HEAD(&dev->dirty_dirs);
+ dev->gc_disable = 0;
+ dev->has_pending_prioritised_gc = 1;
+ /* Assume the worst for now, will get fixed on first GC */
+ INIT_LIST_HEAD(&dev->dirty_dirs);
dev->oldest_dirty_seq = 0;
dev->oldest_dirty_block = 0;
dev->cache = NULL;
dev->gc_cleanup_list = NULL;
-
- if (!init_failed &&
- dev->param.n_caches > 0) {
+ if (!init_failed && dev->param.n_caches > 0) {
int i;
void *buf;
- int cacheBytes = dev->param.n_caches * sizeof(yaffs_cache_t);
+ int cache_bytes =
+ dev->param.n_caches * sizeof(struct yaffs_cache);
if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
- dev->cache = YMALLOC(cacheBytes);
+ dev->cache = kmalloc(cache_bytes, GFP_NOFS);
- buf = (__u8 *) dev->cache;
+ buf = (u8 *) dev->cache;
if (dev->cache)
- memset(dev->cache, 0, cacheBytes);
+ memset(dev->cache, 0, cache_bytes);
for (i = 0; i < dev->param.n_caches && buf; i++) {
dev->cache[i].object = NULL;
dev->cache[i].last_use = 0;
dev->cache[i].dirty = 0;
- dev->cache[i].data = buf = YMALLOC_DMA(dev->param.total_bytes_per_chunk);
+ dev->cache[i].data = buf =
+ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
}
if (!buf)
init_failed = 1;
dev->cache_hits = 0;
if (!init_failed) {
- dev->gc_cleanup_list = YMALLOC(dev->param.chunks_per_block * sizeof(__u32));
+ dev->gc_cleanup_list =
+ kmalloc(dev->param.chunks_per_block * sizeof(u32),
+ GFP_NOFS);
if (!dev->gc_cleanup_list)
init_failed = 1;
}
if (!init_failed && !yaffs_create_initial_dir(dev))
init_failed = 1;
+ if (!init_failed && dev->param.is_yaffs2 &&
+ !dev->param.disable_summary &&
+ !yaffs_summary_init(dev))
+ init_failed = 1;
if (!init_failed) {
/* Now scan the flash. */
if (dev->param.is_yaffs2) {
if (yaffs2_checkpt_restore(dev)) {
yaffs_check_obj_details_loaded(dev->root_dir);
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: restored from checkpoint" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT |
+ YAFFS_TRACE_MOUNT,
+ "yaffs: restored from checkpoint"
+ );
} else {
- /* Clean up the mess caused by an aborted checkpoint load
- * and scan backwards.
+ /* Clean up the mess caused by an aborted
+ * checkpoint load then scan backwards.
*/
yaffs_deinit_blocks(dev);
yaffs_init_tnodes_and_objs(dev);
- if (!init_failed && !yaffs_create_initial_dir(dev))
+ if (!init_failed
+ && !yaffs_create_initial_dir(dev))
init_failed = 1;
if (!init_failed && !yaffs2_scan_backwards(dev))
init_failed = 1;
}
- } else if (!yaffs1_scan(dev))
- init_failed = 1;
+ } else if (!yaffs1_scan(dev)) {
+ init_failed = 1;
+ }
yaffs_strip_deleted_objs(dev);
yaffs_fix_hanging_objs(dev);
- if(dev->param.empty_lost_n_found)
+ if (dev->param.empty_lost_n_found)
yaffs_empty_l_n_f(dev);
}
if (init_failed) {
/* Clean up the mess */
- T(YAFFS_TRACE_TRACING,
- (TSTR("yaffs: yaffs_guts_initialise() aborted.\n" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_TRACING,
+ "yaffs: yaffs_guts_initialise() aborted.");
yaffs_deinitialise(dev);
return YAFFS_FAIL;
dev->n_page_writes = 0;
dev->n_erasures = 0;
dev->n_gc_copies = 0;
- dev->n_retired_writes = 0;
+ dev->n_retried_writes = 0;
dev->n_retired_blocks = 0;
yaffs_verify_blocks(dev);
/* Clean up any aborted checkpoint data */
- if(!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
+ if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
yaffs2_checkpt_invalidate(dev);
- T(YAFFS_TRACE_TRACING,
- (TSTR("yaffs: yaffs_guts_initialise() done.\n" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_TRACING,
+ "yaffs: yaffs_guts_initialise() done.");
return YAFFS_OK;
-
}
-void yaffs_deinitialise(yaffs_dev_t *dev)
+void yaffs_deinitialise(struct yaffs_dev *dev)
{
if (dev->is_mounted) {
int i;
yaffs_deinit_blocks(dev);
yaffs_deinit_tnodes_and_objs(dev);
- if (dev->param.n_caches > 0 &&
- dev->cache) {
+ yaffs_summary_deinit(dev);
+
+ if (dev->param.n_caches > 0 && dev->cache) {
for (i = 0; i < dev->param.n_caches; i++) {
- if (dev->cache[i].data)
- YFREE(dev->cache[i].data);
+ kfree(dev->cache[i].data);
dev->cache[i].data = NULL;
}
- YFREE(dev->cache);
+ kfree(dev->cache);
dev->cache = NULL;
}
- YFREE(dev->gc_cleanup_list);
+ kfree(dev->gc_cleanup_list);
for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
- YFREE(dev->temp_buffer[i].buffer);
+ kfree(dev->temp_buffer[i].buffer);
dev->is_mounted = 0;
- if (dev->param.deinitialise_flash_fn)
- dev->param.deinitialise_flash_fn(dev);
+ yaffs_deinit_nand(dev);
}
}
-int yaffs_count_free_chunks(yaffs_dev_t *dev)
+int yaffs_count_free_chunks(struct yaffs_dev *dev)
{
- int nFree=0;
+ int n_free = 0;
int b;
-
- yaffs_block_info_t *blk;
+ struct yaffs_block_info *blk;
blk = dev->block_info;
for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
case YAFFS_BLOCK_STATE_ALLOCATING:
case YAFFS_BLOCK_STATE_COLLECTING:
case YAFFS_BLOCK_STATE_FULL:
- nFree +=
+ n_free +=
(dev->param.chunks_per_block - blk->pages_in_use +
blk->soft_del_pages);
break;
}
blk++;
}
-
- return nFree;
+ return n_free;
}
-int yaffs_get_n_free_chunks(yaffs_dev_t *dev)
+int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
{
/* This is what we report to the outside world */
-
- int nFree;
- int nDirtyCacheChunks;
- int blocksForCheckpoint;
+ int n_free;
+ int n_dirty_caches;
+ int blocks_for_checkpt;
int i;
-#if 1
- nFree = dev->n_free_chunks;
-#else
- nFree = yaffs_count_free_chunks(dev);
-#endif
+ n_free = dev->n_free_chunks;
+ n_free += dev->n_deleted_files;
- nFree += dev->n_deleted_files;
+ /* Now count and subtract the number of dirty chunks in the cache. */
- /* Now count the number of dirty chunks in the cache and subtract those */
-
- for (nDirtyCacheChunks = 0, i = 0; i < dev->param.n_caches; i++) {
+ for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
if (dev->cache[i].dirty)
- nDirtyCacheChunks++;
+ n_dirty_caches++;
}
- nFree -= nDirtyCacheChunks;
+ n_free -= n_dirty_caches;
+
+ n_free -=
+ ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
- nFree -= ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
+ /* Now figure checkpoint space and report that... */
+ blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
- /* Now we figure out how much to reserve for the checkpoint and report that... */
- blocksForCheckpoint = yaffs_calc_checkpt_blocks_required(dev);
+ n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
- nFree -= (blocksForCheckpoint * dev->param.chunks_per_block);
+ if (n_free < 0)
+ n_free = 0;
+
+ return n_free;
+}
- if (nFree < 0)
- nFree = 0;
- return nFree;
+/*
+ * Marshalling functions to get loff_t file sizes into and out of
+ * object headers.
+ */
+void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
+{
+ oh->file_size_low = (fsize & 0xFFFFFFFF);
+ oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
}
+loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
+{
+ loff_t retval;
+
+ if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))
+ retval = (((loff_t) oh->file_size_high) << 32) |
+ (((loff_t) oh->file_size_low) & 0xFFFFFFFF);
+ else
+ retval = (loff_t) oh->file_size_low;
-/*---------------------------------------- YAFFS test code ----------------------*/
+ return retval;
+}
-#define yaffs_check_struct(structure, syze, name) \
- do { \
- if (sizeof(structure) != syze) { \
- T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
- name, syze, (int) sizeof(structure))); \
- return YAFFS_FAIL; \
- } \
- } while (0)
-static int yaffs_check_structures(void)
+void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10])
{
-/* yaffs_check_struct(yaffs_tags_t,8,"yaffs_tags_t"); */
-/* yaffs_check_struct(yaffs_tags_union_t,8,"yaffs_tags_union_t"); */
-/* yaffs_check_struct(yaffs_spare,16,"yaffs_spare"); */
-/* yaffs_check_struct(yaffs_tnode_t, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_tnode_t"); */
+ int i;
+ struct yaffs_block_info *bi;
+ int s;
-#ifndef CONFIG_YAFFS_WINCE
- yaffs_check_struct(yaffs_obj_header, 512, "yaffs_obj_header");
-#endif
- return YAFFS_OK;
+ for(i = 0; i < 10; i++)
+ bs[i] = 0;
+
+ for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+ bi = yaffs_get_block_info(dev, i);
+ s = bi->block_state;
+ if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN)
+ bs[0]++;
+ else
+ bs[s]++;
+ }
}
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#define __YAFFS_GUTS_H__
#include "yportenv.h"
-#include "devextras.h"
-#include "yaffs_list.h"
#define YAFFS_OK 1
#define YAFFS_FAIL 0
/* Give us a Y=0x59,
* Give us an A=0x41,
- * Give us an FF=0xFF
+ * Give us an FF=0xff
* Give us an S=0x53
* And what have we got...
*/
-#define YAFFS_MAGIC 0x5941FF53
+#define YAFFS_MAGIC 0x5941ff53
-#define YAFFS_NTNODES_LEVEL0 16
+/*
+ * Tnodes form a tree with the tnodes in "levels"
+ * Levels greater than 0 hold 8 slots which point to other tnodes.
+ * Those at level 0 hold 16 slots which point to chunks in NAND.
+ *
+ * A maximum level of 8 thust supports files of size up to:
+ *
+ * 2^(3*MAX_LEVEL+4)
+ *
+ * Thus a max level of 8 supports files with up to 2^^28 chunks which gives
+ * a maximum file size of around 512Gbytees with 2k chunks.
+ */
+#define YAFFS_NTNODES_LEVEL0 16
#define YAFFS_TNODES_LEVEL0_BITS 4
#define YAFFS_TNODES_LEVEL0_MASK 0xf
-#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
-#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
+#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
+#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
#define YAFFS_TNODES_INTERNAL_MASK 0x7
-#define YAFFS_TNODES_MAX_LEVEL 6
+#define YAFFS_TNODES_MAX_LEVEL 8
+#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \
+ YAFFS_TNODES_INTERNAL_BITS * \
+ YAFFS_TNODES_MAX_LEVEL)
+#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1)
+
+#define YAFFS_MAX_FILE_SIZE_32 0x7fffffff
-#ifndef CONFIG_YAFFS_NO_YAFFS1
+/* Constants for YAFFS1 mode */
#define YAFFS_BYTES_PER_SPARE 16
#define YAFFS_BYTES_PER_CHUNK 512
#define YAFFS_CHUNK_SIZE_SHIFT 9
#define YAFFS_CHUNKS_PER_BLOCK 32
-#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
-#endif
+#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
-#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
+#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
-#define YAFFS_MAX_CHUNK_ID 0x000FFFFF
#define YAFFS_ALLOCATION_NOBJECTS 100
#define YAFFS_NOBJECT_BUCKETS 256
-
#define YAFFS_OBJECT_SPACE 0x40000
-#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1)
+#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1)
-#define YAFFS_CHECKPOINT_VERSION 4
+/* Binary data version stamps */
+#define YAFFS_SUMMARY_VERSION 1
+#define YAFFS_CHECKPOINT_VERSION 7
#ifdef CONFIG_YAFFS_UNICODE
#define YAFFS_MAX_NAME_LENGTH 127
#define YAFFS_OBJECTID_UNLINKED 3
#define YAFFS_OBJECTID_DELETED 4
+/* Fake object Id for summary data */
+#define YAFFS_OBJECTID_SUMMARY 0x10
+
/* Pseudo object ids for checkpointing */
-#define YAFFS_OBJECTID_SB_HEADER 0x10
#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
-#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
-
+#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
#define YAFFS_MAX_SHORT_OP_CACHES 20
* The range is limited slightly to help distinguish bad numbers from good.
* This also allows us to perhaps in the future use special numbers for
* special purposes.
- * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,
+ * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
* and is a larger number than the lifetime of a 2GB device.
*/
#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
-#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00
+#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00
/* Special sequence number for bad block that failed to be marked bad */
-#define YAFFS_SEQUENCE_BAD_BLOCK 0xFFFF0000
+#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000
/* ChunkCache is used for short read/write operations.*/
-typedef struct {
- struct yaffs_obj_s *object;
+struct yaffs_cache {
+ struct yaffs_obj *object;
int chunk_id;
int last_use;
int dirty;
int n_bytes; /* Only valid if the cache is dirty */
int locked; /* Can't push out or flush while locked. */
- __u8 *data;
-} yaffs_cache_t;
-
-
+ u8 *data;
+};
-/* Tags structures in RAM
- * NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
- * the structure size will get blown out.
+/* yaffs1 tags structures in RAM
+ * NB This uses bitfield. Bitfields should not straddle a u32 boundary
+ * otherwise the structure size will get blown out.
*/
-#ifndef CONFIG_YAFFS_NO_YAFFS1
-typedef struct {
+struct yaffs_tags {
unsigned chunk_id:20;
unsigned serial_number:2;
unsigned n_bytes_lsb:10;
unsigned obj_id:18;
unsigned ecc:12;
unsigned n_bytes_msb:2;
-} yaffs_tags_t;
+};
-typedef union {
- yaffs_tags_t as_tags;
- __u8 as_bytes[8];
-} yaffs_tags_union_t;
+union yaffs_tags_union {
+ struct yaffs_tags as_tags;
+ u8 as_bytes[8];
+};
-#endif
/* Stuff used for extended tags in YAFFS2 */
-typedef enum {
+enum yaffs_ecc_result {
YAFFS_ECC_RESULT_UNKNOWN,
YAFFS_ECC_RESULT_NO_ERROR,
YAFFS_ECC_RESULT_FIXED,
YAFFS_ECC_RESULT_UNFIXED
-} yaffs_ecc_result;
+};
-typedef enum {
+enum yaffs_obj_type {
YAFFS_OBJECT_TYPE_UNKNOWN,
YAFFS_OBJECT_TYPE_FILE,
YAFFS_OBJECT_TYPE_SYMLINK,
YAFFS_OBJECT_TYPE_DIRECTORY,
YAFFS_OBJECT_TYPE_HARDLINK,
YAFFS_OBJECT_TYPE_SPECIAL
-} yaffs_obj_type;
+};
#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
-typedef struct {
-
- unsigned validity1;
+struct yaffs_ext_tags {
unsigned chunk_used; /* Status of the chunk: used or unused */
- unsigned obj_id; /* If 0 then this is not part of an object (unused) */
- unsigned chunk_id; /* If 0 then this is a header, else a data chunk */
+ unsigned obj_id; /* If 0 this is not used */
+ unsigned chunk_id; /* If 0 this is a header, else a data chunk */
unsigned n_bytes; /* Only valid for data chunks */
/* The following stuff only has meaning when we read */
- yaffs_ecc_result ecc_result;
+ enum yaffs_ecc_result ecc_result;
unsigned block_bad;
/* YAFFS 1 stuff */
/* Extra info if this is an object header (YAFFS2 only) */
- unsigned extra_available; /* There is extra info available if this is not zero */
+ unsigned extra_available; /* Extra info available if not zero */
unsigned extra_parent_id; /* The parent object */
unsigned extra_is_shrink; /* Is it a shrink header? */
- unsigned extra_shadows; /* Does this shadow another object? */
-
- yaffs_obj_type extra_obj_type; /* What object type? */
-
- unsigned extra_length; /* Length if it is a file */
- unsigned extra_equiv_id; /* Equivalent object Id if it is a hard link */
+ unsigned extra_shadows; /* Does this shadow another object? */
- unsigned validty1;
+ enum yaffs_obj_type extra_obj_type; /* What object type? */
-} yaffs_ext_tags;
+ loff_t extra_file_size; /* Length if it is a file */
+ unsigned extra_equiv_id; /* Equivalent object for a hard link */
+};
/* Spare structure for YAFFS1 */
-typedef struct {
- __u8 tb0;
- __u8 tb1;
- __u8 tb2;
- __u8 tb3;
- __u8 page_status; /* set to 0 to delete the chunk */
- __u8 block_status;
- __u8 tb4;
- __u8 tb5;
- __u8 ecc1[3];
- __u8 tb6;
- __u8 tb7;
- __u8 ecc2[3];
-} yaffs_spare;
+struct yaffs_spare {
+ u8 tb0;
+ u8 tb1;
+ u8 tb2;
+ u8 tb3;
+ u8 page_status; /* set to 0 to delete the chunk */
+ u8 block_status;
+ u8 tb4;
+ u8 tb5;
+ u8 ecc1[3];
+ u8 tb6;
+ u8 tb7;
+ u8 ecc2[3];
+};
/*Special structure for passing through to mtd */
struct yaffs_nand_spare {
- yaffs_spare spare;
+ struct yaffs_spare spare;
int eccres1;
int eccres2;
};
/* Block data in RAM */
-typedef enum {
+enum yaffs_block_state {
YAFFS_BLOCK_STATE_UNKNOWN = 0,
YAFFS_BLOCK_STATE_SCANNING,
- /* Being scanned */
-
- YAFFS_BLOCK_STATE_NEEDS_SCANNING,
- /* The block might have something on it (ie it is allocating or full, perhaps empty)
- * but it needs to be scanned to determine its true state.
- * This state is only valid during yaffs_Scan.
- * NB We tolerate empty because the pre-scanner might be incapable of deciding
- * However, if this state is returned on a YAFFS2 device, then we expect a sequence number
+ /* Being scanned */
+
+ YAFFS_BLOCK_STATE_NEEDS_SCAN,
+ /* The block might have something on it (ie it is allocating or full,
+ * perhaps empty) but it needs to be scanned to determine its true
+ * state.
+ * This state is only valid during scanning.
+ * NB We tolerate empty because the pre-scanner might be incapable of
+ * deciding
+ * However, if this state is returned on a YAFFS2 device,
+ * then we expect a sequence number
*/
YAFFS_BLOCK_STATE_EMPTY,
* At least one page holds valid data.
* This is the one currently being used for page
* allocation. Should never be more than one of these.
- * If a block is only partially allocated at mount it is treated as full.
+ * If a block is only partially allocated at mount it is treated as
+ * full.
*/
YAFFS_BLOCK_STATE_FULL,
/* All the pages in this block have been allocated.
- * If a block was only partially allocated when mounted we treat
- * it as fully allocated.
+ * If a block was only partially allocated when mounted we treat
+ * it as fully allocated.
*/
YAFFS_BLOCK_STATE_DIRTY,
/* This block is being garbage collected */
YAFFS_BLOCK_STATE_DEAD
- /* This block has failed and is not in use */
-} yaffs_block_state_t;
+ /* This block has failed and is not in use */
+};
#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
-
-typedef struct {
+struct yaffs_block_info {
int soft_del_pages:10; /* number of soft deleted pages */
int pages_in_use:10; /* number of pages in use */
- unsigned block_state:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
- __u32 needs_retiring:1; /* Data has failed on this block, need to get valid data off */
- /* and retire the block. */
- __u32 skip_erased_check:1; /* If this is set we can skip the erased check on this block */
- __u32 gc_prioritise:1; /* An ECC check or blank check has failed on this block.
- It should be prioritised for GC */
- __u32 chunk_error_strikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
-
-#ifdef CONFIG_YAFFS_YAFFS2
- __u32 has_shrink_hdr:1; /* This block has at least one shrink object header */
- __u32 seq_number; /* block sequence number for yaffs2 */
-#endif
+ unsigned block_state:4; /* One of the above block states. */
+ /* NB use unsigned because enum is sometimes
+ * an int */
+ u32 needs_retiring:1; /* Data has failed on this block, */
+ /*need to get valid data off and retire*/
+ u32 skip_erased_check:1;/* Skip the erased check on this block */
+ u32 gc_prioritise:1; /* An ECC check or blank check has failed.
+ Block should be prioritised for GC */
+ u32 chunk_error_strikes:3; /* How many times we've had ecc etc
+ failures on this block and tried to reuse it */
+ u32 has_summary:1; /* The block has a summary */
+
+ u32 has_shrink_hdr:1; /* This block has at least one shrink header */
+ u32 seq_number; /* block sequence number for yaffs2 */
-} yaffs_block_info_t;
+};
/* -------------------------- Object structure -------------------------------*/
/* This is the object structure as stored on NAND */
-typedef struct {
- yaffs_obj_type type;
+struct yaffs_obj_hdr {
+ enum yaffs_obj_type type;
/* Apply to everything */
int parent_obj_id;
- __u16 sum_no_longer_used; /* checksum of name. No longer used */
+ u16 sum_no_longer_used; /* checksum of name. No longer used */
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
- /* The following apply to directories, files, symlinks - not hard links */
- __u32 yst_mode; /* protection */
+ /* The following apply to all object types except for hard links */
+ u32 yst_mode; /* protection */
-#ifdef CONFIG_YAFFS_WINCE
- __u32 not_for_wince[5];
-#else
- __u32 yst_uid;
- __u32 yst_gid;
- __u32 yst_atime;
- __u32 yst_mtime;
- __u32 yst_ctime;
-#endif
+ u32 yst_uid;
+ u32 yst_gid;
+ u32 yst_atime;
+ u32 yst_mtime;
+ u32 yst_ctime;
/* File size applies to files only */
- int file_size;
+ u32 file_size_low;
/* Equivalent object id applies to hard links only. */
int equiv_id;
/* Alias is for symlinks only. */
YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
- __u32 yst_rdev; /* device stuff for block and char devices (major/min) */
+ u32 yst_rdev; /* stuff for block and char devices (major/min) */
-#ifdef CONFIG_YAFFS_WINCE
- __u32 win_ctime[2];
- __u32 win_atime[2];
- __u32 win_mtime[2];
-#else
- __u32 room_to_grow[6];
+ u32 win_ctime[2];
+ u32 win_atime[2];
+ u32 win_mtime[2];
-#endif
- __u32 inband_shadowed_obj_id;
- __u32 inband_is_shrink;
+ u32 inband_shadowed_obj_id;
+ u32 inband_is_shrink;
- __u32 reserved[2];
- int shadows_obj; /* This object header shadows the specified object if > 0 */
+ u32 file_size_high;
+ u32 reserved[1];
+ int shadows_obj; /* This object header shadows the
+ specified object if > 0 */
- /* is_shrink applies to object headers written when we shrink the file (ie resize) */
- __u32 is_shrink;
+ /* is_shrink applies to object headers written when wemake a hole. */
+ u32 is_shrink;
-} yaffs_obj_header;
+};
/*--------------------------- Tnode -------------------------- */
-union yaffs_tnode_union {
- union yaffs_tnode_union *internal[YAFFS_NTNODES_INTERNAL];
-
+struct yaffs_tnode {
+ struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
};
-typedef union yaffs_tnode_union yaffs_tnode_t;
-
-
/*------------------------ Object -----------------------------*/
/* An object can be one of:
* - a directory (no data, has children links
* - a hard link
*/
-typedef struct {
- __u32 file_size;
- __u32 scanned_size;
- __u32 shrink_size;
+struct yaffs_file_var {
+ loff_t file_size;
+ loff_t scanned_size;
+ loff_t shrink_size;
int top_level;
- yaffs_tnode_t *top;
-} yaffs_file_s;
+ struct yaffs_tnode *top;
+};
-typedef struct {
- struct ylist_head children; /* list of child links */
- struct ylist_head dirty; /* Entry for list of dirty directories */
-} yaffs_dir_s;
+struct yaffs_dir_var {
+ struct list_head children; /* list of child links */
+ struct list_head dirty; /* Entry for list of dirty directories */
+};
-typedef struct {
+struct yaffs_symlink_var {
YCHAR *alias;
-} yaffs_symlink_t;
-
-typedef struct {
- struct yaffs_obj_s *equiv_obj;
- __u32 equiv_id;
-} yaffs_hard_link_s;
-
-typedef union {
- yaffs_file_s file_variant;
- yaffs_dir_s dir_variant;
- yaffs_symlink_t symlink_variant;
- yaffs_hard_link_s hardlink_variant;
-} yaffs_obj_variant;
-
-
-
-struct yaffs_obj_s {
- __u8 deleted:1; /* This should only apply to unlinked files. */
- __u8 soft_del:1; /* it has also been soft deleted */
- __u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/
- __u8 fake:1; /* A fake object has no presence on NAND. */
- __u8 rename_allowed:1; /* Some objects are not allowed to be renamed. */
- __u8 unlink_allowed:1;
- __u8 dirty:1; /* the object needs to be written to flash */
- __u8 valid:1; /* When the file system is being loaded up, this
+};
+
+struct yaffs_hardlink_var {
+ struct yaffs_obj *equiv_obj;
+ u32 equiv_id;
+};
+
+union yaffs_obj_var {
+ struct yaffs_file_var file_variant;
+ struct yaffs_dir_var dir_variant;
+ struct yaffs_symlink_var symlink_variant;
+ struct yaffs_hardlink_var hardlink_variant;
+};
+
+struct yaffs_obj {
+ u8 deleted:1; /* This should only apply to unlinked files. */
+ u8 soft_del:1; /* it has also been soft deleted */
+ u8 unlinked:1; /* An unlinked file.*/
+ u8 fake:1; /* A fake object has no presence on NAND. */
+ u8 rename_allowed:1; /* Some objects cannot be renamed. */
+ u8 unlink_allowed:1;
+ u8 dirty:1; /* the object needs to be written to flash */
+ u8 valid:1; /* When the file system is being loaded up, this
* object might be created before the data
- * is available (ie. file data records appear before the header).
+ * is available
+ * ie. file data chunks encountered before
+ * the header.
*/
- __u8 lazy_loaded:1; /* This object has been lazy loaded and is missing some detail */
+ u8 lazy_loaded:1; /* This object has been lazy loaded and
+ * is missing some detail */
- __u8 defered_free:1; /* For Linux kernel. Object is removed from NAND, but is
- * still in the inode cache. Free of object is defered.
+ u8 defered_free:1; /* Object is removed from NAND, but is
+ * still in the inode cache.
+ * Free of object is defered.
* until the inode is released.
*/
- __u8 being_created:1; /* This object is still being created so skip some checks. */
- __u8 is_shadowed:1; /* This object is shadowed on the way to being renamed. */
+ u8 being_created:1; /* This object is still being created
+ * so skip some verification checks. */
+ u8 is_shadowed:1; /* This object is shadowed on the way
+ * to being renamed. */
- __u8 xattr_known:1; /* We know if this has object has xattribs or not. */
- __u8 has_xattr:1; /* This object has xattribs. Valid if xattr_known. */
+ u8 xattr_known:1; /* We know if this has object has xattribs
+ * or not. */
+ u8 has_xattr:1; /* This object has xattribs.
+ * Only valid if xattr_known. */
- __u8 serial; /* serial number of chunk in NAND. Cached here */
- __u16 sum; /* sum of the name to speed searching */
+ u8 serial; /* serial number of chunk in NAND.*/
+ u16 sum; /* sum of the name to speed searching */
- struct yaffs_dev_s *my_dev; /* The device I'm on */
+ struct yaffs_dev *my_dev; /* The device I'm on */
- struct ylist_head hash_link; /* list of objects in this hash bucket */
+ struct list_head hash_link; /* list of objects in hash bucket */
- struct ylist_head hard_links; /* all the equivalent hard linked objects */
+ struct list_head hard_links; /* hard linked object chain*/
/* directory structure stuff */
/* also used for linking up the free list */
- struct yaffs_obj_s *parent;
- struct ylist_head siblings;
+ struct yaffs_obj *parent;
+ struct list_head siblings;
/* Where's my object header in NAND? */
int hdr_chunk;
- int n_data_chunks; /* Number of data chunks attached to the file. */
+ int n_data_chunks; /* Number of data chunks for this file. */
- __u32 obj_id; /* the object id value */
+ u32 obj_id; /* the object id value */
- __u32 yst_mode;
+ u32 yst_mode;
-#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
-#endif
#ifdef CONFIG_YAFFS_WINCE
- __u32 win_ctime[2];
- __u32 win_mtime[2];
- __u32 win_atime[2];
+ u32 win_ctime[2];
+ u32 win_mtime[2];
+ u32 win_atime[2];
#else
- __u32 yst_uid;
- __u32 yst_gid;
- __u32 yst_atime;
- __u32 yst_mtime;
- __u32 yst_ctime;
+ u32 yst_uid;
+ u32 yst_gid;
+ u32 yst_atime;
+ u32 yst_mtime;
+ u32 yst_ctime;
#endif
- __u32 yst_rdev;
+ u32 yst_rdev;
void *my_inode;
- yaffs_obj_type variant_type;
+ enum yaffs_obj_type variant_type;
- yaffs_obj_variant variant;
+ union yaffs_obj_var variant;
};
-typedef struct yaffs_obj_s yaffs_obj_t;
-
-typedef struct {
- struct ylist_head list;
+struct yaffs_obj_bucket {
+ struct list_head list;
int count;
-} yaffs_obj_bucket;
-
+};
-/* yaffs_checkpt_obj_t holds the definition of an object as dumped
+/* yaffs_checkpt_obj holds the definition of an object as dumped
* by checkpointing.
*/
-typedef struct {
+struct yaffs_checkpt_obj {
int struct_type;
- __u32 obj_id;
- __u32 parent_id;
+ u32 obj_id;
+ u32 parent_id;
int hdr_chunk;
- yaffs_obj_type variant_type:3;
- __u8 deleted:1;
- __u8 soft_del:1;
- __u8 unlinked:1;
- __u8 fake:1;
- __u8 rename_allowed:1;
- __u8 unlink_allowed:1;
- __u8 serial;
-
+ enum yaffs_obj_type variant_type:3;
+ u8 deleted:1;
+ u8 soft_del:1;
+ u8 unlinked:1;
+ u8 fake:1;
+ u8 rename_allowed:1;
+ u8 unlink_allowed:1;
+ u8 serial;
int n_data_chunks;
- __u32 size_or_equiv_obj;
-} yaffs_checkpt_obj_t;
+ loff_t size_or_equiv_obj;
+};
/*--------------------- Temporary buffers ----------------
*
- * These are chunk-sized working buffers. Each device has a few
+ * These are chunk-sized working buffers. Each device has a few.
*/
-typedef struct {
- __u8 *buffer;
- int line; /* track from whence this buffer was allocated */
- int max_line;
-} yaffs_buffer_t;
+struct yaffs_buffer {
+ u8 *buffer;
+ int in_use;
+};
/*----------------- Device ---------------------------------*/
-
-struct yaffs_param_s {
+struct yaffs_param {
const YCHAR *name;
/*
- * Entry parameters set up way early. Yaffs sets up the rest.
- * The structure should be zeroed out before use so that unused
- * and defualt values are zero.
- */
+ * Entry parameters set up way early. Yaffs sets up the rest.
+ * The structure should be zeroed out before use so that unused
+ * and default values are zero.
+ */
- int inband_tags; /* Use unband tags */
- __u32 total_bytes_per_chunk; /* Should be >= 512, does not need to be a power of 2 */
+ int inband_tags; /* Use unband tags */
+ u32 total_bytes_per_chunk; /* Should be >= 512, does not need to
+ be a power of 2 */
int chunks_per_block; /* does not need to be a power of 2 */
int spare_bytes_per_chunk; /* spare area size */
- int start_block; /* Start block we're allowed to use */
+ int start_block; /* Start block we're allowed to use */
int end_block; /* End block we're allowed to use */
- int n_reserved_blocks; /* We want this tuneable so that we can reduce */
- /* reserved blocks on NOR and RAM. */
-
+ int n_reserved_blocks; /* Tuneable so that we can reduce
+ * reserved blocks on NOR and RAM. */
- int n_caches; /* If <= 0, then short op caching is disabled, else
- * the number of short op caches (don't use too many).
- * 10 to 20 is a good bet.
+ int n_caches; /* If <= 0, then short op caching is disabled,
+ * else the number of short op caches.
*/
- int use_nand_ecc; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */
- int no_tags_ecc; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */
+ int cache_bypass_aligned; /* If non-zero then bypass the cache for
+ * aligned writes.
+ */
- int is_yaffs2; /* Use yaffs2 mode on this device */
+ int use_nand_ecc; /* Flag to decide whether or not to use
+ * NAND driver ECC on data (yaffs1) */
+ int tags_9bytes; /* Use 9 byte tags */
+ int no_tags_ecc; /* Flag to decide whether or not to do ECC
+ * on packed tags (yaffs2) */
- int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
+ int is_yaffs2; /* Use yaffs2 mode on this device */
- int refresh_period; /* How often we should check to do a block refresh */
+ int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
+
+ int refresh_period; /* How often to check for a block refresh */
/* Checkpoint control. Can be set before or after initialisation */
- __u8 skip_checkpt_rd;
- __u8 skip_checkpt_wr;
+ u8 skip_checkpt_rd;
+ u8 skip_checkpt_wr;
int enable_xattr; /* Enable xattribs */
- /* NAND access functions (Must be set before calling YAFFS)*/
-
- int (*write_chunk_fn) (struct yaffs_dev_s *dev,
- int nand_chunk, const __u8 *data,
- const yaffs_spare *spare);
- int (*read_chunk_fn) (struct yaffs_dev_s *dev,
- int nand_chunk, __u8 *data,
- yaffs_spare *spare);
- int (*erase_fn) (struct yaffs_dev_s *dev,
- int flash_block);
- int (*initialise_flash_fn) (struct yaffs_dev_s *dev);
- int (*deinitialise_flash_fn) (struct yaffs_dev_s *dev);
-
-#ifdef CONFIG_YAFFS_YAFFS2
- int (*write_chunk_tags_fn) (struct yaffs_dev_s *dev,
- int nand_chunk, const __u8 *data,
- const yaffs_ext_tags *tags);
- int (*read_chunk_tags_fn) (struct yaffs_dev_s *dev,
- int nand_chunk, __u8 *data,
- yaffs_ext_tags *tags);
- int (*bad_block_fn) (struct yaffs_dev_s *dev, int block_no);
- int (*query_block_fn) (struct yaffs_dev_s *dev, int block_no,
- yaffs_block_state_t *state, __u32 *seq_number);
-#endif
+ int max_objects; /*
+ * Set to limit the number of objects created.
+ * 0 = no limit.
+ */
/* The remove_obj_fn function must be supplied by OS flavours that
* need it.
- * yaffs direct uses it to implement the faster readdir.
- * Linux uses it to protect the directory during unlocking.
+ * yaffs direct uses it to implement the faster readdir.
+ * Linux uses it to protect the directory during unlocking.
*/
- void (*remove_obj_fn)(struct yaffs_obj_s *obj);
+ void (*remove_obj_fn) (struct yaffs_obj *obj);
/* Callback to mark the superblock dirty */
- void (*sb_dirty_fn)(struct yaffs_dev_s *dev);
-
+ void (*sb_dirty_fn) (struct yaffs_dev *dev);
+
/* Callback to control garbage collection. */
- unsigned (*gc_control)(struct yaffs_dev_s *dev);
+ unsigned (*gc_control_fn) (struct yaffs_dev *dev);
- /* Debug control flags. Don't use unless you know what you're doing */
- int use_header_file_size; /* Flag to determine if we should use file sizes from the header */
+ /* Debug control flags. Don't use unless you know what you're doing */
+ int use_header_file_size; /* Flag to determine if we should use
+ * file sizes from the header */
int disable_lazy_load; /* Disable lazy loading on this device */
- int wide_tnodes_disabled; /* Set to disable wide tnodes */
- int disable_soft_del; /* yaffs 1 only: Set to disable the use of softdeletion. */
-
- int defered_dir_update; /* Set to defer directory updates */
+ int wide_tnodes_disabled; /* Set to disable wide tnodes */
+ int disable_soft_del; /* yaffs 1 only: Set to disable the use of
+ * softdeletion. */
+
+ int defered_dir_update; /* Set to defer directory updates */
#ifdef CONFIG_YAFFS_AUTO_UNICODE
int auto_unicode;
#endif
- int always_check_erased; /* Force chunk erased check always on */
+ int always_check_erased; /* Force chunk erased check always on */
+
+ int disable_summary;
+ int disable_bad_block_marking;
+
};
-typedef struct yaffs_param_s yaffs_param_t;
+struct yaffs_driver {
+ int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
+ const u8 *data, int data_len,
+ const u8 *oob, int oob_len);
+ int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
+ u8 *data, int data_len,
+ u8 *oob, int oob_len,
+ enum yaffs_ecc_result *ecc_result);
+ int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);
+ int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);
+ int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);
+ int (*drv_initialise_fn) (struct yaffs_dev *dev);
+ int (*drv_deinitialise_fn) (struct yaffs_dev *dev);
+};
+
+struct yaffs_tags_handler {
+ int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
+ int nand_chunk, const u8 *data,
+ const struct yaffs_ext_tags *tags);
+ int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
+ int nand_chunk, u8 *data,
+ struct yaffs_ext_tags *tags);
+
+ int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
+ enum yaffs_block_state *state,
+ u32 *seq_number);
+ int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);
+};
-struct yaffs_dev_s {
- struct yaffs_param_s param;
+struct yaffs_dev {
+ struct yaffs_param param;
+ struct yaffs_driver drv;
+ struct yaffs_tags_handler tagger;
- /* Context storage. Holds extra OS specific data for this device */
+ /* Context storage. Holds extra OS specific data for this device */
void *os_context;
void *driver_context;
- struct ylist_head dev_list;
+ struct list_head dev_list;
+ int ll_init;
/* Runtime parameters. Set up by YAFFS. */
- int data_bytes_per_chunk;
+ int data_bytes_per_chunk;
- /* Non-wide tnode stuff */
- __u16 chunk_grp_bits; /* Number of bits that need to be resolved if
- * the tnodes are not wide enough.
- */
- __u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
+ /* Non-wide tnode stuff */
+ u16 chunk_grp_bits; /* Number of bits that need to be resolved if
+ * the tnodes are not wide enough.
+ */
+ u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
/* Stuff to support wide tnodes */
- __u32 tnode_width;
- __u32 tnode_mask;
- __u32 tnode_size;
+ u32 tnode_width;
+ u32 tnode_mask;
+ u32 tnode_size;
/* Stuff for figuring out file offset to chunk conversions */
- __u32 chunk_shift; /* Shift value */
- __u32 chunk_div; /* Divisor after shifting: 1 for power-of-2 sizes */
- __u32 chunk_mask; /* Mask to use for power-of-2 case */
-
-
+ u32 chunk_shift; /* Shift value */
+ u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */
+ u32 chunk_mask; /* Mask to use for power-of-2 case */
int is_mounted;
int read_only;
int is_checkpointed;
-
/* Stuff to support block offsetting to support start block zero */
int internal_start_block;
int internal_end_block;
int block_offset;
int chunk_offset;
-
/* Runtime checkpointing stuff */
- int checkpt_page_seq; /* running sequence number of checkpoint pages */
+ int checkpt_page_seq; /* running sequence number of checkpt pages */
int checkpt_byte_count;
int checkpt_byte_offs;
- __u8 *checkpt_buffer;
+ u8 *checkpt_buffer;
int checkpt_open_write;
int blocks_in_checkpt;
int checkpt_cur_chunk;
int checkpt_next_block;
int *checkpt_block_list;
int checkpt_max_blocks;
- __u32 checkpt_sum;
- __u32 checkpt_xor;
+ u32 checkpt_sum;
+ u32 checkpt_xor;
- int checkpoint_blocks_required; /* Number of blocks needed to store current checkpoint set */
+ int checkpoint_blocks_required; /* Number of blocks needed to store
+ * current checkpoint set */
/* Block Info */
- yaffs_block_info_t *block_info;
- __u8 *chunk_bits; /* bitmap of chunks in use */
- unsigned block_info_alt:1; /* was allocated using alternative strategy */
- unsigned chunk_bits_alt:1; /* was allocated using alternative strategy */
+ struct yaffs_block_info *block_info;
+ u8 *chunk_bits; /* bitmap of chunks in use */
+ unsigned block_info_alt:1; /* allocated using alternative alloc */
+ unsigned chunk_bits_alt:1; /* allocated using alternative alloc */
int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
* Must be consistent with chunks_per_block.
*/
int n_erased_blocks;
int alloc_block; /* Current block being allocated off */
- __u32 alloc_page;
+ u32 alloc_page;
int alloc_block_finder; /* Used to search for next allocation block */
/* Object and Tnode memory management */
int n_hardlinks;
- yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
- __u32 bucket_finder;
+ struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
+ u32 bucket_finder;
int n_free_chunks;
/* Garbage collection control */
- __u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
- __u32 n_clean_ups;
+ u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
+ u32 n_clean_ups;
- unsigned has_pending_prioritised_gc; /* We think this device might have pending prioritised gcs */
+ unsigned has_pending_prioritised_gc; /* We think this device might
+ have pending prioritised gcs */
unsigned gc_disable;
unsigned gc_block_finder;
unsigned gc_dirtiest;
unsigned gc_block;
unsigned gc_chunk;
unsigned gc_skip;
+ struct yaffs_summary_tags *gc_sum_tags;
/* Special directories */
- yaffs_obj_t *root_dir;
- yaffs_obj_t *lost_n_found;
-
- /* Buffer areas for storing data to recover from write failures TODO
- * __u8 buffered_data[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
- * yaffs_spare buffered_spare[YAFFS_CHUNKS_PER_BLOCK];
- */
+ struct yaffs_obj *root_dir;
+ struct yaffs_obj *lost_n_found;
int buffered_block; /* Which block is buffered here? */
int doing_buffered_block_rewrite;
- yaffs_cache_t *cache;
+ struct yaffs_cache *cache;
int cache_last_use;
- /* Stuff for background deletion and unlinked files.*/
- yaffs_obj_t *unlinked_dir; /* Directory where unlinked and deleted files live. */
- yaffs_obj_t *del_dir; /* Directory where deleted objects are sent to disappear. */
- yaffs_obj_t *unlinked_deletion; /* Current file being background deleted.*/
- int n_deleted_files; /* Count of files awaiting deletion;*/
- int n_unlinked_files; /* Count of unlinked files. */
+ /* Stuff for background deletion and unlinked files. */
+ struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted
+ files live. */
+ struct yaffs_obj *del_dir; /* Directory where deleted objects are
+ sent to disappear. */
+ struct yaffs_obj *unlinked_deletion; /* Current file being
+ background deleted. */
+ int n_deleted_files; /* Count of files awaiting deletion; */
+ int n_unlinked_files; /* Count of unlinked files. */
int n_bg_deletions; /* Count of background deletions. */
/* Temporary buffer management */
- yaffs_buffer_t temp_buffer[YAFFS_N_TEMP_BUFFERS];
+ struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
int max_temp;
int temp_in_use;
int unmanaged_buffer_allocs;
int unmanaged_buffer_deallocs;
/* yaffs2 runtime stuff */
- unsigned seq_number; /* Sequence number of currently allocating block */
+ unsigned seq_number; /* Sequence number of currently
+ allocating block */
unsigned oldest_dirty_seq;
unsigned oldest_dirty_block;
/* Block refreshing */
- int refresh_skip; /* A skip down counter. Refresh happens when this gets to zero. */
+ int refresh_skip; /* A skip down counter.
+ * Refresh happens when this gets to zero. */
/* Dirty directory handling */
- struct ylist_head dirty_dirs; /* List of dirty directories */
-
-
- /* Statistcs */
- __u32 n_page_writes;
- __u32 n_page_reads;
- __u32 n_erasures;
- __u32 n_erase_failures;
- __u32 n_gc_copies;
- __u32 all_gcs;
- __u32 passive_gc_count;
- __u32 oldest_dirty_gc_count;
- __u32 n_gc_blocks;
- __u32 bg_gcs;
- __u32 n_retired_writes;
- __u32 n_retired_blocks;
- __u32 n_ecc_fixed;
- __u32 n_ecc_unfixed;
- __u32 n_tags_ecc_fixed;
- __u32 n_tags_ecc_unfixed;
- __u32 n_deletions;
- __u32 n_unmarked_deletions;
- __u32 refresh_count;
- __u32 cache_hits;
+ struct list_head dirty_dirs; /* List of dirty directories */
+
+ /* Summary */
+ int chunks_per_summary;
+ struct yaffs_summary_tags *sum_tags;
+
+ /* Statistics */
+ u32 n_page_writes;
+ u32 n_page_reads;
+ u32 n_erasures;
+ u32 n_bad_markings;
+ u32 n_erase_failures;
+ u32 n_gc_copies;
+ u32 all_gcs;
+ u32 passive_gc_count;
+ u32 oldest_dirty_gc_count;
+ u32 n_gc_blocks;
+ u32 bg_gcs;
+ u32 n_retried_writes;
+ u32 n_retired_blocks;
+ u32 n_ecc_fixed;
+ u32 n_ecc_unfixed;
+ u32 n_tags_ecc_fixed;
+ u32 n_tags_ecc_unfixed;
+ u32 n_deletions;
+ u32 n_unmarked_deletions;
+ u32 refresh_count;
+ u32 cache_hits;
+ u32 tags_used;
+ u32 summary_used;
};
-typedef struct yaffs_dev_s yaffs_dev_t;
-
-/* The static layout of block usage etc is stored in the super block header */
-typedef struct {
- int StructType;
- int version;
- int checkpt_start_block;
- int checkpt_end_block;
- int start_block;
- int end_block;
- int rfu[100];
-} yaffs_sb_header;
-
-/* The CheckpointDevice structure holds the device information that changes at runtime and
- * must be preserved over unmount/mount cycles.
+/* The CheckpointDevice structure holds the device information that changes
+ *at runtime and must be preserved over unmount/mount cycles.
*/
-typedef struct {
+struct yaffs_checkpt_dev {
int struct_type;
int n_erased_blocks;
int alloc_block; /* Current block being allocated off */
- __u32 alloc_page;
+ u32 alloc_page;
int n_free_chunks;
- int n_deleted_files; /* Count of files awaiting deletion;*/
- int n_unlinked_files; /* Count of unlinked files. */
+ int n_deleted_files; /* Count of files awaiting deletion; */
+ int n_unlinked_files; /* Count of unlinked files. */
int n_bg_deletions; /* Count of background deletions. */
/* yaffs2 runtime stuff */
- unsigned seq_number; /* Sequence number of currently allocating block */
-
-} yaffs_checkpt_dev_t;
+ unsigned seq_number; /* Sequence number of currently
+ * allocating block */
+};
-typedef struct {
+struct yaffs_checkpt_validity {
int struct_type;
- __u32 magic;
- __u32 version;
- __u32 head;
-} yaffs_checkpt_validty_t;
-
+ u32 magic;
+ u32 version;
+ u32 head;
+};
-struct yaffs_shadow_fixer_s {
+struct yaffs_shadow_fixer {
int obj_id;
int shadowed_id;
- struct yaffs_shadow_fixer_s *next;
+ struct yaffs_shadow_fixer *next;
};
/* Structure for doing xattr modifications */
-typedef struct {
- int set; /* If 0 then this is a deletion */
+struct yaffs_xattr_mod {
+ int set; /* If 0 then this is a deletion */
const YCHAR *name;
const void *data;
int size;
int flags;
int result;
-}yaffs_xattr_mod;
-
+};
/*----------------------- YAFFS Functions -----------------------*/
-int yaffs_guts_initialise(yaffs_dev_t *dev);
-void yaffs_deinitialise(yaffs_dev_t *dev);
-
-int yaffs_get_n_free_chunks(yaffs_dev_t *dev);
+int yaffs_guts_initialise(struct yaffs_dev *dev);
+void yaffs_deinitialise(struct yaffs_dev *dev);
-int yaffs_rename_obj(yaffs_obj_t *old_dir, const YCHAR *old_name,
- yaffs_obj_t *new_dir, const YCHAR *new_name);
+int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
-int yaffs_unlinker(yaffs_obj_t *dir, const YCHAR *name);
-int yaffs_del_obj(yaffs_obj_t *obj);
+int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
+ struct yaffs_obj *new_dir, const YCHAR * new_name);
-int yaffs_get_obj_name(yaffs_obj_t *obj, YCHAR *name, int buffer_size);
-int yaffs_get_obj_length(yaffs_obj_t *obj);
-int yaffs_get_obj_inode(yaffs_obj_t *obj);
-unsigned yaffs_get_obj_type(yaffs_obj_t *obj);
-int yaffs_get_obj_link_count(yaffs_obj_t *obj);
+int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
+int yaffs_del_obj(struct yaffs_obj *obj);
-int yaffs_set_attribs(yaffs_obj_t *obj, struct iattr *attr);
-int yaffs_get_attribs(yaffs_obj_t *obj, struct iattr *attr);
+int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
+loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
+int yaffs_get_obj_inode(struct yaffs_obj *obj);
+unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
+int yaffs_get_obj_link_count(struct yaffs_obj *obj);
/* File operations */
-int yaffs_file_rd(yaffs_obj_t *obj, __u8 *buffer, loff_t offset,
- int n_bytes);
-int yaffs_wr_file(yaffs_obj_t *obj, const __u8 *buffer, loff_t offset,
- int n_bytes, int write_trhrough);
-int yaffs_resize_file(yaffs_obj_t *obj, loff_t new_size);
+int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
+ int n_bytes);
+int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
+ int n_bytes, int write_trhrough);
+int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
-yaffs_obj_t *yaffs_create_file(yaffs_obj_t *parent, const YCHAR *name,
- __u32 mode, __u32 uid, __u32 gid);
+struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
+ const YCHAR *name, u32 mode, u32 uid,
+ u32 gid);
-int yaffs_flush_file(yaffs_obj_t *obj, int update_time, int data_sync);
+int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
/* Flushing and checkpointing */
-void yaffs_flush_whole_cache(yaffs_dev_t *dev);
+void yaffs_flush_whole_cache(struct yaffs_dev *dev);
-int yaffs_checkpoint_save(yaffs_dev_t *dev);
-int yaffs_checkpoint_restore(yaffs_dev_t *dev);
+int yaffs_checkpoint_save(struct yaffs_dev *dev);
+int yaffs_checkpoint_restore(struct yaffs_dev *dev);
/* Directory operations */
-yaffs_obj_t *yaffs_create_dir(yaffs_obj_t *parent, const YCHAR *name,
- __u32 mode, __u32 uid, __u32 gid);
-yaffs_obj_t *yaffs_find_by_name(yaffs_obj_t *the_dir, const YCHAR *name);
-int yaffs_ApplyToDirectoryChildren(yaffs_obj_t *the_dir,
- int (*fn) (yaffs_obj_t *));
-
-yaffs_obj_t *yaffs_find_by_number(yaffs_dev_t *dev, __u32 number);
+struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
+ u32 mode, u32 uid, u32 gid);
+struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
+ const YCHAR *name);
+struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
/* Link operations */
-yaffs_obj_t *yaffs_link_obj(yaffs_obj_t *parent, const YCHAR *name,
- yaffs_obj_t *equiv_obj);
+struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
+ struct yaffs_obj *equiv_obj);
-yaffs_obj_t *yaffs_get_equivalent_obj(yaffs_obj_t *obj);
+struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
/* Symlink operations */
-yaffs_obj_t *yaffs_create_symlink(yaffs_obj_t *parent, const YCHAR *name,
- __u32 mode, __u32 uid, __u32 gid,
- const YCHAR *alias);
-YCHAR *yaffs_get_symlink_alias(yaffs_obj_t *obj);
+struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
+ const YCHAR *name, u32 mode, u32 uid,
+ u32 gid, const YCHAR *alias);
+YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
/* Special inodes (fifos, sockets and devices) */
-yaffs_obj_t *yaffs_create_special(yaffs_obj_t *parent, const YCHAR *name,
- __u32 mode, __u32 uid, __u32 gid, __u32 rdev);
-
+struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
+ const YCHAR *name, u32 mode, u32 uid,
+ u32 gid, u32 rdev);
-int yaffs_set_xattrib(yaffs_obj_t *obj, const YCHAR *name, const void * value, int size, int flags);
-int yaffs_get_xattrib(yaffs_obj_t *obj, const YCHAR *name, void *value, int size);
-int yaffs_list_xattrib(yaffs_obj_t *obj, char *buffer, int size);
-int yaffs_remove_xattrib(yaffs_obj_t *obj, const YCHAR *name);
+int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
+ const void *value, int size, int flags);
+int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
+ int size);
+int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
+int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);
/* Special directories */
-yaffs_obj_t *yaffs_root(yaffs_dev_t *dev);
-yaffs_obj_t *yaffs_lost_n_found(yaffs_dev_t *dev);
+struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
+struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
-#ifdef CONFIG_YAFFS_WINCE
-/* CONFIG_YAFFS_WINCE special stuff */
-void yfsd_win_file_time_now(__u32 target[2]);
-#endif
-
-void yaffs_handle_defered_free(yaffs_obj_t *obj);
+void yaffs_handle_defered_free(struct yaffs_obj *obj);
-void yaffs_update_dirty_dirs(yaffs_dev_t *dev);
+void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
-int yaffs_bg_gc(yaffs_dev_t *dev, unsigned urgency);
+int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
/* Debug dump */
-int yaffs_dump_obj(yaffs_obj_t *obj);
+int yaffs_dump_obj(struct yaffs_obj *obj);
+
+void yaffs_guts_test(struct yaffs_dev *dev);
+int yaffs_guts_ll_init(struct yaffs_dev *dev);
-void yaffs_guts_test(yaffs_dev_t *dev);
/* A few useful functions to be used within the core files*/
-void yaffs_chunk_del(yaffs_dev_t *dev, int chunk_id, int mark_flash, int lyn);
-int yaffs_check_ff(__u8 *buffer, int n_bytes);
-void yaffs_handle_chunk_error(yaffs_dev_t *dev, yaffs_block_info_t *bi);
-
-__u8 *yaffs_get_temp_buffer(yaffs_dev_t *dev, int line_no);
-void yaffs_release_temp_buffer(yaffs_dev_t *dev, __u8 *buffer, int line_no);
-
-yaffs_obj_t *yaffs_find_or_create_by_number(yaffs_dev_t *dev,
- int number,
- yaffs_obj_type type);
-int yaffs_put_chunk_in_file(yaffs_obj_t *in, int inode_chunk,
- int nand_chunk, int in_scan);
-void yaffs_set_obj_name(yaffs_obj_t *obj, const YCHAR *name);
-void yaffs_set_obj_name_from_oh(yaffs_obj_t *obj, const yaffs_obj_header *oh);
-void yaffs_add_obj_to_dir(yaffs_obj_t *directory,
- yaffs_obj_t *obj);
+void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
+ int lyn);
+int yaffs_check_ff(u8 *buffer, int n_bytes);
+void yaffs_handle_chunk_error(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi);
+
+u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
+void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);
+
+struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
+ int number,
+ enum yaffs_obj_type type);
+int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+ int nand_chunk, int in_scan);
+void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
+void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
+ const struct yaffs_obj_hdr *oh);
+void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
YCHAR *yaffs_clone_str(const YCHAR *str);
-void yaffs_link_fixup(yaffs_dev_t *dev, yaffs_obj_t *hard_list);
-void yaffs_block_became_dirty(yaffs_dev_t *dev, int block_no);
-int yaffs_update_oh(yaffs_obj_t *in, const YCHAR *name,
- int force, int is_shrink, int shadows,
- yaffs_xattr_mod *xop);
-void yaffs_handle_shadowed_obj(yaffs_dev_t *dev, int obj_id,
- int backward_scanning);
-int yaffs_check_alloc_available(yaffs_dev_t *dev, int n_chunks);
-yaffs_tnode_t *yaffs_get_tnode(yaffs_dev_t *dev);
-yaffs_tnode_t *yaffs_add_find_tnode_0(yaffs_dev_t *dev,
- yaffs_file_s *file_struct,
- __u32 chunk_id,
- yaffs_tnode_t *passed_tn);
-
-int yaffs_do_file_wr(yaffs_obj_t *in, const __u8 *buffer, loff_t offset,
- int n_bytes, int write_trhrough);
-void yaffs_resize_file_down( yaffs_obj_t *obj, loff_t new_size);
-void yaffs_skip_rest_of_block(yaffs_dev_t *dev);
-
-int yaffs_count_free_chunks(yaffs_dev_t *dev);
-
-yaffs_tnode_t *yaffs_find_tnode_0(yaffs_dev_t *dev,
- yaffs_file_s *file_struct,
- __u32 chunk_id);
-
-__u32 yaffs_get_group_base(yaffs_dev_t *dev, yaffs_tnode_t *tn, unsigned pos);
+void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
+void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
+int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
+ int force, int is_shrink, int shadows,
+ struct yaffs_xattr_mod *xop);
+void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
+ int backward_scanning);
+int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
+struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
+struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
+ struct yaffs_file_var *file_struct,
+ u32 chunk_id,
+ struct yaffs_tnode *passed_tn);
+
+int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
+ int n_bytes, int write_trhrough);
+void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
+void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
+
+int yaffs_count_free_chunks(struct yaffs_dev *dev);
+
+struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
+ struct yaffs_file_var *file_struct,
+ u32 chunk_id);
+
+u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+ unsigned pos);
+
+int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
+
+int yaffs_format_dev(struct yaffs_dev *dev);
+
+void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
+ int *chunk_out, u32 *offset_out);
+/*
+ * Marshalling functions to get loff_t file sizes into aand out of
+ * object headers.
+ */
+void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
+loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
+loff_t yaffs_max_file_size(struct yaffs_dev *dev);
+
+/*
+ * Debug function to count number of blocks in each state
+ * NB Needs to be called with correct number of integers
+ */
+
+void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]);
+
+int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+ struct yaffs_ext_tags *tags);
#endif
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#ifndef __YAFFS_LINUX_H__
#define __YAFFS_LINUX_H__
-#include "devextras.h"
#include "yportenv.h"
-struct yaffs_LinuxContext {
- struct ylist_head contextList; /* List of these we have mounted */
- struct yaffs_dev_s *dev;
- struct super_block * superBlock;
- struct task_struct *bgThread; /* Background thread for this device */
- int bgRunning;
- struct semaphore grossLock; /* Gross locking semaphore */
- __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
+struct yaffs_linux_context {
+ struct list_head context_list; /* List of these we have mounted */
+ struct yaffs_dev *dev;
+ struct super_block *super;
+ struct task_struct *bg_thread; /* Background thread for this device */
+ int bg_running;
+ struct mutex gross_lock; /* Gross locking mutex*/
+ u8 *spare_buffer; /* For mtdif2 use. Don't know the buffer size
* at compile time so we have to allocate it.
*/
- struct ylist_head searchContexts;
- void (*putSuperFunc)(struct super_block *sb);
-
- struct task_struct *readdirProcess;
+ struct list_head search_contexts;
+ struct task_struct *readdir_process;
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))
+#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
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#include "yportenv.h"
-
#include "yaffs_mtdif.h"
#include "linux/mtd/mtd.h"
#include "linux/types.h"
#include "linux/time.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"
-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);
- __u32 addr =
- ((loff_t) blockNumber) * dev->param.total_bytes_per_chunk
- * dev->param.chunks_per_block;
+ u32 addr =
+ ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
+ dev->param.chunks_per_block;
struct erase_info ei;
-
int retval = 0;
ei.mtd = mtd;
ei.callback = NULL;
ei.priv = (u_long) dev;
- retval = mtd->erase(mtd, &ei);
+ retval = mtd_erase(mtd, &ei);
if (retval == 0)
return YAFFS_OK;
- else
+
+ return YAFFS_FAIL;
+}
+
+
+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;
}
-int nandmtd_InitialiseNAND(yaffs_dev_t *dev)
+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;
+}
+
+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);
+}
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#include "yaffs_guts.h"
-#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
-extern struct nand_oobinfo yaffs_oobinfo;
-extern struct nand_oobinfo yaffs_noeccinfo;
-#endif
-int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber);
-int nandmtd_InitialiseNAND(yaffs_dev_t *dev);
+void yaffs_mtd_drv_install(struct yaffs_dev *dev);
+struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
+void yaffs_put_mtd_device(struct mtd_info *mtd);
+int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
#endif
+++ /dev/null
-/*
- * 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*/
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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;
-}
-
+++ /dev/null
-/*
- * 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
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
*/
/*
- * This simple implementation of a name-value store assumes a small number of values and fits
- * into a small finite buffer.
+ * This simple implementation of a name-value store assumes a small number of
+* values and fits into a small finite buffer.
*
* Each attribute is stored as a record:
* sizeof(int) bytes record size.
* strnlen+1 bytes name null terminated.
* nbytes value.
* ----------
- * total size stored in record size
+ * total size stored in record size
*
* This code has not been tested with unicode yet.
*/
-
#include "yaffs_nameval.h"
#include "yportenv.h"
-
+
static int nval_find(const char *xb, int xb_size, const YCHAR *name,
- int *exist_size)
+ int *exist_size)
{
- int pos=0;
+ int pos = 0;
int size;
- memcpy(&size,xb,sizeof(int));
- while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
- if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){
- if(exist_size)
+ memcpy(&size, xb, sizeof(int));
+ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
+ if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),
+ name, size)) {
+ if (exist_size)
*exist_size = size;
return pos;
}
pos += size;
- if(pos < xb_size -sizeof(int))
- memcpy(&size,xb + pos,sizeof(int));
+ if (pos < xb_size - sizeof(int))
+ memcpy(&size, xb + pos, sizeof(int));
else
size = 0;
}
- if(exist_size)
+ if (exist_size)
*exist_size = 0;
- return -1;
+ return -ENODATA;
}
static int nval_used(const char *xb, int xb_size)
{
- int pos=0;
+ int pos = 0;
int size;
- memcpy(&size,xb + pos,sizeof(int));
- while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
+ memcpy(&size, xb + pos, sizeof(int));
+ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
pos += size;
- if(pos < xb_size -sizeof(int))
- memcpy(&size,xb + pos,sizeof(int));
+ if (pos < xb_size - sizeof(int))
+ memcpy(&size, xb + pos, sizeof(int));
else
size = 0;
}
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;
-
- 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
+
+ if (pos < 0 || pos >= xb_size)
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 namelen = yaffs_strnlen(name,xb_size);
+ int namelen = strnlen(name, xb_size);
int reclen;
int size_exist = 0;
int space;
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;
- if(flags & XATTR_REPLACE && pos < 0)
+ if (flags & XATTR_REPLACE && pos < 0)
return -ENODATA;
- start = nval_used(xb,xb_size);
+ start = nval_used(xb, xb_size);
space = xb_size - start + size_exist;
reclen = (sizeof(int) + namelen + 1 + bsize);
- if(reclen > space)
+ if (reclen > space)
return -ENOSPC;
- if(pos >= 0){
- nval_del(xb,xb_size,name);
+ if (pos >= 0) {
+ nval_del(xb, xb_size, name);
start = nval_used(xb, xb_size);
}
pos = start;
- memcpy(xb + pos,&reclen,sizeof(int));
- pos +=sizeof(int);
- yaffs_strncpy((YCHAR *)(xb + pos), name, reclen);
- pos+= (namelen+1);
- memcpy(xb + pos,buf,bsize);
+ memcpy(xb + pos, &reclen, sizeof(int));
+ pos += sizeof(int);
+ strncpy((YCHAR *) (xb + pos), name, reclen);
+ pos += (namelen + 1);
+ memcpy(xb + pos, buf, bsize);
return 0;
}
-int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize)
+int 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;
-
- if(pos >= 0 && pos< xb_size){
-
- memcpy(&size,xb +pos,sizeof(int));
- pos+=sizeof(int); /* advance past record length */
+
+ if (pos >= 0 && pos < xb_size) {
+
+ memcpy(&size, xb + pos, sizeof(int));
+ pos += sizeof(int); /* advance past record length */
size -= sizeof(int);
/* Advance over name string */
- while(xb[pos] && size > 0 && pos < xb_size){
+ while (xb[pos] && size > 0 && pos < xb_size) {
pos++;
size--;
}
pos++;
size--;
- if(size <= bsize){
- memcpy(buf,xb + pos,size);
+ /* If bsize is zero then this is a size query.
+ * Return the size, but don't copy.
+ */
+ if (!bsize)
+ return size;
+
+ if (size <= bsize) {
+ memcpy(buf, xb + pos, size);
return size;
}
-
}
- if(pos >= 0)
+ if (pos >= 0)
return -ERANGE;
- else
- return -ENODATA;
+
+ return -ENODATA;
}
int nval_list(const char *xb, int xb_size, char *buf, int bsize)
int ncopied = 0;
int filled = 0;
- memcpy(&size,xb + pos,sizeof(int));
- while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){
- pos+= sizeof(int);
- size-=sizeof(int);
- name_len = yaffs_strnlen((YCHAR *)(xb + pos), size);
- if(ncopied + name_len + 1 < bsize){
- memcpy(buf,xb+pos,name_len * sizeof(YCHAR));
- buf+= name_len;
+ memcpy(&size, xb + pos, sizeof(int));
+ while (size > sizeof(int) &&
+ size <= xb_size &&
+ (pos + size) < xb_size &&
+ !filled) {
+ pos += sizeof(int);
+ size -= sizeof(int);
+ name_len = strnlen((YCHAR *) (xb + pos), size);
+ if (ncopied + name_len + 1 < bsize) {
+ memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
+ buf += name_len;
*buf = '\0';
buf++;
- if(sizeof(YCHAR) > 1){
+ if (sizeof(YCHAR) > 1) {
*buf = '\0';
buf++;
}
- ncopied += (name_len+1);
- } else
+ ncopied += (name_len + 1);
+ } else {
filled = 1;
- pos+=size;
- if(pos < xb_size -sizeof(int))
- memcpy(&size,xb + pos,sizeof(int));
+ }
+ pos += size;
+ if (pos < xb_size - sizeof(int))
+ memcpy(&size, xb + pos, sizeof(int));
else
size = 0;
}
return ncopied;
}
-
int nval_hasvalues(const char *xb, int xb_size)
{
return nval_used(xb, xb_size) > 0;
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
+
#ifndef __NAMEVAL_H__
#define __NAMEVAL_H__
#include "yportenv.h"
-int nval_del(char *xb, int xb_size, const YCHAR *name);
-int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags);
-int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize);
+int nval_del(char *xb, int xb_size, const YCHAR * name);
+int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
+ int bsize, int flags);
+int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
+ int bsize);
int nval_list(const char *xb, int xb_size, char *buf, int bsize);
int nval_hasvalues(const char *xb, int xb_size);
#endif
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#include "yaffs_nand.h"
#include "yaffs_tagscompat.h"
-#include "yaffs_tagsvalidity.h"
#include "yaffs_getblockinfo.h"
+#include "yaffs_summary.h"
-int yaffs_rd_chunk_tags_nand(yaffs_dev_t *dev, int nand_chunk,
- __u8 *buffer,
- yaffs_ext_tags *tags)
+static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
{
- int result;
- yaffs_ext_tags localTags;
+ return chunk - dev->chunk_offset;
+}
- int realignedChunkInNAND = nand_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;
+ struct yaffs_ext_tags local_tags;
+ int flash_chunk = apply_chunk_offset(dev, nand_chunk);
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)
- tags = &localTags;
-
- if (dev->param.read_chunk_tags_fn)
- result = dev->param.read_chunk_tags_fn(dev, realignedChunkInNAND, buffer,
- 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;
- bi = yaffs_get_block_info(dev, nand_chunk/dev->param.chunks_per_block);
+ tags = &local_tags;
+
+ result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);
+ if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
+
+ struct yaffs_block_info *bi;
+ bi = yaffs_get_block_info(dev,
+ nand_chunk /
+ dev->param.chunks_per_block);
yaffs_handle_chunk_error(dev, bi);
}
-
return result;
}
-int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev,
- int nand_chunk,
- const __u8 *buffer,
- 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 result;
+ int flash_chunk = apply_chunk_offset(dev, nand_chunk);
dev->n_page_writes++;
- nand_chunk -= dev->chunk_offset;
-
-
- if (tags) {
- 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 (!tags) {
+ yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
+ BUG();
+ return YAFFS_FAIL;
}
- if (dev->param.write_chunk_tags_fn)
- return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer,
- tags);
- else
- return yaffs_tags_compat_wr(dev,
- nand_chunk,
- buffer,
- tags);
+ tags->seq_number = dev->seq_number;
+ tags->chunk_used = 1;
+ yaffs_trace(YAFFS_TRACE_WRITE,
+ "Writing chunk %d tags %d %d",
+ nand_chunk, tags->obj_id, tags->chunk_id);
+
+ result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk,
+ buffer, tags);
+
+ yaffs_summary_add(dev, tags, nand_chunk);
+
+ return result;
}
-int yaffs_mark_bad(yaffs_dev_t *dev, int block_no)
+int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
{
block_no -= dev->block_offset;
+ dev->n_bad_markings++;
+ if (dev->param.disable_bad_block_marking)
+ return YAFFS_OK;
- 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);
+ return dev->tagger.mark_bad_fn(dev, block_no);
}
-int yaffs_query_init_block_state(yaffs_dev_t *dev,
- int block_no,
- yaffs_block_state_t *state,
- __u32 *seq_number)
+
+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;
-
- 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);
+ return dev->tagger.query_block_fn(dev, block_no, state, seq_number);
}
-
-int yaffs_erase_block(struct yaffs_dev_s *dev,
- int flash_block)
+int yaffs_erase_block(struct yaffs_dev *dev, int block_no)
{
int result;
- flash_block -= dev->block_offset;
-
+ block_no -= dev->block_offset;
dev->n_erasures++;
-
- result = dev->param.erase_fn(dev, flash_block);
-
+ result = dev->drv.drv_erase_fn(dev, block_no);
return result;
}
-int yaffs_init_nand(struct yaffs_dev_s *dev)
+int yaffs_init_nand(struct yaffs_dev *dev)
{
- if(dev->param.initialise_flash_fn)
- return dev->param.initialise_flash_fn(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;
+}
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#define __YAFFS_NAND_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,
- __u8 *buffer,
- yaffs_ext_tags *tags);
+int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
-int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev,
- int nand_chunk,
- const __u8 *buffer,
- yaffs_ext_tags *tags);
+int yaffs_query_init_block_state(struct yaffs_dev *dev,
+ int block_no,
+ enum yaffs_block_state *state,
+ 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 block_no,
- 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);
+int yaffs_init_nand(struct yaffs_dev *dev);
+int yaffs_deinit_nand(struct yaffs_dev *dev);
#endif
-
+++ /dev/null
-/*
- * 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
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#include "yaffs_packedtags1.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->serial_number = t->serial_number;
pt->obj_id = t->obj_id;
pt->ecc = 0;
pt->deleted = (t->is_deleted) ? 0 : 1;
- pt->unusedStuff = 0;
- pt->shouldBeFF = 0xFFFFFFFF;
-
+ pt->unused_stuff = 0;
+ 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;
- if (pt->shouldBeFF != 0xFFFFFFFF)
+ if (pt->should_be_ff != 0xffffffff)
t->block_bad = 1;
t->chunk_used = 1;
t->obj_id = pt->obj_id;
t->is_deleted = (pt->deleted) ? 0 : 1;
t->serial_number = pt->serial_number;
} else {
- memset(t, 0, sizeof(yaffs_ext_tags));
+ memset(t, 0, sizeof(struct yaffs_ext_tags));
}
}
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#include "yaffs_guts.h"
-typedef struct {
+struct yaffs_packed_tags1 {
unsigned chunk_id:20;
unsigned serial_number:2;
unsigned n_bytes:10;
unsigned obj_id:18;
unsigned ecc:12;
unsigned deleted:1;
- unsigned unusedStuff:1;
- unsigned shouldBeFF;
+ unsigned unused_stuff:1;
+ unsigned should_be_ff;
-} yaffs_PackedTags1;
+};
-void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t);
-void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt);
+void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
+ const struct yaffs_ext_tags *t);
+void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
+ const struct yaffs_packed_tags1 *pt);
#endif
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#include "yaffs_packedtags2.h"
#include "yportenv.h"
#include "yaffs_trace.h"
-#include "yaffs_tagsvalidity.h"
/* This code packs a set of extended tags into a binary structure for
* NAND storage
#define EXTRA_SHADOWS_FLAG 0x20000000
#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. */
#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_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt)
+static void yaffs_dump_packed_tags2_tags_only(
+ const struct yaffs_packed_tags2_tags_only *ptt)
{
- T(YAFFS_TRACE_MTD,
- (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
- ptt->obj_id, ptt->chunk_id, ptt->n_bytes,
- ptt->seq_number));
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "packed tags obj %d chunk %d byte %d seq %d",
+ ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
}
-static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
+
+static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
{
- yaffs_DumpPackedTags2TagsPart(&pt->t);
+ yaffs_dump_packed_tags2_tags_only(&pt->t);
}
-static void yaffs_DumpTags2(const yaffs_ext_tags *t)
+static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
{
- T(YAFFS_TRACE_MTD,
- (TSTR
- ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
- TENDSTR), 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));
+ 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,
- const yaffs_ext_tags *t)
+static int yaffs_check_tags_extra_packable(const struct 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->seq_number = t->seq_number;
ptt->n_bytes = t->n_bytes;
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 */
/* We save the parent object in the chunk_id */
- ptt->chunk_id = EXTRA_HEADER_INFO_FLAG
- | t->extra_parent_id;
+ ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
if (t->extra_is_shrink)
ptt->chunk_id |= EXTRA_SHRINK_FLAG;
if (t->extra_shadows)
ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
- ptt->obj_id |=
- (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
+ ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
ptt->n_bytes = t->extra_equiv_id;
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
ptt->n_bytes = 0;
}
- yaffs_DumpPackedTags2TagsPart(ptt);
- yaffs_DumpTags2(t);
+ yaffs_dump_packed_tags2_tags_only(ptt);
+ yaffs_dump_tags2(t);
}
-
-void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC)
+void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
+ 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,
- sizeof(yaffs_PackedTags2TagsPart),
- &pt->ecc);
+ sizeof(struct yaffs_packed_tags2_tags_only),
+ &pt->ecc);
}
-
-void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t,
- yaffs_PackedTags2TagsPart *ptt)
+void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
+ struct yaffs_packed_tags2_tags_only *ptt)
{
+ memset(t, 0, sizeof(struct yaffs_ext_tags));
+
+ if (ptt->seq_number == 0xffffffff)
+ return;
+
+ 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;
+
+ /* Do extra header info stuff */
+ if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
+ t->chunk_id = 0;
+ t->n_bytes = 0;
+
+ 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;
- memset(t, 0, sizeof(yaffs_ext_tags));
-
- yaffs_init_tags(t);
-
- if (ptt->seq_number != 0xFFFFFFFF) {
- 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;
-
- /* Do extra header info stuff */
-
- if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
- t->chunk_id = 0;
- t->n_bytes = 0;
-
- 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;
- }
+ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
+ t->extra_equiv_id = ptt->n_bytes;
+ else
+ t->extra_file_size = ptt->n_bytes;
}
-
- yaffs_DumpPackedTags2TagsPart(ptt);
- yaffs_DumpTags2(t);
-
+ yaffs_dump_packed_tags2_tags_only(ptt);
+ yaffs_dump_tags2(t);
}
-
-void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC)
+void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
+ 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 &&
- tagsECC){
+ if (pt->t.seq_number != 0xffffffff && tags_ecc) {
/* Chunk is in use and we need to do ECC */
-
- yaffs_ECCOther ecc;
+
+ struct yaffs_ecc_other ecc;
int result;
yaffs_ecc_calc_other((unsigned char *)&pt->t,
- sizeof(yaffs_PackedTags2TagsPart),
- &ecc);
- result = yaffs_ecc_correct_other((unsigned char *)&pt->t,
- sizeof(yaffs_PackedTags2TagsPart),
- &pt->ecc, &ecc);
+ sizeof(struct yaffs_packed_tags2_tags_only),
+ &ecc);
+ result =
+ yaffs_ecc_correct_other((unsigned char *)&pt->t,
+ sizeof(struct yaffs_packed_tags2_tags_only),
+ &pt->ecc, &ecc);
switch (result) {
- case 0:
- ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
- break;
- case 1:
- ecc_result = YAFFS_ECC_RESULT_FIXED;
- break;
- case -1:
- ecc_result = YAFFS_ECC_RESULT_UNFIXED;
- break;
- default:
- ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
+ case 0:
+ ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+ break;
+ case 1:
+ ecc_result = YAFFS_ECC_RESULT_FIXED;
+ break;
+ case -1:
+ ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+ break;
+ default:
+ ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
}
}
-
- yaffs_unpack_tags2tags_part(t, &pt->t);
+ yaffs_unpack_tags2_tags_only(t, &pt->t);
t->ecc_result = ecc_result;
- yaffs_DumpPackedTags2(pt);
- yaffs_DumpTags2(t);
+ yaffs_dump_packed_tags2(pt);
+ yaffs_dump_tags2(t);
}
-
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#include "yaffs_guts.h"
#include "yaffs_ecc.h"
-typedef struct {
+struct yaffs_packed_tags2_tags_only {
unsigned seq_number;
unsigned obj_id;
unsigned chunk_id;
unsigned n_bytes;
-} yaffs_PackedTags2TagsPart;
+};
-typedef struct {
- yaffs_PackedTags2TagsPart t;
- yaffs_ECCOther ecc;
-} yaffs_PackedTags2;
+struct yaffs_packed_tags2 {
+ struct yaffs_packed_tags2_tags_only t;
+ struct yaffs_ecc_other ecc;
+};
/* Full packed tags with ECC, used for oob tags */
-void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC);
-void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC);
+void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
+ 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 */
-void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ext_tags *t);
-void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t, yaffs_PackedTags2TagsPart *pt);
+void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *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
+++ /dev/null
-/*
- * 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);*/
-}
+++ /dev/null
-/*
- * 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
--- /dev/null
+/*
+ * 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++;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#include "yaffs_getblockinfo.h"
#include "yaffs_trace.h"
-static void yaffs_handle_rd_data_error(yaffs_dev_t *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;
-}
+static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
+
/********** 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 */
-
- unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes;
+ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
unsigned i, j;
unsigned ecc = 0;
unsigned bit = 0;
ecc ^= bit;
}
}
-
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;
if (ecc && ecc <= 64) {
/* 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--;
/* TODO Need to do somethiong here */
return -1; /* unrecovered error */
}
-
return 0;
}
/********** Tags **********/
-static void yaffs_load_tags_to_spare(yaffs_spare *sparePtr,
- yaffs_tags_t *tagsPtr)
+static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
+ struct yaffs_tags *tags_ptr)
{
- yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr;
-
- yaffs_calc_tags_ecc(tagsPtr);
-
- sparePtr->tb0 = tu->as_bytes[0];
- sparePtr->tb1 = tu->as_bytes[1];
- sparePtr->tb2 = tu->as_bytes[2];
- sparePtr->tb3 = tu->as_bytes[3];
- sparePtr->tb4 = tu->as_bytes[4];
- sparePtr->tb5 = tu->as_bytes[5];
- sparePtr->tb6 = tu->as_bytes[6];
- sparePtr->tb7 = tu->as_bytes[7];
+ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
+
+ yaffs_calc_tags_ecc(tags_ptr);
+
+ spare_ptr->tb0 = tu->as_bytes[0];
+ spare_ptr->tb1 = tu->as_bytes[1];
+ spare_ptr->tb2 = tu->as_bytes[2];
+ spare_ptr->tb3 = tu->as_bytes[3];
+ spare_ptr->tb4 = tu->as_bytes[4];
+ spare_ptr->tb5 = tu->as_bytes[5];
+ spare_ptr->tb6 = tu->as_bytes[6];
+ spare_ptr->tb7 = tu->as_bytes[7];
}
-static void yaffs_get_tags_from_spare(yaffs_dev_t *dev, yaffs_spare *sparePtr,
- yaffs_tags_t *tagsPtr)
+static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
+ 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;
- tu->as_bytes[0] = sparePtr->tb0;
- tu->as_bytes[1] = sparePtr->tb1;
- tu->as_bytes[2] = sparePtr->tb2;
- tu->as_bytes[3] = sparePtr->tb3;
- tu->as_bytes[4] = sparePtr->tb4;
- tu->as_bytes[5] = sparePtr->tb5;
- tu->as_bytes[6] = sparePtr->tb6;
- tu->as_bytes[7] = sparePtr->tb7;
+ tu->as_bytes[0] = spare_ptr->tb0;
+ tu->as_bytes[1] = spare_ptr->tb1;
+ tu->as_bytes[2] = spare_ptr->tb2;
+ tu->as_bytes[3] = spare_ptr->tb3;
+ tu->as_bytes[4] = spare_ptr->tb4;
+ tu->as_bytes[5] = spare_ptr->tb5;
+ tu->as_bytes[6] = spare_ptr->tb6;
+ tu->as_bytes[7] = spare_ptr->tb7;
- result = yaffs_check_tags_ecc(tagsPtr);
+ result = yaffs_check_tags_ecc(tags_ptr);
if (result > 0)
dev->n_tags_ecc_fixed++;
else if (result < 0)
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,
- int nand_chunk, const __u8 *data,
- yaffs_spare *spare)
+static int yaffs_wr_nand(struct yaffs_dev *dev,
+ int nand_chunk, const u8 *data,
+ struct yaffs_spare *spare)
{
- if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
- T(YAFFS_TRACE_ERROR,
- (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
- nand_chunk));
- return YAFFS_FAIL;
- }
+ int data_size = dev->data_bytes_per_chunk;
- 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,
- int nand_chunk,
- __u8 *data,
- yaffs_spare *spare,
- yaffs_ecc_result *ecc_result,
- int doErrorCorrection)
+static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
+ int nand_chunk,
+ u8 *data,
+ struct yaffs_spare *spare,
+ enum yaffs_ecc_result *ecc_result,
+ int correct_errors)
{
- int retVal;
- yaffs_spare localSpare;
-
- if (!spare && data) {
+ int ret_val;
+ struct yaffs_spare local_spare;
+ int data_size;
+ int spare_size;
+ int ecc_result1, ecc_result2;
+ u8 calc_ecc[3];
+
+ if (!spare) {
/* If we don't have a real spare, then we use a local one. */
/* Need this for the calculation of the ecc */
- spare = &localSpare;
+ spare = &local_spare;
}
-
- if (!dev->param.use_nand_ecc) {
- retVal = dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
- if (data && doErrorCorrection) {
- /* Do ECC correction */
- /* Todo handle any errors */
- int ecc_result1, ecc_result2;
- __u8 calcEcc[3];
-
- yaffs_ecc_cacl(data, calcEcc);
- ecc_result1 =
- 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;
-
- }
+ 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++;
}
- return retVal;
-}
-#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 (ecc_result2 > 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>yaffs ecc error fix performed on chunk %d:1",
+ nand_chunk);
+ dev->n_ecc_fixed++;
+ } else if (ecc_result2 < 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>yaffs ecc error unfixed on chunk %d:1",
+ nand_chunk);
+ dev->n_ecc_unfixed++;
}
- if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
- return YAFFS_FAIL;
- if (memcmp(cmpbuf, spare, 16))
- return YAFFS_FAIL;
+ if (ecc_result1 || ecc_result2) {
+ /* We had a data problem on this page */
+ yaffs_handle_rd_data_error(dev, nand_chunk);
+ }
- return YAFFS_OK;
+ 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;
}
-#endif
/*
* 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;
/* Mark the block for retirement */
- yaffs_get_block_info(dev, flash_block + dev->block_offset)->needs_retiring = 1;
- T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
- (TSTR("**>>Block %d marked for retirement" TENDSTR), flash_block));
+ yaffs_get_block_info(dev, flash_block + dev->block_offset)->
+ needs_retiring = 1;
+ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+ "**>>Block %d marked for retirement",
+ flash_block);
/* TODO:
* Just do a garbage collection on the affected block
*/
}
-#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)
-{
- 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)
+static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
+ int nand_chunk,
+ const u8 *data, const struct yaffs_ext_tags *ext_tags)
{
- yaffs_spare spare;
- yaffs_tags_t tags;
+ struct yaffs_spare spare;
+ struct yaffs_tags tags;
yaffs_spare_init(&spare);
- if (eTags->is_deleted)
+ if (ext_tags->is_deleted)
spare.page_status = 0;
else {
- tags.obj_id = eTags->obj_id;
- tags.chunk_id = eTags->chunk_id;
+ tags.obj_id = ext_tags->obj_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)
- tags.n_bytes_msb = (eTags->n_bytes >> 10) & 3;
+ tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
else
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_calc_ecc(data, &spare);
+ if (!dev->param.use_nand_ecc && data) {
+ yaffs_ecc_calc(data, spare.ecc1);
+ yaffs_ecc_calc(&data[256], spare.ecc2);
+ }
yaffs_load_tags_to_spare(&spare, &tags);
-
}
-
return yaffs_wr_nand(dev, nand_chunk, data, &spare);
}
-int yaffs_tags_compat_rd(yaffs_dev_t *dev,
- int nand_chunk,
- __u8 *data,
- yaffs_ext_tags *eTags)
+static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
+ int nand_chunk,
+ u8 *data, struct yaffs_ext_tags *ext_tags)
{
-
- yaffs_spare spare;
- yaffs_tags_t tags;
- yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
-
- static yaffs_spare spareFF;
+ struct yaffs_spare spare;
+ struct yaffs_tags tags;
+ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
+ static struct yaffs_spare spare_ff;
static int init;
+ int deleted;
if (!init) {
- memset(&spareFF, 0xFF, sizeof(spareFF));
+ memset(&spare_ff, 0xff, sizeof(spare_ff));
init = 1;
}
- if (yaffs_rd_chunk_nand
- (dev, nand_chunk, data, &spare, &ecc_result, 1)) {
- /* eTags may be NULL */
- if (eTags) {
-
- int deleted =
- (yaffs_count_bits(spare.page_status) < 7) ? 1 : 0;
+ if (!yaffs_rd_chunk_nand(dev, nand_chunk,
+ data, &spare, &ecc_result, 1))
+ return YAFFS_FAIL;
- 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;
+ /* ext_tags may be NULL */
+ if (!ext_tags)
+ return YAFFS_OK;
- if (eTags->chunk_used) {
- yaffs_get_tags_from_spare(dev, &spare, &tags);
+ deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
- eTags->obj_id = tags.obj_id;
- eTags->chunk_id = tags.chunk_id;
- eTags->n_bytes = tags.n_bytes_lsb;
+ 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 (dev->data_bytes_per_chunk >= 1024)
- eTags->n_bytes |= (((unsigned) tags.n_bytes_msb) << 10);
+ 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;
- eTags->serial_number = tags.serial_number;
- }
- }
+ if (dev->data_bytes_per_chunk >= 1024)
+ ext_tags->n_bytes |=
+ (((unsigned)tags.n_bytes_msb) << 10);
- return YAFFS_OK;
- } else {
- return YAFFS_FAIL;
+ ext_tags->serial_number = tags.serial_number;
}
+
+ return YAFFS_OK;
}
-int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev,
- int flash_block)
+static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
{
+ struct yaffs_spare spare;
- yaffs_spare spare;
-
- memset(&spare, 0xff, sizeof(yaffs_spare));
+ memset(&spare, 0xff, sizeof(struct yaffs_spare));
spare.block_status = 'Y';
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,
- NULL, &spare);
+ NULL, &spare);
return YAFFS_OK;
-
}
-int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev,
- int block_no,
- yaffs_block_state_t *state,
- __u32 *seq_number)
+static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
+ int block_no,
+ enum yaffs_block_state *state,
+ u32 *seq_number)
{
-
- yaffs_spare spare0, spare1;
- static yaffs_spare spareFF;
+ struct yaffs_spare spare0, spare1;
+ static struct yaffs_spare spare_ff;
static int init;
- yaffs_ecc_result dummy;
+ enum yaffs_ecc_result dummy;
if (!init) {
- memset(&spareFF, 0xFF, sizeof(spareFF));
+ memset(&spare_ff, 0xff, sizeof(spare_ff));
init = 1;
}
*seq_number = 0;
- yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL,
- &spare0, &dummy, 1);
- yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, NULL,
- &spare1, &dummy, 1);
+ /* Look for bad block markers in the first two chunks */
+ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block,
+ NULL, &spare0, &dummy, 0);
+ 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;
- else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
+ else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
*state = YAFFS_BLOCK_STATE_EMPTY;
else
- *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
+ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
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;
+}
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#ifndef __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);
-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
--- /dev/null
+/*
+ * 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;
+
+}
--- /dev/null
+/*
+ * 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_TAGSMARSHALL_H__
+#define __YAFFS_TAGSMARSHALL_H__
+
+#include "yaffs_guts.h"
+void yaffs_tags_marshall_install(struct yaffs_dev *dev);
+
+#endif
+++ /dev/null
-/*
- * 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);
-
-}
+++ /dev/null
-/*
- * 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
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
-
#ifndef __YTRACE_H__
#define __YTRACE_H__
#define YAFFS_TRACE_VERIFY 0x00010000
#define YAFFS_TRACE_VERIFY_NAND 0x00020000
#define YAFFS_TRACE_VERIFY_FULL 0x00040000
-#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
+#define YAFFS_TRACE_VERIFY_ALL 0x000f0000
#define YAFFS_TRACE_SYNC 0x00100000
#define YAFFS_TRACE_BACKGROUND 0x00200000
#define YAFFS_TRACE_LOCK 0x00400000
+#define YAFFS_TRACE_MOUNT 0x00800000
#define YAFFS_TRACE_ERROR 0x40000000
#define YAFFS_TRACE_BUG 0x80000000
-#define YAFFS_TRACE_ALWAYS 0xF0000000
-
-
-#define T(mask, p) do { if ((mask) & (yaffs_trace_mask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
+#define YAFFS_TRACE_ALWAYS 0xf0000000
#endif
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
* published by the Free Software Foundation.
*/
-
#include "yaffs_verify.h"
#include "yaffs_trace.h"
#include "yaffs_bitmap.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_nand.h"
-int yaffs_skip_verification(yaffs_dev_t *dev)
+int yaffs_skip_verification(struct yaffs_dev *dev)
{
- dev=dev;
- return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
+ (void) dev;
+ 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));
}
-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));
}
-
-static const char *block_stateName[] = {
-"Unknown",
-"Needs scanning",
-"Scanning",
-"Empty",
-"Allocating",
-"Full",
-"Dirty",
-"Checkpoint",
-"Collecting",
-"Dead"
+static const char * const block_state_name[] = {
+ "Unknown",
+ "Needs scan",
+ "Scanning",
+ "Empty",
+ "Allocating",
+ "Full",
+ "Dirty",
+ "Checkpoint",
+ "Collecting",
+ "Dead"
};
-
-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, int n)
{
- int actuallyUsed;
- int inUse;
+ int actually_used;
+ int in_use;
if (yaffs_skip_verification(dev))
return;
/* Report illegal runtime states */
if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
- T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->block_state));
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Block %d has undefined state %d",
+ n, bi->block_state);
switch (bi->block_state) {
case YAFFS_BLOCK_STATE_UNKNOWN:
case YAFFS_BLOCK_STATE_SCANNING:
- case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
- T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
- n, block_stateName[bi->block_state]));
+ case YAFFS_BLOCK_STATE_NEEDS_SCAN:
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Block %d has bad run-state %s",
+ n, block_state_name[bi->block_state]);
}
/* Check pages in use and soft deletions are legal */
- actuallyUsed = bi->pages_in_use - bi->soft_del_pages;
-
- if (bi->pages_in_use < 0 || bi->pages_in_use > dev->param.chunks_per_block ||
- bi->soft_del_pages < 0 || bi->soft_del_pages > dev->param.chunks_per_block ||
- actuallyUsed < 0 || actuallyUsed > dev->param.chunks_per_block)
- T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pages_in_used %d soft_del_pages %d"TENDSTR),
- n, bi->pages_in_use, bi->soft_del_pages));
+ 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 ||
+ 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 */
- inUse = yaffs_count_chunk_bits(dev, n);
- if (inUse != bi->pages_in_use)
- T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pages_in_use %d counted chunk bits %d"TENDSTR),
- n, bi->pages_in_use, inUse));
-
+ in_use = yaffs_count_chunk_bits(dev, n);
+ if (in_use != bi->pages_in_use)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "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(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n)
+void yaffs_verify_collected_blk(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi, int n)
{
yaffs_verify_blk(dev, bi, n);
/* After collection the block should be in the erased state */
if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
- bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
- T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
- n, bi->block_state));
+ bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "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 nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
- int nIllegalBlockStates = 0;
+ int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
+ int illegal_states = 0;
if (yaffs_skip_verification(dev))
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++) {
- 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);
if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
- nBlocksPerState[bi->block_state]++;
+ state_count[bi->block_state]++;
else
- nIllegalBlockStates++;
+ illegal_states++;
}
- T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
- T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary");
- T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
- if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
- T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "%d blocks have illegal states",
+ 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++)
- T(YAFFS_TRACE_VERIFY,
- (TSTR("%s %d blocks"TENDSTR),
- block_stateName[i], nBlocksPerState[i]));
-
- if (dev->blocks_in_checkpt != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
- dev->blocks_in_checkpt, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
-
- if (dev->n_erased_blocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
- dev->n_erased_blocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
-
- if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
- nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
-
- T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
-
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "%s %d blocks",
+ block_state_name[i], state_count[i]);
+
+ if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Checkpoint block count wrong dev %d count %d",
+ dev->blocks_in_checkpt,
+ state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
+
+ if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Erased block count wrong dev %d count %d",
+ dev->n_erased_blocks,
+ state_count[YAFFS_BLOCK_STATE_EMPTY]);
+
+ 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
- * case those tests will not be performed.
+ * Verify the object header. oh must be valid, but obj and tags may be NULL in
+ * which case those tests will not be performed.
*/
-void yaffs_verify_oh(yaffs_obj_t *obj, yaffs_obj_header *oh, yaffs_ext_tags *tags, int parentCheck)
+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))
return;
if (!(tags && obj && oh)) {
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
- tags, obj, oh));
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Verifying object header tags %p obj %p oh %p",
+ tags, obj, oh);
return;
}
if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
- oh->type > YAFFS_OBJECT_TYPE_MAX)
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
- tags->obj_id, oh->type));
+ oh->type > YAFFS_OBJECT_TYPE_MAX)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d header type is illegal value 0x%x",
+ tags->obj_id, oh->type);
if (tags->obj_id != obj->obj_id)
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d header mismatch obj_id %d"TENDSTR),
- tags->obj_id, obj->obj_id));
-
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d header mismatch obj_id %d",
+ 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.
*/
- if (parentCheck && tags->obj_id > 1 && !obj->parent)
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d header mismatch parent_id %d obj->parent is NULL"TENDSTR),
- tags->obj_id, oh->parent_obj_id));
-
- if (parentCheck && obj->parent &&
- oh->parent_obj_id != obj->parent->obj_id &&
- (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
- obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d header mismatch parent_id %d parent_obj_id %d"TENDSTR),
- tags->obj_id, oh->parent_obj_id, obj->parent->obj_id));
-
- if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d header name is NULL"TENDSTR),
- obj->obj_id));
-
- if (tags->obj_id > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d header name is 0xFF"TENDSTR),
- obj->obj_id));
+ if (parent_check && tags->obj_id > 1 && !obj->parent)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d header mismatch parent_id %d obj->parent is NULL",
+ tags->obj_id, oh->parent_obj_id);
+
+ if (parent_check && obj->parent &&
+ oh->parent_obj_id != obj->parent->obj_id &&
+ (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
+ obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d header mismatch parent_id %d parent_obj_id %d",
+ tags->obj_id, oh->parent_obj_id,
+ obj->parent->obj_id);
+
+ if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d header name is NULL",
+ obj->obj_id);
+
+ if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d header name is 0xff",
+ obj->obj_id);
}
-
-#if 0
-/* Not being used, but don't want to throw away yet */
-int yaffs_verify_tnode_worker(yaffs_obj_t *obj, yaffs_tnode_t *tn,
- __u32 level, int chunk_offset)
+void yaffs_verify_file(struct yaffs_obj *obj)
{
- int i;
- yaffs_dev_t *dev = obj->my_dev;
- int ok = 1;
-
- if (tn) {
- if (level > 0) {
-
- for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
- if (tn->internal[i]) {
- ok = yaffs_verify_tnode_worker(obj,
- tn->internal[i],
- level - 1,
- (chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i);
- }
- }
- } else if (level == 0) {
- yaffs_ext_tags tags;
- __u32 obj_id = obj->obj_id;
-
- chunk_offset <<= YAFFS_TNODES_LEVEL0_BITS;
-
- for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
- __u32 theChunk = yaffs_get_group_base(dev, tn, i);
-
- if (theChunk > 0) {
- /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.obj_id,tags.chunk_id,theChunk)); */
- yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags);
- if (tags.obj_id != obj_id || tags.chunk_id != chunk_offset) {
- T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
- obj_id, chunk_offset, theChunk,
- tags.obj_id, tags.chunk_id));
- }
- }
- chunk_offset++;
- }
- }
- }
-
- return ok;
-
-}
-
-#endif
-
-void yaffs_verify_file(yaffs_obj_t *obj)
-{
- int requiredTallness;
- int actualTallness;
- __u32 lastChunk;
- __u32 x;
- __u32 i;
- yaffs_dev_t *dev;
- yaffs_ext_tags tags;
- yaffs_tnode_t *tn;
- __u32 obj_id;
+ u32 x;
+ int required_depth;
+ int actual_depth;
+ int last_chunk;
+ u32 offset_in_chunk;
+ u32 the_chunk;
+
+ u32 i;
+ struct yaffs_dev *dev;
+ struct yaffs_ext_tags tags;
+ struct yaffs_tnode *tn;
+ u32 obj_id;
if (!obj)
return;
dev = obj->my_dev;
obj_id = obj->obj_id;
+
/* Check file size is consistent with tnode depth */
- lastChunk = obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1;
- x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
- requiredTallness = 0;
+ yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
+ &last_chunk, &offset_in_chunk);
+ last_chunk++;
+ x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
+ required_depth = 0;
while (x > 0) {
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.
* We do this by scanning through the tnode tree and
if (yaffs_skip_nand_verification(dev))
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);
- if (tn) {
- __u32 theChunk = yaffs_get_group_base(dev, tn, i);
- if (theChunk > 0) {
- /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),obj_id,i,theChunk)); */
- yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags);
- if (tags.obj_id != obj_id || tags.chunk_id != i) {
- T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
- obj_id, i, theChunk,
- tags.obj_id, tags.chunk_id));
- }
- }
+ if (!tn)
+ continue;
+
+ the_chunk = yaffs_get_group_base(dev, tn, i);
+ if (the_chunk > 0) {
+ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
+ &tags);
+ if (tags.obj_id != obj_id || tags.chunk_id != i)
+ 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(yaffs_obj_t *obj)
+void yaffs_verify_link(struct yaffs_obj *obj)
{
if (obj && yaffs_skip_verification(obj->my_dev))
return;
/* 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))
return;
/* 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))
return;
}
-void yaffs_verify_obj(yaffs_obj_t *obj)
+void yaffs_verify_obj(struct yaffs_obj *obj)
{
- yaffs_dev_t *dev;
-
- __u32 chunkMin;
- __u32 chunkMax;
-
- __u32 chunk_idOk;
- __u32 chunkInRange;
- __u32 chunkShouldNotBeDeleted;
- __u32 chunkValid;
+ struct yaffs_dev *dev;
+ u32 chunk_min;
+ u32 chunk_max;
+ u32 chunk_id_ok;
+ u32 chunk_in_range;
+ u32 chunk_wrongly_deleted;
+ u32 chunk_valid;
if (!obj)
return;
/* Check sane object header chunk */
- chunkMin = dev->internal_start_block * dev->param.chunks_per_block;
- chunkMax = (dev->internal_end_block+1) * dev->param.chunks_per_block - 1;
-
- chunkInRange = (((unsigned)(obj->hdr_chunk)) >= chunkMin && ((unsigned)(obj->hdr_chunk)) <= chunkMax);
- chunk_idOk = chunkInRange || (obj->hdr_chunk == 0);
- chunkValid = chunkInRange &&
- yaffs_check_chunk_bit(dev,
- obj->hdr_chunk / dev->param.chunks_per_block,
- obj->hdr_chunk % dev->param.chunks_per_block);
- chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
-
- if (!obj->fake &&
- (!chunk_idOk || chunkShouldNotBeDeleted)) {
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d has chunk_id %d %s %s"TENDSTR),
+ chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
+ chunk_max =
+ (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
+
+ chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
+ ((unsigned)(obj->hdr_chunk)) <= chunk_max);
+ chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
+ chunk_valid = chunk_in_range &&
+ yaffs_check_chunk_bit(dev,
+ obj->hdr_chunk / dev->param.chunks_per_block,
+ obj->hdr_chunk % dev->param.chunks_per_block);
+ chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
+
+ if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d has chunk_id %d %s %s",
obj->obj_id, obj->hdr_chunk,
- chunk_idOk ? "" : ",out of range",
- chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
- }
+ chunk_id_ok ? "" : ",out of range",
+ chunk_wrongly_deleted ? ",marked as deleted" : "");
- if (chunkValid && !yaffs_skip_nand_verification(dev)) {
- yaffs_ext_tags tags;
- yaffs_obj_header *oh;
- __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
+ if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
+ struct yaffs_ext_tags tags;
+ struct yaffs_obj_hdr *oh;
+ 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,
- &tags);
+ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
yaffs_verify_oh(obj, oh, &tags, 1);
- yaffs_release_temp_buffer(dev, buffer, __LINE__);
+ yaffs_release_temp_buffer(dev, buffer);
}
/* Verify it has a parent */
- if (obj && !obj->fake &&
- (!obj->parent || obj->parent->my_dev != dev)) {
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
- obj->obj_id, obj->parent));
+ if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d has parent pointer %p which does not look like an object",
+ obj->obj_id, obj->parent);
}
/* Verify parent is a directory */
- if (obj->parent && obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
- obj->obj_id, obj->parent->variant_type));
+ if (obj->parent &&
+ obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d's parent is not a directory (type %d)",
+ obj->obj_id, obj->parent->variant_type);
}
switch (obj->variant_type) {
break;
case YAFFS_OBJECT_TYPE_UNKNOWN:
default:
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d has illegaltype %d"TENDSTR),
- obj->obj_id, obj->variant_type));
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d has illegaltype %d",
+ obj->obj_id, obj->variant_type);
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;
- struct ylist_head *lh;
+ struct list_head *lh;
if (yaffs_skip_verification(dev))
return;
/* Iterate through the objects in each hash entry */
- for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
- ylist_for_each(lh, &dev->obj_bucket[i].list) {
- if (lh) {
- obj = ylist_entry(lh, yaffs_obj_t, hash_link);
- yaffs_verify_obj(obj);
- }
+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+ list_for_each(lh, &dev->obj_bucket[i].list) {
+ obj = list_entry(lh, struct yaffs_obj, hash_link);
+ yaffs_verify_obj(obj);
}
}
}
-
-void yaffs_verify_obj_in_dir(yaffs_obj_t *obj)
+void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
{
- struct ylist_head *lh;
- yaffs_obj_t *listObj;
-
+ struct list_head *lh;
+ struct yaffs_obj *list_obj;
int count = 0;
if (!obj) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
- YBUG();
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
+ BUG();
return;
}
return;
if (!obj->parent) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
- YBUG();
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
+ BUG();
return;
}
if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
- YBUG();
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
+ BUG();
}
/* Iterate through the objects in each hash entry */
- ylist_for_each(lh, &obj->parent->variant.dir_variant.children) {
- if (lh) {
- listObj = ylist_entry(lh, yaffs_obj_t, siblings);
- yaffs_verify_obj(listObj);
- if (obj == listObj)
- count++;
- }
- }
+ list_for_each(lh, &obj->parent->variant.dir_variant.children) {
+ list_obj = list_entry(lh, struct yaffs_obj, siblings);
+ yaffs_verify_obj(list_obj);
+ if (obj == list_obj)
+ count++;
+ }
if (count != 1) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
- YBUG();
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "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;
- yaffs_obj_t *listObj;
+ struct list_head *lh;
+ struct yaffs_obj *list_obj;
if (!directory) {
- YBUG();
+ BUG();
return;
}
return;
if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variant_type));
- YBUG();
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "Directory has wrong type: %d",
+ directory->variant_type);
+ BUG();
}
/* Iterate through the objects in each hash entry */
- ylist_for_each(lh, &directory->variant.dir_variant.children) {
- if (lh) {
- listObj = ylist_entry(lh, yaffs_obj_t, siblings);
- if (listObj->parent != directory) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
- YBUG();
- }
- yaffs_verify_obj_in_dir(listObj);
+ list_for_each(lh, &directory->variant.dir_variant.children) {
+ list_obj = list_entry(lh, struct yaffs_obj, siblings);
+ if (list_obj->parent != directory) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "Object in directory list has wrong parent %p",
+ list_obj->parent);
+ BUG();
}
+ yaffs_verify_obj_in_dir(list_obj);
}
}
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 difference;
difference = dev->n_free_chunks - counted;
if (difference) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
- dev->n_free_chunks, counted, difference));
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "Freechunks verification failure %d %d %d",
+ dev->n_free_chunks, counted, difference);
yaffs_free_verification_failures++;
}
}
-int yaffs_verify_file_sane(yaffs_obj_t *in)
+int yaffs_verify_file_sane(struct yaffs_obj *in)
{
-#if 0
- int chunk;
- int n_chunks;
- int fSize;
- int failed = 0;
- int obj_id;
- yaffs_tnode_t *tn;
- yaffs_tags_t localTags;
- yaffs_tags_t *tags = &localTags;
- int theChunk;
- int is_deleted;
-
- if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
- return YAFFS_FAIL;
-
- obj_id = in->obj_id;
- fSize = in->variant.file_variant.file_size;
- n_chunks =
- (fSize + in->my_dev->data_bytes_per_chunk - 1) / in->my_dev->data_bytes_per_chunk;
-
- for (chunk = 1; chunk <= n_chunks; chunk++) {
- tn = yaffs_find_tnode_0(in->my_dev, &in->variant.file_variant,
- chunk);
-
- if (tn) {
-
- theChunk = yaffs_get_group_base(dev, tn, chunk);
-
- if (yaffs_check_chunk_bits
- (dev, theChunk / dev->param.chunks_per_block,
- theChunk % dev->param.chunks_per_block)) {
-
- yaffs_rd_chunk_tags_nand(in->my_dev, theChunk,
- tags,
- &is_deleted);
- if (yaffs_tags_match
- (tags, in->obj_id, chunk, is_deleted)) {
- /* found it; */
-
- }
- } else {
-
- failed = 1;
- }
-
- } else {
- /* T(("No level 0 found for %d\n", chunk)); */
- }
- }
-
- return failed ? YAFFS_FAIL : YAFFS_OK;
-#else
- in=in;
+ (void) in;
return YAFFS_OK;
-#endif
}
/*
- * 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
*
* 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
+ * 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_VERIFY_H__
#include "yaffs_guts.h"
-void yaffs_verify_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n);
-void yaffs_verify_collected_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n);
-void yaffs_verify_blocks(yaffs_dev_t *dev);
+void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
+ int n);
+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_file(yaffs_obj_t *obj);
-void yaffs_verify_link(yaffs_obj_t *obj);
-void yaffs_verify_symlink(yaffs_obj_t *obj);
-void yaffs_verify_special(yaffs_obj_t *obj);
-void yaffs_verify_obj(yaffs_obj_t *obj);
-void yaffs_verify_objects(yaffs_dev_t *dev);
-void yaffs_verify_obj_in_dir(yaffs_obj_t *obj);
-void yaffs_verify_dir(yaffs_obj_t *directory);
-void yaffs_verify_free_chunks(yaffs_dev_t *dev);
+void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
+ struct yaffs_ext_tags *tags, int parent_check);
+void yaffs_verify_file(struct yaffs_obj *obj);
+void yaffs_verify_link(struct yaffs_obj *obj);
+void yaffs_verify_symlink(struct yaffs_obj *obj);
+void yaffs_verify_special(struct yaffs_obj *obj);
+void yaffs_verify_obj(struct yaffs_obj *obj);
+void yaffs_verify_objects(struct yaffs_dev *dev);
+void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
+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
-
--- /dev/null
+/*
+ * 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>
+ * Acknowledgements:
+ * Luc van OostenRyck for numerous patches.
+ * Nick Bane for numerous patches.
+ * Nick Bane for 2.5/2.6 integration.
+ * Andras Toth for mknod rdev issue.
+ * Michael Fischer for finding the problem with inode inconsistency.
+ * Some code bodily lifted from JFFS
+ *
+ * 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 is the file system front-end to YAFFS that hooks it up to
+ * the VFS.
+ *
+ * Special notes:
+ * >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with
+ * this superblock
+ * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this
+ * superblock
+ * >> inode->u.generic_ip points to the associated struct yaffs_obj.
+ */
+
+/*
+ * There are two variants of the VFS glue code. This variant should compile
+ * for any version of Linux.
+ */
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
+#define YAFFS_COMPILE_BACKGROUND
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23))
+#define YAFFS_COMPILE_FREEZER
+#endif
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
+#define YAFFS_COMPILE_EXPORTFS
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
+#define YAFFS_USE_SETATTR_COPY
+#define YAFFS_USE_TRUNCATE_SETSIZE
+#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
+#define YAFFS_HAS_EVICT_INODE
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
+#define YAFFS_NEW_FOLLOW_LINK 1
+#else
+#define YAFFS_NEW_FOLLOW_LINK 0
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+#define YAFFS_HAS_WRITE_SUPER
+#endif
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
+#include <linux/config.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#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>
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+#include <linux/namei.h>
+#endif
+
+#ifdef YAFFS_COMPILE_EXPORTFS
+#include <linux/exportfs.h>
+#endif
+
+#ifdef YAFFS_COMPILE_BACKGROUND
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#endif
+#ifdef YAFFS_COMPILE_FREEZER
+#include <linux/freezer.h>
+#endif
+
+#include <asm/div64.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+
+#include <linux/statfs.h>
+
+#define UnlockPage(p) unlock_page(p)
+#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
+
+/* FIXME: use sb->s_id instead ? */
+#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
+
+#else
+
+#include <linux/locks.h>
+#define BDEVNAME_SIZE 0
+#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
+/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
+#define __user
+#endif
+
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
+#define YPROC_ROOT (&proc_root)
+#else
+#define YPROC_ROOT NULL
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
+#define Y_INIT_TIMER(a) init_timer(a)
+#else
+#define Y_INIT_TIMER(a) init_timer_on_stack(a)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
+#define YAFFS_USE_WRITE_BEGIN_END 1
+#else
+#define YAFFS_USE_WRITE_BEGIN_END 0
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+#define YAFFS_SUPER_HAS_DIRTY
+#endif
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
+#define set_nlink(inode, count) do { (inode)->i_nlink = (count); } while(0)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
+static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
+{
+ uint64_t result = partition_size;
+ do_div(result, block_size);
+ return (uint32_t) result;
+}
+#else
+#define YCALCBLOCKS(s, b) ((s)/(b))
+#endif
+
+#include <linux/uaccess.h>
+#include <linux/mtd/mtd.h>
+
+#include "yportenv.h"
+#include "yaffs_trace.h"
+#include "yaffs_guts.h"
+#include "yaffs_attribs.h"
+
+#include "yaffs_linux.h"
+
+#include "yaffs_mtdif.h"
+#include "yaffs_packedtags2.h"
+#include "yaffs_getblockinfo.h"
+
+unsigned int yaffs_trace_mask =
+ YAFFS_TRACE_BAD_BLOCKS |
+ YAFFS_TRACE_ALWAYS |
+ 0;
+
+unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
+unsigned int yaffs_auto_checkpoint = 1;
+unsigned int yaffs_gc_control = 1;
+unsigned int yaffs_bg_enable = 1;
+unsigned int yaffs_auto_select = 1;
+/* Module Parameters */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+module_param(yaffs_trace_mask, uint, 0644);
+module_param(yaffs_wr_attempts, uint, 0644);
+module_param(yaffs_auto_checkpoint, uint, 0644);
+module_param(yaffs_gc_control, uint, 0644);
+module_param(yaffs_bg_enable, uint, 0644);
+#else
+MODULE_PARM(yaffs_trace_mask, "i");
+MODULE_PARM(yaffs_wr_attempts, "i");
+MODULE_PARM(yaffs_auto_checkpoint, "i");
+MODULE_PARM(yaffs_gc_control, "i");
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
+/* use iget and read_inode */
+#define Y_IGET(sb, inum) iget((sb), (inum))
+
+#else
+/* Call local equivalent */
+#define YAFFS_USE_OWN_IGET
+#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
+
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
+#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)
+#else
+#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip)
+#endif
+
+#define yaffs_inode_to_obj(iptr) \
+ ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
+#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info)
+#else
+#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->u.generic_sbp)
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+#define Y_CLEAR_INODE(i) clear_inode(i)
+#else
+#define Y_CLEAR_INODE(i) end_writeback(i)
+#endif
+
+
+#define update_dir_time(dir) do {\
+ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
+ } while (0)
+
+static void yaffs_fill_inode_from_obj(struct inode *inode,
+ struct yaffs_obj *obj);
+
+
+static void yaffs_gross_lock(struct yaffs_dev *dev)
+{
+ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current);
+ mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock));
+ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current);
+}
+
+static void yaffs_gross_unlock(struct yaffs_dev *dev)
+{
+ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current);
+ mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock));
+}
+
+
+static int yaffs_readpage_nolock(struct file *f, struct page *pg)
+{
+ /* Lifted from jffs2 */
+
+ struct yaffs_obj *obj;
+ unsigned char *pg_buf;
+ int ret;
+ loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;
+ struct yaffs_dev *dev;
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_readpage_nolock at %lld, size %08x",
+ (long long)pos,
+ (unsigned)PAGE_CACHE_SIZE);
+
+ obj = yaffs_dentry_to_obj(f->f_dentry);
+
+ dev = obj->my_dev;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+ BUG_ON(!PageLocked(pg));
+#else
+ if (!PageLocked(pg))
+ PAGE_BUG(pg);
+#endif
+
+ pg_buf = kmap(pg);
+ /* FIXME: Can kmap fail? */
+
+ yaffs_gross_lock(dev);
+
+ ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE);
+
+ yaffs_gross_unlock(dev);
+
+ if (ret >= 0)
+ ret = 0;
+
+ if (ret) {
+ ClearPageUptodate(pg);
+ SetPageError(pg);
+ } else {
+ SetPageUptodate(pg);
+ ClearPageError(pg);
+ }
+
+ flush_dcache_page(pg);
+ kunmap(pg);
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done");
+ return ret;
+}
+
+static int yaffs_readpage_unlock(struct file *f, struct page *pg)
+{
+ int ret = yaffs_readpage_nolock(f, pg);
+ UnlockPage(pg);
+ return ret;
+}
+
+static int yaffs_readpage(struct file *f, struct page *pg)
+{
+ int ret;
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage");
+ ret = yaffs_readpage_unlock(f, pg);
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done");
+ return ret;
+}
+
+
+static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)
+{
+ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
+
+ if (lc)
+ lc->dirty = val;
+
+# ifdef YAFFS_SUPER_HAS_DIRTY
+ {
+ struct super_block *sb = lc->super;
+
+ if (sb)
+ sb->s_dirt = val;
+ }
+#endif
+
+}
+
+static void yaffs_set_super_dirty(struct yaffs_dev *dev)
+{
+ yaffs_set_super_dirty_val(dev, 1);
+}
+
+static void yaffs_clear_super_dirty(struct yaffs_dev *dev)
+{
+ yaffs_set_super_dirty_val(dev, 0);
+}
+
+static int yaffs_check_super_dirty(struct yaffs_dev *dev)
+{
+ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
+
+ if (lc && lc->dirty)
+ return 1;
+
+# ifdef YAFFS_SUPER_HAS_DIRTY
+ {
+ struct super_block *sb = lc->super;
+
+ if (sb && sb->s_dirt)
+ return 1;
+ }
+#endif
+ return 0;
+
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
+#else
+static int yaffs_writepage(struct page *page)
+#endif
+{
+ struct yaffs_dev *dev;
+ struct address_space *mapping = page->mapping;
+ struct inode *inode;
+ unsigned long end_index;
+ char *buffer;
+ struct yaffs_obj *obj;
+ int n_written = 0;
+ unsigned n_bytes;
+ loff_t i_size;
+
+ if (!mapping)
+ BUG();
+ inode = mapping->host;
+ if (!inode)
+ BUG();
+ i_size = i_size_read(inode);
+
+ end_index = i_size >> PAGE_CACHE_SHIFT;
+
+ if (page->index < end_index)
+ n_bytes = PAGE_CACHE_SIZE;
+ else {
+ n_bytes = i_size & (PAGE_CACHE_SIZE - 1);
+
+ if (page->index > end_index || !n_bytes) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_writepage at %lld, inode size = %lld!!",
+ ((loff_t)page->index) << PAGE_CACHE_SHIFT,
+ inode->i_size);
+ yaffs_trace(YAFFS_TRACE_OS,
+ " -> don't care!!");
+
+ zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+ set_page_writeback(page);
+ unlock_page(page);
+ end_page_writeback(page);
+ return 0;
+ }
+ }
+
+ if (n_bytes != PAGE_CACHE_SIZE)
+ zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE);
+
+ get_page(page);
+
+ buffer = kmap(page);
+
+ obj = yaffs_inode_to_obj(inode);
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_writepage at %lld, size %08x",
+ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes);
+ yaffs_trace(YAFFS_TRACE_OS,
+ "writepag0: obj = %lld, ino = %lld",
+ obj->variant.file_variant.file_size, inode->i_size);
+
+ n_written = yaffs_wr_file(obj, buffer,
+ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0);
+
+ yaffs_set_super_dirty(dev);
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "writepag1: obj = %lld, ino = %lld",
+ obj->variant.file_variant.file_size, inode->i_size);
+
+ yaffs_gross_unlock(dev);
+
+ kunmap(page);
+ set_page_writeback(page);
+ unlock_page(page);
+ end_page_writeback(page);
+ put_page(page);
+
+ return (n_written == n_bytes) ? 0 : -ENOSPC;
+}
+
+/* Space holding and freeing is done to ensure we have space available for write_begin/end */
+/* For now we just assume few parallel writes and check against a small number. */
+/* Todo: need to do this with a counter to handle parallel reads better */
+
+static ssize_t yaffs_hold_space(struct file *f)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_dev *dev;
+
+ int n_free_chunks;
+
+ obj = yaffs_dentry_to_obj(f->f_dentry);
+
+ dev = obj->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ n_free_chunks = yaffs_get_n_free_chunks(dev);
+
+ yaffs_gross_unlock(dev);
+
+ return (n_free_chunks > 20) ? 1 : 0;
+}
+
+static void yaffs_release_space(struct file *f)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_dev *dev;
+
+ obj = yaffs_dentry_to_obj(f->f_dentry);
+
+ dev = obj->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ yaffs_gross_unlock(dev);
+}
+
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata)
+{
+ struct page *pg = NULL;
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+
+ int ret = 0;
+ int space_held = 0;
+
+ /* Get a page */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+ pg = grab_cache_page_write_begin(mapping, index, flags);
+#else
+ pg = __grab_cache_page(mapping, index);
+#endif
+
+ *pagep = pg;
+ if (!pg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ yaffs_trace(YAFFS_TRACE_OS,
+ "start yaffs_write_begin index %d(%x) uptodate %d",
+ (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0);
+
+ /* Get fs space */
+ space_held = yaffs_hold_space(filp);
+
+ if (!space_held) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ /* Update page if required */
+
+ if (!Page_Uptodate(pg))
+ ret = yaffs_readpage_nolock(filp, pg);
+
+ if (ret)
+ goto out;
+
+ /* Happy path return */
+ yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok");
+
+ return 0;
+
+out:
+ yaffs_trace(YAFFS_TRACE_OS,
+ "end yaffs_write_begin fail returning %d", ret);
+ if (space_held)
+ yaffs_release_space(filp);
+ if (pg) {
+ unlock_page(pg);
+ page_cache_release(pg);
+ }
+ return ret;
+}
+
+#else
+
+static int yaffs_prepare_write(struct file *f, struct page *pg,
+ unsigned offset, unsigned to)
+{
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write");
+
+ if (!Page_Uptodate(pg))
+ return yaffs_readpage_nolock(f, pg);
+ return 0;
+}
+#endif
+
+
+static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
+ loff_t * pos)
+{
+ struct yaffs_obj *obj;
+ int n_written;
+ loff_t ipos;
+ struct inode *inode;
+ struct yaffs_dev *dev;
+
+ obj = yaffs_dentry_to_obj(f->f_dentry);
+
+ if (!obj) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_file_write: hey obj is null!");
+ return -EINVAL;
+ }
+
+ dev = obj->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ inode = f->f_dentry->d_inode;
+
+ if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
+ ipos = inode->i_size;
+ else
+ ipos = *pos;
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld",
+ (unsigned)n, (unsigned)n, obj->obj_id, ipos);
+
+ n_written = yaffs_wr_file(obj, buf, ipos, n, 0);
+
+ yaffs_set_super_dirty(dev);
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_file_write: %d(%x) bytes written",
+ (unsigned)n, (unsigned)n);
+
+ if (n_written > 0) {
+ ipos += n_written;
+ *pos = ipos;
+ if (ipos > inode->i_size) {
+ inode->i_size = ipos;
+ inode->i_blocks = (ipos + 511) >> 9;
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_file_write size updated to %lld bytes, %d blocks",
+ ipos, (int)(inode->i_blocks));
+ }
+
+ }
+ yaffs_gross_unlock(dev);
+ return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;
+}
+
+
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+static int yaffs_write_end(struct file *filp, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *pg, void *fsdadata)
+{
+ int ret = 0;
+ void *addr, *kva;
+ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
+
+ kva = kmap(pg);
+ addr = kva + offset_into_page;
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_write_end addr %p pos %lld n_bytes %d",
+ addr, pos, copied);
+
+ ret = yaffs_file_write(filp, addr, copied, &pos);
+
+ if (ret != copied) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_write_end not same size ret %d copied %d",
+ ret, copied);
+ SetPageError(pg);
+ }
+
+ kunmap(pg);
+
+ yaffs_release_space(filp);
+ unlock_page(pg);
+ page_cache_release(pg);
+ return ret;
+}
+#else
+
+static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
+ unsigned to)
+{
+ void *addr, *kva;
+
+ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
+ int n_bytes = to - offset;
+ int n_written;
+
+ kva = kmap(pg);
+ addr = kva + offset;
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_commit_write addr %p pos %lld n_bytes %d",
+ addr, pos, n_bytes);
+
+ n_written = yaffs_file_write(f, addr, n_bytes, &pos);
+
+ if (n_written != n_bytes) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_commit_write not same size n_written %d n_bytes %d",
+ n_written, n_bytes);
+ SetPageError(pg);
+ }
+ kunmap(pg);
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_commit_write returning %d",
+ n_written == n_bytes ? 0 : n_written);
+
+ return n_written == n_bytes ? 0 : n_written;
+}
+#endif
+
+static struct address_space_operations yaffs_file_address_operations = {
+ .readpage = yaffs_readpage,
+ .writepage = yaffs_writepage,
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+ .write_begin = yaffs_write_begin,
+ .write_end = yaffs_write_end,
+#else
+ .prepare_write = yaffs_prepare_write,
+ .commit_write = yaffs_commit_write,
+#endif
+};
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_file_flush(struct file *file, fl_owner_t id)
+#else
+static int yaffs_file_flush(struct file *file)
+#endif
+{
+ struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
+
+ struct yaffs_dev *dev = obj->my_dev;
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_file_flush object %d (%s)",
+ obj->obj_id,
+ obj->dirty ? "dirty" : "clean");
+
+ yaffs_gross_lock(dev);
+
+ yaffs_flush_file(obj, 1, 0);
+
+ yaffs_gross_unlock(dev);
+
+ return 0;
+}
+
+
+#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,
+ int datasync)
+#endif
+{
+ struct yaffs_obj *obj;
+ struct yaffs_dev *dev;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+ struct dentry *dentry = file->f_path.dentry;
+#endif
+
+ obj = yaffs_dentry_to_obj(dentry);
+
+ dev = obj->my_dev;
+
+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
+ "yaffs_sync_object");
+ yaffs_gross_lock(dev);
+ yaffs_flush_file(obj, 1, datasync);
+ yaffs_gross_unlock(dev);
+ return 0;
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
+static const struct file_operations yaffs_file_operations = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = generic_file_aio_read,
+ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .flush = yaffs_file_flush,
+ .fsync = yaffs_sync_object,
+ .splice_read = generic_file_splice_read,
+ .splice_write = generic_file_splice_write,
+ .llseek = generic_file_llseek,
+};
+
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
+
+static const struct file_operations yaffs_file_operations = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = generic_file_aio_read,
+ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .flush = yaffs_file_flush,
+ .fsync = yaffs_sync_object,
+ .sendfile = generic_file_sendfile,
+};
+
+#else
+
+static const struct file_operations yaffs_file_operations = {
+ .read = generic_file_read,
+ .write = generic_file_write,
+ .mmap = generic_file_mmap,
+ .flush = yaffs_file_flush,
+ .fsync = yaffs_sync_object,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+ .sendfile = generic_file_sendfile,
+#endif
+};
+#endif
+
+
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
+static void zero_user_segment(struct page *page, unsigned start, unsigned end)
+{
+ void *kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr + start, 0, end - start);
+ kunmap_atomic(kaddr, KM_USER0);
+ flush_dcache_page(page);
+}
+#endif
+
+
+static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
+{
+#ifdef YAFFS_USE_TRUNCATE_SETSIZE
+ truncate_setsize(inode, newsize);
+ return 0;
+#else
+ truncate_inode_pages(&inode->i_data, newsize);
+ return 0;
+#endif
+
+}
+
+
+static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
+{
+#ifdef YAFFS_USE_SETATTR_COPY
+ setattr_copy(inode, attr);
+ return 0;
+#else
+ return inode_setattr(inode, attr);
+#endif
+
+}
+
+static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ int error = 0;
+ struct yaffs_dev *dev;
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_setattr of object %d",
+ yaffs_inode_to_obj(inode)->obj_id);
+#if 0
+ /* Fail if a requested resize >= 2GB */
+ if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
+ error = -EINVAL;
+#endif
+
+ if (error == 0)
+ error = inode_change_ok(inode, attr);
+ if (error == 0) {
+ int result;
+ if (!error) {
+ error = yaffs_vfs_setattr(inode, attr);
+ yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");
+ if (attr->ia_valid & ATTR_SIZE) {
+ yaffs_vfs_setsize(inode, attr->ia_size);
+ inode->i_blocks = (inode->i_size + 511) >> 9;
+ }
+ }
+ dev = yaffs_inode_to_obj(inode)->my_dev;
+ if (attr->ia_valid & ATTR_SIZE) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "resize to %d(%x)",
+ (int)(attr->ia_size),
+ (int)(attr->ia_size));
+ }
+ yaffs_gross_lock(dev);
+ result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);
+ if (result == YAFFS_OK) {
+ error = 0;
+ } else {
+ error = -EPERM;
+ }
+ yaffs_gross_unlock(dev);
+
+ }
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error);
+
+ return error;
+}
+
+static int yaffs_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ struct inode *inode = dentry->d_inode;
+ int error = 0;
+ struct yaffs_dev *dev;
+ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id);
+
+ if (error == 0) {
+ int result;
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ result = yaffs_set_xattrib(obj, name, value, size, flags);
+ if (result == YAFFS_OK)
+ error = 0;
+ else if (result < 0)
+ error = result;
+ yaffs_gross_unlock(dev);
+
+ }
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error);
+
+ return error;
+}
+
+static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name,
+ void *buff, size_t size)
+{
+ struct inode *inode = dentry->d_inode;
+ int error = 0;
+ struct yaffs_dev *dev;
+ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_getxattr \"%s\" from object %d",
+ name, obj->obj_id);
+
+ if (error == 0) {
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ error = yaffs_get_xattrib(obj, name, buff, size);
+ yaffs_gross_unlock(dev);
+
+ }
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error);
+
+ return error;
+}
+
+static int yaffs_removexattr(struct dentry *dentry, const char *name)
+{
+ struct inode *inode = dentry->d_inode;
+ int error = 0;
+ struct yaffs_dev *dev;
+ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_removexattr of object %d", obj->obj_id);
+
+ if (error == 0) {
+ int result;
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ result = yaffs_remove_xattrib(obj, name);
+ if (result == YAFFS_OK)
+ error = 0;
+ else if (result < 0)
+ error = result;
+ yaffs_gross_unlock(dev);
+
+ }
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_removexattr done returning %d", error);
+
+ return error;
+}
+
+static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
+{
+ struct inode *inode = dentry->d_inode;
+ int error = 0;
+ struct yaffs_dev *dev;
+ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_listxattr of object %d", obj->obj_id);
+
+ if (error == 0) {
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ error = yaffs_list_xattrib(obj, buff, size);
+ yaffs_gross_unlock(dev);
+
+ }
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_listxattr done returning %d", error);
+
+ return error;
+}
+
+
+static const struct inode_operations yaffs_file_inode_operations = {
+ .setattr = yaffs_setattr,
+ .setxattr = yaffs_setxattr,
+ .getxattr = yaffs_getxattr,
+ .listxattr = yaffs_listxattr,
+ .removexattr = yaffs_removexattr,
+};
+
+
+static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
+ int buflen)
+{
+ unsigned char *alias;
+ int ret;
+
+ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
+
+ yaffs_gross_unlock(dev);
+
+ if (!alias)
+ return -ENOMEM;
+
+ ret = vfs_readlink(dentry, buffer, buflen, alias);
+ kfree(alias);
+ return ret;
+}
+
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ void *ret;
+#else
+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ int ret
+#endif
+ unsigned char *alias;
+ int ret_int = 0;
+ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
+ yaffs_gross_unlock(dev);
+
+ if (!alias) {
+ ret_int = -ENOMEM;
+ goto out;
+ }
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+ nd_set_link(nd, alias);
+ ret = alias;
+out:
+ if (ret_int)
+ ret = ERR_PTR(ret_int);
+ return ret;
+#else
+ ret = vfs_follow_link(nd, alias);
+ kfree(alias);
+out:
+ if (ret_int)
+ ret = ret_int;
+ return ret;
+#endif
+}
+
+
+#ifdef YAFFS_HAS_PUT_INODE
+
+/* For now put inode is just for debugging
+ * Put inode is called when the inode **structure** is put.
+ */
+static void yaffs_put_inode(struct inode *inode)
+{
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_put_inode: ino %d, count %d"),
+ (int)inode->i_ino, atomic_read(&inode->i_count);
+
+}
+#endif
+
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
+{
+ kfree(alias);
+}
+#endif
+
+static const struct inode_operations yaffs_symlink_inode_operations = {
+ .readlink = yaffs_readlink,
+ .follow_link = yaffs_follow_link,
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+ .put_link = yaffs_put_link,
+#endif
+ .setattr = yaffs_setattr,
+ .setxattr = yaffs_setxattr,
+ .getxattr = yaffs_getxattr,
+ .listxattr = yaffs_listxattr,
+ .removexattr = yaffs_removexattr,
+};
+
+#ifdef YAFFS_USE_OWN_IGET
+
+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
+{
+ struct inode *inode;
+ struct yaffs_obj *obj;
+ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino);
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ /* NB This is called as a side effect of other functions, but
+ * we had to release the lock to prevent deadlocks, so
+ * need to lock again.
+ */
+
+ yaffs_gross_lock(dev);
+
+ obj = yaffs_find_by_number(dev, inode->i_ino);
+
+ yaffs_fill_inode_from_obj(inode, obj);
+
+ yaffs_gross_unlock(dev);
+
+ unlock_new_inode(inode);
+ return inode;
+}
+
+#else
+
+static void yaffs_read_inode(struct inode *inode)
+{
+ /* NB This is called as a side effect of other functions, but
+ * we had to release the lock to prevent deadlocks, so
+ * need to lock again.
+ */
+
+ struct yaffs_obj *obj;
+ struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb);
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_read_inode for %d", (int)inode->i_ino);
+
+ if (current != yaffs_dev_to_lc(dev)->readdir_process)
+ yaffs_gross_lock(dev);
+
+ obj = yaffs_find_by_number(dev, inode->i_ino);
+
+ yaffs_fill_inode_from_obj(inode, obj);
+
+ if (current != yaffs_dev_to_lc(dev)->readdir_process)
+ yaffs_gross_unlock(dev);
+}
+
+#endif
+
+
+
+struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
+ struct yaffs_obj *obj)
+{
+ struct inode *inode;
+
+ if (!sb) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_get_inode for NULL super_block!!");
+ return NULL;
+
+ }
+
+ if (!obj) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_get_inode for NULL object!!");
+ return NULL;
+
+ }
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_get_inode for object %d", obj->obj_id);
+
+ inode = Y_IGET(sb, obj->obj_id);
+ if (IS_ERR(inode))
+ return NULL;
+
+ /* NB Side effect: iget calls back to yaffs_read_inode(). */
+ /* iget also increments the inode's i_count */
+ /* NB You can't be holding gross_lock or deadlock will happen! */
+
+ return inode;
+}
+
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
+#define YCRED(x) x
+#else
+#define YCRED(x) (x->cred)
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 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
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ int rdev)
+#endif
+{
+ struct inode *inode;
+
+ struct yaffs_obj *obj = NULL;
+ struct yaffs_dev *dev;
+
+ struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
+
+ int error = -ENOSPC;
+ uid_t uid = YCRED(current)->fsuid;
+ gid_t gid =
+ (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+
+ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
+ mode |= S_ISGID;
+
+ if (parent) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_mknod: parent object %d type %d",
+ parent->obj_id, parent->variant_type);
+ } else {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_mknod: could not get parent object");
+ return -EPERM;
+ }
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_mknod: making oject for %s, mode %x dev %x",
+ dentry->d_name.name, mode, rdev);
+
+ dev = parent->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ switch (mode & S_IFMT) {
+ default:
+ /* Special (socket, fifo, device...) */
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special");
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+ obj =
+ yaffs_create_special(parent, dentry->d_name.name, mode, uid,
+ gid, old_encode_dev(rdev));
+#else
+ obj =
+ yaffs_create_special(parent, dentry->d_name.name, mode, uid,
+ gid, rdev);
+#endif
+ break;
+ case S_IFREG: /* file */
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file");
+ obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
+ gid);
+ break;
+ case S_IFDIR: /* directory */
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory");
+ obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
+ uid, gid);
+ break;
+ case S_IFLNK: /* symlink */
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink");
+ obj = NULL; /* Do we ever get here? */
+ break;
+ }
+
+ /* Can not call yaffs_get_inode() with gross lock held */
+ yaffs_gross_unlock(dev);
+
+ if (obj) {
+ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
+ d_instantiate(dentry, inode);
+ update_dir_time(dir);
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_mknod created object %d count = %d",
+ obj->obj_id, atomic_read(&inode->i_count));
+ error = 0;
+ yaffs_fill_inode_from_obj(dir, parent);
+ } else {
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object");
+ error = -ENOMEM;
+ }
+
+ return error;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 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 ret_val;
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir");
+ ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
+ return ret_val;
+}
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+ bool dummy)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 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
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
+#endif
+{
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_create");
+ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int dummy)
+#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 struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
+#endif
+{
+ struct yaffs_obj *obj;
+ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
+
+ struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
+
+ if (current != yaffs_dev_to_lc(dev)->readdir_process)
+ yaffs_gross_lock(dev);
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s",
+ yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name);
+
+ obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name);
+
+ obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
+
+ /* Can't hold gross lock when calling yaffs_get_inode() */
+ if (current != yaffs_dev_to_lc(dev)->readdir_process)
+ yaffs_gross_unlock(dev);
+
+ if (obj) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_lookup found %d", obj->obj_id);
+
+ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+ } else {
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found");
+
+ }
+
+/* added NCB for 2.5/6 compatability - forces add even if inode is
+ * NULL which creates dentry hash */
+ d_add(dentry, inode);
+
+ return NULL;
+}
+
+/*
+ * Create a link...
+ */
+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry)
+{
+ struct inode *inode = old_dentry->d_inode;
+ struct yaffs_obj *obj = NULL;
+ struct yaffs_obj *link = NULL;
+ struct yaffs_dev *dev;
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_link");
+
+ obj = yaffs_inode_to_obj(inode);
+ dev = obj->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
+ link =
+ yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name,
+ obj);
+
+ if (link) {
+ 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);
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_link link count %d i_count %d",
+ old_dentry->d_inode->i_nlink,
+ atomic_read(&old_dentry->d_inode->i_count));
+ }
+
+ yaffs_gross_unlock(dev);
+
+ if (link) {
+ update_dir_time(dir);
+ return 0;
+ }
+
+ return -EPERM;
+}
+
+static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_dev *dev;
+ uid_t uid = YCRED(current)->fsuid;
+ gid_t gid =
+ (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
+
+ if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) >
+ YAFFS_MAX_NAME_LENGTH)
+ return -ENAMETOOLONG;
+
+ if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) >
+ YAFFS_MAX_ALIAS_LENGTH)
+ return -ENAMETOOLONG;
+
+ dev = yaffs_inode_to_obj(dir)->my_dev;
+ yaffs_gross_lock(dev);
+ obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
+ S_IFLNK | S_IRWXUGO, uid, gid, symname);
+ yaffs_gross_unlock(dev);
+
+ if (obj) {
+ struct inode *inode;
+
+ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+ d_instantiate(dentry, inode);
+ update_dir_time(dir);
+ yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
+ return 0;
+ } else {
+ yaffs_trace(YAFFS_TRACE_OS, "symlink not created");
+ }
+
+ return -ENOMEM;
+}
+
+/*
+ * The VFS layer already does all the dentry stuff for rename.
+ *
+ * NB: POSIX says you can rename an object over an old object of the same name
+ */
+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+{
+ struct yaffs_dev *dev;
+ int ret_val = YAFFS_FAIL;
+ struct yaffs_obj *target;
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename");
+ dev = yaffs_inode_to_obj(old_dir)->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ /* Check if the target is an existing directory that is not empty. */
+ target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir),
+ new_dentry->d_name.name);
+
+ if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
+ !list_empty(&target->variant.dir_variant.children)) {
+
+ yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir");
+
+ ret_val = YAFFS_FAIL;
+ } else {
+ /* Now does unlinking internally using shadowing mechanism */
+ yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj");
+
+ ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir),
+ old_dentry->d_name.name,
+ yaffs_inode_to_obj(new_dir),
+ new_dentry->d_name.name);
+ }
+ yaffs_gross_unlock(dev);
+
+ if (ret_val == YAFFS_OK) {
+ if (target)
+ inode_dec_link_count(new_dentry->d_inode);
+
+ update_dir_time(old_dir);
+ if (old_dir != new_dir)
+ update_dir_time(new_dir);
+ return 0;
+ } else {
+ return -ENOTEMPTY;
+ }
+}
+
+
+
+
+static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
+{
+ int ret_val;
+
+ struct yaffs_dev *dev;
+ struct yaffs_obj *obj;
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s",
+ (int)(dir->i_ino), dentry->d_name.name);
+ obj = yaffs_inode_to_obj(dir);
+ dev = obj->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ ret_val = yaffs_unlinker(obj, dentry->d_name.name);
+
+ if (ret_val == YAFFS_OK) {
+ inode_dec_link_count(dentry->d_inode);
+ dir->i_version++;
+ yaffs_gross_unlock(dev);
+ update_dir_time(dir);
+ return 0;
+ }
+ yaffs_gross_unlock(dev);
+ return -ENOTEMPTY;
+}
+
+
+
+static const struct inode_operations yaffs_dir_inode_operations = {
+ .create = yaffs_create,
+ .lookup = yaffs_lookup,
+ .link = yaffs_link,
+ .unlink = yaffs_unlink,
+ .symlink = yaffs_symlink,
+ .mkdir = yaffs_mkdir,
+ .rmdir = yaffs_unlink,
+ .mknod = yaffs_mknod,
+ .rename = yaffs_rename,
+ .setattr = yaffs_setattr,
+ .setxattr = yaffs_setxattr,
+ .getxattr = yaffs_getxattr,
+ .listxattr = yaffs_listxattr,
+ .removexattr = yaffs_removexattr,
+};
+
+/*-----------------------------------------------------------------*/
+/* Directory search context allows us to unlock access to yaffs during
+ * filldir without causing problems with the directory being modified.
+ * This is similar to the tried and tested mechanism used in yaffs direct.
+ *
+ * A search context iterates along a doubly linked list of siblings in the
+ * directory. If the iterating object is deleted then this would corrupt
+ * the list iteration, likely causing a crash. The search context avoids
+ * this by using the remove_obj_fn to move the search context to the
+ * next object before the object is deleted.
+ *
+ * Many readdirs (and thus seach conexts) may be alive simulateously so
+ * each struct yaffs_dev has a list of these.
+ *
+ * A seach context lives for the duration of a readdir.
+ *
+ * All these functions must be called while yaffs is locked.
+ */
+
+struct yaffs_search_context {
+ struct yaffs_dev *dev;
+ struct yaffs_obj *dir_obj;
+ struct yaffs_obj *next_return;
+ struct list_head others;
+};
+
+/*
+ * yaffs_new_search() creates a new search context, initialises it and
+ * adds it to the device's search context list.
+ *
+ * Called at start of readdir.
+ */
+static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)
+{
+ struct yaffs_dev *dev = dir->my_dev;
+ struct yaffs_search_context *sc =
+ kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS);
+ if (sc) {
+ sc->dir_obj = dir;
+ sc->dev = dev;
+ if (list_empty(&sc->dir_obj->variant.dir_variant.children))
+ sc->next_return = NULL;
+ else
+ sc->next_return =
+ list_entry(dir->variant.dir_variant.children.next,
+ struct yaffs_obj, siblings);
+ INIT_LIST_HEAD(&sc->others);
+ list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
+ }
+ return sc;
+}
+
+/*
+ * yaffs_search_end() disposes of a search context and cleans up.
+ */
+static void yaffs_search_end(struct yaffs_search_context *sc)
+{
+ if (sc) {
+ list_del(&sc->others);
+ kfree(sc);
+ }
+}
+
+/*
+ * yaffs_search_advance() moves a search context to the next object.
+ * Called when the search iterates or when an object removal causes
+ * the search context to be moved to the next object.
+ */
+static void yaffs_search_advance(struct yaffs_search_context *sc)
+{
+ if (!sc)
+ return;
+
+ if (sc->next_return == NULL ||
+ list_empty(&sc->dir_obj->variant.dir_variant.children))
+ sc->next_return = NULL;
+ else {
+ struct list_head *next = sc->next_return->siblings.next;
+
+ if (next == &sc->dir_obj->variant.dir_variant.children)
+ sc->next_return = NULL; /* end of list */
+ else
+ sc->next_return =
+ list_entry(next, struct yaffs_obj, siblings);
+ }
+}
+
+/*
+ * yaffs_remove_obj_callback() is called when an object is unlinked.
+ * We check open search contexts and advance any which are currently
+ * on the object being iterated.
+ */
+static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
+{
+
+ struct list_head *i;
+ struct yaffs_search_context *sc;
+ struct list_head *search_contexts =
+ &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);
+
+ /* Iterate through the directory search contexts.
+ * If any are currently on the object being removed, then advance
+ * the search context to the next object to prevent a hanging pointer.
+ */
+ list_for_each(i, search_contexts) {
+ sc = list_entry(i, struct yaffs_search_context, others);
+ if (sc->next_return == obj)
+ yaffs_search_advance(sc);
+ }
+
+}
+
+
+/*-----------------------------------------------------------------*/
+
+static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_dev *dev;
+ struct yaffs_search_context *sc;
+ struct inode *inode = f->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(f->f_dentry);
+ dev = obj->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ yaffs_dev_to_lc(dev)->readdir_process = current;
+
+ offset = f->f_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 (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {
+ yaffs_gross_lock(dev);
+ goto out;
+ }
+ yaffs_gross_lock(dev);
+ offset++;
+ f->f_pos++;
+ }
+ if (offset == 1) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_readdir: entry .. ino %d",
+ (int)f->f_dentry->d_parent->d_inode->i_ino);
+ yaffs_gross_unlock(dev);
+ if (filldir(dirent, "..", 2, offset,
+ f->f_dentry->d_parent->d_inode->i_ino,
+ DT_DIR) < 0) {
+ yaffs_gross_lock(dev);
+ goto out;
+ }
+ yaffs_gross_lock(dev);
+ offset++;
+ f->f_pos++;
+ }
+
+ curoffs = 1;
+
+ /* If the directory has changed since the open or last call to
+ readdir, rewind to after the 2 canned entries. */
+ if (f->f_version != inode->i_version) {
+ offset = 2;
+ f->f_pos = offset;
+ f->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 (filldir(dirent,
+ name,
+ strlen(name),
+ offset, this_inode, this_type) < 0) {
+ yaffs_gross_lock(dev);
+ goto out;
+ }
+
+ yaffs_gross_lock(dev);
+
+ offset++;
+ f->f_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;
+}
+
+static const struct file_operations yaffs_dir_operations = {
+ .read = generic_read_dir,
+ .readdir = yaffs_readdir,
+ .fsync = yaffs_sync_object,
+ .llseek = generic_file_llseek,
+};
+
+static void yaffs_fill_inode_from_obj(struct inode *inode,
+ struct yaffs_obj *obj)
+{
+ if (inode && obj) {
+
+ /* Check mode against the variant type and attempt to repair if broken. */
+ u32 mode = obj->yst_mode;
+ switch (obj->variant_type) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ if (!S_ISREG(mode)) {
+ obj->yst_mode &= ~S_IFMT;
+ obj->yst_mode |= S_IFREG;
+ }
+
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ if (!S_ISLNK(mode)) {
+ obj->yst_mode &= ~S_IFMT;
+ obj->yst_mode |= S_IFLNK;
+ }
+
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ if (!S_ISDIR(mode)) {
+ obj->yst_mode &= ~S_IFMT;
+ obj->yst_mode |= S_IFDIR;
+ }
+
+ break;
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ default:
+ /* TODO? */
+ break;
+ }
+
+ inode->i_flags |= S_NOATIME;
+
+ inode->i_ino = obj->obj_id;
+ inode->i_mode = obj->yst_mode;
+ inode->i_uid = obj->yst_uid;
+ inode->i_gid = obj->yst_gid;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
+ inode->i_blksize = inode->i_sb->s_blocksize;
+#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+
+ inode->i_rdev = old_decode_dev(obj->yst_rdev);
+ inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
+ inode->i_atime.tv_nsec = 0;
+ inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
+ inode->i_mtime.tv_nsec = 0;
+ inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
+ inode->i_ctime.tv_nsec = 0;
+#else
+ inode->i_rdev = obj->yst_rdev;
+ inode->i_atime = obj->yst_atime;
+ inode->i_mtime = obj->yst_mtime;
+ inode->i_ctime = obj->yst_ctime;
+#endif
+ inode->i_size = yaffs_get_obj_length(obj);
+ inode->i_blocks = (inode->i_size + 511) >> 9;
+
+ set_nlink(inode, yaffs_get_obj_link_count(obj));
+
+ 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_size, atomic_read(&inode->i_count));
+
+ switch (obj->yst_mode & S_IFMT) {
+ default: /* fifo, device or socket */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+ init_special_inode(inode, obj->yst_mode,
+ old_decode_dev(obj->yst_rdev));
+#else
+ init_special_inode(inode, obj->yst_mode,
+ (dev_t) (obj->yst_rdev));
+#endif
+ break;
+ case S_IFREG: /* file */
+ inode->i_op = &yaffs_file_inode_operations;
+ inode->i_fop = &yaffs_file_operations;
+ inode->i_mapping->a_ops =
+ &yaffs_file_address_operations;
+ break;
+ case S_IFDIR: /* directory */
+ inode->i_op = &yaffs_dir_inode_operations;
+ inode->i_fop = &yaffs_dir_operations;
+ break;
+ case S_IFLNK: /* symlink */
+ inode->i_op = &yaffs_symlink_inode_operations;
+ break;
+ }
+
+ yaffs_inode_to_obj_lv(inode) = obj;
+
+ obj->my_inode = inode;
+
+ } else {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_fill_inode invalid parameters");
+ }
+
+}
+
+
+
+/*
+ * yaffs background thread functions .
+ * yaffs_bg_thread_fn() the thread function
+ * yaffs_bg_start() launches the background thread.
+ * yaffs_bg_stop() cleans up the background thread.
+ *
+ * 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.
+ */
+
+static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)
+{
+ unsigned erased_chunks =
+ dev->n_erased_blocks * dev->param.chunks_per_block;
+ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
+ unsigned scattered = 0; /* Free chunks not in an erased block */
+
+ if (erased_chunks < dev->n_free_chunks)
+ scattered = (dev->n_free_chunks - erased_chunks);
+
+ if (!context->bg_running)
+ return 0;
+ else if (scattered < (dev->param.chunks_per_block * 2))
+ return 0;
+ else if (erased_chunks > dev->n_free_chunks / 2)
+ return 0;
+ else if (erased_chunks > dev->n_free_chunks / 4)
+ return 1;
+ else
+ return 2;
+}
+
+#ifdef YAFFS_COMPILE_BACKGROUND
+
+void yaffs_background_waker(unsigned long data)
+{
+ wake_up_process((struct task_struct *)data);
+}
+
+static int yaffs_bg_thread_fn(void *data)
+{
+ struct yaffs_dev *dev = (struct yaffs_dev *)data;
+ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
+ unsigned long now = jiffies;
+ unsigned long next_dir_update = now;
+ unsigned long next_gc = now;
+ unsigned long expires;
+ unsigned int urgency;
+
+ int gc_result;
+ struct timer_list timer;
+
+ yaffs_trace(YAFFS_TRACE_BACKGROUND,
+ "yaffs_background starting for dev %p", (void *)dev);
+
+#ifdef YAFFS_COMPILE_FREEZER
+ set_freezable();
+#endif
+ while (context->bg_running) {
+ yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background");
+
+ if (kthread_should_stop())
+ break;
+
+#ifdef YAFFS_COMPILE_FREEZER
+ if (try_to_freeze())
+ continue;
+#endif
+ yaffs_gross_lock(dev);
+
+ now = jiffies;
+
+ if (time_after(now, next_dir_update) && yaffs_bg_enable) {
+ yaffs_update_dirty_dirs(dev);
+ next_dir_update = now + HZ;
+ }
+
+ if (time_after(now, next_gc) && yaffs_bg_enable) {
+ if (!dev->is_checkpointed) {
+ urgency = yaffs_bg_gc_urgency(dev);
+ gc_result = yaffs_bg_gc(dev, urgency);
+ if (urgency > 1)
+ next_gc = now + HZ / 20 + 1;
+ else if (urgency > 0)
+ next_gc = now + HZ / 10 + 1;
+ else
+ next_gc = now + HZ * 2;
+ } else {
+ /*
+ * gc not running so set to next_dir_update
+ * to cut down on wake ups
+ */
+ next_gc = next_dir_update;
+ }
+ }
+ yaffs_gross_unlock(dev);
+#if 1
+ expires = next_dir_update;
+ if (time_before(next_gc, expires))
+ expires = next_gc;
+ if (time_before(expires, now))
+ expires = now + HZ;
+
+ Y_INIT_TIMER(&timer);
+ timer.expires = expires + 1;
+ timer.data = (unsigned long)current;
+ timer.function = yaffs_background_waker;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_timer(&timer);
+ schedule();
+ del_timer_sync(&timer);
+#else
+ msleep(10);
+#endif
+ }
+
+ return 0;
+}
+
+static int yaffs_bg_start(struct yaffs_dev *dev)
+{
+ int retval = 0;
+ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
+
+ if (dev->read_only)
+ return -1;
+
+ context->bg_running = 1;
+
+ context->bg_thread = kthread_run(yaffs_bg_thread_fn,
+ (void *)dev, "yaffs-bg-%d",
+ context->mount_id);
+
+ if (IS_ERR(context->bg_thread)) {
+ retval = PTR_ERR(context->bg_thread);
+ context->bg_thread = NULL;
+ context->bg_running = 0;
+ }
+ return retval;
+}
+
+static void yaffs_bg_stop(struct yaffs_dev *dev)
+{
+ struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);
+
+ ctxt->bg_running = 0;
+
+ if (ctxt->bg_thread) {
+ kthread_stop(ctxt->bg_thread);
+ ctxt->bg_thread = NULL;
+ }
+}
+#else
+static int yaffs_bg_thread_fn(void *data)
+{
+ return 0;
+}
+
+static int yaffs_bg_start(struct yaffs_dev *dev)
+{
+ return 0;
+}
+
+static void yaffs_bg_stop(struct yaffs_dev *dev)
+{
+}
+#endif
+
+
+static void yaffs_flush_inodes(struct super_block *sb)
+{
+ struct inode *iptr;
+ struct yaffs_obj *obj;
+
+ list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
+ obj = yaffs_inode_to_obj(iptr);
+ if (obj) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "flushing obj %d",
+ obj->obj_id);
+ yaffs_flush_file(obj, 1, 0);
+ }
+ }
+}
+
+static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
+{
+ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+ if (!dev)
+ return;
+
+ yaffs_flush_inodes(sb);
+ yaffs_update_dirty_dirs(dev);
+ yaffs_flush_whole_cache(dev);
+ if (do_checkpoint)
+ yaffs_checkpoint_save(dev);
+}
+
+static LIST_HEAD(yaffs_context_list);
+struct mutex yaffs_context_lock;
+
+static void yaffs_put_super(struct super_block *sb)
+{
+ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+
+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
+ "yaffs_put_super");
+
+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
+ "Shutting down yaffs background thread");
+ yaffs_bg_stop(dev);
+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
+ "yaffs background thread shut down");
+
+ yaffs_gross_lock(dev);
+
+ yaffs_flush_super(sb, 1);
+
+ yaffs_deinitialise(dev);
+
+ yaffs_gross_unlock(dev);
+
+ mutex_lock(&yaffs_context_lock);
+ list_del_init(&(yaffs_dev_to_lc(dev)->context_list));
+ mutex_unlock(&yaffs_context_lock);
+
+ if (yaffs_dev_to_lc(dev)->spare_buffer) {
+ kfree(yaffs_dev_to_lc(dev)->spare_buffer);
+ yaffs_dev_to_lc(dev)->spare_buffer = NULL;
+ }
+
+ kfree(dev);
+
+ yaffs_put_mtd_device(mtd);
+
+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
+ "yaffs_put_super done");
+}
+
+
+static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)
+{
+ return yaffs_gc_control;
+}
+
+
+#ifdef YAFFS_COMPILE_EXPORTFS
+
+static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
+ uint32_t generation)
+{
+ return Y_IGET(sb, ino);
+}
+
+static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb,
+ struct fid *fid, int fh_len,
+ int fh_type)
+{
+ return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+ yaffs2_nfs_get_inode);
+}
+
+static struct dentry *yaffs2_fh_to_parent(struct super_block *sb,
+ struct fid *fid, int fh_len,
+ int fh_type)
+{
+ return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+ yaffs2_nfs_get_inode);
+}
+
+struct dentry *yaffs2_get_parent(struct dentry *dentry)
+{
+
+ struct super_block *sb = dentry->d_inode->i_sb;
+ struct dentry *parent = ERR_PTR(-ENOENT);
+ struct inode *inode;
+ unsigned long parent_ino;
+ struct yaffs_obj *d_obj;
+ struct yaffs_obj *parent_obj;
+
+ d_obj = yaffs_inode_to_obj(dentry->d_inode);
+
+ if (d_obj) {
+ parent_obj = d_obj->parent;
+ if (parent_obj) {
+ parent_ino = yaffs_get_obj_inode(parent_obj);
+ inode = Y_IGET(sb, parent_ino);
+
+ if (IS_ERR(inode)) {
+ parent = ERR_CAST(inode);
+ } else {
+ parent = d_obtain_alias(inode);
+ if (!IS_ERR(parent)) {
+ parent = ERR_PTR(-ENOMEM);
+ iput(inode);
+ }
+ }
+ }
+ }
+
+ return parent;
+}
+
+/* Just declare a zero structure as a NULL value implies
+ * using the default functions of exportfs.
+ */
+
+static struct export_operations yaffs_export_ops = {
+ .fh_to_dentry = yaffs2_fh_to_dentry,
+ .fh_to_parent = yaffs2_fh_to_parent,
+ .get_parent = yaffs2_get_parent,
+};
+
+#endif
+
+static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)
+{
+ /* Clear the association between the inode and
+ * the struct yaffs_obj.
+ */
+ obj->my_inode = NULL;
+ yaffs_inode_to_obj_lv(inode) = NULL;
+
+ /* If the object freeing was deferred, then the real
+ * free happens now.
+ * This should fix the inode inconsistency problem.
+ */
+ yaffs_handle_defered_free(obj);
+}
+
+#ifdef YAFFS_HAS_EVICT_INODE
+/* yaffs_evict_inode combines into one operation what was previously done in
+ * yaffs_clear_inode() and yaffs_delete_inode()
+ *
+ */
+static void yaffs_evict_inode(struct inode *inode)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_dev *dev;
+ int deleteme = 0;
+
+ obj = yaffs_inode_to_obj(inode);
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_evict_inode: ino %d, count %d %s",
+ (int)inode->i_ino, atomic_read(&inode->i_count),
+ obj ? "object exists" : "null object");
+
+ if (!inode->i_nlink && !is_bad_inode(inode))
+ deleteme = 1;
+ truncate_inode_pages(&inode->i_data, 0);
+ Y_CLEAR_INODE(inode);
+
+ if (deleteme && obj) {
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ yaffs_del_obj(obj);
+ yaffs_gross_unlock(dev);
+ }
+ if (obj) {
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ yaffs_unstitch_obj(inode, obj);
+ yaffs_gross_unlock(dev);
+ }
+}
+#else
+
+/* clear is called to tell the fs to release any per-inode data it holds.
+ * The object might still exist on disk and is just being thrown out of the cache
+ * or else the object has actually been deleted and we're being called via
+ * the chain
+ * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
+ */
+
+static void yaffs_clear_inode(struct inode *inode)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_dev *dev;
+
+ obj = yaffs_inode_to_obj(inode);
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_clear_inode: ino %d, count %d %s",
+ (int)inode->i_ino, atomic_read(&inode->i_count),
+ obj ? "object exists" : "null object");
+
+ if (obj) {
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ yaffs_unstitch_obj(inode, obj);
+ yaffs_gross_unlock(dev);
+ }
+
+}
+
+/* delete is called when the link count is zero and the inode
+ * is put (ie. nobody wants to know about it anymore, time to
+ * delete the file).
+ * NB Must call clear_inode()
+ */
+static void yaffs_delete_inode(struct inode *inode)
+{
+ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+ struct yaffs_dev *dev;
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_delete_inode: ino %d, count %d %s",
+ (int)inode->i_ino, atomic_read(&inode->i_count),
+ obj ? "object exists" : "null object");
+
+ if (obj) {
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ yaffs_del_obj(obj);
+ yaffs_gross_unlock(dev);
+ }
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
+ truncate_inode_pages(&inode->i_data, 0);
+#endif
+ clear_inode(inode);
+}
+#endif
+
+
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
+ struct super_block *sb = dentry->d_sb;
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
+{
+ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+#else
+static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
+{
+ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+#endif
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs");
+
+ yaffs_gross_lock(dev);
+
+ buf->f_type = YAFFS_MAGIC;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_namelen = 255;
+
+ if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
+ /* Do this if chunk size is not a power of 2 */
+
+ uint64_t bytes_in_dev;
+ uint64_t bytes_free;
+
+ bytes_in_dev =
+ ((uint64_t)
+ ((dev->param.end_block - dev->param.start_block +
+ 1))) * ((uint64_t) (dev->param.chunks_per_block *
+ dev->data_bytes_per_chunk));
+
+ do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */
+ buf->f_blocks = bytes_in_dev;
+
+ bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *
+ ((uint64_t) (dev->data_bytes_per_chunk));
+
+ do_div(bytes_free, sb->s_blocksize);
+
+ buf->f_bfree = bytes_free;
+
+ } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
+
+ buf->f_blocks =
+ (dev->param.end_block - dev->param.start_block + 1) *
+ dev->param.chunks_per_block /
+ (sb->s_blocksize / dev->data_bytes_per_chunk);
+ buf->f_bfree =
+ yaffs_get_n_free_chunks(dev) /
+ (sb->s_blocksize / dev->data_bytes_per_chunk);
+ } else {
+ buf->f_blocks =
+ (dev->param.end_block - dev->param.start_block + 1) *
+ dev->param.chunks_per_block *
+ (dev->data_bytes_per_chunk / sb->s_blocksize);
+
+ buf->f_bfree =
+ yaffs_get_n_free_chunks(dev) *
+ (dev->data_bytes_per_chunk / sb->s_blocksize);
+ }
+
+ buf->f_files = 0;
+ buf->f_ffree = 0;
+ buf->f_bavail = buf->f_bfree;
+
+ yaffs_gross_unlock(dev);
+ return 0;
+}
+
+
+
+static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)
+{
+
+ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+ unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
+ unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
+ int do_checkpoint;
+ int dirty = yaffs_check_super_dirty(dev);
+
+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
+ "yaffs_do_sync_fs: gc-urgency %d %s %s%s",
+ gc_urgent,
+ dirty ? "dirty" : "clean",
+ request_checkpoint ? "checkpoint requested" : "no checkpoint",
+ oneshot_checkpoint ? " one-shot" : "");
+
+ yaffs_gross_lock(dev);
+ do_checkpoint = ((request_checkpoint && !gc_urgent) ||
+ oneshot_checkpoint) && !dev->is_checkpointed;
+
+ if (dirty || do_checkpoint) {
+ yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
+ yaffs_clear_super_dirty(dev);
+ if (oneshot_checkpoint)
+ yaffs_auto_checkpoint &= ~4;
+ }
+ yaffs_gross_unlock(dev);
+
+ return 0;
+}
+
+
+#ifdef YAFFS_HAS_WRITE_SUPER
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static void yaffs_write_super(struct super_block *sb)
+#else
+static int yaffs_write_super(struct super_block *sb)
+#endif
+{
+ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
+
+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
+ "yaffs_write_super %s",
+ request_checkpoint ? " checkpt" : "");
+
+ yaffs_do_sync_fs(sb, request_checkpoint);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+ return 0;
+#endif
+}
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_sync_fs(struct super_block *sb, int wait)
+#else
+static int yaffs_sync_fs(struct super_block *sb)
+#endif
+{
+ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
+
+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
+ "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : "");
+
+ yaffs_do_sync_fs(sb, request_checkpoint);
+
+ return 0;
+}
+
+
+
+static const struct super_operations yaffs_super_ops = {
+ .statfs = yaffs_statfs,
+
+#ifndef YAFFS_USE_OWN_IGET
+ .read_inode = yaffs_read_inode,
+#endif
+#ifdef YAFFS_HAS_PUT_INODE
+ .put_inode = yaffs_put_inode,
+#endif
+ .put_super = yaffs_put_super,
+#ifdef YAFFS_HAS_EVICT_INODE
+ .evict_inode = yaffs_evict_inode,
+#else
+ .delete_inode = yaffs_delete_inode,
+ .clear_inode = yaffs_clear_inode,
+#endif
+ .sync_fs = yaffs_sync_fs,
+#ifdef YAFFS_HAS_WRITE_SUPER
+ .write_super = yaffs_write_super,
+#endif
+};
+
+struct yaffs_options {
+ int inband_tags;
+ int skip_checkpoint_read;
+ int skip_checkpoint_write;
+ int no_cache;
+ int tags_ecc_on;
+ int tags_ecc_overridden;
+ int lazy_loading_enabled;
+ int lazy_loading_overridden;
+ int empty_lost_and_found;
+ int empty_lost_and_found_overridden;
+ int disable_summary;
+};
+
+#define MAX_OPT_LEN 30
+static int yaffs_parse_options(struct yaffs_options *options,
+ const char *options_str)
+{
+ char cur_opt[MAX_OPT_LEN + 1];
+ int p;
+ int error = 0;
+
+ /* Parse through the options which is a comma seperated list */
+
+ while (options_str && *options_str && !error) {
+ memset(cur_opt, 0, MAX_OPT_LEN + 1);
+ p = 0;
+
+ while (*options_str == ',')
+ options_str++;
+
+ while (*options_str && *options_str != ',') {
+ if (p < MAX_OPT_LEN) {
+ cur_opt[p] = *options_str;
+ p++;
+ }
+ options_str++;
+ }
+
+ if (!strcmp(cur_opt, "inband-tags")) {
+ options->inband_tags = 1;
+ } else if (!strcmp(cur_opt, "tags-ecc-off")) {
+ options->tags_ecc_on = 0;
+ options->tags_ecc_overridden = 1;
+ } else if (!strcmp(cur_opt, "tags-ecc-on")) {
+ options->tags_ecc_on = 1;
+ options->tags_ecc_overridden = 1;
+ } else if (!strcmp(cur_opt, "lazy-loading-off")) {
+ options->lazy_loading_enabled = 0;
+ options->lazy_loading_overridden = 1;
+ } else if (!strcmp(cur_opt, "lazy-loading-on")) {
+ options->lazy_loading_enabled = 1;
+ options->lazy_loading_overridden = 1;
+ } else if (!strcmp(cur_opt, "disable-summary")) {
+ options->disable_summary = 1;
+ } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) {
+ options->empty_lost_and_found = 0;
+ options->empty_lost_and_found_overridden = 1;
+ } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) {
+ options->empty_lost_and_found = 1;
+ options->empty_lost_and_found_overridden = 1;
+ } else if (!strcmp(cur_opt, "no-cache")) {
+ options->no_cache = 1;
+ } else if (!strcmp(cur_opt, "no-checkpoint-read")) {
+ options->skip_checkpoint_read = 1;
+ } else if (!strcmp(cur_opt, "no-checkpoint-write")) {
+ options->skip_checkpoint_write = 1;
+ } else if (!strcmp(cur_opt, "no-checkpoint")) {
+ options->skip_checkpoint_read = 1;
+ options->skip_checkpoint_write = 1;
+ } else {
+ printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
+ cur_opt);
+ error = 1;
+ }
+ }
+
+ return error;
+}
+
+
+static struct dentry *yaffs_make_root(struct inode *inode)
+{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
+ struct dentry *root = d_alloc_root(inode);
+
+ if (!root)
+ iput(inode);
+
+ return root;
+#else
+ return d_make_root(inode);
+#endif
+}
+
+
+
+
+static struct super_block *yaffs_internal_read_super(int yaffs_version,
+ struct super_block *sb,
+ void *data, int silent)
+{
+ int n_blocks;
+ struct inode *inode = NULL;
+ struct dentry *root;
+ struct yaffs_dev *dev = 0;
+ char devname_buf[BDEVNAME_SIZE + 1];
+ struct mtd_info *mtd;
+ int err;
+ char *data_str = (char *)data;
+ struct yaffs_linux_context *context = NULL;
+ struct yaffs_param *param;
+
+ int read_only = 0;
+ int inband_tags = 0;
+
+ struct yaffs_options options;
+
+ unsigned mount_id;
+ int found;
+ struct yaffs_linux_context *context_iterator;
+ struct list_head *l;
+
+ if (!sb) {
+ printk(KERN_INFO "yaffs: sb is NULL\n");
+ return NULL;
+ }
+
+ sb->s_magic = YAFFS_MAGIC;
+ sb->s_op = &yaffs_super_ops;
+ sb->s_flags |= MS_NOATIME;
+
+ read_only = ((sb->s_flags & MS_RDONLY) != 0);
+
+#ifdef YAFFS_COMPILE_EXPORTFS
+ sb->s_export_op = &yaffs_export_ops;
+#endif
+
+ if (!sb->s_dev)
+ printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
+ else if (!yaffs_devname(sb, devname_buf))
+ printk(KERN_INFO "yaffs: devname is NULL\n");
+ else
+ printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
+ sb->s_dev,
+ yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw");
+
+ if (!data_str)
+ data_str = "";
+
+ printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
+
+ memset(&options, 0, sizeof(options));
+
+ if (yaffs_parse_options(&options, data_str)) {
+ /* Option parsing failed */
+ return NULL;
+ }
+
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_read_super: Using yaffs%d", yaffs_version);
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_read_super: block size %d", (int)(sb->s_blocksize));
+
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs: Attempting MTD mount of %u.%u,\"%s\"",
+ MAJOR(sb->s_dev), MINOR(sb->s_dev),
+ yaffs_devname(sb, devname_buf));
+
+ /* Get the device */
+ mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
+ if (!mtd) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs: MTD device %u either not valid or unavailable",
+ MINOR(sb->s_dev));
+ return NULL;
+ }
+
+ if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2");
+ yaffs_version = 2;
+ }
+
+ /* Added NCB 26/5/2006 for completeness */
+ if (yaffs_version == 2 && !options.inband_tags
+ && WRITE_SIZE(mtd) == 512) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
+ yaffs_version = 1;
+ }
+
+ if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
+ options.inband_tags)
+ inband_tags = 1;
+
+ if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
+ return NULL;
+
+ /* OK, so if we got here, we have an MTD that's NAND and looks
+ * like it has the right capabilities
+ * Set the struct yaffs_dev up for mtd
+ */
+
+ if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
+ read_only = 1;
+ printk(KERN_INFO
+ "yaffs: mtd is read only, setting superblock read only\n"
+ );
+ sb->s_flags |= MS_RDONLY;
+ }
+
+ dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL);
+ context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
+
+ if (!dev || !context) {
+ if (dev)
+ kfree(dev);
+ if (context)
+ kfree(context);
+ dev = NULL;
+ context = NULL;
+ }
+
+ if (!dev) {
+ /* Deep shit could not allocate device structure */
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs_read_super: Failed trying to allocate struct yaffs_dev."
+ );
+ return NULL;
+ }
+ memset(dev, 0, sizeof(struct yaffs_dev));
+ param = &(dev->param);
+
+ memset(context, 0, sizeof(struct yaffs_linux_context));
+ dev->os_context = context;
+ INIT_LIST_HEAD(&(context->context_list));
+ context->dev = dev;
+ context->super = sb;
+
+ dev->read_only = read_only;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+ sb->s_fs_info = dev;
+#else
+ sb->u.generic_sbp = dev;
+#endif
+
+
+ dev->driver_context = mtd;
+ param->name = mtd->name;
+
+ /* Set up the memory size parameters.... */
+
+
+ param->n_reserved_blocks = 5;
+ param->n_caches = (options.no_cache) ? 0 : 10;
+ param->inband_tags = inband_tags;
+
+ param->enable_xattr = 1;
+ if (options.lazy_loading_overridden)
+ param->disable_lazy_load = !options.lazy_loading_enabled;
+
+ param->defered_dir_update = 1;
+
+ if (options.tags_ecc_overridden)
+ param->no_tags_ecc = !options.tags_ecc_on;
+
+ param->empty_lost_n_found = 1;
+ param->refresh_period = 500;
+ param->disable_summary = options.disable_summary;
+
+
+#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING
+ param->disable_bad_block_marking = 1;
+#endif
+ if (options.empty_lost_and_found_overridden)
+ param->empty_lost_n_found = options.empty_lost_and_found;
+
+ /* ... and the functions. */
+ if (yaffs_version == 2) {
+ param->is_yaffs2 = 1;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+ param->total_bytes_per_chunk = mtd->writesize;
+ param->chunks_per_block = mtd->erasesize / mtd->writesize;
+#else
+ param->total_bytes_per_chunk = mtd->oobblock;
+ param->chunks_per_block = mtd->erasesize / mtd->oobblock;
+#endif
+ n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
+
+ param->start_block = 0;
+ param->end_block = n_blocks - 1;
+ } else {
+ param->is_yaffs2 = 0;
+ n_blocks = YCALCBLOCKS(mtd->size,
+ YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
+
+ param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
+ param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
+ }
+
+ param->start_block = 0;
+ param->end_block = n_blocks - 1;
+
+ yaffs_mtd_drv_install(dev);
+
+ param->sb_dirty_fn = yaffs_set_super_dirty;
+ param->gc_control_fn = yaffs_gc_control_callback;
+
+ yaffs_dev_to_lc(dev)->super = sb;
+
+ param->use_nand_ecc = 1;
+
+ param->skip_checkpt_rd = options.skip_checkpoint_read;
+ param->skip_checkpt_wr = options.skip_checkpoint_write;
+
+ mutex_lock(&yaffs_context_lock);
+ /* Get a mount id */
+ found = 0;
+ for (mount_id = 0; !found; mount_id++) {
+ found = 1;
+ list_for_each(l, &yaffs_context_list) {
+ context_iterator =
+ list_entry(l, struct yaffs_linux_context,
+ context_list);
+ if (context_iterator->mount_id == mount_id)
+ found = 0;
+ }
+ }
+ context->mount_id = mount_id;
+
+ list_add_tail(&(yaffs_dev_to_lc(dev)->context_list),
+ &yaffs_context_list);
+ mutex_unlock(&yaffs_context_lock);
+
+ /* Directory search handling... */
+ INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts));
+ param->remove_obj_fn = yaffs_remove_obj_callback;
+
+ mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock));
+
+ yaffs_gross_lock(dev);
+
+ err = yaffs_guts_initialise(dev);
+
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_read_super: guts initialised %s",
+ (err == YAFFS_OK) ? "OK" : "FAILED");
+
+ if (err == YAFFS_OK)
+ yaffs_bg_start(dev);
+
+ if (!context->bg_thread)
+ param->defered_dir_update = 0;
+
+ sb->s_maxbytes = yaffs_max_file_size(dev);
+
+ /* Release lock before yaffs_get_inode() */
+ yaffs_gross_unlock(dev);
+
+ /* Create root inode */
+ if (err == YAFFS_OK)
+ inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, yaffs_root(dev));
+
+ if (!inode)
+ return NULL;
+
+ inode->i_op = &yaffs_dir_inode_operations;
+ inode->i_fop = &yaffs_dir_operations;
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode");
+
+ root = yaffs_make_root(inode);
+
+ if (!root)
+ return NULL;
+
+ sb->s_root = root;
+ if(!dev->is_checkpointed)
+ yaffs_set_super_dirty(dev);
+
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs_read_super: is_checkpointed %d",
+ dev->is_checkpointed);
+
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done");
+ return sb;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
+ int silent)
+{
+ return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
+}
+
+#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)
+{
+
+ return get_sb_bdev(fs, flags, dev_name, data,
+ yaffs_internal_read_super_mtd, mnt);
+}
+#else
+static struct super_block *yaffs_read_super(struct file_system_type *fs,
+ int flags, const char *dev_name,
+ void *data)
+{
+
+ return get_sb_bdev(fs, flags, dev_name, data,
+ yaffs_internal_read_super_mtd);
+}
+#endif
+
+static struct file_system_type yaffs_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "yaffs",
+#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
+static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
+ int silent)
+{
+ return yaffs_internal_read_super(1, sb, data, silent);
+}
+
+static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
+ FS_REQUIRES_DEV);
+#endif
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
+ int silent)
+{
+ return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
+}
+
+#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)
+{
+ return get_sb_bdev(fs, flags, dev_name, data,
+ yaffs2_internal_read_super_mtd, mnt);
+}
+#else
+static struct super_block *yaffs2_read_super(struct file_system_type *fs,
+ int flags, const char *dev_name,
+ void *data)
+{
+
+ return get_sb_bdev(fs, flags, dev_name, data,
+ yaffs2_internal_read_super_mtd);
+}
+#endif
+
+static struct file_system_type yaffs2_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "yaffs2",
+#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
+static struct super_block *yaffs2_read_super(struct super_block *sb,
+ void *data, int silent)
+{
+ return yaffs_internal_read_super(2, sb, data, silent);
+}
+
+static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
+ FS_REQUIRES_DEV);
+#endif
+
+
+static struct proc_dir_entry *my_proc_entry;
+
+static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
+{
+ struct yaffs_param *param = &dev->param;
+ int bs[10];
+
+ yaffs_count_blocks_by_state(dev,bs);
+
+ buf += sprintf(buf, "start_block.......... %d\n", param->start_block);
+ buf += sprintf(buf, "end_block............ %d\n", param->end_block);
+ buf += sprintf(buf, "total_bytes_per_chunk %d\n",
+ param->total_bytes_per_chunk);
+ buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc);
+ buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc);
+ buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2);
+ buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags);
+ buf += sprintf(buf, "empty_lost_n_found... %d\n",
+ param->empty_lost_n_found);
+ buf += sprintf(buf, "disable_lazy_load.... %d\n",
+ param->disable_lazy_load);
+ buf += sprintf(buf, "disable_bad_block_mrk %d\n",
+ param->disable_bad_block_marking);
+ buf += sprintf(buf, "refresh_period....... %d\n",
+ param->refresh_period);
+ buf += sprintf(buf, "n_caches............. %d\n", param->n_caches);
+ buf += sprintf(buf, "n_reserved_blocks.... %d\n",
+ param->n_reserved_blocks);
+ buf += sprintf(buf, "always_check_erased.. %d\n",
+ param->always_check_erased);
+ buf += sprintf(buf, "\n");
+ buf += sprintf(buf, "block count by state\n");
+ buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n",
+ bs[0], bs[1], bs[2], bs[3], bs[4]);
+ buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n",
+ bs[5], bs[6], bs[7], bs[8], bs[9]);
+
+ return buf;
+}
+
+static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
+{
+ buf += sprintf(buf, "max file size....... %lld\n",
+ (long long) yaffs_max_file_size(dev));
+ buf += sprintf(buf, "data_bytes_per_chunk. %d\n",
+ dev->data_bytes_per_chunk);
+ buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
+ buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
+ buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
+ buf += sprintf(buf, "blocks_in_checkpt.... %d\n",
+ dev->blocks_in_checkpt);
+ buf += sprintf(buf, "\n");
+ buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
+ buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
+ buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
+ buf += sprintf(buf, "\n");
+ buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
+ buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
+ buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
+ buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
+ buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
+ buf += sprintf(buf, "passive_gc_count..... %u\n",
+ dev->passive_gc_count);
+ buf += sprintf(buf, "oldest_dirty_gc_count %u\n",
+ dev->oldest_dirty_gc_count);
+ buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
+ buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
+ buf += sprintf(buf, "n_retried_writes..... %u\n",
+ dev->n_retried_writes);
+ buf += sprintf(buf, "n_retired_blocks..... %u\n",
+ dev->n_retired_blocks);
+ buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
+ buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
+ buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n",
+ dev->n_tags_ecc_fixed);
+ buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n",
+ dev->n_tags_ecc_unfixed);
+ buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
+ buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
+ buf += sprintf(buf, "n_unlinked_files..... %u\n",
+ dev->n_unlinked_files);
+ buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
+ buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
+ buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used);
+ buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used);
+
+ return buf;
+}
+
+static int yaffs_proc_read(char *page,
+ char **start,
+ off_t offset, int count, int *eof, void *data)
+{
+ struct list_head *item;
+ char *buf = page;
+ int step = offset;
+ int n = 0;
+
+ /* Get proc_file_read() to step 'offset' by one on each sucessive call.
+ * We use 'offset' (*ppos) to indicate where we are in dev_list.
+ * This also assumes the user has posted a read buffer large
+ * enough to hold the complete output; but that's life in /proc.
+ */
+
+ *(int *)start = 1;
+
+ /* Print header first */
+ if (step == 0)
+ buf +=
+ sprintf(buf,
+ "Multi-version YAFFS built:" __DATE__ " " __TIME__
+ "\n");
+ else if (step == 1)
+ 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. */
+ list_for_each(item, &yaffs_context_list) {
+ struct yaffs_linux_context *dc =
+ list_entry(item, struct yaffs_linux_context,
+ context_list);
+ struct yaffs_dev *dev = dc->dev;
+
+ if (n < (step & ~1)) {
+ n += 2;
+ continue;
+ }
+ if ((step & 1) == 0) {
+ buf +=
+ sprintf(buf, "\nDevice %d \"%s\"\n", n,
+ dev->param.name);
+ buf = yaffs_dump_dev_part0(buf, dev);
+ } else {
+ buf = yaffs_dump_dev_part1(buf, dev);
+ }
+
+ break;
+ }
+ mutex_unlock(&yaffs_context_lock);
+ }
+
+ return buf - page < count ? buf - page : count;
+}
+
+/**
+ * Set the verbosity of the warnings and error messages.
+ *
+ * Note that the names can only be a..z or _ with the current code.
+ */
+
+static struct {
+ char *mask_name;
+ unsigned mask_bitfield;
+} mask_flags[] = {
+ {"allocate", YAFFS_TRACE_ALLOCATE},
+ {"always", YAFFS_TRACE_ALWAYS},
+ {"background", YAFFS_TRACE_BACKGROUND},
+ {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
+ {"buffers", YAFFS_TRACE_BUFFERS},
+ {"bug", YAFFS_TRACE_BUG},
+ {"checkpt", YAFFS_TRACE_CHECKPOINT},
+ {"deletion", YAFFS_TRACE_DELETION},
+ {"erase", YAFFS_TRACE_ERASE},
+ {"error", YAFFS_TRACE_ERROR},
+ {"gc_detail", YAFFS_TRACE_GC_DETAIL},
+ {"gc", YAFFS_TRACE_GC},
+ {"lock", YAFFS_TRACE_LOCK},
+ {"mtd", YAFFS_TRACE_MTD},
+ {"nandaccess", YAFFS_TRACE_NANDACCESS},
+ {"os", YAFFS_TRACE_OS},
+ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
+ {"scan", YAFFS_TRACE_SCAN},
+ {"mount", YAFFS_TRACE_MOUNT},
+ {"tracing", YAFFS_TRACE_TRACING},
+ {"sync", YAFFS_TRACE_SYNC},
+ {"write", YAFFS_TRACE_WRITE},
+ {"verify", YAFFS_TRACE_VERIFY},
+ {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
+ {"verify_full", YAFFS_TRACE_VERIFY_FULL},
+ {"verify_all", YAFFS_TRACE_VERIFY_ALL},
+ {"all", 0xffffffff},
+ {"none", 0},
+ {NULL, 0},
+};
+
+#define MAX_MASK_NAME_LENGTH 40
+static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
+ unsigned long count, void *data)
+{
+ unsigned rg = 0, mask_bitfield;
+ char *end;
+ char *mask_name;
+ const char *x;
+ char substring[MAX_MASK_NAME_LENGTH + 1];
+ int i;
+ int done = 0;
+ int add, len = 0;
+ int pos = 0;
+
+ rg = yaffs_trace_mask;
+
+ while (!done && (pos < count)) {
+ done = 1;
+ while ((pos < count) && isspace(buf[pos]))
+ pos++;
+
+ switch (buf[pos]) {
+ case '+':
+ case '-':
+ case '=':
+ add = buf[pos];
+ pos++;
+ break;
+
+ default:
+ add = ' ';
+ break;
+ }
+ mask_name = NULL;
+
+ mask_bitfield = simple_strtoul(buf + pos, &end, 0);
+
+ if (end > buf + pos) {
+ mask_name = "numeral";
+ len = end - (buf + pos);
+ pos += len;
+ done = 0;
+ } else {
+ for (x = buf + pos, i = 0;
+ (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
+ i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
+ substring[i] = *x;
+ substring[i] = '\0';
+
+ for (i = 0; mask_flags[i].mask_name != NULL; i++) {
+ if (strcmp(substring, mask_flags[i].mask_name)
+ == 0) {
+ mask_name = mask_flags[i].mask_name;
+ mask_bitfield =
+ mask_flags[i].mask_bitfield;
+ done = 0;
+ break;
+ }
+ }
+ }
+
+ if (mask_name != NULL) {
+ done = 0;
+ switch (add) {
+ case '-':
+ rg &= ~mask_bitfield;
+ break;
+ case '+':
+ rg |= mask_bitfield;
+ break;
+ case '=':
+ rg = mask_bitfield;
+ break;
+ default:
+ rg |= mask_bitfield;
+ break;
+ }
+ }
+ }
+
+ yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS;
+
+ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
+
+ if (rg & YAFFS_TRACE_ALWAYS) {
+ for (i = 0; mask_flags[i].mask_name != NULL; i++) {
+ char flag;
+ flag = ((rg & mask_flags[i].mask_bitfield) ==
+ mask_flags[i].mask_bitfield) ? '+' : '-';
+ printk(KERN_DEBUG "%c%s\n", flag,
+ mask_flags[i].mask_name);
+ }
+ }
+
+ return count;
+}
+
+/* Debug strings are of the form:
+ * .bnnn print info on block n
+ * .cobjn,chunkn print nand chunk id for objn:chunkn
+ */
+
+static int yaffs_proc_debug_write(struct file *file, const char *buf,
+ unsigned long count, void *data)
+{
+
+ char str[100];
+ char *p0;
+ char *p1;
+ long p1_val;
+ long p0_val;
+ char cmd;
+ struct list_head *item;
+
+ memset(str, 0, sizeof(str));
+ memcpy(str, buf, min(count, sizeof(str) -1));
+
+ cmd = str[1];
+
+ p0 = str + 2;
+
+ p1 = p0;
+
+ while (*p1 && *p1 != ',') {
+ p1++;
+ }
+ *p1 = '\0';
+ p1++;
+
+ p0_val = simple_strtol(p0, NULL, 0);
+ p1_val = simple_strtol(p1, NULL, 0);
+
+
+ mutex_lock(&yaffs_context_lock);
+
+ /* Locate and print the Nth entry. Order N-squared but N is small. */
+ list_for_each(item, &yaffs_context_list) {
+ struct yaffs_linux_context *dc =
+ list_entry(item, struct yaffs_linux_context,
+ context_list);
+ struct yaffs_dev *dev = dc->dev;
+
+ if (cmd == 'b') {
+ struct yaffs_block_info *bi;
+
+ bi = yaffs_get_block_info(dev,p0_val);
+
+ if(bi) {
+ printk("Block %d: state %d, retire %d, use %d, seq %d\n",
+ (int)p0_val, bi->block_state,
+ bi->needs_retiring, bi->pages_in_use,
+ bi->seq_number);
+ }
+ } else if (cmd == 'c') {
+ struct yaffs_obj *obj;
+ int nand_chunk;
+
+ obj = yaffs_find_by_number(dev, p0_val);
+ if (!obj)
+ printk("No obj %d\n", (int)p0_val);
+ else {
+ if(p1_val == 0)
+ nand_chunk = obj->hdr_chunk;
+ else
+ nand_chunk =
+ yaffs_find_chunk_in_file(obj,
+ p1_val, NULL);
+ printk("Nand chunk for %d:%d is %d\n",
+ (int)p0_val, (int)p1_val, nand_chunk);
+ }
+ }
+ }
+
+ mutex_unlock(&yaffs_context_lock);
+
+ return count;
+}
+
+static int yaffs_proc_write(struct file *file, const char *buf,
+ unsigned long count, void *data)
+{
+ if (buf[0] == '.')
+ return yaffs_proc_debug_write(file, buf, count, data);
+ return yaffs_proc_write_trace_options(file, buf, count, data);
+}
+
+/* Stuff to handle installation of file systems */
+struct file_system_to_install {
+ struct file_system_type *fst;
+ int installed;
+};
+
+static struct file_system_to_install fs_to_install[] = {
+ {&yaffs_fs_type, 0},
+ {&yaffs2_fs_type, 0},
+ {NULL, 0}
+};
+
+static int __init init_yaffs_fs(void)
+{
+ int error = 0;
+ struct file_system_to_install *fsinst;
+
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs built " __DATE__ " " __TIME__ " Installing.");
+
+ mutex_init(&yaffs_context_lock);
+
+ /* Install the proc_fs entries */
+ my_proc_entry = create_proc_entry("yaffs",
+ S_IRUGO | S_IFREG, YPROC_ROOT);
+
+ if (my_proc_entry) {
+ my_proc_entry->write_proc = yaffs_proc_write;
+ my_proc_entry->read_proc = yaffs_proc_read;
+ my_proc_entry->data = NULL;
+ } else {
+ return -ENOMEM;
+ }
+
+ /* Now add the file system entries */
+
+ fsinst = fs_to_install;
+
+ while (fsinst->fst && !error) {
+ error = register_filesystem(fsinst->fst);
+ if (!error)
+ fsinst->installed = 1;
+ fsinst++;
+ }
+
+ /* Any errors? uninstall */
+ if (error) {
+ fsinst = fs_to_install;
+
+ while (fsinst->fst) {
+ if (fsinst->installed) {
+ unregister_filesystem(fsinst->fst);
+ fsinst->installed = 0;
+ }
+ fsinst++;
+ }
+ }
+
+ return error;
+}
+
+static void __exit exit_yaffs_fs(void)
+{
+
+ struct file_system_to_install *fsinst;
+
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs built " __DATE__ " " __TIME__ " removing.");
+
+ remove_proc_entry("yaffs", YPROC_ROOT);
+
+ fsinst = fs_to_install;
+
+ while (fsinst->fst) {
+ if (fsinst->installed) {
+ unregister_filesystem(fsinst->fst);
+ fsinst->installed = 0;
+ }
+ fsinst++;
+ }
+}
+
+module_init(init_yaffs_fs)
+ module_exit(exit_yaffs_fs)
+
+ MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
+MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2011");
+MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * 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>
- * Acknowledgements:
- * Luc van OostenRyck for numerous patches.
- * Nick Bane for numerous patches.
- * Nick Bane for 2.5/2.6 integration.
- * Andras Toth for mknod rdev issue.
- * Michael Fischer for finding the problem with inode inconsistency.
- * Some code bodily lifted from JFFS
- *
- * 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 is the file system front-end to YAFFS that hooks it up to
- * the VFS.
- *
- * Special notes:
- * >> 2.4: sb->u.generic_sbp points to the yaffs_dev_t associated with
- * this superblock
- * >> 2.6: sb->s_fs_info points to the yaffs_dev_t associated with this
- * superblock
- * >> inode->u.generic_ip points to the associated yaffs_obj_t.
- */
-
-/*
- * There are two variants of the VFS glue code. This variant should compile
- * for any version of Linux.
- */
-#include <linux/version.h>
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
-#define YAFFS_COMPILE_BACKGROUND
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6, 23))
-#define YAFFS_COMPILE_FREEZER
-#endif
-#endif
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
-#define YAFFS_COMPILE_EXPORTFS
-#endif
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
-#define YAFFS_USE_SETATTR_COPY
-#define YAFFS_USE_TRUNCATE_SETSIZE
-#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
-#define YAFFS_HAS_EVICT_INODE
-#endif
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
-#define YAFFS_NEW_FOLLOW_LINK 1
-#else
-#define YAFFS_NEW_FOLLOW_LINK 0
-#endif
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
-#include <linux/config.h>
-#endif
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
-#include <linux/pagemap.h>
-#include <linux/mtd/mtd.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-
-#if (YAFFS_NEW_FOLLOW_LINK == 1)
-#include <linux/namei.h>
-#endif
-
-#ifdef YAFFS_COMPILE_EXPORTFS
-#include <linux/exportfs.h>
-#endif
-
-#ifdef YAFFS_COMPILE_BACKGROUND
-#include <linux/kthread.h>
-#include <linux/delay.h>
-#endif
-#ifdef YAFFS_COMPILE_FREEZER
-#include <linux/freezer.h>
-#endif
-
-#include <asm/div64.h>
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-
-#include <linux/statfs.h>
-
-#define UnlockPage(p) unlock_page(p)
-#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
-
-/* FIXME: use sb->s_id instead ? */
-#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
-
-#else
-
-#include <linux/locks.h>
-#define BDEVNAME_SIZE 0
-#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
-/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
-#define __user
-#endif
-
-#endif
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
-#define YPROC_ROOT (&proc_root)
-#else
-#define YPROC_ROOT NULL
-#endif
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
-#define Y_INIT_TIMER(a) init_timer(a)
-#else
-#define Y_INIT_TIMER(a) init_timer_on_stack(a)
-#endif
-
-#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
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
-#define YAFFS_USE_WRITE_BEGIN_END 1
-#else
-#define YAFFS_USE_WRITE_BEGIN_END 0
-#endif
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
-static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
-{
- uint64_t result = partition_size;
- do_div(result, block_size);
- return (uint32_t)result;
-}
-#else
-#define YCALCBLOCKS(s, b) ((s)/(b))
-#endif
-
-#include <linux/uaccess.h>
-#include <linux/mtd/mtd.h>
-
-#include "yportenv.h"
-#include "yaffs_trace.h"
-#include "yaffs_guts.h"
-
-#include "yaffs_linux.h"
-
-#include "yaffs_mtdif.h"
-#include "yaffs_mtdif1.h"
-#include "yaffs_mtdif2.h"
-
-unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
-unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
-unsigned int yaffs_auto_checkpoint = 1;
-unsigned int yaffs_gc_control = 1;
-unsigned int yaffs_bg_enable = 1;
-
-/* Module Parameters */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-module_param(yaffs_trace_mask, uint, 0644);
-module_param(yaffs_wr_attempts, uint, 0644);
-module_param(yaffs_auto_checkpoint, uint, 0644);
-module_param(yaffs_gc_control, uint, 0644);
-module_param(yaffs_bg_enable, uint, 0644);
-#else
-MODULE_PARM(yaffs_trace_mask, "i");
-MODULE_PARM(yaffs_wr_attempts, "i");
-MODULE_PARM(yaffs_auto_checkpoint, "i");
-MODULE_PARM(yaffs_gc_control, "i");
-#endif
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
-/* use iget and read_inode */
-#define Y_IGET(sb, inum) iget((sb), (inum))
-static void yaffs_read_inode(struct inode *inode);
-
-#else
-/* Call local equivalent */
-#define YAFFS_USE_OWN_IGET
-#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
-
-static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
-#endif
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
-#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
-#else
-#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
-#endif
-
-#define yaffs_InodeToObject(iptr) ((yaffs_obj_t *)(yaffs_InodeToObjectLV(iptr)))
-#define yaffs_dentry_to_obj(dptr) yaffs_InodeToObject((dptr)->d_inode)
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->s_fs_info)
-#else
-#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->u.generic_sbp)
-#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,
- loff_t *pos);
-static ssize_t yaffs_hold_space(struct file *f);
-static void yaffs_release_space(struct file *f);
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
-static int yaffs_file_flush(struct file *file, fl_owner_t id);
-#else
-static int yaffs_file_flush(struct file *file);
-#endif
-
-#if (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,
- int datasync);
-#endif
-
-static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
- struct nameidata *n);
-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);
-static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
- const char *symname);
-static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
- dev_t dev);
-#else
-static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
- int dev);
-#endif
-static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry);
-static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
-static int yaffs_sync_fs(struct super_block *sb, int wait);
-static void yaffs_write_super(struct super_block *sb);
-#else
-static int yaffs_sync_fs(struct super_block *sb);
-static int yaffs_write_super(struct super_block *sb);
-#endif
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
-static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
-#else
-static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
-#endif
-
-#ifdef YAFFS_HAS_PUT_INODE
-static void yaffs_put_inode(struct inode *inode);
-#endif
-
-#ifdef YAFFS_HAS_EVICT_INODE
-static void yaffs_evict_inode(struct inode *);
-#else
-static void yaffs_delete_inode(struct inode *);
-static void yaffs_clear_inode(struct inode *);
-#endif
-
-static int yaffs_readpage(struct file *file, struct page *page);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
-#else
-static int yaffs_writepage(struct page *page);
-#endif
-
-#ifdef CONFIG_YAFFS_XATTR
-int yaffs_setxattr(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags);
-ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
- size_t size);
-int yaffs_removexattr(struct dentry *dentry, const char *name);
-ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size);
-#endif
-
-
-#if (YAFFS_USE_WRITE_BEGIN_END != 0)
-static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata);
-static int yaffs_write_end(struct file *filp, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned copied,
- struct page *pg, void *fsdadata);
-#else
-static int yaffs_prepare_write(struct file *f, struct page *pg,
- unsigned offset, unsigned to);
-static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
- unsigned to);
-
-#endif
-
-static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
- int buflen);
-#if (YAFFS_NEW_FOLLOW_LINK == 1)
-void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias);
-static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
-#else
-static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
-#endif
-
-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 *);
-
-
-static struct address_space_operations yaffs_file_address_operations = {
- .readpage = yaffs_readpage,
- .writepage = yaffs_writepage,
-#if (YAFFS_USE_WRITE_BEGIN_END > 0)
- .write_begin = yaffs_write_begin,
- .write_end = yaffs_write_end,
-#else
- .prepare_write = yaffs_prepare_write,
- .commit_write = yaffs_commit_write,
-#endif
-};
-
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
-static const struct file_operations yaffs_file_operations = {
- .read = do_sync_read,
- .write = do_sync_write,
- .aio_read = generic_file_aio_read,
- .aio_write = generic_file_aio_write,
- .mmap = generic_file_mmap,
- .flush = yaffs_file_flush,
- .fsync = yaffs_sync_object,
- .splice_read = generic_file_splice_read,
- .splice_write = generic_file_splice_write,
- .llseek = generic_file_llseek,
-};
-
-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
-
-static const struct file_operations yaffs_file_operations = {
- .read = do_sync_read,
- .write = do_sync_write,
- .aio_read = generic_file_aio_read,
- .aio_write = generic_file_aio_write,
- .mmap = generic_file_mmap,
- .flush = yaffs_file_flush,
- .fsync = yaffs_sync_object,
- .sendfile = generic_file_sendfile,
-};
-
-#else
-
-static const struct file_operations yaffs_file_operations = {
- .read = generic_file_read,
- .write = generic_file_write,
- .mmap = generic_file_mmap,
- .flush = yaffs_file_flush,
- .fsync = yaffs_sync_object,
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
- .sendfile = generic_file_sendfile,
-#endif
-};
-#endif
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
-static void zero_user_segment(struct page *page, unsigned start, unsigned end)
-{
- void * kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + start, 0, end - start);
- kunmap_atomic(kaddr, KM_USER0);
- flush_dcache_page(page);
-}
-#endif
-
-
-static const struct inode_operations yaffs_file_inode_operations = {
- .setattr = yaffs_setattr,
-#ifdef CONFIG_YAFFS_XATTR
- .setxattr = yaffs_setxattr,
- .getxattr = yaffs_getxattr,
- .listxattr = yaffs_listxattr,
- .removexattr = yaffs_removexattr,
-#endif
-};
-
-static const struct inode_operations yaffs_symlink_inode_operations = {
- .readlink = yaffs_readlink,
- .follow_link = yaffs_follow_link,
-#if (YAFFS_NEW_FOLLOW_LINK == 1)
- .put_link = yaffs_put_link,
-#endif
- .setattr = yaffs_setattr,
-#ifdef CONFIG_YAFFS_XATTR
- .setxattr = yaffs_setxattr,
- .getxattr = yaffs_getxattr,
- .listxattr = yaffs_listxattr,
- .removexattr = yaffs_removexattr,
-#endif
-};
-
-static const struct inode_operations yaffs_dir_inode_operations = {
- .create = yaffs_create,
- .lookup = yaffs_lookup,
- .link = yaffs_link,
- .unlink = yaffs_unlink,
- .symlink = yaffs_symlink,
- .mkdir = yaffs_mkdir,
- .rmdir = yaffs_unlink,
- .mknod = yaffs_mknod,
- .rename = yaffs_rename,
- .setattr = yaffs_setattr,
-#ifdef CONFIG_YAFFS_XATTR
- .setxattr = yaffs_setxattr,
- .getxattr = yaffs_getxattr,
- .listxattr = yaffs_listxattr,
- .removexattr = yaffs_removexattr,
-#endif
-};
-
-static const struct file_operations yaffs_dir_operations = {
- .read = generic_read_dir,
- .readdir = yaffs_readdir,
- .fsync = yaffs_sync_object,
- .llseek = yaffs_dir_llseek,
-};
-
-static const struct super_operations yaffs_super_ops = {
- .statfs = yaffs_statfs,
-
-#ifndef YAFFS_USE_OWN_IGET
- .read_inode = yaffs_read_inode,
-#endif
-#ifdef YAFFS_HAS_PUT_INODE
- .put_inode = yaffs_put_inode,
-#endif
- .put_super = yaffs_put_super,
-#ifdef YAFFS_HAS_EVICT_INODE
- .evict_inode = yaffs_evict_inode,
-#else
- .delete_inode = yaffs_delete_inode,
- .clear_inode = yaffs_clear_inode,
-#endif
- .sync_fs = yaffs_sync_fs,
- .write_super = yaffs_write_super,
-};
-
-
-static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
-{
-#ifdef YAFFS_USE_SETATTR_COPY
- setattr_copy(inode,attr);
- return 0;
-#else
- return inode_setattr(inode, attr);
-#endif
-
-}
-
-static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
-{
-#ifdef YAFFS_USE_TRUNCATE_SETSIZE
- truncate_setsize(inode,newsize);
- return 0;
-#else
- truncate_inode_pages(&inode->i_data,newsize);
- return 0;
-#endif
-
-}
-
-static unsigned yaffs_gc_control_callback(yaffs_dev_t *dev)
-{
- return yaffs_gc_control;
-}
-
-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));
- 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));
-}
-
-#ifdef YAFFS_COMPILE_EXPORTFS
-
-static struct inode *
-yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation)
-{
- return Y_IGET(sb, ino);
-}
-
-static struct dentry *
-yaffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
-{
- return generic_fh_to_dentry(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode) ;
-}
-
-static struct dentry *
- yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
-{
- return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode);
-}
-
-struct dentry *yaffs2_get_parent(struct dentry *dentry)
-{
-
- struct super_block *sb = dentry->d_inode->i_sb;
- struct dentry *parent = ERR_PTR(-ENOENT);
- struct inode *inode;
- unsigned long parent_ino;
- yaffs_obj_t *d_obj;
- yaffs_obj_t *parent_obj;
-
- d_obj = yaffs_InodeToObject(dentry->d_inode);
-
- if (d_obj) {
- parent_obj = d_obj->parent;
- if (parent_obj) {
- parent_ino = yaffs_get_obj_inode(parent_obj);
- inode = Y_IGET(sb, parent_ino);
-
- if (IS_ERR(inode)) {
- parent = ERR_CAST(inode);
- } else {
- parent = d_obtain_alias(inode);
- if (!IS_ERR(parent)) {
- parent = ERR_PTR(-ENOMEM);
- iput(inode);
- }
- }
- }
- }
-
- return parent;
-}
-
-/* Just declare a zero structure as a NULL value implies
- * using the default functions of exportfs.
- */
-
-static struct export_operations yaffs_export_ops =
-{
- .fh_to_dentry = yaffs2_fh_to_dentry,
- .fh_to_parent = yaffs2_fh_to_parent,
- .get_parent = yaffs2_get_parent,
-} ;
-
-#endif
-
-/*-----------------------------------------------------------------*/
-/* Directory search context allows us to unlock access to yaffs during
- * filldir without causing problems with the directory being modified.
- * This is similar to the tried and tested mechanism used in yaffs direct.
- *
- * A search context iterates along a doubly linked list of siblings in the
- * directory. If the iterating object is deleted then this would corrupt
- * the list iteration, likely causing a crash. The search context avoids
- * this by using the remove_obj_fn to move the search context to the
- * next object before the object is deleted.
- *
- * Many readdirs (and thus seach conexts) may be alive simulateously so
- * each yaffs_dev_t has a list of these.
- *
- * A seach context lives for the duration of a readdir.
- *
- * All these functions must be called while yaffs is locked.
- */
-
-struct yaffs_SearchContext {
- yaffs_dev_t *dev;
- yaffs_obj_t *dirObj;
- yaffs_obj_t *nextReturn;
- struct ylist_head others;
-};
-
-/*
- * yaffs_NewSearch() creates a new search context, initialises it and
- * adds it to the device's search context list.
- *
- * Called at start of readdir.
- */
-static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_obj_t *dir)
-{
- yaffs_dev_t *dev = dir->my_dev;
- struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
- if(sc){
- sc->dirObj = dir;
- sc->dev = dev;
- if( ylist_empty(&sc->dirObj->variant.dir_variant.children))
- sc->nextReturn = NULL;
- else
- sc->nextReturn = ylist_entry(
- dir->variant.dir_variant.children.next,
- yaffs_obj_t,siblings);
- YINIT_LIST_HEAD(&sc->others);
- ylist_add(&sc->others,&(yaffs_dev_to_lc(dev)->searchContexts));
- }
- return sc;
-}
-
-/*
- * yaffs_search_end() disposes of a search context and cleans up.
- */
-static void yaffs_search_end(struct yaffs_SearchContext * sc)
-{
- if(sc){
- ylist_del(&sc->others);
- YFREE(sc);
- }
-}
-
-/*
- * yaffs_search_advance() moves a search context to the next object.
- * Called when the search iterates or when an object removal causes
- * the search context to be moved to the next object.
- */
-static void yaffs_search_advance(struct yaffs_SearchContext *sc)
-{
- if(!sc)
- return;
-
- if( sc->nextReturn == NULL ||
- ylist_empty(&sc->dirObj->variant.dir_variant.children))
- sc->nextReturn = NULL;
- else {
- struct ylist_head *next = sc->nextReturn->siblings.next;
-
- if( next == &sc->dirObj->variant.dir_variant.children)
- sc->nextReturn = NULL; /* end of list */
- else
- sc->nextReturn = ylist_entry(next,yaffs_obj_t,siblings);
- }
-}
-
-/*
- * yaffs_remove_obj_callback() is called when an object is unlinked.
- * We check open search contexts and advance any which are currently
- * on the object being iterated.
- */
-static void yaffs_remove_obj_callback(yaffs_obj_t *obj)
-{
-
- struct ylist_head *i;
- struct yaffs_SearchContext *sc;
- struct ylist_head *search_contexts = &(yaffs_dev_to_lc(obj->my_dev)->searchContexts);
-
-
- /* Iterate through the directory search contexts.
- * If any are currently on the object being removed, then advance
- * the search context to the next object to prevent a hanging pointer.
- */
- ylist_for_each(i, search_contexts) {
- if (i) {
- sc = ylist_entry(i, struct yaffs_SearchContext,others);
- if(sc->nextReturn == obj)
- yaffs_search_advance(sc);
- }
- }
-
-}
-
-
-/*-----------------------------------------------------------------*/
-
-static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
- int buflen)
-{
- unsigned char *alias;
- int ret;
-
- yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev;
-
- yaffs_gross_lock(dev);
-
- alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
-
- yaffs_gross_unlock(dev);
-
- if (!alias)
- return -ENOMEM;
-
- ret = vfs_readlink(dentry, buffer, buflen, alias);
- kfree(alias);
- return ret;
-}
-
-#if (YAFFS_NEW_FOLLOW_LINK == 1)
-static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
-#else
-static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
-#endif
-{
- unsigned char *alias;
- int ret;
- yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev;
-
- yaffs_gross_lock(dev);
-
- alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
- yaffs_gross_unlock(dev);
-
- if (!alias) {
- ret = -ENOMEM;
- goto out;
- }
-
-#if (YAFFS_NEW_FOLLOW_LINK == 1)
- nd_set_link(nd, alias);
- ret = (int)alias;
-out:
- return ERR_PTR(ret);
-#else
- ret = vfs_follow_link(nd, alias);
- kfree(alias);
-out:
- return ret;
-#endif
-}
-
-#if (YAFFS_NEW_FOLLOW_LINK == 1)
-void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) {
- kfree(alias);
-}
-#endif
-
-struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
- yaffs_obj_t *obj);
-
-/*
- * Lookup is used to find objects in the fs
- */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-
-static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
- struct nameidata *n)
-#else
-static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
-#endif
-{
- yaffs_obj_t *obj;
- struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
-
- yaffs_dev_t *dev = yaffs_InodeToObject(dir)->my_dev;
-
- if(current != yaffs_dev_to_lc(dev)->readdirProcess)
- yaffs_gross_lock(dev);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_lookup for %d:%s\n"),
- yaffs_InodeToObject(dir)->obj_id, dentry->d_name.name));
-
- obj = yaffs_find_by_name(yaffs_InodeToObject(dir),
- dentry->d_name.name);
-
- obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
-
- /* Can't hold gross lock when calling yaffs_get_inode() */
- if(current != yaffs_dev_to_lc(dev)->readdirProcess)
- yaffs_gross_unlock(dev);
-
- if (obj) {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_lookup found %d\n"), obj->obj_id));
-
- inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
-
- if (inode) {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_loookup dentry \n")));
-/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
- * d_add even if NULL inode */
-#if 0
- /*dget(dentry); // try to solve directory bug */
- d_add(dentry, inode);
-
- /* return dentry; */
- return NULL;
-#endif
- }
-
- } else {
- T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n")));
-
- }
-
-/* added NCB for 2.5/6 compatability - forces add even if inode is
- * NULL which creates dentry hash */
- d_add(dentry, inode);
-
- return NULL;
-}
-
-
-#ifdef YAFFS_HAS_PUT_INODE
-
-/* For now put inode is just for debugging
- * Put inode is called when the inode **structure** is put.
- */
-static void yaffs_put_inode(struct inode *inode)
-{
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino,
- atomic_read(&inode->i_count)));
-
-}
-#endif
-
-
-static void yaffs_unstitch_obj(struct inode *inode, yaffs_obj_t *obj)
-{
- /* Clear the association between the inode and
- * the yaffs_obj_t.
- */
- obj->my_inode = NULL;
- yaffs_InodeToObjectLV(inode) = NULL;
-
- /* If the object freeing was deferred, then the real
- * free happens now.
- * This should fix the inode inconsistency problem.
- */
- yaffs_handle_defered_free(obj);
-}
-
-#ifdef YAFFS_HAS_EVICT_INODE
-/* yaffs_evict_inode combines into one operation what was previously done in
- * yaffs_clear_inode() and yaffs_delete_inode()
- *
- */
-static void yaffs_evict_inode( struct inode *inode)
-{
- yaffs_obj_t *obj;
- yaffs_dev_t *dev;
- int deleteme = 0;
-
- obj = yaffs_InodeToObject(inode);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
- atomic_read(&inode->i_count),
- obj ? "object exists" : "null object"));
-
- if (!inode->i_nlink && !is_bad_inode(inode))
- deleteme = 1;
- truncate_inode_pages(&inode->i_data,0);
- end_writeback(inode);
-
- if(deleteme && obj){
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- yaffs_del_obj(obj);
- yaffs_gross_unlock(dev);
- }
- if (obj) {
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- yaffs_unstitch_obj(inode,obj);
- yaffs_gross_unlock(dev);
- }
-
-
-}
-#else
-
-/* clear is called to tell the fs to release any per-inode data it holds.
- * The object might still exist on disk and is just being thrown out of the cache
- * or else the object has actually been deleted and we're being called via
- * the chain
- * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
- */
-
-static void yaffs_clear_inode(struct inode *inode)
-{
- yaffs_obj_t *obj;
- yaffs_dev_t *dev;
-
- obj = yaffs_InodeToObject(inode);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
- atomic_read(&inode->i_count),
- obj ? "object exists" : "null object"));
-
- if (obj) {
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- yaffs_unstitch_obj(inode,obj);
- yaffs_gross_unlock(dev);
- }
-
-}
-
-/* delete is called when the link count is zero and the inode
- * is put (ie. nobody wants to know about it anymore, time to
- * delete the file).
- * NB Must call clear_inode()
- */
-static void yaffs_delete_inode(struct inode *inode)
-{
- yaffs_obj_t *obj = yaffs_InodeToObject(inode);
- yaffs_dev_t *dev;
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
- atomic_read(&inode->i_count),
- obj ? "object exists" : "null object"));
-
- if (obj) {
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- yaffs_del_obj(obj);
- yaffs_gross_unlock(dev);
- }
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
- truncate_inode_pages(&inode->i_data, 0);
-#endif
- clear_inode(inode);
-}
-#endif
-
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
-static int yaffs_file_flush(struct file *file, fl_owner_t id)
-#else
-static int yaffs_file_flush(struct file *file)
-#endif
-{
- yaffs_obj_t *obj = yaffs_dentry_to_obj(file->f_dentry);
-
- yaffs_dev_t *dev = obj->my_dev;
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_file_flush object %d (%s)\n"), obj->obj_id,
- obj->dirty ? "dirty" : "clean"));
-
- yaffs_gross_lock(dev);
-
- yaffs_flush_file(obj, 1, 0);
-
- yaffs_gross_unlock(dev);
-
- return 0;
-}
-
-static int yaffs_readpage_nolock(struct file *f, struct page *pg)
-{
- /* Lifted from jffs2 */
-
- yaffs_obj_t *obj;
- unsigned char *pg_buf;
- int ret;
-
- yaffs_dev_t *dev;
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"),
- (unsigned)(pg->index << PAGE_CACHE_SHIFT),
- (unsigned)PAGE_CACHE_SIZE));
-
- obj = yaffs_dentry_to_obj(f->f_dentry);
-
- dev = obj->my_dev;
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
- BUG_ON(!PageLocked(pg));
-#else
- if (!PageLocked(pg))
- PAGE_BUG(pg);
-#endif
-
- pg_buf = kmap(pg);
- /* FIXME: Can kmap fail? */
-
- yaffs_gross_lock(dev);
-
- ret = yaffs_file_rd(obj, pg_buf,
- pg->index << PAGE_CACHE_SHIFT,
- PAGE_CACHE_SIZE);
-
- yaffs_gross_unlock(dev);
-
- if (ret >= 0)
- ret = 0;
-
- if (ret) {
- ClearPageUptodate(pg);
- SetPageError(pg);
- } else {
- SetPageUptodate(pg);
- ClearPageError(pg);
- }
-
- flush_dcache_page(pg);
- kunmap(pg);
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n")));
- return ret;
-}
-
-static int yaffs_readpage_unlock(struct file *f, struct page *pg)
-{
- int ret = yaffs_readpage_nolock(f, pg);
- UnlockPage(pg);
- return ret;
-}
-
-static int yaffs_readpage(struct file *f, struct page *pg)
-{
- int ret;
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n")));
- ret=yaffs_readpage_unlock(f, pg);
- T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n")));
- return ret;
-}
-
-/* writepage inspired by/stolen from smbfs */
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
-#else
-static int yaffs_writepage(struct page *page)
-#endif
-{
- yaffs_dev_t *dev;
- struct address_space *mapping = page->mapping;
- struct inode *inode;
- unsigned long end_index;
- char *buffer;
- yaffs_obj_t *obj;
- int nWritten = 0;
- unsigned n_bytes;
- loff_t i_size;
-
- if (!mapping)
- BUG();
- inode = mapping->host;
- if (!inode)
- BUG();
- i_size = i_size_read(inode);
-
- end_index = i_size >> PAGE_CACHE_SHIFT;
-
- if(page->index < end_index)
- n_bytes = PAGE_CACHE_SIZE;
- else {
- n_bytes = i_size & (PAGE_CACHE_SIZE -1);
-
- if (page->index > end_index || !n_bytes) {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_writepage at %08x, inode size = %08x!!!\n"),
- (unsigned)(page->index << PAGE_CACHE_SHIFT),
- (unsigned)inode->i_size));
- T(YAFFS_TRACE_OS,
- (TSTR(" -> don't care!!\n")));
-
- zero_user_segment(page,0,PAGE_CACHE_SIZE);
- set_page_writeback(page);
- unlock_page(page);
- end_page_writeback(page);
- return 0;
- }
- }
-
- if(n_bytes != PAGE_CACHE_SIZE)
- zero_user_segment(page,n_bytes,PAGE_CACHE_SIZE);
-
- get_page(page);
-
- buffer = kmap(page);
-
- obj = yaffs_InodeToObject(inode);
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_writepage at %08x, size %08x\n"),
- (unsigned)(page->index << PAGE_CACHE_SHIFT), n_bytes));
- T(YAFFS_TRACE_OS,
- (TSTR("writepag0: obj = %05x, ino = %05x\n"),
- (int)obj->variant.file_variant.file_size, (int)inode->i_size));
-
- nWritten = yaffs_wr_file(obj, buffer,
- page->index << PAGE_CACHE_SHIFT, n_bytes, 0);
-
- yaffs_touch_super(dev);
-
- T(YAFFS_TRACE_OS,
- (TSTR("writepag1: obj = %05x, ino = %05x\n"),
- (int)obj->variant.file_variant.file_size, (int)inode->i_size));
-
- yaffs_gross_unlock(dev);
-
- kunmap(page);
- set_page_writeback(page);
- unlock_page(page);
- end_page_writeback(page);
- put_page(page);
-
- return (nWritten == n_bytes) ? 0 : -ENOSPC;
-}
-
-
-#if (YAFFS_USE_WRITE_BEGIN_END > 0)
-static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata)
-{
- struct page *pg = NULL;
- pgoff_t index = pos >> PAGE_CACHE_SHIFT;
-
- int ret = 0;
- int space_held = 0;
-
- /* Get a page */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
- pg = grab_cache_page_write_begin(mapping, index, flags);
-#else
- pg = __grab_cache_page(mapping, index);
-#endif
-
- *pagep = pg;
- if (!pg) {
- ret = -ENOMEM;
- goto out;
- }
- T(YAFFS_TRACE_OS,
- (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"),
- (int)index,(int)index,Page_Uptodate(pg) ? 1 : 0));
-
- /* Get fs space */
- space_held = yaffs_hold_space(filp);
-
- if (!space_held) {
- ret = -ENOSPC;
- goto out;
- }
-
- /* Update page if required */
-
- if (!Page_Uptodate(pg))
- ret = yaffs_readpage_nolock(filp, pg);
-
- if (ret)
- goto out;
-
- /* Happy path return */
- T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n")));
-
- return 0;
-
-out:
- T(YAFFS_TRACE_OS,
- (TSTR("end yaffs_write_begin fail returning %d\n"), ret));
- if (space_held)
- yaffs_release_space(filp);
- if (pg) {
- unlock_page(pg);
- page_cache_release(pg);
- }
- return ret;
-}
-
-#else
-
-static int yaffs_prepare_write(struct file *f, struct page *pg,
- unsigned offset, unsigned to)
-{
- T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n")));
-
- if (!Page_Uptodate(pg))
- return yaffs_readpage_nolock(f, pg);
- return 0;
-}
-#endif
-
-#if (YAFFS_USE_WRITE_BEGIN_END > 0)
-static int yaffs_write_end(struct file *filp, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned copied,
- struct page *pg, void *fsdadata)
-{
- int ret = 0;
- void *addr, *kva;
- uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
-
- kva = kmap(pg);
- addr = kva + offset_into_page;
-
- T(YAFFS_TRACE_OS,
- ("yaffs_write_end addr %p pos %x n_bytes %d\n",
- addr,(unsigned)pos, copied));
-
- ret = yaffs_file_write(filp, addr, copied, &pos);
-
- if (ret != copied) {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_write_end not same size ret %d copied %d\n"),
- ret, copied));
- SetPageError(pg);
- } else {
- /* Nothing */
- }
-
- kunmap(pg);
-
- yaffs_release_space(filp);
- unlock_page(pg);
- page_cache_release(pg);
- return ret;
-}
-#else
-
-static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
- unsigned to)
-{
- void *addr, *kva;
-
- loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
- int n_bytes = to - offset;
- int nWritten;
-
- unsigned spos = pos;
- unsigned saddr;
-
- kva = kmap(pg);
- addr = kva + offset;
-
- saddr = (unsigned) addr;
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_commit_write addr %x pos %x n_bytes %d\n"),
- saddr, spos, n_bytes));
-
- nWritten = yaffs_file_write(f, addr, n_bytes, &pos);
-
- if (nWritten != n_bytes) {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_commit_write not same size nWritten %d n_bytes %d\n"),
- nWritten, n_bytes));
- SetPageError(pg);
- } else {
- /* Nothing */
- }
-
- kunmap(pg);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_commit_write returning %d\n"),
- nWritten == n_bytes ? 0 : nWritten));
-
- return nWritten == n_bytes ? 0 : nWritten;
-}
-#endif
-
-
-static void yaffs_fill_inode_from_obj(struct inode *inode, yaffs_obj_t *obj)
-{
- if (inode && obj) {
-
-
- /* Check mode against the variant type and attempt to repair if broken. */
- __u32 mode = obj->yst_mode;
- switch (obj->variant_type) {
- case YAFFS_OBJECT_TYPE_FILE:
- if (!S_ISREG(mode)) {
- obj->yst_mode &= ~S_IFMT;
- obj->yst_mode |= S_IFREG;
- }
-
- break;
- case YAFFS_OBJECT_TYPE_SYMLINK:
- if (!S_ISLNK(mode)) {
- obj->yst_mode &= ~S_IFMT;
- obj->yst_mode |= S_IFLNK;
- }
-
- break;
- case YAFFS_OBJECT_TYPE_DIRECTORY:
- if (!S_ISDIR(mode)) {
- obj->yst_mode &= ~S_IFMT;
- obj->yst_mode |= S_IFDIR;
- }
-
- break;
- case YAFFS_OBJECT_TYPE_UNKNOWN:
- case YAFFS_OBJECT_TYPE_HARDLINK:
- case YAFFS_OBJECT_TYPE_SPECIAL:
- default:
- /* TODO? */
- break;
- }
-
- inode->i_flags |= S_NOATIME;
-
- inode->i_ino = obj->obj_id;
- inode->i_mode = obj->yst_mode;
- inode->i_uid = obj->yst_uid;
- inode->i_gid = obj->yst_gid;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
- inode->i_blksize = inode->i_sb->s_blocksize;
-#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-
- inode->i_rdev = old_decode_dev(obj->yst_rdev);
- inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
- inode->i_atime.tv_nsec = 0;
- inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
- inode->i_mtime.tv_nsec = 0;
- inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
- inode->i_ctime.tv_nsec = 0;
-#else
- inode->i_rdev = obj->yst_rdev;
- inode->i_atime = obj->yst_atime;
- inode->i_mtime = obj->yst_mtime;
- inode->i_ctime = obj->yst_ctime;
-#endif
- 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);
-
- 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,
- (int)inode->i_size, atomic_read(&inode->i_count)));
-
- switch (obj->yst_mode & S_IFMT) {
- default: /* fifo, device or socket */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
- init_special_inode(inode, obj->yst_mode,
- old_decode_dev(obj->yst_rdev));
-#else
- init_special_inode(inode, obj->yst_mode,
- (dev_t) (obj->yst_rdev));
-#endif
- break;
- case S_IFREG: /* file */
- inode->i_op = &yaffs_file_inode_operations;
- inode->i_fop = &yaffs_file_operations;
- inode->i_mapping->a_ops =
- &yaffs_file_address_operations;
- break;
- case S_IFDIR: /* directory */
- inode->i_op = &yaffs_dir_inode_operations;
- inode->i_fop = &yaffs_dir_operations;
- break;
- case S_IFLNK: /* symlink */
- inode->i_op = &yaffs_symlink_inode_operations;
- break;
- }
-
- yaffs_InodeToObjectLV(inode) = obj;
-
- obj->my_inode = inode;
-
- } else {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_FileInode invalid parameters\n")));
- }
-
-}
-
-struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
- yaffs_obj_t *obj)
-{
- struct inode *inode;
-
- if (!sb) {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_get_inode for NULL super_block!!\n")));
- return NULL;
-
- }
-
- if (!obj) {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_get_inode for NULL object!!\n")));
- return NULL;
-
- }
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_get_inode for object %d\n"), obj->obj_id));
-
- inode = Y_IGET(sb, obj->obj_id);
- if (IS_ERR(inode))
- return NULL;
-
- /* NB Side effect: iget calls back to yaffs_read_inode(). */
- /* iget also increments the inode's i_count */
- /* NB You can't be holding grossLock or deadlock will happen! */
-
- return inode;
-}
-
-static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
- loff_t *pos)
-{
- yaffs_obj_t *obj;
- int nWritten, ipos;
- struct inode *inode;
- yaffs_dev_t *dev;
-
- obj = yaffs_dentry_to_obj(f->f_dentry);
-
- dev = obj->my_dev;
-
- yaffs_gross_lock(dev);
-
- inode = f->f_dentry->d_inode;
-
- if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
- ipos = inode->i_size;
- else
- ipos = *pos;
-
- if (!obj)
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_file_write: hey obj is null!\n")));
- else
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_file_write about to write writing %u(%x) bytes"
- "to object %d at %d(%x)\n"),
- (unsigned) n, (unsigned) n, obj->obj_id, ipos,ipos));
-
- nWritten = yaffs_wr_file(obj, buf, ipos, n, 0);
-
- yaffs_touch_super(dev);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_file_write: %d(%x) bytes written\n"),
- (unsigned )n,(unsigned)n));
-
- if (nWritten > 0) {
- ipos += nWritten;
- *pos = ipos;
- if (ipos > inode->i_size) {
- inode->i_size = ipos;
- inode->i_blocks = (ipos + 511) >> 9;
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_file_write size updated to %d bytes, "
- "%d blocks\n"),
- ipos, (int)(inode->i_blocks)));
- }
-
- }
- yaffs_gross_unlock(dev);
- return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
-}
-
-/* Space holding and freeing is done to ensure we have space available for write_begin/end */
-/* For now we just assume few parallel writes and check against a small number. */
-/* Todo: need to do this with a counter to handle parallel reads better */
-
-static ssize_t yaffs_hold_space(struct file *f)
-{
- yaffs_obj_t *obj;
- yaffs_dev_t *dev;
-
- int n_free_chunks;
-
-
- obj = yaffs_dentry_to_obj(f->f_dentry);
-
- dev = obj->my_dev;
-
- yaffs_gross_lock(dev);
-
- n_free_chunks = yaffs_get_n_free_chunks(dev);
-
- yaffs_gross_unlock(dev);
-
- return (n_free_chunks > 20) ? 1 : 0;
-}
-
-static void yaffs_release_space(struct file *f)
-{
- yaffs_obj_t *obj;
- yaffs_dev_t *dev;
-
-
- obj = yaffs_dentry_to_obj(f->f_dentry);
-
- dev = obj->my_dev;
-
- yaffs_gross_lock(dev);
-
-
- yaffs_gross_unlock(dev);
-}
-
-
-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;
- yaffs_dev_t *dev;
- struct yaffs_SearchContext *sc;
- struct inode *inode = f->f_dentry->d_inode;
- unsigned long offset, curoffs;
- yaffs_obj_t *l;
- int retVal = 0;
-
- char name[YAFFS_MAX_NAME_LENGTH + 1];
-
- obj = yaffs_dentry_to_obj(f->f_dentry);
- dev = obj->my_dev;
-
- yaffs_gross_lock(dev);
-
- yaffs_dev_to_lc(dev)->readdirProcess = current;
-
- offset = f->f_pos;
-
- sc = yaffs_NewSearch(obj);
- if(!sc){
- retVal = -ENOMEM;
- goto out;
- }
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset));
-
- if (offset == 0) {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_readdir: entry . ino %d \n"),
- (int)inode->i_ino));
- yaffs_gross_unlock(dev);
- if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){
- yaffs_gross_lock(dev);
- goto out;
- }
- yaffs_gross_lock(dev);
- offset++;
- f->f_pos++;
- }
- if (offset == 1) {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_readdir: entry .. ino %d \n"),
- (int)f->f_dentry->d_parent->d_inode->i_ino));
- yaffs_gross_unlock(dev);
- if (filldir(dirent, "..", 2, offset,
- f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){
- yaffs_gross_lock(dev);
- goto out;
- }
- yaffs_gross_lock(dev);
- offset++;
- f->f_pos++;
- }
-
- curoffs = 1;
-
- /* If the directory has changed since the open or last call to
- readdir, rewind to after the 2 canned entries. */
- if (f->f_version != inode->i_version) {
- offset = 2;
- f->f_pos = offset;
- f->f_version = inode->i_version;
- }
-
- while(sc->nextReturn){
- curoffs++;
- l = sc->nextReturn;
- 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);
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_readdir: %s inode %d\n"),
- name, yaffs_get_obj_inode(l)));
-
- yaffs_gross_unlock(dev);
-
- if (filldir(dirent,
- name,
- strlen(name),
- offset,
- this_inode,
- this_type) < 0){
- yaffs_gross_lock(dev);
- goto out;
- }
-
- yaffs_gross_lock(dev);
-
- offset++;
- f->f_pos++;
- }
- yaffs_search_advance(sc);
- }
-
-out:
- yaffs_search_end(sc);
- yaffs_dev_to_lc(dev)->readdirProcess = NULL;
- yaffs_gross_unlock(dev);
-
- return retVal;
-}
-
-
-
-/*
- * File creation. Allocate an inode, and we're done..
- */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
-#define YCRED(x) x
-#else
-#define YCRED(x) (x->cred)
-#endif
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
- dev_t rdev)
-#else
-static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
- int rdev)
-#endif
-{
- struct inode *inode;
-
- yaffs_obj_t *obj = NULL;
- yaffs_dev_t *dev;
-
- 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;
-
- if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
- mode |= S_ISGID;
-
- if (parent) {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_mknod: parent object %d type %d\n"),
- parent->obj_id, parent->variant_type));
- } else {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_mknod: could not get parent object\n")));
- return -EPERM;
- }
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, "
- "mode %x dev %x\n"),
- dentry->d_name.name, mode, rdev));
-
- dev = parent->my_dev;
-
- yaffs_gross_lock(dev);
-
- switch (mode & S_IFMT) {
- default:
- /* Special (socket, fifo, device...) */
- T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n")));
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
- obj = yaffs_create_special(parent, dentry->d_name.name, mode, uid,
- gid, old_encode_dev(rdev));
-#else
- obj = yaffs_create_special(parent, dentry->d_name.name, mode, uid,
- gid, rdev);
-#endif
- break;
- case S_IFREG: /* file */
- T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n")));
- obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
- gid);
- break;
- case S_IFDIR: /* directory */
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_mknod: making directory\n")));
- obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
- uid, gid);
- break;
- case S_IFLNK: /* symlink */
- T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n")));
- obj = NULL; /* Do we ever get here? */
- break;
- }
-
- /* Can not call yaffs_get_inode() with gross lock held */
- yaffs_gross_unlock(dev);
-
- if (obj) {
- inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
- d_instantiate(dentry, inode);
- update_dir_time(dir);
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_mknod created object %d count = %d\n"),
- obj->obj_id, atomic_read(&inode->i_count)));
- error = 0;
- yaffs_fill_inode_from_obj(dir,parent);
- } else {
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_mknod failed making object\n")));
- error = -ENOMEM;
- }
-
- return error;
-}
-
-static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
-{
- int retVal;
- T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
- retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
- return retVal;
-}
-
-#if (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
-{
- T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n")));
- return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
-}
-
-static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
-{
- int retVal;
-
- yaffs_dev_t *dev;
- yaffs_obj_t *obj;
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_unlink %d:%s\n"),
- (int)(dir->i_ino),
- dentry->d_name.name));
- obj = yaffs_InodeToObject(dir);
- dev = obj->my_dev;
-
- yaffs_gross_lock(dev);
-
- retVal = yaffs_unlinker(obj, dentry->d_name.name);
-
- if (retVal == YAFFS_OK) {
- dentry->d_inode->i_nlink--;
- dir->i_version++;
- yaffs_gross_unlock(dev);
- mark_inode_dirty(dentry->d_inode);
- update_dir_time(dir);
- return 0;
- }
- yaffs_gross_unlock(dev);
- return -ENOTEMPTY;
-}
-
-/*
- * Create a link...
- */
-static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
- struct dentry *dentry)
-{
- struct inode *inode = old_dentry->d_inode;
- yaffs_obj_t *obj = NULL;
- yaffs_obj_t *link = NULL;
- yaffs_dev_t *dev;
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n")));
-
- obj = yaffs_InodeToObject(inode);
- dev = obj->my_dev;
-
- yaffs_gross_lock(dev);
-
- if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
- link = yaffs_link_obj(yaffs_InodeToObject(dir), dentry->d_name.name,
- obj);
-
- if (link) {
- old_dentry->d_inode->i_nlink = 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,
- (TSTR("yaffs_link link count %d i_count %d\n"),
- old_dentry->d_inode->i_nlink,
- atomic_read(&old_dentry->d_inode->i_count)));
- }
-
- yaffs_gross_unlock(dev);
-
- if (link){
- update_dir_time(dir);
- return 0;
- }
-
- return -EPERM;
-}
-
-static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
- const char *symname)
-{
- 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;
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
-
- dev = yaffs_InodeToObject(dir)->my_dev;
- yaffs_gross_lock(dev);
- obj = yaffs_create_symlink(yaffs_InodeToObject(dir), dentry->d_name.name,
- S_IFLNK | S_IRWXUGO, uid, gid, symname);
- yaffs_gross_unlock(dev);
-
- if (obj) {
- struct inode *inode;
-
- inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
- d_instantiate(dentry, inode);
- update_dir_time(dir);
- T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n")));
- return 0;
- } else {
- T(YAFFS_TRACE_OS, (TSTR("symlink not created\n")));
- }
-
- return -ENOMEM;
-}
-
-#if (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,
- int datasync)
-#endif
-{
-
- yaffs_obj_t *obj;
- yaffs_dev_t *dev;
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
- struct dentry *dentry = file->f_path.dentry;
-#endif
-
- obj = yaffs_dentry_to_obj(dentry);
-
- dev = obj->my_dev;
-
- T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
- (TSTR("yaffs_sync_object\n")));
- yaffs_gross_lock(dev);
- yaffs_flush_file(obj, 1, datasync);
- yaffs_gross_unlock(dev);
- return 0;
-}
-
-/*
- * The VFS layer already does all the dentry stuff for rename.
- *
- * NB: POSIX says you can rename an object over an old object of the same name
- */
-static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
-{
- yaffs_dev_t *dev;
- int retVal = YAFFS_FAIL;
- yaffs_obj_t *target;
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n")));
- dev = yaffs_InodeToObject(old_dir)->my_dev;
-
- yaffs_gross_lock(dev);
-
- /* Check if the target is an existing directory that is not empty. */
- target = yaffs_find_by_name(yaffs_InodeToObject(new_dir),
- new_dentry->d_name.name);
-
-
-
- if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
- !ylist_empty(&target->variant.dir_variant.children)) {
-
- T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n")));
-
- retVal = YAFFS_FAIL;
- } else {
- /* Now does unlinking internally using shadowing mechanism */
- T(YAFFS_TRACE_OS, (TSTR("calling yaffs_rename_obj\n")));
-
- retVal = yaffs_rename_obj(yaffs_InodeToObject(old_dir),
- old_dentry->d_name.name,
- yaffs_InodeToObject(new_dir),
- new_dentry->d_name.name);
- }
- yaffs_gross_unlock(dev);
-
- if (retVal == YAFFS_OK) {
- if (target) {
- new_dentry->d_inode->i_nlink--;
- mark_inode_dirty(new_dentry->d_inode);
- }
-
- update_dir_time(old_dir);
- if(old_dir != new_dir)
- update_dir_time(new_dir);
- return 0;
- } else {
- return -ENOTEMPTY;
- }
-}
-
-static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
-{
- struct inode *inode = dentry->d_inode;
- int error = 0;
- yaffs_dev_t *dev;
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_setattr of object %d\n"),
- yaffs_InodeToObject(inode)->obj_id));
-
- /* Fail if a requested resize >= 2GB */
- if (attr->ia_valid & ATTR_SIZE &&
- (attr->ia_size >> 31))
- error = -EINVAL;
-
- if (error == 0)
- error = inode_change_ok(inode, attr);
- if (error == 0) {
- int result;
- if (!error){
- error = yaffs_vfs_setattr(inode, attr);
- T(YAFFS_TRACE_OS,(TSTR("inode_setattr called\n")));
- if (attr->ia_valid & ATTR_SIZE){
- yaffs_vfs_setsize(inode,attr->ia_size);
- inode->i_blocks = (inode->i_size + 511) >> 9;
- }
- }
- dev = yaffs_InodeToObject(inode)->my_dev;
- if (attr->ia_valid & ATTR_SIZE){
- T(YAFFS_TRACE_OS,(TSTR("resize to %d(%x)\n"),
- (int)(attr->ia_size),(int)(attr->ia_size)));
- }
- yaffs_gross_lock(dev);
- result = yaffs_set_attribs(yaffs_InodeToObject(inode), attr);
- if(result == YAFFS_OK) {
- error = 0;
- } else {
- error = -EPERM;
- }
- yaffs_gross_unlock(dev);
-
- }
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_setattr done returning %d\n"),error));
-
- return error;
-}
-
-#ifdef CONFIG_YAFFS_XATTR
-int yaffs_setxattr(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags)
-{
- struct inode *inode = dentry->d_inode;
- int error = 0;
- yaffs_dev_t *dev;
- yaffs_obj_t *obj = yaffs_InodeToObject(inode);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_setxattr of object %d\n"),
- obj->obj_id));
-
-
- if (error == 0) {
- int result;
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- result = yaffs_set_xattrib(obj, name, value, size, flags);
- if(result == YAFFS_OK)
- error = 0;
- else if(result < 0)
- error = result;
- yaffs_gross_unlock(dev);
-
- }
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_setxattr done returning %d\n"),error));
-
- return error;
-}
-
-
-ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
- size_t size)
-{
- struct inode *inode = dentry->d_inode;
- int error = 0;
- yaffs_dev_t *dev;
- yaffs_obj_t *obj = yaffs_InodeToObject(inode);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_getxattr \"%s\" from object %d\n"),
- name, obj->obj_id));
-
- if (error == 0) {
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- error = yaffs_get_xattrib(obj, name, buff, size);
- yaffs_gross_unlock(dev);
-
- }
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_getxattr done returning %d\n"),error));
-
- return error;
-}
-
-int yaffs_removexattr(struct dentry *dentry, const char *name)
-{
- struct inode *inode = dentry->d_inode;
- int error = 0;
- yaffs_dev_t *dev;
- yaffs_obj_t *obj = yaffs_InodeToObject(inode);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_removexattr of object %d\n"),
- obj->obj_id));
-
-
- if (error == 0) {
- int result;
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- result = yaffs_remove_xattrib(obj, name);
- if(result == YAFFS_OK)
- error = 0;
- else if(result < 0)
- error = result;
- yaffs_gross_unlock(dev);
-
- }
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_removexattr done returning %d\n"),error));
-
- return error;
-}
-
-ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size)
-{
- struct inode *inode = dentry->d_inode;
- int error = 0;
- yaffs_dev_t *dev;
- yaffs_obj_t *obj = yaffs_InodeToObject(inode);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_listxattr of object %d\n"),
- obj->obj_id));
-
-
- if (error == 0) {
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- error = yaffs_list_xattrib(obj, buff, size);
- yaffs_gross_unlock(dev);
-
- }
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_listxattr done returning %d\n"),error));
-
- return error;
-}
-
-#endif
-
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
-static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
-{
- yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev;
- struct super_block *sb = dentry->d_sb;
-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
-{
- yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
-#else
-static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
-{
- yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
-#endif
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n")));
-
- yaffs_gross_lock(dev);
-
- buf->f_type = YAFFS_MAGIC;
- buf->f_bsize = sb->s_blocksize;
- buf->f_namelen = 255;
-
- if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
- /* Do this if chunk size is not a power of 2 */
-
- uint64_t bytesInDev;
- uint64_t bytesFree;
-
- bytesInDev = ((uint64_t)((dev->param.end_block - dev->param.start_block + 1))) *
- ((uint64_t)(dev->param.chunks_per_block * dev->data_bytes_per_chunk));
-
- do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
- buf->f_blocks = bytesInDev;
-
- bytesFree = ((uint64_t)(yaffs_get_n_free_chunks(dev))) *
- ((uint64_t)(dev->data_bytes_per_chunk));
-
- do_div(bytesFree, sb->s_blocksize);
-
- buf->f_bfree = bytesFree;
-
- } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
-
- buf->f_blocks =
- (dev->param.end_block - dev->param.start_block + 1) *
- dev->param.chunks_per_block /
- (sb->s_blocksize / dev->data_bytes_per_chunk);
- buf->f_bfree =
- yaffs_get_n_free_chunks(dev) /
- (sb->s_blocksize / dev->data_bytes_per_chunk);
- } else {
- buf->f_blocks =
- (dev->param.end_block - dev->param.start_block + 1) *
- dev->param.chunks_per_block *
- (dev->data_bytes_per_chunk / sb->s_blocksize);
-
- buf->f_bfree =
- yaffs_get_n_free_chunks(dev) *
- (dev->data_bytes_per_chunk / sb->s_blocksize);
- }
-
- buf->f_files = 0;
- buf->f_ffree = 0;
- buf->f_bavail = buf->f_bfree;
-
- yaffs_gross_unlock(dev);
- return 0;
-}
-
-
-
-static void yaffs_flush_inodes(struct super_block *sb)
-{
- struct inode *iptr;
- yaffs_obj_t *obj;
-
- list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
- obj = yaffs_InodeToObject(iptr);
- if(obj){
- T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"),
- obj->obj_id));
- yaffs_flush_file(obj,1,0);
- }
- }
-}
-
-
-static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
-{
- yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
- if(!dev)
- return;
-
- yaffs_flush_inodes(sb);
- yaffs_update_dirty_dirs(dev);
- yaffs_flush_whole_cache(dev);
- if(do_checkpoint)
- yaffs_checkpoint_save(dev);
-}
-
-
-static unsigned yaffs_bg_gc_urgency(yaffs_dev_t *dev)
-{
- unsigned erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block;
- struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
- unsigned scatteredFree = 0; /* Free chunks not in an erased block */
-
- if(erasedChunks < dev->n_free_chunks)
- scatteredFree = (dev->n_free_chunks - erasedChunks);
-
- if(!context->bgRunning)
- return 0;
- else if(scatteredFree < (dev->param.chunks_per_block * 2))
- return 0;
- else if(erasedChunks > dev->n_free_chunks/2)
- return 0;
- else if(erasedChunks > dev->n_free_chunks/4)
- return 1;
- else
- return 2;
-}
-
-static int yaffs_do_sync_fs(struct super_block *sb,
- int request_checkpoint)
-{
-
- yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
- unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
- unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
- int do_checkpoint;
-
- 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",
- request_checkpoint ? "checkpoint requested" : "no checkpoint",
- oneshot_checkpoint ? " one-shot" : "" ));
-
- yaffs_gross_lock(dev);
- do_checkpoint = ((request_checkpoint && !gc_urgent) ||
- oneshot_checkpoint) &&
- !dev->is_checkpointed;
-
- if (sb->s_dirt || do_checkpoint) {
- yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
- sb->s_dirt = 0;
- if(oneshot_checkpoint)
- yaffs_auto_checkpoint &= ~4;
- }
- yaffs_gross_unlock(dev);
-
- return 0;
-}
-
-/*
- * yaffs background thread functions .
- * yaffs_bg_thread_fn() the thread function
- * yaffs_bg_start() launches the background thread.
- * yaffs_bg_stop() cleans up the background thread.
- *
- * 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.
- */
-
-#ifdef YAFFS_COMPILE_BACKGROUND
-
-void yaffs_background_waker(unsigned long data)
-{
- wake_up_process((struct task_struct *)data);
-}
-
-static int yaffs_bg_thread_fn(void *data)
-{
- yaffs_dev_t *dev = (yaffs_dev_t *)data;
- struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
- unsigned long now = jiffies;
- unsigned long next_dir_update = now;
- unsigned long next_gc = now;
- unsigned long expires;
- unsigned int urgency;
-
- int gcResult;
- struct timer_list timer;
-
- T(YAFFS_TRACE_BACKGROUND,
- (TSTR("yaffs_background starting for dev %p\n"),
- (void *)dev));
-
-#ifdef YAFFS_COMPILE_FREEZER
- set_freezable();
-#endif
- while(context->bgRunning){
- T(YAFFS_TRACE_BACKGROUND,
- (TSTR("yaffs_background\n")));
-
- if(kthread_should_stop())
- break;
-
-#ifdef YAFFS_COMPILE_FREEZER
- if(try_to_freeze())
- continue;
-#endif
- yaffs_gross_lock(dev);
-
- now = jiffies;
-
- if(time_after(now, next_dir_update) && yaffs_bg_enable){
- yaffs_update_dirty_dirs(dev);
- next_dir_update = now + HZ;
- }
-
- if(time_after(now,next_gc) && yaffs_bg_enable){
- if(!dev->is_checkpointed){
- urgency = yaffs_bg_gc_urgency(dev);
- gcResult = yaffs_bg_gc(dev, urgency);
- if(urgency > 1)
- next_gc = now + HZ/20+1;
- else if(urgency > 0)
- next_gc = now + HZ/10+1;
- else
- next_gc = now + HZ * 2;
- } else /*
- * gc not running so set to next_dir_update
- * to cut down on wake ups
- */
- next_gc = next_dir_update;
- }
- yaffs_gross_unlock(dev);
-#if 1
- expires = next_dir_update;
- if (time_before(next_gc,expires))
- expires = next_gc;
- if(time_before(expires,now))
- expires = now + HZ;
-
- Y_INIT_TIMER(&timer);
- timer.expires = expires+1;
- timer.data = (unsigned long) current;
- timer.function = yaffs_background_waker;
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_timer(&timer);
- schedule();
- del_timer_sync(&timer);
-#else
- msleep(10);
-#endif
- }
-
- return 0;
-}
-
-static int yaffs_bg_start(yaffs_dev_t *dev)
-{
- int retval = 0;
- struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
-
- if(dev->read_only)
- return -1;
-
- context->bgRunning = 1;
-
- context->bgThread = kthread_run(yaffs_bg_thread_fn,
- (void *)dev,"yaffs-bg-%d",context->mount_id);
-
- if(IS_ERR(context->bgThread)){
- retval = PTR_ERR(context->bgThread);
- context->bgThread = NULL;
- context->bgRunning = 0;
- }
- return retval;
-}
-
-static void yaffs_bg_stop(yaffs_dev_t *dev)
-{
- struct yaffs_LinuxContext *ctxt = yaffs_dev_to_lc(dev);
-
- ctxt->bgRunning = 0;
-
- if( ctxt->bgThread){
- kthread_stop(ctxt->bgThread);
- ctxt->bgThread = NULL;
- }
-}
-#else
-static int yaffs_bg_thread_fn(void *data)
-{
- return 0;
-}
-
-static int yaffs_bg_start(yaffs_dev_t *dev)
-{
- return 0;
-}
-
-static void yaffs_bg_stop(yaffs_dev_t *dev)
-{
-}
-#endif
-
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
-static void yaffs_write_super(struct super_block *sb)
-#else
-static int yaffs_write_super(struct super_block *sb)
-#endif
-{
- unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
-
- T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
- (TSTR("yaffs_write_super%s\n"),
- request_checkpoint ? " checkpt" : ""));
-
- yaffs_do_sync_fs(sb, request_checkpoint);
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
- return 0;
-#endif
-}
-
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
-static int yaffs_sync_fs(struct super_block *sb, int wait)
-#else
-static int yaffs_sync_fs(struct super_block *sb)
-#endif
-{
- unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
-
- T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
- (TSTR("yaffs_sync_fs%s\n"),
- request_checkpoint ? " checkpt" : ""));
-
- yaffs_do_sync_fs(sb, request_checkpoint);
-
- return 0;
-}
-
-#ifdef YAFFS_USE_OWN_IGET
-
-static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
-{
- struct inode *inode;
- yaffs_obj_t *obj;
- yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_iget for %lu\n"), ino));
-
- inode = iget_locked(sb, ino);
- if (!inode)
- return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW))
- return inode;
-
- /* NB This is called as a side effect of other functions, but
- * we had to release the lock to prevent deadlocks, so
- * need to lock again.
- */
-
- yaffs_gross_lock(dev);
-
- obj = yaffs_find_by_number(dev, inode->i_ino);
-
- yaffs_fill_inode_from_obj(inode, obj);
-
- yaffs_gross_unlock(dev);
-
- unlock_new_inode(inode);
- return inode;
-}
-
-#else
-
-static void yaffs_read_inode(struct inode *inode)
-{
- /* NB This is called as a side effect of other functions, but
- * we had to release the lock to prevent deadlocks, so
- * need to lock again.
- */
-
- yaffs_obj_t *obj;
- yaffs_dev_t *dev = yaffs_SuperToDevice(inode->i_sb);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
-
- if(current != yaffs_dev_to_lc(dev)->readdirProcess)
- yaffs_gross_lock(dev);
-
- obj = yaffs_find_by_number(dev, inode->i_ino);
-
- yaffs_fill_inode_from_obj(inode, obj);
-
- if(current != yaffs_dev_to_lc(dev)->readdirProcess)
- yaffs_gross_unlock(dev);
-}
-
-#endif
-
-static YLIST_HEAD(yaffs_context_list);
-struct semaphore yaffs_context_lock;
-
-static void yaffs_put_super(struct super_block *sb)
-{
- yaffs_dev_t *dev = yaffs_SuperToDevice(sb);
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n")));
-
- T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
- (TSTR("Shutting down yaffs background thread\n")));
- yaffs_bg_stop(dev);
- T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
- (TSTR("yaffs background thread shut down\n")));
-
- yaffs_gross_lock(dev);
-
- yaffs_flush_super(sb,1);
-
- if (yaffs_dev_to_lc(dev)->putSuperFunc)
- yaffs_dev_to_lc(dev)->putSuperFunc(sb);
-
-
- yaffs_deinitialise(dev);
-
- yaffs_gross_unlock(dev);
-
- down(&yaffs_context_lock);
- ylist_del_init(&(yaffs_dev_to_lc(dev)->contextList));
- up(&yaffs_context_lock);
-
- if (yaffs_dev_to_lc(dev)->spareBuffer) {
- YFREE(yaffs_dev_to_lc(dev)->spareBuffer);
- yaffs_dev_to_lc(dev)->spareBuffer = NULL;
- }
-
- kfree(dev);
-}
-
-
-static void yaffs_MTDPutSuper(struct super_block *sb)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_SuperToDevice(sb));
-
- if (mtd->sync)
- mtd->sync(mtd);
-
- put_mtd_device(mtd);
-}
-
-
-static void yaffs_touch_super(yaffs_dev_t *dev)
-{
- struct super_block *sb = yaffs_dev_to_lc(dev)->superBlock;
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_touch_super() sb = %p\n"), sb));
- if (sb)
- sb->s_dirt = 1;
-}
-
-typedef struct {
- int inband_tags;
- int skip_checkpoint_read;
- int skip_checkpoint_write;
- int no_cache;
- int tags_ecc_on;
- int tags_ecc_overridden;
- int lazy_loading_enabled;
- int lazy_loading_overridden;
- int empty_lost_and_found;
- int empty_lost_and_found_overridden;
-} yaffs_options;
-
-#define MAX_OPT_LEN 30
-static int yaffs_parse_options(yaffs_options *options, const char *options_str)
-{
- char cur_opt[MAX_OPT_LEN + 1];
- int p;
- int error = 0;
-
- /* Parse through the options which is a comma seperated list */
-
- while (options_str && *options_str && !error) {
- memset(cur_opt, 0, MAX_OPT_LEN + 1);
- p = 0;
-
- while(*options_str == ',')
- options_str++;
-
- while (*options_str && *options_str != ',') {
- if (p < MAX_OPT_LEN) {
- cur_opt[p] = *options_str;
- p++;
- }
- options_str++;
- }
-
- if (!strcmp(cur_opt, "inband-tags"))
- options->inband_tags = 1;
- else if (!strcmp(cur_opt, "tags-ecc-off")){
- options->tags_ecc_on = 0;
- options->tags_ecc_overridden=1;
- } else if (!strcmp(cur_opt, "tags-ecc-on")){
- options->tags_ecc_on = 1;
- options->tags_ecc_overridden = 1;
- } else if (!strcmp(cur_opt, "lazy-loading-off")){
- options->lazy_loading_enabled = 0;
- options->lazy_loading_overridden=1;
- } else if (!strcmp(cur_opt, "lazy-loading-on")){
- options->lazy_loading_enabled = 1;
- options->lazy_loading_overridden = 1;
- } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
- options->empty_lost_and_found = 0;
- options->empty_lost_and_found_overridden=1;
- } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
- options->empty_lost_and_found = 1;
- options->empty_lost_and_found_overridden=1;
- } else if (!strcmp(cur_opt, "no-cache"))
- options->no_cache = 1;
- else if (!strcmp(cur_opt, "no-checkpoint-read"))
- options->skip_checkpoint_read = 1;
- else if (!strcmp(cur_opt, "no-checkpoint-write"))
- options->skip_checkpoint_write = 1;
- else if (!strcmp(cur_opt, "no-checkpoint")) {
- options->skip_checkpoint_read = 1;
- options->skip_checkpoint_write = 1;
- } else {
- printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
- cur_opt);
- error = 1;
- }
- }
-
- return error;
-}
-
-static struct super_block *yaffs_internal_read_super(int yaffs_version,
- struct super_block *sb,
- void *data, int silent)
-{
- int nBlocks;
- struct inode *inode = NULL;
- struct dentry *root;
- yaffs_dev_t *dev = 0;
- char devname_buf[BDEVNAME_SIZE + 1];
- struct mtd_info *mtd;
- int err;
- char *data_str = (char *)data;
- struct yaffs_LinuxContext *context = NULL;
- yaffs_param_t *param;
-
- int read_only = 0;
-
- yaffs_options options;
-
- unsigned mount_id;
- int found;
- struct yaffs_LinuxContext *context_iterator;
- struct ylist_head *l;
-
- sb->s_magic = YAFFS_MAGIC;
- sb->s_op = &yaffs_super_ops;
- sb->s_flags |= MS_NOATIME;
-
- read_only =((sb->s_flags & MS_RDONLY) != 0);
-
-
-#ifdef YAFFS_COMPILE_EXPORTFS
- sb->s_export_op = &yaffs_export_ops;
-#endif
-
- if (!sb)
- printk(KERN_INFO "yaffs: sb is NULL\n");
- else if (!sb->s_dev)
- printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
- else if (!yaffs_devname(sb, devname_buf))
- printk(KERN_INFO "yaffs: devname is NULL\n");
- else
- printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
- sb->s_dev,
- yaffs_devname(sb, devname_buf),
- read_only ? "ro" : "rw");
-
- if (!data_str)
- data_str = "";
-
- printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
-
- memset(&options, 0, sizeof(options));
-
- if (yaffs_parse_options(&options, data_str)) {
- /* Option parsing failed */
- return NULL;
- }
-
-
- sb->s_blocksize = PAGE_CACHE_SIZE;
- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffs_version));
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_read_super: block size %d\n"),
- (int)(sb->s_blocksize)));
-
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"),
- MAJOR(sb->s_dev), MINOR(sb->s_dev),
- yaffs_devname(sb, devname_buf)));
-
- /* Check it's an mtd device..... */
- if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
- return NULL; /* This isn't an mtd device */
-
- /* Get the device */
- mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
- if (!mtd) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"),
- MINOR(sb->s_dev)));
- return NULL;
- }
- /* Check it's NAND */
- if (mtd->type != MTD_NANDFLASH) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: MTD device is not NAND it's type %d\n"),
- mtd->type));
- return NULL;
- }
-
- 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));
- 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));
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
- T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size));
-#else
- T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size));
-#endif
-
-#ifdef CONFIG_YAFFS_AUTO_YAFFS2
-
- if (yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: auto selecting yaffs2\n")));
- yaffs_version = 2;
- }
-
- /* Added NCB 26/5/2006 for completeness */
- if (yaffs_version == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: auto selecting yaffs1\n")));
- yaffs_version = 1;
- }
-
-#endif
-
- if (yaffs_version == 2) {
- /* Check for version 2 style functions */
- if (!mtd->erase ||
- !mtd->block_isbad ||
- !mtd->block_markbad ||
- !mtd->read ||
- !mtd->write ||
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
- !mtd->read_oob || !mtd->write_oob) {
-#else
- !mtd->write_ecc ||
- !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
-#endif
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: MTD device does not support required "
- "functions\n")));
- return NULL;
- }
-
- if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
- mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
- !options.inband_tags) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: MTD device does not have the "
- "right page sizes\n")));
- return NULL;
- }
- } else {
- /* Check for V1 style functions */
- if (!mtd->erase ||
- !mtd->read ||
- !mtd->write ||
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
- !mtd->read_oob || !mtd->write_oob) {
-#else
- !mtd->write_ecc ||
- !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
-#endif
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: MTD device does not support required "
- "functions\n")));
- return NULL;
- }
-
- if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
- mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: MTD device does not support have the "
- "right page sizes\n")));
- return NULL;
- }
- }
-
- /* OK, so if we got here, we have an MTD that's NAND and looks
- * like it has the right capabilities
- * Set the yaffs_dev_t up for mtd
- */
-
- if (!read_only && !(mtd->flags & MTD_WRITEABLE)){
- read_only = 1;
- printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only");
- sb->s_flags |= MS_RDONLY;
- }
-
- dev = kmalloc(sizeof(yaffs_dev_t), GFP_KERNEL);
- context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
-
- if(!dev || !context ){
- if(dev)
- kfree(dev);
- if(context)
- kfree(context);
- dev = NULL;
- context = NULL;
- }
-
- if (!dev) {
- /* Deep shit could not allocate device structure */
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs_read_super: Failed trying to allocate "
- "yaffs_dev_t. \n")));
- return NULL;
- }
- memset(dev, 0, sizeof(yaffs_dev_t));
- param = &(dev->param);
-
- memset(context,0,sizeof(struct yaffs_LinuxContext));
- dev->os_context = context;
- YINIT_LIST_HEAD(&(context->contextList));
- context->dev = dev;
- context->superBlock = sb;
-
- dev->read_only = read_only;
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
- sb->s_fs_info = dev;
-#else
- sb->u.generic_sbp = dev;
-#endif
-
- dev->driver_context = mtd;
- param->name = mtd->name;
-
- /* Set up the memory size parameters.... */
-
- nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
-
- param->start_block = 0;
- param->end_block = nBlocks - 1;
- param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
- param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
- param->n_reserved_blocks = 5;
- param->n_caches = (options.no_cache) ? 0 : 10;
- param->inband_tags = options.inband_tags;
-
-#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
- param->disable_lazy_load = 1;
-#endif
-#ifdef CONFIG_YAFFS_XATTR
- param->enable_xattr = 1;
-#endif
- if(options.lazy_loading_overridden)
- param->disable_lazy_load = !options.lazy_loading_enabled;
-
-#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
- param->no_tags_ecc = 1;
-#endif
-
-#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
-#else
- param->defered_dir_update = 1;
-#endif
-
- if(options.tags_ecc_overridden)
- param->no_tags_ecc = !options.tags_ecc_on;
-
-#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
- param->empty_lost_n_found = 1;
-#endif
-
-#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
- param->refresh_period = 0;
-#else
- param->refresh_period = 500;
-#endif
-
-#ifdef CONFIG_YAFFS__ALWAYS_CHECK_CHUNK_ERASED
- param->always_check_erased = 1;
-#endif
-
- if(options.empty_lost_and_found_overridden)
- param->empty_lost_n_found = options.empty_lost_and_found;
-
- /* ... and the functions. */
- if (yaffs_version == 2) {
- param->write_chunk_tags_fn =
- nandmtd2_WriteChunkWithTagsToNAND;
- param->read_chunk_tags_fn =
- nandmtd2_ReadChunkWithTagsFromNAND;
- param->bad_block_fn = nandmtd2_MarkNANDBlockBad;
- param->query_block_fn = nandmtd2_QueryNANDBlock;
- yaffs_dev_to_lc(dev)->spareBuffer = YMALLOC(mtd->oobsize);
- param->is_yaffs2 = 1;
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
- param->total_bytes_per_chunk = mtd->writesize;
- param->chunks_per_block = mtd->erasesize / mtd->writesize;
-#else
- param->total_bytes_per_chunk = mtd->oobblock;
- param->chunks_per_block = mtd->erasesize / mtd->oobblock;
-#endif
- nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
-
- param->start_block = 0;
- param->end_block = nBlocks - 1;
- } else {
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
- /* use the MTD interface in yaffs_mtdif1.c */
- param->write_chunk_tags_fn =
- nandmtd1_WriteChunkWithTagsToNAND;
- param->read_chunk_tags_fn =
- nandmtd1_ReadChunkWithTagsFromNAND;
- param->bad_block_fn = nandmtd1_MarkNANDBlockBad;
- param->query_block_fn = nandmtd1_QueryNANDBlock;
-#else
- param->write_chunk_fn = nandmtd_WriteChunkToNAND;
- param->read_chunk_fn = nandmtd_ReadChunkFromNAND;
-#endif
- param->is_yaffs2 = 0;
- }
- /* ... and common functions */
- param->erase_fn = nandmtd_EraseBlockInNAND;
- param->initialise_flash_fn = nandmtd_InitialiseNAND;
-
- yaffs_dev_to_lc(dev)->putSuperFunc = yaffs_MTDPutSuper;
-
- param->sb_dirty_fn = yaffs_touch_super;
- param->gc_control = yaffs_gc_control_callback;
-
- yaffs_dev_to_lc(dev)->superBlock= sb;
-
-
-#ifndef CONFIG_YAFFS_DOES_ECC
- param->use_nand_ecc = 1;
-#endif
-
-#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
- param->wide_tnodes_disabled = 1;
-#endif
-
- param->skip_checkpt_rd = options.skip_checkpoint_read;
- param->skip_checkpt_wr = options.skip_checkpoint_write;
-
- down(&yaffs_context_lock);
- /* Get a mount id */
- found = 0;
- for(mount_id=0; ! found; mount_id++){
- found = 1;
- ylist_for_each(l,&yaffs_context_list){
- context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList);
- if(context_iterator->mount_id == mount_id)
- found = 0;
- }
- }
- context->mount_id = mount_id;
-
- ylist_add_tail(&(yaffs_dev_to_lc(dev)->contextList), &yaffs_context_list);
- up(&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));
-
- yaffs_gross_lock(dev);
-
- err = yaffs_guts_initialise(dev);
-
- 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;
-
-
- /* Release lock before yaffs_get_inode() */
- yaffs_gross_unlock(dev);
-
- /* Create root inode */
- if (err == YAFFS_OK)
- inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
- yaffs_root(dev));
-
- if (!inode)
- return NULL;
-
- inode->i_op = &yaffs_dir_inode_operations;
- inode->i_fop = &yaffs_dir_operations;
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
-
- root = d_alloc_root(inode);
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));
-
- if (!root) {
- iput(inode);
- return NULL;
- }
- sb->s_root = root;
- sb->s_dirt = !dev->is_checkpointed;
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs_read_super: is_checkpointed %d\n"),
- dev->is_checkpointed));
-
- T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n")));
- return sb;
-}
-
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
- int silent)
-{
- return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
-}
-
-#if (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)
-{
-
- return get_sb_bdev(fs, flags, dev_name, data,
- yaffs_internal_read_super_mtd, mnt);
-}
-#else
-static struct super_block *yaffs_read_super(struct file_system_type *fs,
- int flags, const char *dev_name,
- void *data)
-{
-
- return get_sb_bdev(fs, flags, dev_name, data,
- yaffs_internal_read_super_mtd);
-}
-#endif
-
-static struct file_system_type yaffs_fs_type = {
- .owner = THIS_MODULE,
- .name = "yaffs",
- .get_sb = yaffs_read_super,
- .kill_sb = kill_block_super,
- .fs_flags = FS_REQUIRES_DEV,
-};
-#else
-static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
- int silent)
-{
- return yaffs_internal_read_super(1, sb, data, silent);
-}
-
-static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
- FS_REQUIRES_DEV);
-#endif
-
-
-#ifdef CONFIG_YAFFS_YAFFS2
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
-static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
- int silent)
-{
- return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
-}
-
-#if (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)
-{
- return get_sb_bdev(fs, flags, dev_name, data,
- yaffs2_internal_read_super_mtd, mnt);
-}
-#else
-static struct super_block *yaffs2_read_super(struct file_system_type *fs,
- int flags, const char *dev_name,
- void *data)
-{
-
- return get_sb_bdev(fs, flags, dev_name, data,
- yaffs2_internal_read_super_mtd);
-}
-#endif
-
-static struct file_system_type yaffs2_fs_type = {
- .owner = THIS_MODULE,
- .name = "yaffs2",
- .get_sb = yaffs2_read_super,
- .kill_sb = kill_block_super,
- .fs_flags = FS_REQUIRES_DEV,
-};
-#else
-static struct super_block *yaffs2_read_super(struct super_block *sb,
- void *data, int silent)
-{
- return yaffs_internal_read_super(2, sb, data, silent);
-}
-
-static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
- FS_REQUIRES_DEV);
-#endif
-
-#endif /* CONFIG_YAFFS_YAFFS2 */
-
-static struct proc_dir_entry *my_proc_entry;
-static struct proc_dir_entry *debug_proc_entry;
-
-static char *yaffs_dump_dev_part0(char *buf, yaffs_dev_t * dev)
-{
- buf += sprintf(buf, "start_block.......... %d\n", dev->param.start_block);
- buf += sprintf(buf, "end_block............ %d\n", dev->param.end_block);
- buf += sprintf(buf, "total_bytes_per_chunk %d\n", dev->param.total_bytes_per_chunk);
- buf += sprintf(buf, "use_nand_ecc......... %d\n", dev->param.use_nand_ecc);
- buf += sprintf(buf, "no_tags_ecc.......... %d\n", dev->param.no_tags_ecc);
- buf += sprintf(buf, "is_yaffs2............ %d\n", dev->param.is_yaffs2);
- buf += sprintf(buf, "inband_tags.......... %d\n", dev->param.inband_tags);
- buf += sprintf(buf, "empty_lost_n_found... %d\n", dev->param.empty_lost_n_found);
- buf += sprintf(buf, "disable_lazy_load.... %d\n", dev->param.disable_lazy_load);
- buf += sprintf(buf, "refresh_period....... %d\n", dev->param.refresh_period);
- buf += sprintf(buf, "n_caches............. %d\n", dev->param.n_caches);
- buf += sprintf(buf, "n_reserved_blocks.... %d\n", dev->param.n_reserved_blocks);
- buf += sprintf(buf, "always_check_erased.. %d\n", dev->param.always_check_erased);
-
- buf += sprintf(buf, "\n");
-
- return buf;
-}
-
-
-static char *yaffs_dump_dev_part1(char *buf, yaffs_dev_t * dev)
-{
- buf += sprintf(buf, "data_bytes_per_chunk. %d\n", dev->data_bytes_per_chunk);
- buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
- buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
- buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
- buf += sprintf(buf, "blocks_in_checkpt.... %d\n", dev->blocks_in_checkpt);
- buf += sprintf(buf, "\n");
- buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
- buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
- buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
- buf += sprintf(buf, "\n");
- buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
- buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
- buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
- buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
- buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
- buf += sprintf(buf, "passive_gc_count..... %u\n", dev->passive_gc_count);
- buf += sprintf(buf, "oldest_dirty_gc_count %u\n", dev->oldest_dirty_gc_count);
- buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
- buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
- buf += sprintf(buf, "n_retired_writes..... %u\n", dev->n_retired_writes);
- buf += sprintf(buf, "nRetireBlocks........ %u\n", dev->n_retired_blocks);
- buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
- buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
- buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n", dev->n_tags_ecc_fixed);
- buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n", dev->n_tags_ecc_unfixed);
- buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
- buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
- buf += sprintf(buf, "n_unlinked_files..... %u\n", dev->n_unlinked_files);
- buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
- buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
-
- return buf;
-}
-
-static int yaffs_proc_read(char *page,
- char **start,
- off_t offset, int count, int *eof, void *data)
-{
- struct ylist_head *item;
- char *buf = page;
- int step = offset;
- int n = 0;
-
- /* Get proc_file_read() to step 'offset' by one on each sucessive call.
- * We use 'offset' (*ppos) to indicate where we are in dev_list.
- * This also assumes the user has posted a read buffer large
- * enough to hold the complete output; but that's life in /proc.
- */
-
- *(int *)start = 1;
-
- /* Print header first */
- if (step == 0)
- buf += sprintf(buf, "Multi-version YAFFS built:" __DATE__ " " __TIME__"\n");
- else if (step == 1)
- buf += sprintf(buf,"\n");
- else {
- step-=2;
-
- down(&yaffs_context_lock);
-
- /* Locate and print the Nth entry. Order N-squared but N is small. */
- ylist_for_each(item, &yaffs_context_list) {
- struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
- yaffs_dev_t *dev = dc->dev;
-
- if (n < (step & ~1)) {
- n+=2;
- continue;
- }
- if((step & 1)==0){
- buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->param.name);
- buf = yaffs_dump_dev_part0(buf, dev);
- } else
- buf = yaffs_dump_dev_part1(buf, dev);
-
- break;
- }
- up(&yaffs_context_lock);
- }
-
- return buf - page < count ? buf - page : count;
-}
-
-static int yaffs_stats_proc_read(char *page,
- char **start,
- off_t offset, int count, int *eof, void *data)
-{
- struct ylist_head *item;
- char *buf = page;
- int n = 0;
-
- down(&yaffs_context_lock);
-
- /* Locate and print the Nth entry. Order N-squared but N is small. */
- ylist_for_each(item, &yaffs_context_list) {
- struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
- yaffs_dev_t *dev = dc->dev;
-
- 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,
- dev->n_obj, dev->n_tnodes);
- }
- up(&yaffs_context_lock);
-
-
- return buf - page < count ? buf - page : count;
-}
-
-/**
- * Set the verbosity of the warnings and error messages.
- *
- * Note that the names can only be a..z or _ with the current code.
- */
-
-static struct {
- char *mask_name;
- unsigned mask_bitfield;
-} mask_flags[] = {
- {"allocate", YAFFS_TRACE_ALLOCATE},
- {"always", YAFFS_TRACE_ALWAYS},
- {"background", YAFFS_TRACE_BACKGROUND},
- {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
- {"buffers", YAFFS_TRACE_BUFFERS},
- {"bug", YAFFS_TRACE_BUG},
- {"checkpt", YAFFS_TRACE_CHECKPOINT},
- {"deletion", YAFFS_TRACE_DELETION},
- {"erase", YAFFS_TRACE_ERASE},
- {"error", YAFFS_TRACE_ERROR},
- {"gc_detail", YAFFS_TRACE_GC_DETAIL},
- {"gc", YAFFS_TRACE_GC},
- {"lock", YAFFS_TRACE_LOCK},
- {"mtd", YAFFS_TRACE_MTD},
- {"nandaccess", YAFFS_TRACE_NANDACCESS},
- {"os", YAFFS_TRACE_OS},
- {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
- {"scan", YAFFS_TRACE_SCAN},
- {"tracing", YAFFS_TRACE_TRACING},
- {"sync", YAFFS_TRACE_SYNC},
- {"write", YAFFS_TRACE_WRITE},
-
- {"verify", YAFFS_TRACE_VERIFY},
- {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
- {"verify_full", YAFFS_TRACE_VERIFY_FULL},
- {"verify_all", YAFFS_TRACE_VERIFY_ALL},
-
- {"all", 0xffffffff},
- {"none", 0},
- {NULL, 0},
-};
-
-#define MAX_MASK_NAME_LENGTH 40
-static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
- unsigned long count, void *data)
-{
- unsigned rg = 0, mask_bitfield;
- char *end;
- char *mask_name;
- const char *x;
- char substring[MAX_MASK_NAME_LENGTH + 1];
- int i;
- int done = 0;
- int add, len = 0;
- int pos = 0;
-
- rg = yaffs_trace_mask;
-
- while (!done && (pos < count)) {
- done = 1;
- while ((pos < count) && isspace(buf[pos]))
- pos++;
-
- switch (buf[pos]) {
- case '+':
- case '-':
- case '=':
- add = buf[pos];
- pos++;
- break;
-
- default:
- add = ' ';
- break;
- }
- mask_name = NULL;
-
- mask_bitfield = simple_strtoul(buf + pos, &end, 0);
-
- if (end > buf + pos) {
- mask_name = "numeral";
- len = end - (buf + pos);
- pos += len;
- done = 0;
- } else {
- for (x = buf + pos, i = 0;
- (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
- i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
- substring[i] = *x;
- substring[i] = '\0';
-
- for (i = 0; mask_flags[i].mask_name != NULL; i++) {
- if (strcmp(substring, mask_flags[i].mask_name) == 0) {
- mask_name = mask_flags[i].mask_name;
- mask_bitfield = mask_flags[i].mask_bitfield;
- done = 0;
- break;
- }
- }
- }
-
- if (mask_name != NULL) {
- done = 0;
- switch (add) {
- case '-':
- rg &= ~mask_bitfield;
- break;
- case '+':
- rg |= mask_bitfield;
- break;
- case '=':
- rg = mask_bitfield;
- break;
- default:
- rg |= mask_bitfield;
- break;
- }
- }
- }
-
- yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS;
-
- printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
-
- if (rg & YAFFS_TRACE_ALWAYS) {
- for (i = 0; mask_flags[i].mask_name != NULL; i++) {
- char flag;
- flag = ((rg & mask_flags[i].mask_bitfield) ==
- mask_flags[i].mask_bitfield) ? '+' : '-';
- printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
- }
- }
-
- return count;
-}
-
-
-static int yaffs_proc_write(struct file *file, const char *buf,
- unsigned long count, void *data)
-{
- return yaffs_proc_write_trace_options(file, buf, count, data);
-}
-
-/* Stuff to handle installation of file systems */
-struct file_system_to_install {
- struct file_system_type *fst;
- int installed;
-};
-
-static struct file_system_to_install fs_to_install[] = {
- {&yaffs_fs_type, 0},
- {&yaffs2_fs_type, 0},
- {NULL, 0}
-};
-
-static int __init init_yaffs_fs(void)
-{
- int error = 0;
- struct file_system_to_install *fsinst;
-
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n")));
-
-#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
- T(YAFFS_TRACE_ALWAYS,
- (TSTR(" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n")));
-#endif
-
-
-
-
- init_MUTEX(&yaffs_context_lock);
-
- /* Install the proc_fs entries */
- my_proc_entry = create_proc_entry("yaffs",
- S_IRUGO | S_IFREG,
- YPROC_ROOT);
-
- if (my_proc_entry) {
- my_proc_entry->write_proc = yaffs_proc_write;
- my_proc_entry->read_proc = yaffs_proc_read;
- my_proc_entry->data = NULL;
- } else
- return -ENOMEM;
-
- debug_proc_entry = create_proc_entry("yaffs_stats",
- S_IRUGO | S_IFREG,
- YPROC_ROOT);
-
- if (debug_proc_entry) {
- debug_proc_entry->write_proc = NULL;
- debug_proc_entry->read_proc = yaffs_stats_proc_read;
- debug_proc_entry->data = NULL;
- } else
- return -ENOMEM;
-
- /* Now add the file system entries */
-
- fsinst = fs_to_install;
-
- while (fsinst->fst && !error) {
- error = register_filesystem(fsinst->fst);
- if (!error)
- fsinst->installed = 1;
- fsinst++;
- }
-
- /* Any errors? uninstall */
- if (error) {
- fsinst = fs_to_install;
-
- while (fsinst->fst) {
- if (fsinst->installed) {
- unregister_filesystem(fsinst->fst);
- fsinst->installed = 0;
- }
- fsinst++;
- }
- }
-
- return error;
-}
-
-static void __exit exit_yaffs_fs(void)
-{
-
- struct file_system_to_install *fsinst;
-
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
-
- remove_proc_entry("yaffs", YPROC_ROOT);
- remove_proc_entry("yaffs_stats", YPROC_ROOT);
-
- fsinst = fs_to_install;
-
- while (fsinst->fst) {
- if (fsinst->installed) {
- unregister_filesystem(fsinst->fst);
- fsinst->installed = 0;
- }
- fsinst++;
- }
-}
-
-module_init(init_yaffs_fs)
-module_exit(exit_yaffs_fs)
-
-MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
-MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
-MODULE_LICENSE("GPL");
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+
#include "yaffs_yaffs1.h"
#include "yportenv.h"
#include "yaffs_trace.h"
#include "yaffs_bitmap.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_nand.h"
+#include "yaffs_attribs.h"
-
-int yaffs1_scan(yaffs_dev_t *dev)
+int yaffs1_scan(struct yaffs_dev *dev)
{
- yaffs_ext_tags tags;
+ struct yaffs_ext_tags tags;
int blk;
- int blockIterator;
- int startIterator;
- int endIterator;
int result;
-
int chunk;
int c;
int deleted;
- yaffs_block_state_t state;
- yaffs_obj_t *hard_list = NULL;
- yaffs_block_info_t *bi;
- __u32 seq_number;
- yaffs_obj_header *oh;
- yaffs_obj_t *in;
- yaffs_obj_t *parent;
-
+ enum yaffs_block_state state;
+ LIST_HEAD(hard_list);
+ struct yaffs_block_info *bi;
+ u32 seq_number;
+ struct yaffs_obj_hdr *oh;
+ struct yaffs_obj *in;
+ struct yaffs_obj *parent;
int alloc_failed = 0;
+ struct yaffs_shadow_fixer *shadow_fixers = NULL;
+ u8 *chunk_data;
- struct yaffs_shadow_fixer_s *shadowFixerList = NULL;
-
-
- __u8 *chunkData;
-
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "yaffs1_scan starts intstartblk %d intendblk %d...",
+ dev->internal_start_block, dev->internal_end_block);
-
- 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__);
+ chunk_data = yaffs_get_temp_buffer(dev);
dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
/* Scan all the blocks to determine their state */
bi = dev->block_info;
- for (blk = dev->internal_start_block; blk <= dev->internal_end_block; blk++) {
+ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
+ blk++) {
yaffs_clear_chunk_bits(dev, blk);
bi->pages_in_use = 0;
bi->soft_del_pages = 0;
if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
- T(YAFFS_TRACE_SCAN_DEBUG,
- (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
- state, seq_number));
+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
+ "Block scanning block %d state %d seq %d",
+ blk, state, seq_number);
if (state == YAFFS_BLOCK_STATE_DEAD) {
- T(YAFFS_TRACE_BAD_BLOCKS,
- (TSTR("block %d is bad" TENDSTR), blk));
+ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
+ "block %d is bad", blk);
} else if (state == YAFFS_BLOCK_STATE_EMPTY) {
- T(YAFFS_TRACE_SCAN_DEBUG,
- (TSTR("Block empty " TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
dev->n_erased_blocks++;
dev->n_free_chunks += dev->param.chunks_per_block;
}
bi++;
}
- startIterator = dev->internal_start_block;
- endIterator = dev->internal_end_block;
-
/* For each block.... */
- for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
- blockIterator++) {
-
- YYIELD();
+ for (blk = dev->internal_start_block;
+ !alloc_failed && blk <= dev->internal_end_block; blk++) {
- YYIELD();
-
- blk = blockIterator;
+ cond_resched();
bi = yaffs_get_block_info(dev, blk);
state = bi->block_state;
deleted = 0;
- /* For each chunk in each block that needs scanning....*/
- for (c = 0; !alloc_failed && c < dev->param.chunks_per_block &&
- state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
+ /* For each chunk in each block that needs scanning.... */
+ for (c = 0;
+ !alloc_failed && c < dev->param.chunks_per_block &&
+ state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
/* Read the tags and decide what to do */
chunk = blk * dev->param.chunks_per_block + c;
result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
- &tags);
+ &tags);
/* 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...
* A deleted chunk
*/
deleted++;
dev->n_free_chunks++;
- /*T((" %d %d deleted\n",blk,c)); */
} else if (!tags.chunk_used) {
/* An unassigned chunk in the block
* This means that either the block is empty or
*/
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;
dev->n_erased_blocks++;
} else {
- /* this is the block being allocated from */
- T(YAFFS_TRACE_SCAN,
- (TSTR
- (" Allocating from %d %d" TENDSTR),
- blk, c));
+ /* this is the block being allocated */
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ " Allocating from %d %d",
+ blk, c);
state = YAFFS_BLOCK_STATE_ALLOCATING;
dev->alloc_block = blk;
dev->alloc_page = c;
dev->alloc_block_finder = blk;
- /* Set block finder here to encourage the allocator to go forth from here. */
}
- dev->n_free_chunks += (dev->param.chunks_per_block - c);
+ dev->n_free_chunks +=
+ (dev->param.chunks_per_block - c);
} else if (tags.chunk_id > 0) {
/* chunk_id > 0 so it is a data chunk... */
unsigned int endpos;
bi->pages_in_use++;
in = yaffs_find_or_create_by_number(dev,
- tags.
- obj_id,
- YAFFS_OBJECT_TYPE_FILE);
- /* PutChunkIntoFile checks for a clash (two data chunks with
- * the same chunk_id).
+ tags.obj_id,
+ YAFFS_OBJECT_TYPE_FILE);
+ /* PutChunkIntoFile checks for a clash
+ * (two data chunks with the same chunk_id).
*/
if (!in)
alloc_failed = 1;
if (in) {
- if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, 1))
+ if (!yaffs_put_chunk_in_file
+ (in, tags.chunk_id, chunk, 1))
alloc_failed = 1;
}
endpos =
- (tags.chunk_id - 1) * dev->data_bytes_per_chunk +
+ (tags.chunk_id - 1) *
+ dev->data_bytes_per_chunk +
tags.n_bytes;
if (in &&
- in->variant_type == YAFFS_OBJECT_TYPE_FILE
- && in->variant.file_variant.scanned_size <
- endpos) {
- in->variant.file_variant.
- scanned_size = endpos;
+ in->variant_type ==
+ YAFFS_OBJECT_TYPE_FILE &&
+ in->variant.file_variant.scanned_size <
+ endpos) {
+ in->variant.file_variant.scanned_size =
+ endpos;
if (!dev->param.use_header_file_size) {
- in->variant.file_variant.
- file_size =
- in->variant.file_variant.
- scanned_size;
+ in->variant.
+ file_variant.file_size =
+ in->variant.
+ file_variant.scanned_size;
}
}
- /* T((" %d %d data %d %d\n",blk,c,tags.obj_id,tags.chunk_id)); */
} else {
/* chunk_id == 0, so it is an ObjectHeader.
- * Thus, we read in the object header and make the object
+ * Make the object
*/
yaffs_set_chunk_bit(dev, blk, c);
bi->pages_in_use++;
result = yaffs_rd_chunk_tags_nand(dev, chunk,
- chunkData,
- NULL);
+ chunk_data,
+ NULL);
- oh = (yaffs_obj_header *) chunkData;
+ oh = (struct yaffs_obj_hdr *)chunk_data;
- in = yaffs_find_by_number(dev,
- tags.obj_id);
+ in = yaffs_find_by_number(dev, tags.obj_id);
if (in && in->variant_type != oh->type) {
/* This should not happen, but somehow
- * Wev'e ended up with an obj_id that has been reused but not yet
- * deleted, and worse still it has changed type. Delete the old object.
+ * Wev'e ended up with an obj_id that
+ * has been reused but not yet deleted,
+ * and worse still it has changed type.
+ * Delete the old object.
*/
yaffs_del_obj(in);
-
- in = 0;
+ in = NULL;
}
in = yaffs_find_or_create_by_number(dev,
- tags.
- obj_id,
- oh->type);
+ tags.obj_id,
+ oh->type);
if (!in)
alloc_failed = 1;
if (in && oh->shadows_obj > 0) {
- struct yaffs_shadow_fixer_s *fixer;
- fixer = YMALLOC(sizeof(struct yaffs_shadow_fixer_s));
+ struct yaffs_shadow_fixer *fixer;
+ fixer =
+ kmalloc(sizeof
+ (struct yaffs_shadow_fixer),
+ GFP_NOFS);
if (fixer) {
- fixer->next = shadowFixerList;
- shadowFixerList = fixer;
+ fixer->next = shadow_fixers;
+ shadow_fixers = fixer;
fixer->obj_id = tags.obj_id;
- fixer->shadowed_id = oh->shadows_obj;
- T(YAFFS_TRACE_SCAN,
- (TSTR
- (" Shadow fixer: %d shadows %d" TENDSTR),
- fixer->obj_id, fixer->shadowed_id));
+ fixer->shadowed_id =
+ oh->shadows_obj;
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ " Shadow fixer: %d shadows %d",
+ fixer->obj_id,
+ fixer->shadowed_id);
}
}
if (in && in->valid) {
- /* We have already filled this one. We have a duplicate and need to resolve it. */
-
- unsigned existingSerial = in->serial;
- unsigned newSerial = tags.serial_number;
-
- if (((existingSerial + 1) & 3) == newSerial) {
- /* Use new one - destroy the exisiting one */
+ /* We have already filled this one.
+ * We have a duplicate and need to
+ * resolve it. */
+
+ unsigned existing_serial = in->serial;
+ unsigned new_serial =
+ tags.serial_number;
+
+ if (((existing_serial + 1) & 3) ==
+ new_serial) {
+ /* Use new one - destroy the
+ * exisiting one */
yaffs_chunk_del(dev,
- in->hdr_chunk,
- 1, __LINE__);
+ in->hdr_chunk,
+ 1, __LINE__);
in->valid = 0;
} else {
- /* Use existing - destroy this one. */
+ /* Use existing - destroy
+ * this one. */
yaffs_chunk_del(dev, chunk, 1,
- __LINE__);
+ __LINE__);
}
}
if (in && !in->valid &&
(tags.obj_id == YAFFS_OBJECTID_ROOT ||
- tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
- /* We only load some info, don't fiddle with directory structure */
+ tags.obj_id ==
+ YAFFS_OBJECTID_LOSTNFOUND)) {
+ /* We only load some info, don't fiddle
+ * with directory structure */
in->valid = 1;
in->variant_type = oh->type;
in->yst_mode = oh->yst_mode;
-#ifdef CONFIG_YAFFS_WINCE
- in->win_atime[0] = oh->win_atime[0];
- in->win_ctime[0] = oh->win_ctime[0];
- in->win_mtime[0] = oh->win_mtime[0];
- in->win_atime[1] = oh->win_atime[1];
- in->win_ctime[1] = oh->win_ctime[1];
- in->win_mtime[1] = oh->win_mtime[1];
-#else
- in->yst_uid = oh->yst_uid;
- in->yst_gid = oh->yst_gid;
- in->yst_atime = oh->yst_atime;
- in->yst_mtime = oh->yst_mtime;
- in->yst_ctime = oh->yst_ctime;
- in->yst_rdev = oh->yst_rdev;
-#endif
+ yaffs_load_attribs(in, oh);
in->hdr_chunk = chunk;
in->serial = tags.serial_number;
in->variant_type = oh->type;
in->yst_mode = oh->yst_mode;
-#ifdef CONFIG_YAFFS_WINCE
- in->win_atime[0] = oh->win_atime[0];
- in->win_ctime[0] = oh->win_ctime[0];
- in->win_mtime[0] = oh->win_mtime[0];
- in->win_atime[1] = oh->win_atime[1];
- in->win_ctime[1] = oh->win_ctime[1];
- in->win_mtime[1] = oh->win_mtime[1];
-#else
- in->yst_uid = oh->yst_uid;
- in->yst_gid = oh->yst_gid;
- in->yst_atime = oh->yst_atime;
- in->yst_mtime = oh->yst_mtime;
- in->yst_ctime = oh->yst_ctime;
- in->yst_rdev = oh->yst_rdev;
-#endif
+ yaffs_load_attribs(in, oh);
in->hdr_chunk = chunk;
in->serial = tags.serial_number;
YAFFS_OBJECT_TYPE_UNKNOWN) {
/* Set up as a directory */
parent->variant_type =
- YAFFS_OBJECT_TYPE_DIRECTORY;
- YINIT_LIST_HEAD(&parent->variant.
- dir_variant.
- children);
- } else if (!parent || parent->variant_type !=
- YAFFS_OBJECT_TYPE_DIRECTORY) {
- /* Hoosterman, another problem....
- * We're trying to use a non-directory as a directory
+ YAFFS_OBJECT_TYPE_DIRECTORY;
+ INIT_LIST_HEAD(&parent->
+ variant.dir_variant.
+ children);
+ } else if (!parent ||
+ parent->variant_type !=
+ YAFFS_OBJECT_TYPE_DIRECTORY) {
+ /* Hoosterman, a problem....
+ * We're trying to use a
+ * non-directory as a directory
*/
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
- TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
+ );
parent = dev->lost_n_found;
}
yaffs_add_obj_to_dir(parent, in);
- if (0 && (parent == dev->del_dir ||
- parent == dev->unlinked_dir)) {
- in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
- dev->n_deleted_files++;
- }
- /* Note re hardlinks.
- * Since we might scan a hardlink before its equivalent object is scanned
- * we put them all in a list.
- * After scanning is complete, we should have all the objects, so we run through this
- * list and fix up all the chains.
- */
-
switch (in->variant_type) {
case YAFFS_OBJECT_TYPE_UNKNOWN:
/* Todo got a problem */
break;
case YAFFS_OBJECT_TYPE_FILE:
- if (dev->param.use_header_file_size)
-
- in->variant.file_variant.
- file_size =
- oh->file_size;
-
+ if (dev->param.
+ use_header_file_size)
+ in->variant.
+ file_variant.file_size
+ = yaffs_oh_to_size(oh);
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
- in->variant.hardlink_variant.
- equiv_id =
- oh->equiv_id;
- in->hard_links.next =
- (struct ylist_head *)
- hard_list;
- hard_list = in;
+ in->variant.
+ hardlink_variant.equiv_id =
+ oh->equiv_id;
+ list_add(&in->hard_links,
+ &hard_list);
break;
case YAFFS_OBJECT_TYPE_DIRECTORY:
/* Do nothing */
/* Do nothing */
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
- in->variant.symlink_variant.alias =
+ in->variant.symlink_variant.
+ alias =
yaffs_clone_str(oh->alias);
- if (!in->variant.symlink_variant.alias)
+ if (!in->variant.
+ symlink_variant.alias)
alloc_failed = 1;
break;
}
-
}
}
}
- if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
- /* If we got this far while scanning, then the block is fully allocated.*/
+ if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+ /* If we got this far while scanning,
+ * then the block is fully allocated. */
state = YAFFS_BLOCK_STATE_FULL;
}
if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
- /* If the block was partially allocated then treat it as fully allocated.*/
+ /* If the block was partially allocated then
+ * treat it as fully allocated. */
state = YAFFS_BLOCK_STATE_FULL;
dev->alloc_block = -1;
}
/* Now let's see if it was dirty */
if (bi->pages_in_use == 0 &&
!bi->has_shrink_hdr &&
- bi->block_state == YAFFS_BLOCK_STATE_FULL) {
+ bi->block_state == YAFFS_BLOCK_STATE_FULL)
yaffs_block_became_dirty(dev, blk);
- }
-
}
-
/* Ok, we've done all the scanning.
* Fix up the hard link chains.
- * We should now have scanned all the objects, now it's time to add these
- * hardlinks.
+ * We should now have scanned all the objects, now it's time to add
+ * 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;
- yaffs_obj_t *obj;
-
- while (shadowFixerList) {
- fixer = shadowFixerList;
- shadowFixerList = fixer->next;
- /* Complete the rename transaction by deleting the shadowed object
- * then setting the object header to unshadowed.
+ struct yaffs_shadow_fixer *fixer;
+ struct yaffs_obj *obj;
+
+ while (shadow_fixers) {
+ fixer = shadow_fixers;
+ shadow_fixers = fixer->next;
+ /* Complete the rename transaction by deleting the
+ * shadowed object then setting the object header
+ to unshadowed.
*/
obj = yaffs_find_by_number(dev, fixer->shadowed_id);
if (obj)
if (obj)
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)
return YAFFS_FAIL;
- T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_scan ends" TENDSTR)));
-
+ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
return YAFFS_OK;
}
-
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
#define __YAFFS_YAFFS1_H__
#include "yaffs_guts.h"
-int yaffs1_scan(yaffs_dev_t *dev);
+int yaffs1_scan(struct yaffs_dev *dev);
#endif
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
* published by the Free Software Foundation.
*/
-
#include "yaffs_guts.h"
#include "yaffs_trace.h"
#include "yaffs_yaffs2.h"
#include "yaffs_checkptrw.h"
#include "yaffs_bitmap.h"
-#include "yaffs_qsort.h"
#include "yaffs_nand.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_verify.h"
+#include "yaffs_attribs.h"
+#include "yaffs_summary.h"
/*
* Checkpoints are really no benefit on very small partitions.
* the partition is at least this big.
*/
#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
-
#define YAFFS_SMALL_HOLE_THRESHOLD 4
-
/*
* Oldest Dirty Sequence Number handling.
*/
-
+
/* yaffs_calc_oldest_dirty_seq()
* yaffs2_find_oldest_dirty_seq()
* Calculate the oldest dirty sequence number if we don't know it.
*/
-void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev)
+void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
{
int i;
unsigned seq;
unsigned block_no = 0;
- yaffs_block_info_t *b;
+ struct yaffs_block_info *b;
- if(!dev->param.is_yaffs2)
+ if (!dev->param.is_yaffs2)
return;
/* Find the oldest dirty sequence number. */
b = dev->block_info;
for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
- (b->pages_in_use - b->soft_del_pages) < dev->param.chunks_per_block &&
- b->seq_number < seq) {
+ (b->pages_in_use - b->soft_del_pages) <
+ dev->param.chunks_per_block &&
+ b->seq_number < seq) {
seq = b->seq_number;
block_no = i;
}
b++;
}
- if(block_no){
+ if (block_no) {
dev->oldest_dirty_seq = seq;
dev->oldest_dirty_block = block_no;
}
-
}
-
-void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev)
+void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
{
- if(!dev->param.is_yaffs2)
+ if (!dev->param.is_yaffs2)
return;
- if(!dev->oldest_dirty_seq)
+ if (!dev->oldest_dirty_seq)
yaffs_calc_oldest_dirty_seq(dev);
}
/*
* yaffs_clear_oldest_dirty_seq()
* Called when a block is erased or marked bad. (ie. when its seq_number
- * becomes invalid). If the value matches the oldest then we clear
+ * becomes invalid). If the value matches the oldest then we clear
* dev->oldest_dirty_seq to force its recomputation.
*/
-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,
+ struct yaffs_block_info *bi)
{
- if(!dev->param.is_yaffs2)
+ if (!dev->param.is_yaffs2)
return;
- if(!bi || bi->seq_number == dev->oldest_dirty_seq){
+ if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
dev->oldest_dirty_seq = 0;
dev->oldest_dirty_block = 0;
}
* Update the oldest dirty sequence number whenever we dirty a block.
* Only do this if the oldest_dirty_seq is actually being tracked.
*/
-void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi)
+void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
+ struct yaffs_block_info *bi)
{
- if(!dev->param.is_yaffs2)
+ if (!dev->param.is_yaffs2)
return;
- if(dev->oldest_dirty_seq){
- if(dev->oldest_dirty_seq > bi->seq_number){
+ if (dev->oldest_dirty_seq) {
+ if (dev->oldest_dirty_seq > bi->seq_number) {
dev->oldest_dirty_seq = bi->seq_number;
dev->oldest_dirty_block = block_no;
}
}
}
-int yaffs_block_ok_for_gc(yaffs_dev_t *dev,
- yaffs_block_info_t *bi)
+int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
{
if (!dev->param.is_yaffs2)
yaffs2_find_oldest_dirty_seq(dev);
- /* Can't do gc of this block if there are any blocks older than this one that have
- * discarded pages.
+ /* Can't do gc of this block if there are any blocks older than this
+ * one that have discarded pages.
*/
return (bi->seq_number <= dev->oldest_dirty_seq);
}
* periodically finds the oldest full block by sequence number for refreshing.
* Only for yaffs2.
*/
-__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev)
+u32 yaffs2_find_refresh_block(struct yaffs_dev *dev)
{
- __u32 b ;
-
- __u32 oldest = 0;
- __u32 oldestSequence = 0;
-
- yaffs_block_info_t *bi;
+ u32 b;
+ u32 oldest = 0;
+ u32 oldest_seq = 0;
+ struct yaffs_block_info *bi;
- if(!dev->param.is_yaffs2)
+ if (!dev->param.is_yaffs2)
return oldest;
/*
* If refresh period < 10 then refreshing is disabled.
*/
- if(dev->param.refresh_period < 10)
- return oldest;
+ if (dev->param.refresh_period < 10)
+ return oldest;
- /*
- * Fix broken values.
- */
- if(dev->refresh_skip > dev->param.refresh_period)
- dev->refresh_skip = dev->param.refresh_period;
+ /*
+ * Fix broken values.
+ */
+ if (dev->refresh_skip > dev->param.refresh_period)
+ dev->refresh_skip = dev->param.refresh_period;
- if(dev->refresh_skip > 0)
- return oldest;
+ if (dev->refresh_skip > 0)
+ return oldest;
/*
* Refresh skip is now zero.
dev->refresh_skip = dev->param.refresh_period;
dev->refresh_count++;
bi = dev->block_info;
- for (b = dev->internal_start_block; b <=dev->internal_end_block; b++){
+ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
- if (bi->block_state == YAFFS_BLOCK_STATE_FULL){
+ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
- if(oldest < 1 ||
- bi->seq_number < oldestSequence){
- oldest = b;
- oldestSequence = bi->seq_number;
- }
+ if (oldest < 1 || bi->seq_number < oldest_seq) {
+ oldest = b;
+ oldest_seq = bi->seq_number;
+ }
}
bi++;
}
if (oldest > 0) {
- T(YAFFS_TRACE_GC,
- (TSTR("GC refresh count %d selected block %d with seq_number %d" TENDSTR),
- dev->refresh_count, oldest, oldestSequence));
+ yaffs_trace(YAFFS_TRACE_GC,
+ "GC refresh count %d selected block %d with seq_number %d",
+ dev->refresh_count, oldest, oldest_seq);
}
return oldest;
}
-int yaffs2_checkpt_required(yaffs_dev_t *dev)
+int yaffs2_checkpt_required(struct yaffs_dev *dev)
{
int nblocks;
-
- if(!dev->param.is_yaffs2)
+
+ if (!dev->param.is_yaffs2)
return 0;
-
- nblocks = dev->internal_end_block - dev->internal_start_block + 1 ;
- return !dev->param.skip_checkpt_wr &&
- !dev->read_only &&
- (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
+ nblocks = dev->internal_end_block - dev->internal_start_block + 1;
+
+ return !dev->param.skip_checkpt_wr &&
+ !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
}
-int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev)
+int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
{
int retval;
+ int n_bytes = 0;
+ int n_blocks;
+ int dev_blocks;
- if(!dev->param.is_yaffs2)
+ if (!dev->param.is_yaffs2)
return 0;
- if (!dev->checkpoint_blocks_required &&
- yaffs2_checkpt_required(dev)){
+ if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
/* Not a valid value so recalculate */
- int n_bytes = 0;
- int nBlocks;
- int devBlocks = (dev->param.end_block - dev->param.start_block + 1);
-
- n_bytes += sizeof(yaffs_checkpt_validty_t);
- n_bytes += sizeof(yaffs_checkpt_dev_t);
- n_bytes += devBlocks * sizeof(yaffs_block_info_t);
- n_bytes += devBlocks * dev->chunk_bit_stride;
- n_bytes += (sizeof(yaffs_checkpt_obj_t) + sizeof(__u32)) * (dev->n_obj);
- n_bytes += (dev->tnode_size + sizeof(__u32)) * (dev->n_tnodes);
- n_bytes += sizeof(yaffs_checkpt_validty_t);
- n_bytes += sizeof(__u32); /* checksum*/
-
- /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
-
- nBlocks = (n_bytes/(dev->data_bytes_per_chunk * dev->param.chunks_per_block)) + 3;
-
- dev->checkpoint_blocks_required = nBlocks;
+ dev_blocks = dev->param.end_block - dev->param.start_block + 1;
+ n_bytes += sizeof(struct yaffs_checkpt_validity);
+ n_bytes += sizeof(struct yaffs_checkpt_dev);
+ n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
+ n_bytes += dev_blocks * dev->chunk_bit_stride;
+ n_bytes +=
+ (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) *
+ dev->n_obj;
+ n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes;
+ n_bytes += sizeof(struct yaffs_checkpt_validity);
+ n_bytes += sizeof(u32); /* checksum */
+
+ /* Round up and add 2 blocks to allow for some bad blocks,
+ * so add 3 */
+
+ n_blocks =
+ (n_bytes /
+ (dev->data_bytes_per_chunk *
+ dev->param.chunks_per_block)) + 3;
+
+ dev->checkpoint_blocks_required = n_blocks;
}
retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
- if(retval < 0)
+ if (retval < 0)
retval = 0;
return retval;
}
/*--------------------- Checkpointing --------------------*/
-
-static int yaffs2_wr_checkpt_validity_marker(yaffs_dev_t *dev, int head)
+static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
{
- yaffs_checkpt_validty_t cp;
+ struct yaffs_checkpt_validity cp;
memset(&cp, 0, sizeof(cp));
cp.version = YAFFS_CHECKPOINT_VERSION;
cp.head = (head) ? 1 : 0;
- return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
- 1 : 0;
+ return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
}
-static int yaffs2_rd_checkpt_validty_marker(yaffs_dev_t *dev, int head)
+static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
{
- yaffs_checkpt_validty_t cp;
+ struct yaffs_checkpt_validity cp;
int ok;
ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
if (ok)
ok = (cp.struct_type == sizeof(cp)) &&
- (cp.magic == YAFFS_MAGIC) &&
- (cp.version == YAFFS_CHECKPOINT_VERSION) &&
- (cp.head == ((head) ? 1 : 0));
+ (cp.magic == YAFFS_MAGIC) &&
+ (cp.version == YAFFS_CHECKPOINT_VERSION) &&
+ (cp.head == ((head) ? 1 : 0));
return ok ? 1 : 0;
}
-static void yaffs2_dev_to_checkpt_dev(yaffs_checkpt_dev_t *cp,
- yaffs_dev_t *dev)
+static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
+ struct yaffs_dev *dev)
{
cp->n_erased_blocks = dev->n_erased_blocks;
cp->alloc_block = dev->alloc_block;
}
-static void yaffs_checkpt_dev_to_dev(yaffs_dev_t *dev,
- yaffs_checkpt_dev_t *cp)
+static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
+ struct yaffs_checkpt_dev *cp)
{
dev->n_erased_blocks = cp->n_erased_blocks;
dev->alloc_block = cp->alloc_block;
dev->seq_number = cp->seq_number;
}
-
-static int yaffs2_wr_checkpt_dev(yaffs_dev_t *dev)
+static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
{
- yaffs_checkpt_dev_t cp;
- __u32 n_bytes;
- __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1);
-
+ struct yaffs_checkpt_dev cp;
+ u32 n_bytes;
+ u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
int ok;
- /* Write device runtime values*/
+ /* Write device runtime values */
yaffs2_dev_to_checkpt_dev(&cp, dev);
cp.struct_type = sizeof(cp);
ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
+ if (!ok)
+ return 0;
/* Write block info */
- if (ok) {
- n_bytes = nBlocks * sizeof(yaffs_block_info_t);
- ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
- }
+ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
+ ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
+ if (!ok)
+ return 0;
/* Write chunk bits */
- if (ok) {
- n_bytes = nBlocks * dev->chunk_bit_stride;
- ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
- }
- return ok ? 1 : 0;
+ n_bytes = n_blocks * dev->chunk_bit_stride;
+ ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
+ return ok ? 1 : 0;
}
-static int yaffs2_rd_checkpt_dev(yaffs_dev_t *dev)
+static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
{
- yaffs_checkpt_dev_t cp;
- __u32 n_bytes;
- __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1);
-
+ struct yaffs_checkpt_dev cp;
+ u32 n_bytes;
+ u32 n_blocks =
+ (dev->internal_end_block - dev->internal_start_block + 1);
int ok;
ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
if (cp.struct_type != sizeof(cp))
return 0;
-
yaffs_checkpt_dev_to_dev(dev, &cp);
- n_bytes = nBlocks * sizeof(yaffs_block_info_t);
+ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
if (!ok)
return 0;
- n_bytes = nBlocks * dev->chunk_bit_stride;
+
+ n_bytes = n_blocks * dev->chunk_bit_stride;
ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
return ok ? 1 : 0;
}
-static void yaffs2_obj_checkpt_obj(yaffs_checkpt_obj_t *cp,
- yaffs_obj_t *obj)
+static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
+ struct yaffs_obj *obj)
{
-
cp->obj_id = obj->obj_id;
cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
cp->hdr_chunk = obj->hdr_chunk;
cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
}
-static int taffs2_checkpt_obj_to_obj(yaffs_obj_t *obj, yaffs_checkpt_obj_t *cp)
+static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
+ struct yaffs_checkpt_obj *cp)
{
-
- yaffs_obj_t *parent;
+ struct yaffs_obj *parent;
if (obj->variant_type != cp->variant_type) {
- T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
- TCONT("chunk %d does not match existing object type %d")
- TENDSTR), cp->obj_id, cp->variant_type, cp->hdr_chunk,
- obj->variant_type));
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "Checkpoint read object %d type %d chunk %d does not match existing object type %d",
+ cp->obj_id, cp->variant_type, cp->hdr_chunk,
+ obj->variant_type);
return 0;
}
obj->obj_id = cp->obj_id;
if (cp->parent_id)
- parent = yaffs_find_or_create_by_number(
- obj->my_dev,
- cp->parent_id,
- YAFFS_OBJECT_TYPE_DIRECTORY);
+ parent = yaffs_find_or_create_by_number(obj->my_dev,
+ cp->parent_id,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
else
parent = NULL;
if (parent) {
if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
- TCONT(" chunk %d Parent type, %d, not directory")
- TENDSTR),
- cp->obj_id, cp->parent_id, cp->variant_type,
- cp->hdr_chunk, parent->variant_type));
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",
+ cp->obj_id, cp->parent_id,
+ cp->variant_type, cp->hdr_chunk,
+ parent->variant_type);
return 0;
}
yaffs_add_obj_to_dir(parent, obj);
return 1;
}
-
-
-static int yaffs2_checkpt_tnode_worker(yaffs_obj_t *in, yaffs_tnode_t *tn,
- __u32 level, int chunk_offset)
+static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
+ struct yaffs_tnode *tn, u32 level,
+ int chunk_offset)
{
int i;
- yaffs_dev_t *dev = in->my_dev;
+ struct yaffs_dev *dev = in->my_dev;
int ok = 1;
-
- if (tn) {
- if (level > 0) {
-
- for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
- if (tn->internal[i]) {
- ok = yaffs2_checkpt_tnode_worker(in,
- tn->internal[i],
- level - 1,
- (chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i);
- }
- }
- } else if (level == 0) {
- __u32 baseOffset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
- ok = (yaffs2_checkpt_wr(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
- if (ok)
- ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == dev->tnode_size);
+ u32 base_offset;
+
+ if (!tn)
+ return 1;
+
+ if (level > 0) {
+ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
+ if (!tn->internal[i])
+ continue;
+ ok = yaffs2_checkpt_tnode_worker(in,
+ tn->internal[i],
+ level - 1,
+ (chunk_offset <<
+ YAFFS_TNODES_INTERNAL_BITS) + i);
}
+ return ok;
}
- return ok;
+ /* Level 0 tnode */
+ base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
+ ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==
+ sizeof(base_offset));
+ if (ok)
+ ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==
+ dev->tnode_size);
+ return ok;
}
-static int yaffs2_wr_checkpt_tnodes(yaffs_obj_t *obj)
+static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
{
- __u32 endMarker = ~0;
+ u32 end_marker = ~0;
int ok = 1;
- if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
- ok = yaffs2_checkpt_tnode_worker(obj,
- obj->variant.file_variant.top,
- obj->variant.file_variant.top_level,
- 0);
- if (ok)
- ok = (yaffs2_checkpt_wr(obj->my_dev, &endMarker, sizeof(endMarker)) ==
- sizeof(endMarker));
- }
+ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
+ return ok;
+
+ ok = yaffs2_checkpt_tnode_worker(obj,
+ obj->variant.file_variant.top,
+ obj->variant.file_variant.
+ top_level, 0);
+ if (ok)
+ ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker,
+ sizeof(end_marker)) == sizeof(end_marker));
return ok ? 1 : 0;
}
-static int yaffs2_rd_checkpt_tnodes(yaffs_obj_t *obj)
+static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
{
- __u32 baseChunk;
+ u32 base_chunk;
int ok = 1;
- yaffs_dev_t *dev = obj->my_dev;
- yaffs_file_s *fileStructPtr = &obj->variant.file_variant;
- yaffs_tnode_t *tn;
+ struct yaffs_dev *dev = obj->my_dev;
+ struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
+ struct yaffs_tnode *tn;
int nread = 0;
- ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
+ ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
+ sizeof(base_chunk));
- while (ok && (~baseChunk)) {
+ while (ok && (~base_chunk)) {
nread++;
/* Read level 0 tnode */
-
tn = yaffs_get_tnode(dev);
- if (tn){
- ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == dev->tnode_size);
- } else
+ if (tn)
+ ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
+ dev->tnode_size);
+ else
ok = 0;
if (tn && ok)
ok = yaffs_add_find_tnode_0(dev,
- fileStructPtr,
- baseChunk,
- tn) ? 1 : 0;
+ file_stuct_ptr,
+ base_chunk, tn) ? 1 : 0;
if (ok)
- ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
-
+ ok = (yaffs2_checkpt_rd
+ (dev, &base_chunk,
+ sizeof(base_chunk)) == sizeof(base_chunk));
}
- T(YAFFS_TRACE_CHECKPOINT, (
- TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
- nread, baseChunk, ok));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "Checkpoint read tnodes %d records, last %d. ok %d",
+ nread, base_chunk, ok);
return ok ? 1 : 0;
}
-
-static int yaffs2_wr_checkpt_objs(yaffs_dev_t *dev)
+static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
{
- yaffs_obj_t *obj;
- yaffs_checkpt_obj_t cp;
+ struct yaffs_obj *obj;
+ struct yaffs_checkpt_obj cp;
int i;
int ok = 1;
- struct ylist_head *lh;
-
+ struct list_head *lh;
/* Iterate through the objects in each hash entry,
* dumping them to the checkpointing stream.
*/
- for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
- ylist_for_each(lh, &dev->obj_bucket[i].list) {
- if (lh) {
- obj = ylist_entry(lh, yaffs_obj_t, hash_link);
- if (!obj->defered_free) {
- yaffs2_obj_checkpt_obj(&cp, obj);
- cp.struct_type = sizeof(cp);
-
- T(YAFFS_TRACE_CHECKPOINT, (
- TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
- cp.obj_id, cp.parent_id, cp.variant_type, cp.hdr_chunk, obj));
-
- ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
-
- if (ok && obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
- ok = yaffs2_wr_checkpt_tnodes(obj);
- }
+ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
+ list_for_each(lh, &dev->obj_bucket[i].list) {
+ obj = list_entry(lh, struct yaffs_obj, hash_link);
+ if (!obj->defered_free) {
+ yaffs2_obj_checkpt_obj(&cp, obj);
+ cp.struct_type = sizeof(cp);
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "Checkpoint write object %d parent %d type %d chunk %d obj addr %p",
+ cp.obj_id, cp.parent_id,
+ cp.variant_type, cp.hdr_chunk, obj);
+
+ ok = (yaffs2_checkpt_wr(dev, &cp,
+ sizeof(cp)) == sizeof(cp));
+
+ if (ok &&
+ obj->variant_type ==
+ YAFFS_OBJECT_TYPE_FILE)
+ ok = yaffs2_wr_checkpt_tnodes(obj);
}
}
}
/* Dump end of list */
- memset(&cp, 0xFF, sizeof(yaffs_checkpt_obj_t));
+ memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));
cp.struct_type = sizeof(cp);
if (ok)
return ok ? 1 : 0;
}
-static int yaffs2_rd_checkpt_objs(yaffs_dev_t *dev)
+static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
{
- yaffs_obj_t *obj;
- yaffs_checkpt_obj_t cp;
+ struct yaffs_obj *obj;
+ struct yaffs_checkpt_obj cp;
int ok = 1;
int done = 0;
- yaffs_obj_t *hard_list = NULL;
+ LIST_HEAD(hard_list);
+
while (ok && !done) {
ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
if (cp.struct_type != sizeof(cp)) {
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
- cp.struct_type, (int)sizeof(cp), ok));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "struct size %d instead of %d ok %d",
+ cp.struct_type, (int)sizeof(cp), ok);
ok = 0;
}
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
- cp.obj_id, cp.parent_id, cp.variant_type, cp.hdr_chunk));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "Checkpoint read object %d parent %d type %d chunk %d ",
+ cp.obj_id, cp.parent_id, cp.variant_type,
+ cp.hdr_chunk);
- if (ok && cp.obj_id == ~0)
+ if (ok && cp.obj_id == ~0) {
done = 1;
- else if (ok) {
- obj = yaffs_find_or_create_by_number(dev, cp.obj_id, cp.variant_type);
+ } else if (ok) {
+ obj =
+ yaffs_find_or_create_by_number(dev, cp.obj_id,
+ cp.variant_type);
if (obj) {
- ok = taffs2_checkpt_obj_to_obj(obj, &cp);
+ ok = yaffs2_checkpt_obj_to_obj(obj, &cp);
if (!ok)
break;
- if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
+ if (obj->variant_type ==
+ YAFFS_OBJECT_TYPE_FILE) {
ok = yaffs2_rd_checkpt_tnodes(obj);
- } else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
- obj->hard_links.next =
- (struct ylist_head *) hard_list;
- hard_list = obj;
+ } else if (obj->variant_type ==
+ YAFFS_OBJECT_TYPE_HARDLINK) {
+ list_add(&obj->hard_links, &hard_list);
}
- } else
+ } else {
ok = 0;
+ }
}
}
if (ok)
- yaffs_link_fixup(dev, hard_list);
+ yaffs_link_fixup(dev, &hard_list);
return ok ? 1 : 0;
}
-static int yaffs2_wr_checkpt_sum(yaffs_dev_t *dev)
+static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
{
- __u32 checkpt_sum;
+ u32 checkpt_sum;
int ok;
yaffs2_get_checkpt_sum(dev, &checkpt_sum);
- ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == sizeof(checkpt_sum));
+ ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
+ sizeof(checkpt_sum));
if (!ok)
return 0;
return 1;
}
-static int yaffs2_rd_checkpt_sum(yaffs_dev_t *dev)
+static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
{
- __u32 checkpt_sum0;
- __u32 checkpt_sum1;
+ u32 checkpt_sum0;
+ u32 checkpt_sum1;
int ok;
yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
- ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == sizeof(checkpt_sum1));
+ ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
+ sizeof(checkpt_sum1));
if (!ok)
return 0;
return 1;
}
-
-static int yaffs2_wr_checkpt_data(yaffs_dev_t *dev)
+static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
{
int ok = 1;
if (!yaffs2_checkpt_required(dev)) {
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "skipping checkpoint write");
ok = 0;
}
ok = yaffs2_checkpt_open(dev, 1);
if (ok) {
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "write checkpoint validity");
ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
}
if (ok) {
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "write checkpoint device");
ok = yaffs2_wr_checkpt_dev(dev);
}
if (ok) {
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "write checkpoint objects");
ok = yaffs2_wr_checkpt_objs(dev);
}
if (ok) {
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "write checkpoint validity");
ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
}
return dev->is_checkpointed;
}
-static int yaffs2_rd_checkpt_data(yaffs_dev_t *dev)
+static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
{
int ok = 1;
-
- if(!dev->param.is_yaffs2)
+
+ if (!dev->param.is_yaffs2)
ok = 0;
if (ok && dev->param.skip_checkpt_rd) {
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "skipping checkpoint read");
ok = 0;
}
ok = yaffs2_checkpt_open(dev, 0); /* open for read */
if (ok) {
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
- ok = yaffs2_rd_checkpt_validty_marker(dev, 1);
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "read checkpoint validity");
+ ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
}
if (ok) {
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "read checkpoint device");
ok = yaffs2_rd_checkpt_dev(dev);
}
if (ok) {
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "read checkpoint objects");
ok = yaffs2_rd_checkpt_objs(dev);
}
if (ok) {
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
- ok = yaffs2_rd_checkpt_validty_marker(dev, 0);
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "read checkpoint validity");
+ ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
}
if (ok) {
ok = yaffs2_rd_checkpt_sum(dev);
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "read checkpoint checksum %d", ok);
}
if (!yaffs_checkpt_close(dev))
dev->is_checkpointed = 0;
return ok ? 1 : 0;
-
}
-void yaffs2_checkpt_invalidate(yaffs_dev_t *dev)
+void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
{
- if (dev->is_checkpointed ||
- dev->blocks_in_checkpt > 0) {
+ if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
dev->is_checkpointed = 0;
yaffs2_checkpt_invalidate_stream(dev);
}
dev->param.sb_dirty_fn(dev);
}
-
-int yaffs_checkpoint_save(yaffs_dev_t *dev)
+int yaffs_checkpoint_save(struct yaffs_dev *dev)
{
-
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "save entry: is_checkpointed %d",
+ dev->is_checkpointed);
yaffs_verify_objects(dev);
yaffs_verify_blocks(dev);
yaffs2_wr_checkpt_data(dev);
}
- T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
+ "save exit: is_checkpointed %d",
+ dev->is_checkpointed);
return dev->is_checkpointed;
}
-int yaffs2_checkpt_restore(yaffs_dev_t *dev)
+int yaffs2_checkpt_restore(struct yaffs_dev *dev)
{
int retval;
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "restore entry: is_checkpointed %d",
+ dev->is_checkpointed);
retval = yaffs2_rd_checkpt_data(dev);
yaffs_verify_free_chunks(dev);
}
- T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "restore exit: is_checkpointed %d",
+ dev->is_checkpointed);
return retval;
}
-int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size)
+int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
{
- /* if newsSize > oldFileSize.
+ /* if new_size > old_file_size.
* We're going to be writing a hole.
- * If the hole is small then write zeros otherwise write a start of hole marker.
+ * If the hole is small then write zeros otherwise write a start
+ * of hole marker.
*/
-
-
- loff_t oldFileSize;
- int increase;
- int smallHole ;
+ loff_t old_file_size;
+ loff_t increase;
+ int small_hole;
int result = YAFFS_OK;
- yaffs_dev_t *dev = NULL;
+ struct yaffs_dev *dev = NULL;
+ u8 *local_buffer = NULL;
+ int small_increase_ok = 0;
- __u8 *localBuffer = NULL;
-
- int smallIncreaseOk = 0;
-
- if(!obj)
+ if (!obj)
return YAFFS_FAIL;
- if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
+ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
return YAFFS_FAIL;
-
+
dev = obj->my_dev;
-
+
/* Bail out if not yaffs2 mode */
- if(!dev->param.is_yaffs2)
+ if (!dev->param.is_yaffs2)
return YAFFS_OK;
- oldFileSize = obj->variant.file_variant.file_size;
+ old_file_size = obj->variant.file_variant.file_size;
- if (new_size <= oldFileSize)
+ if (new_size <= old_file_size)
return YAFFS_OK;
- increase = new_size - oldFileSize;
+ increase = new_size - old_file_size;
- if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
- yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
- smallHole = 1;
+ if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
+ yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
+ small_hole = 1;
else
- smallHole = 0;
+ small_hole = 0;
- if(smallHole)
- localBuffer= yaffs_get_temp_buffer(dev, __LINE__);
-
- if(localBuffer){
+ if (small_hole)
+ local_buffer = yaffs_get_temp_buffer(dev);
+
+ if (local_buffer) {
/* fill hole with zero bytes */
- int pos = oldFileSize;
- int thisWrite;
+ loff_t pos = old_file_size;
+ int this_write;
int written;
- memset(localBuffer,0,dev->data_bytes_per_chunk);
- smallIncreaseOk = 1;
-
- while(increase > 0 && smallIncreaseOk){
- thisWrite = increase;
- if(thisWrite > dev->data_bytes_per_chunk)
- thisWrite = dev->data_bytes_per_chunk;
- written = yaffs_do_file_wr(obj,localBuffer,pos,thisWrite,0);
- if(written == thisWrite){
- pos += thisWrite;
- increase -= thisWrite;
- } else
- smallIncreaseOk = 0;
+ memset(local_buffer, 0, dev->data_bytes_per_chunk);
+ small_increase_ok = 1;
+
+ while (increase > 0 && small_increase_ok) {
+ this_write = increase;
+ if (this_write > dev->data_bytes_per_chunk)
+ this_write = dev->data_bytes_per_chunk;
+ written =
+ yaffs_do_file_wr(obj, local_buffer, pos, this_write,
+ 0);
+ if (written == this_write) {
+ pos += this_write;
+ increase -= this_write;
+ } else {
+ small_increase_ok = 0;
+ }
}
- yaffs_release_temp_buffer(dev,localBuffer,__LINE__);
+ yaffs_release_temp_buffer(dev, local_buffer);
- /* If we were out of space then reverse any chunks we've added */
- if(!smallIncreaseOk)
- yaffs_resize_file_down(obj, oldFileSize);
+ /* If out of space then reverse any chunks we've added */
+ if (!small_increase_ok)
+ yaffs_resize_file_down(obj, old_file_size);
}
-
- if (!smallIncreaseOk &&
- obj->parent &&
- obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
- obj->parent->obj_id != YAFFS_OBJECTID_DELETED){
+
+ if (!small_increase_ok &&
+ obj->parent &&
+ obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
+ obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
/* Write a hole start header with the old file size */
yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
}
return result;
-
}
-
-typedef struct {
+struct yaffs_block_index {
int seq;
int block;
-} yaffs_BlockIndex;
-
+};
static int yaffs2_ybicmp(const void *a, const void *b)
{
- register int aseq = ((yaffs_BlockIndex *)a)->seq;
- register int bseq = ((yaffs_BlockIndex *)b)->seq;
- register int ablock = ((yaffs_BlockIndex *)a)->block;
- register int bblock = ((yaffs_BlockIndex *)b)->block;
+ int aseq = ((struct yaffs_block_index *)a)->seq;
+ int bseq = ((struct yaffs_block_index *)b)->seq;
+ int ablock = ((struct yaffs_block_index *)a)->block;
+ int bblock = ((struct yaffs_block_index *)b)->block;
+
if (aseq == bseq)
return ablock - bblock;
- else
- return aseq - bseq;
+
+ return aseq - bseq;
}
-int yaffs2_scan_backwards(yaffs_dev_t *dev)
+static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi,
+ int blk, int chunk_in_block,
+ int *found_chunks,
+ u8 *chunk_data,
+ struct list_head *hard_list,
+ int summary_available)
{
- yaffs_ext_tags tags;
- int blk;
- int blockIterator;
- int startIterator;
- int endIterator;
- int nBlocksToScan = 0;
-
- int chunk;
- int result;
- int c;
- int deleted;
- yaffs_block_state_t state;
- yaffs_obj_t *hard_list = NULL;
- yaffs_block_info_t *bi;
- __u32 seq_number;
- yaffs_obj_header *oh;
- yaffs_obj_t *in;
- yaffs_obj_t *parent;
- int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
- int itsUnlinked;
- __u8 *chunkData;
-
- int file_size;
- int is_shrink;
- int foundChunksInBlock;
+ struct yaffs_obj_hdr *oh;
+ struct yaffs_obj *in;
+ struct yaffs_obj *parent;
int equiv_id;
+ loff_t file_size;
+ int is_shrink;
+ int is_unlinked;
+ struct yaffs_ext_tags tags;
+ int result;
int alloc_failed = 0;
+ int chunk = blk * dev->param.chunks_per_block + chunk_in_block;
+ struct yaffs_file_var *file_var;
+ struct yaffs_hardlink_var *hl_var;
+ struct yaffs_symlink_var *sl_var;
+
+ if (summary_available) {
+ result = yaffs_summary_fetch(dev, &tags, chunk_in_block);
+ tags.seq_number = bi->seq_number;
+ }
+
+ if (!summary_available || tags.obj_id == 0) {
+ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);
+ dev->tags_used++;
+ } else {
+ dev->summary_used++;
+ }
+
+ /* Let's have a good look at this chunk... */
+
+ if (!tags.chunk_used) {
+ /* An unassigned chunk in the block.
+ * If there are used chunks after this one, then
+ * it is a chunk that was skipped due to failing
+ * the erased check. Just skip it so that it can
+ * be deleted.
+ * But, more typically, We get here when this is
+ * an unallocated chunk and his means that
+ * either the block is empty or this is the one
+ * being allocated from
+ */
+
+ if (*found_chunks) {
+ /* This is a chunk that was skipped due
+ * to failing the erased check */
+ } else if (chunk_in_block == 0) {
+ /* We're looking at the first chunk in
+ * the block so the block is unused */
+ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
+ dev->n_erased_blocks++;
+ } else {
+ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
+ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
+ if (dev->seq_number == bi->seq_number) {
+ /* Allocating from this block*/
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ " Allocating from %d %d",
+ blk, chunk_in_block);
+
+ bi->block_state =
+ YAFFS_BLOCK_STATE_ALLOCATING;
+ dev->alloc_block = blk;
+ dev->alloc_page = chunk_in_block;
+ dev->alloc_block_finder = blk;
+ } else {
+ /* This is a partially written block
+ * that is not the current
+ * allocation block.
+ */
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "Partially written block %d detected. gc will fix this.",
+ blk);
+ }
+ }
+ }
+
+ dev->n_free_chunks++;
+
+ } else if (tags.ecc_result ==
+ YAFFS_ECC_RESULT_UNFIXED) {
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ " Unfixed ECC in chunk(%d:%d), chunk ignored",
+ blk, chunk_in_block);
+ dev->n_free_chunks++;
+ } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
+ tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
+ tags.obj_id == YAFFS_OBJECTID_SUMMARY ||
+ (tags.chunk_id > 0 &&
+ tags.n_bytes > dev->data_bytes_per_chunk) ||
+ tags.seq_number != bi->seq_number) {
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",
+ blk, chunk_in_block, tags.obj_id,
+ tags.chunk_id, tags.n_bytes);
+ dev->n_free_chunks++;
+ } else if (tags.chunk_id > 0) {
+ /* chunk_id > 0 so it is a data chunk... */
+ loff_t endpos;
+ loff_t chunk_base = (tags.chunk_id - 1) *
+ dev->data_bytes_per_chunk;
+
+ *found_chunks = 1;
+
+ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+ bi->pages_in_use++;
+
+ in = yaffs_find_or_create_by_number(dev,
+ tags.obj_id,
+ YAFFS_OBJECT_TYPE_FILE);
+ if (!in)
+ /* Out of memory */
+ alloc_failed = 1;
+
+ if (in &&
+ in->variant_type == YAFFS_OBJECT_TYPE_FILE &&
+ chunk_base < in->variant.file_variant.shrink_size) {
+ /* This has not been invalidated by
+ * a resize */
+ if (!yaffs_put_chunk_in_file(in, tags.chunk_id,
+ chunk, -1))
+ alloc_failed = 1;
+
+ /* File size is calculated by looking at
+ * the data chunks if we have not
+ * seen an object header yet.
+ * Stop this practice once we find an
+ * object header.
+ */
+ endpos = chunk_base + tags.n_bytes;
+
+ if (!in->valid &&
+ in->variant.file_variant.scanned_size < endpos) {
+ in->variant.file_variant.
+ scanned_size = endpos;
+ in->variant.file_variant.
+ file_size = endpos;
+ }
+ } else if (in) {
+ /* This chunk has been invalidated by a
+ * resize, or a past file deletion
+ * so delete the chunk*/
+ yaffs_chunk_del(dev, chunk, 1, __LINE__);
+ }
+ } else {
+ /* chunk_id == 0, so it is an ObjectHeader.
+ * Thus, we read in the object header and make
+ * the object
+ */
+ *found_chunks = 1;
+
+ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+ bi->pages_in_use++;
+
+ oh = NULL;
+ in = NULL;
+
+ if (tags.extra_available) {
+ in = yaffs_find_or_create_by_number(dev,
+ tags.obj_id,
+ tags.extra_obj_type);
+ if (!in)
+ alloc_failed = 1;
+ }
+
+ if (!in ||
+ (!in->valid && dev->param.disable_lazy_load) ||
+ tags.extra_shadows ||
+ (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT ||
+ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
+
+ /* If we don't have valid info then we
+ * need to read the chunk
+ * TODO In future we can probably defer
+ * reading the chunk and living with
+ * invalid data until needed.
+ */
+
+ result = yaffs_rd_chunk_tags_nand(dev,
+ chunk,
+ chunk_data,
+ NULL);
+
+ oh = (struct yaffs_obj_hdr *)chunk_data;
+
+ if (dev->param.inband_tags) {
+ /* Fix up the header if they got
+ * corrupted by inband tags */
+ oh->shadows_obj =
+ oh->inband_shadowed_obj_id;
+ oh->is_shrink =
+ oh->inband_is_shrink;
+ }
+
+ if (!in) {
+ in = yaffs_find_or_create_by_number(dev,
+ tags.obj_id, oh->type);
+ if (!in)
+ alloc_failed = 1;
+ }
+ }
+
+ if (!in) {
+ /* TODO Hoosterman we have a problem! */
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: Could not make object for object %d at chunk %d during scan",
+ tags.obj_id, chunk);
+ return YAFFS_FAIL;
+ }
+ if (in->valid) {
+ /* We have already filled this one.
+ * We have a duplicate that will be
+ * discarded, but we first have to suck
+ * out resize info if it is a file.
+ */
+ if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
+ ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
+ (tags.extra_available &&
+ tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
+ )) {
+ loff_t this_size = (oh) ?
+ yaffs_oh_to_size(oh) :
+ tags.extra_file_size;
+ u32 parent_obj_id = (oh) ?
+ oh->parent_obj_id :
+ tags.extra_parent_id;
+
+ is_shrink = (oh) ?
+ oh->is_shrink :
+ tags.extra_is_shrink;
+
+ /* If it is deleted (unlinked
+ * at start also means deleted)
+ * we treat the file size as
+ * being zeroed at this point.
+ */
+ if (parent_obj_id == YAFFS_OBJECTID_DELETED ||
+ parent_obj_id == YAFFS_OBJECTID_UNLINKED) {
+ this_size = 0;
+ is_shrink = 1;
+ }
+
+ if (is_shrink &&
+ in->variant.file_variant.shrink_size >
+ this_size)
+ in->variant.file_variant.shrink_size =
+ this_size;
+
+ if (is_shrink)
+ bi->has_shrink_hdr = 1;
+ }
+ /* Use existing - destroy this one. */
+ yaffs_chunk_del(dev, chunk, 1, __LINE__);
+ }
+
+ if (!in->valid && in->variant_type !=
+ (oh ? oh->type : tags.extra_obj_type))
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: Bad object type, %d != %d, for object %d at chunk %d during scan",
+ oh ? oh->type : tags.extra_obj_type,
+ in->variant_type, tags.obj_id,
+ chunk);
+
+ if (!in->valid &&
+ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
+ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
+ /* We only load some info, don't fiddle
+ * with directory structure */
+ in->valid = 1;
+
+ if (oh) {
+ in->yst_mode = oh->yst_mode;
+ yaffs_load_attribs(in, oh);
+ in->lazy_loaded = 0;
+ } else {
+ in->lazy_loaded = 1;
+ }
+ in->hdr_chunk = chunk;
+
+ } else if (!in->valid) {
+ /* we need to load this info */
+ in->valid = 1;
+ in->hdr_chunk = chunk;
+ if (oh) {
+ in->variant_type = oh->type;
+ in->yst_mode = oh->yst_mode;
+ yaffs_load_attribs(in, oh);
+
+ if (oh->shadows_obj > 0)
+ yaffs_handle_shadowed_obj(dev,
+ oh->shadows_obj, 1);
+
+ yaffs_set_obj_name_from_oh(in, oh);
+ parent = yaffs_find_or_create_by_number(dev,
+ oh->parent_obj_id,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+ file_size = yaffs_oh_to_size(oh);
+ is_shrink = oh->is_shrink;
+ equiv_id = oh->equiv_id;
+ } else {
+ in->variant_type = tags.extra_obj_type;
+ parent = yaffs_find_or_create_by_number(dev,
+ tags.extra_parent_id,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+ file_size = tags.extra_file_size;
+ is_shrink = tags.extra_is_shrink;
+ equiv_id = tags.extra_equiv_id;
+ in->lazy_loaded = 1;
+ }
+ in->dirty = 0;
- yaffs_BlockIndex *blockIndex = NULL;
- int altBlockIndex = 0;
+ if (!parent)
+ alloc_failed = 1;
+
+ /* directory stuff...
+ * hook up to parent
+ */
+
+ if (parent &&
+ parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) {
+ /* Set up as a directory */
+ parent->variant_type =
+ YAFFS_OBJECT_TYPE_DIRECTORY;
+ INIT_LIST_HEAD(&parent->
+ variant.dir_variant.children);
+ } else if (!parent ||
+ parent->variant_type !=
+ YAFFS_OBJECT_TYPE_DIRECTORY) {
+ /* Hoosterman, another problem....
+ * Trying to use a non-directory as a directory
+ */
+
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
+ );
+ parent = dev->lost_n_found;
+ }
+ yaffs_add_obj_to_dir(parent, in);
+
+ is_unlinked = (parent == dev->del_dir) ||
+ (parent == dev->unlinked_dir);
+
+ if (is_shrink)
+ /* Mark the block */
+ bi->has_shrink_hdr = 1;
+
+ /* Note re hardlinks.
+ * Since we might scan a hardlink before its equivalent
+ * object is scanned we put them all in a list.
+ * After scanning is complete, we should have all the
+ * objects, so we run through this list and fix up all
+ * the chains.
+ */
+
+ switch (in->variant_type) {
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* Todo got a problem */
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+ file_var = &in->variant.file_variant;
+ if (file_var->scanned_size < file_size) {
+ /* This covers the case where the file
+ * size is greater than the data held.
+ * This will happen if the file is
+ * resized to be larger than its
+ * current data extents.
+ */
+ file_var->file_size = file_size;
+ file_var->scanned_size = file_size;
+ }
+
+ if (file_var->shrink_size > file_size)
+ file_var->shrink_size = file_size;
+
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ hl_var = &in->variant.hardlink_variant;
+ if (!is_unlinked) {
+ hl_var->equiv_id = equiv_id;
+ list_add(&in->hard_links, hard_list);
+ }
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ sl_var = &in->variant.symlink_variant;
+ if (oh) {
+ sl_var->alias =
+ yaffs_clone_str(oh->alias);
+ if (!sl_var->alias)
+ alloc_failed = 1;
+ }
+ break;
+ }
+ }
+ }
+ return alloc_failed ? YAFFS_FAIL : YAFFS_OK;
+}
- T(YAFFS_TRACE_SCAN,
- (TSTR
- ("yaffs2_scan_backwards starts intstartblk %d intendblk %d..."
- TENDSTR), dev->internal_start_block, dev->internal_end_block));
+int yaffs2_scan_backwards(struct yaffs_dev *dev)
+{
+ int blk;
+ int block_iter;
+ int start_iter;
+ int end_iter;
+ int n_to_scan = 0;
+ enum yaffs_block_state state;
+ int c;
+ int deleted;
+ LIST_HEAD(hard_list);
+ struct yaffs_block_info *bi;
+ u32 seq_number;
+ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
+ u8 *chunk_data;
+ int found_chunks;
+ int alloc_failed = 0;
+ struct yaffs_block_index *block_index = NULL;
+ int alt_block_index = 0;
+ int summary_available;
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "yaffs2_scan_backwards starts intstartblk %d intendblk %d...",
+ dev->internal_start_block, dev->internal_end_block);
dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
- blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
+ block_index =
+ kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS);
- if (!blockIndex) {
- blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
- altBlockIndex = 1;
+ if (!block_index) {
+ block_index =
+ vmalloc(n_blocks * sizeof(struct yaffs_block_index));
+ alt_block_index = 1;
}
- if (!blockIndex) {
- T(YAFFS_TRACE_SCAN,
- (TSTR("yaffs2_scan_backwards() could not allocate block index!" TENDSTR)));
+ if (!block_index) {
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "yaffs2_scan_backwards() could not allocate block index!"
+ );
return YAFFS_FAIL;
}
dev->blocks_in_checkpt = 0;
- chunkData = yaffs_get_temp_buffer(dev, __LINE__);
+ chunk_data = yaffs_get_temp_buffer(dev);
/* Scan all the blocks to determine their state */
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);
bi->pages_in_use = 0;
bi->soft_del_pages = 0;
bi->seq_number = seq_number;
if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
- bi->block_state = state = YAFFS_BLOCK_STATE_CHECKPOINT;
+ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
- bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
+ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
- T(YAFFS_TRACE_SCAN_DEBUG,
- (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
- state, seq_number));
+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
+ "Block scanning block %d state %d seq %d",
+ blk, bi->block_state, seq_number);
-
- if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
+ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
dev->blocks_in_checkpt++;
- } else if (state == YAFFS_BLOCK_STATE_DEAD) {
- T(YAFFS_TRACE_BAD_BLOCKS,
- (TSTR("block %d is bad" TENDSTR), blk));
- } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
- T(YAFFS_TRACE_SCAN_DEBUG,
- (TSTR("Block empty " TENDSTR)));
+ } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) {
+ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
+ "block %d is bad", blk);
+ } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
dev->n_erased_blocks++;
dev->n_free_chunks += dev->param.chunks_per_block;
- } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
-
+ } else if (bi->block_state ==
+ YAFFS_BLOCK_STATE_NEEDS_SCAN) {
/* Determine the highest sequence number */
if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
-
- blockIndex[nBlocksToScan].seq = seq_number;
- blockIndex[nBlocksToScan].block = blk;
-
- nBlocksToScan++;
-
+ block_index[n_to_scan].seq = seq_number;
+ block_index[n_to_scan].block = blk;
+ n_to_scan++;
if (seq_number >= dev->seq_number)
dev->seq_number = seq_number;
} else {
/* TODO: Nasty sequence number! */
- T(YAFFS_TRACE_SCAN,
- (TSTR
- ("Block scanning block %d has bad sequence number %d"
- TENDSTR), blk, seq_number));
-
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "Block scanning block %d has bad sequence number %d",
+ blk, seq_number);
}
}
bi++;
}
- T(YAFFS_TRACE_SCAN,
- (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
-
-
+ yaffs_trace(YAFFS_TRACE_SCAN, "%d blocks to be sorted...", n_to_scan);
- YYIELD();
+ cond_resched();
- /* Sort the blocks by sequence number*/
- yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
+ /* Sort the blocks by sequence number */
+ sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
+ yaffs2_ybicmp, NULL);
- YYIELD();
+ cond_resched();
- T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_SCAN, "...done");
/* Now scan the blocks looking at the data. */
- startIterator = 0;
- endIterator = nBlocksToScan - 1;
- T(YAFFS_TRACE_SCAN_DEBUG,
- (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
+ start_iter = 0;
+ end_iter = n_to_scan - 1;
+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);
/* For each block.... backwards */
- for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
- blockIterator--) {
+ for (block_iter = end_iter;
+ !alloc_failed && block_iter >= start_iter;
+ block_iter--) {
/* Cooperative multitasking! This loop can run for so
long that watchdog timers expire. */
- YYIELD();
+ cond_resched();
/* get the block to scan in the correct order */
- blk = blockIndex[blockIterator].block;
-
+ blk = block_index[block_iter].block;
bi = yaffs_get_block_info(dev, blk);
-
-
- state = bi->block_state;
-
deleted = 0;
+ summary_available = yaffs_summary_read(dev, dev->sum_tags, blk);
+
/* For each chunk in each block that needs scanning.... */
- foundChunksInBlock = 0;
- for (c = dev->param.chunks_per_block - 1;
+ found_chunks = 0;
+ if (summary_available)
+ c = dev->chunks_per_summary - 1;
+ else
+ c = dev->param.chunks_per_block - 1;
+
+ for (/* c is already initialised */;
!alloc_failed && c >= 0 &&
- (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
- state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
+ (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
+ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING);
+ c--) {
/* Scan backwards...
* Read the tags and decide what to do
*/
-
- chunk = blk * dev->param.chunks_per_block + c;
-
- result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
- &tags);
-
- /* Let's have a good look at this chunk... */
-
- if (!tags.chunk_used) {
- /* An unassigned chunk in the block.
- * If there are used chunks after this one, then
- * it is a chunk that was skipped due to failing the erased
- * check. Just skip it so that it can be deleted.
- * But, more typically, We get here when this is an unallocated
- * chunk and his means that either the block is empty or
- * this is the one being allocated from
- */
-
- if (foundChunksInBlock) {
- /* This is a chunk that was skipped due to failing the erased check */
- } else if (c == 0) {
- /* We're looking at the first chunk in the block so the block is unused */
- state = YAFFS_BLOCK_STATE_EMPTY;
- dev->n_erased_blocks++;
- } else {
- if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
- state == YAFFS_BLOCK_STATE_ALLOCATING) {
- if (dev->seq_number == bi->seq_number) {
- /* this is the block being allocated from */
-
- T(YAFFS_TRACE_SCAN,
- (TSTR
- (" Allocating from %d %d"
- TENDSTR), blk, c));
-
- state = YAFFS_BLOCK_STATE_ALLOCATING;
- dev->alloc_block = blk;
- dev->alloc_page = c;
- dev->alloc_block_finder = blk;
- } else {
- /* This is a partially written block that is not
- * the current allocation block.
- */
-
- T(YAFFS_TRACE_SCAN,
- (TSTR("Partially written block %d detected" TENDSTR),
- blk));
- }
- }
- }
-
- dev->n_free_chunks++;
-
- } else if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
- T(YAFFS_TRACE_SCAN,
- (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
- blk, c));
-
- dev->n_free_chunks++;
-
- } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
- tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
- (tags.chunk_id > 0 && tags.n_bytes > dev->data_bytes_per_chunk) ||
- tags.seq_number != bi->seq_number ) {
- T(YAFFS_TRACE_SCAN,
- (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored"TENDSTR),
- blk, c,tags.obj_id, tags.chunk_id, tags.n_bytes));
-
- dev->n_free_chunks++;
-
- } else if (tags.chunk_id > 0) {
- /* chunk_id > 0 so it is a data chunk... */
- unsigned int endpos;
- __u32 chunkBase =
- (tags.chunk_id - 1) * dev->data_bytes_per_chunk;
-
- foundChunksInBlock = 1;
-
-
- yaffs_set_chunk_bit(dev, blk, c);
- bi->pages_in_use++;
-
- in = yaffs_find_or_create_by_number(dev,
- tags.
- obj_id,
- YAFFS_OBJECT_TYPE_FILE);
- if (!in) {
- /* Out of memory */
- alloc_failed = 1;
- }
-
- if (in &&
- in->variant_type == YAFFS_OBJECT_TYPE_FILE
- && chunkBase < in->variant.file_variant.shrink_size) {
- /* This has not been invalidated by a resize */
- if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, -1)) {
- alloc_failed = 1;
- }
-
- /* File size is calculated by looking at the data chunks if we have not
- * seen an object header yet. Stop this practice once we find an object header.
- */
- endpos = chunkBase + tags.n_bytes;
-
- if (!in->valid && /* have not got an object header yet */
- in->variant.file_variant.scanned_size < endpos) {
- in->variant.file_variant.scanned_size = endpos;
- in->variant.file_variant.file_size = endpos;
- }
-
- } else if (in) {
- /* This chunk has been invalidated by a resize, or a past file deletion
- * so delete the chunk*/
- yaffs_chunk_del(dev, chunk, 1, __LINE__);
-
- }
- } else {
- /* chunk_id == 0, so it is an ObjectHeader.
- * Thus, we read in the object header and make the object
- */
- foundChunksInBlock = 1;
-
- yaffs_set_chunk_bit(dev, blk, c);
- bi->pages_in_use++;
-
- oh = NULL;
- in = NULL;
-
- if (tags.extra_available) {
- in = yaffs_find_or_create_by_number(dev,
- tags.obj_id,
- tags.extra_obj_type);
- if (!in)
- alloc_failed = 1;
- }
-
- if (!in ||
- (!in->valid && dev->param.disable_lazy_load) ||
- tags.extra_shadows ||
- (!in->valid &&
- (tags.obj_id == YAFFS_OBJECTID_ROOT ||
- tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
-
- /* If we don't have valid info then we need to read the chunk
- * TODO In future we can probably defer reading the chunk and
- * living with invalid data until needed.
- */
-
- result = yaffs_rd_chunk_tags_nand(dev,
- chunk,
- chunkData,
- NULL);
-
- oh = (yaffs_obj_header *) chunkData;
-
- if (dev->param.inband_tags) {
- /* Fix up the header if they got corrupted by inband tags */
- oh->shadows_obj = oh->inband_shadowed_obj_id;
- oh->is_shrink = oh->inband_is_shrink;
- }
-
- if (!in) {
- in = yaffs_find_or_create_by_number(dev, tags.obj_id, oh->type);
- if (!in)
- alloc_failed = 1;
- }
-
- }
-
- if (!in) {
- /* TODO Hoosterman we have a problem! */
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
- TENDSTR), tags.obj_id, chunk));
- continue;
- }
-
- if (in->valid) {
- /* We have already filled this one.
- * We have a duplicate that will be discarded, but
- * we first have to suck out resize info if it is a file.
- */
-
- if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
- ((oh &&
- oh->type == YAFFS_OBJECT_TYPE_FILE) ||
- (tags.extra_available &&
- tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE))) {
- __u32 thisSize =
- (oh) ? oh->file_size : tags.
- extra_length;
- __u32 parent_obj_id =
- (oh) ? oh->
- parent_obj_id : tags.
- extra_parent_id;
-
-
- is_shrink =
- (oh) ? oh->is_shrink : tags.
- extra_is_shrink;
-
- /* If it is deleted (unlinked at start also means deleted)
- * we treat the file size as being zeroed at this point.
- */
- if (parent_obj_id ==
- YAFFS_OBJECTID_DELETED
- || parent_obj_id ==
- YAFFS_OBJECTID_UNLINKED) {
- thisSize = 0;
- is_shrink = 1;
- }
-
- if (is_shrink && in->variant.file_variant.shrink_size > thisSize)
- in->variant.file_variant.shrink_size = thisSize;
-
- if (is_shrink)
- bi->has_shrink_hdr = 1;
-
- }
- /* Use existing - destroy this one. */
- yaffs_chunk_del(dev, chunk, 1, __LINE__);
-
- }
-
- if (!in->valid && in->variant_type !=
- (oh ? oh->type : tags.extra_obj_type))
- T(YAFFS_TRACE_ERROR, (
- TSTR("yaffs tragedy: Bad object type, "
- TCONT("%d != %d, for object %d at chunk ")
- TCONT("%d during scan")
- TENDSTR), oh ?
- oh->type : tags.extra_obj_type,
- in->variant_type, tags.obj_id,
- chunk));
-
- if (!in->valid &&
- (tags.obj_id == YAFFS_OBJECTID_ROOT ||
- tags.obj_id ==
- YAFFS_OBJECTID_LOSTNFOUND)) {
- /* We only load some info, don't fiddle with directory structure */
- in->valid = 1;
-
- if (oh) {
-
- in->yst_mode = oh->yst_mode;
-#ifdef CONFIG_YAFFS_WINCE
- in->win_atime[0] = oh->win_atime[0];
- in->win_ctime[0] = oh->win_ctime[0];
- in->win_mtime[0] = oh->win_mtime[0];
- in->win_atime[1] = oh->win_atime[1];
- in->win_ctime[1] = oh->win_ctime[1];
- in->win_mtime[1] = oh->win_mtime[1];
-#else
- in->yst_uid = oh->yst_uid;
- in->yst_gid = oh->yst_gid;
- in->yst_atime = oh->yst_atime;
- in->yst_mtime = oh->yst_mtime;
- in->yst_ctime = oh->yst_ctime;
- in->yst_rdev = oh->yst_rdev;
-
- in->lazy_loaded = 0;
-
-#endif
- } else
- in->lazy_loaded = 1;
-
- in->hdr_chunk = chunk;
-
- } else if (!in->valid) {
- /* we need to load this info */
-
- in->valid = 1;
- in->hdr_chunk = chunk;
-
- if (oh) {
- in->variant_type = oh->type;
-
- in->yst_mode = oh->yst_mode;
-#ifdef CONFIG_YAFFS_WINCE
- in->win_atime[0] = oh->win_atime[0];
- in->win_ctime[0] = oh->win_ctime[0];
- in->win_mtime[0] = oh->win_mtime[0];
- in->win_atime[1] = oh->win_atime[1];
- in->win_ctime[1] = oh->win_ctime[1];
- in->win_mtime[1] = oh->win_mtime[1];
-#else
- in->yst_uid = oh->yst_uid;
- in->yst_gid = oh->yst_gid;
- in->yst_atime = oh->yst_atime;
- in->yst_mtime = oh->yst_mtime;
- in->yst_ctime = oh->yst_ctime;
- in->yst_rdev = oh->yst_rdev;
-#endif
-
- if (oh->shadows_obj > 0)
- yaffs_handle_shadowed_obj(dev,
- oh->
- shadows_obj,
- 1);
-
-
-
- yaffs_set_obj_name_from_oh(in, oh);
- parent =
- yaffs_find_or_create_by_number
- (dev, oh->parent_obj_id,
- YAFFS_OBJECT_TYPE_DIRECTORY);
-
- file_size = oh->file_size;
- is_shrink = oh->is_shrink;
- equiv_id = oh->equiv_id;
-
- } else {
- in->variant_type = tags.extra_obj_type;
- parent =
- yaffs_find_or_create_by_number
- (dev, tags.extra_parent_id,
- YAFFS_OBJECT_TYPE_DIRECTORY);
- file_size = tags.extra_length;
- is_shrink = tags.extra_is_shrink;
- equiv_id = tags.extra_equiv_id;
- in->lazy_loaded = 1;
-
- }
- in->dirty = 0;
-
- if (!parent)
- alloc_failed = 1;
-
- /* directory stuff...
- * hook up to parent
- */
-
- if (parent && parent->variant_type ==
- YAFFS_OBJECT_TYPE_UNKNOWN) {
- /* Set up as a directory */
- parent->variant_type =
- YAFFS_OBJECT_TYPE_DIRECTORY;
- YINIT_LIST_HEAD(&parent->variant.
- dir_variant.
- children);
- } else if (!parent || parent->variant_type !=
- YAFFS_OBJECT_TYPE_DIRECTORY) {
- /* Hoosterman, another problem....
- * We're trying to use a non-directory as a directory
- */
-
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
- TENDSTR)));
- parent = dev->lost_n_found;
- }
-
- yaffs_add_obj_to_dir(parent, in);
-
- itsUnlinked = (parent == dev->del_dir) ||
- (parent == dev->unlinked_dir);
-
- if (is_shrink) {
- /* Mark the block as having a shrinkHeader */
- bi->has_shrink_hdr = 1;
- }
-
- /* Note re hardlinks.
- * Since we might scan a hardlink before its equivalent object is scanned
- * we put them all in a list.
- * After scanning is complete, we should have all the objects, so we run
- * through this list and fix up all the chains.
- */
-
- switch (in->variant_type) {
- case YAFFS_OBJECT_TYPE_UNKNOWN:
- /* Todo got a problem */
- break;
- case YAFFS_OBJECT_TYPE_FILE:
-
- if (in->variant.file_variant.
- scanned_size < file_size) {
- /* This covers the case where the file size is greater
- * than where the data is
- * This will happen if the file is resized to be larger
- * than its current data extents.
- */
- in->variant.file_variant.file_size = file_size;
- in->variant.file_variant.scanned_size = file_size;
- }
-
- if (in->variant.file_variant.shrink_size > file_size)
- in->variant.file_variant.shrink_size = file_size;
-
-
- break;
- case YAFFS_OBJECT_TYPE_HARDLINK:
- if (!itsUnlinked) {
- in->variant.hardlink_variant.equiv_id =
- equiv_id;
- in->hard_links.next =
- (struct ylist_head *) hard_list;
- hard_list = in;
- }
- break;
- case YAFFS_OBJECT_TYPE_DIRECTORY:
- /* Do nothing */
- break;
- case YAFFS_OBJECT_TYPE_SPECIAL:
- /* Do nothing */
- break;
- case YAFFS_OBJECT_TYPE_SYMLINK:
- if (oh) {
- in->variant.symlink_variant.alias =
- yaffs_clone_str(oh->alias);
- if (!in->variant.symlink_variant.alias)
- alloc_failed = 1;
- }
- break;
- }
-
- }
-
- }
-
- } /* End of scanning for each chunk */
-
- if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
- /* If we got this far while scanning, then the block is fully allocated. */
- state = YAFFS_BLOCK_STATE_FULL;
+ if (yaffs2_scan_chunk(dev, bi, blk, c,
+ &found_chunks, chunk_data,
+ &hard_list, summary_available) ==
+ YAFFS_FAIL)
+ alloc_failed = 1;
}
-
- bi->block_state = state;
+ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+ /* If we got this far while scanning, then the block
+ * is fully allocated. */
+ bi->block_state = YAFFS_BLOCK_STATE_FULL;
+ }
/* Now let's see if it was dirty */
if (bi->pages_in_use == 0 &&
bi->block_state == YAFFS_BLOCK_STATE_FULL) {
yaffs_block_became_dirty(dev, blk);
}
-
}
-
+
yaffs_skip_rest_of_block(dev);
- if (altBlockIndex)
- YFREE_ALT(blockIndex);
+ if (alt_block_index)
+ vfree(block_index);
else
- YFREE(blockIndex);
+ kfree(block_index);
/* Ok, we've done all the scanning.
* Fix up the hard link chains.
- * We should now have scanned all the objects, now it's time to add these
+ * We have scanned all the objects, now it's time to add these
* hardlinks.
*/
- yaffs_link_fixup(dev, hard_list);
-
+ yaffs_link_fixup(dev, &hard_list);
- yaffs_release_temp_buffer(dev, chunkData, __LINE__);
+ yaffs_release_temp_buffer(dev, chunk_data);
if (alloc_failed)
return YAFFS_FAIL;
- T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_scan_backwards ends" TENDSTR)));
+ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");
return YAFFS_OK;
}
/*
- * 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
*
* 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
+ * 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_YAFFS2_H__
#include "yaffs_guts.h"
-void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev);
-void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev);
-void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t *dev, yaffs_block_info_t *bi);
-void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi);
-int yaffs_block_ok_for_gc(yaffs_dev_t *dev, yaffs_block_info_t *bi);
-__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev);
-int yaffs2_checkpt_required(yaffs_dev_t *dev);
-int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev);
-
+void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
+void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
+void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi);
+void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
+ struct yaffs_block_info *bi);
+int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
+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(yaffs_dev_t *dev);
-int yaffs2_checkpt_save(yaffs_dev_t *dev);
-int yaffs2_checkpt_restore(yaffs_dev_t *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);
-int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size);
-int yaffs2_scan_backwards(yaffs_dev_t *dev);
+int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
+int yaffs2_scan_backwards(struct yaffs_dev *dev);
#endif
+++ /dev/null
-/*
- * 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 __YAFFSINTERFACE_H__
-#define __YAFFSINTERFACE_H__
-
-int yaffs_initialise(unsigned nBlocks);
-
-#endif
/*
* 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
*
* Created by Charles Manning <charles@aleph1.co.uk>
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
-
#ifndef __YPORTENV_H__
#define __YPORTENV_H__
#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
-#if defined CONFIG_YAFFS_WINCE
-
-#include "ywinceenv.h"
-
-#elif defined __KERNEL__
-
+#ifdef YAFFS_OUT_OF_TREE
#include "moduleconfig.h"
-
-/* Linux kernel */
+#endif
#include <linux/version.h>
#define MTD_VERSION_CODE LINUX_VERSION_CODE
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
#include <linux/config.h>
#endif
-
+#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.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 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_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_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_LOSTNFOUND_MODE 0700
#define Y_TIME_CONVERT(x) (x)
#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) \
({ 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)
-
-/* Direct interface */
-#include "ydirectenv.h"
-
-#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
+#define yaffs_printf(msk, fmt, ...) \
+ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__)
-#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();\
+#define yaffs_trace(msk, fmt, ...) do { \
+ if (yaffs_trace_mask & (msk)) \
+ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \
} while (0)
-#endif
#endif
--- /dev/null
+--- 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;
+++ /dev/null
-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);
--- /dev/null
+--- 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;
+
+++ /dev/null
-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",
+++ /dev/null
-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;
+++ /dev/null
-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
+++ /dev/null
---- 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
+++ /dev/null
---- 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);
+++ /dev/null
---- 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
+++ /dev/null
---- 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;
+++ /dev/null
---- 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")));
+++ /dev/null
---- 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")));
-
+++ /dev/null
---- 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;
+++ /dev/null
---- 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
+++ /dev/null
---- 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))
+++ /dev/null
---- 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
+++ /dev/null
---- 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;
-
--- /dev/null
+--- 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;
+++ /dev/null
-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);
--- /dev/null
+--- 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;
+
+++ /dev/null
-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",
--- /dev/null
+--- 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,
+ };
+++ /dev/null
-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;
+++ /dev/null
-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
+++ /dev/null
---- 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
+++ /dev/null
---- 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);
+++ /dev/null
---- 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
+++ /dev/null
---- 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;
+++ /dev/null
---- 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")));
+++ /dev/null
---- 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")));
-
+++ /dev/null
---- 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;
+++ /dev/null
---- 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
+++ /dev/null
---- 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))
+++ /dev/null
---- 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
+++ /dev/null
---- 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;
-
--- /dev/null
+--- 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;
+++ /dev/null
-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);
+++ /dev/null
-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",
+++ /dev/null
-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;
+++ /dev/null
-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
+++ /dev/null
---- 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
+++ /dev/null
---- 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);
+++ /dev/null
---- 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
+++ /dev/null
---- 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;
+++ /dev/null
---- 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")));
+++ /dev/null
---- 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")));
-
+++ /dev/null
---- 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;
+++ /dev/null
---- 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
+++ /dev/null
---- 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))
+++ /dev/null
---- 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