策略例程request_fn(定义在请求结构中)的执行过程如下: u 策略例程处理队列中的第一个请求并设置块设备控制器,使数据传送完成后产生一个中断。然后策略例程就终止。
u 数据传送完毕后块设备控制器产生中断,中断处理程序就激活下半部分。这个下半部分的处理程序把这个请求从队列中删除(end_request( ))并重新执行策略例程来处理队列中的下一个请求。
好了,写操作说完了,是不是觉得不知所云呀,其实上面仅仅是抽取写操作的骨架简要讲解,具体操作还要复杂得多,下面我们将上面的流程总结一便。
粗略地分,读操作依次需要经过:
l 用户界面层——负责从用户函数经过系统调用进入内核;
l 基本文件系统层——负责调用文件写方法,从高速缓存中搜索数据页,返回给用户。 l I/O调度层——负责对请求排队,从而提高吞吐量。 l I/O传输层——利用任务列队异步操作设备控制器完成数据传输。 写操作和读操作大体相同,不同之处主要在于写页面高速缓存时,稍微麻烦一些,因为写操作不象读操作那样必须和用户空间同步[13]执行,所以用户写操作更新了数据内容后往往先存先存储在页高速缓存中,然后等页回写后台例程bdflush和kupdate[14]等来完成写如磁盘的工作。当然写入请求处理还是要通过上面提到的submit_bh函数[15]进行I/O处理的。下面简要介绍写过程: page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec); status = a_ops->prepare_write(file,page,offset,offset+bytes); page_fault = filemap_copy_from_user(page,offset,buf,bytes); status = a_ops->commit_write(file,page,offset,offset+bytes); 首先,在页高速缓存中搜索需要的页,如果需要的页不在高速缓存中,那么内核在高速缓存中新分配一空闲项;下一步,prepare_write()方法被调用,为页分配异步缓冲区首部;接着数据被从用户空间拷贝到了内核缓冲;最后通过commit_write()函数将对应的函数把基础缓冲区标记为脏,以便随后它们被页回写例程写回到磁盘。 好累呀,到此总算把文件读写过程顺了一便,大家明白了上述概念后,我门进入最后一部分:Romfs事例分析。 实例—romfs文件系统的实现 文件系统实在是个庞杂的“怪物”,我很难编写一个恰当的例子来演示文件系统的实现。开始我想写一个纯虚文件系统,但考虑到它几乎没有实用价值,而且更重要的是虚文件系统不涉及I/O操作,缺少现实文件系统中置关重要的部分,所以放弃了;后来想写一个实际文件系统,但是那样工程量太大,而且也不容易让大家简明扼要的理解文件系统的实现,所以也放弃了。最后我发现内核中提供的romfs文件系统是个非常理想的实例,它即有实际应用结构也清晰明了,我们以romfs为实例分析文件系统的实现。 Linux文件系统实现要素 编写新文件系统自己需要一些基本对象[16]。具体的讲创建文件系统需要建立“一个结构四个操作表”: n 文件系统类型结构(file_system_type)、 n 超级块操作表(super_operations)、 n 索引节点操作表(inode_operations)、 n 页高速缓存(address_space_operations)、 n 文件操作表(file_operations)。 对上述几种结构的处理贯穿了文件系统的主要操作过程,理清晰这几种结构之间的关系是编写文件系统的基础,下来我们具体分析这几个结构和文件系统实现的要点。 |