diff --git a/dir.go b/dir.go index c3f1936..9aaffec 100644 --- a/dir.go +++ b/dir.go @@ -26,6 +26,7 @@ import ( "errors" "os" "path" + "sync" "bazil.org/fuse" "bazil.org/fuse/fs" @@ -42,22 +43,23 @@ type verDir struct { node *verNode inode uint64 parent *verDir + mutex sync.Mutex } func newVerDir(node *verNode, parent *verDir) *verDir { dirs := make(map[string]*verDir) files := make(map[string]*verFile) + mutex := sync.Mutex{} - return &verDir{dirs, files, node, allocInode(), parent} + return &verDir{dirs, files, node, allocInode(), parent, mutex} } func (vd *verDir) version() error { - if vd.node.flags&NodeFlagVer == NodeFlagVer { + if vd.node.flags&NodeFlagNew == NodeFlagNew { return nil } - node := newVerNode(vd.node.path, vd.node.ver.db.lastVersion(), vd.node, NodeFlagDir|NodeFlagVer) - + node := newVerNode(vd.node.path, vd.node.ver.db.lastVersion(), vd.node, NodeFlagDir|NodeFlagNew) if err := os.MkdirAll(node.rebasedPath(), 0755); err != nil { return err } @@ -78,7 +80,7 @@ func (vd *verDir) createDir(name string) (*verDir, error) { return nil, err } - node := newVerNode(childPath, vd.node.ver, nil, NodeFlagDir|NodeFlagVer) + node := newVerNode(childPath, vd.node.ver, nil, NodeFlagDir|NodeFlagNew) dir := newVerDir(node, vd) vd.dirs[name] = dir node.ver.meta.createNode(node.path) @@ -86,24 +88,24 @@ func (vd *verDir) createDir(name string) (*verDir, error) { return dir, nil } -func (vd *verDir) createFile(name string, flags fuse.OpenFlags, mode os.FileMode) (*verFile, *verFileHandle, error) { +func (vd *verDir) createFile(name string, flags fuse.OpenFlags, mode os.FileMode) (*verFile, *verFileHandle, fuse.HandleID, error) { if err := vd.version(); err != nil { - return nil, nil, err + return nil, nil, 0, err } childPath := path.Join(vd.node.path, name) - node := newVerNode(childPath, vd.node.ver, nil, NodeFlagVer) + node := newVerNode(childPath, vd.node.ver, nil, NodeFlagNew) file := newVerFile(node, vd) - handle, err := file.open(flags, mode) + handle, id, err := file.open(flags, mode) if err != nil { - return nil, nil, err + return nil, nil, 0, err } vd.files[name] = file node.ver.meta.createNode(node.path) - return file, handle, nil + return file, handle, id, nil } // Node @@ -129,11 +131,14 @@ func (vd *verDir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *f // NodeCreater func (vd *verDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (node fs.Node, handle fs.Handle, err error) { + vd.mutex.Lock() + defer vd.mutex.Unlock() + if req.Mode.IsDir() { node, err = vd.createDir(req.Name) handle = node } else if req.Mode.IsRegular() { - node, handle, err = vd.createFile(req.Name, req.Flags, req.Mode) + node, handle, resp.Handle, err = vd.createFile(req.Name, req.Flags, req.Mode) } else { err = errors.New("unsupported filetype") } @@ -143,16 +148,22 @@ func (vd *verDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fus // NodeMkdirer func (vd *verDir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) { + vd.mutex.Lock() + defer vd.mutex.Unlock() + return vd.createDir(req.Name) } // NodeRemover func (vd *verDir) Remove(ctx context.Context, req *fuse.RemoveRequest) error { + vd.mutex.Lock() + defer vd.mutex.Unlock() + if req.Dir { node := vd.dirs[req.Name].node ver := node.ver - if node.flags&NodeFlagVer == NodeFlagVer { + if node.flags&NodeFlagNew == NodeFlagNew { if err := os.Remove(node.rebasedPath()); err != nil { return err } @@ -166,7 +177,7 @@ func (vd *verDir) Remove(ctx context.Context, req *fuse.RemoveRequest) error { node := vd.files[req.Name].node ver := node.ver - if node.flags&NodeFlagVer == NodeFlagVer { + if node.flags&NodeFlagNew == NodeFlagNew { if err := os.Remove(node.rebasedPath()); err != nil { return err } @@ -183,6 +194,9 @@ func (vd *verDir) Remove(ctx context.Context, req *fuse.RemoveRequest) error { // NodeRequestLookuper func (vd *verDir) Lookup(ctx context.Context, name string) (fs.Node, error) { + vd.mutex.Lock() + defer vd.mutex.Unlock() + if dir, ok := vd.dirs[name]; ok { return dir, nil } @@ -196,6 +210,9 @@ func (vd *verDir) Lookup(ctx context.Context, name string) (fs.Node, error) { // HandleReadDirAller func (vd *verDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { + vd.mutex.Lock() + defer vd.mutex.Unlock() + entries := []fuse.Dirent{{Inode: vd.inode, Name: ".", Type: fuse.DT_Dir}} if vd.parent != nil { entry := fuse.Dirent{Inode: vd.parent.inode, Name: "..", Type: fuse.DT_Dir} diff --git a/file.go b/file.go index 0ba07d1..68ddd22 100644 --- a/file.go +++ b/file.go @@ -24,6 +24,7 @@ package main import ( "os" + "sync" "bazil.org/fuse" "bazil.org/fuse/fs" @@ -34,24 +35,28 @@ import ( // verFile // +type handleMap map[fuse.HandleID]*verFileHandle + type verFile struct { node *verNode inode uint64 parent *verDir - handles map[uint64]*verFileHandle + handles handleMap + mutex sync.Mutex } func newVerFile(node *verNode, parent *verDir) *verFile { - return &verFile{node, allocInode(), parent, make(map[uint64]*verFileHandle)} + handles := make(handleMap) + mutex := sync.Mutex{} + return &verFile{node, allocInode(), parent, handles, mutex} } func (vf *verFile) version() error { - if vf.node.flags&NodeFlagVer == NodeFlagVer { + if vf.node.flags&NodeFlagNew == NodeFlagNew { return nil } - node := newVerNode(vf.node.path, vf.node.ver.db.lastVersion(), vf.node, NodeFlagVer) - + node := newVerNode(vf.node.path, vf.node.ver.db.lastVersion(), vf.node, NodeFlagNew) if _, err := copyFile(vf.node.rebasedPath(), node.rebasedPath()); err != nil { return err } @@ -62,10 +67,13 @@ func (vf *verFile) version() error { return nil } -func (vf *verFile) open(flags fuse.OpenFlags, mode os.FileMode) (*verFileHandle, error) { +func (vf *verFile) open(flags fuse.OpenFlags, mode os.FileMode) (*verFileHandle, fuse.HandleID, error) { + vf.mutex.Lock() + defer vf.mutex.Unlock() + if !flags.IsReadOnly() { if err := vf.version(); err != nil { - return nil, err + return nil, 0, err } } @@ -73,18 +81,20 @@ func (vf *verFile) open(flags fuse.OpenFlags, mode os.FileMode) (*verFileHandle, handle, err := os.OpenFile(path, int(flags), mode) if err != nil { - return nil, err + return nil, 0, err } id := allocHandleId() - verHandle := &verFileHandle{vf, path, handle, id} + verHandle := &verFileHandle{vf, path, handle} vf.handles[id] = verHandle - return verHandle, nil + return verHandle, id, nil } -func (vf *verFile) release(handle uint64) { +func (vf *verFile) release(handle fuse.HandleID) { + vf.mutex.Lock() delete(vf.handles, handle) + vf.mutex.Unlock() } // Node @@ -106,23 +116,20 @@ func (vf *verFile) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp * // NodeOpener func (vf *verFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) { - handle, err := vf.open(req.Flags, 0644) + handle, id, err := vf.open(req.Flags, 0644) if err != nil { return nil, err } + resp.Handle = id return handle, nil } // NodeFsyncer func (vf *verFile) Fsync(ctx context.Context, req *fuse.FsyncRequest) error { - for _, vfh := range vf.handles { - if err := vfh.handle.Sync(); err != nil { - return err - } - } - - return nil + vf.mutex.Lock() + defer vf.mutex.Unlock() + return vf.handles[req.Handle].handle.Sync() } // @@ -133,7 +140,6 @@ type verFileHandle struct { node *verFile path string handle *os.File - id uint64 } // HandleReader @@ -177,6 +183,6 @@ func (vfh *verFileHandle) Release(ctx context.Context, req *fuse.ReleaseRequest) vfh.handle.Close() vfh.handle = nil - vfh.node.release(vfh.id) + vfh.node.release(req.Handle) return nil } diff --git a/node.go b/node.go index afd06c7..6e30c0d 100644 --- a/node.go +++ b/node.go @@ -36,7 +36,7 @@ import ( const ( NodeFlagDir = 1 << iota - NodeFlagVer + NodeFlagNew ) type verNode struct { diff --git a/util.go b/util.go index 9950607..68c2441 100644 --- a/util.go +++ b/util.go @@ -32,6 +32,8 @@ import ( "strconv" "sync/atomic" "time" + + "bazil.org/fuse" ) var inodeCnt, handleCnt uint64 @@ -40,8 +42,8 @@ func allocInode() uint64 { return atomic.AddUint64(&inodeCnt, 1) } -func allocHandleId() uint64 { - return atomic.AddUint64(&handleCnt, 1) +func allocHandleId() fuse.HandleID { + return fuse.HandleID(atomic.AddUint64(&handleCnt, 1)) } func copyFile(src, dst string) (int64, error) {