diff options
| author | Jakob Unterwurzacher | 2015-11-08 22:36:29 +0100 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2015-11-08 22:36:29 +0100 | 
| commit | fa3a382aa4a2010c83e02ac65385f5388a9fc84d (patch) | |
| tree | 9d2141529537409b60a00060b0b0700130242fb6 | |
| parent | 8b836656930708aaa2f7183cbaf4d8349b927e37 (diff) | |
Handle ENOSPC errors better by preallocating the space before writing
Prevent the case that we run out of space in the middle of
writing a block - that would leave a corrupt block behind.
| -rw-r--r-- | pathfs_frontend/file.go | 19 | 
1 files changed, 15 insertions, 4 deletions
| diff --git a/pathfs_frontend/file.go b/pathfs_frontend/file.go index bbc211d..5c76fb1 100644 --- a/pathfs_frontend/file.go +++ b/pathfs_frontend/file.go @@ -194,6 +194,8 @@ func (f *file) Read(buf []byte, off int64) (resultData fuse.ReadResult, code fus  	return fuse.ReadResultData(out), status  } +const FALLOC_FL_KEEP_SIZE = 0x01 +  // doWrite - encrypt "data" and write it to plaintext offset "off"  //  // Arguments do not have to be block-aligned, read-modify-write is @@ -238,16 +240,25 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {  		}  		// Write -		blockOffset, _ := b.CiphertextRange() +		blockOffset, blockLen := b.CiphertextRange()  		blockData = f.cfs.EncryptBlock(blockData, b.BlockNo, f.header.Id)  		cryptfs.Debug.Printf("ino%d: Writing %d bytes to block #%d, md5=%s\n",  			f.ino, len(blockData)-cryptfs.BLOCK_OVERHEAD, b.BlockNo, cryptfs.Debug.Md5sum(blockData)) + +		// Prevent partially written (=corrupt) blocks by preallocating the space beforehand  		f.fdLock.Lock() -		_, err := f.fd.WriteAt(blockData, int64(blockOffset)) +		err := syscall.Fallocate(int(f.fd.Fd()), FALLOC_FL_KEEP_SIZE, int64(blockOffset), int64(blockLen)) +		f.fdLock.Unlock() +		if err != nil { +			cryptfs.Warn.Printf("doWrite: Fallocate failed: %s\n", err.Error()) +			status = fuse.ToStatus(err) +			break +		} +		f.fdLock.Lock() +		_, err = f.fd.WriteAt(blockData, int64(blockOffset))  		f.fdLock.Unlock() -  		if err != nil { -			cryptfs.Warn.Printf("Write failed: %s\n", err.Error()) +			cryptfs.Warn.Printf("doWrite: Write failed: %s\n", err.Error())  			status = fuse.ToStatus(err)  			break  		} | 
