void uffs_flush_all(const char *mount_point)
{
	uffs_Device *dev = NULL;

	dev = uffs_GetDeviceFromMountPoint(mount_point);
	if (dev) {
		uffs_GlobalFsLockLock();
		uffs_BufFlushAll(dev);
		uffs_PutDevice(dev);
		uffs_GlobalFsLockUnlock();
	}
}
Пример #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;
}
Пример #3
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;
	TreeNode *node;
	uffs_Device *dev;
	u16 block;
	uffs_Buf *buf;
	URET ret = U_FAIL;

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

	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 err1;
		}
	}

	uffs_TruncateObject(obj, 0);

	uffs_ObjectDevLock(obj);
	dev = obj->dev;

	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 err;  //have sub dirs ?
		}

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

	block = GET_BLOCK_FROM_NODE(obj);
	node = obj->node;

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

	if (HAVE_BADBLOCK(dev))
		uffs_BadBlockRecover(dev);

	buf = uffs_BufFind(dev, obj->parent, obj->serial, 0);

	if (buf) {
		//need to expire this buffer ...
		if (buf->ref_count != 0) {
			//there is other obj for this file still in use ?
			uffs_Perror(UFFS_ERR_NORMAL, "Try to delete object but still have buf referenced.");
			if (err)
				*err = UEACCES;
			goto err;
		}

		buf->mark = UFFS_BUF_EMPTY; //!< make this buffer expired.
	}

	//TODO: need to take care of other obj->node ?

	uffs_BreakFromEntry(dev, obj->type, node);
	uffs_FlashEraseBlock(dev, block);
	node->u.list.block = block;
	if (HAVE_BADBLOCK(dev))
		uffs_BadBlockProcess(dev, node);
	else
		uffs_TreeInsertToErasedListTail(dev, node);

	ret = U_SUCC;
err:
	uffs_ObjectDevUnLock(obj);
err1:
	do_ReleaseObjectResource(obj);

	uffs_PutObject(obj);

	return ret;
}
URET uffs_FormatDevice(uffs_Device *dev, UBOOL force)
{
	u16 i, slot;
	URET ret = U_SUCC;
	
	if (dev == NULL)
		return U_FAIL;

	if (dev->ops == NULL) 
		return U_FAIL;

	uffs_GlobalFsLockLock();

	ret = uffs_BufFlushAll(dev);

	if (dev->ref_count > 1 && !force) {
		uffs_Perror(UFFS_MSG_NORMAL,
					"can't format when dev->ref_count = %d",
					dev->ref_count);
		ret = U_FAIL;
	}

	if (ret == U_SUCC && force) {
		uffs_DirEntryBufPutAll(dev);
		uffs_PutAllObjectBuf(dev);
		uffs_FdSignatureIncrease();
	}

	if (ret == U_SUCC &&
		uffs_BufIsAllFree(dev) == U_FALSE &&
		!force)
	{
		uffs_Perror(UFFS_MSG_NORMAL, "some page still in used!");
		ret = U_FAIL;
	}

	if (!force) {
		for (slot = 0; ret == U_SUCC && slot < dev->cfg.dirty_groups; slot++) {
			if (dev->buf.dirtyGroup[slot].count > 0) {
				uffs_Perror(UFFS_MSG_SERIOUS, "there still have dirty pages!");
				ret = U_FAIL;
			}
		}
	}

	if (ret == U_SUCC)
		uffs_BufSetAllEmpty(dev);


	if (ret == U_SUCC && uffs_BlockInfoIsAllFree(dev) == U_FALSE && !force) {
		uffs_Perror(UFFS_MSG_NORMAL,
					"there still have block info cache ? fail to format");
		ret = U_FAIL;
	}

	if (ret == U_SUCC)
		uffs_BlockInfoExpireAll(dev);

	for (i = dev->par.start; ret == U_SUCC && i <= dev->par.end; i++) {
		if (uffs_FlashIsBadBlock(dev, i) == U_FALSE) {
			uffs_FlashEraseBlock(dev, i);
			if (HAVE_BADBLOCK(dev))
				uffs_BadBlockProcess(dev, NULL);
		}
		else {
#ifdef CONFIG_ENABLE_BAD_BLOCK_VERIFY
			_ForceFormatAndCheckBlock(dev, i);
#endif
		}
	}

	if (ret == U_SUCC && uffs_TreeRelease(dev) == U_FAIL) {
		ret = U_FAIL;
	}

	if (ret == U_SUCC && uffs_TreeInit(dev) == U_FAIL) {
		ret = U_FAIL;
	}

	if (ret == U_SUCC && uffs_BuildTree(dev) == U_FAIL) {
		ret = U_FAIL;
	}

	uffs_GlobalFsLockUnlock();

	return ret;
}