2012-01-25 10 views
11

Scrive un semplice filesystem FUSE che viene archiviato in memoria. Il file system deve supportare i seguenti comandi:In filesystem FUSE in memoria

ls, mkdir, CP

Questa domanda è stato chiesto di recente in un'intervista, non ero in grado risposta esso. Quindi ho deciso di impararlo.

Effettuava alcune ricerche e trovato alcune guide sulla creazione del mio file system FUSE. Sono davvero all'oscuro su come implementare il filesystem in memoria.

Le mie domande sono

  • Am I andando nella direzione giusta?
  • Cos'altro dovrei leggere?
  • Qual è la soluzione?

Link che sto leggendo:

Nell'ultimo link c'è una menzione sul caching in memoria con PyFileSystem. Non sono sicuro di come possa essere d'aiuto.

PS: Questa è stata un'interrogazione scritta Domanda, quindi la risposta deve essere abbastanza semplice da scrivere su carta entro 10-15 minuti.

+1

Capisco che questo potrebbe aggirare la domanda, ma perché non usare [tmpfs] (http://en.wikipedia.org/wiki/Tmpfs) invece di far ruotare il proprio file system tramite FUSE? –

+0

@ FrédéricHamidi: tmpfs è una buona alternativa, grazie. Ma purtroppo questo non risponde alla domanda come hai detto tu. – Gautam

+0

Immagino che _stored in memory_ significhi che devi allocare qualche tipo di buffer e usare quel buffer come back-end fs? –

risposta

5

Avevo seguito un corso in cui dovevamo creare un file system distribuito in memoria simile nella progettazione a Frangipani. Il corso è stato fortemente ispirato da MIT's Distributed Systems course. Fare i primi compiti di laboratorio sarebbe un buon esercizio.

This tutorial è anche abbastanza utile.

3

Non è stato specificato un linguaggio di programmazione, sebbene FUSE sia nativo in C++, esistono binding nativi di Golang, implementati a bazil.org/fuse.

direi che le parti principali della risposta devono includere quanto segue:

  1. Una struttura di dati per gestire l'albero del file system in memoria
  2. Le descrizioni dei nodi e la loro relazione inode
  3. Ganci per catturare le richieste del server FUSE per gestire i comandi cli
  4. Una descrizione del montaggio di una cartella con il server FUSE.

Ho recentemente scritto un file system in memoria utilizzando questo adattatore: github.com/bbengfort/memfs. La mia recensione sulle sue prestazioni è qui: In-Memory File System with FUSE. Rapidamente, un paio di scelte che ho fatto:

La memoria struttura dati contiene 2 le strutture primarie, dir e di file che sono entrambi i nodi:

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 
} 

Come si può vedere, si tratta di un albero semplice che è percorribile su e giù attraverso i collegamenti Children e Parent. L'attributo Data del file contiene tutti i contenuti dei file. Pertanto, il file system deve solo creare una directory "root" denominata "\" nel punto di montaggio, quindi su mkdir a Dir viene aggiunto ai suoi figli e su cp viene aggiunto uno File. In Go, questo è il più semplice:

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 
    } 
} 

Ora è necessario ganci per implementare le varie richieste di FUSE e chiamate. Ecco un esempio per 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 
} 

Infine, chiudere la questione intervista con una discussione su come compilare ed eseguire il server, il montaggio di un percorso e, forse, come le chiamate del kernel intercetta fusibile e li passa al vostro processo in spazio utente.

+0

Risposta stupenda, codice fornito, grazie! –