@@ -40,11 +40,11 @@ type file struct {
4040contentEnc * contentenc.ContentEnc
4141// Device and inode number uniquely identify the backing file
4242devIno DevInoStruct
43- //File header
44- header * contentenc. FileHeader
43+ //Entry in the open file map
44+ fileTableEntry * openFileEntryT
4545// go-fuse nodefs.loopbackFile
4646loopbackFile nodefs.File
47- // Storewhat the last byte was written
47+ // Storewhere the last byte was written
4848lastWrittenOffset 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
6060return nil ,fuse .ToStatus (err )
6161}
6262di := DevInoFromStat (& st )
63- wlock .register (di )
63+ t := openFileMap .register (di )
6464
6565return & 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 ) {
9191buf := make ([]byte ,contentenc .HeaderLen )
9292_ ,err := f .fd .ReadAt (buf ,0 )
9393if err != nil {
94- return err
94+ return nil , err
9595}
9696h ,err := contentenc .ParseHeader (buf )
9797if 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 ) {
107107h := contentenc .RandomHeader ()
108108buf := 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 )
112111if err != nil {
113112tlog .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 )
119117if 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 ()
144144if err == io .EOF {
145+ f .fileTableEntry .IDLock .Unlock ()
145146return nil ,fuse .OK
146147}
147148if err != nil {
149+ f .fileTableEntry .IDLock .Unlock ()
148150return 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
153161blocks := f .contentEnc .ExplodePlainRange (off ,length )
154162alignedOffset ,alignedLength := blocks [0 ].JointCiphertextRange (blocks )
155163skip := blocks [0 ].Skip
156164tlog .Debug .Printf ("JointCiphertextRange(%d, %d) -> %d, %d, %d" ,off ,length ,alignedOffset ,alignedLength ,skip )
157165ciphertext := make ([]byte ,int (alignedLength ))
158166n ,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 ()
159169if err != nil && err != io .EOF {
160170tlog .Warn .Printf ("read: ReadAt: %s" ,err .Error ())
161171return nil ,fuse .ToStatus (err )
@@ -167,7 +177,7 @@ func (f *file) doRead(off uint64, length uint64) ([]byte, fuse.Status) {
167177tlog .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 )
171181if err != nil {
172182curruptBlockNo := firstBlockNo + f .contentEnc .PlainOffToBlockNo (uint64 (len (plaintext )))
173183tlog .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 ()
230243if err == io .EOF {
231- err = f .createHeader ()
232-
244+ tmpID ,err = f .createHeader ()
233245}
234246if err != nil {
247+ f .fileTableEntry .IDLock .Unlock ()
235248return 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
239259var written uint32
240260status := fuse .OK
@@ -261,7 +281,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
261281
262282// Encrypt
263283blockOffset := b .BlockCipherOff ()
264- blockData = f .contentEnc .EncryptBlock (blockData ,b .BlockNo ,f . header . ID )
284+ blockData = f .contentEnc .EncryptBlock (blockData ,b .BlockNo ,fileID )
265285tlog .Debug .Printf ("ino%d: Writing %d bytes to block #%d" ,
266286f .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 )
296316return 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) {
309329tlog .Warn .Printf ("ino%d fh%d: Write on released file" ,f .devIno .ino ,f .intFd ())
310330return 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 ( )
314334tlog .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}
324344n ,status := f .doWrite (data ,off )
325345if status .Ok () {
326- f .lastOpCount = atomic .LoadUint64 (& wlock .opCount )
346+ f .lastOpCount = atomic .LoadUint64 (& openFileMap .opCount )
327347f .lastWrittenOffset = off + int64 (len (data ))- 1
328348}
329349return n ,status
@@ -339,7 +359,7 @@ func (f *file) Release() {
339359f .released = true
340360f .fdLock .Unlock ()
341361
342- wlock .unregister (f .devIno )
362+ openFileMap .unregister (f .devIno )
343363}
344364
345365// Flush - FUSE call