diff --git a/cmd/olliesrv/server.go b/cmd/olliesrv/server.go index 203d835..3f99889 100644 --- a/cmd/olliesrv/server.go +++ b/cmd/olliesrv/server.go @@ -562,7 +562,9 @@ func read(root *fs.Tree, cs *connState, fc *plan9.Fcall, ctx context.Context) *p f, fidOK := cs.fids[fc.Fid] var base string if fidOK { + f.mu.Lock() base = f.waitBase + f.mu.Unlock() } cs.mu.RUnlock() waitCtx, waitCancel := context.WithTimeout(ctx, 5*time.Second) @@ -595,7 +597,9 @@ func read(root *fs.Tree, cs *connState, fc *plan9.Fcall, ctx context.Context) *p f, fidOK := cs.fids[fc.Fid] var base string if fidOK { + f.mu.Lock() base = f.waitBase + f.mu.Unlock() } cs.mu.RUnlock() waitCtx, waitCancel := context.WithCancel(ctx) @@ -683,24 +687,28 @@ func write(cs *connState, fc *plan9.Fcall) *plan9.Fcall { cs.mu.Unlock() return errFcall(fc, "bad fid") } - - if f.entry != nil && f.entry.RdwrMode() { - f.readCache = nil // clear cached response for next read - cs.mu.Unlock() - if err := f.entry.Write(fc.Data); err != nil { - return errFcall(fc, err.Error()) + f.mu.Lock() + entry := f.entry + if entry != nil && entry.RdwrMode() { + f.readCache = nil + } + if entry == nil || !entry.RdwrMode() { + end := int(fc.Offset) + len(fc.Data) + if end > len(f.writeBuf) { + grown := make([]byte, end) + copy(grown, f.writeBuf) + f.writeBuf = grown } + copy(f.writeBuf[fc.Offset:], fc.Data) + f.mu.Unlock() + cs.mu.Unlock() return &plan9.Fcall{Type: plan9.Rwrite, Tag: fc.Tag, Count: uint32(len(fc.Data))} } - - end := int(fc.Offset) + len(fc.Data) - if end > len(f.writeBuf) { - grown := make([]byte, end) - copy(grown, f.writeBuf) - f.writeBuf = grown - } - copy(f.writeBuf[fc.Offset:], fc.Data) + f.mu.Unlock() cs.mu.Unlock() + if err := entry.Write(fc.Data); err != nil { + return errFcall(fc, err.Error()) + } return &plan9.Fcall{Type: plan9.Rwrite, Tag: fc.Tag, Count: uint32(len(fc.Data))} } @@ -711,13 +719,16 @@ func stat(root *fs.Tree, cs *connState, fc *plan9.Fcall) *plan9.Fcall { if !ok { return errFcall(fc, "bad fid") } - if _, err := root.Stat(f.path[1:]); err != nil { + f.mu.Lock() + path := f.path + f.mu.Unlock() + if _, err := root.Stat(path[1:]); err != nil { cs.mu.Lock() delete(cs.fids, fc.Fid) cs.mu.Unlock() return errFcall(fc, "file not found") } - dir := makeStat(root, f.path) + dir := makeStat(root, path) stat, err := dir.Bytes() if err != nil { return errFcall(fc, err.Error()) @@ -736,22 +747,29 @@ func wstat(root *fs.Tree, cs *connState, fc *plan9.Fcall) *plan9.Fcall { if err != nil { return &plan9.Fcall{Type: plan9.Rwstat, Tag: fc.Tag} } - oldName := pathBase(f.path) + f.mu.Lock() + path := f.path + f.mu.Unlock() + oldName := pathBase(path) if newDir.Name == "" || newDir.Name == oldName { return &plan9.Fcall{Type: plan9.Rwstat, Tag: fc.Tag} } - if err := root.Rename(f.path[1:], newDir.Name); err != nil { + if err := root.Rename(path[1:], newDir.Name); err != nil { return errFcall(fc, err.Error()) } // GC stale fids on this connection referencing the old path - oldPrefix := f.path + oldPrefix := path var stale []fs.File cs.mu.Lock() for id, fid := range cs.fids { - if fid.path == oldPrefix || strings.HasPrefix(fid.path, oldPrefix+"/") { + fid.mu.Lock() + fidPath := fid.path + entry := fid.entry + fid.mu.Unlock() + if fidPath == oldPrefix || strings.HasPrefix(fidPath, oldPrefix+"/") { delete(cs.fids, id) - if fid.entry != nil { - stale = append(stale, fid.entry) + if entry != nil { + stale = append(stale, entry) } } } @@ -770,20 +788,28 @@ func clunk(root *fs.Tree, cs *connState, fc *plan9.Fcall) *plan9.Fcall { var writable bool var isRequest bool if ok { - if m := f.mode & 3; m == plan9.OWRITE || m == plan9.ORDWR { - path = f.path + f.mu.Lock() + mode := f.mode + path = f.path + data = append([]byte(nil), f.writeBuf...) + entry := f.entry + if mode&3 == plan9.OWRITE || mode&3 == plan9.ORDWR { writable = true - data = make([]byte, len(f.writeBuf)) - copy(data, f.writeBuf) - if f.entry != nil { - isRequest = f.entry.RdwrMode() + if entry != nil { + isRequest = entry.RdwrMode() } } + f.mu.Unlock() delete(cs.fids, fc.Fid) } cs.mu.Unlock() - if f != nil && f.entry != nil { - _ = f.entry.Close() + if f != nil { + f.mu.Lock() + entry := f.entry + f.mu.Unlock() + if entry != nil { + _ = entry.Close() + } } if writable && !isRequest { input := strings.TrimSpace(string(data)) @@ -805,16 +831,21 @@ func remove(root *fs.Tree, cs *connState, fc *plan9.Fcall) *plan9.Fcall { delete(cs.fids, fc.Fid) } cs.mu.Unlock() - if ok && f.entry != nil { - _ = f.entry.Close() + var entry fs.File + if ok { + f.mu.Lock() + entry = f.entry + path := f.path + f.mu.Unlock() + if entry != nil { + _ = entry.Close() + } + if err := root.Delete(path[1:]); err != nil { + return errFcall(fc, err.Error()) + } + return &plan9.Fcall{Type: plan9.Rremove, Tag: fc.Tag} } - if !ok { - return errFcall(fc, "bad fid") - } - if err := root.Delete(f.path[1:]); err != nil { - return errFcall(fc, err.Error()) - } - return &plan9.Fcall{Type: plan9.Rremove, Tag: fc.Tag} + return errFcall(fc, "bad fid") } func (s *Server) Kill() {