From 5166631830e78797b0546c9bec664574ccbf3879 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:09:11 +1000 Subject: [PATCH 01/21] Renamed to out_message.go. --- internal/buffer/{buffer.go => out_message.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename internal/buffer/{buffer.go => out_message.go} (100%) diff --git a/internal/buffer/buffer.go b/internal/buffer/out_message.go similarity index 100% rename from internal/buffer/buffer.go rename to internal/buffer/out_message.go From b3d13508fbb05cc7b7330e0f23d35ac7e2a73244 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:11:03 +1000 Subject: [PATCH 02/21] Renamed to OutMessage. --- internal/buffer/out_message.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/buffer/out_message.go b/internal/buffer/out_message.go index fe69a79..123a141e 100644 --- a/internal/buffer/out_message.go +++ b/internal/buffer/out_message.go @@ -21,25 +21,25 @@ import ( "github.com/jacobsa/fuse/internal/fusekernel" ) -// Buffer provides a mechanism for constructing a single contiguous fuse +// OutMessage provides a mechanism for constructing a single contiguous fuse // message from multiple segments, where the first segment is always a // fusekernel.OutHeader message. // // Must be created with New. Exception: the zero value has Bytes() == nil. -type Buffer struct { +type OutMessage struct { slice []byte } // Create a new buffer whose initial contents are a zeroed fusekernel.OutHeader // message, and with room enough to grow by extra bytes. -func New(extra uintptr) (b Buffer) { +func NewOutMessage(extra uintptr) (b OutMessage) { const headerSize = unsafe.Sizeof(fusekernel.OutHeader{}) b.slice = make([]byte, headerSize, headerSize+extra) return } // Return a pointer to the header at the start of the buffer. -func (b *Buffer) OutHeader() (h *fusekernel.OutHeader) { +func (b *OutMessage) OutHeader() (h *fusekernel.OutHeader) { sh := (*reflect.SliceHeader)(unsafe.Pointer(&b.slice)) h = (*fusekernel.OutHeader)(unsafe.Pointer(sh.Data)) return @@ -48,7 +48,7 @@ func (b *Buffer) OutHeader() (h *fusekernel.OutHeader) { // Grow the buffer by the supplied number of bytes, returning a pointer to the // start of the new segment. The sum of the arguments given to Grow must not // exceed the argument given to New when creating the buffer. -func (b *Buffer) Grow(size uintptr) (p unsafe.Pointer) { +func (b *OutMessage) Grow(size uintptr) (p unsafe.Pointer) { sh := (*reflect.SliceHeader)(unsafe.Pointer(&b.slice)) p = unsafe.Pointer(sh.Data + uintptr(sh.Len)) b.slice = b.slice[:len(b.slice)+int(size)] @@ -56,7 +56,7 @@ func (b *Buffer) Grow(size uintptr) (p unsafe.Pointer) { } // Equivalent to growing by the length of p, then copying p into the new segment. -func (b *Buffer) Append(p []byte) { +func (b *OutMessage) Append(p []byte) { sh := reflect.SliceHeader{ Data: uintptr(b.Grow(uintptr(len(p)))), Len: len(p), @@ -67,7 +67,7 @@ func (b *Buffer) Append(p []byte) { } // Equivalent to growing by the length of s, then copying s into the new segment. -func (b *Buffer) AppendString(s string) { +func (b *OutMessage) AppendString(s string) { sh := reflect.SliceHeader{ Data: uintptr(b.Grow(uintptr(len(s)))), Len: len(s), @@ -78,6 +78,6 @@ func (b *Buffer) AppendString(s string) { } // Return a reference to the current contents of the buffer. -func (b *Buffer) Bytes() []byte { +func (b *OutMessage) Bytes() []byte { return b.slice } From 34bba99216ee90a864f81a907018b1e88821a6dc Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:12:12 +1000 Subject: [PATCH 03/21] Fixed a bunch of build errors. --- fuseops/common_op.go | 6 ++-- fuseops/ops.go | 86 ++++++++++++++++++++++---------------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/fuseops/common_op.go b/fuseops/common_op.go index 203793c..fb3a224 100644 --- a/fuseops/common_op.go +++ b/fuseops/common_op.go @@ -36,7 +36,7 @@ type internalOp interface { // // Special case: a zero return value means that the kernel is not expecting a // response. - kernelResponse() (b buffer.Buffer) + kernelResponse() (b buffer.OutMessage) } // A function that sends a reply message back to the kernel for the request @@ -142,11 +142,11 @@ func (o *commonOp) Respond(err error) { // If successful, we ask the op for an appopriate response to the kernel, and // it is responsible for leaving room for the fusekernel.OutHeader struct. // Otherwise, create our own. - var b buffer.Buffer + var b buffer.OutMessage if err == nil { b = o.op.kernelResponse() } else { - b = buffer.New(0) + b = buffer.NewOutMessage(0) } // Fill in the header if a reply is needed. diff --git a/fuseops/ops.go b/fuseops/ops.go index 97cf058..65f951b 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -88,9 +88,9 @@ func (o *LookUpInodeOp) ShortDesc() (desc string) { return } -func (o *LookUpInodeOp) kernelResponse() (b buffer.Buffer) { +func (o *LookUpInodeOp) kernelResponse() (b buffer.OutMessage) { size := fusekernel.EntryOutSize(o.protocol) - b = buffer.New(size) + b = buffer.NewOutMessage(size) out := (*fusekernel.EntryOut)(b.Grow(size)) convertChildInodeEntry(&o.Entry, out) @@ -123,9 +123,9 @@ func (o *GetInodeAttributesOp) DebugString() string { o.Attributes.DebugString()) } -func (o *GetInodeAttributesOp) kernelResponse() (b buffer.Buffer) { +func (o *GetInodeAttributesOp) kernelResponse() (b buffer.OutMessage) { size := fusekernel.AttrOutSize(o.protocol) - b = buffer.New(size) + b = buffer.NewOutMessage(size) out := (*fusekernel.AttrOut)(b.Grow(size)) out.AttrValid, out.AttrValidNsec = convertExpirationTime(o.AttributesExpiration) convertAttributes(o.Inode, &o.Attributes, &out.Attr) @@ -157,9 +157,9 @@ type SetInodeAttributesOp struct { AttributesExpiration time.Time } -func (o *SetInodeAttributesOp) kernelResponse() (b buffer.Buffer) { +func (o *SetInodeAttributesOp) kernelResponse() (b buffer.OutMessage) { size := fusekernel.AttrOutSize(o.protocol) - b = buffer.New(size) + b = buffer.NewOutMessage(size) out := (*fusekernel.AttrOut)(b.Grow(size)) out.AttrValid, out.AttrValidNsec = convertExpirationTime(o.AttributesExpiration) convertAttributes(o.Inode, &o.Attributes, &out.Attr) @@ -216,7 +216,7 @@ type ForgetInodeOp struct { N uint64 } -func (o *ForgetInodeOp) kernelResponse() (b buffer.Buffer) { +func (o *ForgetInodeOp) kernelResponse() (b buffer.OutMessage) { // No response. return } @@ -259,9 +259,9 @@ func (o *MkDirOp) ShortDesc() (desc string) { return } -func (o *MkDirOp) kernelResponse() (b buffer.Buffer) { +func (o *MkDirOp) kernelResponse() (b buffer.OutMessage) { size := fusekernel.EntryOutSize(o.protocol) - b = buffer.New(size) + b = buffer.NewOutMessage(size) out := (*fusekernel.EntryOut)(b.Grow(size)) convertChildInodeEntry(&o.Entry, out) @@ -311,9 +311,9 @@ func (o *CreateFileOp) ShortDesc() (desc string) { return } -func (o *CreateFileOp) kernelResponse() (b buffer.Buffer) { +func (o *CreateFileOp) kernelResponse() (b buffer.OutMessage) { eSize := fusekernel.EntryOutSize(o.protocol) - b = buffer.New(eSize + unsafe.Sizeof(fusekernel.OpenOut{})) + b = buffer.NewOutMessage(eSize + unsafe.Sizeof(fusekernel.OpenOut{})) e := (*fusekernel.EntryOut)(b.Grow(eSize)) convertChildInodeEntry(&o.Entry, e) @@ -357,9 +357,9 @@ func (o *CreateSymlinkOp) ShortDesc() (desc string) { return } -func (o *CreateSymlinkOp) kernelResponse() (b buffer.Buffer) { +func (o *CreateSymlinkOp) kernelResponse() (b buffer.OutMessage) { size := fusekernel.EntryOutSize(o.protocol) - b = buffer.New(size) + b = buffer.NewOutMessage(size) out := (*fusekernel.EntryOut)(b.Grow(size)) convertChildInodeEntry(&o.Entry, out) @@ -418,8 +418,8 @@ type RenameOp struct { NewName string } -func (o *RenameOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(0) +func (o *RenameOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(0) return } @@ -439,8 +439,8 @@ type RmDirOp struct { Name string } -func (o *RmDirOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(0) +func (o *RmDirOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(0) return } @@ -459,8 +459,8 @@ type UnlinkOp struct { Name string } -func (o *UnlinkOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(0) +func (o *UnlinkOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(0) return } @@ -491,8 +491,8 @@ type OpenDirOp struct { Handle HandleID } -func (o *OpenDirOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(unsafe.Sizeof(fusekernel.OpenOut{})) +func (o *OpenDirOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.OpenOut{})) out := (*fusekernel.OpenOut)(b.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) out.Fh = uint64(o.Handle) @@ -589,8 +589,8 @@ type ReadDirOp struct { Data []byte } -func (o *ReadDirOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(uintptr(len(o.Data))) +func (o *ReadDirOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(uintptr(len(o.Data))) b.Append(o.Data) return } @@ -612,8 +612,8 @@ type ReleaseDirHandleOp struct { Handle HandleID } -func (o *ReleaseDirHandleOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(0) +func (o *ReleaseDirHandleOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(0) return } @@ -643,8 +643,8 @@ type OpenFileOp struct { Handle HandleID } -func (o *OpenFileOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(unsafe.Sizeof(fusekernel.OpenOut{})) +func (o *OpenFileOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.OpenOut{})) out := (*fusekernel.OpenOut)(b.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) out.Fh = uint64(o.Handle) @@ -680,8 +680,8 @@ type ReadFileOp struct { Data []byte } -func (o *ReadFileOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(uintptr(len(o.Data))) +func (o *ReadFileOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(uintptr(len(o.Data))) b.Append(o.Data) return } @@ -756,8 +756,8 @@ type WriteFileOp struct { Data []byte } -func (o *WriteFileOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(unsafe.Sizeof(fusekernel.WriteOut{})) +func (o *WriteFileOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.WriteOut{})) out := (*fusekernel.WriteOut)(b.Grow(unsafe.Sizeof(fusekernel.WriteOut{}))) out.Size = uint32(len(o.Data)) @@ -788,8 +788,8 @@ type SyncFileOp struct { Handle HandleID } -func (o *SyncFileOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(0) +func (o *SyncFileOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(0) return } @@ -848,8 +848,8 @@ type FlushFileOp struct { Handle HandleID } -func (o *FlushFileOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(0) +func (o *FlushFileOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(0) return } @@ -870,8 +870,8 @@ type ReleaseFileHandleOp struct { Handle HandleID } -func (o *ReleaseFileHandleOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(0) +func (o *ReleaseFileHandleOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(0) return } @@ -888,7 +888,7 @@ func (o *unknownOp) ShortDesc() (desc string) { return } -func (o *unknownOp) kernelResponse() (b buffer.Buffer) { +func (o *unknownOp) kernelResponse() (b buffer.OutMessage) { panic(fmt.Sprintf("Should never get here for unknown op: %s", o.ShortDesc())) } @@ -907,8 +907,8 @@ type ReadSymlinkOp struct { Target string } -func (o *ReadSymlinkOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(uintptr(len(o.Target))) +func (o *ReadSymlinkOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(uintptr(len(o.Target))) b.AppendString(o.Target) return } @@ -929,8 +929,8 @@ type InternalStatFSOp struct { commonOp } -func (o *InternalStatFSOp) kernelResponse() (b buffer.Buffer) { - b = buffer.New(unsafe.Sizeof(fusekernel.StatfsOut{})) +func (o *InternalStatFSOp) kernelResponse() (b buffer.OutMessage) { + b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.StatfsOut{})) b.Grow(unsafe.Sizeof(fusekernel.StatfsOut{})) return @@ -942,6 +942,6 @@ type InternalInterruptOp struct { FuseID uint64 } -func (o *InternalInterruptOp) kernelResponse() (b buffer.Buffer) { +func (o *InternalInterruptOp) kernelResponse() (b buffer.OutMessage) { panic("Shouldn't get here.") } From 2e8b1546be201032c6a6bf631467961d77118546 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:27:14 +1000 Subject: [PATCH 04/21] Declared InMessage. --- internal/buffer/in_message.go | 54 ++++++++++++++++++++++++++++++++++ internal/buffer/out_message.go | 3 +- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 internal/buffer/in_message.go diff --git a/internal/buffer/in_message.go b/internal/buffer/in_message.go new file mode 100644 index 0000000..26386d6 --- /dev/null +++ b/internal/buffer/in_message.go @@ -0,0 +1,54 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package buffer + +import ( + "errors" + "io" + "unsafe" + + "github.com/jacobsa/fuse/internal/fusekernel" +) + +// An incoming message from the kernel, including leading fusekernel.InHeader +// struct. Provides storage for messages and convenient access to their +// contents. +type InMessage struct { +} + +// Initialize with the data read by a single call to r.Read. The first call to +// Consume will consume the bytes directly after the fusekernel.InHeader +// struct. +func (m *InMessage) Init(r io.Reader) (err error) { + err = errors.New("TODO") + return +} + +// Return a reference to the header read in the most recent call to Init. +func (m *InMessage) Header() (h *fusekernel.InHeader) { + panic("TODO") +} + +// Consume the next n bytes from the message, returning a nil pointer if there +// are fewer than n bytes available. +func (m *InMessage) Consume(n uintptr) (p unsafe.Pointer) { + panic("TODO") +} + +// Equivalent to Consume, except returns a slice of bytes. The result will be +// nil if Consume fails. +func (m *InMessage) ConsumeBytes(n uintptr) (b []byte) { + panic("TODO") +} diff --git a/internal/buffer/out_message.go b/internal/buffer/out_message.go index 123a141e..0fe8ef4 100644 --- a/internal/buffer/out_message.go +++ b/internal/buffer/out_message.go @@ -25,7 +25,8 @@ import ( // message from multiple segments, where the first segment is always a // fusekernel.OutHeader message. // -// Must be created with New. Exception: the zero value has Bytes() == nil. +// Must be created with NewOutMessage. Exception: the zero value has +// Bytes() == nil. type OutMessage struct { slice []byte } From 0370159a6813487c50ed52773058ac3622f1c1a6 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:29:31 +1000 Subject: [PATCH 05/21] Export some fields of fuseshim.Conn. --- internal/fuseshim/fuse.go | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/internal/fuseshim/fuse.go b/internal/fuseshim/fuse.go index 4748db2..22fde82 100644 --- a/internal/fuseshim/fuse.go +++ b/internal/fuseshim/fuse.go @@ -125,10 +125,10 @@ type Conn struct { MountError error // File handle for kernel communication. Only safe to access if - // rio or wio is held. - dev *os.File - wio sync.RWMutex - rio sync.RWMutex + // Rio or Wio is held. + Dev *os.File + Wio sync.RWMutex + Rio sync.RWMutex // Protocol version negotiated with InitRequest/InitResponse. proto fusekernel.Protocol @@ -162,7 +162,7 @@ func Mount(dir string, options ...MountOption) (*Conn, error) { if err != nil { return nil, err } - c.dev = f + c.Dev = f if err := initMount(c, &conf); err != nil { c.Close() @@ -513,16 +513,16 @@ func (malformedMessage) String() string { // Close closes the FUSE connection. func (c *Conn) Close() error { - c.wio.Lock() - defer c.wio.Unlock() - c.rio.Lock() - defer c.rio.Unlock() - return c.dev.Close() + c.Wio.Lock() + defer c.Wio.Unlock() + c.Rio.Lock() + defer c.Rio.Unlock() + return c.Dev.Close() } -// caller must hold wio or rio +// caller must hold Wio or Rio func (c *Conn) fd() int { - return int(c.dev.Fd()) + return int(c.Dev.Fd()) } func (c *Conn) Protocol() fusekernel.Protocol { @@ -536,9 +536,9 @@ func (c *Conn) Protocol() fusekernel.Protocol { func (c *Conn) ReadMessage() (m *Message, err error) { m = getMessage(c) loop: - c.rio.RLock() + c.Rio.RLock() n, err := syscall.Read(c.fd(), m.buf) - c.rio.RUnlock() + c.Rio.RUnlock() if err == syscall.EINTR { // OSXFUSE sends EINTR to userspace when a request interrupt // completed before it got sent to userspace? @@ -1068,8 +1068,8 @@ func (c *Conn) writeToKernel(msg []byte) error { } func (c *Conn) WriteToKernel(msg []byte) error { - c.wio.RLock() - defer c.wio.RUnlock() + c.Wio.RLock() + defer c.Wio.RUnlock() _, err := syscall.Write(c.fd(), msg) return err } From 3b9092aca5719b743494482a69a4d815307370fc Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:33:27 +1000 Subject: [PATCH 06/21] Use InMessage in several places. --- connection.go | 32 +++++++++++++++++++++++-------- fuseops/convert.go | 47 +++++++++++++++++++++++----------------------- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/connection.go b/connection.go index e1d03da..d81fff8 100644 --- a/connection.go +++ b/connection.go @@ -15,6 +15,7 @@ package fuse import ( + "errors" "fmt" "log" "path" @@ -24,6 +25,7 @@ import ( "golang.org/x/net/context" "github.com/jacobsa/fuse/fuseops" + "github.com/jacobsa/fuse/internal/buffer" "github.com/jacobsa/fuse/internal/fusekernel" "github.com/jacobsa/fuse/internal/fuseshim" ) @@ -202,6 +204,21 @@ func (c *Connection) handleInterrupt(fuseID uint64) { cancel() } +func (c *Connection) allocateInMessage() (m *buffer.InMessage) { + panic("TODO") +} + +func (c *Connection) destroyInMessage(m *buffer.InMessage) { + panic("TODO") +} + +// Read the next message from the kernel. The message must later be destroyed +// using destroyInMessage. +func (c *Connection) readMessage() (m *buffer.InMessage, err error) { + err = errors.New("TODO") + return +} + // Read the next op from the kernel process. Return io.EOF if the kernel has // closed the connection. // @@ -212,9 +229,9 @@ func (c *Connection) handleInterrupt(fuseID uint64) { func (c *Connection) ReadOp() (op fuseops.Op, err error) { // Keep going until we find a request we know how to convert. for { - // Read the next message from the fuseshim connection. - var m *fuseshim.Message - m, err = c.wrapped.ReadMessage() + // Read the next message from the kernel. + var m *buffer.InMessage + m, err = c.readMessage() if err != nil { return } @@ -224,7 +241,7 @@ func (c *Connection) ReadOp() (op fuseops.Op, err error) { c.nextOpID++ // Set up op dependencies. - opCtx := c.beginOp(m.Hdr.Opcode, m.Hdr.Unique) + opCtx := c.beginOp(m.Header().Opcode, m.Header().Unique) var debugLogForOp func(int, string, ...interface{}) if c.debugLogger != nil { @@ -238,12 +255,11 @@ func (c *Connection) ReadOp() (op fuseops.Op, err error) { fuseID uint64, replyMsg []byte, opErr error) (err error) { - // Make sure we destroy the message, as required by - // fuseshim.Connection.ReadMessage. - defer m.Destroy() + // Make sure we destroy the message, as required by readMessage. + defer c.destroyInMessage(m) // Clean up state for this op. - c.finishOp(m.Hdr.Opcode, m.Hdr.Unique) + c.finishOp(m.Header().Opcode, m.Header().Unique) // Debug logging if c.debugLogger != nil { diff --git a/fuseops/convert.go b/fuseops/convert.go index fb30d8e..220a91b 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -23,6 +23,7 @@ import ( "time" "unsafe" + "github.com/jacobsa/fuse/internal/buffer" "github.com/jacobsa/fuse/internal/fusekernel" "github.com/jacobsa/fuse/internal/fuseshim" "golang.org/x/net/context" @@ -39,7 +40,7 @@ import ( // responsible for arranging for the message to be destroyed. func Convert( opCtx context.Context, - m *fuseshim.Message, + m *buffer.InMessage, protocol fusekernel.Protocol, debugLogForOp func(int, string, ...interface{}), errorLogger *log.Logger, @@ -47,7 +48,7 @@ func Convert( var co *commonOp var io internalOp - switch m.Hdr.Opcode { + switch m.Header().Opcode { case fusekernel.OpLookup: buf := m.Bytes() n := len(buf) @@ -58,7 +59,7 @@ func Convert( to := &LookUpInodeOp{ protocol: protocol, - Parent: InodeID(m.Hdr.Nodeid), + Parent: InodeID(m.Header().Nodeid), Name: string(buf[:n-1]), } io = to @@ -67,7 +68,7 @@ func Convert( case fusekernel.OpGetattr: to := &GetInodeAttributesOp{ protocol: protocol, - Inode: InodeID(m.Hdr.Nodeid), + Inode: InodeID(m.Header().Nodeid), } io = to co = &to.commonOp @@ -81,7 +82,7 @@ func Convert( to := &SetInodeAttributesOp{ protocol: protocol, - Inode: InodeID(m.Hdr.Nodeid), + Inode: InodeID(m.Header().Nodeid), } valid := fusekernel.SetattrValid(in.Valid) @@ -115,7 +116,7 @@ func Convert( } to := &ForgetInodeOp{ - Inode: InodeID(m.Hdr.Nodeid), + Inode: InodeID(m.Header().Nodeid), N: in.Nlookup, } io = to @@ -138,7 +139,7 @@ func Convert( to := &MkDirOp{ protocol: protocol, - Parent: InodeID(m.Hdr.Nodeid), + Parent: InodeID(m.Header().Nodeid), Name: string(name), // On Linux, vfs_mkdir calls through to the inode with at most @@ -170,7 +171,7 @@ func Convert( to := &CreateFileOp{ protocol: protocol, - Parent: InodeID(m.Hdr.Nodeid), + Parent: InodeID(m.Header().Nodeid), Name: string(name), Mode: fuseshim.FileMode(in.Mode), } @@ -193,7 +194,7 @@ func Convert( to := &CreateSymlinkOp{ protocol: protocol, - Parent: InodeID(m.Hdr.Nodeid), + Parent: InodeID(m.Header().Nodeid), Name: string(newName), Target: string(target), } @@ -224,7 +225,7 @@ func Convert( oldName, newName := names[:i], names[i+1:len(names)-1] to := &RenameOp{ - OldParent: InodeID(m.Hdr.Nodeid), + OldParent: InodeID(m.Header().Nodeid), OldName: string(oldName), NewParent: InodeID(in.Newdir), NewName: string(newName), @@ -241,7 +242,7 @@ func Convert( } to := &UnlinkOp{ - Parent: InodeID(m.Hdr.Nodeid), + Parent: InodeID(m.Header().Nodeid), Name: string(buf[:n-1]), } io = to @@ -256,7 +257,7 @@ func Convert( } to := &RmDirOp{ - Parent: InodeID(m.Hdr.Nodeid), + Parent: InodeID(m.Header().Nodeid), Name: string(buf[:n-1]), } io = to @@ -264,14 +265,14 @@ func Convert( case fusekernel.OpOpen: to := &OpenFileOp{ - Inode: InodeID(m.Hdr.Nodeid), + Inode: InodeID(m.Header().Nodeid), } io = to co = &to.commonOp case fusekernel.OpOpendir: to := &OpenDirOp{ - Inode: InodeID(m.Hdr.Nodeid), + Inode: InodeID(m.Header().Nodeid), } io = to co = &to.commonOp @@ -284,7 +285,7 @@ func Convert( } to := &ReadFileOp{ - Inode: InodeID(m.Hdr.Nodeid), + Inode: InodeID(m.Header().Nodeid), Handle: HandleID(in.Fh), Offset: int64(in.Offset), Size: int(in.Size), @@ -300,7 +301,7 @@ func Convert( } to := &ReadDirOp{ - Inode: InodeID(m.Hdr.Nodeid), + Inode: InodeID(m.Header().Nodeid), Handle: HandleID(in.Fh), Offset: DirOffset(in.Offset), Size: int(in.Size), @@ -349,7 +350,7 @@ func Convert( } to := &WriteFileOp{ - Inode: InodeID(m.Hdr.Nodeid), + Inode: InodeID(m.Header().Nodeid), Handle: HandleID(in.Fh), Data: buf, Offset: int64(in.Offset), @@ -365,7 +366,7 @@ func Convert( } to := &SyncFileOp{ - Inode: InodeID(m.Hdr.Nodeid), + Inode: InodeID(m.Header().Nodeid), Handle: HandleID(in.Fh), } io = to @@ -379,7 +380,7 @@ func Convert( } to := &FlushFileOp{ - Inode: InodeID(m.Hdr.Nodeid), + Inode: InodeID(m.Header().Nodeid), Handle: HandleID(in.Fh), } io = to @@ -387,7 +388,7 @@ func Convert( case fusekernel.OpReadlink: to := &ReadSymlinkOp{ - Inode: InodeID(m.Hdr.Nodeid), + Inode: InodeID(m.Header().Nodeid), } io = to co = &to.commonOp @@ -412,8 +413,8 @@ func Convert( default: to := &unknownOp{ - opCode: m.Hdr.Opcode, - inode: InodeID(m.Hdr.Nodeid), + opCode: m.Header().Opcode, + inode: InodeID(m.Header().Nodeid), } io = to co = &to.commonOp @@ -422,7 +423,7 @@ func Convert( co.init( opCtx, io, - m.Hdr.Unique, + m.Header().Unique, sendReply, debugLogForOp, errorLogger) From 64f4827424f1924669628e1ee0b63982b7df6b93 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:36:59 +1000 Subject: [PATCH 07/21] Fixed some build errors. --- fuseops/convert.go | 12 +++++++----- internal/buffer/in_message.go | 5 +++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 220a91b..d0ad973 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -50,7 +50,7 @@ func Convert( var io internalOp switch m.Header().Opcode { case fusekernel.OpLookup: - buf := m.Bytes() + buf := m.ConsumeBytes(m.Len()) n := len(buf) if n == 0 || buf[n-1] != '\x00' { err = errors.New("Corrupt OpLookup") @@ -74,8 +74,9 @@ func Convert( co = &to.commonOp case fusekernel.OpSetattr: - in := (*fusekernel.SetattrIn)(m.Data()) - if m.Len() < unsafe.Sizeof(*in) { + type input fusekernel.SetattrIn + in := (*input)(m.Consume(unsafe.Sizeof(input{}))) + if in == nil { err = errors.New("Corrupt OpSetattr") return } @@ -109,8 +110,9 @@ func Convert( co = &to.commonOp case fusekernel.OpForget: - in := (*fusekernel.ForgetIn)(m.Data()) - if m.Len() < unsafe.Sizeof(*in) { + type input fusekernel.ForgetIn + in := (*input)(m.Consume(unsafe.Sizeof(input{}))) + if in == nil { err = errors.New("Corrupt OpForget") return } diff --git a/internal/buffer/in_message.go b/internal/buffer/in_message.go index 26386d6..c991b9a 100644 --- a/internal/buffer/in_message.go +++ b/internal/buffer/in_message.go @@ -41,6 +41,11 @@ func (m *InMessage) Header() (h *fusekernel.InHeader) { panic("TODO") } +// Return the number of bytes left to consume. +func (m *InMessage) Len() uintptr { + panic("TODO") +} + // Consume the next n bytes from the message, returning a nil pointer if there // are fewer than n bytes available. func (m *InMessage) Consume(n uintptr) (p unsafe.Pointer) { From eb177d5cf4361b79e3247fa09a78ee77c607c066 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:40:43 +1000 Subject: [PATCH 08/21] Fixed a bunch more. --- fuseops/convert.go | 54 +++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index d0ad973..9f71fb1 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -125,13 +125,13 @@ func Convert( co = &to.commonOp case fusekernel.OpMkdir: - size := fusekernel.MkdirInSize(protocol) - if m.Len() < size { + in := (*fusekernel.MkdirIn)(m.Consume(fusekernel.MkdirInSize(protocol))) + if in == nil { err = errors.New("Corrupt OpMkdir") return } - in := (*fusekernel.MkdirIn)(m.Data()) - name := m.Bytes()[size:] + + name := m.ConsumeBytes(m.Len()) i := bytes.IndexByte(name, '\x00') if i < 0 { err = errors.New("Corrupt OpMkdir") @@ -157,13 +157,13 @@ func Convert( co = &to.commonOp case fusekernel.OpCreate: - size := fusekernel.CreateInSize(protocol) - if m.Len() < size { - err = errors.New("Corrupt OpCreate") + in := (*fusekernel.MkdirIn)(m.Consume(fusekernel.CreateInSize(protocol))) + if in == nil { + err = errors.New("Corrupt OpMkdir") return } - in := (*fusekernel.CreateIn)(m.Data()) - name := m.Bytes()[size:] + + name := m.ConsumeBytes(m.Len()) i := bytes.IndexByte(name, '\x00') if i < 0 { err = errors.New("Corrupt OpCreate") @@ -181,8 +181,8 @@ func Convert( co = &to.commonOp case fusekernel.OpSymlink: - // m.Bytes() is "newName\0target\0" - names := m.Bytes() + // The message is "newName\0target\0". + names := m.ConsumeBytes(m.Len()) if len(names) == 0 || names[len(names)-1] != 0 { err = errors.New("Corrupt OpSymlink") return @@ -204,12 +204,14 @@ func Convert( co = &to.commonOp case fusekernel.OpRename: - in := (*fusekernel.RenameIn)(m.Data()) - if m.Len() < unsafe.Sizeof(*in) { + type input fusekernel.RenameIn + in := (*input)(m.Consume(unsafe.Sizeof(input{}))) + if in == nil { err = errors.New("Corrupt OpRename") return } - names := m.Bytes()[unsafe.Sizeof(*in):] + + names := m.ConsumeBytes(m.Len()) // names should be "old\x00new\x00" if len(names) < 4 { err = errors.New("Corrupt OpRename") @@ -236,7 +238,7 @@ func Convert( co = &to.commonOp case fusekernel.OpUnlink: - buf := m.Bytes() + buf := m.ConsumeBytes(m.Len()) n := len(buf) if n == 0 || buf[n-1] != '\x00' { err = errors.New("Corrupt OpUnlink") @@ -251,7 +253,7 @@ func Convert( co = &to.commonOp case fusekernel.OpRmdir: - buf := m.Bytes() + buf := m.ConsumeBytes(m.Len()) n := len(buf) if n == 0 || buf[n-1] != '\x00' { err = errors.New("Corrupt OpRmdir") @@ -280,8 +282,9 @@ func Convert( co = &to.commonOp case fusekernel.OpRead: - in := (*fusekernel.ReadIn)(m.Data()) - if m.Len() < fusekernel.ReadInSize(protocol) { + type input fusekernel.ReadIn + in := (*input)(m.Consume(unsafe.Sizeof(input{}))) + if in == nil { err = errors.New("Corrupt OpRead") return } @@ -296,8 +299,9 @@ func Convert( co = &to.commonOp case fusekernel.OpReaddir: - in := (*fusekernel.ReadIn)(m.Data()) - if m.Len() < fusekernel.ReadInSize(protocol) { + type input fusekernel.ReadIn + in := (*input)(m.Consume(unsafe.Sizeof(input{}))) + if in == nil { err = errors.New("Corrupt OpReaddir") return } @@ -312,8 +316,9 @@ func Convert( co = &to.commonOp case fusekernel.OpRelease: - in := (*fusekernel.ReleaseIn)(m.Data()) - if m.Len() < unsafe.Sizeof(*in) { + type input fusekernel.ReleaseIn + in := (*input)(m.Consume(unsafe.Sizeof(input{}))) + if in == nil { err = errors.New("Corrupt OpRelease") return } @@ -325,8 +330,9 @@ func Convert( co = &to.commonOp case fusekernel.OpReleasedir: - in := (*fusekernel.ReleaseIn)(m.Data()) - if m.Len() < unsafe.Sizeof(*in) { + type input fusekernel.ReleaseIn + in := (*input)(m.Consume(unsafe.Sizeof(input{}))) + if in == nil { err = errors.New("Corrupt OpReleasedir") return } From ca4f55538f366b3222adf277cf087a9f7a9c564c Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:41:59 +1000 Subject: [PATCH 09/21] Fixed remaining build errors. --- fuseops/convert.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 9f71fb1..ae72784 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -344,14 +344,13 @@ func Convert( co = &to.commonOp case fusekernel.OpWrite: - in := (*fusekernel.WriteIn)(m.Data()) - size := fusekernel.WriteInSize(protocol) - if m.Len() < size { + in := (*fusekernel.WriteIn)(m.Consume(fusekernel.WriteInSize(protocol))) + if in == nil { err = errors.New("Corrupt OpWrite") return } - buf := m.Bytes()[size:] + buf := m.ConsumeBytes(m.Len()) if len(buf) < int(in.Size) { err = errors.New("Corrupt OpWrite") return @@ -367,8 +366,9 @@ func Convert( co = &to.commonOp case fusekernel.OpFsync: - in := (*fusekernel.FsyncIn)(m.Data()) - if m.Len() < unsafe.Sizeof(*in) { + type input fusekernel.FsyncIn + in := (*input)(m.Consume(unsafe.Sizeof(input{}))) + if in == nil { err = errors.New("Corrupt OpFsync") return } @@ -381,8 +381,9 @@ func Convert( co = &to.commonOp case fusekernel.OpFlush: - in := (*fusekernel.FlushIn)(m.Data()) - if m.Len() < unsafe.Sizeof(*in) { + type input fusekernel.FlushIn + in := (*input)(m.Consume(unsafe.Sizeof(input{}))) + if in == nil { err = errors.New("Corrupt OpFlush") return } @@ -407,8 +408,9 @@ func Convert( co = &to.commonOp case fusekernel.OpInterrupt: - in := (*fusekernel.InterruptIn)(m.Data()) - if m.Len() < unsafe.Sizeof(*in) { + type input fusekernel.InterruptIn + in := (*input)(m.Consume(unsafe.Sizeof(input{}))) + if in == nil { err = errors.New("Corrupt OpInterrupt") return } From b8110bf8a7a593420ea4339def600fc1810c18a1 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:45:47 +1000 Subject: [PATCH 10/21] Added a buffer field. --- internal/buffer/in_message.go | 18 ++++++++++++++++++ internal/buffer/in_message_darwin.go | 20 ++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 internal/buffer/in_message_darwin.go diff --git a/internal/buffer/in_message.go b/internal/buffer/in_message.go index c991b9a..2611f9d 100644 --- a/internal/buffer/in_message.go +++ b/internal/buffer/in_message.go @@ -16,16 +16,34 @@ package buffer import ( "errors" + "fmt" "io" + "syscall" "unsafe" "github.com/jacobsa/fuse/internal/fusekernel" ) +// All requests read from the kernel, without data, are shorter than +// this. +const pageSize = 4096 + +func init() { + // Confirm the page size. + if syscall.Getpagesize() != pageSize { + panic(fmt.Sprintf("Page size is unexpectedly %d", syscall.Getpagesize())) + } +} + +// We size the buffer to have enough room for a fuse request plus data +// associated with a write request. +const bufSize = pageSize + MaxWriteSize + // An incoming message from the kernel, including leading fusekernel.InHeader // struct. Provides storage for messages and convenient access to their // contents. type InMessage struct { + buf [bufSize]byte } // Initialize with the data read by a single call to r.Read. The first call to diff --git a/internal/buffer/in_message_darwin.go b/internal/buffer/in_message_darwin.go new file mode 100644 index 0000000..d1f6b9f --- /dev/null +++ b/internal/buffer/in_message_darwin.go @@ -0,0 +1,20 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package buffer + +// The maximum fuse write request size that InMessage can acommodate. +// +// Experimentally, OS X appears to cap the size of writes to 1 MiB. +const MaxWriteSize = 1 << 20 From d93a81b046e4eb1b48559bec350b25d763847ccd Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:46:45 +1000 Subject: [PATCH 11/21] Defined the constant for Linux, too. --- internal/buffer/in_message_darwin.go | 3 ++- internal/buffer/in_message_linux.go | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 internal/buffer/in_message_linux.go diff --git a/internal/buffer/in_message_darwin.go b/internal/buffer/in_message_darwin.go index d1f6b9f..af37a02 100644 --- a/internal/buffer/in_message_darwin.go +++ b/internal/buffer/in_message_darwin.go @@ -16,5 +16,6 @@ package buffer // The maximum fuse write request size that InMessage can acommodate. // -// Experimentally, OS X appears to cap the size of writes to 1 MiB. +// Experimentally, OS X appears to cap the size of writes to 1 MiB, regardless +// of whether a larger size is specified in the mount options. const MaxWriteSize = 1 << 20 diff --git a/internal/buffer/in_message_linux.go b/internal/buffer/in_message_linux.go new file mode 100644 index 0000000..964c7da --- /dev/null +++ b/internal/buffer/in_message_linux.go @@ -0,0 +1,21 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package buffer + +// The maximum fuse write request size that InMessage can acommodate. +// +// Experimentally, Linux appears to refuse to honor a MaxWrite setting in an +// INIT response of more than 128 KiB. +const MaxWriteSize = 1 << 17 From e0d989cba30a931ba1f7efb304ae267541ea2c48 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:52:54 +1000 Subject: [PATCH 12/21] InMessage.Header --- internal/buffer/in_message.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/buffer/in_message.go b/internal/buffer/in_message.go index 2611f9d..c4a5107 100644 --- a/internal/buffer/in_message.go +++ b/internal/buffer/in_message.go @@ -43,7 +43,8 @@ const bufSize = pageSize + MaxWriteSize // struct. Provides storage for messages and convenient access to their // contents. type InMessage struct { - buf [bufSize]byte + remaining []byte + storage [bufSize]byte } // Initialize with the data read by a single call to r.Read. The first call to @@ -56,7 +57,8 @@ func (m *InMessage) Init(r io.Reader) (err error) { // Return a reference to the header read in the most recent call to Init. func (m *InMessage) Header() (h *fusekernel.InHeader) { - panic("TODO") + h = (*fusekernel.InHeader)(unsafe.Pointer(&m.storage[0])) + return } // Return the number of bytes left to consume. From b550b092fe6f9cee38d79fc0db407d921f6fddd1 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:55:35 +1000 Subject: [PATCH 13/21] Implemented some other InMessage methods. --- internal/buffer/in_message.go | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/internal/buffer/in_message.go b/internal/buffer/in_message.go index c4a5107..eb4ab7a 100644 --- a/internal/buffer/in_message.go +++ b/internal/buffer/in_message.go @@ -63,17 +63,31 @@ func (m *InMessage) Header() (h *fusekernel.InHeader) { // Return the number of bytes left to consume. func (m *InMessage) Len() uintptr { - panic("TODO") + return uintptr(len(m.remaining)) } // Consume the next n bytes from the message, returning a nil pointer if there // are fewer than n bytes available. func (m *InMessage) Consume(n uintptr) (p unsafe.Pointer) { - panic("TODO") + if m.Len() == 0 || n > m.Len() { + return + } + + p = unsafe.Pointer(&m.remaining[0]) + m.remaining = m.remaining[n:] + + return } // Equivalent to Consume, except returns a slice of bytes. The result will be -// nil if Consume fails. +// nil if Consume would fail. func (m *InMessage) ConsumeBytes(n uintptr) (b []byte) { - panic("TODO") + if n > m.Len() { + return + } + + b = m.remaining[:n] + m.remaining = m.remaining[n:] + + return } From 9ea4360f19cdaedeb1bb66ae59b6e8d11886084a Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 14:57:18 +1000 Subject: [PATCH 14/21] InMessage.Init --- internal/buffer/in_message.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/internal/buffer/in_message.go b/internal/buffer/in_message.go index eb4ab7a..ee836fc 100644 --- a/internal/buffer/in_message.go +++ b/internal/buffer/in_message.go @@ -15,7 +15,6 @@ package buffer import ( - "errors" "fmt" "io" "syscall" @@ -51,7 +50,17 @@ type InMessage struct { // Consume will consume the bytes directly after the fusekernel.InHeader // struct. func (m *InMessage) Init(r io.Reader) (err error) { - err = errors.New("TODO") + n, err := r.Read(m.storage[:]) + if err != nil { + return + } + + if uintptr(n) < unsafe.Sizeof(fusekernel.InHeader{}) { + err = fmt.Errorf("Unexpectedly read only %d bytes.", n) + return + } + + m.remaining = m.storage[:n] return } From f2e8a5d8068dce478b0287ca54d401af96e268f0 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 15:04:28 +1000 Subject: [PATCH 15/21] Connection.readMessage --- connection.go | 24 +++++++++++++++++++++--- internal/buffer/in_message.go | 11 +++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/connection.go b/connection.go index d81fff8..c48e79f 100644 --- a/connection.go +++ b/connection.go @@ -15,7 +15,6 @@ package fuse import ( - "errors" "fmt" "log" "path" @@ -215,8 +214,27 @@ func (c *Connection) destroyInMessage(m *buffer.InMessage) { // Read the next message from the kernel. The message must later be destroyed // using destroyInMessage. func (c *Connection) readMessage() (m *buffer.InMessage, err error) { - err = errors.New("TODO") - return + // Allocate a message. + m = c.allocateInMessage() + + // Loop past transient errors. + for { + // Lock and read. + // + // TODO(jacobsa): Ensure that we document concurrency constraints that make + // it safe, then kill the lock here. + c.wrapped.Rio.RLock() + err = m.Init(c.wrapped.Dev) + c.wrapped.Rio.RUnlock() + + if err != nil { + c.destroyInMessage(m) + m = nil + return + } + + return + } } // Read the next op from the kernel process. Return io.EOF if the kernel has diff --git a/internal/buffer/in_message.go b/internal/buffer/in_message.go index ee836fc..72ea5c3 100644 --- a/internal/buffer/in_message.go +++ b/internal/buffer/in_message.go @@ -55,11 +55,22 @@ func (m *InMessage) Init(r io.Reader) (err error) { return } + // Make sure the message is long enough that calling Header is safe. if uintptr(n) < unsafe.Sizeof(fusekernel.InHeader{}) { err = fmt.Errorf("Unexpectedly read only %d bytes.", n) return } + // Check the header's length. + if int(m.Header().Len) != n { + err = fmt.Errorf( + "Header says %d bytes, but we read %d", + m.Header().Len, + n) + + return + } + m.remaining = m.storage[:n] return } From 7a5761a67cca894f076bcc034c4d2d59b0e1a68e Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 15:05:27 +1000 Subject: [PATCH 16/21] Fixed some TODOs. --- connection.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/connection.go b/connection.go index c48e79f..e93a996 100644 --- a/connection.go +++ b/connection.go @@ -204,11 +204,13 @@ func (c *Connection) handleInterrupt(fuseID uint64) { } func (c *Connection) allocateInMessage() (m *buffer.InMessage) { - panic("TODO") + // TODO(jacobsa): Use a freelist. + m = new(buffer.InMessage) + return } func (c *Connection) destroyInMessage(m *buffer.InMessage) { - panic("TODO") + // TODO(jacobsa): Use a freelist. } // Read the next message from the kernel. The message must later be destroyed From a1dadab66e6b17e16853cd303f322f1dc01a713a Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 15:07:55 +1000 Subject: [PATCH 17/21] Fixed a bug. --- connection.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/connection.go b/connection.go index e93a996..b9c027d 100644 --- a/connection.go +++ b/connection.go @@ -16,10 +16,13 @@ package fuse import ( "fmt" + "io" "log" + "os" "path" "runtime" "sync" + "syscall" "golang.org/x/net/context" @@ -232,6 +235,12 @@ func (c *Connection) readMessage() (m *buffer.InMessage, err error) { if err != nil { c.destroyInMessage(m) m = nil + + // Special case: ENODEV means fuse has hung up. + if pe, ok := err.(*os.PathError); ok && pe.Err == syscall.ENODEV { + err = io.EOF + } + return } From 59962d69e6891711354c479b6b835741509f161e Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 15:10:28 +1000 Subject: [PATCH 18/21] Fixed a bug. --- internal/buffer/in_message.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/buffer/in_message.go b/internal/buffer/in_message.go index 72ea5c3..f87f3b0 100644 --- a/internal/buffer/in_message.go +++ b/internal/buffer/in_message.go @@ -55,12 +55,15 @@ func (m *InMessage) Init(r io.Reader) (err error) { return } - // Make sure the message is long enough that calling Header is safe. - if uintptr(n) < unsafe.Sizeof(fusekernel.InHeader{}) { + // Make sure the message is long enough. + const headerSize = unsafe.Sizeof(fusekernel.InHeader{}) + if uintptr(n) < headerSize { err = fmt.Errorf("Unexpectedly read only %d bytes.", n) return } + m.remaining = m.storage[headerSize:n] + // Check the header's length. if int(m.Header().Len) != n { err = fmt.Errorf( @@ -71,7 +74,6 @@ func (m *InMessage) Init(r io.Reader) (err error) { return } - m.remaining = m.storage[:n] return } From 36b7b6ab0e766a120dec385b2fb24660b423fbfe Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 15:11:31 +1000 Subject: [PATCH 19/21] Fixed a bug. --- fuseops/convert.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index ae72784..11fd2cc 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -282,8 +282,7 @@ func Convert( co = &to.commonOp case fusekernel.OpRead: - type input fusekernel.ReadIn - in := (*input)(m.Consume(unsafe.Sizeof(input{}))) + in := (*fusekernel.ReadIn)(m.Consume(fusekernel.ReadInSize(protocol))) if in == nil { err = errors.New("Corrupt OpRead") return @@ -299,8 +298,7 @@ func Convert( co = &to.commonOp case fusekernel.OpReaddir: - type input fusekernel.ReadIn - in := (*input)(m.Consume(unsafe.Sizeof(input{}))) + in := (*fusekernel.ReadIn)(m.Consume(fusekernel.ReadInSize(protocol))) if in == nil { err = errors.New("Corrupt OpReaddir") return From 816f77d732847948ca25bd801255e93ef5f1c7fd Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 15:13:26 +1000 Subject: [PATCH 20/21] Fixed a bug. --- fuseops/convert.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 11fd2cc..0f265cd 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -157,9 +157,9 @@ func Convert( co = &to.commonOp case fusekernel.OpCreate: - in := (*fusekernel.MkdirIn)(m.Consume(fusekernel.CreateInSize(protocol))) + in := (*fusekernel.CreateIn)(m.Consume(fusekernel.CreateInSize(protocol))) if in == nil { - err = errors.New("Corrupt OpMkdir") + err = errors.New("Corrupt OpCreate") return } From 4de334e034a014cf4c5c2cfe4c6578397fd6153a Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 24 Jul 2015 15:20:43 +1000 Subject: [PATCH 21/21] Fixed a bug related to EINTR. --- connection.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/connection.go b/connection.go index b9c027d..2d5d9ee 100644 --- a/connection.go +++ b/connection.go @@ -232,15 +232,27 @@ func (c *Connection) readMessage() (m *buffer.InMessage, err error) { err = m.Init(c.wrapped.Dev) c.wrapped.Rio.RUnlock() + // Special cases: + // + // * ENODEV means fuse has hung up. + // + // * EINTR means we should try again. (This seems to happen often on + // OS X, cf. http://golang.org/issue/11180) + // + if pe, ok := err.(*os.PathError); ok { + switch pe.Err { + case syscall.ENODEV: + err = io.EOF + + case syscall.EINTR: + err = nil + continue + } + } + if err != nil { c.destroyInMessage(m) m = nil - - // Special case: ENODEV means fuse has hung up. - if pe, ok := err.(*os.PathError); ok && pe.Err == syscall.ENODEV { - err = io.EOF - } - return }