Commit 6fad53e3 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

nodefs: move open file administration into Inode

This is necessary to provide a file handle to GetAttr.
parent e32d0aa0
...@@ -7,6 +7,7 @@ package nodefs ...@@ -7,6 +7,7 @@ package nodefs
import ( import (
"log" "log"
"sync" "sync"
"syscall"
"time" "time"
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
...@@ -74,6 +75,7 @@ func (b *rawBridge) newInode(node Operations, mode uint32, id FileID, persistent ...@@ -74,6 +75,7 @@ func (b *rawBridge) newInode(node Operations, mode uint32, id FileID, persistent
bridge: b, bridge: b,
persistent: persistent, persistent: persistent,
parents: make(map[parentData]struct{}), parents: make(map[parentData]struct{}),
openFiles: make(map[FileHandle]uint32),
} }
if mode == fuse.S_IFDIR { if mode == fuse.S_IFDIR {
inode.children = make(map[string]*Inode) inode.children = make(map[string]*Inode)
...@@ -141,7 +143,7 @@ func (b *rawBridge) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name s ...@@ -141,7 +143,7 @@ func (b *rawBridge) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name s
return status return status
} }
b.addNewChild(parent, name, child, nil, out) b.addNewChild(parent, name, child, nil, 0, out)
b.setEntryOutTimeout(out) b.setEntryOutTimeout(out)
out.Mode = child.mode | (out.Mode & 07777) out.Mode = child.mode | (out.Mode & 07777)
...@@ -179,7 +181,7 @@ func (b *rawBridge) Mkdir(cancel <-chan struct{}, input *fuse.MkdirIn, name stri ...@@ -179,7 +181,7 @@ func (b *rawBridge) Mkdir(cancel <-chan struct{}, input *fuse.MkdirIn, name stri
log.Panicf("Mkdir: mode must be S_IFDIR (%o), got %o", fuse.S_IFDIR, out.Attr.Mode) log.Panicf("Mkdir: mode must be S_IFDIR (%o), got %o", fuse.S_IFDIR, out.Attr.Mode)
} }
b.addNewChild(parent, name, child, nil, out) b.addNewChild(parent, name, child, nil, 0, out)
b.setEntryOutTimeout(out) b.setEntryOutTimeout(out)
return fuse.OK return fuse.OK
} }
...@@ -192,13 +194,13 @@ func (b *rawBridge) Mknod(cancel <-chan struct{}, input *fuse.MknodIn, name stri ...@@ -192,13 +194,13 @@ func (b *rawBridge) Mknod(cancel <-chan struct{}, input *fuse.MknodIn, name stri
return status return status
} }
b.addNewChild(parent, name, child, nil, out) b.addNewChild(parent, name, child, nil, 0, out)
b.setEntryOutTimeout(out) b.setEntryOutTimeout(out)
return fuse.OK return fuse.OK
} }
// addNewChild inserts the child into the tree. Returns file handle if file != nil. // addNewChild inserts the child into the tree. Returns file handle if file != nil.
func (b *rawBridge) addNewChild(parent *Inode, name string, child *Inode, file FileHandle, out *fuse.EntryOut) uint64 { func (b *rawBridge) addNewChild(parent *Inode, name string, child *Inode, file FileHandle, fileFlags uint32, out *fuse.EntryOut) uint64 {
lockNodes(parent, child) lockNodes(parent, child)
parent.setEntry(name, child) parent.setEntry(name, child)
b.mu.Lock() b.mu.Lock()
...@@ -207,7 +209,7 @@ func (b *rawBridge) addNewChild(parent *Inode, name string, child *Inode, file F ...@@ -207,7 +209,7 @@ func (b *rawBridge) addNewChild(parent *Inode, name string, child *Inode, file F
var fh uint64 var fh uint64
if file != nil { if file != nil {
fh = b.registerFile(file) fh = b.registerFile(child, file, fileFlags)
} }
out.NodeId = child.nodeID.Ino out.NodeId = child.nodeID.Ino
...@@ -239,7 +241,7 @@ func (b *rawBridge) Create(cancel <-chan struct{}, input *fuse.CreateIn, name st ...@@ -239,7 +241,7 @@ func (b *rawBridge) Create(cancel <-chan struct{}, input *fuse.CreateIn, name st
return status return status
} }
out.Fh = b.addNewChild(parent, name, child, f, &out.EntryOut) out.Fh = b.addNewChild(parent, name, child, f, input.Flags|syscall.O_CREAT, &out.EntryOut)
b.setEntryOutTimeout(&out.EntryOut) b.setEntryOutTimeout(&out.EntryOut)
out.OpenFlags = flags out.OpenFlags = flags
...@@ -270,7 +272,16 @@ func (b *rawBridge) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out * ...@@ -270,7 +272,16 @@ func (b *rawBridge) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *
f := fEntry.file f := fEntry.file
if input.Flags()&fuse.FUSE_GETATTR_FH == 0 { if input.Flags()&fuse.FUSE_GETATTR_FH == 0 {
f = nil // The linux kernel doesnt pass along the file
// descriptor, so we have to fake it here.
// See https://github.com/libfuse/libfuse/issues/62
b.mu.Lock()
// TODO: synchronize to avoid closing F while GetAttr runs.
for openF := range n.openFiles {
f = openF
break
}
b.mu.Unlock()
} }
status := n.node.GetAttr(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f, out) status := n.node.GetAttr(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f, out)
...@@ -380,7 +391,7 @@ func (b *rawBridge) Link(cancel <-chan struct{}, input *fuse.LinkIn, name string ...@@ -380,7 +391,7 @@ func (b *rawBridge) Link(cancel <-chan struct{}, input *fuse.LinkIn, name string
return status return status
} }
b.addNewChild(parent, name, child, nil, out) b.addNewChild(parent, name, child, nil, 0, out)
b.setEntryOutTimeout(out) b.setEntryOutTimeout(out)
return fuse.OK return fuse.OK
} }
...@@ -392,7 +403,7 @@ func (b *rawBridge) Symlink(cancel <-chan struct{}, header *fuse.InHeader, targe ...@@ -392,7 +403,7 @@ func (b *rawBridge) Symlink(cancel <-chan struct{}, header *fuse.InHeader, targe
return status return status
} }
b.addNewChild(parent, name, child, nil, out) b.addNewChild(parent, name, child, nil, 0, out)
b.setEntryOutTimeout(out) b.setEntryOutTimeout(out)
return fuse.OK return fuse.OK
} }
...@@ -445,13 +456,13 @@ func (b *rawBridge) Open(cancel <-chan struct{}, input *fuse.OpenIn, out *fuse.O ...@@ -445,13 +456,13 @@ func (b *rawBridge) Open(cancel <-chan struct{}, input *fuse.OpenIn, out *fuse.O
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
out.Fh = b.registerFile(f) out.Fh = b.registerFile(n, f, input.Flags)
out.OpenFlags = flags out.OpenFlags = flags
return fuse.OK return fuse.OK
} }
// registerFile hands out a file handle. Must have bridge.mu // registerFile hands out a file handle. Must have bridge.mu
func (b *rawBridge) registerFile(f FileHandle) uint64 { func (b *rawBridge) registerFile(n *Inode, f FileHandle, flags uint32) uint64 {
var fh uint64 var fh uint64
if len(b.freeFiles) > 0 { if len(b.freeFiles) > 0 {
last := uint64(len(b.freeFiles) - 1) last := uint64(len(b.freeFiles) - 1)
...@@ -461,8 +472,10 @@ func (b *rawBridge) registerFile(f FileHandle) uint64 { ...@@ -461,8 +472,10 @@ func (b *rawBridge) registerFile(f FileHandle) uint64 {
fh = uint64(len(b.files)) fh = uint64(len(b.files))
b.files = append(b.files, &fileEntry{}) b.files = append(b.files, &fileEntry{})
} }
if f != nil {
b.files[fh].file = f n.openFiles[f] = flags
b.files[fh].file = f
}
return fh return fh
} }
...@@ -490,23 +503,29 @@ func (b *rawBridge) Release(input *fuse.ReleaseIn) { ...@@ -490,23 +503,29 @@ func (b *rawBridge) Release(input *fuse.ReleaseIn) {
n, f := b.inode(input.NodeId, input.Fh) n, f := b.inode(input.NodeId, input.Fh)
n.node.Release(f.file) n.node.Release(f.file)
b.releaseFileEntry(input.Fh) b.releaseFileEntry(n, input.Fh)
} }
func (b *rawBridge) ReleaseDir(input *fuse.ReleaseIn) { func (b *rawBridge) ReleaseDir(input *fuse.ReleaseIn) {
_, f := b.inode(input.NodeId, input.Fh) n, f := b.inode(input.NodeId, input.Fh)
if f.dirStream != nil { if f.dirStream != nil {
f.dirStream.Close() f.dirStream.Close()
} }
b.releaseFileEntry(input.Fh) b.releaseFileEntry(n, input.Fh)
} }
func (b *rawBridge) releaseFileEntry(fh uint64) { func (b *rawBridge) releaseFileEntry(n *Inode, fh uint64) {
if fh > 0 { if fh > 0 {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
b.files[fh].file = nil
entry := b.files[fh]
if entry.file != nil {
delete(n.openFiles, entry.file)
}
entry.dirStream = nil
entry.file = nil
b.freeFiles = append(b.freeFiles, fh) b.freeFiles = append(b.freeFiles, fh)
} }
} }
...@@ -539,7 +558,7 @@ func (b *rawBridge) OpenDir(cancel <-chan struct{}, input *fuse.OpenIn, out *fus ...@@ -539,7 +558,7 @@ func (b *rawBridge) OpenDir(cancel <-chan struct{}, input *fuse.OpenIn, out *fus
} }
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
out.Fh = b.registerFile(nil) out.Fh = b.registerFile(n, nil, 0)
return fuse.OK return fuse.OK
} }
...@@ -625,7 +644,7 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out ...@@ -625,7 +644,7 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out
entryOut.SetEntryTimeout(*b.options.NegativeTimeout) entryOut.SetEntryTimeout(*b.options.NegativeTimeout)
} }
} else { } else {
b.addNewChild(n, e.Name, child, nil, entryOut) b.addNewChild(n, e.Name, child, nil, 0, entryOut)
b.setEntryOutTimeout(entryOut) b.setEntryOutTimeout(entryOut)
if (e.Mode &^ 07777) != (child.mode &^ 07777) { if (e.Mode &^ 07777) != (child.mode &^ 07777) {
// XXX should go back and change the // XXX should go back and change the
......
...@@ -59,6 +59,12 @@ type Inode struct { ...@@ -59,6 +59,12 @@ type Inode struct {
// Following data is mutable. // Following data is mutable.
// protected by bridge.mu
// TODO: store using an array and a per-inode handle; the map
// is fairly heavyweight.
openFiles map[FileHandle]uint32
// mu protects the following mutable fields. When locking // mu protects the following mutable fields. When locking
// multiple Inodes, locks must be acquired using // multiple Inodes, locks must be acquired using
// lockNodes/unlockNodes // lockNodes/unlockNodes
......
...@@ -8,7 +8,6 @@ import ( ...@@ -8,7 +8,6 @@ import (
"context" "context"
"os" "os"
"path/filepath" "path/filepath"
"sync"
"syscall" "syscall"
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
...@@ -24,8 +23,7 @@ type loopbackRoot struct { ...@@ -24,8 +23,7 @@ type loopbackRoot struct {
func (n *loopbackRoot) newLoopbackNode() *loopbackNode { func (n *loopbackRoot) newLoopbackNode() *loopbackNode {
return &loopbackNode{ return &loopbackNode{
rootNode: n, rootNode: n,
openFiles: map[*loopbackFile]uint32{},
} }
} }
...@@ -54,21 +52,6 @@ type loopbackNode struct { ...@@ -54,21 +52,6 @@ type loopbackNode struct {
DefaultOperations DefaultOperations
rootNode *loopbackRoot rootNode *loopbackRoot
mu sync.Mutex
// file => openflags
openFiles map[*loopbackFile]uint32
}
func (n *loopbackNode) Release(f FileHandle) {
if f != nil {
n.mu.Lock()
defer n.mu.Unlock()
lf := f.(*loopbackFile)
delete(n.openFiles, lf)
f.Release()
}
} }
func (n *loopbackNode) path() string { func (n *loopbackNode) path() string {
...@@ -190,9 +173,6 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo ...@@ -190,9 +173,6 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo
node := n.rootNode.newLoopbackNode() node := n.rootNode.newLoopbackNode()
ch := n.inode().NewInode(node, uint32(st.Mode), idFromStat(&st)) ch := n.inode().NewInode(node, uint32(st.Mode), idFromStat(&st))
lf := newLoopbackFile(fd) lf := newLoopbackFile(fd)
n.mu.Lock()
defer n.mu.Unlock()
n.openFiles[lf] = flags | syscall.O_CREAT
return ch, lf, 0, fuse.OK return ch, lf, 0, fuse.OK
} }
...@@ -256,10 +236,7 @@ func (n *loopbackNode) Open(ctx context.Context, flags uint32) (fh FileHandle, f ...@@ -256,10 +236,7 @@ func (n *loopbackNode) Open(ctx context.Context, flags uint32) (fh FileHandle, f
if err != nil { if err != nil {
return nil, 0, fuse.ToStatus(err) return nil, 0, fuse.ToStatus(err)
} }
n.mu.Lock()
defer n.mu.Unlock()
lf := newLoopbackFile(f) lf := newLoopbackFile(f)
n.openFiles[lf] = flags
return lf, 0, fuse.OK return lf, 0, fuse.OK
} }
...@@ -276,25 +253,9 @@ func (n *loopbackNode) ReadDir(ctx context.Context) (DirStream, fuse.Status) { ...@@ -276,25 +253,9 @@ func (n *loopbackNode) ReadDir(ctx context.Context) (DirStream, fuse.Status) {
return NewLoopbackDirStream(n.path()) return NewLoopbackDirStream(n.path())
} }
func (n *loopbackNode) fGetAttr(ctx context.Context, out *fuse.AttrOut) (fuse.Status, bool) {
n.mu.Lock()
defer n.mu.Unlock()
for f := range n.openFiles {
if f != nil {
return f.GetAttr(ctx, out), true
}
}
return fuse.EBADF, false
}
func (n *loopbackNode) GetAttr(ctx context.Context, f FileHandle, out *fuse.AttrOut) fuse.Status { func (n *loopbackNode) GetAttr(ctx context.Context, f FileHandle, out *fuse.AttrOut) fuse.Status {
if f != nil { if f != nil {
// this never happens because the kernel never sends FH on getattr.
return f.GetAttr(ctx, out) return f.GetAttr(ctx, out)
}
if status, ok := n.fGetAttr(ctx, out); ok {
return status
} }
p := n.path() p := n.path()
...@@ -314,7 +275,6 @@ func NewLoopback(root string) Operations { ...@@ -314,7 +275,6 @@ func NewLoopback(root string) Operations {
root: root, root: root,
} }
n.rootNode = n n.rootNode = n
n.openFiles = map[*loopbackFile]uint32{}
return n return n
} }
......
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