/** 
 * \brief process bad block: erase bad block, mark it as 'bad' and put the node to bad block list.
 * \param[in] dev uffs device
 * \param[in] node bad block tree node (before the block turn 'bad', it must belong to something ...)
 */
void uffs_BadBlockProcess(uffs_Device *dev, TreeNode *node)
{
	if (HAVE_BADBLOCK(dev)) {
		// mark the bad block
		uffs_FlashMarkBadBlock(dev, dev->bad.block);

		// and put it into bad block list
		if (node != NULL)
			uffs_TreeInsertToBadBlockList(dev, node);

		//clear bad block mark.
		dev->bad.block = UFFS_INVALID_BLOCK;

	}
}
Exemple #2
0
/**
 * \brief delete uffs object
 *
 * \param[in] name full name of object
 * \param[out] err return error code
 *
 * \return U_SUCC if object is deleted successfully. 
 *	return U_FAIL if error happen, error code is set to *err.
 */
URET uffs_DeleteObject(const char * name, int *err)
{
	uffs_Object *obj, *work;
	TreeNode *node, *d_node;
	uffs_Device *dev = NULL;
	u16 block;
	u16 serial, parent, last_serial;
	UBOOL bad = U_FALSE;
	URET ret = U_FAIL;

	obj = uffs_GetObject();
	if (obj == NULL) {
		if (err)
			*err = UEMFILE;
		goto ext_unlock;
	}

	if (uffs_OpenObject(obj, name, UO_RDWR|UO_DIR) == U_FAIL) {
		if (uffs_OpenObject(obj, name, UO_RDWR) == U_FAIL) {
			if (err)
				*err = UENOENT;
			goto ext_unlock;
		}
	}

	dev = obj->dev;

	// working throught object pool see if the object is opened ...
	uffs_ObjectDevLock(obj);
	work = NULL;
	while ((work = (uffs_Object *)uffs_PoolFindNextAllocated(&_object_pool, work)) != NULL) {
		if (work != obj && 
			work->dev &&
			work->dev == obj->dev &&
			work->node &&
			work->node == obj->node) {
			// this object is opened, can't delete it.
			if (err)
				*err = UEACCES;
			goto ext_lock;
		}
	}

	if (obj->type == UFFS_TYPE_DIR) {
		// if the dir is not empty, can't delete it.
		node = uffs_TreeFindDirNodeWithParent(dev, obj->serial);
		if (node != NULL) {
			if (err)
				*err = UEACCES;
			goto ext_lock;  //have sub dirs ?
		}

		node = uffs_TreeFindFileNodeWithParent(dev, obj->serial);
		if (node != NULL) {
			if (err)
				*err = UEACCES;
			goto ext_lock;  //have sub files ?
		}
	}

	// before erase the block, we need to take care of the buffer ...
	uffs_BufFlushAll(dev);

	if (_CheckObjBufRef(obj) > 0) {
		if (err)
			*err = UEACCES;
		goto ext_lock;
	}

	node = obj->node;

	// ok, now we are safe to erase DIR/FILE block :-)
	block = GET_BLOCK_FROM_NODE(obj);
	parent = obj->serial;
	last_serial = (obj->type == UFFS_TYPE_FILE && node->u.file.len > 0 ? GetFdnByOfs(obj, node->u.file.len - 1) : 0);

	uffs_BreakFromEntry(dev, obj->type, node);
	uffs_FlashEraseBlock(dev, block);
	node->u.list.block = block;
	node->u.list.u.serial = obj->serial;

	// From now on, the object is gone physically,
	// but we need to 'suspend' this node so that no one will re-use
	// the serial number during deleting the reset part of object.

	if (HAVE_BADBLOCK(dev)) {
		uffs_BadBlockProcessSuspend(dev, node);
		bad = U_TRUE;  // will be put into 'bad' list later
	}
	else {
		uffs_TreeSuspendAdd(dev, node);
		bad = U_FALSE;	// will be put into erased list later
	}

	// now erase DATA blocks
	if (obj->type == UFFS_TYPE_FILE && last_serial > 0) {
		for (serial = 1; serial <= last_serial; serial++) {

			uffs_ObjectDevUnLock(obj);
			; // yield CPU to improve responsive when deleting large file.
			uffs_ObjectDevLock(obj);

			d_node = uffs_TreeFindDataNode(dev, parent, serial);
			if (uffs_Assert(d_node != NULL, "Can't find DATA node parent = %d, serial = %d\n", parent, serial)) {
				uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, d_node);
				block = d_node->u.data.block;
				uffs_FlashEraseBlock(dev, block);
				d_node->u.list.block = block;
				if (HAVE_BADBLOCK(dev))
					uffs_BadBlockProcess(dev, d_node);
				else
					uffs_TreeInsertToErasedListTail(dev, d_node);
			}
		}
	}
	
	// now process the suspend node
	uffs_TreeRemoveSuspendNode(dev, node);
	if (bad)
		uffs_TreeInsertToBadBlockList(dev, node);
	else
		uffs_TreeInsertToErasedListTail(dev, node);

	ret = U_SUCC;

ext_lock:
	uffs_ObjectDevUnLock(obj);
ext_unlock:
	do_ReleaseObjectResource(obj);

	uffs_PutObject(obj);

	return ret;
}
Exemple #3
0
static URET _BuildTreeStepOne(uffs_Device *dev)
{
	int block_lt;
	uffs_BlockInfo *bc = NULL;
	TreeNode *node;
	struct uffs_TreeSt *tree;
	uffs_Pool *pool;
	struct uffs_MiniHeaderSt header;
	URET ret = U_SUCC;
	struct BlockTypeStatSt st = {0, 0, 0};
	
	tree = &(dev->tree);
	pool = TPOOL(dev);

	tree->bad = NULL;
	tree->bad_count = 0;
	tree->erased = NULL;
	tree->erased_tail = NULL;
	tree->erased_count = 0;

	uffs_Perror(UFFS_MSG_NOISY, "build tree step one");

//	printf("s:%d e:%d\n", dev->par.start, dev->par.end);
	for (block_lt = dev->par.start; block_lt <= dev->par.end; block_lt++) {
		bc = uffs_BlockInfoGet(dev, block_lt);
		if (bc == NULL) {
			uffs_Perror(UFFS_MSG_SERIOUS, "step one:fail to get block info");
			ret = U_FAIL;
			break;
		}
		node = (TreeNode *)uffs_PoolGet(pool);
		if (node == NULL) {
			uffs_Perror(UFFS_MSG_SERIOUS, "insufficient tree node!");
			ret = U_FAIL;
			break;
		}

		// Need to check bad block at first !
		if (uffs_FlashIsBadBlock(dev, block_lt) == U_TRUE) {
			node->u.list.block = block_lt;
			uffs_TreeInsertToBadBlockList(dev, node);
			uffs_Perror(UFFS_MSG_NORMAL, "found bad block %d", block_lt);
		}
		else if (uffs_IsPageErased(dev, bc, 0) == U_TRUE) { //@ read one spare: 0
			// page 0 tag shows it's an erased block, we need to check the mini header status to make sure it is clean.
			if (uffs_LoadMiniHeader(dev, block_lt, 0, &header) == U_FAIL) {
				uffs_Perror(UFFS_MSG_SERIOUS,
							"I/O error when reading mini header !"
							"block %d page %d",
							block_lt, 0);
				ret = U_FAIL;
				break;
			}

			if (header.status != 0xFF) {
				// page 0 tag is clean but page data is dirty ???
				// this block should be erased immediately !
				uffs_FlashEraseBlock(dev, block_lt);
			}
			node->u.list.block = block_lt;
			if (HAVE_BADBLOCK(dev)) {
				uffs_Perror(UFFS_MSG_NORMAL,
							"New bad block (%d) discovered.", block_lt);
				uffs_BadBlockProcess(dev, node);
			}
			else {
				// page 0 is clean does not means all pages in this block are clean,
				// need to check this block later before use it.
				uffs_TreeInsertToErasedListTailEx(dev, node, 1);
			}
		}
		else {
			
			// this block have valid data page(s).

			ret = _ScanAndFixUnCleanPage(dev, bc);
			if (ret == U_FAIL)
				break;

			ret = _BuildValidTreeNode(dev, node, bc, &st);
			if (ret == U_FAIL)
				break;

		}
		uffs_BlockInfoPut(dev, bc);
	} //end of for

	if(ret == U_FAIL) 
		uffs_BlockInfoPut(dev, bc);

	uffs_Perror(UFFS_MSG_NORMAL,
				"DIR %d, FILE %d, DATA %d", st.dir, st.file, st.data);

	return ret;
}