Commit 94429a4b authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Split up pathfilesystem.go and pathops.go

parent bad4ee66
...@@ -11,9 +11,12 @@ MANUAL_GOFILES=api.go \ ...@@ -11,9 +11,12 @@ MANUAL_GOFILES=api.go \
defaultraw.go \ defaultraw.go \
direntry.go\ direntry.go\
files.go \ files.go \
fsmount.go \
fsinode.go \ fsinode.go \
fsconnector.go \
fuse.go \ fuse.go \
handle.go \ handle.go \
inode.go \
latencymap.go \ latencymap.go \
lockingfs.go \ lockingfs.go \
loggingfs.go \ loggingfs.go \
...@@ -23,8 +26,7 @@ MANUAL_GOFILES=api.go \ ...@@ -23,8 +26,7 @@ MANUAL_GOFILES=api.go \
mountstate.go \ mountstate.go \
opcode.go \ opcode.go \
pathdebug.go \ pathdebug.go \
pathfilesystem.go \ fsops.go \
pathops.go \
readonlyfs.go \ readonlyfs.go \
request.go \ request.go \
switchfs.go \ switchfs.go \
......
package fuse package fuse
/*
FilesystemConnector is a lowlevel FUSE filesystem that translates // This file contains the internal logic of the
from inode numbers (as delivered by the kernel) to traditional path // FileSystemConnector. The functions for satisfying the raw interface are in
names. The paths are then used as arguments for methods of // fsops.go
FileSystem instances.
FileSystemConnector supports mounts of different FileSystems
on top of each other's directories.
General todos:
- We are doing lookups (incurring GetAttr() costs) for internal
lookups (eg. after doing a symlink). We could probably do without
the GetAttr calls.
*/
import ( import (
"fmt" "fmt"
"log" "log"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"sync"
"unsafe" "unsafe"
) )
// openedFile stores either an open dir or an open file.
type openedFile struct {
Handled
*fileSystemMount
*inode
// O_CREAT, O_TRUNC, etc.
OpenFlags uint32
// FOPEN_KEEP_CACHE and friends.
FuseFlags uint32
dir rawDir
file File
}
type fileSystemMount struct {
// If non-nil the file system mounted here.
fs FileSystem
// Node that we were mounted on.
mountInode *inode
options *FileSystemOptions
// Protects parent/child relations within the mount.
// treeLock should be acquired before openFilesLock
treeLock sync.RWMutex
// Manage filehandles of open files.
openFiles HandleMap
}
func (me *fileSystemMount) fileInfoToEntry(fi *os.FileInfo, out *EntryOut) {
SplitNs(me.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
SplitNs(me.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
if !fi.IsDirectory() {
fi.Nlink = 1
}
CopyFileInfo(fi, &out.Attr)
me.setOwner(&out.Attr)
}
func (me *fileSystemMount) fileInfoToAttr(fi *os.FileInfo, out *AttrOut) {
CopyFileInfo(fi, &out.Attr)
SplitNs(me.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
me.setOwner(&out.Attr)
}
func (me *FileSystemConnector) getOpenedFile(h uint64) *openedFile {
b := (*openedFile)(unsafe.Pointer(DecodeHandle(h)))
return b
}
func (me *fileSystemMount) unregisterFileHandle(handle uint64) *openedFile {
obj := me.openFiles.Forget(handle)
opened := (*openedFile)(unsafe.Pointer(obj))
node := opened.inode
node.OpenFilesMutex.Lock()
defer node.OpenFilesMutex.Unlock()
idx := -1
for i, v := range node.OpenFiles {
if v == opened {
idx = i
break
}
}
l := len(node.OpenFiles)
node.OpenFiles[idx] = node.OpenFiles[l-1]
node.OpenFiles = node.OpenFiles[:l-1]
return opened
}
func (me *fileSystemMount) registerFileHandle(node *inode, dir rawDir, f File, flags uint32) (uint64, *openedFile) {
node.OpenFilesMutex.Lock()
defer node.OpenFilesMutex.Unlock()
b := &openedFile{
dir: dir,
file: f,
inode: node,
fileSystemMount: me,
OpenFlags: flags,
}
withFlags, ok := f.(*WithFlags)
if ok {
b.FuseFlags = withFlags.Flags
f = withFlags.File
}
node.OpenFiles = append(node.OpenFiles, b)
handle := me.openFiles.Register(&b.Handled)
return handle, b
}
////////////////
// Tests should set to true. // Tests should set to true.
var paranoia = false var paranoia = false
// The inode reflects the kernel's idea of the inode.
type inode struct {
Handled
// Constant during lifetime.
NodeId uint64
// Number of open files and its protection.
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.
//
// 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 *fsInode
Children map[string]*inode
// Contains directories that function as mounts. The entries
// are duplicated in Children.
Mounts map[string]*fileSystemMount
LookupCount int
// Non-nil if this is a mountpoint.
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
}
// Must be called with treeLock for the mount held.
func (me *inode) addChild(name string, child *inode) {
if paranoia {
ch := me.Children[name]
if ch != nil {
panic(fmt.Sprintf("Already have an inode with same name: %v: %v", name, ch))
}
}
me.Children[name] = child
me.fsInode.addChild(name, child.fsInode)
}
// Must be called with treeLock for the mount held.
func (me *inode) rmChild(name string) (ch *inode) {
ch = me.Children[name]
if ch != nil {
me.Children[name] = nil, false
me.fsInode.rmChild(name, ch.fsInode)
}
return ch
}
// Can only be called on untouched inodes.
func (me *inode) mountFs(fs FileSystem, opts *FileSystemOptions) {
me.mountPoint = &fileSystemMount{
fs: fs,
openFiles: NewHandleMap(true),
mountInode: me,
options: opts,
}
me.mount = me.mountPoint
me.treeLock = &me.mountPoint.treeLock
}
// Must be called with treeLock held.
func (me *inode) canUnmount() bool {
for _, v := range me.Children {
if v.mountPoint != nil {
// This access may be out of date, but it is no
// problem to err on the safe side.
return false
}
if !v.canUnmount() {
return false
}
}
me.OpenFilesMutex.Lock()
defer me.OpenFilesMutex.Unlock()
return len(me.OpenFiles) == 0
}
// Must be called with treeLock held
func (me *inode) recursiveUnmount() {
for _, v := range me.Children {
v.recursiveUnmount()
}
me.mount = nil
}
func (me *inode) IsDir() bool {
return me.Children != nil
}
func (me *inode) getMountDirEntries() (out []DirEntry) {
me.treeLock.RLock()
defer me.treeLock.RUnlock()
for k, _ := range me.Mounts {
out = append(out, DirEntry{
Name: k,
Mode: S_IFDIR,
})
}
return out
}
// Returns any open file, preferably a r/w one.
func (me *inode) getAnyFile() (file File) {
me.OpenFilesMutex.Lock()
defer me.OpenFilesMutex.Unlock()
for _, f := range me.OpenFiles {
if file == nil || f.OpenFlags & O_ANYWRITE != 0 {
file = f.file
}
}
return file
}
// Returns an open writable file for the given inode.
func (me *inode) getWritableFiles() (files []File) {
me.OpenFilesMutex.Lock()
defer me.OpenFilesMutex.Unlock()
for _, f := range me.OpenFiles {
if f.OpenFlags & O_ANYWRITE != 0 {
files = append(files, f.file)
}
}
return files
}
const initDirSize = 20
func (me *inode) verify(cur *fileSystemMount) {
if me.mountPoint != nil {
if me != me.mountPoint.mountInode {
panic("mountpoint mismatch")
}
cur = me.mountPoint
}
if me.mount != cur {
panic(fmt.Sprintf("me.mount not set correctly %v %v", me.mount, cur))
}
for name, m := range me.Mounts {
if m.mountInode != me.Children[name] {
panic(fmt.Sprintf("mountpoint parent mismatch: node:%v name:%v ch:%v",
me.mountPoint, name, me.Children))
}
}
for _, ch := range me.Children {
if ch == nil {
panic("Found nil child.")
}
ch.verify(cur)
}
}
func NewFileSystemOptions() *FileSystemOptions { func NewFileSystemOptions() *FileSystemOptions {
return &FileSystemOptions{ return &FileSystemOptions{
NegativeTimeout: 0.0, NegativeTimeout: 0.0,
...@@ -312,6 +25,7 @@ func NewFileSystemOptions() *FileSystemOptions { ...@@ -312,6 +25,7 @@ func NewFileSystemOptions() *FileSystemOptions {
} }
} }
// FilesystemConnector is a raw FUSE filesystem that manages in-process mounts and inodes.
type FileSystemConnector struct { type FileSystemConnector struct {
DefaultRawFileSystem DefaultRawFileSystem
...@@ -322,12 +36,17 @@ type FileSystemConnector struct { ...@@ -322,12 +36,17 @@ type FileSystemConnector struct {
rootNode *inode rootNode *inode
} }
func (me *FileSystemConnector) Init(fsInit *RawFsInit) { func NewFileSystemConnector(fs FileSystem, opts *FileSystemOptions) (me *FileSystemConnector) {
me.fsInit = *fsInit me = new(FileSystemConnector)
} if opts == nil {
opts = NewFileSystemOptions()
func (me *FileSystemConnector) Statistics() string { }
return fmt.Sprintf("Inodes %20d\n", me.inodeMap.Count()) me.inodeMap = NewHandleMap(!opts.SkipCheckHandles)
me.rootNode = me.newInode(true)
me.rootNode.NodeId = FUSE_ROOT_ID
me.verify()
me.mountRoot(fs, opts)
return me
} }
func (me *FileSystemConnector) verify() { func (me *FileSystemConnector) verify() {
...@@ -596,7 +315,6 @@ func (me *FileSystemConnector) Unmount(path string) Status { ...@@ -596,7 +315,6 @@ func (me *FileSystemConnector) Unmount(path string) Status {
return EBUSY return EBUSY
} }
mountInode.recursiveUnmount()
mount.mountInode = nil mount.mountInode = nil
mountInode.mountPoint = nil mountInode.mountPoint = nil
......
package fuse package fuse
import ( import (
"log" "log"
"os" "os"
......
package fuse
import (
"os"
"sync"
"unsafe"
)
// openedFile stores either an open dir or an open file.
type openedFile struct {
Handled
// O_CREAT, O_TRUNC, etc.
OpenFlags uint32
// FOPEN_KEEP_CACHE and friends.
FuseFlags uint32
dir rawDir
file File
}
type fileSystemMount struct {
// The file system we mounted here.
fs FileSystem
// Node that we were mounted on.
mountInode *inode
// Options for the mount.
options *FileSystemOptions
// Protects Children hashmaps within the mount. treeLock
// should be acquired before openFilesLock
treeLock sync.RWMutex
// Manage filehandles of open files.
openFiles HandleMap
}
func (me *fileSystemMount) setOwner(attr *Attr) {
if me.options.Owner != nil {
attr.Owner = *me.options.Owner
}
}
func (me *fileSystemMount) fileInfoToEntry(fi *os.FileInfo, out *EntryOut) {
SplitNs(me.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
SplitNs(me.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
if !fi.IsDirectory() {
fi.Nlink = 1
}
CopyFileInfo(fi, &out.Attr)
me.setOwner(&out.Attr)
}
func (me *fileSystemMount) fileInfoToAttr(fi *os.FileInfo, out *AttrOut) {
CopyFileInfo(fi, &out.Attr)
SplitNs(me.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
me.setOwner(&out.Attr)
}
func (me *FileSystemConnector) getOpenedFile(h uint64) *openedFile {
b := (*openedFile)(unsafe.Pointer(DecodeHandle(h)))
return b
}
func (me *fileSystemMount) unregisterFileHandle(handle uint64, node *inode) *openedFile {
obj := me.openFiles.Forget(handle)
opened := (*openedFile)(unsafe.Pointer(obj))
node.OpenFilesMutex.Lock()
defer node.OpenFilesMutex.Unlock()
idx := -1
for i, v := range node.OpenFiles {
if v == opened {
idx = i
break
}
}
l := len(node.OpenFiles)
node.OpenFiles[idx] = node.OpenFiles[l-1]
node.OpenFiles = node.OpenFiles[:l-1]
return opened
}
func (me *fileSystemMount) registerFileHandle(node *inode, dir rawDir, f File, flags uint32) (uint64, *openedFile) {
node.OpenFilesMutex.Lock()
defer node.OpenFilesMutex.Unlock()
b := &openedFile{
dir: dir,
file: f,
OpenFlags: flags,
}
withFlags, ok := f.(*WithFlags)
if ok {
b.FuseFlags = withFlags.Flags
f = withFlags.File
}
node.OpenFiles = append(node.OpenFiles, b)
handle := me.openFiles.Register(&b.Handled)
return handle, b
}
// Translation of raw operation to path based operations. // FileSystemConnector's implementation of RawFileSystem
package fuse package fuse
...@@ -11,39 +11,14 @@ import ( ...@@ -11,39 +11,14 @@ import (
var _ = log.Println var _ = log.Println
func NewFileSystemConnector(fs FileSystem, opts *FileSystemOptions) (me *FileSystemConnector) {
me = new(FileSystemConnector)
if opts == nil {
opts = NewFileSystemOptions()
}
me.inodeMap = NewHandleMap(!opts.SkipCheckHandles)
me.rootNode = me.newInode(true)
me.rootNode.NodeId = FUSE_ROOT_ID
me.verify()
me.mountRoot(fs, opts)
return me
}
func (me *FileSystemConnector) GetPath(nodeid uint64) (path string, mount *fileSystemMount, node *inode) {
n := me.getInodeData(nodeid)
p := n.fsInode.GetPath()
return p, n.mount, n
}
func (me *fileSystemMount) setOwner(attr *Attr) { func (me *FileSystemConnector) Init(fsInit *RawFsInit) {
if me.options.Owner != nil { me.fsInit = *fsInit
attr.Owner = *me.options.Owner
}
} }
func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *EntryOut, status Status) { func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *EntryOut, status Status) {
parent := me.getInodeData(header.NodeId) parent := me.getInodeData(header.NodeId)
return me.internalLookup(parent, name, 1, &header.Context) out, status, _ = me.internalLookup(parent, name, 1, &header.Context)
}
func (me *FileSystemConnector) internalLookup(parent *inode, name string, lookupCount int, context *Context) (out *EntryOut, status Status) {
out, status, _ = me.internalLookupWithNode(parent, name, lookupCount, context)
return out, status return out, status
} }
...@@ -66,7 +41,7 @@ func (me *FileSystemConnector) internalMountLookup(mount *fileSystemMount, looku ...@@ -66,7 +41,7 @@ func (me *FileSystemConnector) internalMountLookup(mount *fileSystemMount, looku
return out, OK, mount.mountInode return out, OK, mount.mountInode
} }
func (me *FileSystemConnector) internalLookupWithNode(parent *inode, name string, lookupCount int, context *Context) (out *EntryOut, status Status, node *inode) { func (me *FileSystemConnector) internalLookup(parent *inode, name string, lookupCount int, context *Context) (out *EntryOut, status Status, node *inode) {
if mount := me.lookupMount(parent, name, lookupCount); mount != nil { if mount := me.lookupMount(parent, name, lookupCount); mount != nil {
return me.internalMountLookup(mount, lookupCount) return me.internalMountLookup(mount, lookupCount)
} }
...@@ -206,9 +181,9 @@ func (me *FileSystemConnector) Mknod(header *InHeader, input *MknodIn, name stri ...@@ -206,9 +181,9 @@ func (me *FileSystemConnector) Mknod(header *InHeader, input *MknodIn, name stri
n := me.getInodeData(header.NodeId) n := me.getInodeData(header.NodeId)
code = n.fsInode.Mknod(name, input.Mode, uint32(input.Rdev), &header.Context) code = n.fsInode.Mknod(name, input.Mode, uint32(input.Rdev), &header.Context)
if code.Ok() { if code.Ok() {
return me.internalLookup(n, name, 1, &header.Context) out, code, _ = me.internalLookup(n, name, 1, &header.Context)
} }
return nil, code return out, code
} }
func (me *FileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name string) (out *EntryOut, code Status) { func (me *FileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name string) (out *EntryOut, code Status) {
...@@ -216,7 +191,7 @@ func (me *FileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name stri ...@@ -216,7 +191,7 @@ func (me *FileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name stri
code = parent.fsInode.Mkdir(name, input.Mode, &header.Context) code = parent.fsInode.Mkdir(name, input.Mode, &header.Context)
if code.Ok() { if code.Ok() {
out, code = me.internalLookup(parent, name, 1, &header.Context) out, code, _ = me.internalLookup(parent, name, 1, &header.Context)
} }
return out, code return out, code
} }
...@@ -245,9 +220,9 @@ func (me *FileSystemConnector) Symlink(header *InHeader, pointedTo string, linkN ...@@ -245,9 +220,9 @@ func (me *FileSystemConnector) Symlink(header *InHeader, pointedTo string, linkN
parent := me.getInodeData(header.NodeId) parent := me.getInodeData(header.NodeId)
code = parent.fsInode.Symlink(linkName, pointedTo, &header.Context) code = parent.fsInode.Symlink(linkName, pointedTo, &header.Context)
if code.Ok() { if code.Ok() {
return me.internalLookup(parent, linkName, 1, &header.Context) out, code, _ = me.internalLookup(parent, linkName, 1, &header.Context)
} }
return nil, code return out, code
} }
...@@ -283,7 +258,8 @@ func (me *FileSystemConnector) Link(header *InHeader, input *LinkIn, filename st ...@@ -283,7 +258,8 @@ func (me *FileSystemConnector) Link(header *InHeader, input *LinkIn, filename st
return nil, code return nil, code
} }
// TODO - revise this for real hardlinks? // TODO - revise this for real hardlinks?
return me.internalLookup(parent, filename, 1, &header.Context) out, code, _ = me.internalLookup(parent, filename, 1, &header.Context)
return out, code
} }
func (me *FileSystemConnector) Access(header *InHeader, input *AccessIn) (code Status) { func (me *FileSystemConnector) Access(header *InHeader, input *AccessIn) (code Status) {
...@@ -298,7 +274,7 @@ func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name st ...@@ -298,7 +274,7 @@ func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name st
return 0, 0, nil, code return 0, 0, nil, code
} }
out, code, inode := me.internalLookupWithNode(parent, name, 1, &header.Context) out, code, inode := me.internalLookup(parent, name, 1, &header.Context)
if inode == nil { if inode == nil {
msg := fmt.Sprintf("Create succeded, but GetAttr returned no entry %v, %q. code %v", header.NodeId, name, code) msg := fmt.Sprintf("Create succeded, but GetAttr returned no entry %v, %q. code %v", header.NodeId, name, code)
panic(msg) panic(msg)
...@@ -308,18 +284,19 @@ func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name st ...@@ -308,18 +284,19 @@ func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name st
} }
func (me *FileSystemConnector) Release(header *InHeader, input *ReleaseIn) { func (me *FileSystemConnector) Release(header *InHeader, input *ReleaseIn) {
opened := me.getOpenedFile(input.Fh) node := me.getInodeData(header.NodeId)
opened.inode.mount.unregisterFileHandle(input.Fh) node.mount.unregisterFileHandle(input.Fh, node)
} }
func (me *FileSystemConnector) Flush(header *InHeader, input *FlushIn) Status { func (me *FileSystemConnector) Flush(header *InHeader, input *FlushIn) Status {
node := me.getInodeData(header.NodeId)
opened := me.getOpenedFile(input.Fh) opened := me.getOpenedFile(input.Fh)
return opened.inode.fsInode.Flush(opened.file, opened.OpenFlags, &header.Context) return node.fsInode.Flush(opened.file, opened.OpenFlags, &header.Context)
} }
func (me *FileSystemConnector) ReleaseDir(header *InHeader, input *ReleaseIn) { func (me *FileSystemConnector) ReleaseDir(header *InHeader, input *ReleaseIn) {
node := me.getInodeData(header.NodeId) node := me.getInodeData(header.NodeId)
opened := node.mount.unregisterFileHandle(input.Fh) opened := node.mount.unregisterFileHandle(input.Fh, node)
opened.dir.Release() opened.dir.Release()
me.considerDropInode(node) me.considerDropInode(node)
} }
......
package fuse
import (
"fmt"
"sync"
)
// The inode reflects the kernel's idea of the inode.
type inode struct {
Handled
// Constant during lifetime.
NodeId uint64
// Number of open files and its protection.
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.
//
// 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 *fsInode
Children map[string]*inode
// Contains directories that function as mounts. The entries
// are duplicated in Children.
Mounts map[string]*fileSystemMount
LookupCount int
// Non-nil if this is a mountpoint.
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
}
// Must be called with treeLock for the mount held.
func (me *inode) addChild(name string, child *inode) {
if paranoia {
ch := me.Children[name]
if ch != nil {
panic(fmt.Sprintf("Already have an inode with same name: %v: %v", name, ch))
}
}
me.Children[name] = child
me.fsInode.addChild(name, child.fsInode)
}
// Must be called with treeLock for the mount held.
func (me *inode) rmChild(name string) (ch *inode) {
ch = me.Children[name]
if ch != nil {
me.Children[name] = nil, false
me.fsInode.rmChild(name, ch.fsInode)
}
return ch
}
// Can only be called on untouched inodes.
func (me *inode) mountFs(fs FileSystem, opts *FileSystemOptions) {
me.mountPoint = &fileSystemMount{
fs: fs,
openFiles: NewHandleMap(true),
mountInode: me,
options: opts,
}
me.mount = me.mountPoint
me.treeLock = &me.mountPoint.treeLock
}
// Must be called with treeLock held.
func (me *inode) canUnmount() bool {
for _, v := range me.Children {
if v.mountPoint != nil {
// This access may be out of date, but it is no
// problem to err on the safe side.
return false
}
if !v.canUnmount() {
return false
}
}
me.OpenFilesMutex.Lock()
defer me.OpenFilesMutex.Unlock()
return len(me.OpenFiles) == 0
}
func (me *inode) IsDir() bool {
return me.Children != nil
}
func (me *inode) getMountDirEntries() (out []DirEntry) {
me.treeLock.RLock()
defer me.treeLock.RUnlock()
for k, _ := range me.Mounts {
out = append(out, DirEntry{
Name: k,
Mode: S_IFDIR,
})
}
return out
}
// Returns any open file, preferably a r/w one.
func (me *inode) getAnyFile() (file File) {
me.OpenFilesMutex.Lock()
defer me.OpenFilesMutex.Unlock()
for _, f := range me.OpenFiles {
if file == nil || f.OpenFlags & O_ANYWRITE != 0 {
file = f.file
}
}
return file
}
// Returns an open writable file for the given inode.
func (me *inode) getWritableFiles() (files []File) {
me.OpenFilesMutex.Lock()
defer me.OpenFilesMutex.Unlock()
for _, f := range me.OpenFiles {
if f.OpenFlags & O_ANYWRITE != 0 {
files = append(files, f.file)
}
}
return files
}
const initDirSize = 20
func (me *inode) verify(cur *fileSystemMount) {
if me.mountPoint != nil {
if me != me.mountPoint.mountInode {
panic("mountpoint mismatch")
}
cur = me.mountPoint
}
if me.mount != cur {
panic(fmt.Sprintf("me.mount not set correctly %v %v", me.mount, cur))
}
for name, m := range me.Mounts {
if m.mountInode != me.Children[name] {
panic(fmt.Sprintf("mountpoint parent mismatch: node:%v name:%v ch:%v",
me.mountPoint, name, me.Children))
}
}
for _, ch := range me.Children {
if ch == nil {
panic("Found nil child.")
}
ch.verify(cur)
}
}
...@@ -149,11 +149,6 @@ func (me *FileSystemDebug) AddMountState(state *MountState) { ...@@ -149,11 +149,6 @@ func (me *FileSystemDebug) AddMountState(state *MountState) {
func() []byte { return []byte(state.BufferPoolStats()) }) func() []byte { return []byte(state.BufferPoolStats()) })
} }
func (me *FileSystemDebug) AddFileSystemConnector(conn *FileSystemConnector) {
me.Add("filesystemconnector-stats",
func() []byte { return []byte(conn.Statistics()) })
}
func hotPaths(timing *TimingFileSystem) []byte { func hotPaths(timing *TimingFileSystem) []byte {
hot := timing.HotPaths("GetAttr") hot := timing.HotPaths("GetAttr")
unique := len(hot) unique := len(hot)
......
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