From 096c3fa695d82522605db920e6d946f7e761057b Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:02:48 +1100 Subject: [PATCH 01/10] Added a test for directories. --- samples/flushfs/flush_fs.go | 62 ++++++++++++++++++++++++++++---- samples/flushfs/flush_fs_test.go | 24 ++++++++++++- samples/subprocess.go | 3 +- 3 files changed, 81 insertions(+), 8 deletions(-) diff --git a/samples/flushfs/flush_fs.go b/samples/flushfs/flush_fs.go index b30c8b0..8984972 100644 --- a/samples/flushfs/flush_fs.go +++ b/samples/flushfs/flush_fs.go @@ -24,11 +24,14 @@ import ( "golang.org/x/net/context" ) -// Create a file system containing a single file named "foo". +// Create a file system whose sole contents are a file named "foo" and a +// directory named "bar". // // The file may be opened for reading and/or writing. Its initial contents are // empty. Whenever a flush or fsync is received, the supplied function will be // called with the current contents of the file and its status returned. +// +// The directory cannot be modified. func NewFileSystem( reportFlush func(string) error, reportFsync func(string) error) (fs fuse.FileSystem, err error) { @@ -40,7 +43,10 @@ func NewFileSystem( return } -const fooID = fuse.RootInodeID + 1 +const ( + fooID = fuse.RootInodeID + 1 + iota + barID +) type flushFS struct { fuseutil.NotImplementedFileSystem @@ -72,6 +78,14 @@ func (fs *flushFS) fooAttributes() fuse.InodeAttributes { } } +// LOCKS_REQUIRED(fs.mu) +func (fs *flushFS) barAttributes() fuse.InodeAttributes { + return fuse.InodeAttributes{ + Nlink: 1, + Mode: 0777 | os.ModeDir, + } +} + //////////////////////////////////////////////////////////////////////// // File system methods //////////////////////////////////////////////////////////////////////// @@ -94,14 +108,28 @@ func (fs *flushFS) LookUpInode( defer fs.mu.Unlock() // Sanity check. - if req.Parent != fuse.RootInodeID || req.Name != "foo" { + if req.Parent != fuse.RootInodeID { err = fuse.ENOENT return } - resp.Entry = fuse.ChildInodeEntry{ - Child: fooID, - Attributes: fs.fooAttributes(), + // Set up the entry. + switch req.Name { + case "foo": + resp.Entry = fuse.ChildInodeEntry{ + Child: fooID, + Attributes: fs.fooAttributes(), + } + + case "bar": + resp.Entry = fuse.ChildInodeEntry{ + Child: barID, + Attributes: fs.barAttributes(), + } + + default: + err = fuse.ENOENT + return } return @@ -125,6 +153,10 @@ func (fs *flushFS) GetInodeAttributes( resp.Attributes = fs.fooAttributes() return + case barID: + resp.Attributes = fs.barAttributes() + return + default: err = fuse.ENOENT return @@ -222,3 +254,21 @@ func (fs *flushFS) FlushFile( err = fs.reportFlush(string(fs.fooContents)) return } + +func (fs *flushFS) OpenDir( + ctx context.Context, + req *fuse.OpenDirRequest) ( + resp *fuse.OpenDirResponse, err error) { + resp = &fuse.OpenDirResponse{} + + fs.mu.Lock() + defer fs.mu.Unlock() + + // Sanity check. + if req.Inode != barID { + err = fuse.ENOSYS + return + } + + return +} diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index a5ffeb2..6ea5423 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -614,7 +614,29 @@ func (t *NoErrorsTest) Mmap_CloseBeforeMunmap() { } func (t *NoErrorsTest) Directory() { - AssertTrue(false, "TODO") + var err error + + // Open the directory. + t.f1, err = os.Open(path.Join(t.Dir, "bar")) + AssertEq(nil, err) + + // Sanity check: stat it. + fi, err := t.f1.Stat() + AssertEq(nil, err) + AssertEq(0777|os.ModeDir, fi.Mode()) + + // Sync it. + err = t.f1.Sync() + AssertEq(nil, err) + + // Close it. + err = t.f1.Close() + t.f1 = nil + AssertEq(nil, err) + + // No flushes or fsync requests should have been received. + ExpectThat(t.getFlushes(), ElementsAre()) + ExpectThat(t.getFsyncs(), ElementsAre()) } //////////////////////////////////////////////////////////////////////// diff --git a/samples/subprocess.go b/samples/subprocess.go index 38733bf..2d954b0 100644 --- a/samples/subprocess.go +++ b/samples/subprocess.go @@ -236,6 +236,7 @@ func (t *SubprocessTest) initialize() (err error) { // Set up basic args for the subprocess. args := []string{ + "--fuse.debug", "--type", t.MountType, "--mount_point", @@ -270,7 +271,7 @@ func (t *SubprocessTest) initialize() (err error) { // Set up a command. var stderr bytes.Buffer mountCmd := exec.Command(toolPath, args...) - mountCmd.Stderr = &stderr + mountCmd.Stderr = os.Stderr mountCmd.ExtraFiles = extraFiles // Start it. From fddf222e4fd644a5d566c04b483858f6496a3399 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:04:16 +1100 Subject: [PATCH 02/10] Declared fdatasync tests. --- samples/flushfs/flush_fs_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index 6ea5423..1e3bef9 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -409,6 +409,10 @@ func (t *NoErrorsTest) Fsync() { AssertThat(t.getFsyncs(), ElementsAre("taco", "tacos")) } +func (t *NoErrorsTest) Fdatasync() { + AssertTrue(false, "TODO") +} + func (t *NoErrorsTest) Dup() { var n int var err error @@ -750,3 +754,7 @@ func (t *FsyncErrorTest) Fsync() { AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("no such file"))) } + +func (t *FsyncErrorTest) Fdatasync() { + AssertTrue(false, "TODO") +} From 5f3f94992cb5f95471950722f970be8066b3d4eb Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:04:47 +1100 Subject: [PATCH 03/10] Undid debugging changes. --- samples/subprocess.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/samples/subprocess.go b/samples/subprocess.go index 2d954b0..38733bf 100644 --- a/samples/subprocess.go +++ b/samples/subprocess.go @@ -236,7 +236,6 @@ func (t *SubprocessTest) initialize() (err error) { // Set up basic args for the subprocess. args := []string{ - "--fuse.debug", "--type", t.MountType, "--mount_point", @@ -271,7 +270,7 @@ func (t *SubprocessTest) initialize() (err error) { // Set up a command. var stderr bytes.Buffer mountCmd := exec.Command(toolPath, args...) - mountCmd.Stderr = os.Stderr + mountCmd.Stderr = &stderr mountCmd.ExtraFiles = extraFiles // Start it. From 51f6b011351279a433936eeaec1ee16f86b34cca Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:22:25 +1100 Subject: [PATCH 04/10] NoErrorsTest.Fdatasync --- samples/flushfs/flush_fs_test.go | 37 +++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index 1e3bef9..9161b6c 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -410,7 +410,42 @@ func (t *NoErrorsTest) Fsync() { } func (t *NoErrorsTest) Fdatasync() { - AssertTrue(false, "TODO") + var n int + var err error + + // Open the file. + t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) + AssertEq(nil, err) + + // Write some contents to the file. + n, err = t.f1.Write([]byte("taco")) + AssertEq(nil, err) + AssertEq(4, n) + + AssertThat(t.getFlushes(), ElementsAre()) + AssertThat(t.getFsyncs(), ElementsAre()) + + // Fdatasync. + err = syscall.Fdatasync(int(t.f1.Fd())) + AssertEq(nil, err) + + AssertThat(t.getFlushes(), ElementsAre()) + AssertThat(t.getFsyncs(), ElementsAre("taco")) + + // Write some more contents. + n, err = t.f1.Write([]byte("s")) + AssertEq(nil, err) + AssertEq(1, n) + + AssertThat(t.getFlushes(), ElementsAre()) + AssertThat(t.getFsyncs(), ElementsAre("taco")) + + // Fdatasync. + err = syscall.Fdatasync(int(t.f1.Fd())) + AssertEq(nil, err) + + AssertThat(t.getFlushes(), ElementsAre()) + AssertThat(t.getFsyncs(), ElementsAre("taco", "tacos")) } func (t *NoErrorsTest) Dup() { From db0ab82bdd85ce0826bf6bfefbc04322f9f7e244 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:24:00 +1100 Subject: [PATCH 05/10] FsyncErrorTest.Fdatasync --- samples/flushfs/flush_fs_test.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index 9161b6c..e4e30eb 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -791,5 +791,15 @@ func (t *FsyncErrorTest) Fsync() { } func (t *FsyncErrorTest) Fdatasync() { - AssertTrue(false, "TODO") + var err error + + // Open the file. + t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) + AssertEq(nil, err) + + // Fdatasync. + err = syscall.Fdatasync(int(t.f1.Fd())) + + AssertNe(nil, err) + ExpectThat(err, Error(HasSubstr("no such file"))) } From e74d8b6a85efa448172de1c738dbe0a10b00bf84 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:25:27 +1100 Subject: [PATCH 06/10] Added a --debug flag. --- samples/subprocess.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/samples/subprocess.go b/samples/subprocess.go index 38733bf..ccd2ae2 100644 --- a/samples/subprocess.go +++ b/samples/subprocess.go @@ -35,6 +35,8 @@ var fToolPath = flag.String( "", "Path to the mount_sample tool. If unset, we will compile it.") +var fDebug = flag.Bool("debug", false, "If true, print fuse debug info.") + // A struct that implements common behavior needed by tests in the samples/ // directory where the file system is mounted by a subprocess. Use it as an // embedded field in your test fixture, calling its SetUp method from your @@ -273,7 +275,13 @@ func (t *SubprocessTest) initialize() (err error) { mountCmd.Stderr = &stderr mountCmd.ExtraFiles = extraFiles - // Start it. + // Handle debug mode. + if *fDebug { + mountCmd.Stderr = os.Stderr + mountCmd.Args = append(mountCmd.Args, "--fuse.debug") + } + + // Start the command. if err = mountCmd.Start(); err != nil { err = fmt.Errorf("mountCmd.Start: %v", err) return From cf22c432383b4eb2d4569fbdc158d3d4e741e1f0 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:26:22 +1100 Subject: [PATCH 07/10] Removed redundant checks that don't work for all error types. --- samples/flushfs/flush_fs_test.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index e4e30eb..4eab497 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -704,7 +704,6 @@ func (t *FlushErrorTest) Close() { err = t.f1.Close() t.f1 = nil - AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("no such file"))) } @@ -732,7 +731,6 @@ func (t *FlushErrorTest) Dup() { if runtime.GOOS == "darwin" { AssertEq(nil, err) } else { - AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("no such file"))) } @@ -740,7 +738,6 @@ func (t *FlushErrorTest) Dup() { err = t.f2.Close() t.f2 = nil - AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("no such file"))) } @@ -786,7 +783,6 @@ func (t *FsyncErrorTest) Fsync() { // Fsync. err = t.f1.Sync() - AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("no such file"))) } @@ -800,6 +796,5 @@ func (t *FsyncErrorTest) Fdatasync() { // Fdatasync. err = syscall.Fdatasync(int(t.f1.Fd())) - AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("no such file"))) } From e4e12848fb5e9b4d3d4fa8a8d18e155dfb56af5d Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:31:16 +1100 Subject: [PATCH 08/10] Fixed fdatasync build errors on darwin. --- fsutil/fsutil.go | 7 +++++++ samples/flushfs/flush_fs_test.go | 14 +++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/fsutil/fsutil.go b/fsutil/fsutil.go index 152ef85..b21732b 100644 --- a/fsutil/fsutil.go +++ b/fsutil/fsutil.go @@ -48,3 +48,10 @@ func AnonymousFile(dir string) (f *os.File, err error) { return } + +// Call fdatasync on the supplied file. +// +// REQUIRES: FdatasyncSupported is true. +func Fdatasync(f *os.File) error { + return fdatasync(f) +} diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index 4eab497..f58a037 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -413,6 +413,10 @@ func (t *NoErrorsTest) Fdatasync() { var n int var err error + if !fsutil.FdatasyncSupported { + return + } + // Open the file. t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) AssertEq(nil, err) @@ -426,7 +430,7 @@ func (t *NoErrorsTest) Fdatasync() { AssertThat(t.getFsyncs(), ElementsAre()) // Fdatasync. - err = syscall.Fdatasync(int(t.f1.Fd())) + err = fsutil.Fdatasync(t.f1) AssertEq(nil, err) AssertThat(t.getFlushes(), ElementsAre()) @@ -441,7 +445,7 @@ func (t *NoErrorsTest) Fdatasync() { AssertThat(t.getFsyncs(), ElementsAre("taco")) // Fdatasync. - err = syscall.Fdatasync(int(t.f1.Fd())) + err = fsutil.Fdatasync(t.f1) AssertEq(nil, err) AssertThat(t.getFlushes(), ElementsAre()) @@ -789,12 +793,16 @@ func (t *FsyncErrorTest) Fsync() { func (t *FsyncErrorTest) Fdatasync() { var err error + if !fsutil.FdatasyncSupported { + return + } + // Open the file. t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) AssertEq(nil, err) // Fdatasync. - err = syscall.Fdatasync(int(t.f1.Fd())) + err = fsutil.Fdatasync(t.f1) ExpectThat(err, Error(HasSubstr("no such file"))) } From 690a8214c29f4b636c8b9f9b258bef078ffaae1c Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:31:50 +1100 Subject: [PATCH 09/10] Added a missing file. --- fsutil/fdatasync_darwin.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 fsutil/fdatasync_darwin.go diff --git a/fsutil/fdatasync_darwin.go b/fsutil/fdatasync_darwin.go new file mode 100644 index 0000000..4eec368 --- /dev/null +++ b/fsutil/fdatasync_darwin.go @@ -0,0 +1,23 @@ +// 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 fsutil + +import "os" + +const FdatasyncSupported = false + +func fdatasync(f *os.File) error { + panic("We require FdatasyncSupported be true.") +} From 9689fd896f229a40d325bfddbbcbc0f12b74a5c3 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:32:56 +1100 Subject: [PATCH 10/10] Fixed fdatasync build errors on linux. --- fsutil/fdatasync_linux.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 fsutil/fdatasync_linux.go diff --git a/fsutil/fdatasync_linux.go b/fsutil/fdatasync_linux.go new file mode 100644 index 0000000..c983309 --- /dev/null +++ b/fsutil/fdatasync_linux.go @@ -0,0 +1,26 @@ +// 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 fsutil + +import ( + "os" + "syscall" +) + +const FdatasyncSupported = true + +func fdatasync(f *os.File) error { + return syscall.Fdatasync(int(f.Fd())) +}