Skip to content

Commit c9d56c8

Browse files
committed
fix race condition in fileget/fileput
This fixes the concurrent access/locking race in both fileget and fileput when accessing the saved readerAt/writerAt. It eliminates the dedicated functions and moves the access/locking inline where they were called to make it clearer. Thanks to Marshall Brekka (@marshallbrekka) for the original bug report and outline for the fix.
1 parent b9345f4 commit c9d56c8

File tree

1 file changed

+30
-34
lines changed

1 file changed

+30
-34
lines changed

request.go

+30-34
Original file line numberDiff line numberDiff line change
@@ -116,34 +116,12 @@ func (r *Request) lsInc(offset int64) {
116116
}
117117

118118
// manage file read/write state
119-
func (r *Request) setWriterState(wa io.WriterAt) {
120-
r.state.Lock()
121-
defer r.state.Unlock()
122-
r.state.writerAt = wa
123-
}
124-
func (r *Request) setReaderState(ra io.ReaderAt) {
125-
r.state.Lock()
126-
defer r.state.Unlock()
127-
r.state.readerAt = ra
128-
}
129119
func (r *Request) setListerState(la ListerAt) {
130120
r.state.Lock()
131121
defer r.state.Unlock()
132122
r.state.listerAt = la
133123
}
134124

135-
func (r *Request) getWriter() io.WriterAt {
136-
r.state.RLock()
137-
defer r.state.RUnlock()
138-
return r.state.writerAt
139-
}
140-
141-
func (r *Request) getReader() io.ReaderAt {
142-
r.state.RLock()
143-
defer r.state.RUnlock()
144-
return r.state.readerAt
145-
}
146-
147125
func (r *Request) getLister() ListerAt {
148126
r.state.RLock()
149127
defer r.state.RUnlock()
@@ -157,11 +135,15 @@ func (r *Request) close() error {
157135
r.cancelCtx()
158136
}
159137
}()
160-
rd := r.getReader()
138+
r.state.RLock()
139+
rd := r.state.readerAt
140+
r.state.RUnlock()
161141
if c, ok := rd.(io.Closer); ok {
162142
return c.Close()
163143
}
164-
wt := r.getWriter()
144+
r.state.RLock()
145+
wt := r.state.writerAt
146+
r.state.RUnlock()
165147
if c, ok := wt.(io.Closer); ok {
166148
return c.Close()
167149
}
@@ -204,13 +186,20 @@ func packetData(p requestPacket) (data []byte, offset int64, length uint32) {
204186
// wrap FileReader handler
205187
func fileget(h FileReader, r *Request, pkt requestPacket) responsePacket {
206188
var err error
207-
reader := r.getReader()
189+
r.state.RLock()
190+
reader := r.state.readerAt
191+
r.state.RUnlock()
208192
if reader == nil {
209-
reader, err = h.Fileread(r)
210-
if err != nil {
211-
return statusFromError(pkt, err)
193+
r.state.Lock()
194+
if r.state.readerAt == nil {
195+
r.state.readerAt, err = h.Fileread(r)
196+
if err != nil {
197+
r.state.Unlock()
198+
return statusFromError(pkt, err)
199+
}
212200
}
213-
r.setReaderState(reader)
201+
reader = r.state.readerAt
202+
r.state.Unlock()
214203
}
215204

216205
_, offset, length := packetData(pkt)
@@ -230,13 +219,20 @@ func fileget(h FileReader, r *Request, pkt requestPacket) responsePacket {
230219
// wrap FileWriter handler
231220
func fileput(h FileWriter, r *Request, pkt requestPacket) responsePacket {
232221
var err error
233-
writer := r.getWriter()
222+
r.state.RLock()
223+
writer := r.state.writerAt
224+
r.state.RUnlock()
234225
if writer == nil {
235-
writer, err = h.Filewrite(r)
236-
if err != nil {
237-
return statusFromError(pkt, err)
226+
r.state.Lock()
227+
if r.state.writerAt == nil {
228+
r.state.writerAt, err = h.Filewrite(r)
229+
if err != nil {
230+
r.state.Unlock()
231+
return statusFromError(pkt, err)
232+
}
238233
}
239-
r.setWriterState(writer)
234+
writer = r.state.writerAt
235+
r.state.Unlock()
240236
}
241237

242238
data, offset, _ := packetData(pkt)

0 commit comments

Comments
 (0)