yaffs_checkptrw.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /*
  2. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
  3. *
  4. * Copyright (C) 2002-2007 Aleph One Ltd.
  5. * for Toby Churchill Ltd and Brightstar Engineering
  6. *
  7. * Created by Charles Manning <charles@aleph1.co.uk>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. */
  13. const char *yaffs_checkptrw_c_version =
  14. "$Id: yaffs_checkptrw.c,v 1.1 2007/08/13 07:18:33 jsgood Exp $";
  15. #include "yaffs_checkptrw.h"
  16. static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
  17. {
  18. int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
  19. T(YAFFS_TRACE_CHECKPOINT,
  20. (TSTR("checkpt blocks available = %d" TENDSTR),
  21. blocksAvailable));
  22. return (blocksAvailable <= 0) ? 0 : 1;
  23. }
  24. static int yaffs_CheckpointErase(yaffs_Device *dev)
  25. {
  26. int i;
  27. if(!dev->eraseBlockInNAND)
  28. return 0;
  29. T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
  30. dev->internalStartBlock,dev->internalEndBlock));
  31. for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
  32. yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
  33. if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){
  34. T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
  35. if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){
  36. bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
  37. dev->nErasedBlocks++;
  38. dev->nFreeChunks += dev->nChunksPerBlock;
  39. }
  40. else {
  41. dev->markNANDBlockBad(dev,i);
  42. bi->blockState = YAFFS_BLOCK_STATE_DEAD;
  43. }
  44. }
  45. }
  46. dev->blocksInCheckpoint = 0;
  47. return 1;
  48. }
  49. static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
  50. {
  51. int i;
  52. int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
  53. T(YAFFS_TRACE_CHECKPOINT,
  54. (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
  55. dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock));
  56. if(dev->checkpointNextBlock >= 0 &&
  57. dev->checkpointNextBlock <= dev->internalEndBlock &&
  58. blocksAvailable > 0){
  59. for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
  60. yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
  61. if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){
  62. dev->checkpointNextBlock = i + 1;
  63. dev->checkpointCurrentBlock = i;
  64. T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i));
  65. return;
  66. }
  67. }
  68. }
  69. T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
  70. dev->checkpointNextBlock = -1;
  71. dev->checkpointCurrentBlock = -1;
  72. }
  73. static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
  74. {
  75. int i;
  76. yaffs_ExtendedTags tags;
  77. T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
  78. dev->blocksInCheckpoint, dev->checkpointNextBlock));
  79. if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
  80. for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
  81. int chunk = i * dev->nChunksPerBlock;
  82. int realignedChunk = chunk - dev->chunkOffset;
  83. dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags);
  84. T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
  85. i, tags.objectId,tags.sequenceNumber,tags.eccResult));
  86. if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
  87. /* Right kind of block */
  88. dev->checkpointNextBlock = tags.objectId;
  89. dev->checkpointCurrentBlock = i;
  90. dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
  91. dev->blocksInCheckpoint++;
  92. T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
  93. return;
  94. }
  95. }
  96. T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
  97. dev->checkpointNextBlock = -1;
  98. dev->checkpointCurrentBlock = -1;
  99. }
  100. int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
  101. {
  102. /* Got the functions we need? */
  103. if (!dev->writeChunkWithTagsToNAND ||
  104. !dev->readChunkWithTagsFromNAND ||
  105. !dev->eraseBlockInNAND ||
  106. !dev->markNANDBlockBad)
  107. return 0;
  108. if(forWriting && !yaffs_CheckpointSpaceOk(dev))
  109. return 0;
  110. if(!dev->checkpointBuffer)
  111. dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
  112. if(!dev->checkpointBuffer)
  113. return 0;
  114. dev->checkpointPageSequence = 0;
  115. dev->checkpointOpenForWrite = forWriting;
  116. dev->checkpointByteCount = 0;
  117. dev->checkpointSum = 0;
  118. dev->checkpointXor = 0;
  119. dev->checkpointCurrentBlock = -1;
  120. dev->checkpointCurrentChunk = -1;
  121. dev->checkpointNextBlock = dev->internalStartBlock;
  122. /* Erase all the blocks in the checkpoint area */
  123. if(forWriting){
  124. memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
  125. dev->checkpointByteOffset = 0;
  126. return yaffs_CheckpointErase(dev);
  127. } else {
  128. int i;
  129. /* Set to a value that will kick off a read */
  130. dev->checkpointByteOffset = dev->nDataBytesPerChunk;
  131. /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
  132. * going to be way more than we need */
  133. dev->blocksInCheckpoint = 0;
  134. dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
  135. dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
  136. for(i = 0; i < dev->checkpointMaxBlocks; i++)
  137. dev->checkpointBlockList[i] = -1;
  138. }
  139. return 1;
  140. }
  141. int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
  142. {
  143. __u32 compositeSum;
  144. compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
  145. *sum = compositeSum;
  146. return 1;
  147. }
  148. static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
  149. {
  150. int chunk;
  151. int realignedChunk;
  152. yaffs_ExtendedTags tags;
  153. if(dev->checkpointCurrentBlock < 0){
  154. yaffs_CheckpointFindNextErasedBlock(dev);
  155. dev->checkpointCurrentChunk = 0;
  156. }
  157. if(dev->checkpointCurrentBlock < 0)
  158. return 0;
  159. tags.chunkDeleted = 0;
  160. tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
  161. tags.chunkId = dev->checkpointPageSequence + 1;
  162. tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
  163. tags.byteCount = dev->nDataBytesPerChunk;
  164. if(dev->checkpointCurrentChunk == 0){
  165. /* First chunk we write for the block? Set block state to
  166. checkpoint */
  167. yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock);
  168. bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
  169. dev->blocksInCheckpoint++;
  170. }
  171. chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
  172. T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
  173. chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId));
  174. realignedChunk = chunk - dev->chunkOffset;
  175. dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags);
  176. dev->checkpointByteOffset = 0;
  177. dev->checkpointPageSequence++;
  178. dev->checkpointCurrentChunk++;
  179. if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
  180. dev->checkpointCurrentChunk = 0;
  181. dev->checkpointCurrentBlock = -1;
  182. }
  183. memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
  184. return 1;
  185. }
  186. int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
  187. {
  188. int i=0;
  189. int ok = 1;
  190. __u8 * dataBytes = (__u8 *)data;
  191. if(!dev->checkpointBuffer)
  192. return 0;
  193. if(!dev->checkpointOpenForWrite)
  194. return -1;
  195. while(i < nBytes && ok) {
  196. dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
  197. dev->checkpointSum += *dataBytes;
  198. dev->checkpointXor ^= *dataBytes;
  199. dev->checkpointByteOffset++;
  200. i++;
  201. dataBytes++;
  202. dev->checkpointByteCount++;
  203. if(dev->checkpointByteOffset < 0 ||
  204. dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
  205. ok = yaffs_CheckpointFlushBuffer(dev);
  206. }
  207. return i;
  208. }
  209. int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
  210. {
  211. int i=0;
  212. int ok = 1;
  213. yaffs_ExtendedTags tags;
  214. int chunk;
  215. int realignedChunk;
  216. __u8 *dataBytes = (__u8 *)data;
  217. if(!dev->checkpointBuffer)
  218. return 0;
  219. if(dev->checkpointOpenForWrite)
  220. return -1;
  221. while(i < nBytes && ok) {
  222. if(dev->checkpointByteOffset < 0 ||
  223. dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
  224. if(dev->checkpointCurrentBlock < 0){
  225. yaffs_CheckpointFindNextCheckpointBlock(dev);
  226. dev->checkpointCurrentChunk = 0;
  227. }
  228. if(dev->checkpointCurrentBlock < 0)
  229. ok = 0;
  230. else {
  231. chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
  232. dev->checkpointCurrentChunk;
  233. realignedChunk = chunk - dev->chunkOffset;
  234. /* read in the next chunk */
  235. /* printf("read checkpoint page %d\n",dev->checkpointPage); */
  236. dev->readChunkWithTagsFromNAND(dev, realignedChunk,
  237. dev->checkpointBuffer,
  238. &tags);
  239. if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
  240. tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
  241. ok = 0;
  242. dev->checkpointByteOffset = 0;
  243. dev->checkpointPageSequence++;
  244. dev->checkpointCurrentChunk++;
  245. if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
  246. dev->checkpointCurrentBlock = -1;
  247. }
  248. }
  249. if(ok){
  250. *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
  251. dev->checkpointSum += *dataBytes;
  252. dev->checkpointXor ^= *dataBytes;
  253. dev->checkpointByteOffset++;
  254. i++;
  255. dataBytes++;
  256. dev->checkpointByteCount++;
  257. }
  258. }
  259. return i;
  260. }
  261. int yaffs_CheckpointClose(yaffs_Device *dev)
  262. {
  263. if(dev->checkpointOpenForWrite){
  264. if(dev->checkpointByteOffset != 0)
  265. yaffs_CheckpointFlushBuffer(dev);
  266. } else {
  267. int i;
  268. for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
  269. yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]);
  270. if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
  271. bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
  272. else {
  273. // Todo this looks odd...
  274. }
  275. }
  276. YFREE(dev->checkpointBlockList);
  277. dev->checkpointBlockList = NULL;
  278. }
  279. dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
  280. dev->nErasedBlocks -= dev->blocksInCheckpoint;
  281. T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
  282. dev->checkpointByteCount));
  283. if(dev->checkpointBuffer){
  284. /* free the buffer */
  285. YFREE(dev->checkpointBuffer);
  286. dev->checkpointBuffer = NULL;
  287. return 1;
  288. }
  289. else
  290. return 0;
  291. }
  292. int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
  293. {
  294. /* Erase the first checksum block */
  295. T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
  296. if(!yaffs_CheckpointSpaceOk(dev))
  297. return 0;
  298. return yaffs_CheckpointErase(dev);
  299. }