Commit 1adf79ce authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

unionfs: test xattr caching

parent 2fd32745
...@@ -28,5 +28,5 @@ func NewUnionFsFromRoots(roots []string, opts *UnionFsOptions, roCaching bool) ( ...@@ -28,5 +28,5 @@ func NewUnionFsFromRoots(roots []string, opts *UnionFsOptions, roCaching bool) (
fses = append(fses, fs) fses = append(fses, fs)
} }
return NewUnionFs(fses, *opts), nil return NewUnionFs(fses, *opts)
} }
...@@ -86,7 +86,7 @@ const ( ...@@ -86,7 +86,7 @@ const (
_DROP_CACHE = ".drop_cache" _DROP_CACHE = ".drop_cache"
) )
func NewUnionFs(fileSystems []pathfs.FileSystem, options UnionFsOptions) pathfs.FileSystem { func NewUnionFs(fileSystems []pathfs.FileSystem, options UnionFsOptions) (pathfs.FileSystem, error) {
g := &unionFS{ g := &unionFS{
options: &options, options: &options,
fileSystems: fileSystems, fileSystems: fileSystems,
...@@ -96,8 +96,7 @@ func NewUnionFs(fileSystems []pathfs.FileSystem, options UnionFsOptions) pathfs. ...@@ -96,8 +96,7 @@ func NewUnionFs(fileSystems []pathfs.FileSystem, options UnionFsOptions) pathfs.
writable := g.fileSystems[0] writable := g.fileSystems[0]
code := g.createDeletionStore() code := g.createDeletionStore()
if !code.Ok() { if !code.Ok() {
log.Printf("could not create deletion path %v: %v", options.DeletionDirName, code) return nil, fmt.Errorf("could not create deletion path %v: %v", options.DeletionDirName, code)
return nil
} }
g.deletionCache = newDirCache(writable, options.DeletionDirName, options.DeletionCacheTTL) g.deletionCache = newDirCache(writable, options.DeletionDirName, options.DeletionCacheTTL)
...@@ -110,7 +109,7 @@ func NewUnionFs(fileSystems []pathfs.FileSystem, options UnionFsOptions) pathfs. ...@@ -110,7 +109,7 @@ func NewUnionFs(fileSystems []pathfs.FileSystem, options UnionFsOptions) pathfs.
g.hiddenFiles[name] = true g.hiddenFiles[name] = true
} }
return g return g, nil
} }
func (fs *unionFS) OnMount(nodeFs *pathfs.PathNodeFs) { func (fs *unionFS) OnMount(nodeFs *pathfs.PathNodeFs) {
...@@ -707,7 +706,6 @@ func (fs *unionFS) GetXAttr(name string, attr string, context *fuse.Context) ([] ...@@ -707,7 +706,6 @@ func (fs *unionFS) GetXAttr(name string, attr string, context *fuse.Context) ([]
if name == _DROP_CACHE { if name == _DROP_CACHE {
return nil, fuse.ENODATA return nil, fuse.ENODATA
} }
r := fs.getBranch(name) r := fs.getBranch(name)
if r.branch >= 0 { if r.branch >= 0 {
return fs.fileSystems[r.branch].GetXAttr(name, attr, context) return fs.fileSystems[r.branch].GetXAttr(name, attr, context)
......
...@@ -78,8 +78,10 @@ func setupUfs(t *testing.T) (workdir string, cleanup func()) { ...@@ -78,8 +78,10 @@ func setupUfs(t *testing.T) (workdir string, cleanup func()) {
fses = append(fses, pathfs.NewLoopbackFileSystem(wd+"/rw")) fses = append(fses, pathfs.NewLoopbackFileSystem(wd+"/rw"))
fses = append(fses, fses = append(fses,
NewCachingFileSystem(pathfs.NewLoopbackFileSystem(wd+"/ro"), 0)) NewCachingFileSystem(pathfs.NewLoopbackFileSystem(wd+"/ro"), 0))
ufs := NewUnionFs(fses, testOpts) ufs, err := NewUnionFs(fses, testOpts)
if err != nil {
t.Fatalf("NewUnionFs: %v", err)
}
// We configure timeouts are smaller, so we can check for // We configure timeouts are smaller, so we can check for
// UnionFs's cache consistency. // UnionFs's cache consistency.
opts := &nodefs.Options{ opts := &nodefs.Options{
...@@ -96,6 +98,7 @@ func setupUfs(t *testing.T) (workdir string, cleanup func()) { ...@@ -96,6 +98,7 @@ func setupUfs(t *testing.T) (workdir string, cleanup func()) {
} }
conn.SetDebug(VerboseTest()) conn.SetDebug(VerboseTest())
state.SetDebug(VerboseTest()) state.SetDebug(VerboseTest())
pathfs.SetDebug(VerboseTest())
go state.Serve() go state.Serve()
return wd, func() { return wd, func() {
...@@ -1143,7 +1146,10 @@ func TestUnionFsDisappearing(t *testing.T) { ...@@ -1143,7 +1146,10 @@ func TestUnionFsDisappearing(t *testing.T) {
var fses []pathfs.FileSystem var fses []pathfs.FileSystem
fses = append(fses, pathfs.NewLockingFileSystem(wrFs)) fses = append(fses, pathfs.NewLockingFileSystem(wrFs))
fses = append(fses, pathfs.NewLoopbackFileSystem(wd+"/ro")) fses = append(fses, pathfs.NewLoopbackFileSystem(wd+"/ro"))
ufs := NewUnionFs(fses, testOpts) ufs, err := NewUnionFs(fses, testOpts)
if err != nil {
t.Fatalf("NewUnionFs: %v", err)
}
opts := &nodefs.Options{ opts := &nodefs.Options{
EntryTimeout: entryTtl, EntryTimeout: entryTtl,
......
package unionfs
import (
"io/ioutil"
"os"
"syscall"
"testing"
"time"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
"github.com/hanwen/go-fuse/fuse/pathfs"
)
type TestFS struct {
pathfs.FileSystem
xattrRead int
}
func (fs *TestFS) GetAttr(path string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
switch path {
case "":
return &fuse.Attr{Mode: fuse.S_IFDIR | 0755}, fuse.OK
case "file":
return &fuse.Attr{Mode: fuse.S_IFREG | 0755}, fuse.OK
}
return nil, fuse.ENOENT
}
func (fs *TestFS) GetXAttr(path string, name string, context *fuse.Context) ([]byte, fuse.Status) {
if path == "file" && name == "user.attr" {
fs.xattrRead++
return []byte{42}, fuse.OK
}
return nil, fuse.ENODATA
}
func TestXAttrCaching(t *testing.T) {
wd, _ := ioutil.TempDir("", "unionfs")
defer os.RemoveAll(wd)
os.Mkdir(wd+"/mnt", 0700)
err := os.Mkdir(wd+"/rw", 0700)
if err != nil {
t.Fatalf("Mkdir failed: %v", err)
}
rwFS := pathfs.NewLoopbackFileSystem(wd + "/rw")
roFS := &TestFS{
FileSystem: pathfs.NewDefaultFileSystem(),
}
ufs, err := NewUnionFs([]pathfs.FileSystem{rwFS,
NewCachingFileSystem(roFS, entryTtl)}, testOpts)
if err != nil {
t.Fatalf("NewUnionFs: %v", err)
}
opts := &nodefs.Options{
EntryTimeout: entryTtl / 2,
AttrTimeout: entryTtl / 2,
NegativeTimeout: entryTtl / 2,
}
pathfs := pathfs.NewPathNodeFs(ufs,
&pathfs.PathNodeFsOptions{ClientInodes: true})
server, conn, err := nodefs.MountFileSystem(wd+"/mnt", pathfs, opts)
if err != nil {
t.Fatalf("MountNodeFileSystem failed: %v", err)
}
server.SetDebug(VerboseTest())
conn.SetDebug(VerboseTest())
pathfs.SetDebug(VerboseTest())
defer server.Unmount()
go server.Serve()
if fi, err := os.Lstat(wd + "/mnt"); err != nil || !fi.IsDir() {
t.Fatalf("root not readable: %v, %v", err, fi)
}
buf := make([]byte, 1024)
n, err := syscall.Getxattr(wd+"/mnt/file", "user.attr", buf)
if err != nil {
t.Fatalf("Getxattr: %v", err)
}
want := "\x2a"
got := string(buf[:n])
if got != want {
t.Fatalf("Got %q want %q", got, err)
}
time.Sleep(entryTtl / 2)
n, err = syscall.Getxattr(wd+"/mnt/file", "user.attr", buf)
if err != nil {
t.Fatalf("Getxattr: %v", err)
}
got = string(buf[:n])
if got != want {
t.Fatalf("Got %q want %q", got, err)
}
server.Unmount()
if roFS.xattrRead != 1 {
t.Errorf("got xattrRead=%d, want 1", roFS.xattrRead)
}
}
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