uffs_blockInfo.c

Go to the documentation of this file.
00001 
00007 #include "uffs/uffs_blockInfo.h"
00008 #include "uffs/uffs_public.h"
00009 #include "uffs/uffs_os.h"
00010 
00011 #include <string.h>
00012 
00013 #define PFX "bc:"
00014 
00015 #define UFFS_CLONE_BLOCK_INFO_NEXT ((uffs_blockInfo *)(-2))
00016 
00024 URET uffs_InitBlockInfoCache(uffs_Device *dev, int maxCachedBlocks)
00025 {
00026     u8 * eccs = NULL;
00027     uffs_blockInfo * blockInfos = NULL;
00028     uffs_pageSpare * pageSpares = NULL;
00029     void * buf = NULL;
00030     uffs_blockInfo *work = NULL;
00031     int size, i, j;
00032 
00033     if(dev->bc.head != NULL) {
00034         uffs_Perror(UFFS_ERR_NOISY, PFX"block info cache has been inited already, now release it first.\n");
00035         uffs_ReleaseBlockInfoCache(dev);
00036     }
00037 
00038     size = ( 
00039             sizeof(uffs_blockInfo) +
00040             sizeof(uffs_pageSpare) * dev->attr.pages_per_block
00041             ) * maxCachedBlocks;
00042 
00043     buf = uffs_MemAlloc(dev, size);
00044     memset(buf, 0, size);
00045 
00046     if(!buf) {
00047         uffs_Perror(UFFS_ERR_DEAD, "Alloc block cache buffer fail. size:%d bytes.", size);
00048         return U_FAIL;
00049     }
00050     dev->bc.internalBufHead = buf;
00051     dev->bc.maxBlockCached = maxCachedBlocks;
00052 
00053     size = 0;
00054     blockInfos = (uffs_blockInfo *)buf;
00055     size += sizeof(uffs_blockInfo) * maxCachedBlocks;
00056 
00057     pageSpares = (uffs_pageSpare *)((int)buf + size);
00058 
00059     //initialize block info
00060     work = &(blockInfos[0]);
00061     dev->bc.head = work;
00062     work->refCount = 0;
00063     work->prev = NULL;
00064     work->next = &(blockInfos[1]);
00065     work->blockNum = UFFS_INVALID_BLOCK;
00066 
00067     for( i = 0; i < maxCachedBlocks - 2; i++) {
00068         work = &(blockInfos[i+1]);
00069         work->prev = &(blockInfos[i]);
00070         work->next = &(blockInfos[i+2]);
00071         work->refCount = 0;
00072         work->blockNum = UFFS_INVALID_BLOCK;
00073     }
00074     //the last node
00075     work = &(blockInfos[i+1]);
00076     work->prev = &(blockInfos[i]);
00077     work->next = NULL;
00078     work->blockNum = UFFS_INVALID_BLOCK;
00079     work->refCount = 0;
00080     dev->bc.tail = work;
00081 
00082     //initialize spares
00083     work = dev->bc.head;
00084     for( i = 0; i < maxCachedBlocks; i++) {
00085         work->spares = &(pageSpares[i*dev->attr.pages_per_block]);
00086         for(j = 0; j < dev->attr.pages_per_block; j++) {
00087             work->spares[j].expired = 1;
00088         }
00089         work->expiredCount = dev->attr.pages_per_block;
00090         work = work->next;
00091     }
00092     return U_SUCC;
00093 }
00094 
00100 URET uffs_ReleaseBlockInfoCache(uffs_Device *dev)
00101 {
00102     uffs_blockInfo *work;
00103 
00104     if(dev->bc.head) {
00105         for(work = dev->bc.head; work != NULL; work = work->next) {
00106             if(work->refCount != 0) {
00107                 uffs_Perror(UFFS_ERR_SERIOUS, PFX "There have refed block info cache, release cache fail.\n");
00108                 return U_FAIL;
00109             }
00110         }
00111         uffs_MemFree(dev, dev->bc.internalBufHead);
00112     }
00113 
00114     dev->bc.head = dev->bc.tail = NULL;
00115     dev->bc.internalBufHead = NULL;
00116     return U_SUCC;
00117 }
00118 
00119 static void _BreakBcFromList(uffs_Device *dev, uffs_blockInfo *bc)
00120 {
00121     if(bc->prev) {
00122         bc->prev->next = bc->next;
00123     }
00124     if(bc->next) {
00125         bc->next->prev = bc->prev;
00126     }
00127     if(dev->bc.head == bc) dev->bc.head = bc->next;
00128     if(dev->bc.tail == bc) dev->bc.tail = bc->prev;
00129 }
00130 
00131 static void _InsertToBcListTail(uffs_Device *dev, uffs_blockInfo *bc)
00132 {
00133     bc->next = NULL;
00134     bc->prev = dev->bc.tail;
00135     bc->prev->next = bc;
00136     dev->bc.tail = bc;
00137 }
00138 
00139 static void _MoveBcToTail(uffs_Device *dev, uffs_blockInfo *bc)
00140 {
00141     _BreakBcFromList(dev, bc);
00142     _InsertToBcListTail(dev, bc);
00143 }
00144 
00150 void uffs_CheckPageSpare(uffs_Device *dev, uffs_pageSpare *spare)
00151 {
00152     if(uffs_CalTagCheckSum(&(spare->tag)) == spare->tag.checkSum) {
00153         spare->checkOk = 1;
00154     }
00155     else {
00156         spare->checkOk = 0;
00157     }
00158 }
00159 
00171 URET uffs_LoadBlockInfo(uffs_Device *dev, uffs_blockInfo *work, int page)
00172 {
00173     int i;
00174     uffs_pageSpare *spare;
00175 
00176     if(page == UFFS_ALL_PAGES) {
00177         for(i = 0; i < dev->attr.pages_per_block; i++) {
00178             spare = &(work->spares[i]);
00179             if(spare->expired == 0) continue;
00180             
00181             if( dev->flash->LoadPageSpare(dev, work->blockNum, i, &(spare->tag)) == U_FAIL ) {
00182                 uffs_Perror(UFFS_ERR_SERIOUS, PFX "load block %d page %d spare fail.", work->blockNum, i);
00183                 return U_FAIL;
00184             }
00185             uffs_CheckPageSpare(dev, spare);
00186             spare->expired = 0;
00187             work->expiredCount--;
00188         }
00189     }
00190     else {
00191         if(page < 0 || page >= dev->attr.pages_per_block) {
00192             uffs_Perror(UFFS_ERR_SERIOUS, PFX "page out of range !\n");
00193             return U_FAIL;
00194         }
00195         spare = &(work->spares[page]);
00196         if(spare->expired != 0) {
00197             if( dev->flash->LoadPageSpare(dev, work->blockNum, page, &(spare->tag)) == U_FAIL ) {
00198                 uffs_Perror(UFFS_ERR_SERIOUS, PFX "load block %d page %d spare fail.", work->blockNum, page);
00199                 return U_FAIL;
00200             }
00201             uffs_CheckPageSpare(dev, spare);
00202             spare->expired = 0;
00203             work->expiredCount--;
00204         }
00205     }
00206     return U_SUCC;
00207 }
00208 
00209 
00218 uffs_blockInfo * uffs_FindBlockInfoInCache(uffs_Device *dev, int block)
00219 {
00220     uffs_blockInfo *work;
00221     
00222     //search cached block
00223     for(work = dev->bc.head; work != NULL; work = work->next) {
00224         if(work->blockNum == block) {
00225             work->refCount++;
00226             return work;
00227         }
00228     }
00229     return NULL;
00230 }
00231 
00232 
00243 uffs_blockInfo * uffs_GetBlockInfo(uffs_Device *dev, int block)
00244 {
00245     uffs_blockInfo *work;
00246     int i;
00247 
00248     //search cached block
00249     if((work = uffs_FindBlockInfoInCache(dev, block)) != NULL) {
00250         _MoveBcToTail(dev, work);
00251         return work;
00252     }
00253 
00254     //can't find block from cache, need to find a free(unlocked) cache
00255     for(work = dev->bc.head; work != NULL; work = work->next) {
00256         if(work->refCount == 0) break;
00257     }
00258     if(work == NULL) {
00259         //caches used out !
00260         uffs_Perror(UFFS_ERR_SERIOUS, PFX "insufficient block info cache\n");
00261         return NULL;
00262     }
00263 
00264     work->blockNum = block;
00265     work->expiredCount = dev->attr.pages_per_block;
00266     for(i = 0; i < dev->attr.pages_per_block; i++) {
00267         work->spares[i].expired = 1;
00268     }
00269 
00270     work->refCount = 1;
00271 
00272     _MoveBcToTail(dev, work);
00273 
00274     return work;
00275 }
00276 
00282 void uffs_PutBlockInfo(uffs_Device *dev, uffs_blockInfo *p)
00283 {
00284     if(p->refCount == 0) {
00285         uffs_Perror(UFFS_ERR_SERIOUS, PFX "Put an unused block info cache back ?\n");
00286     }
00287     else {
00288         p->refCount--;
00289     }
00290 }
00291 
00292 
00299 void uffs_ExpireBlockInfo(uffs_Device *dev, uffs_blockInfo *p, int page)
00300 {
00301     int i;
00302     uffs_pageSpare *spare;
00303 
00304     if(page == UFFS_ALL_PAGES) {
00305         for(i = 0; i < dev->attr.pages_per_block; i++) {
00306             spare = &(p->spares[i]);
00307             if(spare->expired == 0) {
00308                 spare->expired = 1;
00309                 p->expiredCount++;
00310             }
00311         }
00312     }
00313     else {
00314         if(page >= 0 && page < dev->attr.pages_per_block) {
00315             spare = &(p->spares[page]);
00316             if(spare->expired == 0) {
00317                 spare->expired = 1;
00318                 p->expiredCount++;
00319             }
00320         }
00321     }
00322 }
00323 
00327 UBOOL uffs_IsAllBlockInfoFree(uffs_Device *dev)
00328 {
00329     uffs_blockInfo *work;
00330 
00331     work = dev->bc.head;
00332     while(work) {
00333         if(work->refCount != 0) return U_FALSE;
00334         work = work->next;
00335     }
00336 
00337     return U_TRUE;
00338 }
00339 
00340 void uffs_ExpireAllBlockInfo(uffs_Device *dev)
00341 {
00342     uffs_blockInfo *bc;
00343 
00344     bc = dev->bc.head;
00345     while(bc) {
00346         uffs_ExpireBlockInfo(dev, bc, UFFS_ALL_PAGES);
00347         bc = bc->next;
00348     }
00349     return;
00350 }

Generated on Sat Mar 17 15:45:44 2007 for uffs-doc by  doxygen 1.5.0