Commit 983246ef authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Document implementation.

parent 73a13268
...@@ -4,15 +4,6 @@ package fuse ...@@ -4,15 +4,6 @@ package fuse
// FileSystemConnector. The functions for satisfying the raw interface // FileSystemConnector. The functions for satisfying the raw interface
// are in fsops.go // are in fsops.go
/* TODO - document overall structure and locking strategy.
"at a first glance, questions that come up: why doesn't fsconnector
have the lock, why does every node need it? (I have some ideas, but
they take a while to verify)"
"a short sum up on how the forget count is handled"
*/
import ( import (
"fmt" "fmt"
"log" "log"
...@@ -25,26 +16,42 @@ import ( ...@@ -25,26 +16,42 @@ import (
// Tests should set to true. // Tests should set to true.
var paranoia = false var paranoia = false
func NewFileSystemOptions() *FileSystemOptions { // FilesystemConnector is a raw FUSE filesystem that manages
return &FileSystemOptions{ // in-process mounts and inodes. Its job is twofold:
NegativeTimeout: 0.0, //
AttrTimeout: 1.0, // * It translates between the raw kernel interface (padded structs
EntryTimeout: 1.0, // of int32 and int64) and the more abstract NodeFileSystem interface.
Owner: CurrentOwner(), // that is based on a hierarchy of Inodes
} //
} // * It manages mounting and unmounting of NodeFileSystems into the
// directory hierarchy
// FilesystemConnector is a raw FUSE filesystem that manages in-process mounts and inodes. //
// To achieve this, the connector only needs a pointer to the root
// node.
type FileSystemConnector struct { type FileSystemConnector struct {
DefaultRawFileSystem DefaultRawFileSystem
Debug bool Debug bool
// Callbacks for talking back to the kernel.
fsInit RawFsInit fsInit RawFsInit
// Translate between uint64 handles and *Inode.
inodeMap HandleMap inodeMap HandleMap
// The root of the FUSE file system.
rootNode *Inode rootNode *Inode
} }
func NewFileSystemOptions() *FileSystemOptions {
return &FileSystemOptions{
NegativeTimeout: 0.0,
AttrTimeout: 1.0,
EntryTimeout: 1.0,
Owner: CurrentOwner(),
}
}
func NewFileSystemConnector(nodeFs NodeFileSystem, opts *FileSystemOptions) (me *FileSystemConnector) { func NewFileSystemConnector(nodeFs NodeFileSystem, opts *FileSystemOptions) (me *FileSystemConnector) {
me = new(FileSystemConnector) me = new(FileSystemConnector)
if opts == nil { if opts == nil {
......
...@@ -18,6 +18,7 @@ type openedFile struct { ...@@ -18,6 +18,7 @@ type openedFile struct {
dir rawDir dir rawDir
} }
type fileSystemMount struct { type fileSystemMount struct {
// The file system we mounted here. // The file system we mounted here.
fs NodeFileSystem fs NodeFileSystem
...@@ -32,7 +33,7 @@ type fileSystemMount struct { ...@@ -32,7 +33,7 @@ type fileSystemMount struct {
options *FileSystemOptions options *FileSystemOptions
// Protects Children hashmaps within the mount. treeLock // Protects Children hashmaps within the mount. treeLock
// should be acquired before openFilesLock // should be acquired before openFilesLock.
treeLock sync.RWMutex treeLock sync.RWMutex
// Manage filehandles of open files. // Manage filehandles of open files.
......
...@@ -8,7 +8,9 @@ import ( ...@@ -8,7 +8,9 @@ import (
var _ = log.Println var _ = log.Println
// The inode reflects the kernel's idea of the inode. // The inode reflects the kernel's idea of the inode. Inodes may be
// created automatically when the kernel does lookups inode, or by
// explicitly by calling Inode.CreateChild().
type Inode struct { type Inode struct {
handled Handled handled Handled
...@@ -16,43 +18,48 @@ type Inode struct { ...@@ -16,43 +18,48 @@ type Inode struct {
openFilesMutex sync.Mutex openFilesMutex sync.Mutex
openFiles []*openedFile openFiles []*openedFile
// treeLock is a pointer to me.mount.treeLock; we need store fsInode FsNode
// this mutex separately, since unmount may set me.mount = nil
// during Unmount(). Constant during lifetime. // Each inode belongs to exactly one fileSystemMount. This
// pointer is constant during the lifetime, except upon
// Unmount() when it is set to nil.
mount *fileSystemMount
// treeLock is a pointer to me.mount.treeLock. We store it
// here for convenience. Constant during lifetime of the
// inode.
// //
// If multiple treeLocks must be acquired, the treeLocks // If multiple treeLocks must be acquired, the treeLocks
// closer to the root must be acquired first. // closer to the root must be acquired first.
treeLock *sync.RWMutex treeLock *sync.RWMutex
// All data below is protected by treeLock. // All data below is protected by treeLock.
fsInode FsNode
children map[string]*Inode children map[string]*Inode
// Contains directories that function as mounts. The entries // Contains directories that function as mounts. The entries
// are duplicated in children. // are duplicated in children.
mounts map[string]*fileSystemMount mounts map[string]*fileSystemMount
// This is exclusively used for managing the lifetime of
// nodeId below, and it is ok for a node to have 0 lookupCount
// and be in the system if it is synthetic.
lookupCount int
// The nodeId is only used to communicate to the kernel. If // The nodeId is only used to communicate to the kernel. If
// it is zero, it means the kernel does not know about this // it is zero, it means the kernel does not know about this
// Inode. // Inode. nodeIds are chosen by FileSystemConnector.inodeMap.
nodeId uint64 nodeId uint64
// lookupCount registers how often the kernel got this inode
// back for a Lookup operation. This number is a reference
// count, and the Forget operation lists how many references to drop.
//
// The lookupCount is exclusively used for managing the
// lifetime of nodeId variable. It is ok for a node to have 0
// == lookupCount. This can happen if the inode is synthetic.
lookupCount int
// This is to prevent lookupCount==0 node from being dropped. // This is to prevent lookupCount==0 node from being dropped.
synthetic bool synthetic bool
// Non-nil if this is a mountpoint. // Non-nil if this inode is a mountpoint, ie. the Root of a
// NodeFileSystem.
mountPoint *fileSystemMount mountPoint *fileSystemMount
// The file system to which this node belongs. Is constant
// during the lifetime, except upon Unmount() when it is set
// to nil.
mount *fileSystemMount
} }
func newInode(isDir bool, fsNode FsNode) *Inode { func newInode(isDir bool, fsNode FsNode) *Inode {
......
...@@ -10,20 +10,31 @@ import ( ...@@ -10,20 +10,31 @@ import (
var _ = log.Println var _ = log.Println
// A parent pointer: node should be reachable as parent.children[name]
type clientInodePath struct { type clientInodePath struct {
parent *pathInode parent *pathInode
name string name string
node *pathInode node *pathInode
} }
// PathNodeFs is the file system that can translate an inode back to a
// path. The path name is then used to call into an object that has
// the FileSystem interface.
//
// Lookups (ie. FileSystem.GetAttr) may return a inode number in its
// return value. The inode number ("clientInode") is used to indicate
// linked files. The clientInode is never exported back to the kernel;
// it is only used to maintain a list of all names of an inode.
type PathNodeFs struct { type PathNodeFs struct {
Debug bool Debug bool
fs FileSystem fs FileSystem
root *pathInode root *pathInode
connector *FileSystemConnector connector *FileSystemConnector
// Used for dealing with hardlinks.
clientInodeMapMutex sync.Mutex clientInodeMapMutex sync.Mutex
// This map lists all the parent links known for a given
// nodeId.
clientInodeMap map[uint64][]*clientInodePath clientInodeMap map[uint64][]*clientInodePath
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment