/* * 函数功能: 创建一个文件 * 输入参数: 文件名称 * 返回参数: */ int uffs_mkfile(const char *name) { uffs_Object *fp; int ret = 0; int err = 0; fp = uffs_GetObject(); if(fp != NULL) { if(uffs_CreateObject(fp, name, UO_CREATE) != U_SUCC) { err = fp->err; ret = -1; uffs_Perror(UFFS_ERR_NORMAL, "Create %s fail, err: %d", name, uffs_get_error()); } else { uffs_Perror(UFFS_ERR_NORMAL, "Create %s succ.", name); uffs_CloseObject(fp); ret = 0; } uffs_PutObject(fp); } else { err = UEMFILE; ret = -1; } uffs_set_error(-err); return ret; }
/** compare [name] with tree [node] represented object name by loading uffs_FileInfo from storage */ UBOOL uffs_TreeCompareFileName(uffs_Device *dev, const char *name, u32 len, u16 sum, TreeNode *node, int type) { UBOOL matched = U_FALSE; uffs_FileInfo *fi; uffs_Buf *buf; u16 data_sum; buf = uffs_BufGetEx(dev, type, node, 0, 0); if (buf == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "can't get buf !\n "); goto ext; } fi = (uffs_FileInfo *)(buf->data); data_sum = uffs_MakeSum16(fi->name, fi->name_len); if (data_sum != sum) { uffs_Perror(UFFS_MSG_NORMAL, "the obj's sum in storage is different with given sum!"); goto ext; } if (fi->name_len == len) { if(uffs_CompareFileName(fi->name, fi->name_len, name) == U_TRUE) { matched = U_TRUE; } } ext: if (buf) uffs_BufPut(dev, buf); return matched; }
/** * \brief build tree structure from flash * \param[in] dev uffs device */ URET uffs_BuildTree(uffs_Device *dev) { URET ret; /***** step one: scan all page spares, classify DIR/FILE/DATA nodes, check bad blocks/uncompleted(conflicted) blocks as well *****/ /* if the disk is big and full filled of data this step could be the most time consuming .... */ ret = _BuildTreeStepOne(dev); if (ret != U_SUCC) { uffs_Perror(UFFS_MSG_SERIOUS, "build tree step one fail!"); return ret; } /***** step two: randomize the erased blocks, for ware-leveling purpose *****/ /* this step is very fast :) */ ret = _BuildTreeStepTwo(dev); if (ret != U_SUCC) { uffs_Perror(UFFS_MSG_SERIOUS, "build tree step two fail!"); return ret; } /***** step three: check DATA nodes, find orphan nodes and erase them *****/ /* if there are a lot of files and disk is fully filled, this step could be very time consuming ... */ ret = _BuildTreeStepThree(dev); if (ret != U_SUCC) { uffs_Perror(UFFS_MSG_SERIOUS, "build tree step three fail!"); return ret; } return U_SUCC; }
/* * 函数功能: 格式化分区 * 输入参数: 分区名称 * 返回参数: */ int uffs_format(const char *name) { int ret; const char *mount = "/"; uffs_Device *dev; if(name) { mount = name; } dev = uffs_GetDeviceFromMountPoint(mount); if(dev == NULL) { uffs_Perror(UFFS_ERR_NORMAL, "Can't get device from mount point."); } else { if(dev->ref_count == 1) { ret = uffs_FormatDevice(dev); uffs_Perror(UFFS_ERR_NORMAL, "Format %s.",ret==RT_EOK?"succ":"fail"); } else { uffs_Perror(UFFS_ERR_NORMAL, "dev->ref_count: %d, can't format this device.", dev->ref_count); } uffs_PutDevice(dev); } return TRUE; }
/* calculate file length, etc */ static URET _BuildTreeStepThree(uffs_Device *dev) { int i; u16 x; TreeNode *work; TreeNode *node; struct uffs_TreeSt *tree; uffs_Pool *pool; u16 blockSave; TreeNode *cache = NULL; u16 cacheSerial = INVALID_UFFS_SERIAL; tree = &(dev->tree); pool = TPOOL(dev); uffs_Perror(UFFS_MSG_NOISY, "build tree step three"); for (i = 0; i < DATA_NODE_ENTRY_LEN; i++) { x = tree->data_entry[i]; while (x != EMPTY_NODE) { work = FROM_IDX(x, pool); if (work->u.data.parent == cacheSerial) { node = cache; } else { node = uffs_TreeFindFileNode(dev, work->u.data.parent); cache = node; cacheSerial = work->u.data.parent; } if (node == NULL) { x = work->hash_next; //this data block does not belong to any file ? //should be erased. uffs_Perror(UFFS_MSG_NORMAL, "find a orphan data block:%d, " "parent:%d, serial:%d, will be erased!", work->u.data.block, work->u.data.parent, work->u.data.serial); uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, work); blockSave = work->u.data.block; work->u.list.block = blockSave; uffs_FlashEraseBlock(dev, blockSave); if (HAVE_BADBLOCK(dev)) uffs_BadBlockProcess(dev, work); else uffs_TreeInsertToErasedListTail(dev, work); } else { node->u.file.len += work->u.data.len; x = work->hash_next; } } } return U_SUCC; }
/** * \brief check if there are anyone holding buf of this obj. * If no one holding the buffers, expire the buffer. * \return * 0 : no one holding any buf of this obj * >0 : the ref_count of buf which refer to this obj. */ int _CheckObjBufRef(uffs_Object *obj) { uffs_Device *dev = obj->dev; uffs_Buf *buf; TreeNode *node = obj->node; u16 parent, serial, last_serial; // check the DIR or FILE block for (buf = uffs_BufFind(dev, obj->parent, obj->serial, UFFS_ALL_PAGES); buf != NULL; buf = uffs_BufFindFrom(dev, buf->next, obj->parent, obj->serial, UFFS_ALL_PAGES)) { if (buf->ref_count > 0) { // oops ... uffs_Perror(UFFS_MSG_SERIOUS, "someone still hold buf parent = %d, serial = %d, ref_count", obj->parent, obj->serial, buf->ref_count); return buf->ref_count; } else { buf->mark = UFFS_BUF_EMPTY; } } if (buf == NULL || buf->ref_count == 0) { // check the DATA block if (obj->type == UFFS_TYPE_FILE && node->u.file.len > 0) { parent = obj->serial; last_serial = GetFdnByOfs(obj, node->u.file.len - 1); for (serial = 1; serial <= last_serial; serial++) { for (buf = uffs_BufFind(dev, parent, serial, UFFS_ALL_PAGES); buf != NULL; buf = uffs_BufFindFrom(dev, buf->next, parent, serial, UFFS_ALL_PAGES)) { if (buf->ref_count != 0) { // oops ... uffs_Perror(UFFS_MSG_SERIOUS, "someone still hold buf parent = %d, serial = %d, ref_count", parent, serial, buf->ref_count); return buf->ref_count; } else { buf->mark = UFFS_BUF_EMPTY; } } } } } return 0; }
/** * \brief initialize tree buffers * \param[in] dev uffs device */ URET uffs_TreeInit(uffs_Device *dev) { int size; int num; uffs_Pool *pool; int i; size = sizeof(TreeNode); num = dev->par.end - dev->par.start + 1; pool = &(dev->mem.tree_pool); if (dev->mem.tree_nodes_pool_size == 0) { if (dev->mem.malloc) { dev->mem.tree_nodes_pool_buf = dev->mem.malloc(dev, size * num); if (dev->mem.tree_nodes_pool_buf) dev->mem.tree_nodes_pool_size = size * num; } } if (size * num > dev->mem.tree_nodes_pool_size) { uffs_Perror(UFFS_MSG_DEAD, "Tree buffer require %d but only %d available.", size * num, dev->mem.tree_nodes_pool_size); memset(pool, 0, sizeof(uffs_Pool)); return U_FAIL; } uffs_Perror(UFFS_MSG_NOISY, "alloc tree nodes %d bytes.", size * num); uffs_PoolInit(pool, dev->mem.tree_nodes_pool_buf, dev->mem.tree_nodes_pool_size, size, num, U_FALSE); dev->tree.erased = NULL; dev->tree.erased_tail = NULL; dev->tree.erased_count = 0; dev->tree.bad = NULL; dev->tree.bad_count = 0; for (i = 0; i < DIR_NODE_ENTRY_LEN; i++) { dev->tree.dir_entry[i] = EMPTY_NODE; } for (i = 0; i < FILE_NODE_ENTRY_LEN; i++) { dev->tree.file_entry[i] = EMPTY_NODE; } for (i = 0; i < DATA_NODE_ENTRY_LEN; i++) { dev->tree.data_entry[i] = EMPTY_NODE; } dev->tree.max_serial = ROOT_DIR_SERIAL; return U_SUCC; }
static URET _ScanAndFixUnCleanPage(uffs_Device *dev, uffs_BlockInfo *bc) { int page; uffs_Tags *tag; struct uffs_MiniHeaderSt header; /* in most case, the valid block contents fewer free page, so it's better scan from the last page ... to page 1. note: scanning page 0 is not necessary, will check it later. The worse case: read (pages_per_block - 1) * (mini header + spares) ! most case: read one spare. */ for (page = dev->attr->pages_per_block - 1; page > 0; page--) { uffs_BlockInfoLoad(dev, bc, page); tag = GET_TAG(bc, page); if (TAG_IS_SEALED(tag)) break; // tag sealed, no unclean page in this block. if (TAG_IS_DIRTY(tag) || TAG_IS_VALID(tag)) { // tag not sealed but dirty/valid ? uffs_Perror(UFFS_MSG_NORMAL, "unclean page found, block %d page %d", bc->block, page); // ok, an unclean page found. // This unclean page can be identified by tag. // We can leave it as it is, but performing a block recover would be good ? // There won't be another unclean page in this block ... stop here. break; } // now we have a clean tag (all 0xFF ?). Need to check mini header to see if it's an unclean page. if (uffs_LoadMiniHeader(dev, bc->block, page, &header) == U_FAIL) return U_FAIL; if (header.status != 0xFF) { // page data is dirty? this is an unclean page and we should explicitly mark tag as 'dirty and invalid'. // This writing does not violate "no partial program" claim, because we are writing to a clean page spare. uffs_Perror(UFFS_MSG_NORMAL, "unclean page found, block %d page %d, mark it.", bc->block, page); uffs_FlashMarkDirtyPage(dev, bc, page); } } return U_SUCC; }
URET uffs_InitDevice(uffs_Device *dev) { URET ret; ret = uffs_InitDeviceConfig(dev); if (ret != U_SUCC) return U_FAIL; if (dev->mem.init) { if (dev->mem.init(dev) != U_SUCC) { uffs_Perror(UFFS_MSG_SERIOUS, "Init memory allocator fail."); return U_FAIL; } } memset(&(dev->st), 0, sizeof(uffs_FlashStat)); uffs_DeviceInitLock(dev); uffs_BadBlockInit(dev); if (uffs_FlashInterfaceInit(dev) != U_SUCC) { uffs_Perror(UFFS_MSG_SERIOUS, "Can't initialize flash interface !"); goto fail; } uffs_Perror(UFFS_MSG_NOISY, "init page buf"); ret = uffs_BufInit(dev, dev->cfg.page_buffers, dev->cfg.dirty_pages); if (ret != U_SUCC) { uffs_Perror(UFFS_MSG_DEAD, "Initialize page buffers fail"); goto fail; } uffs_Perror(UFFS_MSG_NOISY, "init block info cache"); ret = uffs_BlockInfoInitCache(dev, dev->cfg.bc_caches); if (ret != U_SUCC) { uffs_Perror(UFFS_MSG_DEAD, "Initialize block info fail"); goto fail; } ret = uffs_TreeInit(dev); if (ret != U_SUCC) { uffs_Perror(UFFS_MSG_SERIOUS, "fail to init tree buffers"); goto fail; } ret = uffs_BuildTree(dev); if (ret != U_SUCC) { uffs_Perror(UFFS_MSG_SERIOUS, "fail to build tree"); goto fail; } return U_SUCC; fail: uffs_DeviceReleaseLock(dev); return U_FAIL; }
/** Mark this block as bad block */ URET uffs_FlashMarkBadBlock(uffs_Device *dev, int block) { int ret; uffs_BlockInfo *bc; uffs_Perror(UFFS_MSG_NORMAL, "Mark bad block: %d", block); bc = uffs_BlockInfoGet(dev, block); if (bc) { uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES); // expire this block, just in case it's been cached before uffs_BlockInfoPut(dev, bc); } if (dev->ops->MarkBadBlock) return dev->ops->MarkBadBlock(dev, block) == 0 ? U_SUCC : U_FAIL; #ifdef CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD ret = dev->ops->EraseBlock(dev, block); if (ret != UFFS_FLASH_IO_ERR) { // note: even EraseBlock return UFFS_FLASH_BAD_BLK, // we still process it ... not recommended for most NAND flash. #endif if (dev->ops->WritePageWithLayout) ret = dev->ops->WritePageWithLayout(dev, block, 0, NULL, 0, NULL, NULL); else ret = dev->ops->WritePage(dev, block, 0, NULL, 0, NULL, 0); #ifdef CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD } #endif return ret == UFFS_FLASH_NO_ERR ? U_SUCC : U_FAIL; }
/* * Release resources */ int femu_ReleaseFlash(uffs_Device *dev) { uffs_FileEmu *emu; emu = (uffs_FileEmu *)(dev->attr->_private); emu->initCount--; if (emu->initCount == 0) { uffs_Perror(UFFS_ERR_NORMAL, "femu device release."); if (emu->fp) { fclose(emu->fp); emu->fp = NULL; } if (emu->em_monitor_page) free(emu->em_monitor_page); if (emu->em_monitor_spare) free(emu->em_monitor_spare); emu->em_monitor_page = NULL; emu->em_monitor_spare = NULL; } return 0; }
/** * \brief Find a cached block in cache pool, * if the cached block exist then return the pointer, * if the block does not cached already, find a non-used cache. * if all of cached are used out, return NULL. * \param[in] dev uffs device * \param[in] block block number to be found * \return found block cache buffer * \retval NULL caches used out * \retval non-NULL buffer pointer of given block */ uffs_BlockInfo * uffs_BlockInfoGet(uffs_Device *dev, int block) { uffs_BlockInfo *work; int i; //search cached block if ((work = uffs_BlockInfoFindInCache(dev, block)) != NULL) { _MoveBcToTail(dev, work); return work; } //can't find block from cache, need to find a free(unlocked) cache for (work = dev->bc.head; work != NULL; work = work->next) { if(work->ref_count == 0) break; } if (work == NULL) { //caches used out ! uffs_Perror(UFFS_MSG_SERIOUS, "insufficient block info cache"); return NULL; } work->block = block; work->expired_count = dev->attr->pages_per_block; for (i = 0; i < dev->attr->pages_per_block; i++) { work->spares[i].expired = 1; // TODO: init tag } work->ref_count = 1; _MoveBcToTail(dev, work); return work; }
/** * create a new file on a free block * \param[in] dev uffs device * \param[in] parent parent dir serial num * \param[in] serial serial num of this new file * \param[in] bc block information * \param[in] fi file information * \note parent, serial, bc must be provided before, * and all information in fi should be filled well before. */ URET uffs_CreateNewFile(uffs_Device *dev, u16 parent, u16 serial, uffs_BlockInfo *bc, uffs_FileInfo *fi) { uffs_Tags *tag; uffs_Buf *buf; uffs_BlockInfoLoad(dev, bc, 0); tag = GET_TAG(bc, 0); TAG_PARENT(tag) = parent; TAG_SERIAL(tag) = serial; TAG_DATA_LEN(tag) = sizeof(uffs_FileInfo); buf = uffs_BufGet(dev, parent, serial, 0); if (buf == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "get buf fail."); return U_FAIL; } memcpy(buf->data, fi, TAG_DATA_LEN(tag)); buf->data_len = TAG_DATA_LEN(tag); return uffs_BufPut(dev, buf); }
static URET femu_releaseDevice(uffs_Device *dev) { uffs_FileEmu *emu; uffs_Perror(UFFS_ERR_NORMAL, "femu device release."); emu = (uffs_FileEmu *)(dev->attr->_private); emu->initCount--; if (emu->initCount == 0) { if (emu->fp) { fclose(emu->fp); emu->fp = NULL; } memset(emu, 0, sizeof(uffs_FileEmu)); if (emu->em_monitor_page) free(emu->em_monitor_page); if (emu->em_monitor_spare) free(emu->em_monitor_spare); emu->em_monitor_page = NULL; emu->em_monitor_spare = NULL; } return U_SUCC; }
/** * write data to obj, from obj->pos * * \param[in] obj file obj * \param[in] data data pointer * \param[in] len length of data to be write * * \return bytes wrote to obj */ int uffs_WriteObject(uffs_Object *obj, const void *data, int len) { uffs_Device *dev = obj->dev; TreeNode *fnode = NULL; int remain; u32 pos; int wrote = 0; if (obj == NULL) return 0; if (obj->dev == NULL || obj->open_succ != U_TRUE) { obj->err = UEBADF; return 0; } if (obj->type == UFFS_TYPE_DIR) { uffs_Perror(UFFS_MSG_NOISY, "Can't write to an dir object!"); obj->err = UEACCES; return 0; } if (obj->oflag == UO_RDONLY) { obj->err = UEACCES; // can't write to 'read only' mode opened file return 0; } fnode = obj->node; uffs_ObjectDevLock(obj); if (obj->oflag & UO_APPEND) obj->pos = fnode->u.file.len; else { if (obj->pos > fnode->u.file.len) { // current pos pass over the end of file, need to fill the gap with '\0' pos = obj->pos; // save desired pos obj->pos = fnode->u.file.len; // filling gap from the end of the file. remain = do_WriteObject(obj, NULL, pos - fnode->u.file.len); // Write filling bytes. Note: the filling data does not count as 'wrote' in this write operation. obj->pos = pos - remain; if (remain > 0) // fail to fill the gap ? stop. goto ext; } } remain = do_WriteObject(obj, data, len); wrote = len - remain; obj->pos += wrote; ext: if (HAVE_BADBLOCK(dev)) uffs_BadBlockRecover(dev); uffs_ObjectDevUnLock(obj); uffs_Assert(fnode == obj->node, "obj->node change!\n"); return wrote; }
/** * \brief load page spare data to given block info structure * with given page number * \param[in] dev uffs device * \param[in] work given block info to be filled with * \param[in] page given page number to be read from, * if #UFFS_ALL_PAGES is presented, it will read * all pages, otherwise it will read only one given page. * \return load result * \retval U_SUCC successful * \retval U_FAIL fail to load * \note work->block must be set before load block info */ URET uffs_BlockInfoLoad(uffs_Device *dev, uffs_BlockInfo *work, int page) { int i, ret; uffs_PageSpare *spare; if (page == UFFS_ALL_PAGES) { for (i = 0; i < dev->attr->pages_per_block; i++) { spare = &(work->spares[i]); if (spare->expired == 0) continue; ret = uffs_FlashReadPageTag(dev, work->block, i, &(spare->tag)); if (UFFS_FLASH_HAVE_ERR(ret)) { uffs_Perror(UFFS_MSG_SERIOUS, "load block %d page %d spare fail.", work->block, i); return U_FAIL; } spare->expired = 0; work->expired_count--; } } else { if (page < 0 || page >= dev->attr->pages_per_block) { uffs_Perror(UFFS_MSG_SERIOUS, "page out of range !"); return U_FAIL; } spare = &(work->spares[page]); if (spare->expired != 0) { ret = uffs_FlashReadPageTag(dev, work->block, page, &(spare->tag)); if (UFFS_FLASH_HAVE_ERR(ret)) { uffs_Perror(UFFS_MSG_SERIOUS, "load block %d page %d spare fail.", work->block, page); return U_FAIL; } spare->expired = 0; work->expired_count--; } } return U_SUCC; }
static URET femu_initDevice(uffs_Device *dev) { uffs_Perror(UFFS_ERR_NORMAL, "femu device init."); dev->ops = &emu_flash_ops; /* EMU device operations */ CheckInit(dev); return U_SUCC; }
/** put a new block to the bad block waiting list */ void uffs_BadBlockAdd(uffs_Device *dev, int block) { if (dev->bad.block == block) return; if (dev->bad.block != UFFS_INVALID_BLOCK) uffs_Perror(UFFS_ERR_SERIOUS, "Can't add more then one bad block !"); else dev->bad.block = block; }
URET uffs_InitDevice(uffs_Device *dev) { URET ret; if (dev->mem.init) { if (dev->mem.init(dev) != U_SUCC) { uffs_Perror(UFFS_ERR_SERIOUS, "Init memory allocator fail."); return U_FAIL; } } memset(&(dev->st), 0, sizeof(uffs_FlashStat)); uffs_DeviceInitLock(dev); uffs_BadBlockInit(dev); if (uffs_FlashInterfaceInit(dev) != U_SUCC) { uffs_Perror(UFFS_ERR_SERIOUS, "Can't initialize flash interface !"); goto fail; } uffs_Perror(UFFS_ERR_NOISY, "init page buf"); ret = uffs_BufInit(dev, MAX_PAGE_BUFFERS, MAX_DIRTY_PAGES_IN_A_BLOCK); if (ret != U_SUCC) { uffs_Perror(UFFS_ERR_DEAD, "Initialize page buffers fail"); goto fail; } uffs_Perror(UFFS_ERR_NOISY, "init block info cache"); ret = uffs_BlockInfoInitCache(dev, MAX_CACHED_BLOCK_INFO); if (ret != U_SUCC) { uffs_Perror(UFFS_ERR_DEAD, "Initialize block info fail"); goto fail; } ret = uffs_TreeInit(dev); if (ret != U_SUCC) { uffs_Perror(UFFS_ERR_SERIOUS, "fail to init tree buffers"); goto fail; } ret = uffs_BuildTree(dev); if (ret != U_SUCC) { uffs_Perror(UFFS_ERR_SERIOUS, "fail to build tree"); goto fail; } return U_SUCC; fail: uffs_DeviceReleaseLock(dev); return U_FAIL; }
void uffs_DeviceUnLock(uffs_Device *dev) { dev->lock.counter--; if (dev->lock.counter != 0) { uffs_Perror(UFFS_MSG_NORMAL, "Unlock device, counter %d NOT zero?!", dev->lock.counter); } uffs_SemSignal(dev->lock.sem); }
UBOOL uffs_IsSrcNewerThanObj(int src, int obj) { switch (src - obj) { case 0: uffs_Perror(UFFS_MSG_SERIOUS, "the two block have the same time stamp ?"); break; case 1: case -2: return U_TRUE; case -1: case 2: return U_FALSE; default: uffs_Perror(UFFS_MSG_SERIOUS, "time stamp out of range !"); break; } return U_FALSE; }
void uffs_DeviceLock(uffs_Device *dev) { uffs_SemWait(dev->lock.sem); if (dev->lock.counter != 0) { uffs_Perror(UFFS_MSG_NORMAL, "Lock device, counter %d NOT zero?!", dev->lock.counter); } dev->lock.counter++; }
URET uffs_InitMountTable(void) { struct uffs_MountTableEntrySt *tbl = uffs_GetMountTable(); struct uffs_MountTableEntrySt *work; int dev_num = 0; for (work = tbl; work; work = work->next) { uffs_Perror(UFFS_ERR_NOISY, "init device for mount point %s ...", work->mount); if (work->dev->Init(work->dev) == U_FAIL) { uffs_Perror(UFFS_ERR_SERIOUS, "init device for mount point %s fail", work->mount); return U_FAIL; } work->dev->par.start = work->start_block; if (work->end_block < 0) { work->dev->par.end = work->dev->attr->total_blocks + work->end_block; } else { work->dev->par.end = work->end_block; } uffs_Perror(UFFS_ERR_NOISY, "mount partiton: %d,%d", work->dev->par.start, work->dev->par.end); if (uffs_InitDevice(work->dev) != U_SUCC) { uffs_Perror(UFFS_ERR_SERIOUS, "init device fail !"); return U_FAIL; } work->dev->dev_num = dev_num++; } if (uffs_InitObjectBuf() == U_SUCC) { if (uffs_InitDirEntryBuf() == U_SUCC) { return U_SUCC; } } return U_FAIL; }
URET uffs_ReleaseDevice(uffs_Device *dev) { URET ret; ret = uffs_BlockInfoReleaseCache(dev); if (ret != U_SUCC) { uffs_Perror(UFFS_MSG_SERIOUS, "fail to release block info."); goto ext; } ret = uffs_BufReleaseAll(dev); if (ret != U_SUCC) { uffs_Perror(UFFS_MSG_SERIOUS, "fail to release page buffers"); goto ext; } ret = uffs_TreeRelease(dev); if (ret != U_SUCC) { uffs_Perror(UFFS_MSG_SERIOUS, "fail to release tree buffers!"); goto ext; } ret = uffs_FlashInterfaceRelease(dev); if (ret != U_SUCC) { uffs_Perror(UFFS_MSG_SERIOUS, "fail to release tree buffers!"); goto ext; } if (dev->mem.release) ret = dev->mem.release(dev); if (ret != U_SUCC) { uffs_Perror(UFFS_MSG_SERIOUS, "fail to release memory allocator!"); } uffs_DeviceReleaseLock(dev); ext: return ret; }
/** * \brief flush all buffers */ URET uffs_BufFlushAll(struct uffs_DeviceSt *dev) { int slot; for (slot = 0; slot < dev->cfg.dirty_groups; slot++) { if(_BufFlush(dev, FALSE, slot) != U_SUCC) { uffs_Perror(UFFS_MSG_NORMAL, "fail to flush buffer(slot %d)", slot); return U_FAIL; } } return U_SUCC; }
static URET _BuildTreeStepTwo(uffs_Device *dev) { //Randomise the start point of erased block to implement wear levelling u32 startCount = 0; u32 endPoint; TreeNode *node; uffs_Perror(UFFS_MSG_NOISY, "build tree step two"); endPoint = uffs_GetCurDateTime() % (dev->tree.erased_count + 1); while (startCount < endPoint) { node = uffs_TreeGetErasedNodeNoCheck(dev); if (node == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "No erased block ?"); return U_FAIL; } uffs_TreeInsertToErasedListTailEx(dev, node, -1); startCount++; } return U_SUCC; }
static u16 _GetParentFromNode(u8 type, TreeNode *node) { switch (type) { case UFFS_TYPE_DIR: return node->u.dir.parent; case UFFS_TYPE_FILE: return node->u.file.parent; case UFFS_TYPE_DATA: return node->u.data.parent; } uffs_Perror(UFFS_MSG_SERIOUS, "unkown type, X-parent"); return INVALID_UFFS_SERIAL; }
void uffs_MemSetupStaticAllocator(uffs_MemAllocator *allocator, void *pool, int size) { allocator->buf_start = (char *)pool; allocator->buf_size = size; allocator->pos = 0; allocator->malloc = static_malloc; allocator->free = NULL; //never free memory for static memory allocator uffs_Perror(UFFS_MSG_NOISY, "System static memory: %d bytes", allocator->buf_size); }
static void * static_malloc(struct uffs_DeviceSt *dev, unsigned int size) { struct uffs_memAllocatorSt *mem = &dev->mem; void *p = NULL; size += (size % sizeof(long) ? sizeof(long) - (size % sizeof(long)) : 0); if (mem->buf_size - mem->pos < (int)size) { uffs_Perror(UFFS_MSG_SERIOUS, "Memory alloc failed! (alloc %d, free %d)", size, mem->buf_size - mem->pos); } else { p = mem->buf_start + mem->pos; mem->pos += size; uffs_Perror(UFFS_MSG_NOISY, "0x%p: Allocated %d, free %d", p, size, mem->buf_size - mem->pos); } return p; }
static u16 _GetSerialFromNode(u8 type, TreeNode *node) { switch (type) { case UFFS_TYPE_DIR: return node->u.dir.serial; case UFFS_TYPE_FILE: return node->u.file.serial; case UFFS_TYPE_DATA: return node->u.data.serial; } uffs_Perror(UFFS_MSG_SERIOUS, "unkown type, X-serial"); return INVALID_UFFS_SERIAL; }