Commit 53f16b0a authored by Jakob Unterwurzacher's avatar Jakob Unterwurzacher Committed by Han-Wen Nienhuys

fs: add TestTypeChange (simulate inode number reuse)

TestTypeChange simulates inode number reuse that happens on real
filesystems. For go-fuse, inode number reuse can look like a file changing
to a directory or vice versa. Acutally, the old inode does not exist anymore,
we just have not received the FORGET yet.

The test fails reliably with iteration count 100. Will be fixed in the
next commit.

Test failure looks like this:

	~/go/src/github.com/hanwen/go-fuse/fs$ go test -run TestTypeChange -v
	=== RUN   TestTypeChange
	21:43:36.065494 rx 2: INIT i0 {7.31 Ra 0x20000 MAX_PAGES,SPLICE_READ,FLOCK_LOCKS,READDIRPLUS,READDIRPLUS_AUTO,ASYNC_DIO,WRITEBACK_CACHE,HANDLE_KILLPRIV,SPLICE_WRITE,PARALLEL_DIROPS,ABORT_ERROR,EXPLICIT_INVAL_DATA,NO_OPENDIR_SUPPORT,ASYNC_READ,BIG_WRITES,DONT_MASK,IOCTL_DIR,AUTO_INVAL_DATA,POSIX_ACL,CACHE_SYMLINKS,POSIX_LOCKS,ATOMIC_O_TRUNC,EXPORT_SUPPORT,SPLICE_MOVE,NO_OPEN_SUPPORT}
	21:43:36.065573 tx 2:     OK, {7.28 Ra 0x20000 PARALLEL_DIROPS,AUTO_INVAL_DATA,ASYNC_READ,BIG_WRITES,NO_OPEN_SUPPORT,READDIRPLUS 0/0 Wr 0x10000 Tg 0x0}
	21:43:36.065742 rx 4: LOOKUP i1 [".go-fuse-epoll-hack"] 20b
	21:43:36.065798 tx 4:     2=no such file or directory, {i0 g0 tE=0s tA=0s {M00 SZ=0 L=0 0:0 B0*0 i0:0 A 0.000000 M 0.000000 C 0.000000}}
	21:43:36.065837 rx 6: CREATE i1 {0100100 [WRONLY,CREAT,TRUNC,0x8000] (00)} [".go-fuse-epoll-hack"] 20b
	21:43:36.065861 tx 6:     OK, {i18446744073709551615 g0 {M0100644 SZ=0 L=1 0:0 B0*0 i0:18446744073709551615 A 0.000000 M 0.000000 C 0.000000} &{18446744073709551615 0 0}}
	21:43:36.065945 rx 8: POLL i18446744073709551615
	21:43:36.065954 tx 8:     38=function not implemented
	21:43:36.066009 rx 10: FLUSH i18446744073709551615 {Fh 18446744073709551615}
	21:43:36.066046 tx 10:     5=input/output error
	21:43:36.066065 rx 12: RELEASE i18446744073709551615 {Fh 18446744073709551615 WRONLY,0x8000  L0}
	21:43:36.066071 tx 12:     5=input/output error
	21:43:36.066107 rx 14: LOOKUP i1 ["file"] 5b
	21:43:36.066181 tx 14:     OK, {i1234 g0 tE=0s tA=0s {M0100644 SZ=0 L=0 0:0 B0*4096 i0:1234 A 0.000000 M 0.000000 C 0.000000}}
	21:43:36.066217 rx 16: GETATTR i1234 {Fh 0}
	21:43:36.066240 tx 16:     OK, {tA=0s {M0100644 SZ=0 L=0 0:0 B0*4096 i0:1234 A 0.000000 M 0.000000 C 0.000000}}
	21:43:36.066264 rx 18: LOOKUP i1 ["file"] 5b
	21:43:36.066285 tx 18:     OK, {i1234 g0 tE=0s tA=0s {M0100644 SZ=0 L=0 0:0 B0*4096 i0:1234 A 0.000000 M 0.000000 C 0.000000}}
	21:43:36.066301 rx 20: UNLINK i1 ["file"] 5b
	21:43:36.066321 tx 20:     OK
	21:43:36.066361 rx 24: LOOKUP i1 ["dir"] 4b
	21:43:36.066371 tx 24:     OK, {i1234 g0 tE=0s tA=0s {M0100644 SZ=0 L=0 0:0 B0*4096 i0:1234 A 0.000000 M 0.000000 C 0.000000}}
	21:43:36.066383 rx 22: FORGET i1234 {Nlookup=2}
	21:43:36.066390 rx 26: GETATTR i1234 {Fh 0}
	21:43:36.068259 tx 26:     OK, {tA=0s {M0100644 SZ=0 L=0 0:0 B0*4096 i0:1234 A 0.000000 M 0.000000 C 0.000000}}
	21:43:36.069664 received ENODEV (unmount request), thread exiting
	21:43:36.073309 received ENODEV (unmount request), thread exiting
	21:43:36.073396 received ENODEV (unmount request), thread exiting
	--- FAIL: TestTypeChange (0.01s)
	    bridge_test.go:96: should be a dir now
	FAIL
	exit status 1
	FAIL	github.com/hanwen/go-fuse/v2/fs	0.017s

Change-Id: I7a1a10303ecc0a8c008d29d5d81079868fc2cc43
parent 68f70527
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
package fs package fs
import ( import (
"context"
"os"
"syscall"
"testing" "testing"
"unsafe" "unsafe"
...@@ -75,3 +78,47 @@ func TestBridgeReaddirPlusVirtualEntries(t *testing.T) { ...@@ -75,3 +78,47 @@ func TestBridgeReaddirPlusVirtualEntries(t *testing.T) {
t.Errorf("entry2 NodeId should be 0, but is %d", entry2.NodeId) t.Errorf("entry2 NodeId should be 0, but is %d", entry2.NodeId)
} }
} }
// TestTypeChange simulates inode number reuse that happens on real
// filesystems. For go-fuse, inode number reuse can look like a file changing
// to a directory or vice versa. Acutally, the old inode does not exist anymore,
// we just have not received the FORGET yet.
func TestTypeChange(t *testing.T) {
rootNode := testTypeChangeIno{}
mnt, _, clean := testMount(t, &rootNode, nil)
defer clean()
for i := 0; i < 100; i++ {
fi, _ := os.Stat(mnt + "/file")
syscall.Unlink(mnt + "/file")
fi, _ = os.Stat(mnt + "/dir")
if !fi.IsDir() {
t.Fatal("should be a dir now")
}
syscall.Rmdir(mnt + "/dir")
fi, _ = os.Stat(mnt + "/file")
if fi.IsDir() {
t.Fatal("should be a file now")
}
}
}
type testTypeChangeIno struct {
Inode
}
// Lookup function for TestTypeChange: if name == "dir", returns a node of
// type dir, otherwise of type file.
func (fn *testTypeChangeIno) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*Inode, syscall.Errno) {
mode := uint32(fuse.S_IFREG)
if name == "dir" {
mode = fuse.S_IFDIR
}
stable := StableAttr{
Mode: mode,
Ino: 1234,
}
childFN := &testTypeChangeIno{}
child := fn.NewInode(ctx, childFN, stable)
return child, syscall.F_OK
}
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