📄 yaffs_guts.c
字号:
/* * YAFFS: Yet another FFS. A NAND-flash specific file system. * * Copyright (C) 2002 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. * */const char *yaffs_guts_c_version = "$Id: yaffs_guts.c,v 1.27 2005/12/20 04:02:18 charles Exp $";#include "yportenv.h"#include "yaffsinterface.h"#include "yaffs_guts.h"#include "yaffs_tagsvalidity.h"#include "yaffs_tagscompat.h"#ifdef CONFIG_YAFFS_WINCEvoid yfsd_LockYAFFS(BOOL fsLockOnly);void yfsd_UnlockYAFFS(BOOL fsLockOnly);#endif#define YAFFS_PASSIVE_GC_CHUNKS 2#include "yaffs_ecc.h"/* NAND access */static Y_INLINE int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * buffer, yaffs_ExtendedTags * tags);static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, const __u8 * data, yaffs_ExtendedTags * tags);static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo);static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device * dev, int blockNo, yaffs_BlockState * state, unsigned *sequenceNumber);/* Robustification (if it ever comes about...) */static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND);static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * tags);static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, const yaffs_ExtendedTags * tags);/* Other local prototypes */static int yaffs_UnlinkObject( yaffs_Object *obj);static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device * dev, const __u8 * buffer, yaffs_ExtendedTags * tags, int useReserve);static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode, int chunkInNAND, int inScan);static yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number, yaffs_ObjectType type);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);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 __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo);static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, int lineNo);static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, int chunkInNAND);static int yaffs_UnlinkWorker(yaffs_Object * obj);static void yaffs_DestroyObject(yaffs_Object * obj);static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId, int chunkInObject);loff_t yaffs_GetFileSize(yaffs_Object * obj);static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve);static void yaffs_VerifyFreeChunks(yaffs_Device * dev);#ifdef YAFFS_PARANOIDstatic int yaffs_CheckFileSanity(yaffs_Object * in);#else#define yaffs_CheckFileSanity(in)#endifstatic void yaffs_InvalidateWholeChunkCache(yaffs_Object * in);static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId);/* * Start of real code. *//* * NAND access layer */ static int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * buffer, yaffs_ExtendedTags * tags){ chunkInNAND -= dev->chunkOffset; if (dev->readChunkWithTagsFromNAND) return dev->readChunkWithTagsFromNAND(dev, chunkInNAND, buffer, tags); else return yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev, chunkInNAND, buffer, tags);}static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, const __u8 * buffer, yaffs_ExtendedTags * tags){ chunkInNAND -= dev->chunkOffset; if (tags) { tags->sequenceNumber = dev->sequenceNumber; tags->chunkUsed = 1; if (!yaffs_ValidateTags(tags)) { T(YAFFS_TRACE_ERROR, (TSTR("Writing uninitialised tags" TENDSTR))); YBUG(); } T(YAFFS_TRACE_WRITE, (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND, tags->objectId, tags->chunkId)); } else { T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR))); YBUG(); } if (dev->writeChunkWithTagsToNAND) return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer, tags); else return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev, chunkInNAND, buffer, tags);}static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo){ blockNo -= dev->blockOffset; if (dev->markNANDBlockBad) return dev->markNANDBlockBad(dev, blockNo); else return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);}static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device * dev, int blockNo, yaffs_BlockState * state, unsigned *sequenceNumber){ blockNo -= dev->blockOffset; if (dev->queryNANDBlock) return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber); else return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo, state, sequenceNumber);}static int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, int blockInNAND){ int result; blockInNAND -= dev->blockOffset; dev->nBlockErasures++; result = dev->eraseBlockInNAND(dev, blockInNAND); /* If at first we don't succeed, try again *once*.*/ if (!result) result = dev->eraseBlockInNAND(dev, blockInNAND); return result;}static int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev){ return dev->initialiseNAND(dev);}/* * Temporary buffer manipulations. */static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo){ int i, j; for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { if (dev->tempBuffer[i].line == 0) { dev->tempBuffer[i].line = lineNo; if ((i + 1) > dev->maxTemp) { dev->maxTemp = i + 1; for (j = 0; j <= i; j++) dev->tempBuffer[j].maxLine = dev->tempBuffer[j].line; } return dev->tempBuffer[i].buffer; } } T(YAFFS_TRACE_BUFFERS, (TSTR("Out of temp buffers at line %d, other held by lines:"), lineNo)); for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line)); } T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR))); /* * If we got here then we have to allocate an unmanaged one * This is not good. */ dev->unmanagedTempAllocations++; return YMALLOC(dev->nBytesPerChunk);}static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, int lineNo){ int i; for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { if (dev->tempBuffer[i].buffer == buffer) { dev->tempBuffer[i].line = 0; return; } } if (buffer) { /* assume it is an unmanaged one. */ T(YAFFS_TRACE_BUFFERS, (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR), lineNo)); YFREE(buffer); dev->unmanagedTempDeallocations++; }}/* * Chunk bitmap manipulations */static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device * dev, int blk){ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { T(YAFFS_TRACE_ERROR, (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR), blk)); YBUG(); } return dev->chunkBits + (dev->chunkBitmapStride * (blk - dev->internalStartBlock));}static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device * dev, int blk){ __u8 *blkBits = yaffs_BlockBits(dev, blk); memset(blkBits, 0, dev->chunkBitmapStride);}static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device * dev, int blk, int chunk){ __u8 *blkBits = yaffs_BlockBits(dev, blk); blkBits[chunk / 8] &= ~(1 << (chunk & 7));}static Y_INLINE void yaffs_SetChunkBit(yaffs_Device * dev, int blk, int chunk){ __u8 *blkBits = yaffs_BlockBits(dev, blk); blkBits[chunk / 8] |= (1 << (chunk & 7));}static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device * dev, int blk, int chunk){ __u8 *blkBits = yaffs_BlockBits(dev, blk); return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;}static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device * dev, int blk){ __u8 *blkBits = yaffs_BlockBits(dev, blk); int i; for (i = 0; i < dev->chunkBitmapStride; i++) { if (*blkBits) return 1; blkBits++; } return 0;}/* * Simple hash function. Needs to have a reasonable spread */ static Y_INLINE int yaffs_HashFunction(int n){ return (n % YAFFS_NOBJECT_BUCKETS);}/* * Access functions to useful fake objects */ yaffs_Object *yaffs_Root(yaffs_Device * dev){ return dev->rootDir;}yaffs_Object *yaffs_LostNFound(yaffs_Device * dev){ return dev->lostNFoundDir;}/* * Erased NAND checking functions */ int yaffs_CheckFF(__u8 * buffer, int nBytes){ /* Horrible, slow implementation */ while (nBytes--) { if (*buffer != 0xFF) return 0; buffer++; } return 1;}static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, int chunkInNAND){ int retval = YAFFS_OK; __u8 *data = yaffs_GetTempBuffer(dev, __LINE__); yaffs_ExtendedTags tags; yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags); if (!yaffs_CheckFF(data, dev->nBytesPerChunk) || tags.chunkUsed) { T(YAFFS_TRACE_NANDACCESS, (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND)); retval = YAFFS_FAIL; } yaffs_ReleaseTempBuffer(dev, data, __LINE__); return retval;}static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, const __u8 * data, yaffs_ExtendedTags * tags, int useReserve){ int chunk; int writeOk = 1; int attempts = 0; do { chunk = yaffs_AllocateChunk(dev, useReserve); if (chunk >= 0) { /* First check this chunk is erased... */#ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK writeOk = yaffs_CheckChunkErased(dev, chunk);#endif if (!writeOk) { T(YAFFS_TRACE_ERROR, (TSTR ("**>> yaffs chunk %d was not erased" TENDSTR), chunk)); } else { writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, data, tags); } attempts++; if (writeOk) { /* * Copy the data into the robustification buffer. * NB We do this at the end to prevent duplicates in the case of a write error. * Todo */ yaffs_HandleWriteChunkOk(dev, chunk, data, tags); } else { yaffs_HandleWriteChunkError(dev, chunk); } } } while (chunk >= 0 && !writeOk); if (attempts > 1) { T(YAFFS_TRACE_ERROR, (TSTR("**>> yaffs write required %d attempts" TENDSTR), attempts)); dev->nRetriedWrites += (attempts - 1); } return chunk;}/* * Block retiring for handling a broken block. */ static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND){ yaffs_MarkBlockBad(dev, blockInNAND); yaffs_GetBlockInfo(dev, blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD; dev->nRetiredBlocks++;}/* * Functions for robustisizing TODO * */ static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * tags){}static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, const yaffs_ExtendedTags * tags){}static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND){ int blockInNAND = chunkInNAND / dev->nChunksPerBlock; /* Mark the block for retirement */ yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; /* Delete the chunk */ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);}/*---------------- Name handling functions ------------*/ static __u16 yaffs_CalcNameSum(const YCHAR * name){ __u16 sum = 0; __u16 i = 1; YUCHAR *bname = (YUCHAR *) name; if (bname) { while ((*bname) && (i <= YAFFS_MAX_NAME_LENGTH)) {#ifdef CONFIG_YAFFS_CASE_INSENSITIVE sum += yaffs_toupper(*bname) * i;#else sum += (*bname) * i;#endif i++; bname++; } } return sum;}static void yaffs_SetObjectName(yaffs_Object * obj, const YCHAR * name){#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) { yaffs_strcpy(obj->shortName, name); } else { obj->shortName[0] = _Y('\0'); }#endif obj->sum = yaffs_CalcNameSum(name);}/*-------------------- TNODES ------------------- * List of spare tnodes * The list is hooked together using the first pointer * 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 int yaffs_CreateTnodes(yaffs_Device * dev, int nTnodes){ int i; int tnodeSize; yaffs_Tnode *newTnodes; __u8 *mem; yaffs_Tnode *curr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -