您的位置:首页 > 编程语言 > PHP开发

Android中的yaffs2文件系统与文件操作底层实现

2013-09-26 13:27 513 查看

1. yaffs2文件系统

yaffs2文件系统是用于NAND FLASH的文件系统. 由Android中增加的. 在原来的Linux2.2.26系统中没有这个文件系统.

2. 应用层的文件操作

应用层的文件操作为fopen,fread, fwrite, 常用的文件操作函数. 下方操作我们以fread为例.

struct file的定义在/kernel/include/linux/fs.h, 这个结构要记住.

struct file{

…

const struct file_operations    *f_op;

…

}

3. read的系统调用

SYSCALL_DEFINE3(read,unsigned int, fd, char __user *, buf, size_t, count)

{

struct file *file;

ssize_t ret = -EBADF;

int fput_needed;

file = fget_light(fd, &fput_needed);

if (file) {

loff_t pos = file_pos_read(file);

ret = vfs_read(file, buf, count,&pos);

file_pos_write(file, pos);

fput_light(file, fput_needed);

}

return ret;

}


在系统调用中使用了函数vfs_read.此函数的实现在/kernel/fs/read_write.c中.

在vfs_read中, 有以下调用语句:

struct file *file;

if (file->f_op->read)

ret = file->f_op->read(file,buf, count, pos);

else

ret = do_sync_read(file, buf, count,pos);

即, 如果file_operations类型的指针f_op有具体实现时, 使用具体实现; 否则直接使用do_sync_read.

 4. yaffs2中的对file_operations实现

file_operations在/kernel/fs/yaffs2/yaffs_vfs.c下有相应实现.

static conststruct file_operations yaffs_file_operations = {

.read = do_sync_read,

.write = do_sync_write,

.aio_read = generic_file_aio_read,

.aio_write = generic_file_aio_write,

.mmap = generic_file_mmap,

.flush = yaffs_file_flush,

.fsync = yaffs_sync_object,

.splice_read = generic_file_splice_read,

.splice_write = generic_file_splice_write,

.llseek = generic_file_llseek,

};

在yaffs2中, 依然使用了do_sync_read. 但是其他如目录的管理等, 则是yaffs2的内容了.
在do_sync_read中, 有对yaffs2中的代码的调用, 即:

ret =filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);

.aio_read =generic_file_aio_read, 说明依然不是在yaffs2中实现的.

5. mm中对generic_file_aio_read的实现

generic_file_aio_read的定义是在/kernel/mm/filemap.c中实现的.

其中有调用do_generic_file_read(filp,ppos, &desc, file_read_actor);

do_generic_file_read是一个内容比较长的函数, 其中有page同步的调用. 大意是, 如果该文件的页面已在缓存中, 则直接读取; 否则, 先从设备中将该页面读取到缓存,然后再读取.

当page_ok时, 执行读取操作.

注意页面缓存这文件读取过程中的作用.

6. 复杂函数do_generic_file_read

这个复杂函数的执行过程如下:

A.     根据address_space和索引去查找页面;

B.     如果没有找到页面, 则跳转到no_cached_page去进行页面缓存;  具体过程是, 先分配一个页面, 加入address_space链表, 然后error =mapping->a_ops->readpage(filp, page);然后执行PageUptodate.  

C.     如果找到了,  执行PageUptodate检查;

D.    如果page_ok, 则调用actor函数指针, 将文件内容从页面缓存读取到用户缓冲区. 这里的actor函数指针的值由do_generic_file_read传入,实际上是file_read_actor.

intfile_read_actor(read_descriptor_t *desc, struct page *page,

unsigned long offset, unsigned longsize)

{

char *kaddr;

unsigned long left, count = desc->count;

if (size > count)

size = count;

/*

*Faults on the destination of a read are common, so do it before

*taking the kmap.

*/

if(!fault_in_pages_writeable(desc->arg.buf, size)) {

kaddr = kmap_atomic(page, KM_USER0);

left =__copy_to_user_inatomic(desc->arg.buf,

kaddr + offset, size);

kunmap_atomic(kaddr, KM_USER0);

if (left == 0)

goto success;

}

/* Do it the slow way */

kaddr = kmap(page);

left = __copy_to_user(desc->arg.buf, kaddr+ offset, size);

kunmap(page);

if (left) {

size -= left;

desc->error = -EFAULT;

}

success:

desc->count = count - size;

desc->written += size;

desc->arg.buf += size;

return size;

}

7.与nandflash驱动的结合

与驱动的结合部分在address_space,它将设备中的内容读取到缓存中. 它的定义在yaffs2中.

static structaddress_space_operations yaffs_file_address_operations = {

.readpage= yaffs_readpage,

.writepage= yaffs_writepage,

.write_begin= yaffs_write_begin,

.write_end= yaffs_write_end,

};

static intyaffs_readpage(struct file *f, struct page *pg)

{

int ret;

yaffs_trace(YAFFS_TRACE_OS,"yaffs_readpage");

ret = yaffs_readpage_unlock(f, pg);

yaffs_trace(YAFFS_TRACE_OS,"yaffs_readpage done");

return ret;

}

yaffs_readpage_unlock调用了yaffs_readpage_nolock,后者又调用了yaffs_file_rd.
yaffs_file_rd在/kernel/fs/yaffs2/yaffs_guts.c中实现.

yaffs_file_rd调用了yaffs_rd_data_obj, 后者调用了yaffs_rd_chunk_tags_nand.

yaffs_rd_chunk_tags_nand在/kernel/fs/yaffs2/yaffs_nand.c中实现.

其中有

if(dev->param.read_chunk_tags_fn)

result =

dev->param.read_chunk_tags_fn(dev, realigned_chunk, buffer,

tags);

param类型为struct yaffs_param. 在yaffs_vfs.c中yaffs_internal_read_super函数中被赋值.
param->read_chunk_tags_fn = nandmtd2_read_chunk_tags;

nandmtd2_read_chunk_tags被定义在yaffs_mtdif2.c中.

通过struct mtd_info *mtd = yaffs_dev_to_mtd(dev);, nandmtd2_read_chunk_tags调用了如下语句:

retval = mtd->read(mtd, addr,dev->param.total_bytes_per_chunk,

&dummy, data);

MTD(memory technology device内存技术设备)是用于访问memory设备(ROM、flash)的Linux的子系统。
所有组成MTD原始设备的Flash芯片必须是同类型(无论是interleave还是地址相连),在描述MTD原始设备数据结构中采用同一结构描述组成Flash芯片。每个MTD原始设备有一个mtd_info结构,其中的priv指针指向一个map_info结构,map_info结构中的fldrv_priv指向一个cfi_private结构,cfi_private结构的cfiq指针指向一个cfi_ident结构,chips指针指向一个flchip结构的数组。其中mtd_info、map_info和cfi_private结构用于描述MTD原始设备,因为组成MTD原始设备的NOR型Flash相同,cfi_ident结构用于描述Flash芯片信息;而flchip结构用于描述每个Flash芯片专有信息。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息