From fa3a382aa4a2010c83e02ac65385f5388a9fc84d Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sun, 8 Nov 2015 22:36:29 +0100 Subject: 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. --- pathfs_frontend/file.go | 19 +++++++++++++++---- 1 file 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 } -- cgit v1.2.3