@@ -40,11 +40,11 @@ type file struct {
4040 contentEnc * contentenc.ContentEnc
4141 // Device and inode number uniquely identify the backing file
4242 devIno DevInoStruct
43- // File header
44- header * contentenc. FileHeader
43+ // Entry in the open file map
44+ fileTableEntry * openFileEntryT
4545 // go-fuse nodefs.loopbackFile
4646 loopbackFile nodefs.File
47- // Store what the last byte was written
47+ // Store where the last byte was written
4848 lastWrittenOffset int64
4949 // The opCount is used to judge whether "lastWrittenOffset" is still
5050 // guaranteed to be correct.
@@ -60,14 +60,15 @@ func NewFile(fd *os.File, writeOnly bool, contentEnc *contentenc.ContentEnc) (no
6060 return nil , fuse .ToStatus (err )
6161 }
6262 di := DevInoFromStat (& st )
63- wlock .register (di )
63+ t := openFileMap .register (di )
6464
6565 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 ),
7172 }, fuse .OK
7273}
7374
@@ -84,44 +85,39 @@ func (f *file) InnerFile() nodefs.File {
8485func (f * file ) SetInode (n * nodefs.Inode ) {
8586}
8687
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 ) {
9191 buf := make ([]byte , contentenc .HeaderLen )
9292 _ , err := f .fd .ReadAt (buf , 0 )
9393 if err != nil {
94- return err
94+ return nil , err
9595 }
9696 h , err := contentenc .ParseHeader (buf )
9797 if err != nil {
98- return err
98+ return nil , err
9999 }
100- f .header = h
101-
102- return nil
100+ return h .ID , nil
103101}
104102
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 ) {
107107 h := contentenc .RandomHeader ()
108108 buf := h .Pack ()
109-
110109 // 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 )
112111 if err != nil {
113112 tlog .Warn .Printf ("ino%d: createHeader: prealloc failed: %s\n " , f .devIno .ino , err .Error ())
114- return err
113+ return nil , err
115114 }
116-
117115 // Actually write header
118116 _ , err = f .fd .WriteAt (buf , 0 )
119117 if err != nil {
120- return err
118+ return nil , err
121119 }
122- f .header = h
123-
124- return nil
120+ return h .ID , err
125121}
126122
127123func (f * file ) String () string {
@@ -137,25 +133,39 @@ func (f *file) String() string {
137133// Called by Read() for normal reading,
138134// by Write() and Truncate() for Read-Modify-Write
139135func (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 ()
144144 if err == io .EOF {
145+ f .fileTableEntry .IDLock .Unlock ()
145146 return nil , fuse .OK
146147 }
147148 if err != nil {
149+ f .fileTableEntry .IDLock .Unlock ()
148150 return nil , fuse .ToStatus (err )
149151 }
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 ()
150158 }
151-
159+ fileID := f . fileTableEntry . ID
152160 // Read the backing ciphertext in one go
153161 blocks := f .contentEnc .ExplodePlainRange (off , length )
154162 alignedOffset , alignedLength := blocks [0 ].JointCiphertextRange (blocks )
155163 skip := blocks [0 ].Skip
156164 tlog .Debug .Printf ("JointCiphertextRange(%d, %d) -> %d, %d, %d" , off , length , alignedOffset , alignedLength , skip )
157165 ciphertext := make ([]byte , int (alignedLength ))
158166 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 ()
159169 if err != nil && err != io .EOF {
160170 tlog .Warn .Printf ("read: ReadAt: %s" , err .Error ())
161171 return nil , fuse .ToStatus (err )
@@ -167,7 +177,7 @@ func (f *file) doRead(off uint64, length uint64) ([]byte, fuse.Status) {
167177 tlog .Debug .Printf ("ReadAt offset=%d bytes (%d blocks), want=%d, got=%d" , alignedOffset , firstBlockNo , alignedLength , n )
168178
169179 // Decrypt it
170- plaintext , err := f .contentEnc .DecryptBlocks (ciphertext , firstBlockNo , f . header . ID )
180+ plaintext , err := f .contentEnc .DecryptBlocks (ciphertext , firstBlockNo , fileID )
171181 if err != nil {
172182 curruptBlockNo := firstBlockNo + f .contentEnc .PlainOffToBlockNo (uint64 (len (plaintext )))
173183 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
223233//
224234// Empty writes do nothing and are allowed.
225235func (f * file ) doWrite (data []byte , off int64 ) (uint32 , fuse.Status ) {
226-
227236 // 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 ()
230243 if err == io .EOF {
231- err = f .createHeader ()
232-
244+ tmpID , err = f .createHeader ()
233245 }
234246 if err != nil {
247+ f .fileTableEntry .IDLock .Unlock ()
235248 return 0 , fuse .ToStatus (err )
236249 }
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 ()
237255 }
256+ fileID := f .fileTableEntry .ID
257+ defer f .fileTableEntry .IDLock .RUnlock ()
238258
239259 var written uint32
240260 status := fuse .OK
@@ -261,7 +281,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
261281
262282 // Encrypt
263283 blockOffset := b .BlockCipherOff ()
264- blockData = f .contentEnc .EncryptBlock (blockData , b .BlockNo , f . header . ID )
284+ blockData = f .contentEnc .EncryptBlock (blockData , b .BlockNo , fileID )
265285 tlog .Debug .Printf ("ino%d: Writing %d bytes to block #%d" ,
266286 f .devIno .ino , uint64 (len (blockData ))- f .contentEnc .BlockOverhead (), b .BlockNo )
267287
@@ -292,7 +312,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
292312// Stat() call is very expensive.
293313// The caller must "wlock.lock(f.devIno.ino)" otherwise this check would be racy.
294314func (f * file ) isConsecutiveWrite (off int64 ) bool {
295- opCount := atomic .LoadUint64 (& wlock .opCount )
315+ opCount := atomic .LoadUint64 (& openFileMap .opCount )
296316 return opCount == f .lastOpCount + 1 && off == f .lastWrittenOffset + 1
297317}
298318
@@ -309,8 +329,8 @@ func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) {
309329 tlog .Warn .Printf ("ino%d fh%d: Write on released file" , f .devIno .ino , f .intFd ())
310330 return 0 , fuse .EBADF
311331 }
312- wlock . lock ( f . devIno )
313- defer wlock . unlock ( f . devIno )
332+ f . fileTableEntry . writeLock . Lock ( )
333+ defer f . fileTableEntry . writeLock . Unlock ( )
314334 tlog .Debug .Printf ("ino%d: FUSE Write: offset=%d length=%d" , f .devIno .ino , off , len (data ))
315335 // If the write creates a file hole, we have to zero-pad the last block.
316336 // 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) {
323343 }
324344 n , status := f .doWrite (data , off )
325345 if status .Ok () {
326- f .lastOpCount = atomic .LoadUint64 (& wlock .opCount )
346+ f .lastOpCount = atomic .LoadUint64 (& openFileMap .opCount )
327347 f .lastWrittenOffset = off + int64 (len (data )) - 1
328348 }
329349 return n , status
@@ -339,7 +359,7 @@ func (f *file) Release() {
339359 f .released = true
340360 f .fdLock .Unlock ()
341361
342- wlock .unregister (f .devIno )
362+ openFileMap .unregister (f .devIno )
343363}
344364
345365// Flush - FUSE call
0 commit comments