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