yaffs_checkptrw.c 10 KB

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