Code Monkey home page Code Monkey logo

go-fuse's People

Contributors

adlternative avatar agoode avatar ahl avatar akalin avatar dsxack avatar esp32wrangler avatar hanwen avatar jille avatar krasin avatar lch avatar levinzimmermannn avatar macos-fuse-t avatar mikegray avatar muryoutaisuu avatar mvdan avatar myitcv avatar navytux avatar ncw avatar nnnlife avatar oneofone avatar orivej avatar patrickxb avatar pooya avatar r4nt avatar rfjakob avatar ryanguest avatar ryanlamore avatar sbinet avatar tiziano88 avatar tomyl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-fuse's Issues

Missing copyrights or who owns the code?

The license is confusing:

  • only one copyright holder in LICENSE despite /graphs page showing more
  • no AUTHORS files to list contributers under an umbrella copyright holder e.g., Go Authors
  • no license header in individual files listing copyright(s) of contributors e.g., for inherited code before CLA was established
  • README and CONTRIBUTING don't agree on affiliation to Google: Why a CLA from an entity that doesn't hold a copyright in the project matters?
$ 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

Operation to Set ACL not supported ?

Hi,

  1. 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:
    test_result

  2. 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!

Why is there no fuse.ENOTEMPTY?

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.

No input buffer for writes in Open() Pathfs

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.

Previous declaration build error

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.

Need Help - operation not permitted

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.

How to unmount when program exit ?

The system is not unmount when using ctrl+c kill runing job.

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)
    }
    }()

}

Background mode

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?

Fails xfstests generic/013, renames files to ".deleted"

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 )

flags seems not be passed correctly

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.

Mac OS X port

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/

Variant symlinks with go-fuse

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

Fails xfstests generic/258, setting times of 'testfile.txt': Invalid argument

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}]

bufferPoolImpl.AllocBuffer() returns a too-big buffer

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:

  • fuse does, say, a READDIR request with size 1500 bytes.
  • doReadDir in opcode.go gets a buffer of size 4096 and uses it.
  • server.filesystem.ReadDir() happily fills up the buffer up to 4096 bytes.
  • we pass the buffer back to fuse, which barfs on OS X. (Linux seems to be more permissive about this.)

This doesn't seem to be a problem with files, likely because READ requests already have sizes of 4096.

Pull request coming soon.

Could not find fusermount binary: exec: "/bin/bin/fusermount"

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.

How to increase block size?

func (f *mFile) Write(data []byte, off int64) (uint32, fuse.Status) { }
It will get 4096bytes data each write request. How to increase block size?

MAC issues, fixes

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

Tests in memnode_test.go don't actually use memNode on OS X (!)

Repro steps:

  1. Put a panic in memNode.Create() (or other callers of newNode() or newFile()).
  2. Run go test with -run MemNodeFsWrite

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 self tests fail 20% of the time on Linux 4.4

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

pathInode.Truncate and friends ignore `file` argument

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?

fsstress still fails

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

unionfs self tests fail on Linux 4.1+

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

Fails xfstests generic/035, directory file handle is lost

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.

OSX crash testing memfs

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?

Input/output error when dynamically creating children in nodefs.Lookup

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.

Fails xfstests generic/257, panic: underflow: handle 170, count 6, object -1

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.

Cross compiling example `hello` for Darwin fails

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?

"pv" hangs example/loopback

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.

panic: runtime error: invalid memory address or nil pointer dereference

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]:

Concurrent reads on a single file do not work

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.

loopbackfs: Utimens on symlinks does not work

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.

loopback: Missing "." and ".." entries

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

Documentation

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 should be rewritten in Go

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.

direct_io support

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

Handling INTERRUPT requests

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
 }

Fails to build on FreeBSD

(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:

  • attr_darwin.go
  • print_linux.go + s/\.O_LARGEFILE/_O_LARGEFILE/
  • request_linux.go
  • server_darwin.go
  • splice_darwin.go
  • syscall_linux.go
  • types_linux.go
  • pathfs/loopback_darwin.go
.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
  • FreeBSD and NetBSD lack fallocate(2) but have posix_fallocate(2) i.e., syscall.SYS_POSIX_FALLOCATE
  • FreeBSD and DragonFly only recently added utimensat(2) support thus missing in syscall package

all.bash doesn't succeed on OS X - el capitan

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

Improve small-file performance

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)
c

TestNodeRead in fileless_test.go fails on OS X

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

fuse/server.go:44: undefined: sync.Pool

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

Generation number isn't being used properly

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:

  • Move the generation field from nodefs/FileSystemConnector to handleMap.
  • Have handleMap.Register() return both the inode number and the generation number.
  • Increment the generation number whenever Register() reuses a previously-used node ID.

Fails xfstests generic/221, UTIME_OMIT does not work

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:

  • generic/002 (missing hardlink support)
  • generic/035 (known bug #55)
  • generic/089 (missing hardlink support)
  • generic/221 (this bug)
  • generic/236 (missing hardlink support)

Everything else passes or is skipped.

nil pointer dereference in pathfs.go:506

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

Mounting NFS Share using pathfs.LoopbackFileSystem

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")

server.Serve()

Looking forward to your response...

build error on mac

github.com/hanwen/go-fuse/fuse/nodefs

../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

Fails xfstests generic/001, data corruption

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.