From 3f954b3056a370a686a9cb537875ef9eb14f0c55 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Wed, 29 Jul 2015 14:05:22 +1000 Subject: [PATCH 1/4] Enable async reads. As best I can tell, this instructs the kernel not to synchronize on the completion of a read request before sending further requests. This definitely means further read requests, but I believe it means any sort of request as well. It appears to make a big difference to gcsfuse read support. --- connection.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/connection.go b/connection.go index 57f36f9..1b1b246 100644 --- a/connection.go +++ b/connection.go @@ -158,7 +158,13 @@ func (c *Connection) Init() (err error) { initOp.Library = c.protocol initOp.MaxReadahead = maxReadahead initOp.MaxWrite = buffer.MaxWriteSize - initOp.Flags = fusekernel.InitBigWrites + + // Tell the kernel not to use pitifully small 4 KiB writes. + initOp.Flags |= fusekernel.InitBigWrites + + // Tell the kernel it is free to send further requests while a read request + // is in flight. + initOp.Flags |= fusekernel.InitAsyncRead c.Reply(ctx, nil) return From 96b8ce71f0ccf71448a52d9a22260db1f85bcb56 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Wed, 29 Jul 2015 14:20:34 +1000 Subject: [PATCH 2/4] Fixed a bug: the flags parameter is in and out. --- connection.go | 2 ++ ops.go | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/connection.go b/connection.go index 1b1b246..fd1fb56 100644 --- a/connection.go +++ b/connection.go @@ -159,6 +159,8 @@ func (c *Connection) Init() (err error) { initOp.MaxReadahead = maxReadahead initOp.MaxWrite = buffer.MaxWriteSize + initOp.Flags = 0 + // Tell the kernel not to use pitifully small 4 KiB writes. initOp.Flags |= fusekernel.InitBigWrites diff --git a/ops.go b/ops.go index 13ede33..8f52850 100644 --- a/ops.go +++ b/ops.go @@ -40,9 +40,11 @@ type initOp struct { // In Kernel fusekernel.Protocol + // In/out + Flags fusekernel.InitFlags + // Out Library fusekernel.Protocol MaxReadahead uint32 - Flags fusekernel.InitFlags MaxWrite uint32 } From d45752960ac89fab4df4c6b18d250bdf050eadcd Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Wed, 29 Jul 2015 14:34:57 +1000 Subject: [PATCH 3/4] Use a custom logging for interruptOp, to aid in debugging. --- debug.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debug.go b/debug.go index 52f49fa..8d5ec9e 100644 --- a/debug.go +++ b/debug.go @@ -20,6 +20,13 @@ import ( ) func describeRequest(op interface{}) (s string) { + // Handle special cases with custom formatting. + switch typed := op.(type) { + case *interruptOp: + s = fmt.Sprintf("interruptOp(fuseid=0x%08x)", typed.FuseID) + return + } + v := reflect.ValueOf(op).Elem() t := v.Type() From cf5cfbccfdbdf4eeaafceadbe0fcf33413296080 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Wed, 29 Jul 2015 14:59:10 +1000 Subject: [PATCH 4/4] Fixed a (new) test bug on Linux. --- samples/interruptfs/interrupt_fs_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/samples/interruptfs/interrupt_fs_test.go b/samples/interruptfs/interrupt_fs_test.go index 089e2da..0ede205 100644 --- a/samples/interruptfs/interrupt_fs_test.go +++ b/samples/interruptfs/interrupt_fs_test.go @@ -19,6 +19,7 @@ import ( "os" "os/exec" "path" + "runtime" "testing" "time" @@ -72,6 +73,18 @@ func (t *InterruptFSTest) StatFoo() { } func (t *InterruptFSTest) InterruptedDuringRead() { + // On Linux, since we have async reads enabled, the kernel sends the read and + // the flush ops in parallel. When the process receives SIGINT, the interrupt + // is delivered only for the flush, probably because that's what the process + // appears to be blocking on. So this test doesn't work. + // + // Note that this means that cancellation is not delivered for reads on + // Linux. This is unfortunate, but probably worth it due to the significant + // increase in performance. + if runtime.GOOS == "linux" { + return + } + var err error t.fs.EnableReadBlocking()