Require FileSystem methods to call Op.Respond.

And provide a helper to make it convenient to do so.

Having the server implementation call Respond makes it unnecessarily tricky to
implement FileSystem methods that continue computations in the background and
return immediately, for example enqueuing writes/flushes for a worker
goroutine.
geesefs-0-30-9
Aaron Jacobs 2015-03-25 10:00:58 +11:00
commit 2c10dd18ca
6 changed files with 242 additions and 112 deletions

View File

@ -26,39 +26,67 @@ import (
// loop" that switches on op types, instead receiving typed method calls
// directly.
//
// Each method should fill in appropriate response fields for the supplied op
// and return an error status, but not call Repand.
// Each method is responsible for calling Respond on the supplied op.
//
// See NotImplementedFileSystem for a convenient way to embed default
// implementations for methods you don't care about.
type FileSystem interface {
Init(*fuseops.InitOp) error
LookUpInode(*fuseops.LookUpInodeOp) error
GetInodeAttributes(*fuseops.GetInodeAttributesOp) error
SetInodeAttributes(*fuseops.SetInodeAttributesOp) error
ForgetInode(*fuseops.ForgetInodeOp) error
MkDir(*fuseops.MkDirOp) error
CreateFile(*fuseops.CreateFileOp) error
RmDir(*fuseops.RmDirOp) error
Unlink(*fuseops.UnlinkOp) error
OpenDir(*fuseops.OpenDirOp) error
ReadDir(*fuseops.ReadDirOp) error
ReleaseDirHandle(*fuseops.ReleaseDirHandleOp) error
OpenFile(*fuseops.OpenFileOp) error
ReadFile(*fuseops.ReadFileOp) error
WriteFile(*fuseops.WriteFileOp) error
SyncFile(*fuseops.SyncFileOp) error
FlushFile(*fuseops.FlushFileOp) error
ReleaseFileHandle(*fuseops.ReleaseFileHandleOp) error
Init(*fuseops.InitOp)
LookUpInode(*fuseops.LookUpInodeOp)
GetInodeAttributes(*fuseops.GetInodeAttributesOp)
SetInodeAttributes(*fuseops.SetInodeAttributesOp)
ForgetInode(*fuseops.ForgetInodeOp)
MkDir(*fuseops.MkDirOp)
CreateFile(*fuseops.CreateFileOp)
RmDir(*fuseops.RmDirOp)
Unlink(*fuseops.UnlinkOp)
OpenDir(*fuseops.OpenDirOp)
ReadDir(*fuseops.ReadDirOp)
ReleaseDirHandle(*fuseops.ReleaseDirHandleOp)
OpenFile(*fuseops.OpenFileOp)
ReadFile(*fuseops.ReadFileOp)
WriteFile(*fuseops.WriteFileOp)
SyncFile(*fuseops.SyncFileOp)
FlushFile(*fuseops.FlushFileOp)
ReleaseFileHandle(*fuseops.ReleaseFileHandleOp)
}
// Create a fuse.Server that serves ops by calling the associated FileSystem
// method and then calling Op.Respond with the resulting error. Unsupported ops
// are responded to directly with ENOSYS.
// Create a fuse.Server that handles ops by calling the associated FileSystem
// method.Respond with the resulting error. Unsupported ops are responded to
// directly with ENOSYS.
//
// FileSystem methods are called ine exactly the order of supported ops
// received by the connection, on a single goroutine. The methods should
// probably not block, instead continuing long-running operations in the
// background. Note however that there are subtleties here: for example, you
// probably want to serialize the order of write and flush operations.
func NewFileSystemServer(fs FileSystem) fuse.Server {
return fileSystemServer{fs}
}
// A convenience function that makes it easy to ensure you respond to an
// operation when a FileSystem method returns. Responds to op with the current
// value of *err.
//
// For example:
//
// func (fs *myFS) ReadFile(op *fuseops.ReadFileOp) {
// var err error
// defer fuseutil.RespondToOp(op, &err)
//
// if err = fs.frobnicate(); err != nil {
// err = fmt.Errorf("frobnicate: %v", err)
// return
// }
//
// // Lots more manipulation of err, and return paths.
// // [...]
// }
//
func RespondToOp(op fuseops.Op, err *error) {
op.Respond(*err)
}
type fileSystemServer struct {
fs FileSystem
}
@ -79,58 +107,58 @@ func (s fileSystemServer) ServeOps(c *fuse.Connection) {
op.Respond(fuse.ENOSYS)
case *fuseops.InitOp:
op.Respond(s.fs.Init(typed))
s.fs.Init(typed)
case *fuseops.LookUpInodeOp:
op.Respond(s.fs.LookUpInode(typed))
s.fs.LookUpInode(typed)
case *fuseops.GetInodeAttributesOp:
op.Respond(s.fs.GetInodeAttributes(typed))
s.fs.GetInodeAttributes(typed)
case *fuseops.SetInodeAttributesOp:
op.Respond(s.fs.SetInodeAttributes(typed))
s.fs.SetInodeAttributes(typed)
case *fuseops.ForgetInodeOp:
op.Respond(s.fs.ForgetInode(typed))
s.fs.ForgetInode(typed)
case *fuseops.MkDirOp:
op.Respond(s.fs.MkDir(typed))
s.fs.MkDir(typed)
case *fuseops.CreateFileOp:
op.Respond(s.fs.CreateFile(typed))
s.fs.CreateFile(typed)
case *fuseops.RmDirOp:
op.Respond(s.fs.RmDir(typed))
s.fs.RmDir(typed)
case *fuseops.UnlinkOp:
op.Respond(s.fs.Unlink(typed))
s.fs.Unlink(typed)
case *fuseops.OpenDirOp:
op.Respond(s.fs.OpenDir(typed))
s.fs.OpenDir(typed)
case *fuseops.ReadDirOp:
op.Respond(s.fs.ReadDir(typed))
s.fs.ReadDir(typed)
case *fuseops.ReleaseDirHandleOp:
op.Respond(s.fs.ReleaseDirHandle(typed))
s.fs.ReleaseDirHandle(typed)
case *fuseops.OpenFileOp:
op.Respond(s.fs.OpenFile(typed))
s.fs.OpenFile(typed)
case *fuseops.ReadFileOp:
op.Respond(s.fs.ReadFile(typed))
s.fs.ReadFile(typed)
case *fuseops.WriteFileOp:
op.Respond(s.fs.WriteFile(typed))
s.fs.WriteFile(typed)
case *fuseops.SyncFileOp:
op.Respond(s.fs.SyncFile(typed))
s.fs.SyncFile(typed)
case *fuseops.FlushFileOp:
op.Respond(s.fs.FlushFile(typed))
s.fs.FlushFile(typed)
case *fuseops.ReleaseFileHandleOp:
op.Respond(s.fs.ReleaseFileHandle(typed))
s.fs.ReleaseFileHandle(typed)
}
}
}

View File

@ -19,7 +19,7 @@ import (
"github.com/jacobsa/fuse/fuseops"
)
// A FileSystem that returns fuse.ENOSYS for all methods. Embed this in your
// A FileSystem that responds to all ops with fuse.ENOSYS. Embed this in your
// struct to inherit default implementations for the methods you don't care
// about, ensuring your struct will continue to implement FileSystem even as
// new methods are added.
@ -29,91 +29,91 @@ type NotImplementedFileSystem struct {
var _ FileSystem = &NotImplementedFileSystem{}
func (fs *NotImplementedFileSystem) Init(
op *fuseops.InitOp) error {
return fuse.ENOSYS
op *fuseops.InitOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) LookUpInode(
op *fuseops.LookUpInodeOp) error {
return fuse.ENOSYS
op *fuseops.LookUpInodeOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) GetInodeAttributes(
op *fuseops.GetInodeAttributesOp) error {
return fuse.ENOSYS
op *fuseops.GetInodeAttributesOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) SetInodeAttributes(
op *fuseops.SetInodeAttributesOp) error {
return fuse.ENOSYS
op *fuseops.SetInodeAttributesOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) ForgetInode(
op *fuseops.ForgetInodeOp) error {
return fuse.ENOSYS
op *fuseops.ForgetInodeOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) MkDir(
op *fuseops.MkDirOp) error {
return fuse.ENOSYS
op *fuseops.MkDirOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) CreateFile(
op *fuseops.CreateFileOp) error {
return fuse.ENOSYS
op *fuseops.CreateFileOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) RmDir(
op *fuseops.RmDirOp) error {
return fuse.ENOSYS
op *fuseops.RmDirOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) Unlink(
op *fuseops.UnlinkOp) error {
return fuse.ENOSYS
op *fuseops.UnlinkOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) OpenDir(
op *fuseops.OpenDirOp) error {
return fuse.ENOSYS
op *fuseops.OpenDirOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) ReadDir(
op *fuseops.ReadDirOp) error {
return fuse.ENOSYS
op *fuseops.ReadDirOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) ReleaseDirHandle(
op *fuseops.ReleaseDirHandleOp) error {
return fuse.ENOSYS
op *fuseops.ReleaseDirHandleOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) OpenFile(
op *fuseops.OpenFileOp) error {
return fuse.ENOSYS
op *fuseops.OpenFileOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) ReadFile(
op *fuseops.ReadFileOp) error {
return fuse.ENOSYS
op *fuseops.ReadFileOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) WriteFile(
op *fuseops.WriteFileOp) error {
return fuse.ENOSYS
op *fuseops.WriteFileOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) SyncFile(
op *fuseops.SyncFileOp) error {
return fuse.ENOSYS
op *fuseops.SyncFileOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) FlushFile(
op *fuseops.FlushFileOp) error {
return fuse.ENOSYS
op *fuseops.FlushFileOp) {
op.Respond(fuse.ENOSYS)
}
func (fs *NotImplementedFileSystem) ReleaseFileHandle(
op *fuseops.ReleaseFileHandleOp) error {
return fuse.ENOSYS
op *fuseops.ReleaseFileHandleOp) {
op.Respond(fuse.ENOSYS)
}

View File

@ -239,13 +239,19 @@ func (fs *cachingFS) SetMtime(mtime time.Time) {
////////////////////////////////////////////////////////////////////////
func (fs *cachingFS) Init(
op *fuseops.InitOp) (err error) {
op *fuseops.InitOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
return
}
// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) LookUpInode(
op *fuseops.LookUpInodeOp) (err error) {
op *fuseops.LookUpInodeOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -299,7 +305,10 @@ func (fs *cachingFS) LookUpInode(
// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) GetInodeAttributes(
op *fuseops.GetInodeAttributesOp) (err error) {
op *fuseops.GetInodeAttributesOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -328,11 +337,17 @@ func (fs *cachingFS) GetInodeAttributes(
}
func (fs *cachingFS) OpenDir(
op *fuseops.OpenDirOp) (err error) {
op *fuseops.OpenDirOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
return
}
func (fs *cachingFS) OpenFile(
op *fuseops.OpenFileOp) (err error) {
op *fuseops.OpenFileOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
return
}

View File

@ -93,12 +93,18 @@ func (fs *flushFS) barAttributes() fuseops.InodeAttributes {
////////////////////////////////////////////////////////////////////////
func (fs *flushFS) Init(
op *fuseops.InitOp) (err error) {
op *fuseops.InitOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
return
}
func (fs *flushFS) LookUpInode(
op *fuseops.LookUpInodeOp) (err error) {
op *fuseops.LookUpInodeOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -131,7 +137,10 @@ func (fs *flushFS) LookUpInode(
}
func (fs *flushFS) GetInodeAttributes(
op *fuseops.GetInodeAttributesOp) (err error) {
op *fuseops.GetInodeAttributesOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -155,7 +164,10 @@ func (fs *flushFS) GetInodeAttributes(
}
func (fs *flushFS) OpenFile(
op *fuseops.OpenFileOp) (err error) {
op *fuseops.OpenFileOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -169,7 +181,10 @@ func (fs *flushFS) OpenFile(
}
func (fs *flushFS) ReadFile(
op *fuseops.ReadFileOp) (err error) {
op *fuseops.ReadFileOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -186,7 +201,10 @@ func (fs *flushFS) ReadFile(
}
func (fs *flushFS) WriteFile(
op *fuseops.WriteFileOp) (err error) {
op *fuseops.WriteFileOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -209,7 +227,10 @@ func (fs *flushFS) WriteFile(
}
func (fs *flushFS) SyncFile(
op *fuseops.SyncFileOp) (err error) {
op *fuseops.SyncFileOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -218,7 +239,10 @@ func (fs *flushFS) SyncFile(
}
func (fs *flushFS) FlushFile(
op *fuseops.FlushFileOp) (err error) {
op *fuseops.FlushFileOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -227,7 +251,10 @@ func (fs *flushFS) FlushFile(
}
func (fs *flushFS) OpenDir(
op *fuseops.OpenDirOp) (err error) {
op *fuseops.OpenDirOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()

View File

@ -147,11 +147,17 @@ func (fs *helloFS) patchAttributes(
attr.Crtime = now
}
func (fs *helloFS) Init(op *fuseops.InitOp) (err error) {
func (fs *helloFS) Init(op *fuseops.InitOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
return
}
func (fs *helloFS) LookUpInode(op *fuseops.LookUpInodeOp) (err error) {
func (fs *helloFS) LookUpInode(op *fuseops.LookUpInodeOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
// Find the info for the parent.
parentInfo, ok := gInodeInfo[op.Parent]
if !ok {
@ -176,7 +182,10 @@ func (fs *helloFS) LookUpInode(op *fuseops.LookUpInodeOp) (err error) {
}
func (fs *helloFS) GetInodeAttributes(
op *fuseops.GetInodeAttributesOp) (err error) {
op *fuseops.GetInodeAttributesOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
// Find the info for this inode.
info, ok := gInodeInfo[op.Inode]
if !ok {
@ -194,13 +203,19 @@ func (fs *helloFS) GetInodeAttributes(
}
func (fs *helloFS) OpenDir(
op *fuseops.OpenDirOp) (err error) {
op *fuseops.OpenDirOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
// Allow opening any directory.
return
}
func (fs *helloFS) ReadDir(
op *fuseops.ReadDirOp) (err error) {
op *fuseops.ReadDirOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
// Find the info for this inode.
info, ok := gInodeInfo[op.Inode]
if !ok {
@ -236,13 +251,19 @@ func (fs *helloFS) ReadDir(
}
func (fs *helloFS) OpenFile(
op *fuseops.OpenFileOp) (err error) {
op *fuseops.OpenFileOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
// Allow opening any file.
return
}
func (fs *helloFS) ReadFile(
op *fuseops.ReadFileOp) (err error) {
op *fuseops.ReadFileOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
// Let io.ReaderAt deal with the semantics.
reader := strings.NewReader("Hello, world!")

View File

@ -200,12 +200,18 @@ func (fs *memFS) deallocateInode(id fuseops.InodeID) {
////////////////////////////////////////////////////////////////////////
func (fs *memFS) Init(
op *fuseops.InitOp) (err error) {
op *fuseops.InitOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
return
}
func (fs *memFS) LookUpInode(
op *fuseops.LookUpInodeOp) (err error) {
op *fuseops.LookUpInodeOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.RLock()
defer fs.mu.RUnlock()
@ -237,7 +243,10 @@ func (fs *memFS) LookUpInode(
}
func (fs *memFS) GetInodeAttributes(
op *fuseops.GetInodeAttributesOp) (err error) {
op *fuseops.GetInodeAttributesOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.RLock()
defer fs.mu.RUnlock()
@ -256,7 +265,10 @@ func (fs *memFS) GetInodeAttributes(
}
func (fs *memFS) SetInodeAttributes(
op *fuseops.SetInodeAttributesOp) (err error) {
op *fuseops.SetInodeAttributesOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.RLock()
defer fs.mu.RUnlock()
@ -278,7 +290,10 @@ func (fs *memFS) SetInodeAttributes(
}
func (fs *memFS) MkDir(
op *fuseops.MkDirOp) (err error) {
op *fuseops.MkDirOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -315,7 +330,10 @@ func (fs *memFS) MkDir(
}
func (fs *memFS) CreateFile(
op *fuseops.CreateFileOp) (err error) {
op *fuseops.CreateFileOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -359,7 +377,10 @@ func (fs *memFS) CreateFile(
}
func (fs *memFS) RmDir(
op *fuseops.RmDirOp) (err error) {
op *fuseops.RmDirOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -394,7 +415,10 @@ func (fs *memFS) RmDir(
}
func (fs *memFS) Unlink(
op *fuseops.UnlinkOp) (err error) {
op *fuseops.UnlinkOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.Lock()
defer fs.mu.Unlock()
@ -423,7 +447,10 @@ func (fs *memFS) Unlink(
}
func (fs *memFS) OpenDir(
op *fuseops.OpenDirOp) (err error) {
op *fuseops.OpenDirOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.RLock()
defer fs.mu.RUnlock()
@ -441,7 +468,10 @@ func (fs *memFS) OpenDir(
}
func (fs *memFS) ReadDir(
op *fuseops.ReadDirOp) (err error) {
op *fuseops.ReadDirOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.RLock()
defer fs.mu.RUnlock()
@ -460,7 +490,10 @@ func (fs *memFS) ReadDir(
}
func (fs *memFS) OpenFile(
op *fuseops.OpenFileOp) (err error) {
op *fuseops.OpenFileOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.RLock()
defer fs.mu.RUnlock()
@ -478,7 +511,10 @@ func (fs *memFS) OpenFile(
}
func (fs *memFS) ReadFile(
op *fuseops.ReadFileOp) (err error) {
op *fuseops.ReadFileOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.RLock()
defer fs.mu.RUnlock()
@ -500,7 +536,10 @@ func (fs *memFS) ReadFile(
}
func (fs *memFS) WriteFile(
op *fuseops.WriteFileOp) (err error) {
op *fuseops.WriteFileOp) {
var err error
defer fuseutil.RespondToOp(op, &err)
fs.mu.RLock()
defer fs.mu.RUnlock()