Exemplo n.º 1
0
/**
 * \brief Initializes the memory pool.
 * \param[in] pool memory pool
 * \param[in] mem pool memory
 * \param[in] mem_size size of pool memory
 * \param[in] buf_size size of a single buffer
 * \param[in] num_bufs number of buffers
 * \return Returns U_SUCC if successful.
 */
URET uffs_PoolInit(uffs_Pool *pool,
				   void *mem, u32 mem_size, u32 buf_size, u32 num_bufs)
{
	unsigned int i;
	uffs_PoolEntry *e1, *e2;

	uffs_Assert(pool, "pool missing");
	uffs_Assert(mem, "pool memory missing");
	uffs_Assert(num_bufs > 0, "not enough buffers");
	uffs_Assert(buf_size % sizeof(void *) == 0,
					"buffer size not aligned to pointer size");
	uffs_Assert(mem_size == num_bufs * buf_size,
					"pool memory size is wrong");

	pool->mem = (u8 *)mem;
	pool->buf_size = buf_size;
	pool->num_bufs = num_bufs;
	pool->sem = uffs_SemCreate(1);
	
	uffs_SemWait(pool->sem);

	// Initialize the free_list
	e1 = e2 = pool->free_list = (uffs_PoolEntry *) pool->mem;
	for (i = 1; i < pool->num_bufs; i++) {
		e2 = (uffs_PoolEntry *) (pool->mem + i * pool->buf_size);
		e1->next = e2;
		e1 = e2;
	}
	e2->next = NULL;
	
	uffs_SemSignal(pool->sem);

	return U_SUCC;
}
Exemplo n.º 2
0
static URET uffs_InitDeviceConfig(uffs_Device *dev)
{
    if (dev->cfg.dirty_groups == 0)
        dev->cfg.dirty_groups = MAX_DIRTY_BUF_GROUPS;

    if (!uffs_Assert(dev->cfg.dirty_groups >= 1 && dev->cfg.dirty_groups <= MAX_DIRTY_BUF_GROUPS,
                     "invalid config: dirty_groups = %d\n", dev->cfg.dirty_groups))
        return U_FAIL;

#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR > 0
    dev->cfg.bc_caches = MAX_CACHED_BLOCK_INFO;
    dev->cfg.page_buffers = MAX_PAGE_BUFFERS;
    dev->cfg.dirty_pages = MAX_DIRTY_PAGES_IN_A_BLOCK;
    dev->cfg.reserved_free_blocks = MINIMUN_ERASED_BLOCK;
#else
    if (dev->cfg.bc_caches == 0)
        dev->cfg.bc_caches = MAX_CACHED_BLOCK_INFO;
    if (dev->cfg.page_buffers == 0)
        dev->cfg.page_buffers = MAX_PAGE_BUFFERS;
    if (dev->cfg.dirty_pages == 0)
        dev->cfg.dirty_pages = MAX_DIRTY_PAGES_IN_A_BLOCK;
    if (dev->cfg.reserved_free_blocks == 0)
        dev->cfg.reserved_free_blocks = MINIMUN_ERASED_BLOCK;

    if (!uffs_Assert(dev->cfg.page_buffers - CLONE_BUFFERS_THRESHOLD >= 3, "invalid config: page_buffers = %d\n", dev->cfg.page_buffers))
        return U_FAIL;

#endif
    return U_SUCC;
}
Exemplo n.º 3
0
/**
 * \brief Gets a buffer by index (offset).
 * This method returns a buffer from the memory pool by index.
 * \param[in] pool memory pool
 * \param[in] index index
 * \return Returns a pointer to the buffer.
 */
void *uffs_PoolGetBufByIndex(uffs_Pool *pool, u32 index)
{
	uffs_Assert(pool, "pool missing");
	uffs_Assert(index < pool->num_bufs, "index out of range");

	return (u8 *) pool->mem + index * pool->buf_size;
}
Exemplo n.º 4
0
/**
 * \brief Gets the index (offset) of a buffer.
 * This method returns the index of a buffer from the memory pool.
 * \param[in] pool memory pool
 * \param[in] p buffer to get index from
 * \return Returns the index of the buffer.
 */
u32 uffs_PoolGetIndex(uffs_Pool *pool, void *p)
{
	uffs_Assert(pool, "pool missing");
	uffs_Assert(p >= (void *) pool->mem &&
			p < (void *) (pool->mem + pool->num_bufs * pool->buf_size),
			"pointer out of range");

	return ((u8 *) p - pool->mem) / pool->buf_size;
}
Exemplo n.º 5
0
/** 
 * \brief calculate data length of a file block
 * \param[in] dev uffs device
 * \param[in] bc block info
 */
int uffs_GetBlockFileDataLength(uffs_Device *dev, uffs_BlockInfo *bc, u8 type)
{
	u16 page_id;
	u16 i;
	uffs_Tags *tag;
	int size = 0;
	u16 page;
	u16 lastPage = dev->attr->pages_per_block - 1;

	uffs_BlockInfoLoad(dev, bc, lastPage);
	tag = GET_TAG(bc, lastPage);

	if (TAG_IS_GOOD(tag) && TAG_PAGE_ID(tag) == lastPage) {
		// First try the last page.
		// if it's the full loaded file/data block, then we have a quick path.
		if (type == UFFS_TYPE_FILE) {
			size = dev->com.pg_data_size * (dev->attr->pages_per_block - 2) + TAG_DATA_LEN(tag);
			return size;
		}
		if (type == UFFS_TYPE_DATA) {
			size = dev->com.pg_data_size * (dev->attr->pages_per_block - 1) + TAG_DATA_LEN(tag);
			return size;
		}
	}

	// ok, it's not the full loaded file/data block,
	// need to read all spares....
	uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
	tag = GET_TAG(bc, 0);
	if (uffs_Assert(TAG_IS_GOOD(tag), "block %d page 0 does not have good tag ?", bc->block)) {
		if (TAG_TYPE(tag) == UFFS_TYPE_FILE) {
			page_id = 1;	//In file header block, file data page_id from 1
			i = 1;			//search from page 1
		}
		else {
			page_id = 0;	//in normal file data block, page_id from 0
			i = 0;			//in normal file data block, search from page 0
		}
		for (; i < dev->attr->pages_per_block; i++) {
			tag = GET_TAG(bc, i);
			if (TAG_IS_GOOD(tag)) {
				if (page_id == TAG_PAGE_ID(tag)) {
					page = uffs_FindBestPageInBlock(dev, bc, i);
					if (uffs_Assert(page != UFFS_INVALID_PAGE, "got an invalid page ?")) {
						size += TAG_DATA_LEN(GET_TAG(bc, page));
						page_id++;
					}
				}
			}
		}
	}

	return size;
}
Exemplo n.º 6
0
/**
 * \brief Gets a buffer by index (offset).
 * This method returns a buffer from the memory pool by index.
 * \param[in] pool memory pool
 * \param[in] index index
 * \return Returns a pointer to the buffer.
 */
void *uffs_PoolGetBufByIndex(uffs_Pool *pool, u32 index)
{
	if (!uffs_Assert(pool != NULL, "pool missing") ||
		!uffs_Assert(index < pool->num_bufs,
				"index(%d) out of range(max %d)", index, pool->num_bufs))
	{
		return NULL;
	}

	return (u8 *) pool->mem + index * pool->buf_size;
}
Exemplo n.º 7
0
/**
 * \brief Gets the index (offset) of a buffer.
 * This method returns the index of a buffer from the memory pool.
 * \param[in] pool memory pool
 * \param[in] p buffer to get index from
 * \return Returns the index of the buffer.
 */
u32 uffs_PoolGetIndex(uffs_Pool *pool, void *p)
{
	if (!uffs_Assert(pool != NULL, "pool missing") ||
		!uffs_Assert(p >= (void *) pool->mem &&
			p < (void *) (pool->mem + pool->num_bufs * pool->buf_size),
			"pointer out of range"))
	{
		uffs_Panic();
	}

	return ((u8 *) p - pool->mem) / pool->buf_size;
}
Exemplo n.º 8
0
static void drain_sdata(u8 *data, int len)
{
	uffs_Assert(sizeof(g_sdata_buf) - g_sdata_buf_pointer >= len, "BUG: Serial Data Buffer overdrain !!");
	if (data)
		memcpy(data, g_sdata_buf + g_sdata_buf_pointer, len);
	g_sdata_buf_pointer += len;
}
Exemplo n.º 9
0
static void feed_sdata(const u8 *data, int len)
{
	uffs_Assert(g_sdata_buf_pointer + len <= sizeof(g_sdata_buf), "BUG: Serial Data Buffer overflow !!");
	if (data)
		memcpy(g_sdata_buf + g_sdata_buf_pointer, data, len);
	g_sdata_buf_pointer += len;
}
Exemplo n.º 10
0
Arquivo: uffs_fs.c Projeto: mazj/uffs
/**
 * 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;
}
Exemplo n.º 11
0
static void feed_sdata_constant(u8 val, int num)
{
	if (!uffs_Assert(g_sdata_buf_pointer + num <= sizeof(g_sdata_buf), "BUG: Serial Data Buffer overflow !!"))
		return;

	memset(g_sdata_buf + g_sdata_buf_pointer, val, num);
	g_sdata_buf_pointer += num;
}
Exemplo n.º 12
0
/**
 * \brief Releases the memory pool.
 * \param[in] pool memory pool
 * \return Returns U_SUCC if successful.
 */
URET uffs_PoolRelease(uffs_Pool *pool)
{
	uffs_Assert(pool, "pool missing");
	
	uffs_SemDelete(pool->sem);
	pool->sem = 0;

	return U_SUCC;
}
Exemplo n.º 13
0
/** 
 * \brief given a page, search the block to find
 *			a better page with the same page id
 *
 * \param[in] dev uffs device
 * \param[in] bc block info
 * \param[in] page page number to be compared with
 *
 * \return the better page number, could be the same with the given page.
 *         if the given page does not have good tag, return UFFS_INVALID_PAGE.
 */
u16 uffs_FindBestPageInBlock(uffs_Device *dev, uffs_BlockInfo *bc, u16 page)
{
	int i;
	uffs_Tags *tag, *tag_old;
	u16 lastPage = dev->attr->pages_per_block - 1;

	if (!uffs_Assert(page != UFFS_INVALID_PAGE, "invalid param !"))
		return page;	// just in case ...

	uffs_BlockInfoLoad(dev, bc, page); // load old page
	tag_old = GET_TAG(bc, page);

	if (!uffs_Assert(TAG_IS_GOOD(tag_old), "try to find a invalid page ?"))
		return UFFS_INVALID_PAGE;

	if (page == lastPage)	// already the last page ?
		return page;

	// check for fully loaded block, in which case the given
	// page id is the best page id

	uffs_BlockInfoLoad(dev, bc, lastPage);
	tag = GET_TAG(bc, lastPage);

	if (TAG_IS_GOOD(tag) && TAG_PAGE_ID(tag) == lastPage)
		return page;

	// block not fully loaded, search from bottom to top

	for (i = lastPage; i > page; i--) {
		uffs_BlockInfoLoad(dev, bc, i);
		tag = GET_TAG(bc, i);
		if (TAG_IS_GOOD(tag) &&
			TAG_PAGE_ID(tag) == TAG_PAGE_ID(tag_old) &&
			TAG_PARENT(tag) == TAG_PARENT(tag_old) &&
			TAG_SERIAL(tag) == TAG_SERIAL(tag_old))
		{
			break;
		}
	}

	return i;
}
Exemplo n.º 14
0
/**
 * \brief Get a buffer from the memory pool.
 * This version is locked and should be used when multiple threads access the
 * same memory pool.
 * \param[in] pool memory pool
 * \return Returns a pointer to the buffer or NULL if none is available.
 */
void *uffs_PoolGetLocked(uffs_Pool *pool)
{
	uffs_PoolEntry *e;

	if (!uffs_Assert(pool != NULL, "pool missing"))
		return NULL;

	if (!uffs_Assert(pool->sem != OSSEM_NOT_INITED, "pool semaphore not initialized"))
		return NULL;

	uffs_SemWait(pool->sem);

	e = pool->free_list;
	if (e)
		pool->free_list = e->next;

	uffs_SemSignal(pool->sem);

	return e;
}
Exemplo n.º 15
0
/**
 * \brief Puts a buffer back to the memory pool.
 * This version is locked and should be used when multiple threads access the
 * same memory pool.
 * \param[in] pool memory pool
 * \param[in] p buffer to put back
 * \return Returns 0 if successful.
 */
int uffs_PoolPutLocked(uffs_Pool *pool, void *p)
{
	uffs_PoolEntry *e = (uffs_PoolEntry *)p;

	if (!uffs_Assert(pool != NULL, "pool missing"))
		return -1;

	if (!uffs_Assert(pool->sem != OSSEM_NOT_INITED, "pool semaphore not initialized"))
		return -1;

	if (e) {
		uffs_SemWait(pool->sem);
		e->next = pool->free_list;
		pool->free_list = e;
		uffs_SemSignal(pool->sem);
		return 0;
	}

	return -1;
}
Exemplo n.º 16
0
/**
 * \brief Initializes the memory pool.
 * \param[in] pool memory pool
 * \param[in] mem pool memory
 * \param[in] mem_size size of pool memory
 * \param[in] buf_size size of a single buffer
 * \param[in] num_bufs number of buffers
 * \param[in] lock create semaphore for locking the memory pool
 * \return Returns U_SUCC if successful.
 */
URET uffs_PoolInit(uffs_Pool *pool,
				   void *mem, u32 mem_size, u32 buf_size, u32 num_bufs, UBOOL lock)
{
	unsigned int i;
	uffs_PoolEntry *e1, *e2;

	if (!uffs_Assert(pool != NULL, "pool missing") ||
		!uffs_Assert(mem != NULL, "pool memory missing") ||
		!uffs_Assert(num_bufs > 0, "not enough buffers") ||
		!uffs_Assert(buf_size % sizeof(void *) == 0,
					"buffer size not aligned to pointer size") ||
		!uffs_Assert(mem_size == num_bufs * buf_size,
					"pool memory size is wrong"))
	{
		return U_FAIL;
	}

	pool->mem = (u8 *)mem;
	pool->buf_size = buf_size;
	pool->num_bufs = num_bufs;

	pool->sem = OSSEM_NOT_INITED;
	if (lock) {
		uffs_SemCreate(&pool->sem);
		uffs_SemWait(pool->sem);
	}

	// Initialize the free_list
	e1 = e2 = pool->free_list = (uffs_PoolEntry *) pool->mem;
	for (i = 1; i < pool->num_bufs; i++) {
		e2 = (uffs_PoolEntry *) (pool->mem + i * pool->buf_size);
		e1->next = e2;
		e1 = e2;
	}
	e2->next = NULL;
	
	if (lock)
		uffs_SemSignal(pool->sem);

	return U_SUCC;
}
Exemplo n.º 17
0
/**
 * \brief Releases the memory pool.
 * \param[in] pool memory pool
 * \return Returns U_SUCC if successful.
 */
URET uffs_PoolRelease(uffs_Pool *pool)
{
	if (!uffs_Assert(pool != NULL, "pool missing"))
		return U_FAIL;
	
	if (pool->sem != OSSEM_NOT_INITED) {
		uffs_SemDelete(&pool->sem);
		pool->sem = OSSEM_NOT_INITED;
	}

	return U_SUCC;
}
Exemplo n.º 18
0
/**
 * \brief Get a buffer from the memory pool.
 * \param[in] pool memory pool
 * \return Returns a pointer to the buffer or NULL if none is available.
 */
void *uffs_PoolGet(uffs_Pool *pool)
{
	uffs_PoolEntry *e;

	uffs_Assert(pool, "pool missing");

	e = pool->free_list;
	if (e)
		pool->free_list = e->next;

	return e;
}
Exemplo n.º 19
0
/**
 * \brief Get a buffer from the memory pool.
 * \param[in] pool memory pool
 * \return Returns a pointer to the buffer or NULL if none is available.
 */
void *uffs_PoolGet(uffs_Pool *pool)
{
	uffs_PoolEntry *e;

	if (!uffs_Assert(pool != NULL, "pool missing"))
		return NULL;

	e = pool->free_list;
	if (e)
		pool->free_list = e->next;

	return e;
}
/**
 * make spare from tag and ecc
 *
 * \param[in] dev uffs dev
 * \param[in] ts uffs tag store, NULL if don't pack tag store
 * \param[in] ecc ecc of data, NULL if don't pack ecc
 * \param[out] spare output buffer
 * \note spare buffer size: dev->mem.spare_data_size,
 *		 all unpacked bytes will be inited 0xFF
 */
void uffs_FlashMakeSpare(uffs_Device *dev,
						 const uffs_TagStore *ts, const u8 *ecc, u8* spare)
{
	u8 *p_ts = (u8 *)ts;
	int ts_size = TAG_STORE_SIZE;
	int ecc_size = ECC_SIZE(dev);
	int n;
	const u8 *p;

	if (!uffs_Assert(spare != NULL, "invalid param"))
		return;

	memset(spare, 0xFF, dev->mem.spare_data_size);	// initialize as 0xFF.
	SEAL_BYTE(dev, spare) = 0;						// set seal byte = 0.

	// load ecc
	p = dev->attr->ecc_layout;
	if (p && ecc) {
		while (*p != 0xFF && ecc_size > 0) {
			n = (p[1] > ecc_size ? ecc_size : p[1]);
			memcpy(spare + p[0], ecc, n);
			ecc_size -= n;
			ecc += n;
			p += 2;
		}
	}

	p = dev->attr->data_layout;
	while (*p != 0xFF && ts_size > 0) {
		n = (p[1] > ts_size ? ts_size : p[1]);
		memcpy(spare + p[0], p_ts, n);
		ts_size -= n;
		p_ts += n;
		p += 2;
	}

	uffs_Assert(SEAL_BYTE(dev, spare) == 0, "Make spare fail!");
}
Exemplo n.º 21
0
/**
 * \brief Puts a buffer back to the memory pool.
 * \param[in] pool memory pool
 * \param[in] p buffer to put back
 * \return Returns 0 if successful.
 */
int uffs_PoolPut(uffs_Pool *pool, void *p)
{
	uffs_PoolEntry *e = (uffs_PoolEntry *)p;

	uffs_Assert(pool, "pool missing");

	if (e) {
		e->next = pool->free_list;
		pool->free_list = e;
		return 0;
	}

	return -1;
}
Exemplo n.º 22
0
/**
 * \brief Get a buffer from the memory pool.
 * This version is locked and should be used when multiple threads access the
 * same memory pool.
 * \param[in] pool memory pool
 * \return Returns a pointer to the buffer or NULL if none is available.
 */
void *uffs_PoolGetLocked(uffs_Pool *pool)
{
	uffs_PoolEntry *e;

	uffs_Assert(pool, "pool missing");

	uffs_SemWait(pool->sem);
	e = pool->free_list;
	if (e)
		pool->free_list = e->next;
	uffs_SemSignal(pool->sem);

	return e;
}
Exemplo n.º 23
0
/**
 * \brief Puts a buffer back to the memory pool.
 * This version is locked and should be used when multiple threads access the
 * same memory pool.
 * \param[in] pool memory pool
 * \param[in] p buffer to put back
 * \return Returns 0 if successful.
 */
int uffs_PoolPutLocked(uffs_Pool *pool, void *p)
{
	uffs_PoolEntry *e = (uffs_PoolEntry *)p;

	uffs_Assert(pool, "pool missing");

	if (e) {
		uffs_SemWait(pool->sem);
		e->next = pool->free_list;
		pool->free_list = e;
		uffs_SemSignal(pool->sem);
		return 0;
	}

	return -1;
}
Exemplo n.º 24
0
static int program_sdata(uffs_Device *dev, int block, int page)
{
	uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
	int abs_page;
	struct uffs_StorageAttrSt *attr = dev->attr;
	u8 ecc_buf[RS_ECC_SIZE];
	int writtern;

	// In the real world, MLC controller will generate RS-ECC code in serial data buffer
	// and might start auto programing NAND flash. Here, we use software ECC to emulate RS-ECC.
	memset(ecc_buf, 0xFF, sizeof(ecc_buf));
	uffs_EccMake(g_sdata_buf, attr->page_data_size, ecc_buf);
	feed_sdata(ecc_buf, RS_ECC_SIZE);

	uffs_Assert(g_sdata_buf_pointer == PAGE_FULL_SIZE, "Serial Data Buffer is not fully filled !!");

	abs_page = attr->pages_per_block * block + page;

	fseek(emu->fp, abs_page * PAGE_FULL_SIZE, SEEK_SET);
	writtern = fwrite(g_sdata_buf, 1, PAGE_FULL_SIZE, emu->fp);

	return (writtern == PAGE_FULL_SIZE) ? UFFS_FLASH_NO_ERR : UFFS_FLASH_IO_ERR;
}
Exemplo n.º 25
0
Arquivo: uffs_fs.c Projeto: mazj/uffs
static URET do_FlushObject(uffs_Object *obj)
{
	uffs_Device *dev;
	URET ret = U_SUCC;
	TreeNode *node = NULL;

	dev = obj->dev;
	if (obj->node) {
		node = obj->node;
		if (obj->type == UFFS_TYPE_DIR)
			ret = uffs_BufFlushGroup(dev, obj->node->u.dir.parent,
										obj->node->u.dir.serial);
		else {
			ret = (
				uffs_BufFlushGroupMatchParent(dev, obj->node->u.file.serial) == U_SUCC &&
				uffs_BufFlushGroup(dev, obj->node->u.file.parent, obj->node->u.file.serial) == U_SUCC
				) ? U_SUCC : U_FAIL;
		}
		uffs_Assert(node == obj->node, "obj->node change!\n");
	}

	return ret;
}
Exemplo n.º 26
0
Arquivo: uffs_fs.c Projeto: mazj/uffs
/**
 * \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;
}
Exemplo n.º 27
0
Arquivo: uffs_fs.c Projeto: mazj/uffs
/**
 * read data from obj
 *
 * \param[in] obj uffs object
 * \param[out] data output data buffer
 * \param[in] len required length of data to be read from object->pos
 *
 * \return return bytes of data have been read
 */
int uffs_ReadObject(uffs_Object *obj, void *data, int len)
{
	uffs_Device *dev = obj->dev;
	TreeNode *fnode = NULL;
	u32 remain = len;
	u16 fdn;
	u32 read_start;
	TreeNode *dnode;
	u32 size;
	uffs_Buf *buf;
	u32 blockOfs;
	u16 page_id;
	u8 type;
	u32 pageOfs;

	if (obj == NULL)
		return 0;

	fnode = obj->node;

	if (obj->dev == NULL || obj->open_succ == U_FALSE) {
		obj->err = UEBADF;
		return 0;
	}

	if (obj->type == UFFS_TYPE_DIR) {
		uffs_Perror(UFFS_MSG_NOISY, "Can't read data from a dir object!");
		obj->err = UEBADF;
		return 0;
	}

	if (obj->pos > fnode->u.file.len) {
		return 0; //can't read file out of range
	}

	if (obj->oflag & UO_WRONLY) {
		obj->err = UEACCES;
		return 0;
	}

	uffs_ObjectDevLock(obj);

	while (remain > 0) {
		read_start = obj->pos + len - remain;
		if (read_start >= fnode->u.file.len) {
			//uffs_Perror(UFFS_MSG_NOISY, "read point out of file ?");
			break;
		}

		fdn = GetFdnByOfs(obj, read_start);
		if (fdn == 0) {
			dnode = obj->node;
			type = UFFS_TYPE_FILE;
		}
		else {
			type = UFFS_TYPE_DATA;
			dnode = uffs_TreeFindDataNode(dev, fnode->u.file.serial, fdn);
			if (dnode == NULL) {
				uffs_Perror(UFFS_MSG_SERIOUS, "can't get data node in entry!");
				obj->err = UEUNKNOWN_ERR;
				break;
			}
		}

		blockOfs = GetStartOfDataBlock(obj, fdn);
		page_id = (read_start - blockOfs) / dev->com.pg_data_size;

		if (fdn == 0) {
			/**
			 * fdn == 0: this means that the reading is start from the first block,
			 * since the page 0 is for file attr, so we move to the next page ID.
			 */
			page_id++;
		}

		buf = uffs_BufGetEx(dev, type, dnode, (u16)page_id, obj->oflag);
		if (buf == NULL) {
			uffs_Perror(UFFS_MSG_SERIOUS, "can't get buffer when read obj.");
			obj->err = UEIOERR;
			break;
		}

		pageOfs = read_start % dev->com.pg_data_size;
		if (pageOfs >= buf->data_len) {
			//uffs_Perror(UFFS_MSG_NOISY, "read data out of page range ?");
			uffs_BufPut(dev, buf);
			break;
		}
		size = (remain + pageOfs > buf->data_len ? buf->data_len - pageOfs : remain);

		uffs_BufRead(dev, buf, (u8 *)data + len - remain, pageOfs, size);
		uffs_BufPut(dev, buf);

		remain -= size;
	}

	obj->pos += (len - remain);

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

	uffs_ObjectDevUnLock(obj);

	uffs_Assert(fnode == obj->node, "obj->node change!\n");

	return len - remain;
}
Exemplo n.º 28
0
Arquivo: uffs_fs.c Projeto: mazj/uffs
//
// To trancate the file, this is the last block to be trancated.
// We need to discard one or more pages within this block, hence requires 'block recover'.
//
static URET do_TruncateInternalWithBlockRecover(uffs_Object *obj,
												u16 fdn, u32 remain, RunOptionE run_opt)
{
	uffs_Device *dev = obj->dev;
	TreeNode *fnode = obj->node;
	u16 page_id, max_page_id;
	TreeNode *node;
	uffs_Buf *buf = NULL;
	u8 type;
	u32 block_start, block_offset;
	u16 parent, serial;
	int slot;
	uffs_BlockInfo *bc = NULL;
	int block = -1;

	if (fdn == 0) {
		node = fnode;
		type = UFFS_TYPE_FILE;
		max_page_id = obj->head_pages;
		block_start = 0;
		parent = node->u.file.parent;
		serial = node->u.file.serial;
		block = node->u.file.block;
	}
	else {
		node = uffs_TreeFindDataNode(dev, fnode->u.file.serial, fdn);
		if (node == NULL) {
			obj->err = UEIOERR;
			uffs_Perror(UFFS_MSG_SERIOUS,
						"can't find data node when truncate obj");
			goto ext;
		}
		block = node->u.data.block;
		type = UFFS_TYPE_DATA;
		max_page_id = dev->attr->pages_per_block - 1;
		block_start = obj->head_pages * dev->com.pg_data_size +
						(fdn - 1) * dev->com.pg_data_size *
						dev->attr->pages_per_block;
		parent = node->u.data.parent;
		serial = node->u.data.serial;
	}

	if (run_opt == eDRY_RUN) {
		// checking the buffer. this is the main reason why we need the 'dry run' mode.
		for (page_id = 0; page_id <= max_page_id; page_id++) {
			buf = uffs_BufFind(dev, parent, serial, page_id);
			if (buf) {
				//!< ok, the buffer was loaded before ...
				if (uffs_BufIsFree(buf) == U_FALSE) {
					obj->err = UEEXIST;
					break;	//!< and someone is still holding the buffer,
							//   can't truncate it !!!
				}
			}
		}
		buf = NULL;
		goto ext;
	}
	
	// find the last page *after* truncate
	block_offset = remain - block_start;
	page_id = block_offset / dev->com.pg_data_size;
	if (fdn == 0)
		page_id++;

	if (!uffs_Assert(page_id <= max_page_id, "fdn = %d, block_start = %d, remain = %d\n", fdn, block_start, remain)) {
		obj->err = UEUNKNOWN_ERR;
		goto ext;
	}

	// flush buffer before performing block recovery
	uffs_BufFlushGroup(dev, parent, serial);

	// load the last page
	buf = uffs_BufGetEx(dev, type, node, page_id, obj->oflag);
	if (buf == NULL) {
		obj->err = UENOMEM;
		uffs_Perror(UFFS_MSG_SERIOUS, "Can't get buf");
		goto ext;
	}

	uffs_BufWrite(dev, buf, NULL, 0, 0); // just make this buf dirty

	// lock the group
	slot = uffs_BufFindGroupSlot(dev, parent, serial);
	uffs_BufLockGroup(dev, slot);

	if (remain == 0) // remain == 0: means discard all data in this block.
		buf->data_len = 0;
	else {
		remain = (remain % dev->com.pg_data_size);
		// remain == 0: means that we need to keep all data in this page.
		buf->data_len = (remain == 0 ? dev->com.pg_data_size : remain);
	}

	/* mark this buf as UFFS_BUF_EXT_MARK_TRUNC_TAIL, when flushing
		dirty buffers, UFFS will not do page recover for pages after
		this buf page id (because this file is ended at this page) */
	buf->ext_mark |= UFFS_BUF_EXT_MARK_TRUNC_TAIL;

	uffs_BufPut(dev, buf);

	// invalidate the rest page buf
	page_id++;
	for (; page_id <= max_page_id; page_id++) {
		buf = uffs_BufFind(dev, parent, serial, page_id);
		if (buf)
			uffs_BufMarkEmpty(dev, buf);
	}

	// flush dirty buffer immediately, forcing block recovery.
	uffs_BufFlushGroupEx(dev, parent, serial, U_TRUE);

	// unlock the group
	uffs_BufUnLockGroup(dev, slot);

	// Invalidate block info cache for the 'old' block
	bc = uffs_BlockInfoGet(dev, block);
	if (bc) {
		uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
		uffs_BlockInfoPut(dev, bc);
	}

ext:
	return (obj->err == UENOERR ? U_SUCC : U_FAIL);
}
Exemplo n.º 29
0
Arquivo: uffs_fs.c Projeto: mazj/uffs
/** truncate obj without lock device */
static URET do_TruncateObject(uffs_Object *obj, u32 remain, RunOptionE run_opt)
{
	uffs_Device *dev = obj->dev;
	TreeNode *fnode = obj->node;
	u16 fdn;
	u32 flen;
	u32 block_start;
	TreeNode *node;
	uffs_BlockInfo *bc;
	uffs_Buf *buf;
	u16 page;
	int pos;

	pos = obj->pos;   // save current file position

	if (obj->dev == NULL || obj->open_succ == U_FALSE || fnode == NULL) {
		obj->err = UEBADF;
		goto ext;
	}

	/* can't truncate a dir */
	/* TODO: delete files under dir ? */
	if (obj->type == UFFS_TYPE_DIR) {
		obj->err = UEEXIST;
		goto ext;
	}

	if (remain >= fnode->u.file.len) {
		goto ext;	//!< nothing to do ... 
	}

	flen = fnode->u.file.len;

	if (flen < remain) {
		// file is shorter than 'reamin', fill the gap with '\0'
		if (run_opt == eREAL_RUN) {
			obj->pos = flen;  // move file pointer to the end
			if (do_WriteObject(obj, NULL, remain - flen) > 0) {	// fill '\0' ...
				uffs_Perror(UFFS_MSG_SERIOUS, "Write object not finished. expect %d but only %d wrote.",
												remain - flen, fnode->u.file.len - flen);
				obj->err = UEIOERR;   // likely be an I/O error.
			}
			flen = obj->node->u.file.len;
		}
	}
	else {
		while (flen > remain) {
			fdn = GetFdnByOfs(obj, flen - 1);

			//uffs_BufFlushGroup(dev, obj->serial, fdn);	//!< flush the buffer

			block_start = GetStartOfDataBlock(obj, fdn);
			if (remain <= block_start && fdn > 0) {
				node = uffs_TreeFindDataNode(dev, obj->serial, fdn);
				if (node == NULL) {
					uffs_Perror(UFFS_MSG_SERIOUS,
								"can't find data node when trancate obj.");
					obj->err = UEIOERR;
					goto ext;
				}
				bc = uffs_BlockInfoGet(dev, node->u.data.block);
				if (bc == NULL) {
					uffs_Perror(UFFS_MSG_SERIOUS,
								"can't get block info when trancate obj.");
					obj->err = UEIOERR;
					goto ext;
				}

				for (page = 0; page < dev->attr->pages_per_block; page++) {
					buf = uffs_BufFind(dev, fnode->u.file.serial, fdn, page);
					if (buf) {
						//!< ok, the buffer was loaded before ...
						if (uffs_BufIsFree(buf) == U_FALSE) {
							uffs_BlockInfoPut(dev, bc);
							goto ext;	//!< and someone is still holding the buffer,
										//   can't truncate it !!!
						}
						else if (run_opt == eREAL_RUN)
							uffs_BufMarkEmpty(dev, buf);	//!< discard the buffer
					}
				}

				if (run_opt == eREAL_RUN) {
					uffs_BreakFromEntry(dev, UFFS_TYPE_DATA, node);
					uffs_FlashEraseBlock(dev, bc->block);
					node->u.list.block = bc->block;
					if (HAVE_BADBLOCK(dev))
						uffs_BadBlockProcess(dev, node);
					else
						uffs_TreeInsertToErasedListTail(dev, node);

					fnode->u.file.len = block_start;
				}

				flen = block_start;
				uffs_BlockInfoPut(dev, bc);
			}
			else {
				if (do_TruncateInternalWithBlockRecover(obj, fdn,
														remain, run_opt) == U_SUCC) {
					if (run_opt == eREAL_RUN)
						fnode->u.file.len = remain;
					flen = remain;
				}
			}
		}
	}

	if (HAVE_BADBLOCK(dev)) 
		uffs_BadBlockRecover(dev);
ext:
	obj->pos = pos;  // keep file pointer offset not changed.

	uffs_Assert(fnode == obj->node, "obj->node change!\n");

	return (obj->err == UENOERR ? U_SUCC : U_FAIL);

}
Exemplo n.º 30
0
Arquivo: uffs_fs.c Projeto: mazj/uffs
/**
 * write data to obj, return remain data (0 if all data been written).
 */
static int do_WriteObject(uffs_Object *obj, const void *data, int len)
{
	uffs_Device *dev = obj->dev;
	TreeNode *fnode = obj->node;
	int remain = len;
	u16 fdn;
	u32 write_start;
	TreeNode *dnode;
	u32 size;

	while (remain > 0) {
		write_start = obj->pos + len - remain;
		if (write_start > fnode->u.file.len) {
			uffs_Perror(UFFS_MSG_SERIOUS, "write point out of file ?");
			break;
		}

		fdn = GetFdnByOfs(obj, write_start);

		if (write_start == fnode->u.file.len && fdn > 0 &&
			write_start == GetStartOfDataBlock(obj, fdn)) {
			if (dev->tree.erased_count < dev->cfg.reserved_free_blocks) {
				uffs_Perror(UFFS_MSG_NOISY, "insufficient block in write obj, new block");
				break;
			}
			size = do_WriteNewBlock(obj, data ? (u8 *)data + len - remain : NULL,
										remain, fnode->u.file.serial, fdn);

			//
			// Flush the new block buffers immediately, so that the new data node will be
			// created and put in the tree.
			//
			// But before do that, we need to make sure the previous
			// data block (if exist) been flushed first.
			//
			if (fdn > 1) {
				uffs_BufFlushGroup(dev, fnode->u.file.serial, fdn - 1);
			}
			else {
				uffs_BufFlushGroup(dev, fnode->u.file.parent, fnode->u.file.serial);
			}
			// Now flush the new block.
			uffs_BufFlushGroup(dev, fnode->u.file.serial, fdn);

			if (size == 0) 
				break;

			remain -= size;
		}
		else {

			if(fdn == 0)
				dnode = obj->node;
			else
				dnode = uffs_TreeFindDataNode(dev, fnode->u.file.serial, fdn);

			if(dnode == NULL) {
				uffs_Perror(UFFS_MSG_SERIOUS, "can't find data node in tree ?");
				obj->err = UEUNKNOWN_ERR;
				break;
			}
			size = do_WriteInternalBlock(obj, dnode, fdn,
									data ? (u8 *)data + len - remain : NULL, remain,
									write_start - GetStartOfDataBlock(obj, fdn));
#ifdef CONFIG_FLUSH_BUF_AFTER_WRITE
			if (fdn == 0)
				uffs_BufFlushGroup(dev, fnode->u.file.parent, fnode->u.file.serial);
			else
				uffs_BufFlushGroup(dev, fnode->u.file.serial, fdn);
#endif
			if (size == 0)
				break;

			remain -= size;
		}
	}

	uffs_Assert(fnode == obj->node, "obj->node change!\n");

	return remain;
}