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

Handle EBADF returns from open file attribute operations.

parent 4d28ef4b
......@@ -136,7 +136,7 @@ type FileSystem interface {
// A File object should be returned from FileSystem.Open and
// FileSystem.Create. Include DefaultFile into the struct to inherit
// a default null implementation.
// a default null implementation.
//
// TODO - should File be thread safe?
// TODO - should we pass a *Context argument?
......@@ -153,15 +153,17 @@ type File interface {
Read(*ReadIn, BufferPool) ([]byte, 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)
Chown(uid uint32, gid uint32) Status
Chmod(perms uint32) 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
......
......@@ -5,6 +5,7 @@ import (
"io/ioutil"
"log"
"os"
"sync"
"testing"
)
......@@ -138,3 +139,48 @@ func TestNonseekable(t *testing.T) {
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
// Must call GetAttr(); the filesystem may override some of
// the changes we effect here.
fi, code := node.fsInode.GetAttr(f, &header.Context)
if code.Ok() {
out = node.mount.fileInfoToAttr(fi, header.NodeId)
}
......
......@@ -566,7 +566,7 @@ func (me *pathInode) GetAttr(file File, context *Context) (fi *os.FileInfo, code
fi, code = file.GetAttr()
}
if file == nil || code == ENOSYS {
if file == nil || code == ENOSYS || code == EBADF {
fi, code = me.fs.GetAttr(me.GetPath(), context)
}
......@@ -585,12 +585,12 @@ func (me *pathInode) Chmod(file File, perms uint32, context *Context) (code Stat
for _, f := range files {
// TODO - pass context
code = f.Chmod(perms)
if !code.Ok() {
break
if code.Ok() {
return
}
}
if len(files) == 0 || code == ENOSYS {
if len(files) == 0 || code == ENOSYS || code == EBADF {
code = me.fs.Chmod(me.GetPath(), perms, context)
}
return code
......@@ -601,11 +601,11 @@ func (me *pathInode) Chown(file File, uid uint32, gid uint32, context *Context)
for _, f := range files {
// TODO - pass context
code = f.Chown(uid, gid)
if !code.Ok() {
break
if code.Ok() {
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 ?
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
for _, f := range files {
// TODO - pass context
code = f.Truncate(size)
if !code.Ok() {
break
if code.Ok() {
return code
}
}
if len(files) == 0 || code == ENOSYS {
if len(files) == 0 || code == ENOSYS || code == EBADF {
code = me.fs.Truncate(me.GetPath(), size, context)
}
return code
......@@ -632,11 +632,11 @@ func (me *pathInode) Utimens(file File, atime uint64, mtime uint64, context *Con
for _, f := range files {
// TODO - pass context
code = f.Utimens(atime, mtime)
if !code.Ok() {
break
if code.Ok() {
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)
}
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