2012-01-25 87 views
11

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

LS,MKDIR,CP

这个问题最近被要求在接受采访时,我不能回答。 所以我决定学习它。

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

我的问题是

  • 上午我在正确的方向前进吗?
  • 我还应该阅读些什么?
  • 解决方案是什么?

链接,我读:

在最后一个环节中存在的内存缓存与PyFileSystem一提。 我不确定这可能会有帮助。

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

+1

我明白这可能会绕过这个问题,但为什么不使用[tmpfs](http://en.wikipedia.org/wiki/Tmpfs)而不是通过FUSE来滚动自己的文件系统? –

+0

@FrédéricHamidi:tmpfs是一个很好的选择,谢谢。但可悲的是,这并不能回答你提到的问题。 – Gautam

+0

我想_stored in memory_意味着你必须分配某种缓冲区并将该缓冲区用作fs后端? –

回答

3

您没有指定编程语言,但FUSE是本地C++,本地Golang绑定在bazil.org/fuse处执行。

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

  1. 的数据结构来处理文件系统树在内存中的节点
  2. 描述和他们的i节点
  3. 关系
  4. 用于捕获FUSE服务器请求以处理cli命令的钩子
  5. 用FUSE服务器装入文件夹的说明。

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

的内存中的数据结构包含2层主要结构,目录和文件是两个节点:

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拦截内核调用,并在它们传递给你的流程的讨论用户空间。

+0

真棒回答,提供代码,谢谢! –