📄 yaffs_guts.c
字号:
/* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * * Copyright (C) 2002-2007 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.82 2009/03/09 04:24:17 charles Exp $";#include "yportenv.h"#include "yaffsinterface.h"#include "yaffs_guts.h"#include "yaffs_tagsvalidity.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"#define YAFFS_PASSIVE_GC_CHUNKS 2#include "yaffs_ecc.h"/* Robustification (if it ever comes about...) */static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, int erasedOk);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_ObjectHasCachedWriteData(yaffs_Object *obj);static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);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 int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, int chunkInNAND);static int yaffs_UnlinkWorker(yaffs_Object *obj);static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject);static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, yaffs_BlockInfo **blockUsedPtr);static void yaffs_VerifyFreeChunks(yaffs_Device *dev);static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);static void yaffs_VerifyDirectory(yaffs_Object *directory);#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);static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode, yaffs_ExtendedTags *tags);static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos);static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId);/* Function to calculate chunk and offset */static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut, __u32 *offsetOut){ int chunk; __u32 offset; chunk = (__u32)(addr >> dev->chunkShift); if (dev->chunkDiv == 1) { /* easy power of 2 case */ offset = (__u32)(addr & dev->chunkMask); } else { /* Non power-of-2 case */ loff_t chunkBase; chunk /= dev->chunkDiv; chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk; offset = (__u32)(addr - chunkBase); } *chunkOut = chunk; *offsetOut = offset;}/* Function to return the number of shifts for a power of 2 greater than or * equal to the given number * Note we don't try to cater for all possible numbers and this does not have to * be hellishly efficient. */static __u32 ShiftsGE(__u32 x){ int extraBits; int nShifts; nShifts = extraBits = 0; while (x > 1) { if (x & 1) extraBits++; x >>= 1; nShifts++; } if (extraBits) nShifts++; return nShifts;}/* Function to return the number of shifts to get a 1 in bit 0 */static __u32 Shifts(__u32 x){ int nShifts; nShifts = 0; if (!x) return 0; while (!(x&1)) { x >>= 1; nShifts++; } return nShifts;}/* * Temporary buffer manipulations. */static int yaffs_InitialiseTempBuffers(yaffs_Device *dev){ int i; __u8 *buf = (__u8 *)1; memset(dev->tempBuffer, 0, sizeof(dev->tempBuffer)); for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { dev->tempBuffer[i].line = 0; /* not in use */ dev->tempBuffer[i].buffer = buf = YMALLOC_DMA(dev->totalBytesPerChunk); } return buf ? YAFFS_OK : YAFFS_FAIL;}__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo){ int i, j; dev->tempInUse++; if (dev->tempInUse > dev->maxTemp) dev->maxTemp = dev->tempInUse; 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->nDataBytesPerChunk);}void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo){ int i; dev->tempInUse--; 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++; }}/* * Determine if we have a managed buffer. */int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer){ int i; for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { if (dev->tempBuffer[i].buffer == buffer) return 1; } for (i = 0; i < dev->nShortOpCaches; i++) { if (dev->srCache[i].data == buffer) return 1; } if (buffer == dev->checkpointBuffer) return 1; T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR))); return 0;}/* * 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_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk){ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock || chunk < 0 || chunk >= dev->nChunksPerBlock) { T(YAFFS_TRACE_ERROR, (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR), blk, chunk)); YBUG(); }}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); yaffs_VerifyChunkBitId(dev, blk, chunk); 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); yaffs_VerifyChunkBitId(dev, blk, chunk); 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); yaffs_VerifyChunkBitId(dev, blk, chunk); 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;}static int yaffs_CountChunkBits(yaffs_Device *dev, int blk){ __u8 *blkBits = yaffs_BlockBits(dev, blk); int i; int n = 0; for (i = 0; i < dev->chunkBitmapStride; i++) { __u8 x = *blkBits; while (x) { if (x & 1) n++; x >>= 1; } blkBits++; } return n;}/* * Verification code */static int yaffs_SkipVerification(yaffs_Device *dev){ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));}static int yaffs_SkipFullVerification(yaffs_Device *dev){ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));}static int yaffs_SkipNANDVerification(yaffs_Device *dev){ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));}static const char *blockStateName[] = {"Unknown","Needs scanning","Scanning","Empty","Allocating","Full","Dirty","Checkpoint","Collecting","Dead"};static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n){ int actuallyUsed; int inUse; if (yaffs_SkipVerification(dev)) return; /* Report illegal runtime states */ if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState)); switch (bi->blockState) { 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, blockStateName[bi->blockState])); } /* Check pages in use and soft deletions are legal */ actuallyUsed = bi->pagesInUse - bi->softDeletions; if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock || bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock || actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock) T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR), n, bi->pagesInUse, bi->softDeletions)); /* Check chunk bitmap legal */ inUse = yaffs_CountChunkBits(dev, n); if (inUse != bi->pagesInUse) T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR), n, bi->pagesInUse, inUse)); /* Check that the sequence number is valid. * Ten million is legal, but is very unlikely */ if (dev->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));}static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n){ yaffs_VerifyBlock(dev, bi, n); /* After collection the block should be in the erased state */ /* This will need to change if we do partial gc */ if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && bi->blockState != YAFFS_BLOCK_STATE_EMPTY) { T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), n, bi->blockState)); }}static void yaffs_VerifyBlocks(yaffs_Device *dev){ int i; int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; int nIllegalBlockStates = 0; if (yaffs_SkipVerification(dev)) return; memset(nBlocksPerState, 0, sizeof(nBlocksPerState)); for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i); yaffs_VerifyBlock(dev, bi, i); if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) nBlocksPerState[bi->blockState]++; else nIllegalBlockStates++; } T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR))); 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))); for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) T(YAFFS_TRACE_VERIFY, (TSTR("%s %d blocks"TENDSTR), blockStateName[i], nBlocksPerState[i])); if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) T(YAFFS_TRACE_VERIFY, (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) T(YAFFS_TRACE_VERIFY, (TSTR("Erased block count wrong dev %d count %d"TENDSTR), dev->nErasedBlocks, 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)));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -