免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2873 | 回复: 2
打印 上一主题 下一主题

[文件系统] 文件系统数据流程分析 [复制链接]

论坛徽章:
1
双子座
日期:2014-09-25 13:38:50
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-12-07 15:16 |只看该作者 |倒序浏览
发一个几年前分析文件系统的时候写的文档

文件系统数据流程分析


一,文件系统层次结构图

图一.  Kernel components affected by a block device operation
VFS:文件系统抽象层,它屏蔽底层具体的文件系统的接口,为应用层提供了统一的调用接口。
Disk Caches:主要包括dentry cache(即文件系统目录项的cache,作用是能够快速的定位文件)、inode cache、page cache(即具体的文件block的cache,用于提高文件的读写性能,例如读文件时如果文件已经在page cache中,则可以直接从cache中读出数据,不需要从磁盘读数据, 写文件时采用延迟写,减少对磁盘的访问次数)。
Mapping Layer: 主要作用有1)确定文件的块大小和块数,2)映射到具体的文件系统的操作(如ext2的read文件函数),确定所请求数据的逻辑块号。
Generic Block Layer:也是一个抽象层,用于处理所有的块设备的请求。可以理解为在块设备和具体的文件系统(ext2, ReiserFS)提供一个通用的接口。
I/O scheduler layer:管理I/O请求的queue;提供具体的I/O调度算法,如NOOP、CFO、电梯调度算法;合并某些请求,例如两个request所请求的磁盘块是相邻的块,则可将这两次请求合并为一次I/O请求。
Block Device Driver:具体的块设备驱动层。

二、文件读写流程

        以read为例,当提交一个read请求时,调用的sys_read()请求,如果所请求的数据块已经在page cache中,则将请求的数据块从内核page拷贝到用户buffer中,如果请求的数据块没有被cache,则需要执行以下步骤:
1) 从LRU block cache中查找或者申请一个新的page,然后检查该page的PG_private位,如果为null,则说明该page还不是一个buffer page , 跳到3)执行。
2) 执行到这里说明该page已经是buffer page,获取page的privte成员,该成员存放的是buffer head链表的第一个节点的地址。检查bh ->size是否是等于block的大小,如果是,则表示找到了所需要的buffer page,则执行4),如果不相等,则调用try_to_free_buffers,释放buffer head。
3) 调用alloc_page_buffers()函数,为该page申请buffer head,将这些buffer head链接成链表,将buffer head的b_page成员指向page descriptor,b_data执行block buffer,也即图二page中的buffer。
4) 调用init_page_buffers()函数,初始化buffer head并把它链接到page上。图三即是它们的指向关系图。
5) 返回page descriptor的地址。

图二. A buffer page including four buffers and their buffer heads

执行到这里已经为新请求的数据准备好了buffer page。调用submit_bh提交I/O请求,submit_bh参数包括READ/WRITE标志和buffer head,最终由Generic Block Layer来申请一个bio,并初始化这些bio,见程序块1)。然后调用generic_make_request(struct bio *bio),将bio最终加入到request queue中,request queue包含一个request结构体成员,request结构体中有一个char 型的buffer指针,数据会从磁盘读到该buffer中,而该buffer指向的就是bio中的page地址。

Buffer到bio中的page地址映射关系实现函数为int __make_request(struct request_queue *q, struct bio *bio)(block/blk-core.c), 赋值语句为req->buffer = bio_data(bio)。bio_data函数实现见程序块2)。

程序块1):

bio = bio_alloc(GFP_NOIO, 1);
        bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
        bio->bi_bdev = bh->b_bdev;
        bio->bi_io_vec[0].bv_page = bh->b_page;
        bio->bi_io_vec[0].bv_len = bh->b_size;
        bio->bi_io_vec[0].bv_offset = bh_offset(bh);
        bio->bi_size = bh->b_size;
        bio->bi_private = bh;

About bio struct:The core data structure of the generic block layer is a descriptor of an ongoing I/O block device operation called bio. Each bio essentially includes an identifier for a disk storage areathe initial sector number and the number of sectors included in the storage areaand one or more segments describing the memory areas involved in the I/O operation。

程序块2):
static inline void *bio_data(struct bio *bio)
{
        if (bio->bi_vcnt)
                return page_address(bio_page(bio)) + bio_offset(bio);
        return NULL;
}

总结:如果文件数据没有缓存,那么先将数据从磁盘读到buffer page中,然后使用copy_to_user函数将数据从内核空间拷贝到用户空间的buffer中。数据不需要从磁盘读到一个临时的buffer,然后在拷贝到buffer page。

        对于比较大的文件,如果对其进行操作,那么有大量的page在cache中,linux采用基树对这些page进行管理,方便快速的定位cache中具体的某个page。每个基树最多有64个slot,基树的一个叶子节点就是一个page。


图三. Two examples of a radix tree
三、Ext2文件系统read函数调用过程



图四. Read系统调用执行流程图

文件系统数据流程分析.doc.tar.gz

250.32 KB, 下载次数: 143

论坛徽章:
0
2 [报告]
发表于 2012-12-09 16:00 |只看该作者
谢谢您无私的分享,学习了.

论坛徽章:
0
3 [报告]
发表于 2013-09-20 11:14 |只看该作者
学习,分享!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP