From edd7a48815266412f312e3f0616ad69c9eb58d61 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:51:19 +1100 Subject: [PATCH 01/14] Declared msync-related tests. --- samples/flushfs/flush_fs_test.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index 7f8bba5..403e6ee 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -173,6 +173,9 @@ func dup2(oldfd int, newfd int) (err error) { return } +// Call msync(2) on a slice previously returned by mmap(2). +func msync(p []byte) (err error) + //////////////////////////////////////////////////////////////////////// // No errors //////////////////////////////////////////////////////////////////////// @@ -542,7 +545,7 @@ func (t *NoErrorsTest) Dup2() { ExpectThat(t.getFsyncs(), ElementsAre()) } -func (t *NoErrorsTest) Mmap_MunmapBeforeClose() { +func (t *NoErrorsTest) Mmap_NoMsync_MunmapBeforeClose() { var n int var err error @@ -589,7 +592,7 @@ func (t *NoErrorsTest) Mmap_MunmapBeforeClose() { } } -func (t *NoErrorsTest) Mmap_CloseBeforeMunmap() { +func (t *NoErrorsTest) Mmap_NoMsync_CloseBeforeMunmap() { var n int var err error @@ -630,6 +633,14 @@ func (t *NoErrorsTest) Mmap_CloseBeforeMunmap() { ExpectThat(t.getFsyncs(), ElementsAre()) } +func (t *NoErrorsTest) Mmap_WithMsync_MunmapBeforeClose() { + AssertTrue(false, "TODO") +} + +func (t *NoErrorsTest) Mmap_WithMsync_CloseBeforeMunmap() { + AssertTrue(false, "TODO") +} + func (t *NoErrorsTest) Directory() { var err error From 0888482d8ac8b22b4008492e246e281163d633d2 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:56:01 +1100 Subject: [PATCH 02/14] Implemented msync helper. --- samples/flushfs/flush_fs_test.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index 403e6ee..c716259 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -24,6 +24,9 @@ import ( "runtime" "syscall" "testing" + "unsafe" + + "golang.org/x/sys/unix" "github.com/jacobsa/bazilfuse" "github.com/jacobsa/fuse/fsutil" @@ -174,7 +177,20 @@ func dup2(oldfd int, newfd int) (err error) { } // Call msync(2) on a slice previously returned by mmap(2). -func msync(p []byte) (err error) +func msync(p []byte) (err error) { + _, _, errno := unix.Syscall( + unix.SYS_MMAP, + uintptr(unsafe.Pointer(&p[0])), + uintptr(len(p)), + 0) + + if errno != 0 { + err = errno + return + } + + return +} //////////////////////////////////////////////////////////////////////// // No errors From 597e1264094ea19c754dc4c9f0c546913a9c6451 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:57:38 +1100 Subject: [PATCH 03/14] NoErrorsTest.Mmap_WithMsync_MunmapBeforeClose --- samples/flushfs/flush_fs_test.go | 48 ++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index c716259..9d0b3fb 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -583,9 +583,10 @@ func (t *NoErrorsTest) Mmap_NoMsync_MunmapBeforeClose() { AssertEq(nil, err) AssertEq("taco", string(data)) - // Modify then unmap. + // Modify the contents. data[0] = 'p' + // Unmap. err = syscall.Munmap(data) AssertEq(nil, err) @@ -650,7 +651,50 @@ func (t *NoErrorsTest) Mmap_NoMsync_CloseBeforeMunmap() { } func (t *NoErrorsTest) Mmap_WithMsync_MunmapBeforeClose() { - AssertTrue(false, "TODO") + var n int + var err error + + // Open the file. + t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) + AssertEq(nil, err) + + // Write some contents to the file. + n, err = t.f1.Write([]byte("taco")) + AssertEq(nil, err) + AssertEq(4, n) + + // mmap the file. + data, err := syscall.Mmap( + int(t.f1.Fd()), 0, 4, + syscall.PROT_READ|syscall.PROT_WRITE, + syscall.MAP_SHARED) + + AssertEq(nil, err) + AssertEq("taco", string(data)) + + // Modify the contents. + data[0] = 'p' + + // msync. This causes a write, but not a flush. + ExpectThat(t.getFlushes(), ElementsAre()) + ExpectThat(t.getFsyncs(), ElementsAre()) + + // Unmap. Again, this does not cause a flush. + err = syscall.Munmap(data) + AssertEq(nil, err) + + ExpectThat(t.getFlushes(), ElementsAre()) + ExpectThat(t.getFsyncs(), ElementsAre()) + + // Close the file. We should now see a flush with the modified contents, even + // on OS X, which works differently from Linux with regard to flushing dirty + // pages (cf. https://github.com/osxfuse/osxfuse/issues/202). + err = t.f1.Close() + t.f1 = nil + AssertEq(nil, err) + + ExpectThat(t.getFlushes(), ElementsAre("paco")) + ExpectThat(t.getFsyncs(), ElementsAre()) } func (t *NoErrorsTest) Mmap_WithMsync_CloseBeforeMunmap() { From 331695907be430cab161fa3b3da58f212e6a67e6 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 12:58:59 +1100 Subject: [PATCH 04/14] Oops, forgot to msync. --- samples/flushfs/flush_fs_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index 9d0b3fb..2f26c68 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -676,6 +676,9 @@ func (t *NoErrorsTest) Mmap_WithMsync_MunmapBeforeClose() { data[0] = 'p' // msync. This causes a write, but not a flush. + err = msync(data) + ExpectEq(nil, err) + ExpectThat(t.getFlushes(), ElementsAre()) ExpectThat(t.getFsyncs(), ElementsAre()) From 2f5062ac6cf64ed2d9311642d9ef34ef31f104e3 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 13:00:18 +1100 Subject: [PATCH 05/14] Oops, msync helper is broken. --- samples/flushfs/flush_fs_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index 2f26c68..d5a04b1 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -179,7 +179,7 @@ func dup2(oldfd int, newfd int) (err error) { // Call msync(2) on a slice previously returned by mmap(2). func msync(p []byte) (err error) { _, _, errno := unix.Syscall( - unix.SYS_MMAP, + unix.SYS_MSYNC, uintptr(unsafe.Pointer(&p[0])), uintptr(len(p)), 0) From 3aaca555a40eb4110b2433219e070ae8c181d7c1 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 13:01:32 +1100 Subject: [PATCH 06/14] NoErrorsTest.Mmap_WithMsync_CloseBeforeMunmap --- samples/flushfs/flush_fs_test.go | 49 ++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index d5a04b1..5a5ff14 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -639,9 +639,10 @@ func (t *NoErrorsTest) Mmap_NoMsync_CloseBeforeMunmap() { AssertThat(t.getFlushes(), ElementsAre("taco")) AssertThat(t.getFsyncs(), ElementsAre()) - // Modify then unmap. + // Modify the contents. data[0] = 'p' + // Unmap. err = syscall.Munmap(data) AssertEq(nil, err) @@ -701,7 +702,51 @@ func (t *NoErrorsTest) Mmap_WithMsync_MunmapBeforeClose() { } func (t *NoErrorsTest) Mmap_WithMsync_CloseBeforeMunmap() { - AssertTrue(false, "TODO") + var n int + var err error + + // Open the file. + t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) + AssertEq(nil, err) + + // Write some contents to the file. + n, err = t.f1.Write([]byte("taco")) + AssertEq(nil, err) + AssertEq(4, n) + + // mmap the file. + data, err := syscall.Mmap( + int(t.f1.Fd()), 0, 4, + syscall.PROT_READ|syscall.PROT_WRITE, + syscall.MAP_SHARED) + + AssertEq(nil, err) + AssertEq("taco", string(data)) + + // Close the file. We should see a flush. + err = t.f1.Close() + t.f1 = nil + AssertEq(nil, err) + + AssertThat(t.getFlushes(), ElementsAre("taco")) + AssertThat(t.getFsyncs(), ElementsAre()) + + // Modify the contents. + data[0] = 'p' + + // msync. This causes a write, but not a flush. + err = msync(data) + ExpectEq(nil, err) + + ExpectThat(t.getFlushes(), ElementsAre("taco")) + ExpectThat(t.getFsyncs(), ElementsAre()) + + // Unmap. Again, this does not cause a flush. + err = syscall.Munmap(data) + AssertEq(nil, err) + + ExpectThat(t.getFlushes(), ElementsAre("taco")) + ExpectThat(t.getFsyncs(), ElementsAre()) } func (t *NoErrorsTest) Directory() { From 97c18fea3e98e29d7503abc4c811320c7527a18e Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 13:04:53 +1100 Subject: [PATCH 07/14] Updated the reference for the assertion about munmap. The link points here: http://sourceforge.net/p/fuse/mailman/message/33627382/ This is a fuse-devel thread titled "munmap(2) and fuse flush requests" by me on 2015-03-23. --- file_system.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/file_system.go b/file_system.go index a0253ad..955e5f7 100644 --- a/file_system.go +++ b/file_system.go @@ -243,9 +243,8 @@ type FileSystem interface { // is not. // // Note that one potentially significant case where this is *not* called is - // munmap(2). (Cf. http://goo.gl/7n1r9X, fuse-devel mailing list thread from - // Han-Wen Nienhuys on 2014-10-08.) Even if users close(2) after writing to - // an mmap'd file, on OS X the contents are not immediately flushed (cf. + // munmap(2) (cf. http://goo.gl/j8B9g0). Even if users close(2) after writing + // to an mmap'd file, on OS X the contents are not immediately flushed (cf. // https://github.com/osxfuse/osxfuse/issues/202). // // Because of cases like dup2(2), calls to FlushFile are not necessarily one From 917735c39ed7ee90f632763a16deea06e8b7aaa9 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 13:06:41 +1100 Subject: [PATCH 08/14] Added documentation about the safe way to close a mapping. --- file_system.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/file_system.go b/file_system.go index 955e5f7..4e6256a 100644 --- a/file_system.go +++ b/file_system.go @@ -245,7 +245,9 @@ type FileSystem interface { // Note that one potentially significant case where this is *not* called is // munmap(2) (cf. http://goo.gl/j8B9g0). Even if users close(2) after writing // to an mmap'd file, on OS X the contents are not immediately flushed (cf. - // https://github.com/osxfuse/osxfuse/issues/202). + // https://github.com/osxfuse/osxfuse/issues/202). On both Linux and OS X + // users can get safe behavior by calling msync(2), then munmap(2), then + // close(2). // // Because of cases like dup2(2), calls to FlushFile are not necessarily one // to one with calls to OpenFile. They should not be used for reference From 80c462596db436d0478f69ea70a9deebd0831fd3 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 13:32:41 +1100 Subject: [PATCH 09/14] Oops, set MS_SYNC or Linux does nothing. --- samples/flushfs/flush_fs_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index 5a5ff14..01bff6a 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -176,13 +176,14 @@ func dup2(oldfd int, newfd int) (err error) { return } -// Call msync(2) on a slice previously returned by mmap(2). +// Call msync(2) with the MS_SYNC flag on a slice previously returned by +// mmap(2). func msync(p []byte) (err error) { _, _, errno := unix.Syscall( unix.SYS_MSYNC, uintptr(unsafe.Pointer(&p[0])), uintptr(len(p)), - 0) + unix.MS_SYNC) if errno != 0 { err = errno From a0d210e535d517d7d45f31b4743a880c70adb453 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 13:36:33 +1100 Subject: [PATCH 10/14] Updated msync tests after setting MS_SYNC. --- samples/flushfs/flush_fs_test.go | 42 +++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index 01bff6a..6e73a93 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -110,6 +110,8 @@ func (t *flushFSTest) TearDown() { // Helpers //////////////////////////////////////////////////////////////////////// +var isDarwin = runtime.GOOS == "darwin" + func readReports(f *os.File) (reports []string, err error) { // Seek the file to the start. _, err = f.Seek(0, 0) @@ -476,7 +478,6 @@ func (t *NoErrorsTest) Dup() { var n int var err error - isDarwin := runtime.GOOS == "darwin" var expectedFlushes []interface{} // Open the file. @@ -601,7 +602,7 @@ func (t *NoErrorsTest) Mmap_NoMsync_MunmapBeforeClose() { t.f1 = nil AssertEq(nil, err) - if runtime.GOOS == "darwin" { + if isDarwin { ExpectThat(t.getFlushes(), ElementsAre("taco")) ExpectThat(t.getFsyncs(), ElementsAre()) } else { @@ -656,6 +657,8 @@ func (t *NoErrorsTest) Mmap_WithMsync_MunmapBeforeClose() { var n int var err error + var expectedFsyncs []interface{} + // Open the file. t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) AssertEq(nil, err) @@ -677,35 +680,41 @@ func (t *NoErrorsTest) Mmap_WithMsync_MunmapBeforeClose() { // Modify the contents. data[0] = 'p' - // msync. This causes a write, but not a flush. + // msync. This causes an fsync, except on OS X (cf. + // https://github.com/osxfuse/osxfuse/issues/202). err = msync(data) ExpectEq(nil, err) - ExpectThat(t.getFlushes(), ElementsAre()) - ExpectThat(t.getFsyncs(), ElementsAre()) + if !isDarwin { + expectedFsyncs = append(expectedFsyncs, "paco") + } - // Unmap. Again, this does not cause a flush. + ExpectThat(t.getFlushes(), ElementsAre()) + ExpectThat(t.getFsyncs(), ElementsAre(expectedFsyncs...)) + + // Unmap. This does not cause anything. err = syscall.Munmap(data) AssertEq(nil, err) ExpectThat(t.getFlushes(), ElementsAre()) - ExpectThat(t.getFsyncs(), ElementsAre()) + ExpectThat(t.getFsyncs(), ElementsAre(expectedFsyncs...)) // Close the file. We should now see a flush with the modified contents, even - // on OS X, which works differently from Linux with regard to flushing dirty - // pages (cf. https://github.com/osxfuse/osxfuse/issues/202). + // on OS X. err = t.f1.Close() t.f1 = nil AssertEq(nil, err) ExpectThat(t.getFlushes(), ElementsAre("paco")) - ExpectThat(t.getFsyncs(), ElementsAre()) + ExpectThat(t.getFsyncs(), ElementsAre(expectedFsyncs...)) } func (t *NoErrorsTest) Mmap_WithMsync_CloseBeforeMunmap() { var n int var err error + var expectedFsyncs []interface{} + // Open the file. t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) AssertEq(nil, err) @@ -735,19 +744,24 @@ func (t *NoErrorsTest) Mmap_WithMsync_CloseBeforeMunmap() { // Modify the contents. data[0] = 'p' - // msync. This causes a write, but not a flush. + // msync. This causes an fsync, except on OS X (cf. + // https://github.com/osxfuse/osxfuse/issues/202). err = msync(data) ExpectEq(nil, err) + if !isDarwin { + expectedFsyncs = append(expectedFsyncs, "paco") + } + ExpectThat(t.getFlushes(), ElementsAre("taco")) - ExpectThat(t.getFsyncs(), ElementsAre()) + ExpectThat(t.getFsyncs(), ElementsAre(expectedFsyncs...)) // Unmap. Again, this does not cause a flush. err = syscall.Munmap(data) AssertEq(nil, err) ExpectThat(t.getFlushes(), ElementsAre("taco")) - ExpectThat(t.getFsyncs(), ElementsAre()) + ExpectThat(t.getFsyncs(), ElementsAre(expectedFsyncs...)) } func (t *NoErrorsTest) Directory() { @@ -826,7 +840,7 @@ func (t *FlushErrorTest) Dup() { err = t.f1.Close() t.f1 = nil - if runtime.GOOS == "darwin" { + if isDarwin { AssertEq(nil, err) } else { ExpectThat(err, Error(HasSubstr("no such file"))) From dd25450c724dcaa3df479fd8766bd7dc59efb867 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 13:45:56 +1100 Subject: [PATCH 11/14] Wrote a novel on mmap'd files. --- file_system.go | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/file_system.go b/file_system.go index 4e6256a..de2a52b 100644 --- a/file_system.go +++ b/file_system.go @@ -242,12 +242,28 @@ type FileSystem interface { // case of close(2), a flush error is returned to the user. For dup2(2), it // is not. // - // Note that one potentially significant case where this is *not* called is - // munmap(2) (cf. http://goo.gl/j8B9g0). Even if users close(2) after writing - // to an mmap'd file, on OS X the contents are not immediately flushed (cf. - // https://github.com/osxfuse/osxfuse/issues/202). On both Linux and OS X - // users can get safe behavior by calling msync(2), then munmap(2), then - // close(2). + // One potentially significant case where this may not be called is mmap'd + // files, where the behavior is complicated: + // + // * munmap(2) does not cause flushes (cf. http://goo.gl/j8B9g0). + // + // * On OS X, if a user modifies a mapped file via the mapping before + // closing the file with close(2), the WriteFile calls for the + // modifications may not be received before the FlushFile request for the + // close(2) (cf. http://goo.gl/kVmNcx). + // + // * However, even on OS X you can arrange for writes via a mapping to be + // either fsync'd or flush'd by calling msync(2) followed by close(2). On + // OS X msync(2) will cause a write to go through and close(2) will cause + // a flush as usual (cf. http://goo.gl/kVmNcx). On Linux, msync(2) does + // nothing unless you set the MS_SYNC flag, in which case it causes an + // fsync (cf. http://goo.gl/P3mErk). + // + // In summary: if you make data durable in both FlushFile and SyncFile, then + // your users can get safe behavior from mapped files by calling msync(2) + // with MS_SYNC, followed by munmap(2), followed by close(2). On Linux, the + // msync(2) appears to be optional because close(2) implies dirty page + // writeback (cf. http://goo.gl/HyzLTT). // // Because of cases like dup2(2), calls to FlushFile are not necessarily one // to one with calls to OpenFile. They should not be used for reference From c4c7ce568c1c4db69bed859700b3ec0eba2548a2 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 13:46:35 +1100 Subject: [PATCH 12/14] Added a callout to msync for SyncFile. --- file_system.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/file_system.go b/file_system.go index de2a52b..1044164 100644 --- a/file_system.go +++ b/file_system.go @@ -218,9 +218,12 @@ type FileSystem interface { // // * (http://goo.gl/IQkWZa) sys_fsync calls do_fsync, calls vfs_fsync, calls // vfs_fsync_range. + // // * (http://goo.gl/5L2SMy) vfs_fsync_range calls f_op->fsync. // - // Note that this is also called by fdatasync(2) (cf. http://goo.gl/01R7rF). + // Note that this is also called by fdatasync(2) (cf. http://goo.gl/01R7rF), + // and may be called for msync(2) with the MS_SYNC flag (see the notes on + // FlushFile). // // See also: FlushFile, which may perform a similar purpose when closing a // file (but which is not used in "real" file systems). From 366567acf6e0117f799142eb4799127cd0e322e6 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 13:47:59 +1100 Subject: [PATCH 13/14] Updated some wording. --- file_system.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/file_system.go b/file_system.go index 1044164..52f8998 100644 --- a/file_system.go +++ b/file_system.go @@ -256,11 +256,11 @@ type FileSystem interface { // close(2) (cf. http://goo.gl/kVmNcx). // // * However, even on OS X you can arrange for writes via a mapping to be - // either fsync'd or flush'd by calling msync(2) followed by close(2). On - // OS X msync(2) will cause a write to go through and close(2) will cause - // a flush as usual (cf. http://goo.gl/kVmNcx). On Linux, msync(2) does - // nothing unless you set the MS_SYNC flag, in which case it causes an - // fsync (cf. http://goo.gl/P3mErk). + // flushed by calling msync(2) followed by close(2). On OS X msync(2) + // will cause a WriteFile to go through and close(2) will cause a + // FlushFile as usual (cf. http://goo.gl/kVmNcx). On Linux, msync(2) does + // nothing unless you set the MS_SYNC flag, in which case it causes a + // SyncFile (cf. http://goo.gl/P3mErk). // // In summary: if you make data durable in both FlushFile and SyncFile, then // your users can get safe behavior from mapped files by calling msync(2) From 32da7d50151a7a6606c22039b68760e4d4763224 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 13:49:44 +1100 Subject: [PATCH 14/14] FsyncErrorTest.Msync --- samples/flushfs/flush_fs_test.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/samples/flushfs/flush_fs_test.go b/samples/flushfs/flush_fs_test.go index 6e73a93..927e693 100644 --- a/samples/flushfs/flush_fs_test.go +++ b/samples/flushfs/flush_fs_test.go @@ -914,3 +914,32 @@ func (t *FsyncErrorTest) Fdatasync() { ExpectThat(err, Error(HasSubstr("no such file"))) } + +func (t *FsyncErrorTest) Msync() { + var err error + + // On OS X, msync does not cause SyncFile. + if isDarwin { + return + } + + // Open the file. + t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) + AssertEq(nil, err) + + // mmap the file. + data, err := syscall.Mmap( + int(t.f1.Fd()), 0, 4, + syscall.PROT_READ|syscall.PROT_WRITE, + syscall.MAP_SHARED) + + AssertEq(nil, err) + + // msync the mapping. + err = msync(data) + ExpectThat(err, Error(HasSubstr("no such file"))) + + // Unmap. + err = syscall.Munmap(data) + AssertEq(nil, err) +}