X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_guts.c;h=f910f386dfdb5a33d86a19b4069ee951d887e804;hp=a8b850a71711dda636dc3dd330f5576f0d9c6f2b;hb=55c18cfca44ed18e9501ddbde3a3361b4f377739;hpb=bfb36fe45ceea5a7e8347b24a575ab627e60df94 diff --git a/yaffs_guts.c b/yaffs_guts.c index a8b850a..f910f38 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -66,15 +66,12 @@ static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, yaffs_ObjectType type); -static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod); +static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod); static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj); static int yaffs_CheckStructures(void); static int yaffs_DoGenericObjectDeletion(yaffs_Object *in); -static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo); - - static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, int chunkInNAND); @@ -99,6 +96,11 @@ static int yaffs_VerifyChunkWritten(yaffs_Device *dev, const __u8 *data, yaffs_ExtendedTags *tags); + +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize); +static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev,YCHAR *ohName, const YCHAR *name); + + /* Function to calculate chunk and offset */ static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut, @@ -622,6 +624,18 @@ void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name) obj->sum = yaffs_CalcNameSum(name); } +void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1]; + memset(tmpName,0,sizeof(tmpName)); + yaffs_LoadNameFromObjectHeader(obj->myDev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1); + yaffs_SetObjectName(obj,tmpName); +#else + yaffs_SetObjectName(obj,oh->name); +#endif +} + /*-------------------- TNODES ------------------- * List of spare tnodes @@ -2089,7 +2103,6 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, int newChunk; int markNAND; int retVal = YAFFS_OK; - int cleanups = 0; int i; int isCheckpointBlock; int matchingChunk; @@ -2207,14 +2220,15 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, * We have to decrement free chunks so this works out properly. */ dev->nFreeChunks--; + bi->softDeletions--; object->nDataChunks--; if (object->nDataChunks <= 0) { /* remeber to clean up the object */ - dev->gcCleanupList[cleanups] = + dev->gcCleanupList[dev->nCleanups] = tags.objectId; - cleanups++; + dev->nCleanups++; } markNAND = 0; } else if (0) { @@ -2300,8 +2314,23 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); + + } + + yaffs_VerifyCollectedBlock(dev, bi, block); + + + + if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) { + /* + * The gc did not complete. Set block state back to FULL + * because checkpointing does not restore gc. + */ + bi->blockState = YAFFS_BLOCK_STATE_FULL; + } else { + /* The gc completed. */ /* Do any required cleanups */ - for (i = 0; i < cleanups; i++) { + for (i = 0; i < dev->nCleanups; i++) { /* Time to delete the file too */ object = yaffs_FindObjectByNumber(dev, @@ -2321,20 +2350,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, } - } - - yaffs_VerifyCollectedBlock(dev, bi, block); - - - if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) { - /* - * The gc did not complete. Set block state back to FULL - * because checkpointing does not restore gc. - */ - bi->blockState = YAFFS_BLOCK_STATE_FULL; - } else { - /* The gc completed. */ chunksAfter = yaffs_GetErasedChunks(dev); if (chunksBefore >= chunksAfter) { T(YAFFS_TRACE_GC, @@ -2344,6 +2360,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, } dev->gcBlock = 0; dev->gcChunk = 0; + dev->nCleanups = 0; } dev->gcDisable = 0; @@ -2415,7 +2432,16 @@ static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, threshold = dev->param.nChunksPerBlock; iterations = nBlocks; } else { - int maxThreshold = dev->param.nChunksPerBlock/2; + int maxThreshold; + + if(background) + maxThreshold = dev->param.nChunksPerBlock/2; + else + maxThreshold = dev->param.nChunksPerBlock/8; + + if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD) + maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD; + threshold = background ? (dev->gcNotDone + 2) * 2 : 0; if(threshold param.nChunksPerBlock - dev->gcPagesInUse, prioritised)); + dev->nGCBlocks++; if(background) dev->backgroundGCs++; + dev->gcDirtiest = 0; dev->gcPagesInUse = 0; dev->gcNotDone = 0; @@ -2515,10 +2543,8 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background) int aggressive = 0; int gcOk = YAFFS_OK; int maxTries = 0; - int minErased; int erasedChunks; - int checkpointBlockAdjust; if(dev->param.gcControl && @@ -2546,6 +2572,9 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background) if (dev->nErasedBlocks < minErased) aggressive = 1; else { + if(!background && erasedChunks > (dev->nFreeChunks / 4)) + break; + if(dev->gcSkip > 20) dev->gcSkip = 20; if(erasedChunks < dev->nFreeChunks/2 || @@ -2565,10 +2594,12 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background) if (dev->gcBlock < 1 && !aggressive) { dev->gcBlock = yaffs2_FindRefreshBlock(dev); dev->gcChunk = 0; + dev->nCleanups=0; } if (dev->gcBlock < 1) { dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background); dev->gcChunk = 0; + dev->nCleanups=0; } if (dev->gcBlock > 0) { @@ -2977,7 +3008,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, int newChunkId; yaffs_ExtendedTags newTags; yaffs_ExtendedTags oldTags; - YCHAR *alias = NULL; + const YCHAR *alias = NULL; __u8 *buffer = NULL; YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1]; @@ -3036,7 +3067,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, if (name && *name) { memset(oh->name, 0, sizeof(oh->name)); - yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH); + yaffs_LoadObjectHeaderFromName(dev,oh->name,name); } else if (prevChunkId > 0) memcpy(oh->name, oldName, sizeof(oh->name)); else @@ -3078,7 +3109,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, /* process any xattrib modifications */ if(xmod) - yaffs_ApplyXMod(dev, (char *)buffer, xmod); + yaffs_ApplyXMod(in, (char *)buffer, xmod); /* Tags */ @@ -4168,6 +4199,9 @@ static void yaffs_StripDeletedObjects(yaffs_Device *dev) struct ylist_head *n; yaffs_Object *l; + if (dev->readOnly) + return; + /* Soft delete all the unlinked files */ ylist_for_each_safe(i, n, &dev->unlinkedDir->variant.directoryVariant.children) { @@ -4221,6 +4255,8 @@ static void yaffs_FixHangingObjects(yaffs_Device *dev) int depthLimit; int hanging; + if (dev->readOnly) + return; /* Iterate through the objects in each hash entry, * looking at each object. @@ -4350,7 +4386,7 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) in->yst_rdev = oh->yst_rdev; #endif - yaffs_SetObjectName(in, oh->name); + yaffs_SetObjectNameFromOH(in, oh); if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { in->variant.symLinkVariant.alias = @@ -4386,6 +4422,7 @@ static void yaffs_UpdateParent(yaffs_Object *obj) yaffs_Device *dev; if(!obj) return; +#ifndef CONFIG_YAFFS_WINCE dev = obj->myDev; obj->dirty = 1; @@ -4400,6 +4437,7 @@ static void yaffs_UpdateParent(yaffs_Object *obj) } else yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL); +#endif } void yaffs_UpdateDirtyDirectories(yaffs_Device *dev) @@ -4600,36 +4638,124 @@ yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj) return obj; } -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize) -{ - memset(name, 0, buffSize * sizeof(YCHAR)); - - yaffs_CheckObjectDetailsLoaded(obj); +/* + * A note or two on object names. + * * If the object name is missing, we then make one up in the form objnnn + * + * * ASCII names are stored in the object header's name field from byte zero + * * Unicode names are historically stored starting from byte zero. + * + * Then there are automatic Unicode names... + * The purpose of these is to save names in a way that can be read as + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII + * 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 + * ascii names as per above. + * - If the name needs Unicode then the name is saved in Unicode + * starting at oh->name[1]. - if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { - yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1); - } else if (obj->hdrChunk <= 0) { + */ +static void yaffs_FixNullName(yaffs_Object * obj,YCHAR * name, int buffSize) +{ + /* 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]; unsigned v = obj->objectId; numString[19] = 0; - while (v > 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_strcat(locName,x); yaffs_strncpy(name, locName, buffSize - 1); + } +} + +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + if(dev->param.autoUnicode){ + 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_LoadObjectHeaderFromName(yaffs_Device *dev, YCHAR *ohName, const YCHAR *name) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + + int isAscii; + YCHAR *w; + if(dev->param.autoUnicode){ + + 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); + } } + else +#endif + yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1); + +} + +int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize) +{ + memset(name, 0, buffSize * sizeof(YCHAR)); + + yaffs_CheckObjectDetailsLoaded(obj); + + if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { + yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1); + } #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM - else if (obj->shortName[0]) - yaffs_strncpy(name, obj->shortName,YAFFS_SHORT_NAME_LENGTH+1); + else if (obj->shortName[0]) { + yaffs_strcpy(name, obj->shortName); + } #endif - else { + else if(obj->hdrChunk > 0) { int result; __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__); @@ -4642,15 +4768,17 @@ int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize) obj->hdrChunk, buffer, NULL); } - yaffs_strncpy(name, oh->name, buffSize - 1); - name[buffSize-1]=0; + yaffs_LoadNameFromObjectHeader(obj->myDev,name,oh->name,buffSize); yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__); } - return yaffs_strnlen(name,buffSize-1); + yaffs_FixNullName(obj,name,buffSize); + + return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH); } + int yaffs_GetObjectFileLength(yaffs_Object *obj) { /* Dereference any hard linking */ @@ -4787,7 +4915,7 @@ int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr) #endif -static int yaffs_DoXMod(yaffs_Object *obj, int set, const char *name, const void *value, int size, int flags) +static int yaffs_DoXMod(yaffs_Object *obj, int set, const YCHAR *name, const void *value, int size, int flags) { yaffs_XAttrMod xmod; @@ -4808,10 +4936,11 @@ static int yaffs_DoXMod(yaffs_Object *obj, int set, const char *name, const void return -ENOSPC; } -static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod) +static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod) { int retval = 0; int x_offs = sizeof(yaffs_ObjectHeader); + yaffs_Device *dev = obj->myDev; int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader); char * x_buffer = buffer + x_offs; @@ -4821,12 +4950,15 @@ static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod else retval = nval_del(x_buffer, x_size, xmod->name); + obj->hasXattr = nval_hasvalues(x_buffer, x_size); + obj->xattrKnown = 1; + xmod->result = retval; return retval; } -static int yaffs_DoXFetch(yaffs_Object *obj, const char *name, void *value, int size) +static int yaffs_DoXFetch(yaffs_Object *obj, const YCHAR *name, void *value, int size) { char *buffer = NULL; int result; @@ -4835,44 +4967,59 @@ static int yaffs_DoXFetch(yaffs_Object *obj, const char *name, void *value, int int x_offs = sizeof(yaffs_ObjectHeader); int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader); - __u8 * x_buffer; + char * x_buffer; int retval = 0; if(obj->hdrChunk < 1) return -ENODATA; - buffer = yaffs_GetTempBuffer(dev, __LINE__); + /* If we know that the object has no xattribs then don't do all the + * reading and parsing. + */ + if(obj->xattrKnown && !obj->hasXattr){ + if(name) + return -ENODATA; + else + return 0; + } + + buffer = (char *) yaffs_GetTempBuffer(dev, __LINE__); if(!buffer) return -ENOMEM; - result = yaffs_ReadChunkWithTagsFromNAND(dev,obj->hdrChunk, buffer, &tags); + result = yaffs_ReadChunkWithTagsFromNAND(dev,obj->hdrChunk, (__u8 *)buffer, &tags); if(result != YAFFS_OK) retval = -ENOENT; else{ x_buffer = buffer + x_offs; + if (!obj->xattrKnown){ + obj->hasXattr = nval_hasvalues(x_buffer, x_size); + obj->xattrKnown = 1; + } + 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__); + yaffs_ReleaseTempBuffer(dev,(__u8 *)buffer,__LINE__); return retval; } -int yaffs_SetXAttribute(yaffs_Object *obj, const char *name, const void * value, int size, int flags) +int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *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) +int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name) { return yaffs_DoXMod(obj, 0, name, NULL, 0, 0); } -int yaffs_GetXAttribute(yaffs_Object *obj, const char *name, void *value, int size) +int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size) { return yaffs_DoXFetch(obj, name, value, size); } @@ -5388,9 +5535,8 @@ static int yaffs_CheckStructures(void) /* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */ /* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */ /* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */ -#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG /* yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); */ -#endif + #ifndef CONFIG_YAFFS_WINCE yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader"); #endif