ImageVerifierCode 换一换
格式:DOCX , 页数:17 ,大小:180.06KB ,
资源ID:17209541      下载积分:5 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-17209541.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(linuxkernelfuse源码剖析.docx)为本站会员(b****2)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

linuxkernelfuse源码剖析.docx

1、linuxkernelfuse源码剖析FUSE源码剖析1.前言 本文是对FUSE-2.9.2源码的学习总结。FUSE代码在用户空间和内核空间都有运行,为了突出重点,先简要描述了在基于FUSE的用户空间文件系统中执行write操作的一般流程,接下来介绍了重要的数据结构,最后以FUSE的运行过程为线索,剖析FUSE程序运行过程的3个关键步骤:1.FUSE模块加载2.mount和open过程3.对文件write。对于虚拟文件系统和设备驱动的相关概念本文仅作简要说明。需要说明的是,由于内核的复杂性及个人能力的有限,本文省略了包括内核同步,异常检查在内的诸多内容,希望可以突出重点。2.FUSE下writ

2、e的一般流程 图1在基于FUSE的用户空间文件系统中执行write操作的流程如图1所示(由于版面关系,图中部分函数是缩写,请参考源码):1.客户端在mount目录下面,对一个regularfile调用write,这一步是在用户空间执行2.write内部会调用虚拟文件系统提供的一致性接口vfs_write3.根据FUSE模块注册的file_operations信息,vfs_write会调用fuse_file_aio_write,将写请求放入fuseconnection的requestpendingqueue,随后进入睡眠等待应用程序reply4.用户空间的libfuse有一个守护进程通过函数fu

3、se_session_loop轮询杂项设备/dev/fuse,一旦requestqueue有请求即通过fuse_kern_chan_receive接收5.fuse_kern_chan_receive通过read读取requestqueue中的内容,read系统调用实际上是调用的设备驱动接口fuse_dev_read6.在用户空间读取并分析数据,执行用户定义的write操作,将状态通过fuse_reply_write返回给kernel7.fuse_reply_write调用VFS提供的一致性接口vfs_write8.vfs_write最终调用fuse_dev_write将执行结果返回给第3步中等

4、待在waitq的进程,此进程得到reply后,write返回3.数据结构本节主要介绍了FUSE中比较重要的数据结构,需要说明的是图示中只列出了与叙述相关的数据成员,完整的数据结构细节请参考源码。3.1.内核部分 图2structfuse_conn:每一次mount会实例化一个structfuse_conn即fuseconnection,它代表了用户空间和内核的通信连接。fuseconnection维护了包括pendinglist,processinglist和iolist在内的requestqueue,fuseconnection通过这些队列管理用户空间和内核空间通信过程。structfuse

5、_req:每次执行系统调用时会生成一个structfuse_req,这些fuse_req依据state被组织在不同的队列中,structfuse_conn维护了这些队列.structfile:存放打开文件与进程之间进行交互的有关信息,描述了进程怎样与一个打开的文件进行交互,这类信息仅当进程访问文件期间存在于内核内存中。structinode:文件系统处理文件所需要得所有信息都放在一个名为inode(索引节点)的数据结构中。文件名可以随时更改,但是索引节点对文件是唯一的,并且随着文件的存在而存在。structfile_operation:定义了可以对文件执行的操作。3.2.用户空间部分 图3st

6、ructfuse_req:这个结构和上文中内核的fuse_req同名,有着类似的作用,但是数据成员不同。structfuse_session:定义了客户端管理会话的结构体,包含了一组对session可以执行的操作。structfuse_chan:定义了客户端与FUSE内核连接通道的结构体,包含了一组对channel可以执行的操作。structfuse_ll_ops:结构的成员为一个函数指针func和命令名字符串name,内核中发过来的每一个request最后都映射到以此结构为元素的数组中。4.FUSE模块加载FUSE内核模块需要在用户空间使用insmod或者modprobe加载。它们通过系统调

7、用init_module启动加载过程,注册过程比较简单,包括如下步骤:1.创建高速缓存结构fuse_inode_cachep2.遍历file_systems链表,如果未注册,则将fuseblk_fs_type链到file_systems链表尾部3.遍历file_systems链表,如果未注册,则将fuse_fs_type链到file_systems链表尾部4.创建fuse_kobj和connections_kobj两个kobject5.遍历file_systems链表,如果未注册,则将fuse_ctl_fs_type链到file_systems链表尾部模块成功加载以后,以下接口被注册12345

8、67891011121314151617181920212223242526272829303132333435static structfile_system_typefuseblk_fs_type = /块设备.owner= THIS_MODULE,.name = fuseblk,.mount= fuse_mount_blk,.kill_sb= fuse_kill_sb_blk,.fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE,;static structfile_system_typefuse_fs_type = .owner= THIS_MODU

9、LE,.name = fuse,.fs_flags = FS_HAS_SUBTYPE,.mount= fuse_mount,.kill_sb= fuse_kill_sb_anon,;conststructfile_operationsfuse_dev_operations = .owner= THIS_MODULE,.llseek = no_llseek,.read = do_sync_read,.aio_read = fuse_dev_read,.splice_read= fuse_dev_splice_read,.write= do_sync_write,.aio_write= fuse_

10、dev_write,.splice_write = fuse_dev_splice_write,.poll = fuse_dev_poll,.release= fuse_dev_release,.fasync = fuse_dev_fasync,;static structmiscdevicefuse_miscdevice = .minor = FUSE_MINOR,.name= fuse,.fops= &fuse_dev_operations,;5.mount和open过程FUSE模块加载注册了fuseblk_fs_type和fuse_fs_type两种文件类型,默认情况下使用的是fuse_

11、fs_type即mount函数指针被初始化为fuse_mount,而fuse_mount实际调用mount_nodev,它主要由如下两步组成:1.sget(fs_type)搜索文件系统的超级块对象(super_block)链表(type-fs_supers),如果找到一个与块设备相关的超级块,则返回它的地址。否则,分配并初始化一个新的超级块对象,把它插入到文件系统链表和超级块全局链表中,并返回其地址。2.fill_super(此函数由各文件系统自行定义):这个函数式各文件系统自行定义的函数,它实际上是fuse_fill_super。一般fill_super会分配索引节点对象和对应的目录项对象,

12、并填充超级块字段值,另外对于fuse还需要分配fuse_conn,fuse_req。需要说明的是,它在底层调用了fuse_init_file_inode用fuse_file_operations和fuse_file_aops分别初始化inode-i_fop和inode-i_data.a_ops。1234567891011121314151617181920212223242526272829static conststructfile_operationsfuse_file_operations = .llseek = fuse_file_llseek,.read = do_sync_read

13、,.aio_read = fuse_file_aio_read,.write= do_sync_write,.aio_write= fuse_file_aio_write,.mmap = fuse_file_mmap,.open = fuse_open,.flush= fuse_flush,.release= fuse_release,.fsync= fuse_fsync,.lock = fuse_file_lock,.flock= fuse_file_flock,.splice_read= generic_file_splice_read,.unlocked_ioctl = fuse_fil

14、e_ioctl,.compat_ioctl = fuse_file_compat_ioctl,.poll = fuse_file_poll,.fallocate= fuse_file_fallocate,;static conststructaddress_space_operationsfuse_file_aops= .readpage = fuse_readpage,.writepage= fuse_writepage,.launder_page = fuse_launder_page,.readpages= fuse_readpages,.set_page_dirty = _set_pa

15、ge_dirty_nobuffers,.bmap = fuse_bmap,.direct_IO= fuse_direct_IO,;open系统调用底层实现相当复杂,它的主要工作是实例化file对象。file-f_op就是在open中被赋值为inode-i_fop,这一过程读者可以在fs/open.c中的do_entry_open函数中找到。如上所述,inode-i_fop已经被fuse_init_file_inode初始化为fuse_file_operations。至此,普通文件和设备文件的操作接口都已成功初始化。6.FUSE用户空间流程FUSE在用户空间提供了fuseuserspacelib

16、rary和mount/unmount。fuseusespacelibrary提供了一组API供用户开发用户空间文件系统。用户要做的就是实现fuse_operations或fuse_lowlevel_ops定义的操作,这两个结构类似于VFS中的structfile_operations。mount工具fusermount用于挂载用fuse实现的文件系统。用户在使用fuse的时候有两种开发模式:一种是high-level模式,此模式下fuse的入口函数为fuse_main,它封装了一系列初始化操作,使用简单,但是不灵活。另一种是low-level模式,用户可以利用fuse提供的底层函数灵活开发应用

17、程序。需要说明的是high-level模式其实是对low-level的封装,因此这里分析lowlevel模式。 图4图4展示FUSE在用户空间总体工作流程:1.调用fuse_mount实例化structfuse_chan为ch,将指定目录mount到挂载点2.实例化structfuse_session为se,并且将se和ch关联3.进入循环,从/dev/fuse读取数据,处理以后执行响应的操作 图5图5展示了fuse_mount函数内部流程:1.确保打开的文件描述符至少大于22.分析并检查用户传入的参数3.打开/dev/fuse得到fd,用户空间与内核通过/dev/fuse通信4.mount源

18、目录到挂载点5.用fd实例化structfuse_chan为ch6.返回ch 图6图6展示了fuse_mount_compat25内部细节,进入循环以后,函数fuse_session_receive_buf实际通过fuse_ll_receive_buf从/dev/fuse中读取数据,其通过fbuf返回。fuse_ll_receive_buf是通过read或者splice系统调用从内核request队列中读取数据。函数fuse_session_process_buf实际通过fuse_ll_process_buf处理数据,fuse_ll_process_buf会根据数据类型最后执行用户定义的操作f

19、use_ll_opsin-opcode.func(req,in-nodeid,inarg)。执行完用户定义的操作以后需要向内核返回执行结果,fuse提供了一组类似fuse_reply_XXX的API,这些API最后实际通过系统调用writev将结果传入内核。7.FUSE内核部分流程FUSE在内核空间执行的部分主要包括FUSE模块加载以及杂项设备驱动。模块加载过程已经在第4节介绍,这一节主要描述从request队列读写请求的流程。FUSE设备驱动程序本质上是一个生产者消费者模型。生产者为用户在挂载目录下对普通文件(regularfile)执行的系统调用,每一次系统调用会产生一个request然后

20、将去放入pendinglist。pendinglist能存放的元素个数只和系统内存有关;消费者为用户对设备文件/dev/fuse或者/dev/fuseblk的read,这一操作会去pendinglist或interruptlist取request,当list为空时,进程主动schedule让出CPU。request结构的细节在第3节已经介绍,此处不赘述。enmufuse_req_state定义了request的6种状态,其含义分别为:FUSE_REQ_INIT:请求被初始化FUSE_REQ_PENDING:请求挂起待处理FUSE_REQ_READING:请求正在读FUSE_REQ_SENT:请

21、求被发送FUSE_REQ_WRITING:请求正在写FUSE_REQ_FINISHED:请求已经完成 图7图7是在mount目录下面执行write以后触发的一个函数调用序列,图中省略了VFS层的函数调用。fuse_file_aio_write是在mount过程中注册到fuse_file_operations.aio_write的函数指针,它会调用fuse_perform_write,fuse_perform_write调用get_fuse_conn得到structfuse_conn实例fc,它保存在structsuper_block的私有数据成员中s_fs_info中,而structsuper

22、_block是structinode的一个成员。接下来是循环从用户空间拷贝数据到内核,数据实际保存在structpages中,内核fuse_req保存了pages指针,然后调用fuse_send_write_pages。 图8Fuse_send_write_pages调用会等待脏数据写回到磁盘上,然后调用fuse_write_fill将包括操作码FUSE_WRITE在内的信息写入request。随后fuse_request_send(fc,req),它先通过fuse_get_unique获取唯一请求号,请求号是一个64位无符号整数,请求号从1开始随请求依次递增。然后调用queue_reques

23、t(fc,req),它主要完成4件事情:1.将request-list插入fc维护的pending链表尾部2.置req-state为FUSE_REQ_PENDING3.wake_up唤醒等待队列fc-waitq4.kill_fasync异步通知用户进程数据到达从queue_request返回以后调用request_wait_answer:进程被投入睡眠,等待请求完成(wait_event(req-state=FUSE_REQ_FINISHED)。如果用户程序处理完了请求,它会reply,进程被唤醒,到此可以向上层调用返回处理结果(错误码或者写入字节数)。在第6节我们提到了用户空间有个daemo

24、n进程会循环read设备文件/fuse/dev以便处理内核请求,图9展示了该read调用触发的函数调用序列。 图9从第4节可知,FUSE模块加载过程注册了对设备文件/dev/fuse的操作接口fuse_dev_operations。由此可知,read底层实际调用的是fuse_dev_readfuse_dev_read首先通过fuse_get_conn获得structfuse_conn的实例fc,通过fuse_copy_init为structfuse_copy_state分配内存并将其实例化。主要的数据读取在fuse_dev_do_read中分4步完成:1.request_wait:在挂起的列表

25、上等待一个请求到达:(1).DECLARE_WAITQUEUE(wait,current):创建等待队列项,并将其初始化为current(2).add_wait_queue_exclusive(&fc-waitq,&wait):将wait加入fc-waitq,当有请求发送到FUSE文件系统时,这个等待队列上的进程会被唤醒(3).如果没有request,一直循环检查pendinglist和interruptlist,直到有请求;如果有请求则将state设置为TASK_RUNNING(4).将wait从等待队列中移除2.list_entry(fc-pending.next,structfuse_req,list):从fc-pending.next中取出request,req-state状态设为FUSE_REQ_READING,3.将req-list移到fc-io4.fuse_copy_one:将数据拷贝到structfuse_copy_state的buf中

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2