/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
- * Copyright (C) 2002-2007 Aleph One Ltd.
+ * Copyright (C) 2002-2010 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.
*/
-
-const char *yaffs_guts_c_version =
- "$Id: yaffs_guts.c,v 1.120 2010-03-15 23:10:34 charles Exp $";
-
#include "yportenv.h"
#include "yaffs_trace.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_tagscompat.h"
-#ifndef CONFIG_YAFFS_USE_OWN_SORT
#include "yaffs_qsort.h"
-#endif
+
#include "yaffs_nand.h"
#include "yaffs_checkptrw.h"
#include "yaffs_nand.h"
#include "yaffs_packedtags2.h"
+#include "yaffs_nameval.h"
+#include "yaffs_allocator.h"
/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
#define YAFFS_GC_GOOD_ENOUGH 2
#define YAFFS_GC_PASSIVE_THRESHOLD 4
+
#define YAFFS_SMALL_HOLE_THRESHOLD 3
+/*
+ * Checkpoints are really no benefit on very small partitions.
+ *
+ * To save space on small partitions don't bother with checkpoints unless
+ * the partition is at least this big.
+ */
+#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
+
#include "yaffs_ecc.h"
+/* Private structure for doing xattr modifications */
+typedef struct {
+ int set; /* If 0 then this is a deletion */
+ const char *name;
+ const void *data;
+ int size;
+ int flags;
+ int result;
+} yaffs_XAttrMod;
/* Robustification (if it ever comes about...) */
static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);
static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
yaffs_Object *obj);
static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
- int force, int isShrink, int shadows);
+ int force, int isShrink, int shadows, yaffs_XAttrMod *xop);
+static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod);
+
static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
static int yaffs_CheckStructures(void);
-static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
- int chunkOffset, int *limit);
static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
-static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
+static void yaffs2_InvalidateCheckpoint(yaffs_Device *dev);
static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
yaffs_ExtendedTags *tags);
yaffs_FileStructure *fStruct,
__u32 chunkId);
-static int yaffs_HandleHole(yaffs_Object *obj, loff_t newSize);
+static int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize);
static void yaffs_SkipRestOfBlock(yaffs_Device *dev);
static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
int chunkInNAND,
static __u32 Shifts(__u32 x)
{
- int nShifts;
+ __u32 nShifts;
nShifts = 0;
"Dead"
};
+static void yaffs2_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
+{
+ if (!dev->param.isYaffs2)
+ return;
+
+ if((bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
+ (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
+ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
+ n, bi->sequenceNumber));
+}
+
static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
{
int actuallyUsed;
/* Check that the sequence number is valid.
* Ten million is legal, but is very unlikely
*/
- if (dev->param.isYaffs2 &&
- (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
- (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
- T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
- n, bi->sequenceNumber));
+
+ yaffs2_VerifyBlock(dev,bi,n);
}
+
+
static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
int n)
{
}
-
+#if 0
+/* Not being used, but don't want to throw away yet */
static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
__u32 level, int chunkOffset)
{
}
+#endif
static void yaffs_VerifyFile(yaffs_Object *obj)
{
int writeOk = 0;
int chunk;
- yaffs_InvalidateCheckpoint(dev);
+ yaffs2_InvalidateCheckpoint(dev);
do {
yaffs_BlockInfo *bi = 0;
* Oldest Dirty Sequence Number handling.
*/
-/* yaffs_CalcOldestDirtySequence()
- * yaffs_FindOldestDirtySequence()
+/* yaffs2_CalcOldestDirtySequence()
+ * yaffs2_FindOldestDirtySequence()
* Calculate the oldest dirty sequence number if we don't know it.
*/
-static void yaffs_CalcOldestDirtySequence(yaffs_Device *dev)
+static void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev)
{
int i;
unsigned seq;
}
-static void yaffs_FindOldestDirtySequence(yaffs_Device *dev)
+static void yaffs2_FindOldestDirtySequence(yaffs_Device *dev)
{
- if(dev->param.isYaffs2 && !dev->oldestDirtySequence)
- yaffs_CalcOldestDirtySequence(dev);
+ if(!dev->param.isYaffs2)
+ return;
+
+ if(!dev->oldestDirtySequence)
+ yaffs2_CalcOldestDirtySequence(dev);
}
/*
* becomes invalid). If the value matches the oldest then we clear
* dev->oldestDirtySequence to force its recomputation.
*/
-static void yaffs_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi)
+static void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi)
{
if(!dev->param.isYaffs2)
}
/*
- * yaffs_UpdateOldestDirtySequence()
+ * yaffs2_UpdateOldestDirtySequence()
* Update the oldest dirty sequence number whenever we dirty a block.
* Only do this if the oldestDirtySequence is actually being tracked.
*/
-static void yaffs_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi)
+static void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi)
{
- if(dev->param.isYaffs2 && dev->oldestDirtySequence){
+ if(!dev->param.isYaffs2)
+ return;
+
+ if(dev->oldestDirtySequence){
if(dev->oldestDirtySequence > bi->sequenceNumber){
dev->oldestDirtySequence = bi->sequenceNumber;
dev->oldestDirtyBlock = blockNo;
{
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
- yaffs_InvalidateCheckpoint(dev);
+ yaffs2_InvalidateCheckpoint(dev);
- yaffs_ClearOldestDirtySequence(dev,bi);
+ yaffs2_ClearOldestDirtySequence(dev,bi);
if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
* in the tnode.
*/
-/* yaffs_CreateTnodes creates a bunch more tnodes and
- * adds them to the tnode free list.
- * Don't use this function directly
- */
-static Y_INLINE int yaffs_CalcTnodeSize(yaffs_Device *dev)
-{
- int tnodeSize;
- /* Calculate the tnode size in bytes for variable width tnode support.
- * Must be a multiple of 32-bits */
- tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
-
- if (tnodeSize < sizeof(yaffs_Tnode))
- tnodeSize = sizeof(yaffs_Tnode);
- return tnodeSize;
-}
-static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
+static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
{
- int i;
- int tnodeSize = yaffs_CalcTnodeSize(dev);
- yaffs_Tnode *newTnodes;
- __u8 *mem;
- yaffs_Tnode *curr;
- yaffs_Tnode *next;
- yaffs_TnodeList *tnl;
-
- if (nTnodes < 1)
- return YAFFS_OK;
-
-
- /* make these things */
-
- newTnodes = YMALLOC(nTnodes * tnodeSize);
- mem = (__u8 *)newTnodes;
-
- if (!newTnodes) {
- T(YAFFS_TRACE_ERROR,
- (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
- return YAFFS_FAIL;
- }
-
- /* Hook them into the free list */
-#if 0
- for (i = 0; i < nTnodes - 1; i++) {
- newTnodes[i].internal[0] = &newTnodes[i + 1];
-#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
- newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
-#endif
- }
-
- newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
-#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
- newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
-#endif
- dev->freeTnodes = newTnodes;
-#else
- /* New hookup for wide tnodes */
- for (i = 0; i < nTnodes - 1; i++) {
- curr = (yaffs_Tnode *) &mem[i * tnodeSize];
- next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
- curr->internal[0] = next;
- }
-
- curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
- curr->internal[0] = dev->freeTnodes;
- dev->freeTnodes = (yaffs_Tnode *)mem;
-
-#endif
-
-
- dev->nFreeTnodes += nTnodes;
- dev->nTnodesCreated += nTnodes;
-
- /* 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));
- if (!tnl) {
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs: Could not add tnodes to management list" TENDSTR)));
- return YAFFS_FAIL;
- } else {
- tnl->tnodes = newTnodes;
- tnl->next = dev->allocatedTnodeList;
- dev->allocatedTnodeList = tnl;
+ yaffs_Tnode *tn = yaffs_AllocateRawTnode(dev);
+ if (tn){
+ memset(tn, 0, dev->tnodeSize);
+ dev->nTnodes++;
}
- T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
-
- return YAFFS_OK;
-}
-
-/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
-
-static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
-{
- yaffs_Tnode *tn = NULL;
-
-#ifdef CONFIG_YAFFS_VALGRIND_TEST
- tn = YMALLOC(yaffs_CalcTnodeSize(dev));
- if(tn)
- dev->nTnodesCreated++;
-#else
- /* If there are none left make more */
- if (!dev->freeTnodes)
- yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
-
- if (dev->freeTnodes) {
- tn = dev->freeTnodes;
-#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
- if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
- /* Hoosterman, this thing looks like it isn't in the list */
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
- }
-#endif
- dev->freeTnodes = dev->freeTnodes->internal[0];
- dev->nFreeTnodes--;
- }
-#endif
dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
return tn;
}
-static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
-{
- yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
- int tnodeSize = yaffs_CalcTnodeSize(dev);
-
- if (tn)
- memset(tn, 0, tnodeSize);
-
- return tn;
-}
-
/* FreeTnode frees up a tnode and puts it back on the free list */
static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
{
- if (tn) {
-#ifdef CONFIG_YAFFS_VALGRIND_TEST
- YFREE(tn);
- dev->nTnodesCreated--;
-#else
-#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
- if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
- /* Hoosterman, this thing looks like it is already in the list */
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
- }
- tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
-#endif
- tn->internal[0] = dev->freeTnodes;
- dev->freeTnodes = tn;
- dev->nFreeTnodes++;
-#endif
- }
+ yaffs_FreeRawTnode(dev,tn);
+ dev->nTnodes--;
dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
}
-static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)
-{
- /* Free the list of allocated tnodes */
- yaffs_TnodeList *tmp;
-
- while (dev->allocatedTnodeList) {
- tmp = dev->allocatedTnodeList->next;
-
- YFREE(dev->allocatedTnodeList->tnodes);
- YFREE(dev->allocatedTnodeList);
- dev->allocatedTnodeList = tmp;
-
- }
-
- dev->freeTnodes = NULL;
- dev->nFreeTnodes = 0;
- dev->nTnodesCreated = 0;
-}
-
-static void yaffs_InitialiseTnodes(yaffs_Device *dev)
+static void yaffs_DeinitialiseTnodesAndObjects(yaffs_Device *dev)
{
- dev->allocatedTnodeList = NULL;
- dev->freeTnodes = NULL;
- dev->nFreeTnodes = 0;
- dev->nTnodesCreated = 0;
+ yaffs_DeinitialiseRawTnodesAndObjects(dev);
+ dev->nObjects = 0;
+ dev->nTnodes = 0;
}
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
+ * 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.
*/
}
+#endif
+
static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
{
yaffs_BlockInfo *theBlock;
if (theBlock) {
theBlock->softDeletions++;
dev->nFreeChunks++;
- yaffs_UpdateOldestDirtySequence(dev, blockNo, theBlock);
+ yaffs2_UpdateOldestDirtySequence(dev, blockNo, theBlock);
}
}
hasData++;
}
} else {
- int tnodeSize_u32 = yaffs_CalcTnodeSize(dev)/sizeof(__u32);
+ int tnodeSize_u32 = dev->tnodeSize/sizeof(__u32);
__u32 *map = (__u32 *)tn;
for(i = 0; !hasData && i < tnodeSize_u32; i++){
/*-------------------- End of File Structure functions.-------------------*/
-/* yaffs_CreateFreeObjects creates a bunch more objects and
- * adds them to the object free list.
- */
-static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
-{
- int i;
- yaffs_Object *newObjects;
- yaffs_ObjectList *list;
-
- if (nObjects < 1)
- return YAFFS_OK;
-
- /* make these things */
- newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
- list = YMALLOC(sizeof(yaffs_ObjectList));
-
- 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)));
- return YAFFS_FAIL;
- }
-
- /* Hook them into the free list */
- for (i = 0; i < nObjects - 1; i++) {
- newObjects[i].siblings.next =
- (struct ylist_head *)(&newObjects[i + 1]);
- }
-
- newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
- dev->freeObjects = newObjects;
- dev->nFreeObjects += nObjects;
- dev->nObjectsCreated += nObjects;
-
- /* Now add this bunch of Objects to a list for freeing up. */
-
- list->objects = newObjects;
- list->next = dev->allocatedObjectList;
- dev->allocatedObjectList = list;
-
- return YAFFS_OK;
-}
-
/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
{
- yaffs_Object *tn = NULL;
+ yaffs_Object *obj = yaffs_AllocateRawObject(dev);
-#ifdef CONFIG_YAFFS_VALGRIND_TEST
- tn = YMALLOC(sizeof(yaffs_Object));
- if(tn)
- dev->nObjectsCreated++;
-#else
- /* If there are none left make more */
- if (!dev->freeObjects)
- yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
+ if (obj) {
+ dev->nObjects++;
- if (dev->freeObjects) {
- tn = dev->freeObjects;
- dev->freeObjects =
- (yaffs_Object *) (dev->freeObjects->siblings.next);
- dev->nFreeObjects--;
- }
-#endif
- if (tn) {
/* Now sweeten it up... */
- memset(tn, 0, sizeof(yaffs_Object));
- tn->beingCreated = 1;
+ memset(obj, 0, sizeof(yaffs_Object));
+ obj->beingCreated = 1;
- tn->myDev = dev;
- tn->hdrChunk = 0;
- tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
- YINIT_LIST_HEAD(&(tn->hardLinks));
- YINIT_LIST_HEAD(&(tn->hashLink));
- YINIT_LIST_HEAD(&tn->siblings);
+ obj->myDev = dev;
+ obj->hdrChunk = 0;
+ obj->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
+ YINIT_LIST_HEAD(&(obj->hardLinks));
+ YINIT_LIST_HEAD(&(obj->hashLink));
+ YINIT_LIST_HEAD(&obj->siblings);
/* Now make the directory sane */
if (dev->rootDir) {
- tn->parent = dev->rootDir;
- ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children);
+ obj->parent = dev->rootDir;
+ ylist_add(&(obj->siblings), &dev->rootDir->variant.directoryVariant.children);
}
/* Add it to the lost and found directory.
* check if lostNFound exists first
*/
if (dev->lostNFoundDir)
- yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
+ yaffs_AddObjectToDirectory(dev->lostNFoundDir, obj);
- tn->beingCreated = 0;
+ obj->beingCreated = 0;
}
dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
- return tn;
+ return obj;
}
static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
}
-static void yaffs_UnhashObject(yaffs_Object *tn)
+static void yaffs_UnhashObject(yaffs_Object *obj)
{
int bucket;
- yaffs_Device *dev = tn->myDev;
+ yaffs_Device *dev = obj->myDev;
/* If it is still linked into the bucket list, free from the list */
- if (!ylist_empty(&tn->hashLink)) {
- ylist_del_init(&tn->hashLink);
- bucket = yaffs_HashFunction(tn->objectId);
+ if (!ylist_empty(&obj->hashLink)) {
+ ylist_del_init(&obj->hashLink);
+ bucket = yaffs_HashFunction(obj->objectId);
dev->objectBucket[bucket].count--;
}
}
/* FreeObject frees up a Object and puts it back on the free list */
-static void yaffs_FreeObject(yaffs_Object *tn)
+static void yaffs_FreeObject(yaffs_Object *obj)
{
- yaffs_Device *dev = tn->myDev;
+ yaffs_Device *dev = obj->myDev;
- T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
+ T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->myInode));
- if (!tn)
+ if (!obj)
YBUG();
- if (tn->parent)
+ if (obj->parent)
YBUG();
- if (!ylist_empty(&tn->siblings))
+ if (!ylist_empty(&obj->siblings))
YBUG();
- if (tn->myInode) {
+ if (obj->myInode) {
/* We're still hooked up to a cached inode.
* Don't delete now, but mark for later deletion
*/
- tn->deferedFree = 1;
+ obj->deferedFree = 1;
return;
}
- yaffs_UnhashObject(tn);
+ yaffs_UnhashObject(obj);
-#ifdef CONFIG_YAFFS_VALGRIND_TEST
- YFREE(tn);
- dev->nObjectsCreated--;
- tn = NULL;
-#else
- /* Link into the free list. */
- tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
- dev->freeObjects = tn;
- dev->nFreeObjects++;
-#endif
+ yaffs_FreeRawObject(dev,obj);
+ dev->nObjects--;
dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
}
yaffs_FreeObject(obj);
}
-
-static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
-{
- /* Free the list of allocated Objects */
-
- yaffs_ObjectList *tmp;
-
- while (dev->allocatedObjectList) {
- tmp = dev->allocatedObjectList->next;
- YFREE(dev->allocatedObjectList->objects);
- YFREE(dev->allocatedObjectList);
-
- dev->allocatedObjectList = tmp;
- }
-
- dev->freeObjects = NULL;
- dev->nFreeObjects = 0;
- dev->nObjectsCreated = 0;
-}
-
-static void yaffs_InitialiseObjects(yaffs_Device *dev)
+static void yaffs_InitialiseTnodesAndObjects(yaffs_Device *dev)
{
int i;
- dev->allocatedObjectList = NULL;
- dev->freeObjects = NULL;
- dev->nFreeObjects = 0;
+ dev->nObjects = 0;
+ dev->nTnodes = 0;
+
+ yaffs_InitialiseRawTnodesAndObjects(dev);
for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
YINIT_LIST_HEAD(&dev->objectBucket[i].list);
break;
}
- if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
+ if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0, NULL) < 0) {
/* Could not create the object header, fail the creation */
yaffs_DeleteObject(in);
in = NULL;
obj->unlinked = 1;
/* If it is a deletion then we mark it as a shrink for gc purposes. */
- if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0)
+ if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows, NULL) >= 0)
return YAFFS_OK;
}
dev->chunkBits = NULL;
}
-static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
+static int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
yaffs_BlockInfo *bi)
{
if (!bi->hasShrinkHeader)
return 1; /* can gc */
- yaffs_FindOldestDirtySequence(dev);
+ yaffs2_FindOldestDirtySequence(dev);
/* Can't do gc of this block if there are any blocks older than this one that have
* discarded pages.
}
/*
- * yaffs_FindRefreshBlock()
+ * yaffs2_FindRefreshBlock()
* periodically finds the oldest full block by sequence number for refreshing.
* Only for yaffs2.
*/
-static __u32 yaffs_FindRefreshBlock(yaffs_Device *dev)
+static __u32 yaffs2_FindRefreshBlock(yaffs_Device *dev)
{
__u32 b ;
yaffs_BlockInfo *bi;
+ if(!dev->param.isYaffs2)
+ return oldest;
+
/*
* If refresh period < 10 then refreshing is disabled.
*/
- if(dev->param.refreshPeriod < 10 ||
- !dev->param.isYaffs2)
+ if(dev->param.refreshPeriod < 10)
return oldest;
/*
(TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
- yaffs_ClearOldestDirtySequence(dev,bi);
+ yaffs2_ClearOldestDirtySequence(dev,bi);
bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
}
if (!bi->needsRetiring) {
- yaffs_InvalidateCheckpoint(dev);
+ yaffs2_InvalidateCheckpoint(dev);
erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
if (!erasedOk) {
dev->nErasureFailures++;
-static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
+static int yaffs2_CheckpointRequired(yaffs_Device *dev)
{
+ int nblocks;
+
+ if(!dev->param.isYaffs2)
+ return 0;
+
+ nblocks = dev->internalEndBlock - dev->internalStartBlock + 1 ;
+
+ return !dev->param.skipCheckpointWrite &&
+ (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
+}
+
+static int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev)
+{
+ int retval;
+
+ if(!dev->param.isYaffs2)
+ return 0;
+
if (!dev->nCheckpointBlocksRequired &&
- dev->param.isYaffs2) {
+ yaffs2_CheckpointRequired(dev)){
/* Not a valid value so recalculate */
int nBytes = 0;
int nBlocks;
int devBlocks = (dev->param.endBlock - dev->param.startBlock + 1);
- int tnodeSize = yaffs_CalcTnodeSize(dev);
nBytes += sizeof(yaffs_CheckpointValidity);
nBytes += sizeof(yaffs_CheckpointDevice);
nBytes += devBlocks * sizeof(yaffs_BlockInfo);
nBytes += devBlocks * dev->chunkBitmapStride;
- nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);
- nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);
+ nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjects);
+ nBytes += (dev->tnodeSize + sizeof(__u32)) * (dev->nTnodes);
nBytes += sizeof(yaffs_CheckpointValidity);
nBytes += sizeof(__u32); /* checksum*/
dev->nCheckpointBlocksRequired = nBlocks;
}
- return dev->nCheckpointBlocksRequired;
+ retval = dev->nCheckpointBlocksRequired - dev->blocksInCheckpoint;
+ if(retval < 0)
+ retval = 0;
+ return retval;
}
/*
int reservedBlocks = dev->param.nReservedBlocks;
int checkpointBlocks;
- if (dev->param.isYaffs2) {
- checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) -
- dev->blocksInCheckpoint;
- if (checkpointBlocks < 0)
- checkpointBlocks = 0;
- } else {
- checkpointBlocks = 0;
- }
+ checkpointBlocks = yaffs2_CalcCheckpointBlocksRequired(dev);
reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.nChunksPerBlock);
if (bi->gcPrioritise) {
prioritisedExists = 1;
if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
- yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
+ yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) {
selected = i;
prioritised = 1;
}
if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
pagesUsed < dev->param.nChunksPerBlock &&
(dev->gcDirtiest < 1 || pagesUsed < dev->gcPagesInUse) &&
- yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
+ yaffs2_BlockNotDisqualifiedFromGC(dev, bi)) {
dev->gcDirtiest = dev->gcBlockFinder;
dev->gcPagesInUse = pagesUsed;
}
if(!selected && dev->param.isYaffs2 &&
dev->gcNotDone >= ( background ? 10 : 20)){
- yaffs_FindOldestDirtySequence(dev);
+ yaffs2_FindOldestDirtySequence(dev);
if(dev->oldestDirtyBlock > 0) {
selected = dev->oldestDirtyBlock;
dev->gcDirtiest = selected;
do {
maxTries++;
- checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
- if (checkpointBlockAdjust < 0)
- checkpointBlockAdjust = 0;
+ checkpointBlockAdjust = yaffs2_CalcCheckpointBlocksRequired(dev);
minErased = dev->param.nReservedBlocks + checkpointBlockAdjust + 1;
erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
/* If we don't already have a block being gc'd then see if we should start another */
if (dev->gcBlock < 1 && !aggressive) {
- dev->gcBlock = yaffs_FindRefreshBlock(dev);
+ dev->gcBlock = yaffs2_FindRefreshBlock(dev);
dev->gcChunk = 0;
}
if (dev->gcBlock < 1) {
*/
if (existingChunk > 0) {
- /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
+ /* NB Right now existing chunk will not be real chunkId 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:
}
if ((inScan > 0) &&
- (in->myDev->param.isYaffs2 ||
- existingChunk <= 0 ||
+ (existingChunk <= 0 ||
((existingSerial + 1) & 3) == newSerial)) {
/* Forward scanning.
* Use new
bi = yaffs_GetBlockInfo(dev, block);
- yaffs_UpdateOldestDirtySequence(dev, block, bi);
+ yaffs2_UpdateOldestDirtySequence(dev, block, bi);
T(YAFFS_TRACE_DELETION,
(TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
- if (markNAND &&
- bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->param.isYaffs2) {
+ if (!dev->param.isYaffs2 && markNAND &&
+ bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
yaffs_InitialiseTags(&tags);
* If name is not NULL, then that new name is used.
*/
int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
- int isShrink, int shadows)
+ int isShrink, int shadows, yaffs_XAttrMod *xmod)
{
yaffs_BlockInfo *bi;
if (!in->fake ||
in == dev->rootDir || /* The rootDir should also be saved */
- force) {
+ force || xmod) {
yaffs_CheckGarbageCollection(dev,0);
yaffs_CheckObjectDetailsLoaded(in);
yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
memcpy(oldName, oh->name, sizeof(oh->name));
- }
-
- memset(buffer, 0xFF, dev->nDataBytesPerChunk);
+ memset(buffer, 0xFF, sizeof(yaffs_ObjectHeader));
+ } else
+ memset(buffer, 0xFF, dev->nDataBytesPerChunk);
oh->type = in->variantType;
oh->yst_mode = in->yst_mode;
break;
}
+ /* process any xattrib modifications */
+ if(xmod)
+ yaffs_ApplyXMod(dev, (char *)buffer, xmod);
+
+
/* Tags */
yaffs_InitialiseTags(&newTags);
in->serial++;
/*--------------------- Checkpointing --------------------*/
-static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
+static int yaffs2_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
{
yaffs_CheckpointValidity cp;
cp.version = YAFFS_CHECKPOINT_VERSION;
cp.head = (head) ? 1 : 0;
- return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
+ return (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
1 : 0;
}
-static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
+static int yaffs2_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
{
yaffs_CheckpointValidity cp;
int ok;
- ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
+ ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
if (ok)
ok = (cp.structType == sizeof(cp)) &&
return ok ? 1 : 0;
}
-static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
+static void yaffs2_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
yaffs_Device *dev)
{
cp->nErasedBlocks = dev->nErasedBlocks;
}
-static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
+static void yaffs2_CheckpointDeviceToDevice(yaffs_Device *dev,
yaffs_CheckpointDevice *cp)
{
dev->nErasedBlocks = cp->nErasedBlocks;
}
-static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
+static int yaffs2_WriteCheckpointDevice(yaffs_Device *dev)
{
yaffs_CheckpointDevice cp;
__u32 nBytes;
int ok;
/* Write device runtime values*/
- yaffs_DeviceToCheckpointDevice(&cp, dev);
+ yaffs2_DeviceToCheckpointDevice(&cp, dev);
cp.structType = sizeof(cp);
- ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
+ ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
/* Write block info */
if (ok) {
nBytes = nBlocks * sizeof(yaffs_BlockInfo);
- ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
+ ok = (yaffs2_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
}
/* Write chunk bits */
if (ok) {
nBytes = nBlocks * dev->chunkBitmapStride;
- ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
+ ok = (yaffs2_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
}
return ok ? 1 : 0;
}
-static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
+static int yaffs2_ReadCheckpointDevice(yaffs_Device *dev)
{
yaffs_CheckpointDevice cp;
__u32 nBytes;
int ok;
- ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
+ ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
if (!ok)
return 0;
return 0;
- yaffs_CheckpointDeviceToDevice(dev, &cp);
+ yaffs2_CheckpointDeviceToDevice(dev, &cp);
nBytes = nBlocks * sizeof(yaffs_BlockInfo);
- ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
+ ok = (yaffs2_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
if (!ok)
return 0;
nBytes = nBlocks * dev->chunkBitmapStride;
- ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
+ ok = (yaffs2_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
return ok ? 1 : 0;
}
-static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
+static void yaffs2_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
yaffs_Object *obj)
{
cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
}
-static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
+static int yaffs2_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
{
yaffs_Object *parent;
int i;
yaffs_Device *dev = in->myDev;
int ok = 1;
- int tnodeSize = yaffs_CalcTnodeSize(dev);
if (tn) {
if (level > 0) {
}
} else if (level == 0) {
__u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
- ok = (yaffs_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
+ ok = (yaffs2_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
if (ok)
- ok = (yaffs_CheckpointWrite(dev, tn, tnodeSize) == tnodeSize);
+ ok = (yaffs2_CheckpointWrite(dev, tn, dev->tnodeSize) == dev->tnodeSize);
}
}
}
-static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
+static int yaffs2_WriteCheckpointTnodes(yaffs_Object *obj)
{
__u32 endMarker = ~0;
int ok = 1;
obj->variant.fileVariant.topLevel,
0);
if (ok)
- ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
+ ok = (yaffs2_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
sizeof(endMarker));
}
return ok ? 1 : 0;
}
-static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
+static int yaffs2_ReadCheckpointTnodes(yaffs_Object *obj)
{
__u32 baseChunk;
int ok = 1;
yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
yaffs_Tnode *tn;
int nread = 0;
- int tnodeSize = yaffs_CalcTnodeSize(dev);
- ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
+ ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
while (ok && (~baseChunk)) {
nread++;
/* Read level 0 tnode */
- tn = yaffs_GetTnodeRaw(dev);
- if (tn)
- ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize);
- else
+ tn = yaffs_GetTnode(dev);
+ if (tn){
+ ok = (yaffs2_CheckpointRead(dev, tn, dev->tnodeSize) == dev->tnodeSize);
+ } else
ok = 0;
if (tn && ok)
tn) ? 1 : 0;
if (ok)
- ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
+ ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
}
}
-static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
+static int yaffs2_WriteCheckpointObjects(yaffs_Device *dev)
{
yaffs_Object *obj;
yaffs_CheckpointObject cp;
if (lh) {
obj = ylist_entry(lh, yaffs_Object, hashLink);
if (!obj->deferedFree) {
- yaffs_ObjectToCheckpointObject(&cp, obj);
+ yaffs2_ObjectToCheckpointObject(&cp, obj);
cp.structType = sizeof(cp);
T(YAFFS_TRACE_CHECKPOINT, (
TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, obj));
- ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
+ ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
- ok = yaffs_WriteCheckpointTnodes(obj);
+ ok = yaffs2_WriteCheckpointTnodes(obj);
}
}
}
cp.structType = sizeof(cp);
if (ok)
- ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
+ ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
return ok ? 1 : 0;
}
-static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
+static int yaffs2_ReadCheckpointObjects(yaffs_Device *dev)
{
yaffs_Object *obj;
yaffs_CheckpointObject cp;
yaffs_Object *hardList = NULL;
while (ok && !done) {
- ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
+ ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
if (cp.structType != sizeof(cp)) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
cp.structType, (int)sizeof(cp), ok));
else if (ok) {
obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
if (obj) {
- ok = yaffs_CheckpointObjectToObject(obj, &cp);
+ ok = yaffs2_CheckpointObjectToObject(obj, &cp);
if (!ok)
break;
if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
- ok = yaffs_ReadCheckpointTnodes(obj);
+ ok = yaffs2_ReadCheckpointTnodes(obj);
} else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
obj->hardLinks.next =
(struct ylist_head *) hardList;
return ok ? 1 : 0;
}
-static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
+static int yaffs2_WriteCheckpointSum(yaffs_Device *dev)
{
__u32 checkpointSum;
int ok;
- yaffs_GetCheckpointSum(dev, &checkpointSum);
+ yaffs2_GetCheckpointSum(dev, &checkpointSum);
- ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
+ ok = (yaffs2_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
if (!ok)
return 0;
return 1;
}
-static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
+static int yaffs2_ReadCheckpointSum(yaffs_Device *dev)
{
__u32 checkpointSum0;
__u32 checkpointSum1;
int ok;
- yaffs_GetCheckpointSum(dev, &checkpointSum0);
+ yaffs2_GetCheckpointSum(dev, &checkpointSum0);
- ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
+ ok = (yaffs2_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
if (!ok)
return 0;
}
-static int yaffs_WriteCheckpointData(yaffs_Device *dev)
+static int yaffs2_WriteCheckpointData(yaffs_Device *dev)
{
int ok = 1;
- if (dev->param.skipCheckpointWrite || !dev->param.isYaffs2) {
+ if (!yaffs2_CheckpointRequired(dev)) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
ok = 0;
}
if (ok)
- ok = yaffs_CheckpointOpen(dev, 1);
+ ok = yaffs2_CheckpointOpen(dev, 1);
if (ok) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
- ok = yaffs_WriteCheckpointValidityMarker(dev, 1);
+ ok = yaffs2_WriteCheckpointValidityMarker(dev, 1);
}
if (ok) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
- ok = yaffs_WriteCheckpointDevice(dev);
+ ok = yaffs2_WriteCheckpointDevice(dev);
}
if (ok) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
- ok = yaffs_WriteCheckpointObjects(dev);
+ ok = yaffs2_WriteCheckpointObjects(dev);
}
if (ok) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
- ok = yaffs_WriteCheckpointValidityMarker(dev, 0);
+ ok = yaffs2_WriteCheckpointValidityMarker(dev, 0);
}
if (ok)
- ok = yaffs_WriteCheckpointSum(dev);
+ ok = yaffs2_WriteCheckpointSum(dev);
- if (!yaffs_CheckpointClose(dev))
+ if (!yaffs2_CheckpointClose(dev))
ok = 0;
if (ok)
return dev->isCheckpointed;
}
-static int yaffs_ReadCheckpointData(yaffs_Device *dev)
+static int yaffs2_ReadCheckpointData(yaffs_Device *dev)
{
int ok = 1;
+
+ if(!dev->param.isYaffs2)
+ ok = 0;
- if (dev->param.skipCheckpointRead || !dev->param.isYaffs2) {
+ if (ok && dev->param.skipCheckpointRead) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
ok = 0;
}
if (ok)
- ok = yaffs_CheckpointOpen(dev, 0); /* open for read */
+ ok = yaffs2_CheckpointOpen(dev, 0); /* open for read */
if (ok) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
- ok = yaffs_ReadCheckpointValidityMarker(dev, 1);
+ ok = yaffs2_ReadCheckpointValidityMarker(dev, 1);
}
if (ok) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
- ok = yaffs_ReadCheckpointDevice(dev);
+ ok = yaffs2_ReadCheckpointDevice(dev);
}
if (ok) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
- ok = yaffs_ReadCheckpointObjects(dev);
+ ok = yaffs2_ReadCheckpointObjects(dev);
}
if (ok) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
- ok = yaffs_ReadCheckpointValidityMarker(dev, 0);
+ ok = yaffs2_ReadCheckpointValidityMarker(dev, 0);
}
if (ok) {
- ok = yaffs_ReadCheckpointSum(dev);
+ ok = yaffs2_ReadCheckpointSum(dev);
T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
}
- if (!yaffs_CheckpointClose(dev))
+ if (!yaffs2_CheckpointClose(dev))
ok = 0;
if (ok)
}
-static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
+static void yaffs2_InvalidateCheckpoint(yaffs_Device *dev)
{
if (dev->isCheckpointed ||
dev->blocksInCheckpoint > 0) {
dev->isCheckpointed = 0;
- yaffs_CheckpointInvalidateStream(dev);
+ yaffs2_CheckpointInvalidateStream(dev);
}
if (dev->param.markSuperBlockDirty)
dev->param.markSuperBlockDirty(dev);
yaffs_VerifyFreeChunks(dev);
if (!dev->isCheckpointed) {
- yaffs_InvalidateCheckpoint(dev);
- yaffs_WriteCheckpointData(dev);
+ yaffs2_InvalidateCheckpoint(dev);
+ yaffs2_WriteCheckpointData(dev);
}
T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
return dev->isCheckpointed;
}
-int yaffs_CheckpointRestore(yaffs_Device *dev)
+int yaffs2_CheckpointRestore(yaffs_Device *dev)
{
int retval;
T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
- retval = yaffs_ReadCheckpointData(dev);
+ retval = yaffs2_ReadCheckpointData(dev);
if (dev->isCheckpointed) {
yaffs_VerifyObjects(dev);
dev = in->myDev;
while (n > 0 && chunkWritten >= 0) {
- /* chunk = offset / dev->nDataBytesPerChunk + 1; */
- /* start = offset % dev->nDataBytesPerChunk; */
yaffs_AddrToChunk(dev, offset, &chunk, &start);
if (chunk * dev->nDataBytesPerChunk + start != offset ||
TENDSTR),
(int)offset, chunk, start));
}
- chunk++;
+ chunk++; /* File pos to chunk in file offset */
/* OK now check for the curveball where the start and end are in
* the same chunk.
int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
int nBytes, int writeThrough)
{
- yaffs_HandleHole(in,offset);
+ yaffs2_HandleHole(in,offset);
return yaffs_DoWriteDataToFile(in,buffer,offset,nBytes,writeThrough);
}
}
-static int yaffs_HandleHole(yaffs_Object *obj, loff_t newSize)
+static int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize)
{
/* if newsSize > oldFileSize.
* We're going to be writing a hole.
obj->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
obj->parent->objectId != YAFFS_OBJECTID_DELETED){
/* Write a hole start header with the old file size */
- yaffs_UpdateObjectHeader(obj, NULL, 0,1,0);
+ yaffs_UpdateObjectHeader(obj, NULL, 0, 1, 0, NULL);
}
return result;
return YAFFS_OK;
if(newSize > oldFileSize){
- yaffs_HandleHole(in,newSize);
+ yaffs2_HandleHole(in,newSize);
in->variant.fileVariant.fileSize = newSize;
} else {
/* newSize < oldFileSize */
!in->isShadowed &&
in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
in->parent->objectId != YAFFS_OBJECTID_DELETED)
- yaffs_UpdateObjectHeader(in, NULL, 0,0,0);
+ yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL);
return YAFFS_OK;
#endif
}
- retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
+ retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0, NULL) >=
0) ? YAFFS_OK : YAFFS_FAIL;
}
} else {
int yaffs_DeleteFile(yaffs_Object *in)
{
int retVal = YAFFS_OK;
- int deleted = in->deleted;
+ int deleted; /* Need to cache value on stack if in is freed */
yaffs_Device *dev = in->myDev;
if (dev->param.disableSoftDelete || dev->param.isYaffs2)
if (!in->unlinked)
retVal = yaffs_UnlinkFileIfNeeded(in);
+ deleted = in->deleted;
+
if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
in->deleted = 1;
deleted = 1;
-static int ybicmp(const void *a, const void *b)
+static int yaffs2_ybicmp(const void *a, const void *b)
{
register int aseq = ((yaffs_BlockIndex *)a)->seq;
register int bseq = ((yaffs_BlockIndex *)b)->seq;
yaffs_DeleteDirectoryContents(dev->lostNFoundDir);
}
-static int yaffs_Scan(yaffs_Device *dev)
+static int yaffs1_Scan(yaffs_Device *dev)
{
yaffs_ExtendedTags tags;
int blk;
T(YAFFS_TRACE_SCAN,
- (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),
+ (TSTR("yaffs1_Scan starts intstartblk %d intendblk %d..." TENDSTR),
dev->internalStartBlock, dev->internalEndBlock));
chunkData = yaffs_GetTempBuffer(dev, __LINE__);
obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
if (obj)
- yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
+ yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL);
YFREE(fixer);
}
if (alloc_failed)
return YAFFS_FAIL;
- T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
+ T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_Scan ends" TENDSTR)));
return YAFFS_OK;
}
}
-static int yaffs_ScanBackwards(yaffs_Device *dev)
+static int yaffs2_ScanBackwards(yaffs_Device *dev)
{
yaffs_ExtendedTags tags;
int blk;
yaffs_BlockIndex *blockIndex = NULL;
int altBlockIndex = 0;
- if (!dev->param.isYaffs2) {
- T(YAFFS_TRACE_SCAN,
- (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
- return YAFFS_FAIL;
- }
-
T(YAFFS_TRACE_SCAN,
(TSTR
- ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..."
+ ("yaffs2_ScanBackwards starts intstartblk %d intendblk %d..."
TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
if (!blockIndex) {
T(YAFFS_TRACE_SCAN,
- (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));
+ (TSTR("yaffs2_ScanBackwards() could not allocate block index!" TENDSTR)));
return YAFFS_FAIL;
}
YYIELD();
- /* Sort the blocks */
-#ifndef CONFIG_YAFFS_USE_OWN_SORT
- {
- /* Use qsort now. */
- yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);
- }
-#else
- {
- /* Dungy old bubble sort... */
-
- yaffs_BlockIndex temp;
- int i;
- int j;
-
- for (i = 0; i < nBlocksToScan; i++)
- for (j = i + 1; j < nBlocksToScan; j++)
- if (blockIndex[i].seq > blockIndex[j].seq) {
- temp = blockIndex[j];
- blockIndex[j] = blockIndex[i];
- blockIndex[i] = temp;
- }
- }
-#endif
+ /* Sort the blocks by sequence number*/
+ yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
YYIELD();
* the current allocation block.
*/
- T(YAFFS_TRACE_ALWAYS,
+ T(YAFFS_TRACE_SCAN,
(TSTR("Partially written block %d detected" TENDSTR),
blk));
}
if (alloc_failed)
return YAFFS_FAIL;
- T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
+ T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_ScanBackwards ends" TENDSTR)));
return YAFFS_OK;
}
}
} else
- yaffs_UpdateObjectHeader(obj,NULL,0,0,0);
+ yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
}
void yaffs_UpdateDirtyDirectories(yaffs_Device *dev)
T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->objectId));
if(obj->dirty)
- yaffs_UpdateObjectHeader(obj,NULL,0,0,0);
+ yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
}
}
if (valid & ATTR_SIZE)
yaffs_ResizeFile(obj, attr->ia_size);
- yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
+ yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL);
return YAFFS_OK;
#endif
+
+static int yaffs_DoXMod(yaffs_Object *obj, int set, const char *name, const void *value, int size, int flags)
+{
+ yaffs_XAttrMod xmod;
+
+ int result;
+
+ xmod.set = set;
+ xmod.name = name;
+ xmod.data = value;
+ xmod.size = size;
+ xmod.flags = flags;
+ xmod.result = -ENOSPC;
+
+ result = yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, &xmod);
+
+ if(result > 0)
+ return xmod.result;
+ else
+ return -ENOSPC;
+}
+
+static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod)
+{
+ int retval = 0;
+ int x_offs = sizeof(yaffs_ObjectHeader);
+ int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
+
+ 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);
+
+ xmod->result = retval;
+
+ return retval;
+}
+
+static int yaffs_DoXFetch(yaffs_Object *obj, const char *name, void *value, int size)
+{
+ char *buffer = NULL;
+ int result;
+ yaffs_ExtendedTags tags;
+ yaffs_Device *dev = obj->myDev;
+ int x_offs = sizeof(yaffs_ObjectHeader);
+ int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
+
+ __u8 * x_buffer;
+
+ int retval = 0;
+
+ if(obj->hdrChunk < 1)
+ return -ENODATA;
+
+ buffer = yaffs_GetTempBuffer(dev, __LINE__);
+ if(!buffer)
+ return -ENOMEM;
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev,obj->hdrChunk, buffer, &tags);
+
+ if(result != YAFFS_OK)
+ retval = -ENOENT;
+ else{
+ x_buffer = buffer + x_offs;
+
+ if(name)
+ retval = nval_get(x_buffer, x_size, name, value, size);
+ else
+ retval = nval_list(x_buffer, x_size, value,size);
+ }
+ yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
+ return retval;
+}
+
+int yaffs_SetXAttribute(yaffs_Object *obj, const char *name, const void * value, int size, int flags)
+{
+ return yaffs_DoXMod(obj, 1, name, value, size, flags);
+}
+
+int yaffs_RemoveXAttribute(yaffs_Object *obj, const char *name)
+{
+ return yaffs_DoXMod(obj, 0, name, NULL, 0, 0);
+}
+
+int yaffs_GetXAttribute(yaffs_Object *obj, const char *name, void *value, int size)
+{
+ return yaffs_DoXFetch(obj, name, value, size);
+}
+
+int yaffs_ListXAttributes(yaffs_Object *obj, char *buffer, int size)
+{
+ return yaffs_DoXFetch(obj, NULL, buffer,size);
+}
+
+
+
#if 0
int yaffs_DumpObject(yaffs_Object *obj)
{
else
dev->chunkGroupBits = bits - dev->tnodeWidth;
+ dev->tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
+ if(dev->tnodeSize < sizeof(yaffs_Tnode))
+ dev->tnodeSize = sizeof(yaffs_Tnode);
dev->chunkGroupSize = 1 << dev->chunkGroupBits;
if (!init_failed && !yaffs_InitialiseBlocks(dev))
init_failed = 1;
- yaffs_InitialiseTnodes(dev);
- yaffs_InitialiseObjects(dev);
+ yaffs_InitialiseTnodesAndObjects(dev);
if (!init_failed && !yaffs_CreateInitialDirectories(dev))
init_failed = 1;
if (!init_failed) {
/* Now scan the flash. */
if (dev->param.isYaffs2) {
- if (yaffs_CheckpointRestore(dev)) {
+ if (yaffs2_CheckpointRestore(dev)) {
yaffs_CheckObjectDetailsLoaded(dev->rootDir);
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs: restored from checkpoint" TENDSTR)));
* and scan backwards.
*/
yaffs_DeinitialiseBlocks(dev);
- yaffs_DeinitialiseTnodes(dev);
- yaffs_DeinitialiseObjects(dev);
+ yaffs_DeinitialiseTnodesAndObjects(dev);
dev->nErasedBlocks = 0;
dev->nFreeChunks = 0;
if (!init_failed && !yaffs_InitialiseBlocks(dev))
init_failed = 1;
- yaffs_InitialiseTnodes(dev);
- yaffs_InitialiseObjects(dev);
+ yaffs_InitialiseTnodesAndObjects(dev);
if (!init_failed && !yaffs_CreateInitialDirectories(dev))
init_failed = 1;
- if (!init_failed && !yaffs_ScanBackwards(dev))
+ if (!init_failed && !yaffs2_ScanBackwards(dev))
init_failed = 1;
}
- } else if (!yaffs_Scan(dev))
+ } else if (!yaffs1_Scan(dev))
init_failed = 1;
yaffs_StripDeletedObjects(dev);
/* Clean up any aborted checkpoint data */
if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
- yaffs_InvalidateCheckpoint(dev);
+ yaffs2_InvalidateCheckpoint(dev);
T(YAFFS_TRACE_TRACING,
(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
int i;
yaffs_DeinitialiseBlocks(dev);
- yaffs_DeinitialiseTnodes(dev);
- yaffs_DeinitialiseObjects(dev);
+ yaffs_DeinitialiseTnodesAndObjects(dev);
if (dev->param.nShortOpCaches > 0 &&
dev->srCache) {
nFree -= ((dev->param.nReservedBlocks + 1) * dev->param.nChunksPerBlock);
/* Now we figure out how much to reserve for the checkpoint and report that... */
- blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
- if (blocksForCheckpoint < 0)
- blocksForCheckpoint = 0;
+ blocksForCheckpoint = yaffs2_CalcCheckpointBlocksRequired(dev);
nFree -= (blocksForCheckpoint * dev->param.nChunksPerBlock);