Commit f822c9db authored by Kirill Smelkov's avatar Kirill Smelkov

X Demo that it is possible to change mmapping while under pagefault to it

--- FAIL: TestCacheControl (0.05s)
    cachecontrol_test.go:154: original: file mmap: got "Debian GNU/"  ; want "hello world"

If there was no mmapFixed(fmmap, "/etc/issue") under DataNode.Read the
test would not fail (i.e. it will see the old - not mmapped page)
parent a53ed6b9
...@@ -8,7 +8,7 @@ package test ...@@ -8,7 +8,7 @@ package test
import ( import (
"os" "os"
"io/ioutil" //"io/ioutil"
"testing" "testing"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
...@@ -38,7 +38,21 @@ func (d *DataNode) GetAttr(out *fuse.Attr, _ nodefs.File, _ *fuse.Context) fuse. ...@@ -38,7 +38,21 @@ func (d *DataNode) GetAttr(out *fuse.Attr, _ nodefs.File, _ *fuse.Context) fuse.
return fuse.OK return fuse.OK
} }
var fetc *os.File
func init() {
var err error
fetc, err = os.Open("/etc/issue")
if err != nil {
panic(err)
}
}
func (d *DataNode) Read(_ nodefs.File, dest []byte, off int64, _ *fuse.Context) (fuse.ReadResult, fuse.Status) { func (d *DataNode) Read(_ nodefs.File, dest []byte, off int64, _ *fuse.Context) (fuse.ReadResult, fuse.Status) {
err := mmapFixed(fmmap, int(fetc.Fd()), unix.PROT_READ, unix.MAP_SHARED)
if err != nil {
panic(err)
}
l := int64(len(d.data)) l := int64(len(d.data))
end := off + l end := off + l
if end > l { if end > l {
...@@ -48,6 +62,8 @@ func (d *DataNode) Read(_ nodefs.File, dest []byte, off int64, _ *fuse.Context) ...@@ -48,6 +62,8 @@ func (d *DataNode) Read(_ nodefs.File, dest []byte, off int64, _ *fuse.Context)
return fuse.ReadResultData(d.data[off:end]), fuse.OK return fuse.ReadResultData(d.data[off:end]), fuse.OK
} }
var fmmap []byte
// TestCacheControl verifies that FUSE server process can store/retrieve kernel data cache. // TestCacheControl verifies that FUSE server process can store/retrieve kernel data cache.
func TestCacheControl(t *testing.T) { func TestCacheControl(t *testing.T) {
dir := testutil.TempDir() dir := testutil.TempDir()
...@@ -63,6 +79,7 @@ func TestCacheControl(t *testing.T) { ...@@ -63,6 +79,7 @@ func TestCacheControl(t *testing.T) {
opts := nodefs.NewOptions() opts := nodefs.NewOptions()
opts.Debug = testutil.VerboseTest() opts.Debug = testutil.VerboseTest()
srv, fsconn, err := nodefs.MountRoot(dir, root, opts) srv, fsconn, err := nodefs.MountRoot(dir, root, opts)
_ = fsconn
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -82,6 +99,7 @@ func TestCacheControl(t *testing.T) { ...@@ -82,6 +99,7 @@ func TestCacheControl(t *testing.T) {
} }
}() }()
/*
// assertFileRead asserts that the file content reads as dataOK. // assertFileRead asserts that the file content reads as dataOK.
assertFileRead := func(subj, dataOK string) { assertFileRead := func(subj, dataOK string) {
t.Helper() t.Helper()
...@@ -97,13 +115,14 @@ func TestCacheControl(t *testing.T) { ...@@ -97,13 +115,14 @@ func TestCacheControl(t *testing.T) {
// make sure the file reads correctly // make sure the file reads correctly
assertFileRead("original", data0) assertFileRead("original", data0)
*/
// pin file content into OS cache // pin file content into OS cache
f, err := os.Open(dir + "/hello.txt") f, err := os.Open(dir + "/hello.txt")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
fmmap, err := unix.Mmap(int(f.Fd()), 0, len(data0), unix.PROT_READ, unix.MAP_SHARED) fmmap, err = unix.Mmap(int(f.Fd()), 0, len(data0), unix.PROT_READ, unix.MAP_SHARED)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -117,10 +136,10 @@ func TestCacheControl(t *testing.T) { ...@@ -117,10 +136,10 @@ func TestCacheControl(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
}() }()
err = unix.Mlock(fmmap) //err = unix.Mlock(fmmap)
if err != nil { //if err != nil {
t.Fatal(err) // t.Fatal(err)
} //}
// assertMmapRead asserts that file's mmaped memory reads as dataOK. // assertMmapRead asserts that file's mmaped memory reads as dataOK.
assertMmapRead := func(subj, dataOK string) { assertMmapRead := func(subj, dataOK string) {
...@@ -133,6 +152,7 @@ func TestCacheControl(t *testing.T) { ...@@ -133,6 +152,7 @@ func TestCacheControl(t *testing.T) {
// make sure the cache has original data // make sure the cache has original data
assertMmapRead("original", data0) assertMmapRead("original", data0)
/*
// store changed data into OS cache // store changed data into OS cache
st := fsconn.FileNotifyStoreCache(file.Inode(), 7, []byte("123")) st := fsconn.FileNotifyStoreCache(file.Inode(), 7, []byte("123"))
if st != fuse.OK { if st != fuse.OK {
...@@ -155,4 +175,5 @@ func TestCacheControl(t *testing.T) { ...@@ -155,4 +175,5 @@ func TestCacheControl(t *testing.T) {
// make sure mmapped data and file read as original data // make sure mmapped data and file read as original data
assertMmapRead("after invalcache", data0) assertMmapRead("after invalcache", data0)
assertFileRead("after invalcache", data0) assertFileRead("after invalcache", data0)
*/
} }
...@@ -5,3 +5,39 @@ ...@@ -5,3 +5,39 @@
// Package test holds the tests for Go-FUSE and is not for end-user // Package test holds the tests for Go-FUSE and is not for end-user
// consumption. // consumption.
package test package test
import (
"reflect"
"unsafe"
"syscall"
)
/*
#include <sys/mman.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int mmapFixed(int fd, void *addr, size_t length, int prot, int flags) {
void *ok;
ok = mmap(addr, length, prot, flags | MAP_FIXED, fd, 0);
if (ok == MAP_FAILED) {
return errno;
}
if (ok != addr) {
fprintf(stderr, "mmap(fixed): ret != addr\n");
abort();
}
return 0;
}
*/
import "C"
func mmapFixed(where []byte, fd int, prot int, flags int) error {
bp := (*reflect.SliceHeader)(unsafe.Pointer(&where))
errno := C.mmapFixed(C.int(fd), unsafe.Pointer(bp.Data), C.size_t(bp.Len), C.int(prot), C.int(flags))
if errno != 0 {
return syscall.Errno(errno)
}
return nil
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment