📄 yaffs_guts.c
字号:
#else theObject->yst_atime = theObject->yst_mtime = theObject->yst_ctime = Y_CURRENT_TIME;#endif switch (type) { case YAFFS_OBJECT_TYPE_FILE: theObject->variant.fileVariant.fileSize = 0; theObject->variant.fileVariant.scannedFileSize = 0; theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */ theObject->variant.fileVariant.topLevel = 0; theObject->variant.fileVariant.top = yaffs_GetTnode(dev); break; case YAFFS_OBJECT_TYPE_DIRECTORY: INIT_LIST_HEAD(&theObject->variant.directoryVariant. children); 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 theObject;}static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device * dev, int number, yaffs_ObjectType type){ yaffs_Object *theObject = NULL; if (number > 0) { theObject = yaffs_FindObjectByNumber(dev, number); } if (!theObject) { theObject = yaffs_CreateNewObject(dev, number, type); } return theObject;} static YCHAR *yaffs_CloneString(const YCHAR * str){ YCHAR *newStr = NULL; if (str && *str) { newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); yaffs_strcpy(newStr, str); } return newStr;}/* * Mknod (create) a new object. * equivalentObject only has meaning for a hard link; * aliasString only has meaning for a sumlink. * rdev only has meaning for devices (a subset of special objects) */ static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, yaffs_Object * parent, const YCHAR * name, __u32 mode, __u32 uid, __u32 gid, yaffs_Object * equivalentObject, const YCHAR * aliasString, __u32 rdev){ yaffs_Object *in; yaffs_Device *dev = parent->myDev; /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/ if (yaffs_FindObjectByName(parent, name)) { return NULL; } in = yaffs_CreateNewObject(dev, -1, type); if (in) { in->chunkId = -1; in->valid = 1; in->variantType = type; in->yst_mode = mode;#ifdef CONFIG_YAFFS_WINCE yfsd_WinFileTimeNow(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->nDataChunks = 0; yaffs_SetObjectName(in, name); in->dirty = 1; yaffs_AddObjectToDirectory(parent, in); in->myDev = parent->myDev; switch (type) { case YAFFS_OBJECT_TYPE_SYMLINK: in->variant.symLinkVariant.alias = yaffs_CloneString(aliasString); break; case YAFFS_OBJECT_TYPE_HARDLINK: in->variant.hardLinkVariant.equivalentObject = equivalentObject; in->variant.hardLinkVariant.equivalentObjectId = equivalentObject->objectId; list_add(&in->hardLinks, &equivalentObject->hardLinks); 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_UpdateObjectHeader(in, name, 0, 0, 0) < 0) { /* Could not create the object header, fail the creation */ yaffs_DestroyObject(in); in = NULL; } } return in;}yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name, __u32 mode, __u32 uid, __u32 gid){ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, uid, gid, NULL, NULL, 0);}yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name, __u32 mode, __u32 uid, __u32 gid){ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, mode, uid, gid, NULL, NULL, 0);}yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name, __u32 mode, __u32 uid, __u32 gid, __u32 rdev){ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, uid, gid, NULL, NULL, rdev);}yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name, __u32 mode, __u32 uid, __u32 gid, const YCHAR * alias){ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, uid, gid, NULL, alias, 0);}/* yaffs_Link returns the object id of the equivalent object.*/yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name, yaffs_Object * equivalentObject){ /* Get the real object in case we were fed a hard link as an equivalent object */ equivalentObject = yaffs_GetEquivalentObject(equivalentObject); if (yaffs_MknodObject (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0, equivalentObject, NULL, 0)) { return equivalentObject; } else { return NULL; }}static int yaffs_ChangeObjectName(yaffs_Object * obj, yaffs_Object * newDir, const YCHAR * newName, int force, int shadows){ int unlinkOp; int deleteOp; yaffs_Object *existingTarget; if (newDir == NULL) { newDir = obj->parent; /* use the old directory */ } if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { T(YAFFS_TRACE_ALWAYS, (TSTR ("tragendy: yaffs_ChangeObjectName: newDir is not a directory" TENDSTR))); YBUG(); } /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ if (obj->myDev->isYaffs2) { unlinkOp = (newDir == obj->myDev->unlinkedDir); } else { unlinkOp = (newDir == obj->myDev->unlinkedDir && obj->variantType == YAFFS_OBJECT_TYPE_FILE); } deleteOp = (newDir == obj->myDev->deletedDir); existingTarget = yaffs_FindObjectByName(newDir, newName); /* 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) && newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) { yaffs_SetObjectName(obj, newName); obj->dirty = 1; yaffs_AddObjectToDirectory(newDir, obj); if (unlinkOp) 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) return YAFFS_OK; } return YAFFS_FAIL;}int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName, yaffs_Object * newDir, const YCHAR * newName){ yaffs_Object *obj; yaffs_Object *existingTarget; int force = 0;#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 (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0) { force = 1; }#endif obj = yaffs_FindObjectByName(oldDir, oldName); /* Check new name to long. */ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK && yaffs_strlen(newName) > YAFFS_MAX_ALIAS_LENGTH) /* ENAMETOOLONG */ return YAFFS_FAIL; else if (obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK && yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) /* ENAMETOOLONG */ return YAFFS_FAIL; if (obj && obj->renameAllowed) { /* Now do the handling for an existing target, if there is one */ existingTarget = yaffs_FindObjectByName(newDir, newName); if (existingTarget && existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && !list_empty(&existingTarget->variant.directoryVariant.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 */ yaffs_ChangeObjectName(obj, newDir, newName, force, existingTarget->objectId); yaffs_UnlinkObject(existingTarget); } return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0); } return YAFFS_FAIL;}/*------------------------- Block Management and Page Allocation ----------------*/static int yaffs_InitialiseBlocks(yaffs_Device * dev){ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; dev->allocationBlock = -1; /* force it to get a new one */ /* Todo we're assuming the malloc will pass. */ dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo)); if(!dev->blockInfo){ dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo)); dev->blockInfoAlt = 1; } else dev->blockInfoAlt = 0; /* Set up dynamic blockinfo stuff. */ dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); if(!dev->chunkBits){ dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); dev->chunkBitsAlt = 1; } else dev->chunkBitsAlt = 0; if (dev->blockInfo && dev->chunkBits) { memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo)); memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks); return YAFFS_OK; } return YAFFS_FAIL;}static void yaffs_DeinitialiseBlocks(yaffs_Device * dev){ if(dev->blockInfoAlt) YFREE_ALT(dev->blockInfo); else YFREE(dev->blockInfo); dev->blockInfoAlt = 0; dev->blockInfo = NULL; if(dev->chunkBitsAlt) YFREE_ALT(dev->chunkBits); else YFREE(dev->chunkBits); dev->chunkBitsAlt = 0; dev->chunkBits = NULL;}static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device * dev, yaffs_BlockInfo * bi){ int i; __u32 seq; yaffs_BlockInfo *b; if (!dev->isYaffs2) return 1; /* disqualification only applies to yaffs2. */ if (!bi->hasShrinkHeader) return 1; /* can gc */ /* Find the oldest dirty sequence number if we don't know it and save it * so we don't have to keep recomputing it. */ if (!dev->oldestDirtySequence) { seq = dev->sequenceNumber; for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { b = yaffs_GetBlockInfo(dev, i); if (b->blockState == YAFFS_BLOCK_STATE_FULL && (b->pagesInUse - b->softDeletions) < dev->nChunksPerBlock && b->sequenceNumber < seq) { seq = b->sequenceNumber; } } dev->oldestDirtySequence = seq; } /* Can't do gc of this block if there are any blocks older than this one that have * discarded pages. */ return (bi->sequenceNumber <= dev->oldestDirtySequence);}/* FindDiretiestBlock is used to select the dirtiest block (or close enough) * for garbage collection. */static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev, int aggressive){ int b = dev->currentDirtyChecker; int i; int iterations; int dirtiest = -1; int pagesInUse; int prioritised=0; yaffs_BlockInfo *bi; static int nonAggressiveSkip = 0; int pendingPrioritisedExist = 0; /* First let's see if we need to grab a prioritised block */ if(dev->hasPendingPrioritisedGCs){ for(i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++){ bi = yaffs_GetBlockInfo(dev, i); if(bi->gcPrioritise) { pendingPrioritisedExist = 1; if(bi->blockState == YAFFS_BLOCK_STATE_FULL && yaffs_BlockNotDisqualifiedFromGC(dev, bi)){ pagesInUse = (bi->pagesInUse - bi->softDeletions); dirtiest = i; prioritised = 1; aggressive = 1; /* Fool the non-aggressive skip logiv below */ } } } if(!pendingPrioritisedExist) /* None found, so we can clear this */ dev->hasPendingPrioritisedGCs = 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 * block has only a few pages in use. */ nonAggressiveSkip--; if (!aggressive && (nonAggressiveSkip > 0)) { return -1; } if(!prioritised) pagesInUse = (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1; if (aggressive) { iterations = dev->internalEndBlock - dev->internalStartBlock + 1; } else { iterations = dev->internalEndBlock - dev->internalStartBlock + 1; iterations = iterations / 16; if (iterations > 200) { iterations = 200; } } for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) { b++; if (b < dev->internalStartBlock || b > dev->internalEndBlock) { b = dev->internalStartBlock; } if (b < dev->internalStartBlock || b > dev->internalEndBlock) { T(YAFFS_TRACE_ERROR, (TSTR("**>> Block %d is not valid" TENDSTR), b)); YBUG(); } bi = yaffs_GetBlockInfo(dev, b);#if 0 if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) { dirtiest = b; pagesInUse = 0; } else #endif if (bi->blockState == YAFFS_BLOCK_STATE_FULL && (bi->pagesInUse - bi->softDeletions) < pagesInUse && yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { dirtiest = b; pagesInUse = (bi->pagesInUse - bi->softDeletions); } } dev->currentDirtyChecker = b; if (dirtiest > 0) { T(YAFFS_TRACE_GC, (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest, dev->nChunksPerBlock - pagesInUse,prioritised)); } dev->oldestDirtySequence = 0; if (dirtiest > 0) { nonAggressiveSkip = 4; } return dirtiest;}static void yaffs_BlockBecameDirty(yaffs_Device * dev, int blockNo){ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo); int erasedOk = 0; /* 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_BlockBecameDirty block %d state %d %s"TENDSTR), blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : "")); bi->blockState = YAFFS_BLOCK_STATE_DIRTY; if (!bi->needsRetiring) { yaffs_InvalidateCheckpoint(dev); erasedOk = yaffs_EraseBlockInNAND(dev, blockNo); if (!erasedOk) { dev->nErasureFailures++; T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, (TSTR("**>> Erasure failed %d" TENDSTR), blockNo)); } } if (erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -