FUSE - 避免在 GetAttr 中计算大小

Posted

技术标签:

【中文标题】FUSE - 避免在 GetAttr 中计算大小【英文标题】:FUSE - avoid calculating size in GetAttr 【发布时间】:2018-02-26 07:44:25 【问题描述】:

我正在为远程服务实现 FUSE 文件系统。 当用户打开文件时,我会进行网络调用以获取文件的内容。 It appears 必须通过 GetAttr 报告文件的大小才能打开工作。 为了知道文件的大小,我必须发出网络调用,并且由于在执行ls 时每个条目都会调用GetAttr,所以我担心这种设计(如果用户在目录中执行ls有很多项目,它必须获取所有文件,即使用户不想打开其中任何一个)。

我该如何解决这个问题?我的想法是:

使用不依赖于报告大小的较低级别的读取方法?我认为使用 Read 而不是 Open 会有所帮助,但是如果没有尺寸,我就无法使用它。 如果我能将来自OpenGetAttr 呼叫与其他呼叫(包括ls)区分开来,我可以仅在需要时发出网络呼叫。

我使用 Go 和 go-fuse,但我认为这无关紧要,因为这是一个通用的 FUSE 问题。

此外,FUSE 文档是非常少的(实际上是缺失的)文档。如果熟悉此事的人能解释一下lscdcat 的调用流程,那就太好了——按什么顺序调用 FUSE 函数。 比如为什么会有OpenRead

更新: 我一直在浏览 SSHFS,它被认为是 FUSE 文件系统的规范示例,它似乎也可以通过网络在 getattr 上获取文件:https://github.com/libfuse/sshfs/blob/master/sshfs.c#L3167 你怎么看?

【问题讨论】:

【参考方案1】:

您看到的问题是因为内核正在缓冲您的读取,并且当它这样做时,它使用 inode 的大小来准确计算它必须复制到用户空间的字节数 (https://elixir.bootlin.com/linux/v4.19.7/source/mm/filemap.c#L2137)。所以有不同的解决方法:

    从 GetAttr 返回巨大的 st_size

    当您打开文件时,设置 direct_io 标志,这样您就不会使用页面缓存。

【讨论】:

【参考方案2】:

我不知道 go-fuse 的 API。以下信息基于 libfuse 的 API。

SSHFS 的 GetAttr 是在函数sshfs_getattr 中实现的,看起来就像发送网络请求获取文件大小信息。

当你运行cd时,它会运行.access回调来检查目录是否存在。

当您运行ls 时,它会首先调用.readdir 回调获取目录信息,然后调用.getattr 获取该目录中文件的信息。

当您运行cat 时,它将首先调用.getattr 获取文件信息和路径信息。然后调用.open => .read => .release

FUSE 缺少文档,你最好先写一个例子,然后你可以在这些回调中添加一些printf 来获取一些信息。

    .open 中,您可以创建一个私有数据并将其设置为fuse_file_info::fh。这个fuse_file_info::fh 可以在以后的.read 回调中使用。 您可以在.getattr 回调中将所有尺寸信息设置为零。然后在.open中,将fuse_file_info::direct_io设置为1。在.read中,首先从网络中读取数据,如果到达文件末尾,则在return 0中读取return 0

当我编写文件系统时,这个doc 对我帮助很大。

【讨论】:

将文件大小设置为零会使某些程序感到困惑,以至于它们甚至不会尝试读取文件。

以上是关于FUSE - 避免在 GetAttr 中计算大小的主要内容,如果未能解决你的问题,请参考以下文章

Fuse lib示例删除了我的主文件夹

计算字谜时如何避免溢出?

HDFS FUSE 访问频繁致使系统奔溃

玩转红帽JBoss Fuse|红帽技术Open讲

使用 GCC/G++/AS 在固定大小的内存边界上对齐本机代码?

Rust 中“fuse”背后的词源或软件原理是啥?