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

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芯片专有信息。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值