Commit 391ae350 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Use HandleMap for registering file handles too. Rename fileBridge to

openedFile.

To make this work, add OpenCountMutex to inode.  This fixes a race
condition in considerDropInode().
parent 8edb1e8f
...@@ -27,12 +27,15 @@ import ( ...@@ -27,12 +27,15 @@ import (
"unsafe" "unsafe"
) )
// fileBridge stores either an open dir or an open file. // openedFile stores either an open dir or an open file.
type fileBridge struct { type openedFile struct {
Handled
*mountData *mountData
*inode *inode
Flags uint32 Flags uint32
Iface interface{}
dir rawDir
file File
} }
type mountData struct { type mountData struct {
...@@ -59,17 +62,14 @@ type mountData struct { ...@@ -59,17 +62,14 @@ type mountData struct {
// treeLock should be acquired before openFilesLock // treeLock should be acquired before openFilesLock
treeLock sync.RWMutex treeLock sync.RWMutex
// Protects openFiles // Manage filehandles of open files.
openFilesLock sync.RWMutex openFiles *HandleMap
// Open files/directories.
openFiles map[uint64]*fileBridge
} }
func newMount(fs FileSystem) *mountData { func newMount(fs FileSystem) *mountData {
return &mountData{ return &mountData{
fs: fs, fs: fs,
openFiles: make(map[uint64]*fileBridge), openFiles: NewHandleMap(),
} }
} }
...@@ -78,37 +78,30 @@ func (me *mountData) setOwner(attr *Attr) { ...@@ -78,37 +78,30 @@ func (me *mountData) setOwner(attr *Attr) {
attr.Owner = *me.options.Owner attr.Owner = *me.options.Owner
} }
} }
func (me *mountData) unregisterFile(node *inode, handle uint64) interface{} {
me.openFilesLock.Lock() func (me *mountData) unregisterFileHandle(node *inode, handle uint64) (*openedFile) {
defer me.openFilesLock.Unlock() obj := me.openFiles.Forget(handle)
b, ok := me.openFiles[handle] opened := (*openedFile)(unsafe.Pointer(obj))
if !ok {
panic("invalid handle") node.OpenCountMutex.Lock()
} defer node.OpenCountMutex.Unlock()
node.OpenCount-- node.OpenCount--
me.openFiles[handle] = nil, false
return b.Iface
}
func (me *mountData) registerFile(node *inode, f interface{}, flags uint32) uint64 { return opened
me.openFilesLock.Lock() }
defer me.openFilesLock.Unlock()
b := &fileBridge{ func (me *mountData) registerFileHandle(node *inode, dir rawDir, f File, flags uint32) uint64 {
Iface: f, node.OpenCountMutex.Lock()
defer node.OpenCountMutex.Unlock()
b := &openedFile{
dir: dir,
file: f,
inode: node, inode: node,
mountData: me, mountData: me,
Flags: flags, Flags: flags,
} }
h := uint64(uintptr(unsafe.Pointer(b)))
_, ok := me.openFiles[h]
if ok {
panic("handle counter wrapped")
}
node.OpenCount++ node.OpenCount++
me.openFiles[h] = b return me.openFiles.Register(&b.Handled)
return h
} }
//////////////// ////////////////
...@@ -125,8 +118,7 @@ type inode struct { ...@@ -125,8 +118,7 @@ type inode struct {
Name string Name string
LookupCount int LookupCount int
// Protected by openFilesLock. OpenCountMutex sync.Mutex
// TODO - verify() this variable too.
OpenCount int OpenCount int
// Non-nil if this is a mountpoint. // Non-nil if this is a mountpoint.
...@@ -145,10 +137,7 @@ func (me *inode) TotalOpenCount() int { ...@@ -145,10 +137,7 @@ func (me *inode) TotalOpenCount() int {
me.mountPoint.treeLock.RLock() me.mountPoint.treeLock.RLock()
defer me.mountPoint.treeLock.RUnlock() defer me.mountPoint.treeLock.RUnlock()
me.mountPoint.openFilesLock.RLock() o += me.mountPoint.openFiles.Count()
defer me.mountPoint.openFilesLock.RUnlock()
o += len(me.mountPoint.openFiles)
} }
for _, v := range me.Children { for _, v := range me.Children {
...@@ -189,7 +178,7 @@ func (me *inode) verify(cur *mountData) { ...@@ -189,7 +178,7 @@ func (me *inode) verify(cur *mountData) {
panic(fmt.Sprintf("node %v %d should be dead: %v %v", p, me.NodeId, len(me.Children), me.LookupCount)) panic(fmt.Sprintf("node %v %d should be dead: %v %v", p, me.NodeId, len(me.Children), me.LookupCount))
} }
if me.mountPoint != nil { if me.mountPoint != nil {
if me.mountPoint.unmountPending && len(me.mountPoint.openFiles) > 0 { if me.mountPoint.unmountPending && me.mountPoint.openFiles.Count() > 0 {
panic(fmt.Sprintf("cannot have open files for pending unmount")) panic(fmt.Sprintf("cannot have open files for pending unmount"))
} }
cur = me.mountPoint cur = me.mountPoint
...@@ -317,8 +306,8 @@ func (me *FileSystemConnector) Statistics() string { ...@@ -317,8 +306,8 @@ func (me *FileSystemConnector) Statistics() string {
root.TotalOpenCount(), me.inodeMap.Count()) root.TotalOpenCount(), me.inodeMap.Count())
} }
func (me *FileSystemConnector) decodeFileHandle(h uint64) *fileBridge { func (me *FileSystemConnector) getOpenedFile(h uint64) *openedFile {
b := (*fileBridge)(unsafe.Pointer(uintptr(h))) b := (*openedFile)(unsafe.Pointer(DecodeHandle(h)))
return b return b
} }
...@@ -327,16 +316,6 @@ type rawDir interface { ...@@ -327,16 +316,6 @@ type rawDir interface {
Release() Release()
} }
func (me *FileSystemConnector) getDir(h uint64) (dir rawDir, bridge *fileBridge) {
b := me.decodeFileHandle(h)
return b.Iface.(rawDir), b
}
func (me *FileSystemConnector) getFile(h uint64) (file File, bridge *fileBridge) {
b := me.decodeFileHandle(h)
return b.Iface.(File), b
}
func (me *FileSystemConnector) verify() { func (me *FileSystemConnector) verify() {
if !paranoia { if !paranoia {
return return
...@@ -397,6 +376,8 @@ func (me *FileSystemConnector) considerDropInode(n *inode) { ...@@ -397,6 +376,8 @@ func (me *FileSystemConnector) considerDropInode(n *inode) {
n.mount.treeLock.Lock() n.mount.treeLock.Lock()
defer n.mount.treeLock.Unlock() defer n.mount.treeLock.Unlock()
n.OpenCountMutex.Lock()
defer n.OpenCountMutex.Unlock()
dropInode := n.LookupCount <= 0 && len(n.Children) == 0 && dropInode := n.LookupCount <= 0 && len(n.Children) == 0 &&
(n.mountPoint == nil || n.mountPoint.unmountPending) && (n.mountPoint == nil || n.mountPoint.unmountPending) &&
n.OpenCount <= 0 n.OpenCount <= 0
...@@ -581,9 +562,9 @@ func (me *FileSystemConnector) GetPath(nodeid uint64) (path string, mount *mount ...@@ -581,9 +562,9 @@ func (me *FileSystemConnector) GetPath(nodeid uint64) (path string, mount *mount
func (me *FileSystemConnector) getOpenFileData(nodeid uint64, fh uint64) (f File, m *mountData, p string) { func (me *FileSystemConnector) getOpenFileData(nodeid uint64, fh uint64) (f File, m *mountData, p string) {
if fh != 0 { if fh != 0 {
var bridge *fileBridge opened := me.getOpenedFile(fh)
f, bridge = me.getFile(fh) m = opened.mountData
m = bridge.mountData f = opened.file
} }
node := me.getInodeData(nodeid) node := me.getInodeData(nodeid)
node.mount.treeLock.RLock() node.mount.treeLock.RLock()
......
...@@ -87,8 +87,8 @@ func (me *FileSystemConnector) Forget(h *InHeader, input *ForgetIn) { ...@@ -87,8 +87,8 @@ func (me *FileSystemConnector) Forget(h *InHeader, input *ForgetIn) {
func (me *FileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) { func (me *FileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) {
if input.Flags&FUSE_GETATTR_FH != 0 { if input.Flags&FUSE_GETATTR_FH != 0 {
f, bridge := me.getFile(input.Fh) opened := me.getOpenedFile(input.Fh)
fi, err := f.GetAttr() fi, err := opened.file.GetAttr()
if err != OK && err != ENOSYS { if err != OK && err != ENOSYS {
return nil, err return nil, err
} }
...@@ -97,7 +97,7 @@ func (me *FileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out ...@@ -97,7 +97,7 @@ func (me *FileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out
out = &AttrOut{} out = &AttrOut{}
CopyFileInfo(fi, &out.Attr) CopyFileInfo(fi, &out.Attr)
out.Attr.Ino = header.NodeId out.Attr.Ino = header.NodeId
SplitNs(bridge.mountData.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec) SplitNs(opened.mountData.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
return out, OK return out, OK
} }
...@@ -139,14 +139,14 @@ func (me *FileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags u ...@@ -139,14 +139,14 @@ func (me *FileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags u
de := &Dir{ de := &Dir{
stream: stream, stream: stream,
} }
h := mount.registerFile(node, de, input.Flags) h := mount.registerFileHandle(node, de, nil, input.Flags)
return 0, h, OK return 0, h, OK
} }
func (me *FileSystemConnector) ReadDir(header *InHeader, input *ReadIn) (*DirEntryList, Status) { func (me *FileSystemConnector) ReadDir(header *InHeader, input *ReadIn) (*DirEntryList, Status) {
d, _ := me.getDir(input.Fh) opened := me.getOpenedFile(input.Fh)
de, code := d.ReadDir(input) de, code := opened.dir.ReadDir(input)
if code != OK { if code != OK {
return nil, code return nil, code
} }
...@@ -164,7 +164,7 @@ func (me *FileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint ...@@ -164,7 +164,7 @@ func (me *FileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint
if err != OK { if err != OK {
return 0, 0, err return 0, 0, err
} }
h := mount.registerFile(node, f, input.Flags) h := mount.registerFileHandle(node, nil, f, input.Flags)
return 0, h, OK return 0, h, OK
} }
...@@ -382,25 +382,25 @@ func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name st ...@@ -382,25 +382,25 @@ func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name st
} }
out, code, inode := me.internalLookupWithNode(parent, name, 1) out, code, inode := me.internalLookupWithNode(parent, name, 1)
return 0, mount.registerFile(inode, f, input.Flags), out, code return 0, mount.registerFileHandle(inode, nil, f, input.Flags), out, code
} }
func (me *FileSystemConnector) Release(header *InHeader, input *ReleaseIn) { func (me *FileSystemConnector) Release(header *InHeader, input *ReleaseIn) {
node := me.getInodeData(header.NodeId) node := me.getInodeData(header.NodeId)
f := node.mount.unregisterFile(node, input.Fh).(File) opened := node.mount.unregisterFileHandle(node, input.Fh)
f.Release() opened.file.Release()
} }
func (me *FileSystemConnector) Flush(input *FlushIn) Status { func (me *FileSystemConnector) Flush(input *FlushIn) Status {
f, b := me.getFile(input.Fh) opened := me.getOpenedFile(input.Fh)
code := f.Flush() code := opened.file.Flush()
if code.Ok() && b.Flags&O_ANYWRITE != 0 { if code.Ok() && opened.Flags&O_ANYWRITE != 0 {
// We only signal releases to the FS if the // We only signal releases to the FS if the
// open could have changed things. // open could have changed things.
var path string var path string
var mount *mountData var mount *mountData
path, mount = b.inode.GetPath() path, mount = opened.inode.GetPath()
if mount != nil { if mount != nil {
code = mount.fs.Flush(path) code = mount.fs.Flush(path)
...@@ -411,8 +411,8 @@ func (me *FileSystemConnector) Flush(input *FlushIn) Status { ...@@ -411,8 +411,8 @@ func (me *FileSystemConnector) Flush(input *FlushIn) Status {
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)
d := node.mount.unregisterFile(node, input.Fh).(rawDir) opened := node.mount.unregisterFileHandle(node, input.Fh)
d.Release() opened.dir.Release()
me.considerDropInode(node) me.considerDropInode(node)
} }
...@@ -475,25 +475,25 @@ func (me *FileSystemConnector) fileDebug(fh uint64, n *inode) { ...@@ -475,25 +475,25 @@ func (me *FileSystemConnector) fileDebug(fh uint64, n *inode) {
} }
func (me *FileSystemConnector) Write(input *WriteIn, data []byte) (written uint32, code Status) { func (me *FileSystemConnector) Write(input *WriteIn, data []byte) (written uint32, code Status) {
f, b := me.getFile(input.Fh) opened := me.getOpenedFile(input.Fh)
if me.Debug { if me.Debug {
me.fileDebug(input.Fh, b.inode) me.fileDebug(input.Fh, opened.inode)
} }
return f.Write(input, data) return opened.file.Write(input, data)
} }
func (me *FileSystemConnector) Read(input *ReadIn, bp BufferPool) ([]byte, Status) { func (me *FileSystemConnector) Read(input *ReadIn, bp BufferPool) ([]byte, Status) {
f, b := me.getFile(input.Fh) opened := me.getOpenedFile(input.Fh)
if me.Debug { if me.Debug {
me.fileDebug(input.Fh, b.inode) me.fileDebug(input.Fh, opened.inode)
} }
return f.Read(input, bp) return opened.file.Read(input, bp)
} }
func (me *FileSystemConnector) Ioctl(header *InHeader, input *IoctlIn) (out *IoctlOut, data []byte, code Status) { func (me *FileSystemConnector) Ioctl(header *InHeader, input *IoctlIn) (out *IoctlOut, data []byte, code Status) {
f, b := me.getFile(input.Fh) opened := me.getOpenedFile(input.Fh)
if me.Debug { if me.Debug {
me.fileDebug(input.Fh, b.inode) me.fileDebug(input.Fh, opened.inode)
} }
return f.Ioctl(input) return opened.file.Ioctl(input)
} }
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