hanwen / go-fuse Goto Github PK
View Code? Open in Web Editor NEWFUSE bindings for Go
License: Other
FUSE bindings for Go
License: Other
Hello.
I'm try to build small fs and i need SetAttr, but go-fuse has only SetXAttr =(
Can it possible to add this method?
The license is confusing:
$ git grep -F Copyright
LICENSE:// Copyright (c) 2010 Ivan Krasin ([email protected]). All rights reserved.
fuse/mount_darwin.go:// Copyright 2011 The Go Authors. All rights reserved.
fuse/mount_darwin.go:// Copyright (c) 2006 Russ Cox
Hi,
I've mounted NFS Share directly at ('/mnt/servers/1' without fuse layer) and did some tests using 'nfs4_setfacl'; they does replicate ACLs to backend NFS Shares. see attached test_result.png for details:
But when mounted NFS Share through a (golang fuse layer project) at '/mnt/storage/1' and then tried some tests using 'nfs4_setfacl'; I get error like: "Operation to set ACL not supported."
Note: My golang project mounts NFS directly using system 'mount' command and then runs 'go-fuse/NewLoopbackFileSystem' on it and passes through to back-end NFS servers. All works well except I can't run 'nfs4_setfacl' command on NFS Share mounted using 'Loopback file system'.
So my question is; is this allowed to set ACL to remote NFS Shares or I've to explicitly execute such commands directly on NFS Share mounted in a normal way; like I did manually in step 1.
Or I mean; I've to automate step 1 from within fuse project when I get ACL change request?
Many thanks for your help!
In Rmdir
do we want to return ENOTEMPTY
if the directory is not empty? If so, no such const in this library. Is this an omission or I am missing something?
The current workaround is to do return fuse.Status(syscall.ENOTEMPTY)
but it feels a bit wrong.
I am trying to write to a fuse filesystem mounted using pathFS. From what I have seen till now, Open() callback is being called for reading as well as writing. However how is the input data buffer coming in case for write to Open() callback of PathFS .
It is possible to know whether the callback is for read or write using the flags in Open's parameters but I cannot find the buffer which has the data inputted by the user.
Any help is appreciated.
When builiding go-mtpfs I am receiving this error:
go/src/github.com/hanwen/go-fuse/raw/print_linux.go:14: (*Attr).String redeclared in this block
previous declaration at go/src/github.com/hanwen/go-fuse/raw/print.go:213
After applying a temporary fix to this print.go, several build errors were uncovered in fuse/loopback_test_linux.go:
go/src/github.com/hanwen/go-fuse/fuse/loopback_test_linux.go:12: undefined: NewTestCase
...
./loopback_test_linux.go:13: undefined: testCase
./loopback_test_linux.go:14: undefined: testCase
./loopback_test_linux.go:33: undefined: filepath
./loopback_test_linux.go:34: undefined: filepath
./loopback_test_linux.go:35: undefined: filepath
./loopback_test_linux.go:36: undefined: filepath
./loopback_test_linux.go:47: undefined: testTtl
./loopback_test_linux.go:48: undefined: testTtl
....
./loopback_test_linux.go:84: ts.Cleanup undefined (type *testCase has no field or method Cleanup)
Copying over NewTestCase, testCase, tstTtl, Cleanup, and the filepath import from loopback_test.go seemed to fix the problem.
Hi ,
i tried to understand example/hello. what i did is this :
mkdir Test
./hello Test
In another terminal i run this program :
fp, err := os.OpenFile("Test/file.txt",os.O_RDONLY,0644)
if err != nil {
fmt.Println(err)
os.Exit(0)
}
for {
line, err := br.ReadString('\n')
if err != nil {
fmt.Println(line,err)
break
}
fmt.Println(line)
}
fp.Close()
It works as expected.
then i change the code to :
fp, err := os.OpenFile("Test/file.txt",os.O_WRONLY,0644)
if err != nil {
fmt.Println(err)
os.Exit(0)
}
fp.WriteString("Hi Golang")
fp.Close()
It says open Test/file.txt: operation not permitted.
then i did ls Test. Nothing it shows.
i dont understand whats happening.
package main
import (
"flag"
"log"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
"github.com/hanwen/go-fuse/fuse/pathfs"
)
type HelloFs struct {
pathfs.FileSystem
}
func (me _HelloFs) GetAttr(name string, context *fuse.Context) (_fuse.Attr, fuse.Status) {
switch name {
case "file.txt":
return &fuse.Attr{
Mode: fuse.S_IFREG | 0644, Size: uint64(len(name)),
}, fuse.OK
case "":
return &fuse.Attr{
Mode: fuse.S_IFDIR | 0755,
}, fuse.OK
}
return nil, fuse.ENOENT
}
func (me *HelloFs) OpenDir(name string, context *fuse.Context) (c []fuse.DirEntry, code fuse.Status) {
if name == "" {
c = []fuse.DirEntry{{Name: "file.txt", Mode: fuse.S_IFREG}}
return c, fuse.OK
}
return nil, fuse.ENOENT
}
func (me *HelloFs) Open(name string, flags uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
if name != "file.txt" {
return nil, fuse.ENOENT
}
if flags&fuse.O_ANYWRITE != 0 {
return nil, fuse.EPERM
}
return nodefs.NewDataFile([]byte(name)), fuse.OK
}
func main() {
flag.Parse()
if len(flag.Args()) < 1 {
log.Fatal("Usage:\n fuse-hellofs MOUNTPOINT")
}
nfs := pathfs.NewPathNodeFs(&HelloFs{FileSystem: pathfs.NewDefaultFileSystem()}, nil)
server,_, err := nodefs.MountRoot(flag.Arg(0), nfs.Root(), nil)
if err != nil {
log.Fatal("Mount fail: %v\n", err)
}
server.Serve()
defer func (){
err:=server.Unmount()
if err != nil {
log.Println("err:%s",err)
}
}()
}
What is the recommended way to send a go-fuse filesystem to the background? In Python with fusepy I'd use the "foreground=false" parameter, is there something similar in go-fuse? Or should I simply send the command to the background using & on the shell?
I don't know why I haven't seen this earlier in my gocryptfs testing, but the hard link tracking (clientInodes) in pathfs seems to have a few issues (test case below). pathfs seems to lose track of linked files, internally renaming them to ".deleted". These files show up in directory listing but cannot be deleted nor stat'ed. Sometimes it crashes with a null pointer dereference in pathfs.
I am working on fixing the issues. It is not ready for merging yet, but it's probably going be a bigger patch. If you already want to take a look, the state right now with lots of added debugging code is here: rfjakob@fd910e7
Test case, with gocryptfs mounted on /tmp/b:
( set -e;
while true; do
~/src/fuse-xfstests/ltp/fsstress -p 1 -z -f rmdir=10 -f link=10 -f creat=10 -f mkdir=10 -f rename=30 -f stat=30 -f unlink=30 -f truncate=20 -m 8 -n 1000 -d /tmp/b
rm -R /tmp/b/*
sleep 1
done )
loopbackfs fails xfstests generic/053 because SetXAttr is not implemented.
A fix is included in my pull request #53 .
I added a log at fuse/pathfs/loopback.go
func (fs *loopbackFileSystem) Open(name string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) {
+ log.Printf("flags: %b\n", flags)
f, err := os.OpenFile(fs.GetPath(name), int(flags), 0)
if err != nil {
return nil, fuse.ToStatus(err)
}
return nodefs.NewLoopbackFile(f), fuse.OK
}
then I runned up loopback/main.go
cd github.com/hanwen/go-fuse/example/loopback
mkdir mount_dir
go run main.go mount_dir ~/
After that, I wrote a simple program to open a file in the mount point using O_TRUNC.
package main
import (
"log"
"os"
)
func main() {
flags := os.O_TRUNC
log.Printf("flags: %b\n", flags)
os.OpenFile("mount_dir/1.txt", flags, 0666)
}
when I executed this, it printed,
2014/04/16 18:43:24 my flags: 1000000000
but the fuse server side log is:
Mounted!
2014/04/16 18:43:24 flags: 1000000000000000
2014/04/16 18:43:24 flags: 1000000000000000
I'm confused that why the flags of O_TRUNC are different, and why the fuse server side printed two same lines.
This is a clone of hanwen/go-mtpfs#11
I wrote
I'm trying to compile go-mtpfs on OSX 10.8, but this is failing because the splice()
syscall seems to be unavailable on the BSDs and some constants are not available either:
# github.com/hanwen/go-fuse/raw
src/github.com/hanwen/go-fuse/raw/print.go:56: undefined: syscall.O_DIRECT
src/github.com/hanwen/go-fuse/raw/print.go:58: undefined: syscall.O_LARGEFILE
src/github.com/hanwen/go-fuse/raw/print.go:59: undefined: syscall.O_NOATIME
# github.com/hanwen/go-fuse/splice
src/github.com/hanwen/go-fuse/splice/pair.go:68: undefined: syscall.Splice
src/github.com/hanwen/go-fuse/splice/pair.go:78: undefined: syscall.Splice
src/github.com/hanwen/go-fuse/splice/pair.go:86: undefined: syscall.Splice
Being not at all familiar with low-level C programming and Go I was wondering if you could help me out resolving these issues?
From what I've read splice
could be replaced by POSIX' memmap
(http://stackoverflow.com/questions/10329505), but I don't understand the logic here...
On BSD's open(2)
man page I read about the available open flags:
O_RDONLY open for reading only
O_WRONLY open for writing only
O_RDWR open for reading and writing
O_NONBLOCK do not block on open or for data to become available
O_APPEND append on each write
O_CREAT create file if it does not exist
O_TRUNC truncate size to 0
O_EXCL error if O_CREAT and the file exists
O_SHLOCK atomically obtain a shared lock
O_EXLOCK atomically obtain an exclusive lock
O_NOFOLLOW do not follow symlinks
O_SYMLINK allow open of symlinks
O_EVTONLY descriptor requested for event notifications only
O_CLOEXEC mark as close-on-exec
I also read the Linux open(2)
man page and it still has to occur to me if these Linux-specific flags that are used in go-mtpfs are really, really needed, but hey, you're the expert :)
and hanwen answered
Go-FUSE doesn't work on MacOS; there are some small details with how
connection and datatypes are setup. If you want to fix that, feel free;
you can. See for some examples of how to setup the connection and the
datatypes.
http://code.google.com/p/rsc/source/browse/#hg%2Ffuse
you can find the corresponding code in fuse/mount.go and datatypes in raw/
Hi - I'm considering writing a Linux-based (for now) implementation of variant symlinks using go-fuse
With time this would accept mount requests of the form:
var_sym <ROOT_DIR> <ENV_VAR_NAME> <MOUNT_POINT>
So for example:
var_sym /home/myitcv/.gos GO_VERSION /home/myitcv/go
with the command:
GO_VERSION=go1.2.1 ls /home/myitcv/go
would list the contents of /home/myitcv/.gos/go1.2.1
. I won't labour the point, hopefully you get the idea!
Given my limited understanding of fuse, and more specifically go-fuse
, I'm looking for some feedback on how this could work.
My current thinking is this would work along the following lines:
serve ->
PathNodeFs ->
VarSymFs ->
LoopbackFileSystem
VarSymFs
is clearly the piece that's missing here. Again, in pseudo code, taking GetAttr
as an example:
func (me *VarSymFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
root, _ := me.contextToDir(context) // resolve
loopback := pathfs.NewLoopbackFileSystem(root)
return loopback.GetAttr(name, context)
}
Would very much appreciate some thoughts on:
a. Is this even achievable using go-fuse
?
b. Whether the rough outline above will/should work?
Thanks
Loopbackfs fails xfstests generic/258 because timestamps before 1970 are not handled correctly.
touch -t 196001010101 testfile.txt
touch: setting times of 'testfile.txt': Invalid argument
I have tracked this down to https://github.com/hanwen/go-fuse/blob/master/fuse/nodefs/files_linux.go#L35 . The Futimes returns the EINVAL, but UnixNano() seems to be the culprit. I have printed out the values around L35:
a = 1960-01-01 01:01:00 +0100 CET, m = 1960-01-01 01:01:00 +0100 CET
n = -315619140000000000
tv = [{-315619139 -999999} {-315619139 -999999}]
The buffer it returns has length a multiple of the page size, which can be larger than the input size.
This can cause problems, because len(buf) is usually used instead of the input size. This manifests itself in the following way:
doReadDir
in opcode.go gets a buffer of size 4096 and uses it.This doesn't seem to be a problem with files, likely because READ requests already have sizes of 4096.
Pull request coming soon.
Hello,
while compiling a project using go-fuse, I got the following error
Could not find fusermount binary: exec: "/bin/bin/fusermount": stat /bin/bin/fusermount: no such file or directory
which seems to have been introduced in 41b8187, more precisely here. It looks for "/bin/fusermount", which it can't find since I don't have "/usr" in my PATH.
func (f *mFile) Write(data []byte, off int64) (uint32, fuse.Status) { }
It will get 4096bytes data each write request. How to increase block size?
I was able to install go and go-fuse w/ no issues on my linux box, but ran into some issues on my darwin 10.8 machine. The fuse build errors are the following:
splice_darwin.go:9: undefined: Write
splice_darwin.go:11: *ReadResultFd is not a type
mount_darwin.go:124: cannot use nil as type int in return argument
mount_darwin.go:126: cannot use fd (type C.int) as type int in return argument
I followed the instructions here (https://bitbucket.org/oniony/tmsu/issue/59/solving-mac-compilation-errors-but-there) and the build and install works fine, as does go test in the fuse directory.
However, when trying to run the hello world fs, I get this cryptic comment:
go build
main.go:11:2: found packages pathfs (api.go) and fuse (loopback_darwin.go) in /Users/keleher/go/src/github.com/hanwen/go-fuse/fuse/pathfs
Hmm... turns out lookback_darwin.go has package 'fuse'. Chaning this to 'pathfs', I now get:
../../fuse/nodefs/files.go:95: cannot use loopbackFile literal (type *loopbackFile) as type File in return argument:
*loopbackFile does not implement File (missing Allocate method)
../../fuse/nodefs/fsops.go:126: input.NodeId undefined (type *fuse.GetAttrIn has no field or method NodeId)
../../fuse/nodefs/fsops.go:136: input.Context undefined (type *fuse.GetAttrIn has no field or method Context)
../../fuse/nodefs/fsops.go:141: input.NodeId undefined (type *fuse.GetAttrIn has no field or method NodeId)
The first error appears to be because allocate() is only implemented for linux (in files_linux.go). Not sure of the others.
Thanks,
pete
Repro steps:
I expect the panic to be hit (as it is in Linux) but it's not. Various other things that I'd expect to be hit are also not hit.
I'm not sure exactly why this happens. My working hypothesis is that OSXFUSE sends does an ACCESS call, which returns a "not implemented" error, and it gets confused by that and doesn't actually do the mount.
Log below:
=== RUN TestMemNodeFsWrite
2015/04/23 17:23:34 Dispatch: INIT, NodeId: 0. data: *fuse.InitIn: {7.8 Ra 0x100
00 }
2015/04/23 17:23:34 Serialize: INIT code: OK value: {7.8 Ra 0x10000 9/12 Wr 0x10000}
2015/04/23 17:23:34 Dispatch: STATFS, NodeId: 1.
2015/04/23 17:23:34 Serialize: STATFS code: OK value: {blocks (0,0)/0 files 0/0
bs0 nl0 frs0}
2015/04/23 17:23:34 Dispatch: STATFS, NodeId: 1.
2015/04/23 17:23:34 Serialize: STATFS code: OK value: {blocks (0,0)/0 files 0/0
bs0 nl0 frs0}
2015/04/23 17:23:34 Dispatch: STATFS, NodeId: 1.
2015/04/23 17:23:34 Serialize: STATFS code: OK value: {blocks (0,0)/0 files 0/0
(lots of STATFS calls)
2015/04/23 17:23:34 Dispatch: ACCESS, NodeId: 1. data: {}
2015/04/23 17:23:34 Serialize: ACCESS code: 78=function not implemented value:
2015/04/23 17:23:34 Dispatch: GETATTR, NodeId: 1. data:
2015/04/23 17:23:34 Serialize: GETATTR code: OK value: {A0.100000000 {M040777 SZ
=0 L=0 0:0 0 0:1 A 1429835014.567037062 M 1429835014.567037062 C 1429835014.5670
37062}}
(more STATFS and LOOKUP calls (for "._.")
Unionfs seems to be racy. About 20% of the test runs fail with different errors (example output pasted below).
I am on kernel 4.4 now, and given that I have already seen this on older kernels as well ( #67 ) I suspect a logic error somewhere in unionfs.
$ go test github.com/hanwen/go-fuse/unionfs
2016/01/25 23:15:54 Inode = "status/debug_setting" (autoUnionFs(/tmp/419665521/store))
2016/01/25 23:15:54 Inode = "status/debug_setting" (autoUnionFs(/tmp/419665521/store))
2016/01/25 23:15:54 Serialize: SYMLINK code: OK value:
2016/01/25 23:15:54 Dispatch: READLINK, NodeId: 4.
2016/01/25 23:15:54 Inode = "status/debug_setting" (autoUnionFs(/tmp/419665521/store))
2016/01/25 23:15:54 Serialize: READLINK code: OK value: "1"
2016/01/25 23:15:54 Dispatch: BATCH_FORGET, NodeId: 0. data: {2} 32 bytes
2016/01/25 23:15:54 Dispatch: FORGET, NodeId: 1. data: {1}
2016/01/25 23:15:54 Found version: version
2016/01/25 23:15:54 Adding workspace manual1 for roots UnionFs([LoopbackFs(/tmp/851926190/store/backing1) cachingFileSystem(LoopbackFs(/tmp/851926190/store/backing1/READONLY))])
2016/01/25 23:15:54 Looking for new filesystems
2016/01/25 23:15:54 Adding workspace backing1 for roots UnionFs([LoopbackFs(/tmp/851926190/store/backing1) cachingFileSystem(LoopbackFs(/tmp/851926190/store/backing1/READONLY))])
2016/01/25 23:15:54 Done looking
2016/01/25 23:15:54 Looking for new filesystems
2016/01/25 23:15:54 Adding workspace backing1 for roots UnionFs([LoopbackFs(/tmp/657096757/store/backing1) cachingFileSystem(LoopbackFs(/tmp/657096757/store/backing1/READONLY))])
2016/01/25 23:15:54 Done looking
2016/01/25 23:15:54 Looking for new filesystems
2016/01/25 23:15:54 Adding workspace backing1 for roots UnionFs([LoopbackFs(/tmp/916717584/store/backing1) cachingFileSystem(LoopbackFs(/tmp/916717584/store/backing1/READONLY))])
2016/01/25 23:15:54 Done looking
2016/01/25 23:15:54 Adding workspace bar for roots UnionFs([LoopbackFs(/tmp/923392047/store/foo) cachingFileSystem(LoopbackFs(/tmp/923392047/store/foo/READONLY))])
2016/01/25 23:15:54 Already have a union FS for directory /tmp/923392047/store/foo in workspace bar
2016/01/25 23:15:54 Illegal name "config" for overlay: [/tmp/923392047/store/ws2 /tmp/923392047/store/ws2/READONLY]
2016/01/25 23:15:55 Command: /usr/bin/rm -f /tmp/unionfs706380888/mnt/dir
2016/01/25 23:15:55 Contents of /tmp/unionfs706380888/mnt/dir: subdir
2016/01/25 23:15:55 Forced cache drop on UnionFs([LoopbackFs(/tmp/unionfs249050071/rw) cachingFileSystem(LoopbackFs(/tmp/unionfs249050071/ro))])
2016/01/25 23:15:55 Dropping cache for cachingFileSystem(LoopbackFs(/tmp/unionfs249050071/ro))
2016/01/25 23:15:55 Forced cache drop on UnionFs([LoopbackFs(/tmp/unionfs674426186/rw) cachingFileSystem(LoopbackFs(/tmp/unionfs674426186/ro))])
2016/01/25 23:15:55 Dropping cache for cachingFileSystem(LoopbackFs(/tmp/unionfs674426186/ro))
2016/01/25 23:15:55 TestUnionFsDisappearing2
2016/01/25 23:15:55 newDirnameMap(LoopbackFs(/dev/null)): DELETIONS 20=not a directory
2016/01/25 23:15:55 newDirnameMap(LoopbackFs(/dev/null)): DELETIONS 20=not a directory
2016/01/25 23:15:55 newDirnameMap(LoopbackFs(/dev/null)): DELETIONS 20=not a directory
2016/01/25 23:15:55 newDirnameMap(LoopbackFs(/dev/null)): DELETIONS 20=not a directory
2016/01/25 23:15:55 newDirnameMap(LoopbackFs(/dev/null)): DELETIONS 20=not a directory
2016/01/25 23:15:55 expected readdir failure: open /tmp/558197793/mnt: read-only file system
2016/01/25 23:15:55 error accessing deletion marker: DELETIONS/d41d8cd98f00b204-file2
2016/01/25 23:15:55 expected write failure: open /tmp/558197793/mnt/file2: read-only file system
--- FAIL: TestUnionFsFdLeak (0.02s)
unionfs_test.go:1317: /proc/self/fd changed size: after 9 before 8
2016/01/25 23:15:56 Found linked inode, but Nlink == 1 file
FAIL
For example, https://github.com/hanwen/go-fuse/blob/master/fuse/pathfs/pathfs.go#L666 . The passed file
argument is ignored and instead it uses a random (?) file handle.
This sometimes picks a file handle that is already closed when gocryptfs handles the truncate request, leading to unneccessary error messages and a general sense of "how the heck can this even happen" at yours sincerly.
Is there a reason for not using file
or are you ok if I fix this?
Reproducer at https://github.com/rfjakob/fsstress , testing against latest master (259481a) :
~/src/fsstress$ ./stress-loopback
Recompile go-fuse loopback
Waiting for mount: x done, debug log goes to /tmp/log.txt
Starting fsstress loop
1
fsstress.1 seed = 1461280698
fsstress.2 seed = 1460765625
fsstress.3 seed = 1461618057
rm
rm: cannot remove ‘/tmp/b/fsstress.2/p11/d2XXXXXXXXXXX/dcXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/d1aXXXXXXXXXXXXX/f6aXXXXXXXXX’: No such file or directory
rm: cannot remove ‘/tmp/b/fsstress.2/p11/d2XXXXXXXXXXX/dcXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/d1aXXXXXXXXXXXXX’: Directory not empty
rm: cannot remove ‘/tmp/b/fsstress.2/pe/d3XXXXX/d8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/f11XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX’: No such file or directory
rm: cannot remove ‘/tmp/b/fsstress.2/pe/d3XXXXX/d8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/f7’: No such file or directory
rm: cannot remove ‘/tmp/b/fsstress.2/pe/d3XXXXX/d8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX’: Directory not empty
rm: cannot remove ‘/tmp/b/fsstress.2/p5/d6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/d29/d3fXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/f48X’: No such file or directory
rm: cannot remove ‘/tmp/b/fsstress.2/p5/d6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/d29/d3fXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX’: Directory not empty
rm: cannot remove ‘/tmp/b/fsstress.2/p4/d7XXXXXXXX/d13XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/d31XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/d72XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/d1e/l2c’: No such file or directory
rm: cannot remove ‘/tmp/b/fsstress.2/p4/d7XXXXXXXX/d13XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/d31XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/d72XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/d1e’: Directory not empty
Running go test ./...
returns two failed tests:
FAIL: TestExplicitScan (0.02s)
autounion_test.go:218: Should have workspace backing1: lstat /tmp/099791821/mnt/backing1: no such file or directory
FAIL: TestUnionFsDropDeletionCache (0.08s)
unionfs_test.go:1039: Lstat() should have succeeded lstat /tmp/unionfs311629328/mnt/file: no such file or directory
It seems to be like that for a long time, commit f108ee9 from january already has these failures.
Full test log: https://gist.github.com/rfjakob/3955b67502299894a66a
loopbackfs (actually, anything that implements the nodefs API) fails xfstests generic/035.
What this test does is simple:
open("/testdir/20740/dir2", O_RDONLY) = 3
rename("/testdir/20740/dir1", "/testdir/20740/dir2") = 0
fstat(3, 0x7ffd603192d0) = -1 ENOENT (No such file or directory)
This fails because unlike handles that point to files, handles that point to directories are not kept open until the user closes them.
nodefs.OpenDir() should work like Open() and pass the file handle up.
Built the current version of go-fuse on OSX w/ go 1.2.1 64bit and OSX-Fuse 2.6.4 (it is able to run C++ filesystems like encfs without any issues).
started memfs: ~/go/bin/memfs /tmp/testfs testfs
In another terminal, attempted to untar a tarball:
cd /tmp/testfs
tar -xvzf ~/Downloads/encfs-1.7.5.tar.gz
This created a directory, but then was unable to create any of the files:
x encfs-1.7.5/
x encfs-1.7.5/ABOUT-NLS: Can't create 'encfs-1.7.5/ABOUT-NLS'
x encfs-1.7.5/aclocal.m4: Can't create 'encfs-1.7.5/aclocal.m4'
...
Tried a second time:
tar -xvzf ...
This time it extracted a couple files, before the main program crashed:
x encfs-1.7.5/
x encfs-1.7.5/ABOUT-NLS
x encfs-1.7.5/aclocal.m4
x encfs-1.7.5/AUTHORS: Can't create 'encfs-1.7.5/AUTHORS'
...
panic: runtime error: slice bounds out of range
goroutine 1 [running]:
runtime.panic(0x4100740, 0x428e12a)
/usr/local/go/src/pkg/runtime/panic.c:266 +0xb6
github.com/hanwen/go-fuse/fuse.(_request).parse(0xc210062000)
/Users/vgough/go/src/github.com/hanwen/go-fuse/fuse/request.go:167 +0x6bc
github.com/hanwen/go-fuse/fuse.(_Server).handleRequest(0xc210058000, 0xc210062000)
/Users/vgough/go/src/github.com/hanwen/go-fuse/fuse/server.go:327 +0x32
github.com/hanwen/go-fuse/fuse.(_Server).loop(0xc210058000, 0x0)
/Users/vgough/go/src/github.com/hanwen/go-fuse/fuse/server.go:321 +0xbf
github.com/hanwen/go-fuse/fuse.(_Server).Serve(0xc210058000)
/Users/vgough/go/src/github.com/hanwen/go-fuse/fuse/server.go:290 +0x56
main.main()
/Users/vgough/go/src/github.com/hanwen/go-fuse/example/memfs/main.go:35 +0x39a
...
The line in question appears to be:
r.filenames = []string{string(r.arg[:len(r.arg)-1])}
Any ideas?
Hi,
I am trying to dynamically create filenames when they are being accessed but it seems something isn't working. I do not know whether it is a bug in my program or no.
Here's my example program:
package main
import (
"flag"
"fmt"
"log"
"os"
"path"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
)
type testNode struct {
nodefs.Node
}
func newTestNode() nodefs.Node {
node := testNode{nodefs.NewDefaultNode()}
return &node
}
func (r *testNode) Lookup(out *fuse.Attr, name string, context *fuse.Context) (*nodefs.Inode, fuse.Status) {
node := r.Inode().NewChild(name, false, newTestNode())
return node, fuse.OK
}
func main() {
flag.Parse()
if flag.NArg() < 1 {
fmt.Printf("usage: %s MOUNTPOINT\n", path.Base(os.Args[0]))
os.Exit(2)
}
mountPoint := flag.Arg(0)
root := newTestNode()
server, _, err := nodefs.MountRoot(mountPoint, root, &nodefs.Options{
EntryTimeout: 0,
NegativeTimeout: 0,
AttrTimeout: 0,
PortableInodes: true,
})
server.SetDebug(true)
if err != nil {
log.Fatalf("Failed to mount filesystem: %v", err)
}
server.Serve()
}
On the shell I get the following results:
$ go run test.go /tmp/test
$ stat /tmp/test/abc
stat: cannot stat `/tmp/test/abc': Input/output error
$ stat /tmp/test/abc
File: `/tmp/test/abc'
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: 1ah/26d Inode: 3 Links: 0
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 1970-01-01 01:00:00.000000000 +0100
Modify: 1970-01-01 01:00:00.000000000 +0100
Change: 1970-01-01 01:00:00.000000000 +0100
Birth: -
Why does the first call fail and second one succeed?
Best regards,
Frank.
Running xfstests generic/257 against loopbackfs causes the following panic:
panic: underflow: handle 170, count 6, object -1
goroutine 6 [running]:
log.Panicf(0x5ac270, 0x29, 0xc20802bdd0, 0x3, 0x3)
/usr/lib/golang/src/log/log.go:314 +0xd0
github.com/hanwen/go-fuse/fuse/nodefs.(*portableHandleMap).Forget(0xc208058060, 0xaa, 0x6, 0x0, 0xc208038a10)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/nodefs/handle.go:118 +0x23e
github.com/hanwen/go-fuse/fuse/nodefs.(*FileSystemConnector).forgetUpdate(0xc20800a600, 0xaa, 0x6)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/nodefs/fsconnector.go:125 +0x9b
github.com/hanwen/go-fuse/fuse/nodefs.(*rawBridge).Forget(0xc20800a600, 0xaa, 0x6)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/nodefs/fsops.go:108 +0x3c
[....]
The test ( https://github.com/rfjakob/fuse-xfstests/blob/gocryptfs/tests/generic/257 ) runs "t_dir_offset2" ( https://github.com/rfjakob/fuse-xfstests/blob/gocryptfs/src/t_dir_offset2.c ) that exercises getdents
and lseek
on directories.
This feels like more of an issue for golang-dev
but I'll raise it here first just in case I'm missing something obvious.
Using tip
as of right now, on a Linux AMD64 host:
export GOPATH=`mktemp -d`
cd $GOPATH
go get -d github.com/hanwen/go-fuse/example/hello
cd src/github.com/hanwen/go-fuse/fuse/
GOOS=darwin GOARCH=amd64 go build -x
WORK=/tmp/go-build747672204
mkdir -p $WORK/github.com/hanwen/go-fuse/fuse/_obj/
mkdir -p $WORK/github.com/hanwen/go-fuse/
cd /tmp/tmp.wEi3wKl20V/src/github.com/hanwen/go-fuse/fuse
/home/myitcv/gos/pkg/tool/linux_amd64/6g -o $WORK/github.com/hanwen/go-fuse/fuse.a -trimpath $WORK -p github.com/hanwen/go-fuse/fuse -complete -D _/tmp/tmp.wEi3wKl20V/src/github.com/hanwen/go-fuse/fuse -I $WORK -pack ./api.go ./attr.go ./attr_darwin.go ./bufferpool.go ./constants.go ./defaultraw.go ./direntry.go ./lockingfs.go ./misc.go ./opcode.go ./print.go ./print_darwin.go ./read.go ./request.go ./request_darwin.go ./server.go ./server_darwin.go ./splice_darwin.go ./syscall_darwin.go ./typeprint.go ./types.go ./types_darwin.go ./upgrade.go
# github.com/hanwen/go-fuse/fuse
./server.go:96: undefined: unmount
./server.go:176: undefined: mount
Building on Darwin itself works just fine.
Any thoughts? Am I missing something obvious?
I am building an encrypted overlay filesystem, gocryptfs, on top of go-fuse (will release it on github soon). I noticed an issue with using pv that can also be reproduced with the loopback example:
Executing pv > foo < /dev/zero
inside a loopback mount hangs both pv and loopback.
pv cannot be killed at that point (not even -9), trying to strace it will hang strace. The only way out is to pkill -9 loopback
.
stracing loopback shows that all threads have been stopped:
strace -p $(pgrep loopback) -f
Process 22023 attached with 4 threads
[pid 22031] --- stopped by SIGTTOU ---
[pid 22027] --- stopped by SIGTTOU ---
[pid 22024] --- stopped by SIGTTOU ---
[pid 22023] --- stopped by SIGTTOU ---
However, starting pv under strace, I managed to capture this:
strace -f pv > foo < /dev/zero
[....]
mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8dbd74c000
select(1, [0], [], NULL, {0, 90000}) = 1 (in [0], left {0, 89998})
splice(0, NULL, 1, NULL, 131072, SPLICE_F_MORE) = -1 EINVAL (Invalid argument)
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072
select(2, [], [1], NULL, {0, 90000}
[.....hangs....]
The interesting thing here is the "splice()" call, which seems to be an optimisation for doing-zero copy reads. I guess this is where loopback goes AWOL.
I just built go-mtpfs following the instructions in the README file. Running the binary like
bin/go-mtpfs /mnt/nexus4/
yields
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x1 pc=0x80d955c]
goroutine 1 [running]:
sync/atomic.AddUint64()
/usr/local/go/src/pkg/sync/atomic/asm_386.s:69 +0xc
github.com/hanwen/go-fuse/fuse.(*FileSystemConnector).nextGeneration(0x1837d9c0, 0x183a1000, 0x18397d80)
/root/src/go-mtpfs/src/github.com/hanwen/go-fuse/fuse/fsconnector.go:85 +0x3a
github.com/hanwen/go-fuse/fuse.(*Inode).New(0x18375580, 0x8179d01, 0x183a1000, 0x18397d80, 0x0, ...)
/root/src/go-mtpfs/src/github.com/hanwen/go-fuse/fuse/inode.go:114 +0x57
github.com/hanwen/go-mtpfs/fs.(*DeviceFs).OnMount(0x1837b280, 0x1837d9c0)
/root/src/go-mtpfs/src/github.com/hanwen/go-mtpfs/fs/fs.go:139 +0x274
github.com/hanwen/go-fuse/fuse.(*FileSystemConnector).MountRoot(0x1837d9c0, 0x1837d990, 0x1837b280, 0x18397b60)
/root/src/go-mtpfs/src/github.com/hanwen/go-fuse/fuse/fsconnector.go:249 +0x62
github.com/hanwen/go-fuse/fuse.NewFileSystemConnector(0x1837d990, 0x1837b280, 0x18397b60, 0x1837d9c0)
/root/src/go-mtpfs/src/github.com/hanwen/go-fuse/fuse/fsconnector.go:75 +0x142
main.main()
/root/src/go-mtpfs/src/github.com/hanwen/go-mtpfs/main.go:63 +0x77f
goroutine 2 [syscall]:
When writing a test case to catch race conditions in gocryptfs, I noticed that read and write operations on a single file seem to be serialized.
The test case is simple, just insert a 1 second sleep at the top of loopbackFile.Read()
at files.go#L121 to make the issue more visible. Mount loopback to mnt
. Then,
echo a > mnt/a
time ( cat mnt/a & cat mnt/a & wait )
Result: 2 seconds
Expected: 1 second
I tested this against cluefs, that uses bazil-fuse as the backend library. Cluefs shows the expected 1 second runtime on the read test.
On writes, however, cluefs serializes just like go-fuse. This makes me wonder if this is a limitation in the FUSE protocol? The write test is just
time ( echo 1 >> mnt/a & echo 2 >> mnt/a & wait )
It takes 2 seconds instead of the expected one second.
Reproducer:
$ ./loopback /tmp/b /tmp/a &
Mounted!
$ cd /tmp/b
$ ln -s /nonexisting/file symlink
$ touch --no-dereference symlink
touch: setting times of ‘symlink’: No such file or directory
The problem is that Utimens ( https://github.com/hanwen/go-fuse/blob/master/fuse/pathfs/loopback.go#L121 ) operates on the target of the symlink and not on the symlink itself, like it should.
This also happens when extracting a tar that has a symlink in it, and this is how I noticed it.
Utimens has to use utimensat
with AT_SYMLINK_NOFOLLOW
, but the Go API has no way to do that, so we have to define our own syscall wrapper like in fa19882 .
Will send a patch tomorrow.
0 jakob@brikett:~/src/github.com/hanwen/go-fuse/example/loopback$ ls -la backing
total 8
drwxr-xr-x. 2 jakob jakob 4096 26. Aug 00:38 .
drwxr-xr-x. 5 jakob jakob 4096 5. Okt 23:21 ..
0 jakob@brikett:~/src/github.com/hanwen/go-fuse/example/loopback$ ls -la mountpoint
total 0
Hi.
I'm using go-fuse in a college project and so far i've been getting along pretty good by just looking through the code. I've now reached a point where i can't go any further without reading through some sort of documentation and i can't seem to find any. Have you got any? a link would be much appreciated.
mount_darwin.go has a huge C function mountfuse(), which looks like it was taken from Russ Cox's library. I ran into some unexplained hangs on panic, and I strongly suspect this function, specifically the fork() -- if I return before the fork, everything works okay, and otherwise it hangs.
I suspect that plain C fork() doesn't play well with Go. The whole function can probably be rewritten to be in Go, except maybe for getvfsbyname().
Also, errp is freed, but *errp should also be freed.
Fuse has support for direct_io. My understanding is that golang doesn't out of the box, but there are some extensions to support it. Has anyone looked into adding direct_io support?
Thanks
I see that go-fuse ignores INTERRUPT requests from fuse. At least on linux this means that signal handling in the client is delayed indefinitely until the original interrupted request returns. It's not a bug but it's jarring and I'd like to see INTERRUPT requests handled.
I have written a partial patch for one possible implementation that only covers nodefs filesystem. In this implementation the fuse.Context object contains a channel named Interrupted a true value will be written to this channel for an interrupted request.
Author: aarzilli <[email protected]>
Date: Thu Jun 27 11:52:59 2013 +0200
INTERRUPT handling
diff --git a/fuse/nodefs/api.go b/fuse/nodefs/api.go
index 36414c2..94d241a 100644
--- a/fuse/nodefs/api.go
+++ b/fuse/nodefs/api.go
@@ -112,8 +112,8 @@ type File interface {
// the inner file here.
InnerFile() File
- Read(dest []byte, off int64) (fuse.ReadResult, fuse.Status)
- Write(data []byte, off int64) (written uint32, code fuse.Status)
+ Read(dest []byte, off int64, context *fuse.Context) (fuse.ReadResult, fuse.Status)
+ Write(data []byte, off int64, context *fuse.Context) (written uint32, code fuse.Status)
Flush() fuse.Status
Release()
Fsync(flags int) (code fuse.Status)
diff --git a/fuse/nodefs/defaultfile.go b/fuse/nodefs/defaultfile.go
index 27df378..87889e4 100644
--- a/fuse/nodefs/defaultfile.go
+++ b/fuse/nodefs/defaultfile.go
@@ -26,11 +26,11 @@ func (f *defaultFile) String() string {
return "defaultFile"
}
-func (f *defaultFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) {
+func (f *defaultFile) Read(buf []byte, off int64, context *fuse.Context) (fuse.ReadResult, fuse.Status) {
return nil, fuse.ENOSYS
}
-func (f *defaultFile) Write(data []byte, off int64) (uint32, fuse.Status) {
+func (f *defaultFile) Write(data []byte, off int64, context *fuse.Context) (uint32, fuse.Status) {
return 0, fuse.ENOSYS
}
diff --git a/fuse/nodefs/files.go b/fuse/nodefs/files.go
index e00d54d..136515a 100644
--- a/fuse/nodefs/files.go
+++ b/fuse/nodefs/files.go
@@ -43,7 +43,7 @@ func NewDataFile(data []byte) File {
return f
}
-func (f *dataFile) Read(buf []byte, off int64) (res fuse.ReadResult, code fuse.Status) {
+func (f *dataFile) Read(buf []byte, off int64, context *fuse.Context) (res fuse.ReadResult, code fuse.Status) {
end := int(off) + int(len(buf))
if end > len(f.data) {
end = len(f.data)
@@ -74,11 +74,11 @@ func (f *devNullFile) String() string {
return "devNullFile"
}
-func (f *devNullFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) {
+func (f *devNullFile) Read(buf []byte, off int64, context *fuse.Context) (fuse.ReadResult, fuse.Status) {
return &fuse.ReadResultData{}, fuse.OK
}
-func (f *devNullFile) Write(content []byte, off int64) (uint32, fuse.Status) {
+func (f *devNullFile) Write(content []byte, off int64, context *fuse.Context) (uint32, fuse.Status) {
return uint32(len(content)), fuse.OK
}
@@ -125,7 +125,7 @@ func (f *loopbackFile) String() string {
return fmt.Sprintf("loopbackFile(%s)", f.File.Name())
}
-func (f *loopbackFile) Read(buf []byte, off int64) (res fuse.ReadResult, code fuse.Status) {
+func (f *loopbackFile) Read(buf []byte, off int64, context *fuse.Context) (res fuse.ReadResult, code fuse.Status) {
f.lock.Lock()
r := &fuse.ReadResultFd{
Fd: f.File.Fd(),
@@ -136,7 +136,7 @@ func (f *loopbackFile) Read(buf []byte, off int64) (res fuse.ReadResult, code fu
return r, fuse.OK
}
-func (f *loopbackFile) Write(data []byte, off int64) (uint32, fuse.Status) {
+func (f *loopbackFile) Write(data []byte, off int64, context *fuse.Context) (uint32, fuse.Status) {
f.lock.Lock()
n, err := f.File.WriteAt(data, off)
f.lock.Unlock()
@@ -229,7 +229,7 @@ func (f *readOnlyFile) String() string {
return fmt.Sprintf("readOnlyFile(%s)", f.File.String())
}
-func (f *readOnlyFile) Write(data []byte, off int64) (uint32, fuse.Status) {
+func (f *readOnlyFile) Write(data []byte, off int64, context *fuse.Context) (uint32, fuse.Status) {
return 0, fuse.EPERM
}
diff --git a/fuse/nodefs/fsops.go b/fuse/nodefs/fsops.go
index 31e51c5..65ec578 100644
--- a/fuse/nodefs/fsops.go
+++ b/fuse/nodefs/fsops.go
@@ -403,14 +403,14 @@ func (c *rawBridge) ListXAttr(context *fuse.Context) (data []byte, code fuse.Sta
func (c *rawBridge) Write(context *fuse.Context, input *raw.WriteIn, data []byte) (written uint32, code fuse.Status) {
node := c.toInode(context.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
- return opened.WithFlags.File.Write(data, int64(input.Offset))
+ return opened.WithFlags.File.Write(data, int64(input.Offset), context)
}
func (c *rawBridge) Read(context *fuse.Context, input *raw.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) {
node := c.toInode(context.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
- return opened.WithFlags.File.Read(buf, int64(input.Offset))
+ return opened.WithFlags.File.Read(buf, int64(input.Offset), context)
}
func (c *rawBridge) StatFs(out *raw.StatfsOut, context *fuse.Context) fuse.Status {
diff --git a/fuse/request.go b/fuse/request.go
index 37a2859..c071bc1 100644
--- a/fuse/request.go
+++ b/fuse/request.go
@@ -70,6 +70,7 @@ func (r *request) clear() {
r.startTime = time.Time{}
r.handler = nil
r.readResult = nil
+ r.context.Interrupted = make(chan bool, 1)
}
func (r *request) InputDebug() string {
diff --git a/fuse/server.go b/fuse/server.go
index 7f1696b..ed1ed2a 100644
--- a/fuse/server.go
+++ b/fuse/server.go
@@ -45,6 +45,9 @@ type Server struct {
outstandingReadBufs int
kernelSettings raw.InitIn
+ flightMu sync.Mutex
+ inFlight map[uint64]*request
+
canSplice bool
loops sync.WaitGroup
}
@@ -146,8 +149,9 @@ func NewServer(fs RawFileSystem, mountPoint string, opts *MountOptions) (*Server
fileSystem: fs,
started: make(chan struct{}),
opts: &o,
+ inFlight: make(map[uint64]*request),
}
-
+
optStrs := opts.Options
if opts.AllowOther {
optStrs = append(optStrs, "allow_other")
@@ -225,6 +229,7 @@ func (ms *Server) readRequest(exitIdle bool) (req *request, code Status) {
ms.reqPool = ms.reqPool[:l-1]
} else {
req = new(request)
+ req.context.Interrupted = make(chan bool, 1)
}
l = len(ms.readPool)
if l > 0 {
@@ -334,6 +339,24 @@ exit:
}
}
+func (ms *Server) getInFlight(unique uint64) *request {
+ ms.flightMu.Lock()
+ defer ms.flightMu.Unlock()
+ return ms.inFlight[unique]
+}
+
+func (ms *Server) pushInFlight(req *request) {
+ ms.flightMu.Lock()
+ defer ms.flightMu.Unlock()
+ ms.inFlight[req.inHeader.Unique] = req
+}
+
+func (ms *Server) popInFlight(req *request) {
+ ms.flightMu.Lock()
+ defer ms.flightMu.Unlock()
+ delete(ms.inFlight, req.inHeader.Unique)
+}
+
func (ms *Server) handleRequest(req *request) {
req.parse()
if req.handler == nil {
@@ -344,21 +367,42 @@ func (ms *Server) handleRequest(req *request) {
log.Println(req.InputDebug())
}
- if req.status.Ok() && req.handler.Func == nil {
- log.Printf("Unimplemented opcode %v", operationName(req.inHeader.Opcode))
- req.status = ENOSYS
- }
+ if req.status.Ok() && (req.inHeader.Opcode == _OP_INTERRUPT) {
+ interreq := ms.getInFlight((*raw.InterruptIn)(req.inData).Unique)
+ if interreq != nil {
+ select {
+ case interreq.context.Interrupted <- true:
+ default:
+ }
+ ms.returnRequest(req)
+ } else {
+ log.Println("Requesting interrupt repeat")
+ time.Sleep(500 * time.Millisecond)
+ req.status = Status(syscall.EAGAIN)
+ ms.write(req)
+ ms.returnRequest(req)
+ }
+ } else {
+ if req.status.Ok() && req.handler.Func == nil {
+ log.Printf("Unimplemented opcode %v", operationName(req.inHeader.Opcode))
+ req.status = ENOSYS
+ }
- if req.status.Ok() {
- req.handler.Func(ms, req)
- }
+ ms.pushInFlight(req)
- errNo := ms.write(req)
- if errNo != 0 {
- log.Printf("writer: Write/Writev failed, err: %v. opcode: %v",
- errNo, operationName(req.inHeader.Opcode))
+ if req.status.Ok() {
+ req.handler.Func(ms, req)
+ }
+
+ ms.popInFlight(req)
+
+ errNo := ms.write(req)
+ if errNo != 0 {
+ log.Printf("writer: Write/Writev failed, err: %v. opcode: %v",
+ errNo, operationName(req.inHeader.Opcode))
+ }
+ ms.returnRequest(req)
}
- ms.returnRequest(req)
}
func (ms *Server) allocOut(req *request, size uint32) []byte {
diff --git a/fuse/types.go b/fuse/types.go
index 7af20da..9f04435 100644
--- a/fuse/types.go
+++ b/fuse/types.go
@@ -48,5 +48,6 @@ type Owner raw.Owner
// Context contains assorted per-request data
type Context struct {
NodeId uint64
+ Interrupted chan bool
*raw.Context
}
(Not a PR due to CLA -> Google Account -> failed signup over Tor.)
$ go get github.com/hanwen/go-fuse/fuse
.go/src/github.com/hanwen/go-fuse/fuse/types.go:351: undefined: Attr
and lots of similar errors can be fixed by copying from:
s/\.O_LARGEFILE/_O_LARGEFILE/
.go/src/github.com/hanwen/go-fuse/fuse/server.go:96: undefined: unmount
.go/src/github.com/hanwen/go-fuse/fuse/server.go:181: undefined: mount
FreeBSD uses libfuse but not fusermount binary. Instead, the library calls mount_fusefs(8) with special argument obtained via open("/dev/fuse", ...)
. Playing with syscall.Dup()
was enough for mounting to succeed but any VFS operation still hangs.
Regular users only need to sysctl vfs.usermount=1
before mount/umount.
.go/src/github.com/hanwen/go-fuse/fuse/types.go:24: undefined: syscall.ENODATA
NetBSD folks had an interesting discussion. OS X may unintentionally use ENODATA for unionfs here despite it's never returned.
http://fxr.watson.org/fxr/ident?v=xnu-2050.18.24&i=ENODATA
http://fxr.watson.org/fxr/ident?v=xnu-2050.18.24&i=ENOATTR
$ go get github.com/hanwen/go-fuse/zipfs
.go/src/github.com/hanwen/go-fuse/fuse/nodefs/files.go:96: cannot use loopbackFile literal (type *loopbackFile) as type File in return argument:
*loopbackFile does not implement File (missing Allocate method)
.go/src/github.com/hanwen/go-fuse/fuse/nodefs/syscall.go:11: undefined: syscall.SYS_UTIMENSAT
bash all.bash
+ for target in '"clean"' '"install"'
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test clean = install
+ go clean github.com/hanwen/go-fuse/fuse
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test clean = install
+ go clean github.com/hanwen/go-fuse/fuse/pathfs
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test clean = install
+ go clean github.com/hanwen/go-fuse/fuse/test
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test clean = install
+ go clean github.com/hanwen/go-fuse/zipfs
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test clean = install
+ go clean github.com/hanwen/go-fuse/unionfs
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test clean = install
+ go clean github.com/hanwen/go-fuse/example/hello
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test clean = install
+ go clean github.com/hanwen/go-fuse/example/loopback
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test clean = install
+ go clean github.com/hanwen/go-fuse/example/zipfs
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test clean = install
+ go clean github.com/hanwen/go-fuse/example/multizip
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test clean = install
+ go clean github.com/hanwen/go-fuse/example/unionfs
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test clean = install
+ go clean github.com/hanwen/go-fuse/example/memfs
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test clean = install
+ go clean github.com/hanwen/go-fuse/example/autounionfs
+ for target in '"clean"' '"install"'
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test install = install
+ test fuse = fuse/test
+ go install github.com/hanwen/go-fuse/fuse
+ for d in fuse fuse/pathfs fuse/test zipfs unionfs example/hello example/loopback example/zipfs example/multizip example/unionfs example/memfs example/autounionfs
+ test install = install
+ test fuse/pathfs = fuse/test
+ go install github.com/hanwen/go-fuse/fuse/pathfs
# github.com/hanwen/go-fuse/fuse/nodefs
fuse/nodefs/files_darwin.go:5: imported and not used: "time"
fuse/nodefs/syscall.go:11: undefined: syscall.SYS_UTIMENSAT
tar xzf linux-3.0.tar.gz
is my canonical small-file benchmark. The loopback example takes 2x the time compared to EncFS.
Looking at the cpu profile, this is caused by heavy GC activity that originates in go-fuse. For each created file, an inode object is allocated. Recycling inode objects could reduce GC pressure considerably.
(github does not allow SVG attachments. Attaching as PNG and PDF)
This works on Linux, but OS X seems to think that the file doesn't exist.
My current hypothesis is that OSXFUSE is less forgiving about Open() not filling in out.OpenFlags or out.Fh (see nodefs/fsops.go), which we don't since we return "nil, fuse.OK" from nodeReadNode.Open() in fileless_test.go.
Do any "real" filesystems using the nodefs API rely on that behavior of Open()? If not, we should just fix the test and check to make sure that Open() doesn't return (nil, OK).
Log below:
2015/04/23 17:07:40 Dispatch: OPEN, NodeId: 3. data: {O_RDONLY}
2015/04/23 17:07:40 Serialize: OPEN code: OK value: {Fh 0 }
2015/04/23 17:07:40 Dispatch: FLUSH, NodeId: 3. data: {Fh 0}
2015/04/23 17:07:40 Serialize: FLUSH code: OK value:
2015/04/23 17:07:40 Dispatch: RELEASE, NodeId: 3. data: {Fh 0 L0}
2015/04/23 17:07:40 Serialize: RELEASE code: OK value:
2015/04/23 17:07:40 Dispatch: GETATTR, NodeId: 3. data:
2015/04/23 17:07:40 Serialize: GETATTR code: OK value: {A1.000000000 {M0100644 SZ=0 L=0 501:20 0 0:3 A 0.000000000 M 0.000000000 C 0.000000000}}
2015/04/23 17:07:40 Dispatch: OPEN, NodeId: 3. data: {O_RDONLY}
2015/04/23 17:07:40 Serialize: OPEN code: OK value: {Fh 0 }
2015/04/23 17:07:40 Dispatch: FLUSH, NodeId: 3. data: {Fh 0}
2015/04/23 17:07:40 Serialize: FLUSH code: OK value:
2015/04/23 17:07:40 Dispatch: RELEASE, NodeId: 3. data: {Fh 0 L0}
2015/04/23 17:07:40 Serialize: RELEASE code: OK value:
2015/04/23 17:07:40 Dispatch: GETATTR, NodeId: 3. data:
2015/04/23 17:07:40 Serialize: GETATTR code: OK value: {A1.000000000 {M0100644 SZ=0 L=0 501:20 0 0:3 A 0.000000000 M 0.000000000 C 0.000000000}}
2015/04/23 17:07:40 Dispatch: OPEN, NodeId: 3. data: {O_RDONLY}
2015/04/23 17:07:40 Serialize: OPEN code: OK value: {Fh 0 }
2015/04/23 17:07:40 Dispatch: STATFS, NodeId: 1.
2015/04/23 17:07:40 Serialize: STATFS code: OK value: {blocks (0,0)/0 files 0/0 bs0 nl0 frs0}
2015/04/23 17:07:40 Dispatch: FLUSH, NodeId: 3. data: {Fh 0}
2015/04/23 17:07:40 Serialize: FLUSH code: OK value:
2015/04/23 17:07:40 Dispatch: LOOKUP, NodeId: 1. names: [.hidden] 8 bytes
2015/04/23 17:07:40 Serialize: LOOKUP code: OK value: {4 E1.000000000 A1.000000000 {M0100644 SZ=7 L=1 501:20 0 0:4 A 0.000000000 M 0.000000000 C 0.000000000}}
2015/04/23 17:07:40 Dispatch: RELEASE, NodeId: 3. data: {Fh 0 L0}
2015/04/23 17:07:40 Serialize: RELEASE code: OK value:
2015/04/23 17:07:40 Dispatch: GETATTR, NodeId: 4. data:
2015/04/23 17:07:40 Serialize: GETATTR code: OK value: {A1.000000000 {M0100644 SZ=0 L=0 501:20 0 0:4 A 0.000000000 M 0.000000000 C 0.000000000}}
2015/04/23 17:07:40 Dispatch: OPEN, NodeId: 4. data: {O_RDONLY}
2015/04/23 17:07:40 Serialize: OPEN code: OK value: {Fh 0 }
2015/04/23 17:07:40 Dispatch: FLUSH, NodeId: 4. data: {Fh 0}
2015/04/23 17:07:40 Serialize: FLUSH code: OK value:
2015/04/23 17:07:40 Dispatch: RELEASE, NodeId: 4. data: {Fh 0 L0}
2015/04/23 17:07:40 Serialize: RELEASE code: OK value:
2015/04/23 17:07:40 Dispatch: FORGET, NodeId: 4. data: {1}
2015/04/23 17:07:40 Dispatch: FORGET, NodeId: 3. data: {1}
2015/04/23 17:07:40 Dispatch: DESTROY, NodeId: 1.
2015/04/23 17:07:40 Serialize: DESTROY code: OK value:
--- FAIL: TestNodeRead (0.03s)
fileless_test.go:54: MountRoot: open /var/folders/kl/s5jj4qvn0tv62zcl8wfwgnx80000gn/T/nodefs704613733/file: no such file or directory
Hi,
I failed to build go-mtpfs with following log:
/tmp % go get github.com/hanwen/go-mtpfs
# github.com/hanwen/go-fuse/fuse
go/src/github.com/hanwen/go-fuse/fuse/server.go:44: undefined: sync.Pool
go/src/github.com/hanwen/go-fuse/fuse/server.go:47: undefined: sync.Pool
It looks like a new generation number generated for an inode whenever a child is added to it (NewChild). However, I don't think this is correct. This manifests itself in the following way (on OS X -- Linux seems to be more permissive):
Imagine a filesystem with a non-empty directory 'foo'. Let's say I do rmdir foo
. go-fuse does a lookup on foo, and its inode gets a default generation number of 0. Everything works as expected, i.e. the filesystem returns ENOTEMPTY, which gets propagated to the kernel, and nothing is changed.
Now imagine that I then do touch foo/bar
. The filesystem creates the file, etc., which ends up with the node of 'bar' being added to 'foo' via (*Inode).NewChild()
. Then 'foo''s inode now has a non-zero generation number. Now if I try to do rmdir foo
again, the filesystem returns ENOTEMPTY again, which gets propagated to the kernel properly, but then OSXFUSE gets confused by the new generation number and forgets the node ID (sending out a bunch of FORGET requests, too). Then trying to stat the file (or ls
its parent directory) returns with a ESTALE error for 'foo' (with the message 'stale NFS handle').
According to http://ptspts.blogspot.com/2009/11/fuse-protocol-tutorial-for-linux-26.html , the generation number should be incremented only when a node ID is reused. Consulting another go implementation -- https://github.com/bazil/fuse/blob/3a76e04b5ed7533c3530ed338942b5daa13ba9c7/fs/serve.go#L427 -- that seems to be correct.
Taking a quick look at the code, I think the solution is to:
xfstests generic/221 runs t_futimens.c, that executes the following syscall:
utimensat(3, NULL, {{1000000000, 0}, UTIME_OMIT}, 0) = -1 EINVAL (Invalid argument)
As you can see, it fails with EINVAL. Stracing the loopback process shows:
[pid 27783] utimes("/proc/self/fd/3", {{1000000000, 0}, {0, 1073741822}} <unfinished ...>
[pid 27783] <... utimes resumed> ) = -1 EINVAL (Invalid argument)
Note that 1073741822 == UTIME_OMIT. However, this special value only works for utimens
and utimensat
that take nanoseconds, not for utimes
that only takes microseconds!
*** This is the last issue with the "generic" xfstests ***
Failing tests are now:
Everything else passes or is skipped.
I managed to reproduce the nil pointer dereference that I mentioned in #99 with latest master.
loopback example output:
/tmp$ ~/src/github.com/hanwen/go-fuse/example/loopback/loopback b a
Mounted!
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x38 pc=0x4ce100]
goroutine 6062 [running]:
github.com/hanwen/go-fuse/fuse/pathfs.(*pathInode).Rename(0xc82055a280, 0xc820199aa0, 0x4, 0x7fe4b9f8f688, 0xc82055a680, 0xc820199ab0, 0x4, 0xc8200e1820, 0x0)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/pathfs/pathfs.go:506 +0x310
github.com/hanwen/go-fuse/fuse/nodefs.(*rawBridge).Rename(0xc82000a810, 0xc8200e1808, 0xc820199aa0, 0x4, 0xc820199ab0, 0x4, 0x0)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/nodefs/fsops.go:314 +0x156
github.com/hanwen/go-fuse/fuse.doRename(0xc820088000, 0xc8200e1680)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/opcode.go:346 +0xb0
github.com/hanwen/go-fuse/fuse.(*Server).handleRequest(0xc820088000, 0xc8200e1680)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:358 +0x305
github.com/hanwen/go-fuse/fuse.(*Server).loop(0xc820088000, 0x52e401)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:337 +0xe2
created by github.com/hanwen/go-fuse/fuse.(*Server).readRequest
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:265 +0x60e
goroutine 1 [semacquire, 8 minutes]:
sync.runtime_Semacquire(0xc8200880e0)
/usr/lib/golang/src/runtime/sema.go:43 +0x26
sync.(*WaitGroup).Wait(0xc8200880d4)
/usr/lib/golang/src/sync/waitgroup.go:126 +0xb4
github.com/hanwen/go-fuse/fuse.(*Server).Serve(0xc820088000)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:307 +0x71
main.main()
/home/jakob/src/github.com/hanwen/go-fuse/example/loopback/main.go:87 +0xfd6
goroutine 6041 [syscall]:
syscall.Syscall(0x0, 0x5, 0xc8204b6000, 0x11000, 0x4faf58, 0xc8204b4188, 0x22ffffffff)
/usr/lib/golang/src/syscall/asm_linux_amd64.s:18 +0x5
syscall.read(0x5, 0xc8204b6000, 0x11000, 0x11000, 0x4fb67f, 0x0, 0x0)
/usr/lib/golang/src/syscall/zsyscall_linux_amd64.go:783 +0x5f
syscall.Read(0x5, 0xc8204b6000, 0x11000, 0x11000, 0xc820199630, 0x0, 0x0)
/usr/lib/golang/src/syscall/syscall_unix.go:160 +0x4d
github.com/hanwen/go-fuse/fuse.(*Server).readRequest.func1(0x0, 0x0)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:240 +0x64
github.com/hanwen/go-fuse/fuse.handleEINTR(0xc8203dbf08, 0x0, 0x0)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:216 +0x2b
github.com/hanwen/go-fuse/fuse.(*Server).readRequest(0xc820088000, 0xc8200e0d01, 0xc8200e0d80, 0x0)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:238 +0x1fa
github.com/hanwen/go-fuse/fuse.(*Server).loop(0xc820088000, 0x52e401)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:318 +0x7a
created by github.com/hanwen/go-fuse/fuse.(*Server).readRequest
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:265 +0x60e
goroutine 6053 [syscall]:
syscall.Syscall(0x0, 0x5, 0xc820520000, 0x11000, 0xc8203dfd38, 0xc82055d360, 0x52e400)
/usr/lib/golang/src/syscall/asm_linux_amd64.s:18 +0x5
syscall.read(0x5, 0xc820520000, 0x11000, 0x11000, 0x4fb6a8, 0x0, 0x0)
/usr/lib/golang/src/syscall/zsyscall_linux_amd64.go:783 +0x5f
syscall.Read(0x5, 0xc820520000, 0x11000, 0x11000, 0xc820088078, 0x0, 0x0)
/usr/lib/golang/src/syscall/syscall_unix.go:160 +0x4d
github.com/hanwen/go-fuse/fuse.(*Server).readRequest.func1(0x0, 0x0)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:240 +0x64
github.com/hanwen/go-fuse/fuse.handleEINTR(0xc8203dff08, 0x0, 0x0)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:216 +0x2b
github.com/hanwen/go-fuse/fuse.(*Server).readRequest(0xc820088000, 0xc8200e0601, 0xc8200e06c0, 0x0)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:238 +0x1fa
github.com/hanwen/go-fuse/fuse.(*Server).loop(0xc820088000, 0x52e401)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:318 +0x7a
created by github.com/hanwen/go-fuse/fuse.(*Server).readRequest
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:265 +0x60e
goroutine 6025 [syscall]:
syscall.Syscall(0x0, 0x5, 0xc820462000, 0x11000, 0x2, 0xc820019110, 0x4b26cc)
/usr/lib/golang/src/syscall/asm_linux_amd64.s:18 +0x5
syscall.read(0x5, 0xc820462000, 0x11000, 0x11000, 0x4b79b0, 0x0, 0x0)
/usr/lib/golang/src/syscall/zsyscall_linux_amd64.go:783 +0x5f
syscall.Read(0x5, 0xc820462000, 0x11000, 0x11000, 0xc820088078, 0x0, 0x0)
/usr/lib/golang/src/syscall/syscall_unix.go:160 +0x4d
github.com/hanwen/go-fuse/fuse.(*Server).readRequest.func1(0x0, 0x0)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:240 +0x64
github.com/hanwen/go-fuse/fuse.handleEINTR(0xc8204d3f08, 0x0, 0x0)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:216 +0x2b
github.com/hanwen/go-fuse/fuse.(*Server).readRequest(0xc820088000, 0xc8200e1d01, 0xc8200e1d40, 0x7fe400000000)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:238 +0x1fa
github.com/hanwen/go-fuse/fuse.(*Server).loop(0xc820088000, 0x52e401)
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:318 +0x7a
created by github.com/hanwen/go-fuse/fuse.(*Server).readRequest
/home/jakob/src/github.com/hanwen/go-fuse/fuse/server.go:265 +0x60e
Test loop output:
( set -e; while true; do ~/src/fuse-xfstests/ltp/fsstress -p 1 -z -f rmdir=10 -f link=10 -f creat=10 -f mkdir=10 -f rename=30 -f stat=30 -f unlink=30 -f truncate=20 -m 8 -n 1000 -d /tmp/b; rm -R /tmp/b/*; sleep 1; done )
seed = 1457036032
seed = 1457193343
[400 lines more...]
seed = 1456698305
seed = 1456838337
rm: cannot remove ‘/tmp/b/*’: Transport endpoint is not connected
Hi Dear,
I can mount local folder using "FileSystem: pathfs.NewLoopbackFileSystem("/mnt/local")" and can do listing and all other operations; but I can't mount an NFS Share (/home directory) using: "FileSystem: pathfs.NewLoopbackFileSystem("192.168.1.7:/home")".
What could I be missing here? Remember, I can mount NFS Share using normal NFS Client.
code snippet:
//nfsRoot := "192.168.1.7:/home"
nfsRoot := "/tmp/nvd"
mountPoint := "/mnt/storage/1"
os.MkdirAll(mountPoint, 0777)
cffs := fs.NewCFFileSystem(nfsRoot)
vfs := pathfs.NewPathNodeFs(cffs, nil)
vfs.SetDebug(false)
conn := nodefs.NewFileSystemConnector(vfs.Root(), nil)
mOpts := fuse.MountOptions{
AllowOther: true,
RememberInodes: true,
}
server, err := fuse.NewServer(conn.RawFS(), mountPoint, &mOpts)
if err != nil {
log.Fatalf("Mount fail: %v\n", err)
}
log.Println("start server")
Looking forward to your response...
../github.com/hanwen/go-fuse/fuse/nodefs/files_darwin.go:5: imported and not used: "time"
../github.com/hanwen/go-fuse/fuse/nodefs/syscall.go:11: undefined: syscall.SYS_UTIMENSAT
Loopbackfs fails xfstests generic/001 with the output shown below.
The last 1kB of sub/h000 are replaced by zeros. This is due to bugs in trySplice().
Fix is included in pull request #53, commit rfjakob@35cee6c
QA output created by 001
cleanup
setup ....................................
iter 1 chain ... check ..................................
Error: corruption for sub/h000 ...
diff -u sub/h000 sub/h000.last
--- sub/h000 2015-09-20 23:08:30.803715663 +0200
+++ sub/h000.last 2015-09-20 23:08:31.123716790 +0200
@@ -1761,18 +1761,4 @@
000000126720 0000 sub/h000 jk'b$@-Zm18$'M\S0s%fW|jU%ypVHzb2eBTjbAD0R=t9
000000126792 0000 sub/h000 j0l[#RA:NkpSD')LZl> nrj13n!F+u?V%,1h^2#l}s?!
000000126864 0000 sub/h000 3HNNtlNc?xTRfUxR*8(/$9WBKZn(--iA57Ojd}-#Ua5;
-000000126936 0000 sub/h000 6nm fU/jnfly!Za.GK/\B^F&;Sipt�ljm9jSoY}= I7!
-000000127008 0000 sub/h000 #xo*C�fF]mLy 6iUuU?Boju>CR[C{R$^KthNs.tP[!)<
-000000127080 0000 sub/h000 wsql(p.WZcu~u1!pcfNnZv=-$q='RG|IzMu"=c:x&oV{
-000000127152 0000 sub/h000 7kD}y27o/$t!B43ip]c=RE:v_r|/(xo C3]=FulUy@6
-000000127224 0000 sub/h000 {TJd$g'!yM<olnL{wDkwG^4d$)Q:cq0>&:#jajl[wh*D
-000000127296 0000 sub/h000 6V�-Zjd")yfmbw'%IxD/2'ytQE/I-9m$pl1J7V,@/s-Q
-000000127368 0000 sub/h000 Ju7SM[b?B<3sa"|O<iSl6Dv-Z#MIV:['or4<-v\/rO"T
-000000127440 0000 sub/h000 2_c.(vz>zP+U38^iS9J"+>�8t;GgJ*{\I^jQTDPNu[c(
-000000127512 0000 sub/h000 tBR'[\iGzh?n#G5NQ0*ZnU+"y;1nwTWKviR2%;9_$X-g
-000000127584 0000 sub/h000 �Cu0S j"5Vd.qu]h*t3 ]ErBa+!Ed.lC1bTeB~GWT+eF
-000000127656 0000 sub/h000 aBnkv"kSG>Uh)VmMEZqV|E{>CBuXN:~/=lz3NEGVC|>M
-000000127728 0000 sub/h000 SlzXFk.Bpj@t,5L:/*ILv#'E)'{L#yy6eTNk?]mp'mD3
-000000127800 0000 sub/h000 "p.rZ7>P;^UDE0PI*J?O^n{]+HM26q%xA3j{Ki,FGajm
-000000127872 0000 sub/h000 Rzv\DukbcF@Nom@%?F]@9H<D1(j8i4e;/[W31#vTI6#x
-000000127944 0000 sub/h000 cC]"I;CcC?g4GRLpfrlU-#i>f?sp
+000000126936 0000 sub/h000 6nm fU/jnfly!
\ No newline at end of file
.
Fatal error: test abandoned without changes
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.