UFFS文件系统向上负责对象——DFS接口
我们在在应用程序中,对文件读写时,使用的都是open,read,wirte等函数,这些函数是dfs提供的。而dfs负责的是,根据不同的fd判断该文件是什么类型的设备,在调用相应类型的XXX_read函数。
uffs与dfs关系正事如此。当我们需要向NandFlash中的文件进行读写时,dfs会依据文件的属性,将具体read操作交给UFFS处理。
(注释:UFFS文件系统可以看成NandFlash的管理者,真正存储文件的载体是NandFlash这样的具体硬件设备,在下一篇文件中在进一步介绍这部分)。
首选让看一下UFFS系统加载过程中,与dfs相连的部分,系统初始化时 调用uffs_init(); 开始加载UFFS。主要代码如下:
通过UFFS向上层DFS接口看起,在UFFS初始化时,会把上上层负责的接口函数,同样以函数指针的存储方式,存储在dfs_uffs 结构中。上层dfs便可以通过这写接口访问UFFS,
在应用成执行 dfs->read(…) 如同调用 dfs_uffs_read(…)。
int uffs_init(void)
{
rt_strncpy(dfs_uffs.name, "uffs", DFS_FS_NAME_MAX);
dfs_uffs.mount = dfs_uffs_mount;// 加载uffs
dfs_uffs.unmount = dfs_uffs_unmount;// 移除uffs
dfs_uffs.open = dfs_uffs_open;// open
dfs_uffs.close = dfs_uffs_close;
dfs_uffs.ioctl = dfs_uffs_ioctl;
dfs_uffs.read = dfs_uffs_read;
dfs_uffs.write = dfs_uffs_write;
dfs_uffs.lseek = dfs_uffs_lseek;
…
}
这有点类似于linux系统中的file_operations结构。
在uffs加载时,会把一下必要函数传递给dfs接口,也就是说,当dfs 执行read函数时,就会调用dfs_uffs_read。
而在uffs开始加载时。就会调用底层Nandflash初始化。UFFS真的是一个承上启下的东西。
int dfs_uffs_mount(struct dfs_filesystem* fs, unsigned long rwflag, const void* data)
{
int result =uffs_init_filesystem(fs->path);//nandflash_init_filesystem(fs->path)
if(result == 0)
{
return DFS_STATUS_OK;
}
return DFS_STATUS_ENOENT;
}
接着看上边紧接着调用的: nandflash_init_filesystem
void nandflash_init_filesystem(char * path)
{
uffs_MountTable *mtbl = &nand_mount_table[0];//rt_malloc(sizeof(uffs_MountTable)*2);
struct uffs_ConfigSt cfg = {
0, // bc_caches - default
0, // page_buffers - default
0, // dirty_pages - default
0, // dirty_groups - default
0, // reserved_free_blocks - default
};
rt_memset((void*)&nand_device,0,sizeof( uffs_Device));
rt_memset((void*)&flash_storage,0,sizeof(struct uffs_StorageAttrSt));
//EMC_CTRL = 1;//enable,no map,normal mode
if( NandInit() ==0)
{
rt_kprintf("No Flash found\r\n");
return;
}
_ginitinfo = Get_NandInitInfo();
if(_ginitinfo == NULL)
{
rt_kprintf("No Flash Init Info \r\n");
return;
}
rt_kprintf("nand info nandnbBlocks : %X , %d\r\n",_ginitinfo->uNandID,_ginitinfo->uNandNbBlocks) ;
/* setup nand storage attributes */
setup_flash_storage(&flash_storage,_ginitinfo);
while (mtbl->dev) {
rt_memcpy(&mtbl->dev->cfg, &cfg, sizeof(struct uffs_ConfigSt));
#if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
uffs_MemSetupSystemAllocator(&mtbl->dev->mem);
#endif
mtbl->dev->Init = my_initDevice;
mtbl->dev->Release = my_releaseDevice;
mtbl->dev->attr = &flash_storage;
uffs_RegisterMountTable(mtbl);
mtbl++;
}
// 上边的代码都是获取一下必要信息,比如Flash的信息,这都都是结下了uffs加载时必定要用到的,根据不同的flash属性,加载时,申请的内存大小等等都是不同的。
for (mtbl = &(nand_mount_table[0]); mtbl->mount != NULL; mtbl++) {
// 这里才是重点 UFFS 加载的真正函数
//nand_mount_table[] 存储着加载几块Nand设备,和起始地址范围
uffs_Mount(mtbl->mount);
}
}
uffs_Mount(mtbl->mount)这句话变开始建立真正的UFFS系统了。在这函数里面,会申请并初始化所以UFFS运行时所需要的内存,并且完成对底层NandFlash中,有效也的信息记录,把Flash中存储的文件,和文件夹链接关系都加载进入内存中,并且扫描Flash坏块等。在这里就不详细介绍了,后面我会对UFFS文件系统运行原理单独写一篇文章。在这里大家就先记住uffs_Mount 这个函数就行了~
二.UFFS与DFS调用关系
跑题了有点。回头看看UFFS与dfs个调用关系吧!
拿read函数举例,顶层read函数,终是如何调用到uffs_read()的。
1. read函数原型:
int read(int fd, char *buf, int len)
{
int result;
struct dfs_fd* d;
// 通过fd号,找到所对应的dfs文件对象,
/* get the fd */
d = fd_get(fd);
if (d == RT_NULL)
{
rt_set_errno(-RT_ERROR);
return -1;
}
result = dfile_raw_read(d, buf, len);//重点
if (result < 0)
{
rt_set_errno(result);
fd_put(d);
return -1;
}
/* release the ref-count of fd */
fd_put(d);
return result;
}
注释:理解d = fd_get(fd),上层根据不通的fd号,获取到所要操作的dfs对象,在文件open的时候 会创建这样一个对象。
int open(const char *file, int flags, int mode)
{
int fd;
struct dfs_fd* d;
/* allocate a fd */
fd = fd_new();
...
dfile_raw_open(d, file, flags);
....
return fd;
}
在看看dfs_fd结构
/* file descriptor */
struct dfs_fd
{
char path[DFS_PATH_MAX + 1];/* Name (below mount point) */
int type; /* Type (regular or socket) */
int ref_count; /* Descriptor reference count */
struct dfs_filesystem* fs; /* Resident file system */
rt_uint32_t flags; /* Descriptor flags */
rt_size_t size; /* Size in bytes */
rt_off_t pos; /* Current file position */
void *data; /* Specific file system data */
};
这里面struct dfs_filesystem* fs 记录了将要read的文件,以何种方式处理。举个例子,比如一个dfs接口下面有两种文件系统,uffs和romfs。而应用层read(A.txt);这个“A”文件,是属于uffs还是romfs的文件,还有使用什么样的函数来完成具体的read任务。就是在这区分的。
2. dfile_raw_read函数
int dfile_raw_read(struct dfs_fd* fd, void *buf, rt_size_t len)
{
struct dfs_filesystem* fs;
int result = 0;
if (fd == RT_NULL) return -DFS_STATUS_EINVAL;
fs = (struct dfs_filesystem*) fd->fs;
if (fs->ops->read == RT_NULL) return -DFS_STATUS_ENOSYS;
// fs 就是刚才说的 struct dfs_filesystem* fs 结构
if ( (result = fs->ops->read(fd, buf, len)) < 0 ) fd->flags |= DFS_F_EOF;
return result;
}
fs->ops->read(fd, buf, len)),这里调用的指针函数->read是谁呢?
int uffs_init(void)
{
rt_strncpy(dfs_uffs.name, "uffs", DFS_FS_NAME_MAX);
dfs_uffs.read = dfs_uffs_read;//就是它
…
}
到此在dfs_uffs_read()函数中,获取dfs_fd->data,作为uffs_read()函数的参数,向下传递。
dfs_uffs.c 文件中源代码:
int dfs_uffs_read(dfs_fd* file, void* buf, u32 len)
{
….
Int fd = (int)(file->data);
Int fd = (int)(file->data);
uffs_read(fd, buf, len);
….
}
来到了uffs的世界…
其他open,write等函数均类似如此。
dfs访问其他设备接口的过程也类似uffs
关于uffs与dfs的内容到此结束。
关于uffs_read是如何进行操作的,如何找在Flash中找到对应的文件,对文件读写,有待后文。。。