aboutsummaryrefslogtreecommitdiff
path: root/pathfs_frontend
diff options
context:
space:
mode:
authorJakob Unterwurzacher2015-11-08 22:36:29 +0100
committerJakob Unterwurzacher2015-11-08 22:36:29 +0100
commitfa3a382aa4a2010c83e02ac65385f5388a9fc84d (patch)
tree9d2141529537409b60a00060b0b0700130242fb6 /pathfs_frontend
parent8b836656930708aaa2f7183cbaf4d8349b927e37 (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.
Diffstat (limited to 'pathfs_frontend')
-rw-r--r--pathfs_frontend/file.go19
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
}