首页 >> 大全

2. fuse内核队列

2023-10-06 大全 32 作者:考证青年

实现内存零拷贝。在默认情况下,fuse 必须通过read()从/dev/fuse读取请求,通过write()将请求回复写入/dev/fuse。每次读写系统调用都需要进行一次内核-用户空间的内存拷贝。这样对读写的性能损耗十分严重,因为一次内存拷贝需要处理大量数据。为了缓解这个问题,fuse支持了Linux内核提供的 功能。 允许用户空间在两个内核内存缓冲区之间传输数据,而无需将数据复制给用户空间。如果fuse 实现了()方法,则 FUSE 从/dev/fuse读取数据,并以包含文件描述符的缓冲区的形式将数据直接传递给此方法处理,从而省去了一次内存申请与拷贝。

多线程模式。在多线程模式下,fuse 以一个线程开始,如果内核队列中有两个以上的,则会自动生成其他线程。默认最大支持10个线程同时处理请求。

2. fuse内核队列

图片摘自《To FUSE or Not to FUSE: of User-Space File 》

fuse在内核中维护了五个队列,分别为:、、、、。一个请求在任何时候只会存在于一个队列中。

a) : 队列用于暂存异步请求。在默认情况下,只有读请求进入 队列;当 cache启用时,写请求也会进入 队列。当开启 cache时,来自用户进程的写请求会先在页缓存中累积,然后当 线程被唤醒时会下刷脏页。在下刷脏页时,FUSE会构造异步请求,并将它们放入 队列中。

b) :同步请求(例如,元数据)放在 队列中,并且队列会周期性接收来自 的请求。但是队列中异步请求的个数最大为(最大为12),当队列的异步请求未达到12时,队列的请求将被移动到队列中。这样做的目的是为了控制队列中异步请求的个数,防止在突发大量异步请求的情况下,阻塞了同步请求。

c) :当队列中的请求被转发到fuse 的同时,也被移动到队列。所以队列中的请求,表示正在被处理fuse 处理的请求。当fuse 真正处理完请求,通过/dev/fuse下发reply时,该请求将从队列中删除。

d) :用于存放中断请求,比如当发送的请求被用户取消时,内核会发送一个请求,来取消已被发送的请求。中断请求的优先级最高,中的请求会最先得到处理。

e) :请求用于删除中缓存的inode。

3. /dev/fuse 读写调用流程

_内核工作队列_内核消息队列

Fuse 加载过程中注册了对/dev/fuse的操作接口。/分别对应fuse 从内核读取请求,以及处理完请求后写回reply的函数调用。我们分别看下具体的代码片段

当 、、队列都没有请求时,读进程进入休眠。一旦有请求到达,这个等待队列上的进程将被唤醒。 和 的请求优先级高于队列。当请求的数据内容被拷贝至用户空间后,该请求会被移至队列,并且req->flags会保存当前请求的状态。

当fuse 处理完请求后,会将结果写回到/dev/fuse。写数据保存在 中,并且会根据 id在fc()中找到对应的req,并将写回的参数从拷贝至req->out。

最后我们以为例,看下fuse整体是如何工作的:

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了