From 65580f7263cdafb52c05786560c781cc2d715b9b Mon Sep 17 00:00:00 2001 From: Nick Cooper Date: Mon, 10 Mar 2014 16:33:35 +1100 Subject: [PATCH 1/4] add O_CLOEXEC to test assertions, to handle when it is non-zero --- fs/serve_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/serve_test.go b/fs/serve_test.go index 13f7283c..eebe4c89 100644 --- a/fs/serve_test.go +++ b/fs/serve_test.go @@ -438,7 +438,7 @@ func (f *create1) Create(req *fuse.CreateRequest, resp *fuse.CreateResponse, int // OS X does not pass O_TRUNC here, Linux does; as this is a // Create, that's acceptable flags &^= fuse.OpenFlags(os.O_TRUNC) - if g, e := flags, fuse.OpenFlags(os.O_CREATE|os.O_RDWR); g != e { + if g, e := flags, fuse.OpenFlags(os.O_CREATE|os.O_RDWR|syscall.O_CLOEXEC); g != e { log.Printf("ERROR create1.Create unexpected flags: %v != %v\n", g, e) return nil, nil, fuse.EPERM } @@ -1091,7 +1091,7 @@ func TestOpen(t *testing.T) { t.Errorf("unexpected error: %v", err) } - want := fuse.OpenRequest{Dir: false, Flags: fuse.OpenFlags(os.O_WRONLY | os.O_APPEND)} + want := fuse.OpenRequest{Dir: false, Flags: fuse.OpenFlags(os.O_WRONLY | os.O_APPEND | syscall.O_CLOEXEC)} if runtime.GOOS == "darwin" { // osxfuse does not let O_APPEND through at all // From ddf580e553ca24405345266150f7b6b46a9e56d5 Mon Sep 17 00:00:00 2001 From: Nick Cooper Date: Thu, 26 Feb 2015 10:19:06 +1100 Subject: [PATCH 2/4] merge --- fs/serve_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/serve_test.go b/fs/serve_test.go index 3d39d52c..1352d907 100644 --- a/fs/serve_test.go +++ b/fs/serve_test.go @@ -1223,11 +1223,7 @@ func TestOpen(t *testing.T) { t.Errorf("unexpected error: %v", err) } -<<<<<<< HEAD - want := fuse.OpenRequest{Dir: false, Flags: fuse.OpenFlags(os.O_WRONLY | os.O_APPEND | syscall.O_CLOEXEC)} -======= want := fuse.OpenRequest{Dir: false, Flags: fuse.OpenWriteOnly | fuse.OpenAppend} ->>>>>>> upstream/master if runtime.GOOS == "darwin" { // osxfuse does not let O_APPEND through at all // From 2407d66fbc4c3b7895934f6b82088ca7d60bc44f Mon Sep 17 00:00:00 2001 From: Nick Cooper Date: Thu, 26 Feb 2015 10:29:04 +1100 Subject: [PATCH 3/4] add detailed debugger interface --- debug.go | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/debug.go b/debug.go index be9f900d..4070d4f2 100644 --- a/debug.go +++ b/debug.go @@ -9,13 +9,28 @@ func stack() string { return string(buf[:runtime.Stack(buf, false)]) } -func nop(msg interface{}) {} - -// Debug is called to output debug messages, including protocol -// traces. The default behavior is to do nothing. +// Debug is used to output debug messages and protocol traces. The +// default behaviour is to do nothing. // // The messages have human-friendly string representations and are // safe to marshal to JSON. // // Implementations must not retain msg. -var Debug func(msg interface{}) = nop +type Debugger interface { + // Begin begins a trace span, returns a key to close that span. + Begin(msg interface{}) interface{} + + // End ends a trace span. + End(key, msg interface{}) + + // Print outputs a message not from a span. + Print(msg interface{}) +} + +type nopDebugger struct {} + +func (nopDebugger) Begin(msg interface{}) interface{} {} +func (nopDebugger) End(key, msg interface{}) {} +func (nopDebugger) Print(msg interface{}) + +var Debug Debugger = nopDebugger{} From 74ef90e2975406b4f7ead9316d4ae60c499f4a79 Mon Sep 17 00:00:00 2001 From: Nick Cooper Date: Thu, 26 Feb 2015 10:43:18 +1100 Subject: [PATCH 4/4] update debugger to record traces --- debug.go | 8 +++++--- fs/fstestutil/debug.go | 27 ++++++++++++++++++--------- fs/fstestutil/mounted.go | 6 +----- fs/serve.go | 28 ++++++++++++++-------------- fuse.go | 6 +++--- 5 files changed, 41 insertions(+), 34 deletions(-) diff --git a/debug.go b/debug.go index 4070d4f2..ccc4b1b2 100644 --- a/debug.go +++ b/debug.go @@ -27,10 +27,12 @@ type Debugger interface { Print(msg interface{}) } -type nopDebugger struct {} +type nopDebugger struct{} -func (nopDebugger) Begin(msg interface{}) interface{} {} +func (nopDebugger) Begin(msg interface{}) interface{} { + return nil +} func (nopDebugger) End(key, msg interface{}) {} -func (nopDebugger) Print(msg interface{}) +func (nopDebugger) Print(msg interface{}) {} var Debug Debugger = nopDebugger{} diff --git a/fs/fstestutil/debug.go b/fs/fstestutil/debug.go index df44a0c6..8b837f2f 100644 --- a/fs/fstestutil/debug.go +++ b/fs/fstestutil/debug.go @@ -18,19 +18,13 @@ func (f *flagDebug) IsBoolFlag() bool { return true } -func nop(msg interface{}) {} - func (f *flagDebug) Set(s string) error { v, err := strconv.ParseBool(s) if err != nil { return err } *f = flagDebug(v) - if v { - fuse.Debug = logMsg - } else { - fuse.Debug = nop - } + fuse.Debug = testDebugger{} return nil } @@ -38,8 +32,23 @@ func (f *flagDebug) String() string { return strconv.FormatBool(bool(*f)) } -func logMsg(msg interface{}) { - log.Printf("FUSE: %s\n", msg) +// testDebugger is the Debugger used for tests, controlled +// by the debug flag. +type testDebugger struct {} + +func (d testDebugger) Print(msg interface{}) { + if debug { + log.Printf("FUSE: %s\n", msg) + } +} + +func (d testDebugger) Begin(msg interface{}) interface{} { + d.Print(msg) + return nil +} + +func (d testDebugger) End(span, msg interface{}) { + d.Print(msg) } func init() { diff --git a/fs/fstestutil/mounted.go b/fs/fstestutil/mounted.go index 5c30011d..ff8d2ea3 100644 --- a/fs/fstestutil/mounted.go +++ b/fs/fstestutil/mounted.go @@ -103,11 +103,7 @@ func Mounted(srv *fs.Server, options ...fuse.MountOption) (*Mount, error) { func MountedT(t testing.TB, filesys fs.FS, options ...fuse.MountOption) (*Mount, error) { srv := &fs.Server{ FS: filesys, - } - if debug { - srv.Debug = func(msg interface{}) { - t.Logf("FUSE: %s", msg) - } + Debug: testDebugger{}, } return Mounted(srv, options...) } diff --git a/fs/serve.go b/fs/serve.go index f4a13a1d..0a25800b 100644 --- a/fs/serve.go +++ b/fs/serve.go @@ -293,12 +293,12 @@ type HandleReleaser interface { type Server struct { FS FS - // Function to send debug log messages to. If nil, use fuse.Debug. - // Note that changing this or fuse.Debug may not affect existing - // calls to Serve. + // Debugger to use for log and trace information. + // If nil, use fuse.Debug. Note that changing this or fuse.Debug may not + // affect existingcalls to Serve. // - // See fuse.Debug for the rules that log functions must follow. - Debug func(msg interface{}) + // See fuse.Debugger for the expected interface. + Debug fuse.Debugger } // Serve serves the FUSE connection by making calls to the methods @@ -359,7 +359,7 @@ type serveConn struct { freeNode []fuse.NodeID freeHandle []fuse.HandleID nodeGen uint64 - debug func(msg interface{}) + debug fuse.Debugger dynamicInode func(parent uint64, name string) uint64 } @@ -478,7 +478,7 @@ func (c *serveConn) dropNode(id fuse.NodeID, n uint64) (forget bool) { // this should only happen if refcounts kernel<->us disagree // *and* two ForgetRequests for the same node race each other; // this indicates a bug somewhere - c.debug(nodeRefcountDropBug{N: n, Node: id}) + c.debug.Print(nodeRefcountDropBug{N: n, Node: id}) // we may end up triggering Forget twice, but that's better // than not even once, and that's the best we can do @@ -486,7 +486,7 @@ func (c *serveConn) dropNode(id fuse.NodeID, n uint64) (forget bool) { } if n > snode.refs { - c.debug(nodeRefcountDropBug{N: n, Refs: snode.refs, Node: id}) + c.debug.Print(nodeRefcountDropBug{N: n, Refs: snode.refs, Node: id}) n = snode.refs } @@ -527,7 +527,7 @@ func (c *serveConn) getHandle(id fuse.HandleID) (shandle *serveHandle) { shandle = c.handle[uint(id)] } if shandle == nil { - c.debug(missingHandle{ + c.debug.Print(missingHandle{ Handle: id, MaxHandle: fuse.HandleID(len(c.handle)), }) @@ -628,7 +628,7 @@ func (c *serveConn) serve(r fuse.Request) { req := &serveRequest{Request: r, cancel: cancel} - c.debug(request{ + span := c.debug.Begin(request{ Op: opName(r), Request: r.Hdr(), In: r, @@ -643,7 +643,7 @@ func (c *serveConn) serve(r fuse.Request) { } if snode == nil { c.meta.Unlock() - c.debug(response{ + c.debug.End(span, response{ Op: opName(r), Request: logResponseHeader{ID: hdr.ID}, Error: fuse.ESTALE.ErrnoName(), @@ -694,7 +694,7 @@ func (c *serveConn) serve(r fuse.Request) { } else { msg.Out = resp } - c.debug(msg) + c.debug.End(span, msg) c.meta.Lock() delete(c.req, hdr.ID) @@ -821,7 +821,7 @@ func (c *serveConn) serve(r fuse.Request) { } c.meta.Unlock() if oldNode == nil { - c.debug(logLinkRequestOldNodeNotFound{ + c.debug.Print(logLinkRequestOldNodeNotFound{ Request: r.Hdr(), In: r, }) @@ -1179,7 +1179,7 @@ func (c *serveConn) serve(r fuse.Request) { } c.meta.Unlock() if newDirNode == nil { - c.debug(renameNewDirNodeNotFound{ + c.debug.Print(renameNewDirNodeNotFound{ Request: r.Hdr(), In: r, }) diff --git a/fuse.go b/fuse.go index 19925a2b..2f54fd45 100644 --- a/fuse.go +++ b/fuse.go @@ -498,7 +498,7 @@ loop: var req Request switch m.hdr.Opcode { default: - Debug(noOpcode{Opcode: m.hdr.Opcode}) + Debug.Print(noOpcode{Opcode: m.hdr.Opcode}) goto unrecognized case opLookup: @@ -887,7 +887,7 @@ loop: return req, nil corrupt: - Debug(malformedMessage{}) + Debug.Print(malformedMessage{}) putMessage(m) return nil, fmt.Errorf("fuse: malformed message") @@ -924,7 +924,7 @@ func (c *Conn) respond(out *outHeader, n uintptr) { msg := (*[1 << 30]byte)(unsafe.Pointer(out))[:n] nn, err := syscall.Write(c.fd(), msg) if nn != len(msg) || err != nil { - Debug(bugShortKernelWrite{ + Debug.Print(bugShortKernelWrite{ Written: int64(nn), Length: int64(len(msg)), Error: errorString(err),