@@ -40,11 +40,11 @@ type file struct {
40
40
contentEnc * contentenc.ContentEnc
41
41
// Device and inode number uniquely identify the backing file
42
42
devIno DevInoStruct
43
- // File header
44
- header * contentenc. FileHeader
43
+ // Entry in the open file map
44
+ fileTableEntry * openFileEntryT
45
45
// go-fuse nodefs.loopbackFile
46
46
loopbackFile nodefs.File
47
- // Store what the last byte was written
47
+ // Store where the last byte was written
48
48
lastWrittenOffset int64
49
49
// The opCount is used to judge whether "lastWrittenOffset" is still
50
50
// guaranteed to be correct.
@@ -60,14 +60,15 @@ func NewFile(fd *os.File, writeOnly bool, contentEnc *contentenc.ContentEnc) (no
60
60
return nil , fuse .ToStatus (err )
61
61
}
62
62
di := DevInoFromStat (& st )
63
- wlock .register (di )
63
+ t := openFileMap .register (di )
64
64
65
65
return & file {
66
- fd : fd ,
67
- writeOnly : writeOnly ,
68
- contentEnc : contentEnc ,
69
- devIno : di ,
70
- loopbackFile : nodefs .NewLoopbackFile (fd ),
66
+ fd : fd ,
67
+ writeOnly : writeOnly ,
68
+ contentEnc : contentEnc ,
69
+ devIno : di ,
70
+ fileTableEntry : t ,
71
+ loopbackFile : nodefs .NewLoopbackFile (fd ),
71
72
}, fuse .OK
72
73
}
73
74
@@ -84,44 +85,39 @@ func (f *file) InnerFile() nodefs.File {
84
85
func (f * file ) SetInode (n * nodefs.Inode ) {
85
86
}
86
87
87
- // readHeader - load the file header from disk
88
- //
89
- // Returns io.EOF if the file is empty
90
- func (f * file ) readHeader () error {
88
+ // readFileID loads the file header from disk and extracts the file ID.
89
+ // Returns io.EOF if the file is empty.
90
+ func (f * file ) readFileID () ([]byte , error ) {
91
91
buf := make ([]byte , contentenc .HeaderLen )
92
92
_ , err := f .fd .ReadAt (buf , 0 )
93
93
if err != nil {
94
- return err
94
+ return nil , err
95
95
}
96
96
h , err := contentenc .ParseHeader (buf )
97
97
if err != nil {
98
- return err
98
+ return nil , err
99
99
}
100
- f .header = h
101
-
102
- return nil
100
+ return h .ID , nil
103
101
}
104
102
105
- // createHeader - create a new random header and write it to disk
106
- func (f * file ) createHeader () error {
103
+ // createHeader creates a new random header and writes it to disk.
104
+ // Returns the new file ID.
105
+ // The caller must hold fileIDLock.Lock().
106
+ func (f * file ) createHeader () (fileID []byte , err error ) {
107
107
h := contentenc .RandomHeader ()
108
108
buf := h .Pack ()
109
-
110
109
// Prevent partially written (=corrupt) header by preallocating the space beforehand
111
- err : = syscallcompat .EnospcPrealloc (int (f .fd .Fd ()), 0 , contentenc .HeaderLen )
110
+ err = syscallcompat .EnospcPrealloc (int (f .fd .Fd ()), 0 , contentenc .HeaderLen )
112
111
if err != nil {
113
112
tlog .Warn .Printf ("ino%d: createHeader: prealloc failed: %s\n " , f .devIno .ino , err .Error ())
114
- return err
113
+ return nil , err
115
114
}
116
-
117
115
// Actually write header
118
116
_ , err = f .fd .WriteAt (buf , 0 )
119
117
if err != nil {
120
- return err
118
+ return nil , err
121
119
}
122
- f .header = h
123
-
124
- return nil
120
+ return h .ID , err
125
121
}
126
122
127
123
func (f * file ) String () string {
@@ -137,25 +133,39 @@ func (f *file) String() string {
137
133
// Called by Read() for normal reading,
138
134
// by Write() and Truncate() for Read-Modify-Write
139
135
func (f * file ) doRead (off uint64 , length uint64 ) ([]byte , fuse.Status ) {
140
-
141
- // Read file header
142
- if f .header == nil {
143
- err := f .readHeader ()
136
+ // Make sure we have the file ID.
137
+ f .fileTableEntry .IDLock .RLock ()
138
+ if f .fileTableEntry .ID == nil {
139
+ f .fileTableEntry .IDLock .RUnlock ()
140
+ // Yes, somebody else may take the lock before we can. This will get
141
+ // the header read twice, but causes no harm otherwise.
142
+ f .fileTableEntry .IDLock .Lock ()
143
+ tmpID , err := f .readFileID ()
144
144
if err == io .EOF {
145
+ f .fileTableEntry .IDLock .Unlock ()
145
146
return nil , fuse .OK
146
147
}
147
148
if err != nil {
149
+ f .fileTableEntry .IDLock .Unlock ()
148
150
return nil , fuse .ToStatus (err )
149
151
}
152
+ f .fileTableEntry .ID = tmpID
153
+ // Downgrade the lock.
154
+ f .fileTableEntry .IDLock .Unlock ()
155
+ // The file ID may change in here. This does no harm because we
156
+ // re-read it after the RLock().
157
+ f .fileTableEntry .IDLock .RLock ()
150
158
}
151
-
159
+ fileID := f . fileTableEntry . ID
152
160
// Read the backing ciphertext in one go
153
161
blocks := f .contentEnc .ExplodePlainRange (off , length )
154
162
alignedOffset , alignedLength := blocks [0 ].JointCiphertextRange (blocks )
155
163
skip := blocks [0 ].Skip
156
164
tlog .Debug .Printf ("JointCiphertextRange(%d, %d) -> %d, %d, %d" , off , length , alignedOffset , alignedLength , skip )
157
165
ciphertext := make ([]byte , int (alignedLength ))
158
166
n , err := f .fd .ReadAt (ciphertext , int64 (alignedOffset ))
167
+ // We don't care if the file ID changes after we have read the data. Drop the lock.
168
+ f .fileTableEntry .IDLock .RUnlock ()
159
169
if err != nil && err != io .EOF {
160
170
tlog .Warn .Printf ("read: ReadAt: %s" , err .Error ())
161
171
return nil , fuse .ToStatus (err )
@@ -167,7 +177,7 @@ func (f *file) doRead(off uint64, length uint64) ([]byte, fuse.Status) {
167
177
tlog .Debug .Printf ("ReadAt offset=%d bytes (%d blocks), want=%d, got=%d" , alignedOffset , firstBlockNo , alignedLength , n )
168
178
169
179
// Decrypt it
170
- plaintext , err := f .contentEnc .DecryptBlocks (ciphertext , firstBlockNo , f . header . ID )
180
+ plaintext , err := f .contentEnc .DecryptBlocks (ciphertext , firstBlockNo , fileID )
171
181
if err != nil {
172
182
curruptBlockNo := firstBlockNo + f .contentEnc .PlainOffToBlockNo (uint64 (len (plaintext )))
173
183
tlog .Warn .Printf ("ino%d: doRead: corrupt block #%d: %v" , f .devIno .ino , curruptBlockNo , err )
@@ -223,18 +233,28 @@ func (f *file) Read(buf []byte, off int64) (resultData fuse.ReadResult, code fus
223
233
//
224
234
// Empty writes do nothing and are allowed.
225
235
func (f * file ) doWrite (data []byte , off int64 ) (uint32 , fuse.Status ) {
226
-
227
236
// Read header from disk, create a new one if the file is empty
228
- if f .header == nil {
229
- err := f .readHeader ()
237
+ f .fileTableEntry .IDLock .RLock ()
238
+ if f .fileTableEntry .ID == nil {
239
+ f .fileTableEntry .IDLock .RUnlock ()
240
+ // Somebody else may write the header here, but this would do no harm.
241
+ f .fileTableEntry .IDLock .Lock ()
242
+ tmpID , err := f .readFileID ()
230
243
if err == io .EOF {
231
- err = f .createHeader ()
232
-
244
+ tmpID , err = f .createHeader ()
233
245
}
234
246
if err != nil {
247
+ f .fileTableEntry .IDLock .Unlock ()
235
248
return 0 , fuse .ToStatus (err )
236
249
}
250
+ f .fileTableEntry .ID = tmpID
251
+ f .fileTableEntry .IDLock .Unlock ()
252
+ // The file ID may change in here. This does no harm because we
253
+ // re-read it after the RLock().
254
+ f .fileTableEntry .IDLock .RLock ()
237
255
}
256
+ fileID := f .fileTableEntry .ID
257
+ defer f .fileTableEntry .IDLock .RUnlock ()
238
258
239
259
var written uint32
240
260
status := fuse .OK
@@ -261,7 +281,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
261
281
262
282
// Encrypt
263
283
blockOffset := b .BlockCipherOff ()
264
- blockData = f .contentEnc .EncryptBlock (blockData , b .BlockNo , f . header . ID )
284
+ blockData = f .contentEnc .EncryptBlock (blockData , b .BlockNo , fileID )
265
285
tlog .Debug .Printf ("ino%d: Writing %d bytes to block #%d" ,
266
286
f .devIno .ino , uint64 (len (blockData ))- f .contentEnc .BlockOverhead (), b .BlockNo )
267
287
@@ -292,7 +312,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
292
312
// Stat() call is very expensive.
293
313
// The caller must "wlock.lock(f.devIno.ino)" otherwise this check would be racy.
294
314
func (f * file ) isConsecutiveWrite (off int64 ) bool {
295
- opCount := atomic .LoadUint64 (& wlock .opCount )
315
+ opCount := atomic .LoadUint64 (& openFileMap .opCount )
296
316
return opCount == f .lastOpCount + 1 && off == f .lastWrittenOffset + 1
297
317
}
298
318
@@ -309,8 +329,8 @@ func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) {
309
329
tlog .Warn .Printf ("ino%d fh%d: Write on released file" , f .devIno .ino , f .intFd ())
310
330
return 0 , fuse .EBADF
311
331
}
312
- wlock . lock ( f . devIno )
313
- defer wlock . unlock ( f . devIno )
332
+ f . fileTableEntry . writeLock . Lock ( )
333
+ defer f . fileTableEntry . writeLock . Unlock ( )
314
334
tlog .Debug .Printf ("ino%d: FUSE Write: offset=%d length=%d" , f .devIno .ino , off , len (data ))
315
335
// If the write creates a file hole, we have to zero-pad the last block.
316
336
// But if the write directly follows an earlier write, it cannot create a
@@ -323,7 +343,7 @@ func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) {
323
343
}
324
344
n , status := f .doWrite (data , off )
325
345
if status .Ok () {
326
- f .lastOpCount = atomic .LoadUint64 (& wlock .opCount )
346
+ f .lastOpCount = atomic .LoadUint64 (& openFileMap .opCount )
327
347
f .lastWrittenOffset = off + int64 (len (data )) - 1
328
348
}
329
349
return n , status
@@ -339,7 +359,7 @@ func (f *file) Release() {
339
359
f .released = true
340
360
f .fdLock .Unlock ()
341
361
342
- wlock .unregister (f .devIno )
362
+ openFileMap .unregister (f .devIno )
343
363
}
344
364
345
365
// Flush - FUSE call
0 commit comments