2012-01-25 91 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

真棒回答,提供代碼,謝謝! –