⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uffs_buf.c~

📁 nandflash文件系统源代码
💻 C~
📖 第 1 页 / 共 3 页
字号:

	father = dirty->father;
	serial = dirty->serial;
	dirty = dirty->nextDirty;

	while(dirty) {
		if(father != dirty->father ||
			serial != dirty->serial) {
			uffs_Perror(UFFS_ERR_SERIOUS, PFX"father or serial in dirty pages buffer are not the same ?\n");
			return U_FAIL;
		}
		if(dirty->mark != UFFS_BUF_DIRTY) {
			uffs_Perror(UFFS_ERR_SERIOUS, PFX"non-dirty page buffer in dirty buffer list ?\n");
			return U_FAIL;
		}
		dirty = dirty->nextDirty;
	}
	return U_SUCC;
}

/** find a page in dirty list, which has minimum pageID */
uffs_Buf * _FindMinimunPageIdFromDirtyList(uffs_Buf *dirtyList)
{
	uffs_Buf * work = dirtyList;
	uffs_Buf * buf = dirtyList;

	work = work->nextDirty;
	while(work) {
		if(work->pageID < buf->pageID) buf = work;
		work = work->nextDirty;
	}
	return buf;
}

/** 
 * \brief flush buffer to a block with enough free pages 
 *  
 *  pages in dirty list must be sorted by pageID to write to flash
 */
static
URET
 _BufFlush_Exist_With_Enough_FreePage(
		uffs_Device *dev,
		uffs_blockInfo *bc, //!< block info (Source, also destination)
		u16 freePages		//!< free pages number on destination block
		)		
{
	u16 page;
	uffs_Buf *buf;
	uffs_Tags *tag;
	URET ret;

//	uffs_Perror(UFFS_ERR_NOISY, PFX"Flush buffers with Enough Free Page, in block %d\n",
//							bc->blockNum);

	for(page = dev->attr->pages_per_block - freePages;	//page: free page num
			dev->buf.dirtyCount > 0;						//still has dirty pages?
			page++) {

		buf = _FindMinimunPageIdFromDirtyList(dev->buf.dirty);
		if(buf == NULL) {
			uffs_Perror(UFFS_ERR_SERIOUS, PFX"dirtyCount > 0, but no dirty pages in list ?\n");
			return U_FAIL;
		}

		//now a dirty page which has pageID(id) been found
		//write to page i
		uffs_LoadBlockInfo(dev, bc, page);
		tag = &(bc->spares[page].tag);
		tag->blockTimeStamp = uffs_GetBlockTimeStamp(dev, bc);
		tag->dataLength = buf->dataLen;
		tag->type = buf->type;
		tag->dataSum = _GetDataSum(dev, buf);
		tag->father = buf->father;
		tag->serial = buf->serial;
		tag->pageID = (u8)(buf->pageID);  //FIX ME!! if page more than 256 in a block
		ret = uffs_WriteDataToNewPage(dev, bc->blockNum, page, tag, buf);
		if(ret == U_SUCC) {
			if(_BreakFromDirty(dev, buf) == U_SUCC) {
				buf->mark = UFFS_BUF_VALID;
				_MoveNodeToHead(dev, buf);
			}
		}
		else{
			uffs_Perror(UFFS_ERR_NORMAL, PFX"I/O error <1>?\n");
			return U_FAIL;
		}
	} //end of for
	
	if(dev->buf.dirty != NULL || dev->buf.dirtyCount != 0) {
		uffs_Perror(UFFS_ERR_NORMAL, PFX"still has dirty buffer ?\n");
	}
	return U_SUCC;
}


/** 
 * \brief flush buffer to a new block which is not registered in tree
 *
 * Scenario:
 *		1. get a new block
 *		2. write pages in dirty list to new block, sorted by pageID
 *		3. insert new block to tree
 */
static URET _BufFlush_NewBlock(uffs_Device *dev)
{
	u8 type;
	u16 father, serial;
	uffs_Buf *dirty, *buf;
	TreeNode *node;
	u16 i;
	uffs_blockInfo *bc;
	uffs_Tags *tag;
	URET ret;

	dirty = dev->buf.dirty;
	type = dirty->type;
	father = dirty->father;		//all pages in dirty list have the same type, father and serial
	serial = dirty->serial;

	node = uffs_GetErased(dev);
	if(node == NULL) {
		uffs_Perror(UFFS_ERR_NOISY, PFX"no erased block!\n");
		return U_FAIL;
	}
	bc = uffs_GetBlockInfo(dev, node->u.list.block);
	if(bc == NULL) {
		uffs_Perror(UFFS_ERR_SERIOUS, PFX"get block info fail!\n");
		uffs_InsertToErasedListHead(dev, node); //put node back to erased list
		return U_FAIL;
	}

//	uffs_Perror(UFFS_ERR_NOISY, PFX"Flush buffers with NewBlock, block %d\n",
//					bc->blockNum);

	for(i = 0; i < dev->attr->pages_per_block; i++) {
		buf = _FindBufInDirtyList(dev->buf.dirty, i);
		if(buf == NULL) break;
		uffs_LoadBlockInfo(dev, bc, i);
		tag = &(bc->spares[i].tag);
		tag->blockTimeStamp = uffs_GetFirstBlockTimeStamp();
		tag->dataLength = buf->dataLen;
		tag->dataSum = _GetDataSum(dev, buf);
		tag->type = type;
		tag->father = buf->father;
		tag->serial = buf->serial;
		tag->pageID = (u8)(buf->pageID);	//FIX ME!! if page more than 256 in a block
		ret = uffs_WriteDataToNewPage(dev, node->u.list.block, i, tag, buf);
		if(ret == U_SUCC) {
			if(_BreakFromDirty(dev, buf) == U_SUCC) {
				buf->mark = UFFS_BUF_VALID;
				_MoveNodeToHead(dev, buf);
			}
		}
		else{
			uffs_Perror(UFFS_ERR_NORMAL, PFX"I/O error <2>?\n");
			uffs_PutBlockInfo(dev, bc);
			return U_FAIL;
		}
	}

	//now, all pages write successful, fix the tree...
	switch(type) {
	case UFFS_TYPE_DIR:
		node->u.dir.block = bc->blockNum;
		node->u.dir.father = father;
		node->u.dir.serial = serial;
		//node->u.dir.pagID = 0;		//dir stored in page 0,  ??
		//node->u.dir.ofs = 0;		//TODO!!, for dir, the ofs should be ... ?
		node->u.dir.checkSum = bc->spares[0].tag.dataSum; //for dir, the checkSum should be the same as file
								//FIXME: if we support more than one dir in one block
		break;
	case UFFS_TYPE_FILE:
		node->u.file.block = bc->blockNum;
		node->u.file.father = father;
		node->u.file.serial = serial;
		node->u.file.checkSum = bc->spares[0].tag.dataSum; //for file, the page0 is where fileinfo ...
		break;
	case UFFS_TYPE_DATA:
		node->u.data.block = bc->blockNum;
		node->u.data.father = father;
		node->u.data.serial = serial;
		break;
	default:
		uffs_Perror(UFFS_ERR_NOISY, PFX"Unknown type %d\n", type);
		break;
	}

	uffs_InsertNodeToTree(dev, type, node);
	uffs_PutBlockInfo(dev, bc);

	return U_SUCC;
}

/** 
 * \brief flush buffer with block recover
 *
 * Scenario: 
 *		1. get a free (erased) block --> newNode <br>
 *		2. copy from old block ---> oldNode, or copy from dirty list, <br>
 *			sorted by pageID, to new block. Skips the invalid pages when copy pages.<br>
 *		3. erased old block. set new info to oldNode, set newNode->block = old block,<br>
 *			and put newNode to erased list.<br>
 *	\note IT'S IMPORTANT TO KEEP OLD NODE IN THE LIST, so you don't need to update the obj->node :-)
 */
static URET _BufFlush_Exist_With_BlockCover(
			uffs_Device *dev,
			TreeNode *node,		//!< old data node on tree
			uffs_blockInfo *bc	//!< old data block info
			)
{
	u16 i;
	u8 type, timeStamp;
	u16 page, father, serial;
	uffs_Buf *buf;
	TreeNode *newNode;
	uffs_blockInfo *newBc;
	uffs_Tags *tag, *oldTag;
	URET ret = U_SUCC;
	u16 newBlock;
	UBOOL succRecover = U_TRUE; //TRUE: recover successful, erase old block,
								//FALSE: fail to recover, erase new block

	type = dev->buf.dirty->type;
	father = dev->buf.dirty->father;
	serial = dev->buf.dirty->serial;

	newNode = uffs_GetErased(dev);
	if(newNode == NULL) {
		uffs_Perror(UFFS_ERR_NOISY, PFX"no enough erased block!\n");
		return U_FAIL;
	}
	newBlock = newNode->u.list.block;
	newBc = uffs_GetBlockInfo(dev, newBlock);
	if(newBc == NULL) {
		uffs_Perror(UFFS_ERR_SERIOUS, PFX"get block info fail!\n");
		uffs_InsertToErasedListHead(dev, newNode);  //put node back to erased list
													//because it doesn't use, so put to head
		return U_FAIL;
	}

	uffs_LoadBlockInfo(dev, newBc, UFFS_ALL_PAGES);
	timeStamp = uffs_GetNextBlockTimeStamp(uffs_GetBlockTimeStamp(dev, bc));

//	uffs_Perror(UFFS_ERR_NOISY, PFX"Flush buffers with Block Recover, from %d to %d\n", 
//					bc->blockNum, newBc->blockNum);

	for(i = 0; i < dev->attr->pages_per_block; i++) {
		tag = &(newBc->spares[i].tag);
		tag->blockTimeStamp = timeStamp;
		tag->father = father;
		tag->serial = serial;
		tag->type = type;
		tag->pageID = (u8)i; //now, pageID = page, FIX ME!! if more than 256 pages in a block
		
		buf = _FindBufInDirtyList(dev->buf.dirty, i);
		if(buf != NULL) {
			tag->dataLength = buf->dataLen;
			tag->dataSum = _GetDataSum(dev, buf);
			ret = uffs_WriteDataToNewPage(dev, newBlock, i, tag, buf);
			if(ret == U_SUCC) {
				if(_BreakFromDirty(dev, buf) == U_SUCC) {
					buf->mark = UFFS_BUF_VALID;
					_MoveNodeToHead(dev, buf);
				}
			}
			else{
				uffs_Perror(UFFS_ERR_NORMAL, PFX"I/O error <3>?\n");
				succRecover = U_FALSE;
				break;
			}
		}
		else {
			
			page = uffs_FindPageInBlockWithPageId(dev, bc, i);
			if(page == UFFS_INVALID_PAGE) {
				uffs_ExpireBlockInfo(dev, newBc, i);
				break;  //end of last page, normal break
			}
			page = uffs_FindBestPageInBlock(dev, bc, page);
			
			oldTag = &(bc->spares[page].tag);
			buf = uffs_BufClone(dev, NULL);
			if(buf == NULL) {
				uffs_Perror(UFFS_ERR_SERIOUS, PFX"Can't clone a new buf!\n");
				succRecover = U_FALSE;
				break;
			}
			ret = uffs_LoadPhiDataToBuf(dev, buf, bc->blockNum, page);
			if(ret == U_FAIL) {
				uffs_Perror(UFFS_ERR_SERIOUS, PFX"I/O error ?\n");
				uffs_BufFreeClone(dev, buf);
				break;
			}
			buf->dataLen = oldTag->dataLength;
			if(buf->dataLen > dev->com.pgDataSize) {
				uffs_Perror(UFFS_ERR_NOISY, PFX"data length over flow!!!\n");
				buf->dataLen = dev->com.pgDataSize;
			}

			buf->type = type;
			buf->father = father;
			buf->serial = serial;
			buf->dataLen = oldTag->dataLength;
			buf->pageID = oldTag->pageID; 

			tag->dataLength = buf->dataLen;
			tag->dataSum = _GetDataSum(dev, buf);

			ret = uffs_WriteDataToNewPage(dev, newBlock, i, tag, buf);
			uffs_BufFreeClone(dev, buf);
			if(ret != U_SUCC) {
				uffs_Perror(UFFS_ERR_NORMAL, PFX"I/O error <4>?\n");
				succRecover = U_FALSE;
				break;
			}
		}

	} //end of for

	if(succRecover == U_TRUE) {
		switch(type) {
		case UFFS_TYPE_DIR:
			node->u.dir.block = newBlock;
			node->u.dir.checkSum = newBc->spares[0].tag.dataSum;
			//node->u.dir.ofs = 0; //TODO!! fix me!
			//node->u.dir.pagID = 0; //TODO!! fix me!
			break;
		case UFFS_TYPE_FILE:
			node->u.file.block = newBlock;
			node->u.file.checkSum = newBc->spares[0].tag.dataSum;
			break;
		case UFFS_TYPE_DATA:
			node->u.data.block = newBlock;
			break;
		default:
			uffs_Perror(UFFS_ERR_SERIOUS, PFX"UNKNOW TYPE\n");
			break;
		}
		newNode->u.list.block = bc->blockNum;
		dev->ops->EraseBlock(dev, bc->blockNum);
		uffs_InsertToErasedListTail(dev, newNode);
		uffs_ExpireBlockInfo(dev, bc, UFFS_ALL_PAGES);
	}
	else {
		uffs_ExpireBlockInfo(dev, newBc, UFFS_ALL_PAGES);
		dev->ops->EraseBlock(dev, newBlock);
		newNode->u.list.block = newBlock;
		uffs_InsertToErasedListTail(dev, newNode);
	}

	if(dev->buf.dirty != NULL || dev->buf.dirtyCount != 0) {
		uffs_Perror(UFFS_ERR_NORMAL, PFX"still has dirty buffer ?\n");
	}

	uffs_PutBlockInfo(dev, newBc);

	return U_SUCC;
}

URET _BufFlush(struct uffs_DeviceSt *dev, UBOOL force_block_recover)
{
	uffs_Buf *dirty;
	TreeNode *node;
	uffs_blockInfo *bc;
	u16 n;
	URET ret;
	u8 type;
	u16 father;
	u16 serial;
	int block;
	
	dirty = dev->buf.dirty;
	if(dirty == NULL || dev->buf.dirtyCount == 0) {
		return U_SUCC;
	}

	if(_CheckDirtyList(dev) == U_FAIL) return U_FAIL;

	type = dirty->type;
	father = dirty->father;
	serial = dirty->serial;

	switch(type) {
	case UFFS_TYPE_DIR:
		node = uffs_FindDirNodeFromTree(dev, serial);
		break;
	case UFFS_TYPE_FILE:
		node = uffs_FindFileNodeFromTree(dev, serial);
		break;
	case UFFS_TYPE_DATA:
		node = uffs_FindDataNode(dev, father, serial);
		break;
	default:
		uffs_Perror(UFFS_ERR_SERIOUS, PFX"unknown type\n");
		return U_FAIL;
	}

	if(node == NULL) {
		//not found in the tree, need to generate a new block
		ret = _BufFlush_NewBlock(dev);
	}
	else {
		switch(type) {
		case UFFS_TYPE_DIR:
			block = node->u.dir.block;
			break;
		case UFFS_TYPE_FILE:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -