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

Document implementation.

parent 73a13268
......@@ -4,15 +4,6 @@ package fuse
// FileSystemConnector. The functions for satisfying the raw interface
// 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 (
"fmt"
"log"
......@@ -25,26 +16,42 @@ import (
// Tests should set to true.
var paranoia = false
func NewFileSystemOptions() *FileSystemOptions {
return &FileSystemOptions{
NegativeTimeout: 0.0,
AttrTimeout: 1.0,
EntryTimeout: 1.0,
Owner: CurrentOwner(),
}
}
// FilesystemConnector is a raw FUSE filesystem that manages in-process mounts and inodes.
// FilesystemConnector is a raw FUSE filesystem that manages
// in-process mounts and inodes. Its job is twofold:
//
// * It translates between the raw kernel interface (padded structs
// of int32 and int64) and the more abstract NodeFileSystem interface.
// that is based on a hierarchy of Inodes
//
// * It manages mounting and unmounting of NodeFileSystems into the
// directory hierarchy
//
// To achieve this, the connector only needs a pointer to the root
// node.
type FileSystemConnector struct {
DefaultRawFileSystem
Debug bool
// Callbacks for talking back to the kernel.
fsInit RawFsInit
// Translate between uint64 handles and *Inode.
inodeMap HandleMap
// The root of the FUSE file system.
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) {
me = new(FileSystemConnector)
if opts == nil {
......
......@@ -18,6 +18,7 @@ type openedFile struct {
dir rawDir
}
type fileSystemMount struct {
// The file system we mounted here.
fs NodeFileSystem
......@@ -32,7 +33,7 @@ type fileSystemMount struct {
options *FileSystemOptions
// Protects Children hashmaps within the mount. treeLock
// should be acquired before openFilesLock
// should be acquired before openFilesLock.
treeLock sync.RWMutex
// Manage filehandles of open files.
......
......@@ -8,7 +8,9 @@ import (
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 {
handled Handled
......@@ -16,43 +18,48 @@ type Inode struct {
openFilesMutex sync.Mutex
openFiles []*openedFile
// treeLock is a pointer to me.mount.treeLock; we need store
// this mutex separately, since unmount may set me.mount = nil
// during Unmount(). Constant during lifetime.
fsInode FsNode
// 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
// closer to the root must be acquired first.
treeLock *sync.RWMutex
// All data below is protected by treeLock.
fsInode FsNode
children map[string]*Inode
// Contains directories that function as mounts. The entries
// are duplicated in children.
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
// it is zero, it means the kernel does not know about this
// Inode.
// Inode. nodeIds are chosen by FileSystemConnector.inodeMap.
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.
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
// 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 {
......
......@@ -10,20 +10,31 @@ import (
var _ = log.Println
// A parent pointer: node should be reachable as parent.children[name]
type clientInodePath struct {
parent *pathInode
name string
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 {
Debug bool
fs FileSystem
root *pathInode
connector *FileSystemConnector
// Used for dealing with hardlinks.
clientInodeMapMutex sync.Mutex
// This map lists all the parent links known for a given
// nodeId.
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