Commit 9d9bc730 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

nodefs: remove locking from loopbackFile

The fd is set on creation, and never written. We rely on the kernel
and on fileEntry.wg to synchronize such that RELEASE always happens
after read/write has completed.
parent 96be8078
...@@ -81,8 +81,9 @@ or ...@@ -81,8 +81,9 @@ or
* Should Operations.Lookup return *Inode or Operations ? * Should Operations.Lookup return *Inode or Operations ?
* Should bridge.Lookup() add the child, bridge.Unlink remove the child, etc.?
* Merge Fsync/FsyncDir? * Merge Fsync/FsyncDir?
* OnMount in Operations or in Options? Or argument to NewNodeFS ? * OnMount in Operations or in Options? Or argument to NewNodeFS? Or
OnAdd() ?
...@@ -8,7 +8,6 @@ import ( ...@@ -8,7 +8,6 @@ import (
"context" "context"
// "time" // "time"
"sync"
"syscall" "syscall"
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
...@@ -22,45 +21,28 @@ func NewLoopbackFile(fd int) FileHandle { ...@@ -22,45 +21,28 @@ func NewLoopbackFile(fd int) FileHandle {
type loopbackFile struct { type loopbackFile struct {
fd int fd int
// Although fd themselves are constant during the lifetime of
// an open file, the OS may reuse the fd number after it is
// closed. When open races with another close, they may lead
// to confusion as which file gets written in the end.
mu sync.Mutex
} }
func (f *loopbackFile) Read(ctx context.Context, buf []byte, off int64) (res fuse.ReadResult, status fuse.Status) { func (f *loopbackFile) Read(ctx context.Context, buf []byte, off int64) (res fuse.ReadResult, status fuse.Status) {
f.mu.Lock()
// This is not racy by virtue of the kernel properly
// synchronizing the open/write/close.
r := fuse.ReadResultFd(uintptr(f.fd), off, len(buf)) r := fuse.ReadResultFd(uintptr(f.fd), off, len(buf))
f.mu.Unlock()
return r, fuse.OK return r, fuse.OK
} }
func (f *loopbackFile) Write(ctx context.Context, data []byte, off int64) (uint32, fuse.Status) { func (f *loopbackFile) Write(ctx context.Context, data []byte, off int64) (uint32, fuse.Status) {
f.mu.Lock()
n, err := syscall.Pwrite(f.fd, data, off) n, err := syscall.Pwrite(f.fd, data, off)
f.mu.Unlock()
return uint32(n), fuse.ToStatus(err) return uint32(n), fuse.ToStatus(err)
} }
func (f *loopbackFile) Release(ctx context.Context) fuse.Status { func (f *loopbackFile) Release(ctx context.Context) fuse.Status {
f.mu.Lock()
err := syscall.Close(f.fd) err := syscall.Close(f.fd)
f.mu.Unlock()
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
func (f *loopbackFile) Flush(ctx context.Context) fuse.Status { func (f *loopbackFile) Flush(ctx context.Context) fuse.Status {
f.mu.Lock()
// Since Flush() may be called for each dup'd fd, we don't // Since Flush() may be called for each dup'd fd, we don't
// want to really close the file, we just want to flush. This // want to really close the file, we just want to flush. This
// is achieved by closing a dup'd fd. // is achieved by closing a dup'd fd.
newFd, err := syscall.Dup(f.fd) newFd, err := syscall.Dup(f.fd)
f.mu.Unlock()
if err != nil { if err != nil {
return fuse.ToStatus(err) return fuse.ToStatus(err)
...@@ -70,9 +52,7 @@ func (f *loopbackFile) Flush(ctx context.Context) fuse.Status { ...@@ -70,9 +52,7 @@ func (f *loopbackFile) Flush(ctx context.Context) fuse.Status {
} }
func (f *loopbackFile) Fsync(ctx context.Context, flags uint32) (status fuse.Status) { func (f *loopbackFile) Fsync(ctx context.Context, flags uint32) (status fuse.Status) {
f.mu.Lock()
r := fuse.ToStatus(syscall.Fsync(f.fd)) r := fuse.ToStatus(syscall.Fsync(f.fd))
f.mu.Unlock()
return r return r
} }
...@@ -138,8 +118,6 @@ func (f *loopbackFile) SetAttr(ctx context.Context, in *fuse.SetAttrIn, out *fus ...@@ -138,8 +118,6 @@ func (f *loopbackFile) SetAttr(ctx context.Context, in *fuse.SetAttrIn, out *fus
} }
func (f *loopbackFile) setAttr(ctx context.Context, in *fuse.SetAttrIn) fuse.Status { func (f *loopbackFile) setAttr(ctx context.Context, in *fuse.SetAttrIn) fuse.Status {
f.mu.Lock()
defer f.mu.Unlock()
var status fuse.Status var status fuse.Status
if mode, ok := in.GetMode(); ok { if mode, ok := in.GetMode(); ok {
status = fuse.ToStatus(syscall.Fchmod(f.fd, mode)) status = fuse.ToStatus(syscall.Fchmod(f.fd, mode))
...@@ -195,9 +173,7 @@ func (f *loopbackFile) setAttr(ctx context.Context, in *fuse.SetAttrIn) fuse.Sta ...@@ -195,9 +173,7 @@ func (f *loopbackFile) setAttr(ctx context.Context, in *fuse.SetAttrIn) fuse.Sta
func (f *loopbackFile) GetAttr(ctx context.Context, a *fuse.AttrOut) fuse.Status { func (f *loopbackFile) GetAttr(ctx context.Context, a *fuse.AttrOut) fuse.Status {
st := syscall.Stat_t{} st := syscall.Stat_t{}
f.mu.Lock()
err := syscall.Fstat(f.fd, &st) err := syscall.Fstat(f.fd, &st)
f.mu.Unlock()
if err != nil { if err != nil {
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
......
...@@ -13,9 +13,7 @@ import ( ...@@ -13,9 +13,7 @@ import (
) )
func (f *loopbackFile) Allocate(ctx context.Context, off uint64, sz uint64, mode uint32) fuse.Status { func (f *loopbackFile) Allocate(ctx context.Context, off uint64, sz uint64, mode uint32) fuse.Status {
f.mu.Lock()
err := syscall.Fallocate(f.fd, mode, int64(off), int64(sz)) err := syscall.Fallocate(f.fd, mode, int64(off), int64(sz))
f.mu.Unlock()
if err != nil { if err != nil {
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
...@@ -27,8 +25,6 @@ func (f *loopbackFile) utimens(a *time.Time, m *time.Time) fuse.Status { ...@@ -27,8 +25,6 @@ func (f *loopbackFile) utimens(a *time.Time, m *time.Time) fuse.Status {
var ts [2]syscall.Timespec var ts [2]syscall.Timespec
ts[0] = fuse.UtimeToTimespec(a) ts[0] = fuse.UtimeToTimespec(a)
ts[1] = fuse.UtimeToTimespec(m) ts[1] = fuse.UtimeToTimespec(m)
f.mu.Lock()
err := futimens(int(f.fd), &ts) err := futimens(int(f.fd), &ts)
f.mu.Unlock()
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
...@@ -205,7 +205,8 @@ func (n *Inode) Forgotten() bool { ...@@ -205,7 +205,8 @@ func (n *Inode) Forgotten() bool {
return n.lookupCount == 0 && len(n.parents) == 0 && !n.persistent return n.lookupCount == 0 && len(n.parents) == 0 && !n.persistent
} }
// Node returns the Node object implementing the file system operations. // Operations returns the object implementing the file system
// operations.
func (n *Inode) Operations() Operations { func (n *Inode) Operations() Operations {
return n.ops return n.ops
} }
......
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