Commit 9abf7b8e authored by Kirill Smelkov's avatar Kirill Smelkov

Merge remote-tracking branch 'origin/master' into t

* origin/master:
  nodefs: add Inode.IsRoot
  newunionfs: hide DELETIONS
  nodefs: fix style in doReadDir
  newunionfs: implement Readdir
  nodefs: suppress verbose output for some tests
  fuse: add FOPEN_CACHE_DIR to print registry
  newunionfs: disable umask
  nodefs: disable umask in tests
  nodefs: more renaming
parents 55370734 467f4e06
...@@ -37,6 +37,31 @@ type unionFSNode struct { ...@@ -37,6 +37,31 @@ type unionFSNode struct {
const delDir = "DELETIONS" const delDir = "DELETIONS"
var delDirHash = filePathHash(delDir)
func (r *unionFSRoot) allMarkers(result map[string]struct{}) syscall.Errno {
dir := filepath.Join(r.roots[0], delDir)
ds, errno := nodefs.NewLoopbackDirStream(dir)
if errno != 0 {
return errno
}
defer ds.Close()
for ds.HasNext() {
e, errno := ds.Next()
if errno != 0 {
return errno
}
if e.Mode != syscall.S_IFREG {
continue
}
result[e.Name] = struct{}{}
}
return 0
}
func (r *unionFSRoot) rmMarker(name string) syscall.Errno { func (r *unionFSRoot) rmMarker(name string) syscall.Errno {
err := syscall.Unlink(r.markerPath(name)) err := syscall.Unlink(r.markerPath(name))
if err != nil { if err != nil {
...@@ -161,6 +186,10 @@ func (n *unionFSNode) Setattr(ctx context.Context, fh nodefs.FileHandle, in *fus ...@@ -161,6 +186,10 @@ func (n *unionFSNode) Setattr(ctx context.Context, fh nodefs.FileHandle, in *fus
var _ = (nodefs.Creater)((*unionFSNode)(nil)) var _ = (nodefs.Creater)((*unionFSNode)(nil))
func (n *unionFSNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (*nodefs.Inode, nodefs.FileHandle, uint32, syscall.Errno) { func (n *unionFSNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (*nodefs.Inode, nodefs.FileHandle, uint32, syscall.Errno) {
if n.IsRoot() && name == delDir {
return nil, nil, 0, syscall.EPERM
}
var st syscall.Stat_t var st syscall.Stat_t
dirName, idx := n.getBranch(&st) dirName, idx := n.getBranch(&st)
if idx > 0 { if idx > 0 {
...@@ -232,6 +261,10 @@ func (n *unionFSNode) Getattr(ctx context.Context, fh nodefs.FileHandle, out *fu ...@@ -232,6 +261,10 @@ func (n *unionFSNode) Getattr(ctx context.Context, fh nodefs.FileHandle, out *fu
var _ = (nodefs.Lookuper)((*unionFSNode)(nil)) var _ = (nodefs.Lookuper)((*unionFSNode)(nil))
func (n *unionFSNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*nodefs.Inode, syscall.Errno) { func (n *unionFSNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*nodefs.Inode, syscall.Errno) {
if n.IsRoot() && name == delDir {
return nil, syscall.ENOENT
}
var st syscall.Stat_t var st syscall.Stat_t
p := filepath.Join(n.Path(nil), name) p := filepath.Join(n.Path(nil), name)
...@@ -297,6 +330,53 @@ func (n *unionFSNode) Readlink(ctx context.Context) ([]byte, syscall.Errno) { ...@@ -297,6 +330,53 @@ func (n *unionFSNode) Readlink(ctx context.Context) ([]byte, syscall.Errno) {
return buf[:count], 0 return buf[:count], 0
} }
var _ = (nodefs.Readdirer)((*unionFSNode)(nil))
func (n *unionFSNode) Readdir(ctx context.Context) (nodefs.DirStream, syscall.Errno) {
root := n.root()
markers := map[string]struct{}{delDirHash: struct{}{}}
// ignore error: assume no markers
root.allMarkers(markers)
dir := n.Path(nil)
names := map[string]uint32{}
for i := range root.roots {
// deepest root first.
readRoot(root.roots[len(root.roots)-i-1], dir, names)
}
result := make([]fuse.DirEntry, 0, len(names))
for nm, mode := range names {
marker := filePathHash(filepath.Join(dir, nm))
if _, ok := markers[marker]; ok {
continue
}
result = append(result, fuse.DirEntry{
Name: nm,
Mode: mode,
})
}
return nodefs.NewListDirStream(result), 0
}
func readRoot(root string, dir string, result map[string]uint32) {
ds, errno := nodefs.NewLoopbackDirStream(filepath.Join(root, dir))
if errno != 0 {
return
}
defer ds.Close()
for ds.HasNext() {
e, errno := ds.Next()
if errno != 0 {
return
}
result[e.Name] = e.Mode
}
}
// getBranch returns the root where we can find the given file. It // getBranch returns the root where we can find the given file. It
// will check the deletion markers in roots[0]. // will check the deletion markers in roots[0].
func (n *unionFSNode) getBranch(st *syscall.Stat_t) (string, int) { func (n *unionFSNode) getBranch(st *syscall.Stat_t) (string, int) {
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"syscall" "syscall"
"testing" "testing"
...@@ -131,6 +132,15 @@ func TestDeleteMarker(t *testing.T) { ...@@ -131,6 +132,15 @@ func TestDeleteMarker(t *testing.T) {
} }
} }
func TestCreateDeletions(t *testing.T) {
tc := newTestCase(t, true)
defer tc.Clean()
if _, err := syscall.Creat(filepath.Join(tc.mnt, delDir), 0644); err != syscall.EPERM {
t.Fatalf("got err %v, want EPERM", err)
}
}
func TestCreate(t *testing.T) { func TestCreate(t *testing.T) {
tc := newTestCase(t, true) tc := newTestCase(t, true)
defer tc.Clean() defer tc.Clean()
...@@ -196,6 +206,70 @@ func TestDeleteRevert(t *testing.T) { ...@@ -196,6 +206,70 @@ func TestDeleteRevert(t *testing.T) {
} }
} }
func TestReaddirRoot(t *testing.T) {
tc := newTestCase(t, true)
defer tc.Clean()
if err := os.Remove(tc.mnt + "/dir/ro-file"); err != nil {
t.Fatalf("Remove: %v", err)
}
f, err := os.Open(tc.mnt)
if err != nil {
t.Fatalf("Open: %v", err)
}
defer f.Close()
names, err := f.Readdirnames(-1)
if err != nil {
t.Fatalf("Readdirnames: %v", err)
}
got := map[string]bool{}
want := map[string]bool{"dir": true}
for _, nm := range names {
got[nm] = true
}
if !reflect.DeepEqual(want, got) {
t.Errorf("got %v want %v", got, want)
}
}
func TestReaddir(t *testing.T) {
tc := newTestCase(t, true)
defer tc.Clean()
if err := ioutil.WriteFile(tc.ro+"/dir/file2", nil, 0644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
if err := os.Mkdir(tc.rw+"/dir", 0755); err != nil {
t.Fatalf("Mkdir: %v", err)
}
if err := ioutil.WriteFile(tc.rw+"/dir/file3", nil, 0644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
if err := os.Remove(tc.mnt + "/dir/ro-file"); err != nil {
t.Fatalf("Remove: %v", err)
}
res, err := ioutil.ReadDir(tc.mnt + "/dir")
if err != nil {
t.Fatalf("ReadDir: %v", err)
}
got := map[string]bool{}
want := map[string]bool{
"file2": true,
"file3": true,
}
for _, fi := range res {
got[fi.Name()] = true
}
if !reflect.DeepEqual(want, got) {
t.Errorf("got %v want %v", got, want)
}
}
func TestPosix(t *testing.T) { func TestPosix(t *testing.T) {
cases := []string{ cases := []string{
"SymlinkReadlink", "SymlinkReadlink",
...@@ -207,7 +281,7 @@ func TestPosix(t *testing.T) { ...@@ -207,7 +281,7 @@ func TestPosix(t *testing.T) {
// "NlinkZero", // "NlinkZero",
"ParallelFileOpen", "ParallelFileOpen",
// "Link", // "Link",
// "ReadDir", "ReadDir",
} }
for _, nm := range cases { for _, nm := range cases {
...@@ -220,3 +294,7 @@ func TestPosix(t *testing.T) { ...@@ -220,3 +294,7 @@ func TestPosix(t *testing.T) {
}) })
} }
} }
func init() {
syscall.Umask(0)
}
...@@ -126,9 +126,9 @@ func (b *rawBridge) addNewChild(parent *Inode, name string, child *Inode, file F ...@@ -126,9 +126,9 @@ func (b *rawBridge) addNewChild(parent *Inode, name string, child *Inode, file F
fh = b.registerFile(child, file, fileFlags) fh = b.registerFile(child, file, fileFlags)
} }
out.NodeId = child.nodeAttr.Ino out.NodeId = child.stableAttr.Ino
out.Generation = child.nodeAttr.Gen out.Generation = child.stableAttr.Gen
out.Attr.Ino = child.nodeAttr.Ino out.Attr.Ino = child.stableAttr.Ino
b.mu.Unlock() b.mu.Unlock()
unlockNodes(parent, child) unlockNodes(parent, child)
...@@ -406,8 +406,8 @@ func (b *rawBridge) getattr(ctx context.Context, n *Inode, f FileHandle, out *fu ...@@ -406,8 +406,8 @@ func (b *rawBridge) getattr(ctx context.Context, n *Inode, f FileHandle, out *fu
} }
if errno == 0 { if errno == 0 {
out.Ino = n.nodeAttr.Ino out.Ino = n.stableAttr.Ino
out.Mode = (out.Attr.Mode & 07777) | n.nodeAttr.Mode out.Mode = (out.Attr.Mode & 07777) | n.stableAttr.Mode
b.setAttr(&out.Attr) b.setAttr(&out.Attr)
b.setAttrTimeout(out) b.setAttrTimeout(out)
} }
...@@ -786,18 +786,17 @@ func (b *rawBridge) setStream(cancel <-chan struct{}, input *fuse.ReadIn, inode ...@@ -786,18 +786,17 @@ func (b *rawBridge) setStream(cancel <-chan struct{}, input *fuse.ReadIn, inode
} }
func (b *rawBridge) getStream(ctx context.Context, inode *Inode) (DirStream, syscall.Errno) { func (b *rawBridge) getStream(ctx context.Context, inode *Inode) (DirStream, syscall.Errno) {
rd, ok := inode.ops.(Readdirer) if rd, ok := inode.ops.(Readdirer); ok {
if !ok { return rd.Readdir(ctx)
r := []fuse.DirEntry{}
for k, ch := range inode.Children() {
r = append(r, fuse.DirEntry{Mode: ch.Mode(),
Name: k,
Ino: ch.StableAttr().Ino})
}
return NewListDirStream(r), 0
} }
return rd.Readdir(ctx) r := []fuse.DirEntry{}
for k, ch := range inode.Children() {
r = append(r, fuse.DirEntry{Mode: ch.Mode(),
Name: k,
Ino: ch.StableAttr().Ino})
}
return NewListDirStream(r), 0
} }
func (b *rawBridge) ReadDir(cancel <-chan struct{}, input *fuse.ReadIn, out *fuse.DirEntryList) fuse.Status { func (b *rawBridge) ReadDir(cancel <-chan struct{}, input *fuse.ReadIn, out *fuse.DirEntryList) fuse.Status {
...@@ -872,12 +871,12 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out ...@@ -872,12 +871,12 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out
b.addNewChild(n, e.Name, child, nil, 0, entryOut) b.addNewChild(n, e.Name, child, nil, 0, entryOut)
child.setEntryOut(entryOut) child.setEntryOut(entryOut)
b.setEntryOutTimeout(entryOut) b.setEntryOutTimeout(entryOut)
if (e.Mode &^ 07777) != (child.nodeAttr.Mode &^ 07777) { if (e.Mode &^ 07777) != (child.stableAttr.Mode &^ 07777) {
// should go back and change the // should go back and change the
// already serialized entry // already serialized entry
log.Panicf("mode mismatch between readdir %o and lookup %o", e.Mode, child.nodeAttr.Mode) log.Panicf("mode mismatch between readdir %o and lookup %o", e.Mode, child.stableAttr.Mode)
} }
entryOut.Mode = child.nodeAttr.Mode | (entryOut.Mode & 07777) entryOut.Mode = child.stableAttr.Mode | (entryOut.Mode & 07777)
} }
} }
......
...@@ -57,7 +57,7 @@ func (i *StableAttr) Reserved() bool { ...@@ -57,7 +57,7 @@ func (i *StableAttr) Reserved() bool {
// copied. Inodes should be obtained by calling Inode.NewInode() or // copied. Inodes should be obtained by calling Inode.NewInode() or
// Inode.NewPersistentInode(). // Inode.NewPersistentInode().
type Inode struct { type Inode struct {
nodeAttr StableAttr stableAttr StableAttr
ops InodeEmbedder ops InodeEmbedder
bridge *rawBridge bridge *rawBridge
...@@ -97,7 +97,7 @@ type Inode struct { ...@@ -97,7 +97,7 @@ type Inode struct {
} }
func (n *Inode) IsDir() bool { func (n *Inode) IsDir() bool {
return n.nodeAttr.Mode&syscall.S_IFDIR != 0 return n.stableAttr.Mode&syscall.S_IFDIR != 0
} }
func (n *Inode) embed() *Inode { func (n *Inode) embed() *Inode {
...@@ -110,7 +110,7 @@ func (n *Inode) EmbeddedInode() *Inode { ...@@ -110,7 +110,7 @@ func (n *Inode) EmbeddedInode() *Inode {
func initInode(n *Inode, ops InodeEmbedder, attr StableAttr, bridge *rawBridge, persistent bool) { func initInode(n *Inode, ops InodeEmbedder, attr StableAttr, bridge *rawBridge, persistent bool) {
n.ops = ops n.ops = ops
n.nodeAttr = attr n.stableAttr = attr
n.bridge = bridge n.bridge = bridge
n.persistent = persistent n.persistent = persistent
n.parents = make(map[parentData]struct{}) n.parents = make(map[parentData]struct{})
...@@ -121,19 +121,19 @@ func initInode(n *Inode, ops InodeEmbedder, attr StableAttr, bridge *rawBridge, ...@@ -121,19 +121,19 @@ func initInode(n *Inode, ops InodeEmbedder, attr StableAttr, bridge *rawBridge,
// Set node ID and mode in EntryOut // Set node ID and mode in EntryOut
func (n *Inode) setEntryOut(out *fuse.EntryOut) { func (n *Inode) setEntryOut(out *fuse.EntryOut) {
out.NodeId = n.nodeAttr.Ino out.NodeId = n.stableAttr.Ino
out.Ino = n.nodeAttr.Ino out.Ino = n.stableAttr.Ino
out.Mode = (out.Attr.Mode & 07777) | n.nodeAttr.Mode out.Mode = (out.Attr.Mode & 07777) | n.stableAttr.Mode
} }
// StableAttr returns the (Ino, Gen) tuple for this node. // StableAttr returns the (Ino, Gen) tuple for this node.
func (n *Inode) StableAttr() StableAttr { func (n *Inode) StableAttr() StableAttr {
return n.nodeAttr return n.stableAttr
} }
// Mode returns the filetype // Mode returns the filetype
func (n *Inode) Mode() uint32 { func (n *Inode) Mode() uint32 {
return n.nodeAttr.Mode return n.stableAttr.Mode
} }
// Returns the root of the tree // Returns the root of the tree
...@@ -141,6 +141,11 @@ func (n *Inode) Root() *Inode { ...@@ -141,6 +141,11 @@ func (n *Inode) Root() *Inode {
return n.bridge.root return n.bridge.root
} }
// Returns whether this is the root of the tree
func (n *Inode) IsRoot() bool {
return n.bridge.root == n
}
func modeStr(m uint32) string { func modeStr(m uint32) string {
return map[uint32]string{ return map[uint32]string{
syscall.S_IFREG: "reg", syscall.S_IFREG: "reg",
...@@ -159,10 +164,10 @@ func (n *Inode) String() string { ...@@ -159,10 +164,10 @@ func (n *Inode) String() string {
defer n.mu.Unlock() defer n.mu.Unlock()
var ss []string var ss []string
for nm, ch := range n.children { for nm, ch := range n.children {
ss = append(ss, fmt.Sprintf("%q=%d[%s]", nm, ch.nodeAttr.Ino, modeStr(ch.nodeAttr.Mode))) ss = append(ss, fmt.Sprintf("%q=%d[%s]", nm, ch.stableAttr.Ino, modeStr(ch.stableAttr.Mode)))
} }
return fmt.Sprintf("%d[%s]: %s", n.nodeAttr.Ino, modeStr(n.nodeAttr.Mode), strings.Join(ss, ",")) return fmt.Sprintf("%d[%s]: %s", n.stableAttr.Ino, modeStr(n.stableAttr.Mode), strings.Join(ss, ","))
} }
// sortNodes rearranges inode group in consistent order. // sortNodes rearranges inode group in consistent order.
...@@ -391,7 +396,7 @@ retry: ...@@ -391,7 +396,7 @@ retry:
} }
n.bridge.mu.Lock() n.bridge.mu.Lock()
delete(n.bridge.nodes, n.nodeAttr.Ino) delete(n.bridge.nodes, n.stableAttr.Ino)
n.bridge.mu.Unlock() n.bridge.mu.Unlock()
unlockNodes(lockme...) unlockNodes(lockme...)
...@@ -686,7 +691,7 @@ retry: ...@@ -686,7 +691,7 @@ retry:
// tuple should be invalidated. On next access, a LOOKUP operation // tuple should be invalidated. On next access, a LOOKUP operation
// will be started. // will be started.
func (n *Inode) NotifyEntry(name string) syscall.Errno { func (n *Inode) NotifyEntry(name string) syscall.Errno {
status := n.bridge.server.EntryNotify(n.nodeAttr.Ino, name) status := n.bridge.server.EntryNotify(n.stableAttr.Ino, name)
return syscall.Errno(status) return syscall.Errno(status)
} }
...@@ -695,7 +700,7 @@ func (n *Inode) NotifyEntry(name string) syscall.Errno { ...@@ -695,7 +700,7 @@ func (n *Inode) NotifyEntry(name string) syscall.Errno {
// to NotifyEntry, but also sends an event to inotify watchers. // to NotifyEntry, but also sends an event to inotify watchers.
func (n *Inode) NotifyDelete(name string, child *Inode) syscall.Errno { func (n *Inode) NotifyDelete(name string, child *Inode) syscall.Errno {
// XXX arg ordering? // XXX arg ordering?
return syscall.Errno(n.bridge.server.DeleteNotify(n.nodeAttr.Ino, child.nodeAttr.Ino, name)) return syscall.Errno(n.bridge.server.DeleteNotify(n.stableAttr.Ino, child.stableAttr.Ino, name))
} }
...@@ -703,16 +708,16 @@ func (n *Inode) NotifyDelete(name string, child *Inode) syscall.Errno { ...@@ -703,16 +708,16 @@ func (n *Inode) NotifyDelete(name string, child *Inode) syscall.Errno {
// inode should be flushed from buffers. // inode should be flushed from buffers.
func (n *Inode) NotifyContent(off, sz int64) syscall.Errno { func (n *Inode) NotifyContent(off, sz int64) syscall.Errno {
// XXX how does this work for directories? // XXX how does this work for directories?
return syscall.Errno(n.bridge.server.InodeNotify(n.nodeAttr.Ino, off, sz)) return syscall.Errno(n.bridge.server.InodeNotify(n.stableAttr.Ino, off, sz))
} }
// WriteCache stores data in the kernel cache. // WriteCache stores data in the kernel cache.
func (n *Inode) WriteCache(offset int64, data []byte) syscall.Errno { func (n *Inode) WriteCache(offset int64, data []byte) syscall.Errno {
return syscall.Errno(n.bridge.server.InodeNotifyStoreCache(n.nodeAttr.Ino, offset, data)) return syscall.Errno(n.bridge.server.InodeNotifyStoreCache(n.stableAttr.Ino, offset, data))
} }
// ReadCache reads data from the kernel cache. // ReadCache reads data from the kernel cache.
func (n *Inode) ReadCache(offset int64, dest []byte) (count int, errno syscall.Errno) { func (n *Inode) ReadCache(offset int64, dest []byte) (count int, errno syscall.Errno) {
c, s := n.bridge.server.InodeRetrieveCache(n.nodeAttr.Ino, offset, dest) c, s := n.bridge.server.InodeRetrieveCache(n.stableAttr.Ino, offset, dest)
return c, syscall.Errno(s) return c, syscall.Errno(s)
} }
...@@ -17,7 +17,7 @@ import ( ...@@ -17,7 +17,7 @@ import (
) )
func TestRenameExchange(t *testing.T) { func TestRenameExchange(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
if err := os.Mkdir(tc.origDir+"/dir", 0755); err != nil { if err := os.Mkdir(tc.origDir+"/dir", 0755); err != nil {
...@@ -74,7 +74,7 @@ func TestRenameExchange(t *testing.T) { ...@@ -74,7 +74,7 @@ func TestRenameExchange(t *testing.T) {
} }
func TestRenameNoOverwrite(t *testing.T) { func TestRenameNoOverwrite(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
if err := os.Mkdir(tc.origDir+"/dir", 0755); err != nil { if err := os.Mkdir(tc.origDir+"/dir", 0755); err != nil {
...@@ -102,7 +102,7 @@ func TestRenameNoOverwrite(t *testing.T) { ...@@ -102,7 +102,7 @@ func TestRenameNoOverwrite(t *testing.T) {
} }
func TestXAttr(t *testing.T) { func TestXAttr(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
tc.writeOrig("file", "", 0644) tc.writeOrig("file", "", 0644)
...@@ -137,7 +137,7 @@ func TestXAttr(t *testing.T) { ...@@ -137,7 +137,7 @@ func TestXAttr(t *testing.T) {
} }
func TestCopyFileRange(t *testing.T) { func TestCopyFileRange(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
if !tc.server.KernelSettings().SupportsVersion(7, 28) { if !tc.server.KernelSettings().SupportsVersion(7, 28) {
......
...@@ -47,7 +47,16 @@ func (tc *testCase) Clean() { ...@@ -47,7 +47,16 @@ func (tc *testCase) Clean() {
} }
} }
func newTestCase(t *testing.T, entryCache bool, attrCache bool) *testCase { type testOptions struct {
entryCache bool
attrCache bool
suppressDebug bool
}
func newTestCase(t *testing.T, opts *testOptions) *testCase {
if opts == nil {
opts = &testOptions{}
}
tc := &testCase{ tc := &testCase{
dir: testutil.TempDir(), dir: testutil.TempDir(),
T: t, T: t,
...@@ -70,11 +79,11 @@ func newTestCase(t *testing.T, entryCache bool, attrCache bool) *testCase { ...@@ -70,11 +79,11 @@ func newTestCase(t *testing.T, entryCache bool, attrCache bool) *testCase {
oneSec := time.Second oneSec := time.Second
attrDT := &oneSec attrDT := &oneSec
if !attrCache { if !opts.attrCache {
attrDT = nil attrDT = nil
} }
entryDT := &oneSec entryDT := &oneSec
if !entryCache { if !opts.entryCache {
entryDT = nil entryDT = nil
} }
tc.rawFS = NewNodeFS(tc.loopback, &Options{ tc.rawFS = NewNodeFS(tc.loopback, &Options{
...@@ -82,10 +91,11 @@ func newTestCase(t *testing.T, entryCache bool, attrCache bool) *testCase { ...@@ -82,10 +91,11 @@ func newTestCase(t *testing.T, entryCache bool, attrCache bool) *testCase {
AttrTimeout: attrDT, AttrTimeout: attrDT,
}) })
tc.server, err = fuse.NewServer(tc.rawFS, tc.mntDir, mOpts := &fuse.MountOptions{}
&fuse.MountOptions{ if !opts.suppressDebug {
Debug: testutil.VerboseTest(), mOpts.Debug = testutil.VerboseTest()
}) }
tc.server, err = fuse.NewServer(tc.rawFS, tc.mntDir, mOpts)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -98,7 +108,7 @@ func newTestCase(t *testing.T, entryCache bool, attrCache bool) *testCase { ...@@ -98,7 +108,7 @@ func newTestCase(t *testing.T, entryCache bool, attrCache bool) *testCase {
} }
func TestBasic(t *testing.T) { func TestBasic(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
tc.writeOrig("file", "hello", 0644) tc.writeOrig("file", "hello", 0644)
...@@ -128,21 +138,25 @@ func TestBasic(t *testing.T) { ...@@ -128,21 +138,25 @@ func TestBasic(t *testing.T) {
} }
func TestFileBasic(t *testing.T) { func TestFileBasic(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
posixtest.FileBasic(t, tc.mntDir) posixtest.FileBasic(t, tc.mntDir)
} }
func TestFileTruncate(t *testing.T) { func TestFileTruncate(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
posixtest.TruncateFile(t, tc.mntDir) posixtest.TruncateFile(t, tc.mntDir)
} }
func TestFileFdLeak(t *testing.T) { func TestFileFdLeak(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{
suppressDebug: true,
attrCache: true,
entryCache: true,
})
defer func() { defer func() {
if tc != nil { if tc != nil {
tc.Clean() tc.Clean()
...@@ -161,14 +175,14 @@ func TestFileFdLeak(t *testing.T) { ...@@ -161,14 +175,14 @@ func TestFileFdLeak(t *testing.T) {
} }
func TestMkdir(t *testing.T) { func TestMkdir(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
posixtest.MkdirRmdir(t, tc.mntDir) posixtest.MkdirRmdir(t, tc.mntDir)
} }
func testRenameOverwrite(t *testing.T, destExists bool) { func testRenameOverwrite(t *testing.T, destExists bool) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
posixtest.RenameOverwrite(t, tc.mntDir, destExists) posixtest.RenameOverwrite(t, tc.mntDir, destExists)
} }
...@@ -183,35 +197,35 @@ func TestRenameDestNoExist(t *testing.T) { ...@@ -183,35 +197,35 @@ func TestRenameDestNoExist(t *testing.T) {
func TestNlinkZero(t *testing.T) { func TestNlinkZero(t *testing.T) {
// xfstest generic/035. // xfstest generic/035.
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
posixtest.NlinkZero(t, tc.mntDir) posixtest.NlinkZero(t, tc.mntDir)
} }
func TestParallelFileOpen(t *testing.T) { func TestParallelFileOpen(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{suppressDebug: true, attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
posixtest.ParallelFileOpen(t, tc.mntDir) posixtest.ParallelFileOpen(t, tc.mntDir)
} }
func TestSymlink(t *testing.T) { func TestSymlink(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
posixtest.SymlinkReadlink(t, tc.mntDir) posixtest.SymlinkReadlink(t, tc.mntDir)
} }
func TestLink(t *testing.T) { func TestLink(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
posixtest.Link(t, tc.mntDir) posixtest.Link(t, tc.mntDir)
} }
func TestNotifyEntry(t *testing.T) { func TestNotifyEntry(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
orig := tc.origDir + "/file" orig := tc.origDir + "/file"
...@@ -244,14 +258,18 @@ func TestNotifyEntry(t *testing.T) { ...@@ -244,14 +258,18 @@ func TestNotifyEntry(t *testing.T) {
} }
func TestReadDir(t *testing.T) { func TestReadDir(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{
suppressDebug: true,
attrCache: true,
entryCache: true,
})
defer tc.Clean() defer tc.Clean()
posixtest.ReadDir(t, tc.mntDir) posixtest.ReadDir(t, tc.mntDir)
} }
func TestReadDirStress(t *testing.T) { func TestReadDirStress(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{suppressDebug: true, attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
// (ab)use posixtest.ReadDir to create 110 test files // (ab)use posixtest.ReadDir to create 110 test files
posixtest.ReadDir(t, tc.mntDir) posixtest.ReadDir(t, tc.mntDir)
...@@ -286,7 +304,7 @@ func TestReadDirStress(t *testing.T) { ...@@ -286,7 +304,7 @@ func TestReadDirStress(t *testing.T) {
// This test is racy. If an external process consumes space while this // This test is racy. If an external process consumes space while this
// runs, we may see spurious differences between the two statfs() calls. // runs, we may see spurious differences between the two statfs() calls.
func TestStatFs(t *testing.T) { func TestStatFs(t *testing.T) {
tc := newTestCase(t, true, true) tc := newTestCase(t, &testOptions{attrCache: true, entryCache: true})
defer tc.Clean() defer tc.Clean()
empty := syscall.Statfs_t{} empty := syscall.Statfs_t{}
...@@ -314,7 +332,7 @@ func TestGetAttrParallel(t *testing.T) { ...@@ -314,7 +332,7 @@ func TestGetAttrParallel(t *testing.T) {
// can be handled correctly. Here, test that closing and // can be handled correctly. Here, test that closing and
// (f)stat in parallel don't lead to fstat on closed files. // (f)stat in parallel don't lead to fstat on closed files.
// We can only test that if we switch off caching // We can only test that if we switch off caching
tc := newTestCase(t, false, false) tc := newTestCase(t, &testOptions{suppressDebug: true})
defer tc.Clean() defer tc.Clean()
N := 100 N := 100
...@@ -355,7 +373,7 @@ func TestGetAttrParallel(t *testing.T) { ...@@ -355,7 +373,7 @@ func TestGetAttrParallel(t *testing.T) {
} }
func TestMknod(t *testing.T) { func TestMknod(t *testing.T) {
tc := newTestCase(t, false, false) tc := newTestCase(t, &testOptions{})
defer tc.Clean() defer tc.Clean()
modes := map[string]uint32{ modes := map[string]uint32{
...@@ -390,8 +408,12 @@ func TestMknod(t *testing.T) { ...@@ -390,8 +408,12 @@ func TestMknod(t *testing.T) {
} }
func TestTruncate(t *testing.T) { func TestTruncate(t *testing.T) {
tc := newTestCase(t, false, false) tc := newTestCase(t, &testOptions{})
defer tc.Clean() defer tc.Clean()
posixtest.TruncateNoFile(t, tc.mntDir) posixtest.TruncateNoFile(t, tc.mntDir)
} }
func init() {
syscall.Umask(0)
}
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