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

📄 uffs_buf.c~

📁 nandflash文件系统源代码
💻 C~
📖 第 1 页 / 共 3 页
字号:
/*
    Copyright (C) 2005-2008  Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*/
/** 
 * \file uffs_buf.c
 * \brief uffs page buffers manipulations
 * \author Ricky Zheng
 * \note Created in 11th May, 2005
 */

#include "uffs/uffs_types.h"
#include "uffs/uffs_buf.h"
#include "uffs/uffs_device.h"
#include "uffs/uffs_os.h"
#include "uffs/uffs_public.h"
#include "uffs/ubuffer.h"
#include "uffs/uffs_ecc.h"
#include "uffs/uffs_badblock.h"
#include <string.h>

#define PFX "pg buf:"

/**
 * \brief inspect (print) uffs page buffers.
 * \param[in] dev uffs device to be inspected.
 */
void uffs_BufInspect(uffs_Device *dev)
{
	struct uffs_pageBufsSt *pb = &dev->buf;
	uffs_Buf *buf;

	uffs_Perror(UFFS_ERR_NORMAL, "------------- page buffer inspect ---------\n");
	uffs_Perror(UFFS_ERR_NORMAL, "all buffers: \n");
	for (buf = pb->bufHead; buf; buf = buf->next) {
		uffs_Perror(UFFS_ERR_NORMAL, "\tF:%04x S:%04x P:%02d R:%02d D:%03d M:%d\n", 
			buf->father, buf->serial, buf->pageID, buf->refCount, buf->dataLen, buf->mark);
	}
	uffs_Perror(UFFS_ERR_NORMAL, "--------------------------------------------\n");
}

/**
 * \brief initialize page buffers for device
 * in UFFS, each device has one buffer pool
 * \param[in] dev uffs device
 * \param[in] maxBuf maximum buffer number, normally use #MAX_PAGE_BUFFERS
 * \param[in] maxDirtyBuf maximum dirty buffer allowed, if the dirty buffer over this number,
 *            than need to be flush to flash
 */
URET uffs_BufInit(uffs_Device *dev, int maxBuf, int maxDirtyBuf)
{
	void *pool;
	u8 *data;
	uffs_Buf *buf;
	int size;
	int i;

	if(!dev) return U_FAIL;

	//init device common parameters, which are needed by page buffers
	dev->com.pgSize = dev->attr->page_data_size;
	dev->com.eccSize = dev->flash->GetEccSize(dev);
	dev->com.pgDataSize = dev->com.pgSize - dev->com.eccSize;

	if(dev->buf.pool != NULL) {
		uffs_Perror(UFFS_ERR_NORMAL, PFX"buf.pool is not NULL, buf already inited ?\n");
		return U_FAIL;
	}
	
	size = (sizeof(uffs_Buf) + dev->com.pgSize) * maxBuf;
	if (dev->mem.page_buffer_size == 0) {
		if (dev->mem.malloc) {
			dev->mem.page_buffer = dev->mem.malloc(dev, size);
			if (dev->mem.page_buffer) dev->mem.page_buffer_size = size;
		}
	}
	if (size > dev->mem.page_buffer_size) {
		uffs_Perror(UFFS_ERR_DEAD, PFX"page buffers require %d but only %d available.\n", size, dev->mem.page_buffer_size);
		return U_FAIL;
	}
	pool = dev->mem.page_buffer;

	uffs_Perror(UFFS_ERR_NOISY, PFX"allcate %d bytes.\n", size);
	dev->buf.pool = pool;

	data = (u8 *)pool + (sizeof(uffs_Buf) * maxBuf);

	for(i = 0; i < maxBuf; i++) {
		buf = (uffs_Buf *)((u8 *)pool + (sizeof(uffs_Buf) * i));
		memset(buf, 0, sizeof(uffs_Buf));
		data = (u8 *)pool + (sizeof(uffs_Buf) * maxBuf) + (dev->com.pgSize * i);

		buf->data = data;
		buf->ecc = data + dev->com.pgDataSize;
		buf->mark = UFFS_BUF_EMPTY;
		if(i == 0) {
			buf->prev = NULL;
			dev->buf.bufHead = buf;
		}
		else {
			buf->prev = (uffs_Buf *)((u8 *)buf - sizeof(uffs_Buf));
		}

		if(i == maxBuf - 1) {
			buf->next = NULL;
			dev->buf.bufTail = buf;
		}
		else {
			buf->next = (uffs_Buf *)((u8 *)buf + sizeof(uffs_Buf));
		}
	}

	dev->buf.maxBuf = maxBuf;
	dev->buf.maxDirtyBuf = (maxDirtyBuf > dev->attr->pages_per_block ? dev->attr->pages_per_block : maxDirtyBuf);
	dev->buf.dirty = NULL;
	dev->buf.dirtyCount = 0;

	return U_SUCC;
}

/** 
 * \brief release all page buffer, this function should be called 
			when unmounting a uffs device
 * \param[in] dev uffs device
 * \note if there are page buffers in used, it may cause fail to release
 */
URET uffs_BufReleaseAll(uffs_Device *dev)
{
	uffs_Buf *p;

	if(!dev) return U_FAIL;

	//now release all buffer
	p = dev->buf.bufHead;
	while(p) {
		if(p->refCount != 0) {
			uffs_Perror(UFFS_ERR_NORMAL, 
				PFX "can't release buffers, \
					father:%d, serial:%d, pageID:%d still in used.\n", p->father, p->serial, p->pageID);
			return U_FAIL;
		}
		p = p->next;
	}

	if(uffs_BufFlush(dev) != U_SUCC) {
		uffs_Perror(UFFS_ERR_NORMAL, PFX"can't release buf, fail to flush buffer\n");
		return U_FAIL;
	}

	if (dev->mem.free) dev->mem.free(dev, dev->buf.pool);
	dev->buf.pool = NULL;
	dev->buf.bufHead = dev->buf.bufTail = NULL;

	return U_SUCC;
}


static void _BreakFromBufList(uffs_Device *dev, uffs_Buf *buf)
{
	if(buf->next) {
		buf->next->prev = buf->prev;
	}
	if(buf->prev) {
		buf->prev->next = buf->next;
	}
	if(dev->buf.bufHead == buf) {
		dev->buf.bufHead = buf->next;
	}
	if(dev->buf.bufTail == buf) {
		dev->buf.bufTail = buf->prev;
	}
}

static void _LinkToBufListHead(uffs_Device *dev, uffs_Buf *buf)
{
	if(buf == dev->buf.bufHead) return;
	buf->prev = NULL;
	buf->next = dev->buf.bufHead;
	if(dev->buf.bufHead) dev->buf.bufHead->prev = buf;
	if(dev->buf.bufTail == NULL) dev->buf.bufTail = buf;
	dev->buf.bufHead = buf;
}

static void _LinkToBufListTail(uffs_Device *dev, uffs_Buf *buf)
{
	if(dev->buf.bufTail == buf) return;
	buf->prev = dev->buf.bufTail;
	buf->next = NULL;
	if(dev->buf.bufTail) dev->buf.bufTail->next = buf;
	if(dev->buf.bufHead == NULL) dev->buf.bufHead = buf;
	dev->buf.bufTail = buf;
}

//move a node which linked in the list to the head of list
static void _MoveNodeToHead(uffs_Device *dev, uffs_Buf *p)
{
	if(p == dev->buf.bufHead) return;

	//break from list
	_BreakFromBufList(dev, p);

	//link to head
	_LinkToBufListHead(dev, p);
}

static void _LinkToDirtyList(uffs_Device *dev, uffs_Buf *buf)
{
	if (buf == NULL) {
		uffs_Perror(UFFS_ERR_SERIOUS, PFX"Try to insert a NULL node into dirty list ?\n");
		return;
	}
	buf->mark = UFFS_BUF_DIRTY;
	buf->prevDirty = NULL;
	buf->nextDirty = dev->buf.dirty;
	if(dev->buf.dirty) dev->buf.dirty->prevDirty = buf;
	dev->buf.dirty = buf;
	dev->buf.dirtyCount++;
}

static uffs_Buf * _FindFreeBuf(uffs_Device *dev)
{
	uffs_Buf *buf;
#if 1
	buf = dev->buf.bufHead;
	while(buf) {
		if(buf->refCount == 0 && 
			buf->mark != UFFS_BUF_DIRTY) return buf;
		buf = buf->next;
	}
#else
	buf = dev->buf.bufTail;
	while(buf) {
		if(buf->refCount == 0 &&
			buf->mark != UFFS_BUF_DIRTY) return buf;
		buf = buf->prev;
	}
#endif

	return buf;
}

/** 
 * load psychical page data into buf and do ecc check 
 * \param[in] dev uffs device
 * \param[in] buf buf to be load in
 * \param[in] block psychical block number
 * \param[in] page psychical page number
 * \return return U_SUCC if no error, return U_FAIL if I/O error or ecc check fail
 */
URET uffs_LoadPhiDataToBuf(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page)
{
	URET ret;

	ret = dev->ops->ReadPageData(dev, block, page, buf->data, 0, dev->com.pgSize);
	if(ret == U_SUCC) {
		if (uffs_CheckBadBlock(dev, buf, block) == U_SUCC) {
			buf->mark = UFFS_BUF_VALID; // the data is valid now
		}
		else {
			buf->mark = UFFS_BUF_EMPTY;
			ret = U_FAIL;
		}
	}
	else {
		buf->mark = UFFS_BUF_EMPTY; // the data is not valid
	}
	
	return ret;
}

/** 
 * load psychical page data into buf and try ecc check 
 * \param[in] dev uffs device
 * \param[in] buf buf to be load in
 * \param[in] block psychical block number
 * \param[in] page psychical page number
 * \return return U_SUCC if no error, return U_FAIL if I/O error
 * \note this function should be only used when doing bad block recover.
 */
URET uffs_LoadPhiDataToBufEccUnCare(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page)
{
	URET ret;

	ret = dev->ops->ReadPageData(dev, block, page, buf->data, 0, dev->com.pgSize);
	if(ret == U_SUCC) {
		if (uffs_CheckBadBlock(dev, buf, block) == U_SUCC) {
			//ECC check fail, but we return 'successful' anyway !!
			buf->mark = UFFS_BUF_VALID;
		}
		return U_SUCC;
	}
	else {
		buf->mark = UFFS_BUF_EMPTY; // the data is not valid, I/O error ?
	}
	
	return ret;
}


/** 
 * find a buffer in the pool
 * \param[in] dev uffs device
 * \param[in] father father serial num
 * \param[in] serial serial num
 * \param[in] pageID pageID
 * \return return found buffer, return NULL if buffer not found
 */
uffs_Buf * uffs_BufFind(uffs_Device *dev, u16 father, u16 serial, u16 pageID)
{
	uffs_Buf *p = dev->buf.bufHead;

	while(p) {
		if(	p->father == father &&
			p->serial == serial &&
			p->pageID == pageID &&
			p->mark != UFFS_BUF_EMPTY) {
			//they have match one
			return p;
		}
		p = p->next;
	}

	return NULL; //buffer not found
}

static uffs_Buf * _FindBufInDirtyList(uffs_Buf *dirty, u16 pageID)
{
	while(dirty) {
		if(dirty->pageID == pageID) return dirty;
		dirty = dirty->nextDirty;
	}
	return NULL;
}

static URET _BreakFromDirty(uffs_Device *dev, uffs_Buf *dirtyBuf)
{
	if(dirtyBuf->mark != UFFS_BUF_DIRTY) {
		uffs_Perror(UFFS_ERR_NORMAL, PFX"try to break a non-dirty buf from dirty list ?\n");
		return U_FAIL;
	}

	if(dev->buf.dirty == NULL) {
		uffs_Perror(UFFS_ERR_NORMAL, PFX"no dirty list exit ?\n");
		return U_FAIL;
	}

	// break from the link
	if(dirtyBuf->nextDirty) {
		dirtyBuf->nextDirty->prevDirty = dirtyBuf->prevDirty;
	}

	if(dirtyBuf->prevDirty) {
		dirtyBuf->prevDirty->nextDirty = dirtyBuf->nextDirty;
	}

	// check if it's the link head ...
	if(dev->buf.dirty == dirtyBuf) {
		dev->buf.dirty = dirtyBuf->nextDirty;
	}

	dirtyBuf->nextDirty = dirtyBuf->prevDirty = NULL; // clear dirty link

	dev->buf.dirtyCount--;

	return U_SUCC;
}

static u16 _GetDataSum(uffs_Device *dev, uffs_Buf *buf)
{
	u16 dataSum = 0; //default: 0
	uffs_fileInfo *fi;
	
	dev = dev;
	//FIXME: We use the same schema for both dir and file.
	if(buf->type == UFFS_TYPE_FILE || buf->type == UFFS_TYPE_DIR) {
		if(buf->pageID == 0) {
			fi = (uffs_fileInfo *)(buf->data);
			dataSum = uffs_MakeSum16(fi->name, fi->name_len);
		}
	}

	return dataSum;
}


static URET _CheckDirtyList(uffs_Device *dev)
{
	uffs_Buf *dirty = dev->buf.dirty;
	u16 father;
	u16 serial;

	if(dirty == NULL) {
		return U_SUCC;
	}

⌨️ 快捷键说明

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