在内存中的FUSE文件系统

15
写一个简单的FUSE文件系统,存储在内存中。该文件系统必须支持以下命令:ls、mkdir、cp。
这个问题最近在一次面试中被问到,我无法回答。所以我决定学习一下。我查找了一些关于构建自己的FUSE文件系统的指南,但对如何在内存中实现文件系统还不是很清楚。
我的问题是:
- 我是否朝着正确的方向前进? - 我还应该阅读什么? - 解决方案是什么?
我正在阅读的链接: 在最后一个链接中提到了使用PyFileSystem进行内存缓存。我不确定这如何有助于解决问题。
PS:这是一道笔试题,因此答案必须简单明了,能够在10-15分钟内写在纸上。

1
我知道这可能是绕开问题,但为什么不使用tmpfs而不是通过FUSE自己创建文件系统呢? - Frédéric Hamidi
@FrédéricHamidi:tmpfs是一个不错的替代方案,谢谢。但遗憾的是,正如你所提到的,这并没有回答问题。 - Gautam
我猜“存储在内存中”意味着您需要分配某种缓冲区,并将该缓冲区用作fs后端? - Ortwin Angermeier
2
只需下载tar.gz文件,开始实现回调函数,你就完成了。当你编写完回调函数后,你会清楚地看到自己不理解的地方。 - marinara
@FrédéricHamidi 因为这是减少非特权用户对系统管理员依赖的一种方式? - binki
2个回答

5

我曾参加过一门课程,在课程中,我们需要构建一个内存分布式文件系统,其设计类似于Frangipani。该课程深受MIT分布式系统课程的启发。完成他们的前几个实验任务将是一个很好的练习。

这份教程也相当有帮助。


5

您没有指定编程语言,尽管FUSE是C++本地的,但有原生的Golang绑定,在bazil.org/fuse实现。

我认为答案的主要部分需要包括以下内容:

  1. 一个数据结构来处理内存中的文件系统树
  2. 节点及其与iNodes的关系的描述
  3. 钩子以捕获FUSE服务器请求以处理cli命令
  4. 挂载带有FUSE服务器的文件夹的描述。

我最近使用此适配器编写了一个内存文件系统:github.com/bbengfort/memfs。关于其性能的文章在这里:使用FUSE的内存文件系统。简而言之,我做出了一些选择:

内存中的数据结构包含两个主要结构体,dir和file,都是节点:

type Node struct {
    ID uint64 
    Name string 
    Attrs fuse.Attr 
    Parent *Dir 
}

type Dir struct {
    Node
    Children map[string]Node
}

type File struct {
    Node
    Data []byte 
}

如您所见,这是一棵简单的树,可以通过ChildrenParent链接向上和向下遍历。文件的Data属性保存了所有文件的内容。因此,文件系统只需要在挂载点创建一个名为"\"的“根”目录,然后在mkdir时添加一个Dir到其子目录中,在cp时添加一个File。在Go中,这很简单:

type FS struct {
    root *Dir 
}

func Mount(path string) error {

    // Unmount the FS in case it was mounted with errors.
    fuse.Unmount(path)

    // Mount the FS with the specified options
    conn, err := fuse.Mount(path)
    if err != nil {
        return err
    }

    // Ensure that the file system is shutdown
    defer conn.Close()

    // Create the root dir and file system 
    memfs := FS{
        root: &Dir{
            ID: 1, 
            Name: "\", 
            Parent: nil, 
        },
    }

    // Serve the file system
    if err := fs.Serve(conn, memfs); err != nil {
        return err
    }
}

现在你需要钩子来实现各种FUSE请求和调用。这里是一个mkdir的示例:
func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
    // Update the directory Atime
    d.Attrs.Atime = time.Now()

    // Create the child directory
    c := new(Dir)
    c.Init(req.Name, req.Mode, d)

    // Set the directory's UID and GID to that of the caller
    c.Attrs.Uid = req.Header.Uid
    c.Attrs.Gid = req.Header.Gid

    // Add the directory to the directory
    d.Children[c.Name] = c

    // Update the directory Mtime
    d.Attrs.Mtime = time.Now()

    return c, nil
}

最后,通过讨论如何编译和运行服务器并挂载到路径上,以及FUSE如何拦截内核调用并将其传递给用户空间中的进程来结束面试问题。

写作链接已失效:https://web.archive.org/web/20170219015022/https://bbengfort.github.io/snippets/2017/01/30/fuse-inmem-fs.html - mxmlnkn
我已将写作链接更新为新博客。 - bbengfort

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接