Commit 49932918 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Handle EBADF returns from open file attribute operations.

parent 4d28ef4b
...@@ -153,15 +153,17 @@ type File interface { ...@@ -153,15 +153,17 @@ type File interface {
Read(*ReadIn, BufferPool) ([]byte, Status) Read(*ReadIn, BufferPool) ([]byte, Status)
Write(*WriteIn, []byte) (written uint32, code Status) Write(*WriteIn, []byte) (written uint32, code Status)
Truncate(size uint64) Status Flush() Status
Release()
Fsync(*FsyncIn) (code Status)
// The methods below may be called on closed files, due to
// concurrency. In that case, you should return EBADF.
Truncate(size uint64) Status
GetAttr() (*os.FileInfo, Status) GetAttr() (*os.FileInfo, Status)
Chown(uid uint32, gid uint32) Status Chown(uid uint32, gid uint32) Status
Chmod(perms uint32) Status Chmod(perms uint32) Status
Utimens(atimeNs uint64, mtimeNs uint64) Status Utimens(atimeNs uint64, mtimeNs uint64) Status
Flush() Status
Release()
Fsync(*FsyncIn) (code Status)
} }
// Wrap a File return in this to set FUSE flags. Also used internally // Wrap a File return in this to set FUSE flags. Also used internally
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"sync"
"testing" "testing"
) )
...@@ -138,3 +139,48 @@ func TestNonseekable(t *testing.T) { ...@@ -138,3 +139,48 @@ func TestNonseekable(t *testing.T) {
t.Errorf("file was opened nonseekable, but seek successful") t.Errorf("file was opened nonseekable, but seek successful")
} }
} }
func TestGetAttrRace(t *testing.T) {
dir, err := ioutil.TempDir("", "go-fuse")
CheckSuccess(err)
defer os.RemoveAll(dir)
os.Mkdir(dir+"/mnt", 0755)
os.Mkdir(dir+"/orig", 0755)
fs := NewLoopbackFileSystem(dir + "/orig")
pfs := NewPathNodeFs(fs, nil)
state, conn, err := MountNodeFileSystem(dir+"/mnt", pfs,
&FileSystemOptions{})
CheckSuccess(err)
state.Debug = VerboseTest()
conn.Debug = VerboseTest()
pfs.Debug = VerboseTest()
go state.Loop()
defer state.Unmount()
var wg sync.WaitGroup
n := 100
wg.Add(n)
var statErr os.Error
for i := 0; i < n; i++ {
go func() {
defer wg.Done()
fn := dir + "/mnt/file"
err := ioutil.WriteFile(fn, []byte{42}, 0644)
if err != nil {
statErr = err
return
}
_, err = os.Lstat(fn)
if err != nil {
statErr = err
}
}()
}
wg.Wait()
if statErr != nil {
t.Error(statErr)
}
}
...@@ -172,6 +172,7 @@ func (me *FileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) (out ...@@ -172,6 +172,7 @@ func (me *FileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) (out
// Must call GetAttr(); the filesystem may override some of // Must call GetAttr(); the filesystem may override some of
// the changes we effect here. // the changes we effect here.
fi, code := node.fsInode.GetAttr(f, &header.Context) fi, code := node.fsInode.GetAttr(f, &header.Context)
if code.Ok() { if code.Ok() {
out = node.mount.fileInfoToAttr(fi, header.NodeId) out = node.mount.fileInfoToAttr(fi, header.NodeId)
} }
......
...@@ -566,7 +566,7 @@ func (me *pathInode) GetAttr(file File, context *Context) (fi *os.FileInfo, code ...@@ -566,7 +566,7 @@ func (me *pathInode) GetAttr(file File, context *Context) (fi *os.FileInfo, code
fi, code = file.GetAttr() fi, code = file.GetAttr()
} }
if file == nil || code == ENOSYS { if file == nil || code == ENOSYS || code == EBADF {
fi, code = me.fs.GetAttr(me.GetPath(), context) fi, code = me.fs.GetAttr(me.GetPath(), context)
} }
...@@ -585,12 +585,12 @@ func (me *pathInode) Chmod(file File, perms uint32, context *Context) (code Stat ...@@ -585,12 +585,12 @@ func (me *pathInode) Chmod(file File, perms uint32, context *Context) (code Stat
for _, f := range files { for _, f := range files {
// TODO - pass context // TODO - pass context
code = f.Chmod(perms) code = f.Chmod(perms)
if !code.Ok() { if code.Ok() {
break return
} }
} }
if len(files) == 0 || code == ENOSYS { if len(files) == 0 || code == ENOSYS || code == EBADF {
code = me.fs.Chmod(me.GetPath(), perms, context) code = me.fs.Chmod(me.GetPath(), perms, context)
} }
return code return code
...@@ -601,11 +601,11 @@ func (me *pathInode) Chown(file File, uid uint32, gid uint32, context *Context) ...@@ -601,11 +601,11 @@ func (me *pathInode) Chown(file File, uid uint32, gid uint32, context *Context)
for _, f := range files { for _, f := range files {
// TODO - pass context // TODO - pass context
code = f.Chown(uid, gid) code = f.Chown(uid, gid)
if !code.Ok() { if code.Ok() {
break return code
} }
} }
if len(files) == 0 || code == ENOSYS { if len(files) == 0 || code == ENOSYS || code == EBADF {
// TODO - can we get just FATTR_GID but not FATTR_UID ? // TODO - can we get just FATTR_GID but not FATTR_UID ?
code = me.fs.Chown(me.GetPath(), uid, gid, context) code = me.fs.Chown(me.GetPath(), uid, gid, context)
} }
...@@ -617,11 +617,11 @@ func (me *pathInode) Truncate(file File, size uint64, context *Context) (code St ...@@ -617,11 +617,11 @@ func (me *pathInode) Truncate(file File, size uint64, context *Context) (code St
for _, f := range files { for _, f := range files {
// TODO - pass context // TODO - pass context
code = f.Truncate(size) code = f.Truncate(size)
if !code.Ok() { if code.Ok() {
break return code
} }
} }
if len(files) == 0 || code == ENOSYS { if len(files) == 0 || code == ENOSYS || code == EBADF {
code = me.fs.Truncate(me.GetPath(), size, context) code = me.fs.Truncate(me.GetPath(), size, context)
} }
return code return code
...@@ -632,11 +632,11 @@ func (me *pathInode) Utimens(file File, atime uint64, mtime uint64, context *Con ...@@ -632,11 +632,11 @@ func (me *pathInode) Utimens(file File, atime uint64, mtime uint64, context *Con
for _, f := range files { for _, f := range files {
// TODO - pass context // TODO - pass context
code = f.Utimens(atime, mtime) code = f.Utimens(atime, mtime)
if !code.Ok() { if code.Ok() {
break return code
} }
} }
if len(files) == 0 || code == ENOSYS { if len(files) == 0 || code == ENOSYS || code == EBADF {
code = me.fs.Utimens(me.GetPath(), atime, mtime, context) code = me.fs.Utimens(me.GetPath(), atime, mtime, context)
} }
return code return code
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment