uffs_buf.c

Go to the documentation of this file.
00001 
00008 #include "uffs/uffs_types.h"
00009 #include "uffs/uffs_buf.h"
00010 #include "uffs/uffs_device.h"
00011 #include "uffs/uffs_os.h"
00012 #include "uffs/uffs_public.h"
00013 #include "uffs/ubuffer.h"
00014 #include "uffs/uffs_ecc.h"
00015 #include "uffs/uffs_badblock.h"
00016 #include <string.h>
00017 
00018 #define PFX "pg buf:"
00019 
00020 
00029 URET uffs_BufInit(uffs_Device *dev, int maxBuf, int maxDirtyBuf)
00030 {
00031     void *pool;
00032     u8 *data;
00033     uffs_Buf *buf;
00034     int size;
00035     int i;
00036 
00037     if(!dev) return U_FAIL;
00038 
00039     //init device common parameters, which are needed by page buffers
00040     dev->com.pgSize = dev->attr.page_data_size;
00041     dev->com.eccSize = dev->flash->GetEccSize(dev);
00042     dev->com.pgDataSize = dev->com.pgSize - dev->com.eccSize;
00043 
00044     if(dev->buf.pool != NULL) {
00045         uffs_Perror(UFFS_ERR_NORMAL, PFX"buf.pool is not NULL, buf already inited ?\n");
00046         return U_FAIL;
00047     }
00048     
00049     size = (sizeof(uffs_Buf) + dev->com.pgSize) * maxBuf;
00050     pool = uffs_MemAlloc(dev, size);
00051     if(pool == NULL) {
00052         uffs_Perror(UFFS_ERR_NORMAL, PFX"allocate mem fail!\n");
00053         return U_FAIL;
00054     }
00055 
00056     uffs_Perror(UFFS_ERR_NOISY, PFX"allcate %d bytes.\n", size);
00057     dev->buf.pool = pool;
00058 
00059     data = (u8 *)pool + (sizeof(uffs_Buf) * maxBuf);
00060 
00061     for(i = 0; i < maxBuf; i++) {
00062         buf = (uffs_Buf *)((u8 *)pool + (sizeof(uffs_Buf) * i));
00063         memset(buf, 0, sizeof(uffs_Buf));
00064         data = (u8 *)pool + (sizeof(uffs_Buf) * maxBuf) + (dev->com.pgSize * i);
00065 
00066         buf->data = data;
00067         buf->ecc = data + dev->com.pgDataSize;
00068         buf->mark = UFFS_BUF_EMPTY;
00069         if(i == 0) {
00070             buf->prev = NULL;
00071             dev->buf.bufHead = buf;
00072         }
00073         else {
00074             buf->prev = (uffs_Buf *)((u8 *)buf - sizeof(uffs_Buf));
00075         }
00076 
00077         if(i == maxBuf - 1) {
00078             buf->next = NULL;
00079             dev->buf.bufTail = buf;
00080         }
00081         else {
00082             buf->next = (uffs_Buf *)((u8 *)buf + sizeof(uffs_Buf));
00083         }
00084     }
00085 
00086     dev->buf.maxBuf = maxBuf;
00087     dev->buf.maxDirtyBuf = (maxDirtyBuf > dev->attr.pages_per_block ? dev->attr.pages_per_block : maxDirtyBuf);
00088     dev->buf.dirty = NULL;
00089     dev->buf.dirtyCount = 0;
00090 
00091     return U_SUCC;
00092 }
00093 
00100 URET uffs_BufReleaseAll(uffs_Device *dev)
00101 {
00102     uffs_Buf *p;
00103 
00104     if(!dev) return U_FAIL;
00105 
00106     uffs_DeviceLock(dev);
00107 
00108     //now release all buffer
00109     p = dev->buf.bufHead;
00110     while(p) {
00111         if(p->refCount != 0) {
00112             uffs_Perror(UFFS_ERR_NORMAL, 
00113                 PFX "can't release buffers, \
00114                     father:%d, serial:%d, pageID:%d still in used.\n", p->father, p->serial, p->pageID);
00115             uffs_DeviceUnLock(dev);
00116             return U_FAIL;
00117         }
00118         p = p->next;
00119     }
00120 
00121     if(uffs_BufFlush(dev) != U_SUCC) {
00122         uffs_Perror(UFFS_ERR_NORMAL, PFX"can't release buf, fail to flush buffer\n");
00123         uffs_DeviceUnLock(dev);
00124         return U_FAIL;
00125     }
00126 
00127     uffs_MemFree(dev, dev->buf.pool);
00128     dev->buf.pool = NULL;
00129     dev->buf.bufHead = dev->buf.bufTail = NULL;
00130 
00131     uffs_DeviceUnLock(dev);
00132     return U_SUCC;
00133 }
00134 
00135 
00136 static void _BreakFromBufList(uffs_Device *dev, uffs_Buf *buf)
00137 {
00138     if(buf->next) {
00139         buf->next->prev = buf->prev;
00140     }
00141     if(buf->prev) {
00142         buf->prev->next = buf->next;
00143     }
00144     if(dev->buf.bufHead == buf) {
00145         dev->buf.bufHead = buf->next;
00146     }
00147     if(dev->buf.bufTail == buf) {
00148         dev->buf.bufTail = buf->prev;
00149     }
00150 }
00151 
00152 static void _LinkToBufListHead(uffs_Device *dev, uffs_Buf *buf)
00153 {
00154     if(buf == dev->buf.bufHead) return;
00155     buf->prev = NULL;
00156     buf->next = dev->buf.bufHead;
00157     if(dev->buf.bufHead) dev->buf.bufHead->prev = buf;
00158     if(dev->buf.bufTail == NULL) dev->buf.bufTail = buf;
00159     dev->buf.bufHead = buf;
00160 }
00161 
00162 static void _LinkToBufListTail(uffs_Device *dev, uffs_Buf *buf)
00163 {
00164     if(dev->buf.bufTail == buf) return;
00165     buf->prev = dev->buf.bufTail;
00166     buf->next = NULL;
00167     if(dev->buf.bufTail) dev->buf.bufTail->next = buf;
00168     if(dev->buf.bufHead == NULL) dev->buf.bufHead = buf;
00169     dev->buf.bufTail = buf;
00170 }
00171 
00172 //move a node which linked in the list to the head of list
00173 static void _MoveNodeToHead(uffs_Device *dev, uffs_Buf *p)
00174 {
00175     if(p == dev->buf.bufHead) return;
00176 
00177     //break from list
00178     _BreakFromBufList(dev, p);
00179 
00180     //link to head
00181     _LinkToBufListHead(dev, p);
00182 }
00183 
00184 static void _LinkToDirtyList(uffs_Device *dev, uffs_Buf *buf)
00185 {
00186     if (buf == NULL) {
00187         uffs_Perror(UFFS_ERR_SERIOUS, PFX"Try to insert a NULL node into dirty list ?\n");
00188         return;
00189     }
00190     buf->mark = UFFS_BUF_DIRTY;
00191     buf->prevDirty = NULL;
00192     buf->nextDirty = dev->buf.dirty;
00193     if(dev->buf.dirty) dev->buf.dirty->prevDirty = buf;
00194     dev->buf.dirty = buf;
00195     dev->buf.dirtyCount++;
00196 }
00197 
00198 static uffs_Buf * _FindFreeBuf(uffs_Device *dev)
00199 {
00200     uffs_Buf *buf;
00201 #if 1
00202     buf = dev->buf.bufHead;
00203     while(buf) {
00204         if(buf->refCount == 0 && 
00205             buf->mark != UFFS_BUF_DIRTY) return buf;
00206         buf = buf->next;
00207     }
00208 #else
00209     buf = dev->buf.bufTail;
00210     while(buf) {
00211         if(buf->refCount == 0 &&
00212             buf->mark != UFFS_BUF_DIRTY) return buf;
00213         buf = buf->prev;
00214     }
00215 #endif
00216 
00217     return buf;
00218 }
00219 
00228 URET uffs_LoadPhiDataToBuf(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page)
00229 {
00230     URET ret;
00231 
00232     ret = dev->ops->ReadPageData(dev, block, page, buf->data, 0, dev->com.pgSize);
00233     if(ret == U_SUCC) {
00234         if (uffs_CheckBadBlock(dev, buf, block) == U_SUCC) {
00235             buf->mark = UFFS_BUF_VALID; // the data is valid now
00236         }
00237         else {
00238             buf->mark = UFFS_BUF_EMPTY;
00239             ret = U_FAIL;
00240         }
00241     }
00242     else {
00243         buf->mark = UFFS_BUF_EMPTY; // the data is not valid
00244     }
00245     
00246     return ret;
00247 }
00248 
00258 URET uffs_LoadPhiDataToBufEccUnCare(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page)
00259 {
00260     URET ret;
00261 
00262     ret = dev->ops->ReadPageData(dev, block, page, buf->data, 0, dev->com.pgSize);
00263     if(ret == U_SUCC) {
00264         if (uffs_CheckBadBlock(dev, buf, block) == U_SUCC) {
00265             //ECC check fail, but we return 'successful' anyway !!
00266             buf->mark = UFFS_BUF_VALID;
00267         }
00268         return U_SUCC;
00269     }
00270     else {
00271         buf->mark = UFFS_BUF_EMPTY; // the data is not valid, I/O error ?
00272     }
00273     
00274     return ret;
00275 }
00276 
00277 
00286 uffs_Buf * uffs_BufFind(uffs_Device *dev, u16 father, u16 serial, u16 pageID)
00287 {
00288     uffs_Buf *p = dev->buf.bufHead;
00289 
00290     while(p) {
00291         if( p->father == father &&
00292             p->serial == serial &&
00293             p->pageID == pageID &&
00294             p->mark != UFFS_BUF_EMPTY) {
00295             //they have match one
00296             return p;
00297         }
00298         p = p->next;
00299     }
00300 
00301     return NULL; //buffer not found
00302 }
00303 
00304 static uffs_Buf * _FindBufInDirtyList(uffs_Buf *dirty, u16 pageID)
00305 {
00306     while(dirty) {
00307         if(dirty->pageID == pageID) return dirty;
00308         dirty = dirty->nextDirty;
00309     }
00310     return NULL;
00311 }
00312 
00313 static URET _BreakFromDirty(uffs_Device *dev, uffs_Buf *dirtyBuf)
00314 {
00315     if(dirtyBuf->mark != UFFS_BUF_DIRTY) {
00316         uffs_Perror(UFFS_ERR_NORMAL, PFX"try to break a non-dirty buf from dirty list ?\n");
00317         return U_FAIL;
00318     }
00319 
00320     if(dev->buf.dirty == NULL) {
00321         uffs_Perror(UFFS_ERR_NORMAL, PFX"no dirty list exit ?\n");
00322         return U_FAIL;
00323     }
00324 
00325     if(dirtyBuf->nextDirty) {
00326         dirtyBuf->nextDirty->prevDirty = dirtyBuf->prevDirty;
00327     }
00328     if(dirtyBuf->prevDirty) {
00329         dirtyBuf->prevDirty->nextDirty = dirtyBuf->nextDirty;
00330     }
00331     if(dev->buf.dirty == dirtyBuf) {
00332         //dev->buf.dirty = NULL;
00333         dev->buf.dirty = dirtyBuf->nextDirty;
00334     }
00335 
00336     dev->buf.dirtyCount--;
00337 
00338     return U_SUCC;
00339 }
00340 
00341 static u16 _GetDataSum(uffs_Device *dev, uffs_Buf *buf)
00342 {
00343     u16 dataSum = 0; //default: 0
00344     uffs_fileInfo *fi;
00345 
00346     //FIXME: We use the same schema for both dir and file.
00347     if(buf->type == UFFS_TYPE_FILE || buf->type == UFFS_TYPE_DIR) {
00348         if(buf->pageID == 0) {
00349             fi = (uffs_fileInfo *)(buf->data);
00350             dataSum = uffs_MakeSum16(fi->name, fi->name_len);
00351         }
00352     }
00353 
00354     return dataSum;
00355 }
00356 
00357 
00358 static URET _CheckDirtyList(uffs_Device *dev)
00359 {
00360     uffs_Buf *dirty = dev->buf.dirty;
00361     u16 father;
00362     u16 serial;
00363 
00364     if(dirty == NULL) {
00365         return U_SUCC;
00366     }
00367 
00368     father = dirty->father;
00369     serial = dirty->serial;
00370     dirty = dirty->nextDirty;
00371 
00372     while(dirty) {
00373         if(father != dirty->father ||
00374             serial != dirty->serial) {
00375             uffs_Perror(UFFS_ERR_SERIOUS, PFX"father or serial in dirty pages buffer are not the same ?\n");
00376             return U_FAIL;
00377         }
00378         if(dirty->mark != UFFS_BUF_DIRTY) {
00379             uffs_Perror(UFFS_ERR_SERIOUS, PFX"non-dirty page buffer in dirty buffer list ?\n");
00380             return U_FAIL;
00381         }
00382         dirty = dirty->nextDirty;
00383     }
00384     return U_SUCC;
00385 }
00386 
00388 uffs_Buf * _FindMinimunPageIdFromDirtyList(uffs_Buf *dirtyList)
00389 {
00390     uffs_Buf * work = dirtyList;
00391     uffs_Buf * buf = dirtyList;
00392 
00393     work = work->nextDirty;
00394     while(work) {
00395         if(work->pageID < buf->pageID) buf = work;
00396         work = work->nextDirty;
00397     }
00398     return buf;
00399 }
00400 
00406 static
00407 URET
00408  _BufFlush_Exist_With_Enough_FreePage(
00409         uffs_Device *dev,
00410         uffs_blockInfo *bc, 
00411         u16 freePages       
00412         )       
00413 {
00414     u16 page;
00415     uffs_Buf *buf;
00416     uffs_Tags *tag;
00417     URET ret;
00418 
00419 //  uffs_Perror(UFFS_ERR_NOISY, PFX"Flush buffers with Enough Free Page, in block %d\n",
00420 //                          bc->blockNum);
00421 
00422     for(page = dev->attr.pages_per_block - freePages;   //page: free page num
00423             dev->buf.dirtyCount > 0;                        //still has dirty pages?
00424             page++) {
00425 
00426         buf = _FindMinimunPageIdFromDirtyList(dev->buf.dirty);
00427         if(buf == NULL) {
00428             uffs_Perror(UFFS_ERR_SERIOUS, PFX"dirtyCount > 0, but no dirty pages in list ?\n");
00429             return U_FAIL;
00430         }
00431 
00432         //now a dirty page which has pageID(id) been found
00433         //write to page i
00434         uffs_LoadBlockInfo(dev, bc, page);
00435         tag = &(bc->spares[page].tag);
00436         tag->blockTimeStamp = uffs_GetBlockTimeStamp(dev, bc);
00437         tag->dataLength = buf->dataLen;
00438         tag->type = buf->type;
00439         tag->dataSum = _GetDataSum(dev, buf);
00440         tag->father = buf->father;
00441         tag->serial = buf->serial;
00442         tag->pageID = (u8)(buf->pageID);  //FIX ME!! if page more than 256 in a block
00443         ret = uffs_WriteDataToNewPage(dev, bc->blockNum, page, tag, buf);
00444         if(ret == U_SUCC) {
00445             if(_BreakFromDirty(dev, buf) == U_SUCC) {
00446                 buf->mark = UFFS_BUF_VALID;
00447                 _MoveNodeToHead(dev, buf);
00448             }
00449         }
00450         else{
00451             uffs_Perror(UFFS_ERR_NORMAL, PFX"I/O error <1>?\n");
00452             return U_FAIL;
00453         }
00454     } //end of for
00455     
00456     if(dev->buf.dirty != NULL || dev->buf.dirtyCount != 0) {
00457         uffs_Perror(UFFS_ERR_NORMAL, PFX"still has dirty buffer ?\n");
00458     }
00459     return U_SUCC;
00460 }
00461 
00462 
00471 static URET _BufFlush_NewBlock(uffs_Device *dev)
00472 {
00473     u8 type;
00474     u16 father, serial;
00475     uffs_Buf *dirty, *buf;
00476     TreeNode *node;
00477     u16 i;
00478     uffs_blockInfo *bc;
00479     uffs_Tags *tag;
00480     URET ret;
00481 
00482     dirty = dev->buf.dirty;
00483     type = dirty->type;
00484     father = dirty->father;     //all pages in dirty list have the same type, father and serial
00485     serial = dirty->serial;
00486 
00487 
00488 
00489     node = uffs_GetErased(dev);
00490     if(node == NULL) {
00491         uffs_Perror(UFFS_ERR_NOISY, PFX"no erased block!\n");
00492         return U_FAIL;
00493     }
00494     bc = uffs_GetBlockInfo(dev, node->u.list.block);
00495     if(bc == NULL) {
00496         uffs_Perror(UFFS_ERR_SERIOUS, PFX"get block info fail!\n");
00497         uffs_InsertToErasedListHead(dev, node); //put node back to erased list
00498         return U_FAIL;
00499     }
00500 
00501 //  uffs_Perror(UFFS_ERR_NOISY, PFX"Flush buffers with NewBlock, block %d\n",
00502 //                  bc->blockNum);
00503 
00504     for(i = 0; i < dev->attr.pages_per_block; i++) {
00505         buf = _FindBufInDirtyList(dirty, i);
00506         if(buf == NULL) break;
00507         uffs_LoadBlockInfo(dev, bc, i);
00508         tag = &(bc->spares[i].tag);
00509         tag->blockTimeStamp = uffs_GetFirstBlockTimeStamp();
00510         tag->dataLength = buf->dataLen;
00511         tag->dataSum = _GetDataSum(dev, buf);
00512         tag->type = type;
00513         tag->father = buf->father;
00514         tag->serial = buf->serial;
00515         tag->pageID = (u8)(buf->pageID);    //FIX ME!! if page more than 256 in a block
00516         ret = uffs_WriteDataToNewPage(dev, node->u.list.block, i, tag, buf);
00517         if(ret == U_SUCC) {
00518             if(_BreakFromDirty(dev, buf) == U_SUCC) {
00519                 buf->mark = UFFS_BUF_VALID;
00520                 _MoveNodeToHead(dev, buf);
00521             }
00522         }
00523         else{
00524             uffs_Perror(UFFS_ERR_NORMAL, PFX"I/O error <2>?\n");
00525             uffs_PutBlockInfo(dev, bc);
00526             return U_FAIL;
00527         }
00528     }
00529 
00530     //now, all pages write successful, fix the tree...
00531     switch(type) {
00532     case UFFS_TYPE_DIR:
00533         node->u.dir.block = bc->blockNum;
00534         node->u.dir.father = father;
00535         node->u.dir.serial = serial;
00536         //node->u.dir.pagID = 0;        //dir stored in page 0,  ??
00537         //node->u.dir.ofs = 0;      //TODO!!, for dir, the ofs should be ... ?
00538         node->u.dir.checkSum = bc->spares[0].tag.dataSum; //for dir, the checkSum should be the same as file
00539                                 //FIXME: if we support more than one dir in one block
00540         break;
00541     case UFFS_TYPE_FILE:
00542         node->u.file.block = bc->blockNum;
00543         node->u.file.father = father;
00544         node->u.file.serial = serial;
00545         node->u.file.checkSum = bc->spares[0].tag.dataSum; //for file, the page0 is where fileinfo ...
00546         break;
00547     case UFFS_TYPE_DATA:
00548         node->u.data.block = bc->blockNum;
00549         node->u.data.father = father;
00550         node->u.data.serial = serial;
00551         break;
00552     default:
00553         uffs_Perror(UFFS_ERR_NOISY, PFX"Unknown type %d\n", type);
00554         break;
00555     }
00556 
00557     uffs_InsertNodeToTree(dev, type, node);
00558     uffs_PutBlockInfo(dev, bc);
00559 
00560     return U_SUCC;
00561 }
00562 
00574 static URET _BufFlush_Exist_With_BlockCover(
00575             uffs_Device *dev,
00576             TreeNode *node,     
00577             uffs_blockInfo *bc  
00578             )
00579 {
00580     u16 i;
00581     u8 type, timeStamp;
00582     u16 page, father, serial;
00583     uffs_Buf *dirty, *buf;
00584     TreeNode *newNode;
00585     uffs_blockInfo *newBc;
00586     uffs_Tags *tag, *oldTag;
00587     URET ret = U_SUCC;
00588     u16 newBlock;
00589     UBOOL succRecover = U_TRUE; //TRUE: recover successful, erase old block,
00590                                 //FALSE: fail to recover, erase new block
00591 
00592     dirty = dev->buf.dirty;
00593     type = dirty->type;
00594     father = dirty->father;
00595     serial = dirty->serial;
00596 
00597     newNode = uffs_GetErased(dev);
00598     if(newNode == NULL) {
00599         uffs_Perror(UFFS_ERR_NOISY, PFX"no enough erased block!\n");
00600         return U_FAIL;
00601     }
00602     newBlock = newNode->u.list.block;
00603     newBc = uffs_GetBlockInfo(dev, newBlock);
00604     if(newBc == NULL) {
00605         uffs_Perror(UFFS_ERR_SERIOUS, PFX"get block info fail!\n");
00606         uffs_InsertToErasedListHead(dev, newNode);  //put node back to erased list
00607                                                     //because it doesn't use, so put to head
00608         return U_FAIL;
00609     }
00610 
00611     uffs_LoadBlockInfo(dev, newBc, UFFS_ALL_PAGES);
00612     timeStamp = uffs_GetNextBlockTimeStamp(uffs_GetBlockTimeStamp(dev, bc));
00613 
00614 //  uffs_Perror(UFFS_ERR_NOISY, PFX"Flush buffers with Block Recover, from %d to %d\n", 
00615 //                  bc->blockNum, newBc->blockNum);
00616 
00617     for(i = 0; i < dev->attr.pages_per_block; i++) {
00618         tag = &(newBc->spares[i].tag);
00619         tag->blockTimeStamp = timeStamp;
00620         tag->father = father;
00621         tag->serial = serial;
00622         tag->type = type;
00623         tag->pageID = (u8)i; //now, pageID = page, FIX ME!! if more than 256 pages in a block
00624         
00625         buf = _FindBufInDirtyList(dirty, i);
00626         if(buf != NULL) {
00627             tag->dataLength = buf->dataLen;
00628             tag->dataSum = _GetDataSum(dev, buf);
00629             ret = uffs_WriteDataToNewPage(dev, newBlock, i, tag, buf);
00630             if(ret == U_SUCC) {
00631                 if(_BreakFromDirty(dev, buf) == U_SUCC) {
00632                     buf->mark = UFFS_BUF_VALID;
00633                     _MoveNodeToHead(dev, buf);
00634                 }
00635             }
00636             else{
00637                 uffs_Perror(UFFS_ERR_NORMAL, PFX"I/O error <3>?\n");
00638                 succRecover = U_FALSE;
00639                 break;
00640             }
00641         }
00642         else {
00643             
00644             page = uffs_FindPageInBlockWithPageId(dev, bc, i);
00645             if(page == UFFS_INVALID_PAGE) {
00646                 uffs_ExpireBlockInfo(dev, newBc, i);
00647                 break;  //end of last page, normal break
00648             }
00649             page = uffs_FindBestPageInBlock(dev, bc, page);
00650             
00651             oldTag = &(bc->spares[page].tag);
00652             buf = uffs_BufClone(dev, NULL);
00653             if(buf == NULL) {
00654                 uffs_Perror(UFFS_ERR_SERIOUS, PFX"Can't clone a new buf!\n");
00655                 succRecover = U_FALSE;
00656                 break;
00657             }
00658             ret = uffs_LoadPhiDataToBuf(dev, buf, bc->blockNum, page);
00659             if(ret == U_FAIL) {
00660                 uffs_Perror(UFFS_ERR_SERIOUS, PFX"I/O error ?\n");
00661                 uffs_BufFreeClone(dev, buf);
00662                 break;
00663             }
00664             buf->dataLen = oldTag->dataLength;
00665             if(buf->dataLen > dev->com.pgDataSize) {
00666                 uffs_Perror(UFFS_ERR_NOISY, PFX"data length over flow!!!\n");
00667                 buf->dataLen = dev->com.pgDataSize;
00668             }
00669 
00670             buf->type = type;
00671             buf->father = father;
00672             buf->serial = serial;
00673             buf->dataLen = oldTag->dataLength;
00674             buf->pageID = oldTag->pageID; 
00675 
00676             tag->dataLength = buf->dataLen;
00677             tag->dataSum = _GetDataSum(dev, buf);
00678 
00679             ret = uffs_WriteDataToNewPage(dev, newBlock, i, tag, buf);
00680             uffs_BufFreeClone(dev, buf);
00681             if(ret != U_SUCC) {
00682                 uffs_Perror(UFFS_ERR_NORMAL, PFX"I/O error <4>?\n");
00683                 succRecover = U_FALSE;
00684                 break;
00685             }
00686         }
00687 
00688     } //end of for
00689 
00690     if(succRecover == U_TRUE) {
00691         switch(type) {
00692         case UFFS_TYPE_DIR:
00693             node->u.dir.block = newBlock;
00694             node->u.dir.checkSum = newBc->spares[0].tag.dataSum;
00695             //node->u.dir.ofs = 0; //TODO!! fix me!
00696             //node->u.dir.pagID = 0; //TODO!! fix me!
00697             break;
00698         case UFFS_TYPE_FILE:
00699             node->u.file.block = newBlock;
00700             node->u.file.checkSum = newBc->spares[0].tag.dataSum;
00701             break;
00702         case UFFS_TYPE_DATA:
00703             node->u.data.block = newBlock;
00704             break;
00705         default:
00706             uffs_Perror(UFFS_ERR_SERIOUS, PFX"UNKNOW TYPE\n");
00707             break;
00708         }
00709         newNode->u.list.block = bc->blockNum;
00710         dev->ops->EraseBlock(dev, bc->blockNum);
00711         uffs_InsertToErasedListTail(dev, newNode);
00712         uffs_ExpireBlockInfo(dev, bc, UFFS_ALL_PAGES);
00713     }
00714     else {
00715         uffs_ExpireBlockInfo(dev, newBc, UFFS_ALL_PAGES);
00716         dev->ops->EraseBlock(dev, newBlock);
00717         newNode->u.list.block = newBlock;
00718         uffs_InsertToErasedListTail(dev, newNode);
00719     }
00720 
00721     if(dev->buf.dirty != NULL || dev->buf.dirtyCount != 0) {
00722         uffs_Perror(UFFS_ERR_NORMAL, PFX"still has dirty buffer ?\n");
00723     }
00724 
00725     uffs_PutBlockInfo(dev, newBc);
00726 
00727     return U_SUCC;
00728 }
00729 
00734 URET uffs_BufFlush(struct uffs_DeviceSt *dev)
00735 {
00736     uffs_Buf *dirty;
00737     TreeNode *node;
00738     uffs_blockInfo *bc;
00739     u16 n;
00740     URET ret;
00741     u8 type;
00742     u16 father;
00743     u16 serial;
00744     int block;
00745     
00746     dirty = dev->buf.dirty;
00747     if(dirty == NULL || dev->buf.dirtyCount == 0) {
00748         return U_SUCC;
00749     }
00750 
00751     if(_CheckDirtyList(dev) == U_FAIL) return U_FAIL;
00752 
00753     type = dirty->type;
00754     father = dirty->father;
00755     serial = dirty->serial;
00756 
00757     switch(type) {
00758     case UFFS_TYPE_DIR:
00759         node = uffs_FindDirNodeFromTree(dev, serial);
00760         break;
00761     case UFFS_TYPE_FILE:
00762         node = uffs_FindFileNodeFromTree(dev, serial);
00763         break;
00764     case UFFS_TYPE_DATA:
00765         node = uffs_FindDataNode(dev, father, serial);
00766         break;
00767     default:
00768         uffs_Perror(UFFS_ERR_SERIOUS, PFX"unknown type\n");
00769         return U_FAIL;
00770     }
00771 
00772     if(node == NULL) {
00773         //not found in the tree, need to generate a new block
00774         ret = _BufFlush_NewBlock(dev);
00775     }
00776     else {
00777         switch(type) {
00778         case UFFS_TYPE_DIR:
00779             block = node->u.dir.block;
00780             break;
00781         case UFFS_TYPE_FILE:
00782             block = node->u.file.block;
00783             break;
00784         case UFFS_TYPE_DATA:
00785             block = node->u.data.block;
00786             break;
00787         }
00788         bc = uffs_GetBlockInfo(dev, block);
00789         if(bc == NULL) {
00790             uffs_Perror(UFFS_ERR_SERIOUS, PFX"get block info fail.\n");
00791             return U_FAIL;
00792         }
00793         uffs_LoadBlockInfo(dev, bc, UFFS_ALL_PAGES);
00794         n = uffs_GetFreePagesCount(dev, bc);
00795         if(n >= dev->buf.dirtyCount) {
00796             //The free pages are enough for the dirty pages
00797             ret = _BufFlush_Exist_With_Enough_FreePage(dev, bc, n);
00798         }
00799         else {
00800             ret = _BufFlush_Exist_With_BlockCover(dev, node, bc);
00801         }
00802         uffs_PutBlockInfo(dev, bc);
00803     }
00804 
00805     return ret;
00806 }
00807 
00808 
00809 
00818 uffs_Buf * uffs_BufGet(struct uffs_DeviceSt *dev, u16 father, u16 serial, u16 pageID)
00819 {
00820     uffs_Buf *p;
00821 
00822     //first, check whether the buffer exist in buf list ?
00823     p = uffs_BufFind(dev, father, serial, pageID);
00824 
00825     if(p) {
00826         p->refCount++;
00827         _MoveNodeToHead(dev, p);
00828     }
00829 
00830     return p;
00831 }
00832 
00836 uffs_Buf *uffs_BufNew(struct uffs_DeviceSt *dev, u8 type, u16 father, u16 serial, u16 pageID)
00837 {
00838     uffs_Buf *buf;
00839 
00840     buf = uffs_BufGet(dev, father, serial, pageID);
00841     if(buf) {
00842         uffs_Perror(UFFS_ERR_SERIOUS, PFX"Want to create a new buf, buf found in exist ???!!\n");
00843         return buf;
00844     }
00845 
00846     buf = _FindFreeBuf(dev);
00847     if(buf == NULL) {
00848         uffs_BufFlush(dev);
00849         buf = _FindFreeBuf(dev);
00850         if (buf == NULL) {
00851             uffs_Perror(UFFS_ERR_SERIOUS, PFX"no free page buf!\n");
00852             return NULL;
00853         }
00854     }
00855 
00856     buf->mark = UFFS_BUF_EMPTY;
00857     buf->type = type;
00858     buf->father = father;
00859     buf->serial = serial;
00860     buf->pageID = pageID;
00861     buf->dataLen = 0;
00862     buf->refCount++;
00863     memset(buf->data, 0xff, dev->com.pgSize);
00864 
00865     _MoveNodeToHead(dev, buf);
00866     
00867     return buf; 
00868 }
00869 
00870 
00871 
00882 uffs_Buf *uffs_BufGetEx(struct uffs_DeviceSt *dev, u8 type, TreeNode *node, u16 pageID)
00883 {
00884     uffs_Buf *buf;
00885     u16 father, serial, block, page;
00886     uffs_blockInfo *bc;
00887 
00888     switch(type) {
00889     case UFFS_TYPE_DIR:
00890         father = node->u.dir.father;
00891         serial = node->u.dir.serial;
00892         block = node->u.dir.block;
00893         break;
00894     case UFFS_TYPE_FILE:
00895         father = node->u.file.father;
00896         serial = node->u.file.serial;
00897         block = node->u.file.block;
00898         break;
00899     case UFFS_TYPE_DATA:
00900         father = node->u.data.father;
00901         serial = node->u.data.serial;
00902         block = node->u.data.block;
00903         break;
00904     }
00905 
00906     buf = uffs_BufFind(dev, father, serial, pageID);
00907     if(buf) {
00908         buf->refCount++;
00909         return buf;
00910     }
00911 
00912     buf = _FindFreeBuf(dev);
00913     if(buf == NULL) {
00914         uffs_BufFlush(dev);
00915         buf = _FindFreeBuf(dev);
00916         if (buf == NULL) {
00917             uffs_Perror(UFFS_ERR_SERIOUS, PFX"no free page buf!\n");
00918             return NULL;
00919         }
00920     }
00921 
00922     bc = uffs_GetBlockInfo(dev, block);
00923     if (bc == NULL) {
00924         uffs_Perror(UFFS_ERR_SERIOUS, PFX"Can't get block info!\n");
00925         return NULL;
00926     }
00927     
00928     page = uffs_FindPageInBlockWithPageId(dev, bc, pageID);
00929     if(page == UFFS_INVALID_PAGE) {
00930         uffs_PutBlockInfo(dev, bc);
00931         uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't find right page ?\n");
00932         return NULL;
00933     }
00934     page = uffs_FindBestPageInBlock(dev, bc, page);
00935     uffs_PutBlockInfo(dev, bc);
00936 
00937     buf->mark = UFFS_BUF_EMPTY;
00938     buf->type = type;
00939     buf->father = father;
00940     buf->serial = serial;
00941     buf->pageID = pageID;
00942 
00943     if (uffs_LoadPhiDataToBuf(dev, buf, block, page) == U_FAIL) {
00944         uffs_Perror(UFFS_ERR_SERIOUS, PFX"can't load page from flash !\n");
00945         return NULL;
00946     }
00947 
00948     buf->dataLen = bc->spares[page].tag.dataLength;
00949     buf->mark = UFFS_BUF_VALID;
00950     buf->refCount++;
00951 
00952     _MoveNodeToHead(dev, buf);
00953     
00954     return buf;
00955 
00956 }
00957 
00963 URET uffs_BufPut(uffs_Device *dev, uffs_Buf *buf)
00964 {
00965     if(buf == NULL) {
00966         uffs_Perror(UFFS_ERR_NORMAL, PFX "Can't put an NULL buffer!\n");
00967         return U_FAIL;
00968     }
00969     if(buf->refCount == 0) {
00970         uffs_Perror(UFFS_ERR_NORMAL, PFX "Putting an unused page buffer ? \n");
00971         return U_FAIL;
00972     }
00973 
00974     buf->refCount--;
00975     
00976     return U_SUCC;
00977 }
00978 
00979 
00990 uffs_Buf * uffs_BufClone(uffs_Device *dev, uffs_Buf *buf)
00991 {
00992     uffs_Buf *p;
00993 
00994     p = _FindFreeBuf(dev);
00995     if(p == NULL) {
00996         uffs_Perror(UFFS_ERR_SERIOUS, PFX"no enough free pages for clone!\n");
00997         return NULL;
00998     }
00999     _BreakFromBufList(dev, p);
01000 
01001     if(buf) {
01002         p->father = buf->father;
01003         p->type = buf->type;
01004         p->serial = buf->serial;
01005         p->pageID = buf->pageID;
01006         
01007         p->dataLen = buf->dataLen;
01008         //athough the valid data length is .dataLen,
01009         //but we still need copy the whole buffer, include ecc
01010         memcpy(p->data, buf->data, dev->com.pgSize);
01011     }
01012     p->next = p->prev = NULL;           //because the cloned one is not linked to device buffer
01013     p->nextDirty = p->prevDirty = NULL;
01014     p->refCount = CLONE_BUF_MARK;       //CLONE_BUF_MARK indicates that this is an cloned buffer
01015     return p;
01016 }
01017 
01023 void uffs_BufFreeClone(uffs_Device *dev, uffs_Buf *buf)
01024 {
01025     dev = dev; //make compiler happy
01026     if(!buf) return;
01027 
01028     if(buf->refCount != CLONE_BUF_MARK) {
01029         /* a cloned buffer must have a refCount of CLONE_BUF_MARK */
01030         uffs_Perror(UFFS_ERR_SERIOUS, PFX "Try to release a non-cloned page buffer ?\n");
01031         return;
01032     }
01033     buf->refCount = 0;
01034     buf->mark = UFFS_BUF_EMPTY;
01035     _LinkToBufListTail(dev, buf);
01036 }
01037 
01038 
01039 
01040 UBOOL uffs_BufIsAllFree(struct uffs_DeviceSt *dev)
01041 {
01042     uffs_Buf *buf = dev->buf.bufHead;
01043     while(buf) {
01044         if(buf->refCount != 0) return U_FALSE;
01045         buf = buf->next;
01046     }
01047     return U_TRUE;
01048 }
01049 
01050 UBOOL uffs_BufIsAllEmpty(struct uffs_DeviceSt *dev)
01051 {
01052     uffs_Buf *buf = dev->buf.bufHead;
01053     while(buf) {
01054         if(buf->mark != UFFS_BUF_EMPTY) return U_FALSE;
01055         buf = buf->next;
01056     }
01057     return U_TRUE;
01058 }
01059 
01060 
01061 URET uffs_BufSetAllEmpty(struct uffs_DeviceSt *dev)
01062 {
01063     uffs_Buf *buf = dev->buf.bufHead;
01064     while(buf) {
01065         buf->mark = UFFS_BUF_EMPTY;
01066         buf = buf->next;
01067     }
01068     return U_SUCC;
01069 }
01070 
01071 
01072 void uffs_BufIncRef(uffs_Buf *buf)
01073 {
01074     buf->refCount++;
01075 }
01076 
01077 void uffs_BufDecRef(uffs_Buf *buf)
01078 {
01079     if(buf->refCount > 0) buf->refCount--;
01080 }
01081 
01082 void uffs_BufSetMark(uffs_Buf *buf, int mark)
01083 {
01084     buf->mark = mark;
01085 }
01086 
01087 static UBOOL _IsBufInDirtyList(struct uffs_DeviceSt *dev, uffs_Buf *buf)
01088 {
01089     uffs_Buf *p = dev->buf.dirty;
01090     while(p) {
01091         if(p == buf) return U_TRUE;
01092         p = p->nextDirty;
01093     }
01094     return U_FALSE;
01095 }
01096 
01097 URET uffs_BufWrite(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len)
01098 {
01099     uffs_Buf *dirty;
01100     UBOOL inDirtyList = U_FALSE;
01101 
01102     if(ofs + len > dev->com.pgDataSize) {
01103         uffs_Perror(UFFS_ERR_SERIOUS, PFX"data length out of range! %d+%d\n", ofs, len);
01104         return U_FAIL;
01105     }
01106 
01107     if(dev->buf.dirtyCount > 0) {
01108         dirty = dev->buf.dirty;
01109         inDirtyList = _IsBufInDirtyList(dev, buf);
01110 
01111         if(inDirtyList == U_FALSE) {
01112             //new dirty buffer...
01113             
01114             if(dirty->father != buf->father ||
01115                 dirty->serial != buf->serial ||
01116                 dirty->type != buf->type) {
01117                 //new buf is in different block, flush buffer right now
01118                 if(uffs_BufFlush(dev) != U_SUCC) return U_FAIL;
01119             }
01120         }
01121     }
01122 
01123     memcpy(buf->data + ofs, data, len);
01124     if(ofs + len > buf->dataLen) buf->dataLen = ofs + len;
01125     
01126     if(inDirtyList == U_FALSE) {
01127         _LinkToDirtyList(dev, buf);
01128     }
01129 
01130     if(dev->buf.dirtyCount >= dev->buf.maxDirtyBuf) {
01131         if(uffs_BufFlush(dev) != U_SUCC) {
01132             return U_FAIL;
01133         }
01134     }
01135 
01136     return U_SUCC;
01137 }
01138 
01139 URET uffs_BufRead(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len)
01140 {
01141     u32 readSize;
01142     u32 pgDataSize = dev->com.pgDataSize;
01143 
01144     readSize = (ofs >= pgDataSize ? 0 : (ofs + len >= pgDataSize ? pgDataSize - ofs : len));
01145     if(readSize > 0) memcpy(data, buf->data + ofs, readSize);
01146 
01147     return U_SUCC;
01148 }
01149 
01150 
01151 
01152 
01153 
01154 
01155 
01156 
01157 
01158 
01159 
01160 
01161 

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