15

编写一个存储在内存中的简单 FUSE 文件系统。文件系统必须支持以下命令:

ls, mkdir, cp

这个问题最近在一次采访中被问到,我无法回答。所以我决定学习它。

做了一些搜索,找到了一些关于构建我自己的 FUSE 文件系统的指南。我对如何在内存中实现文件系统一无所知。

我的问题是

  • 我是否朝着正确的方向前进?
  • 我还应该阅读什么?
  • 解决办法是什么 ?

我正在阅读的链接:

在最后一个链接中,提到了PyFileSystem的内存缓存。我不确定这有什么帮助。

PS:这是一个书面面试问题,所以答案必须足够简单,以便在 10-15 分钟内写在纸上。

4

2 回答 2

5

我参加了一个课程,我们必须构建一个在设计上类似于Frangipani的内存分布式文件系统。该课程深受麻省理工学院分布式系统课程的启发。做他们最初的几项实验室任务将是一个很好的练习。

本教程也很有帮助。

于 2012-01-27T00:07:04.707 回答
5

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

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

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

我最近使用这个适配器编写了一个内存文件系统:github.com/bbengfort/memfs。我关于它的性能的文章在这里:In-Memory File System with FUSE。很快,我做出了一些选择:

内存中的数据结构包含 2 个主要结构,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 
}

Children如您所见,这是一个简单的树,可以通过和Parent链接上下遍历。File的Data属性保存了文件的所有内容。因此,文件系统只需要创建一个"\"在挂载点调用的“根”目录,然后将 on mkdiraDir添加到其子级,然后添加 on cpa 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 如何拦截内核调用并将它们传递给用户空间中的进程来结束面试问题。

于 2017-02-05T14:42:26.913 回答