sd卡读文件过程分析(一)(内核2.6.29,驱动goldfish)

本文通过分析file的读操作,探讨了在goldfish驱动中,如何从fat32文件系统的file_operations出发,进行读取操作。主要关注get_block调用获取块号以及bio = mpage_bio_submit(READ, bio)提交IO请求的过程,该步骤将操作转交给块设备驱动层完成从文件系统到驱动层的转换。" 136243116,5110923,Sora技术入门教程,"['通信技术', 'SORA', '无线通信', '协议学习', '技术解析']

这段时间想弄懂mmc驱动的读写原理,一直在goldfish的驱动代码中乱撞。某天突然灵光一闪,要从文件系统开始分析。眼前一篇豁然开朗。跟踪过程记录如下:

首先是file的读操作。因为sd卡是fat32文件系统,找到fat32的file_operations:

 

const struct file_operations fat_file_operations = {

         .llseek         = generic_file_llseek,

         .read           = do_sync_read,

         .write          = do_sync_write,

         .aio_read       = generic_file_aio_read,

         .aio_write      = generic_file_aio_write,

         .mmap           = generic_file_mmap,

         ……
}
read操作先调用do_sync_read,然后在do_sync_read中调用generic_file_aio_read。
generic_file_aio_read中先判断是否可以direct to BIO。如果不能,进入读取页面的循环,这个循环中主要的函数是:
          do_generic_file_read(filp, ppos, &desc, file_read_actor);
这个函数也是读文件主要的操作函数。
进入do_generic_file_read,首先在缓存中找要读的页面。查找结果有三种情况:1.找到了,而且内容一致。2.找到了,但是内容不一致。3.没找到该缓存页面。
对于第一种情况,跳转到page_ok,直接复制缓存页面中的内容。
第二种情况,跳转到page_not_up_to_date,等待一会,在次检查。如果还不行,就readpage。
第三种情况,直接跳转到readpage,开始从设备读页面:
/* Start the actual read. The read will unlock the page. */
error = mapping->a_ops->readpage(filp, page);
if(unlikely(error)){
……
具体的读取函数由a_ops的readpage指定,在fat32文件系统中就是fat_readpage,fat32 a_ops的成员如下:
static const struct address_space_operations fat_aops = {
.readpage = fat_readpage,
.readpages = fat_readpages,
.writepage = fat_writepage,
.writepages = fat_writepages,
.sync_page = block_sync_page,
.write_begin = fat_write_begin,
.write_end = fat_write_end,
.direct_IO = fat_direct_IO,
.bmap = _fat_bmap
};
文件系统在操作设备的时候,有一个预读取的动作。一般我们需要的数据是通过预读取读进内存的,这个时候调用的就是fat_readpages操作函数。
再来看fat_readpages函数,它直接返回mpage_readpages函数:
static int fat_readpages(struct file *file, struct address_space *mapping,
struct list_head *pages, unsignednr_pages)
{
return mpage_readpages(mapping, pages, nr_pages, fat_get_block);
}
注意他的最后一个参数fat_get_block是一个函数指针。他的作用是建立从文件块号到设备扇区号的映射。
函数mpage_readpages做了一些初始化,然后循环调用do_mpage_readpage来读取每一个页面。
bio = do_mpage_readpage(bio, page, nr_pages - page_idx, &last_block_in_bio, &map_bh, &first_logical_block, get_block);

do_mpage_readpage函数比较长。具体的也没分析,就看两个重要的地方。

一个是get_block的调用,前面已近提到过了,是为了得到要读取数据在设备上的块号。

一个是提交io请求: bio = mpage_bio_submit(READ, bio);这个函数将要读写命令交给块设备驱动来处理。这样,就完成了从文件系统层到块设备驱动层的转换。

 

块设备驱动层的操作下篇分析。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值