diff options
| author | Jakob Unterwurzacher | 2015-11-29 21:41:38 +0100 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2015-11-29 21:41:38 +0100 | 
| commit | 20b058a33335f48812864513cc13ea0a276aaaa3 (patch) | |
| tree | 60baeaf7f3fe89e896a3a84a934079769d865215 | |
| parent | 1d0a442405e8fc7a0742a8f8db2ea0f874f750a5 (diff) | |
Add single-element cache for DirIV lookup
Another 3x performance boost for applications that walk the
directory tree.
Excerpt from performance.txt:
VERSION         UNTAR    LS     RM
v0.4               48     1.5    5
v0.5-rc1           56     7     19
v0.5-rc1-1         54     4.1    9
v0.5-rc1-2         45     1.7	 3.4  <---- THIS VERSION
| -rw-r--r-- | cryptfs/cryptfs.go | 2 | ||||
| -rw-r--r-- | cryptfs/kdf.go | 6 | ||||
| -rw-r--r-- | cryptfs/names_diriv.go | 59 | ||||
| -rw-r--r-- | pathfs_frontend/fs.go | 13 | ||||
| -rw-r--r-- | performance.txt | 1 | 
5 files changed, 74 insertions, 7 deletions
diff --git a/cryptfs/cryptfs.go b/cryptfs/cryptfs.go index 63febc3..df04973 100644 --- a/cryptfs/cryptfs.go +++ b/cryptfs/cryptfs.go @@ -26,6 +26,8 @@ type CryptFS struct {  	// Stores an all-zero block of size cipherBS  	allZeroBlock   []byte  	plaintextNames bool +	// DirIV cache for filename encryption +	DirIVCacheEnc DirIVCache  }  func NewCryptFS(key []byte, useOpenssl bool, plaintextNames bool) *CryptFS { diff --git a/cryptfs/kdf.go b/cryptfs/kdf.go index 73be0bb..db08500 100644 --- a/cryptfs/kdf.go +++ b/cryptfs/kdf.go @@ -1,10 +1,10 @@  package cryptfs  import ( -	"os" -	"math"  	"fmt"  	"golang.org/x/crypto/scrypt" +	"math" +	"os"  )  const ( @@ -50,5 +50,5 @@ func (s *scryptKdf) DeriveKey(pw string) []byte {  // LogN - N is saved as 2^LogN, but LogN is much easier to work with.  // This function gives you LogN = Log2(N).  func (s *scryptKdf) LogN() int { -	return int(math.Log2(float64(s.N))+0.5) +	return int(math.Log2(float64(s.N)) + 0.5)  } diff --git a/cryptfs/names_diriv.go b/cryptfs/names_diriv.go index ae8545b..9012e48 100644 --- a/cryptfs/names_diriv.go +++ b/cryptfs/names_diriv.go @@ -5,8 +5,47 @@ import (  	"io/ioutil"  	"path/filepath"  	"strings" +	"sync"  ) +// A simple one-entry DirIV cache +type DirIVCache struct { +	// Invalidated? +	cleared       bool +	// The DirIV +	iv            []byte +	// Directory the DirIV belongs to +	dir           string +	// Ecrypted version of "dir" +	translatedDir string +	// Synchronisation +	lock          sync.RWMutex +} + +func (c *DirIVCache) lookup(dir string) (bool, []byte, string) { +	c.lock.RLock() +	defer c.lock.RUnlock() +	if !c.cleared && c.dir == dir { +		return true, c.iv, c.translatedDir +	} +	return false, nil, "" +} + +func (c *DirIVCache) store(dir string, iv []byte, translatedDir string) { +	c.lock.Lock() +	defer c.lock.Unlock() +	c.cleared = false +	c.iv = iv +	c.dir = dir +	c.translatedDir = translatedDir +} + +func (c *DirIVCache) Clear() { +	c.lock.Lock() +	defer c.lock.Unlock() +	c.cleared = true +} +  // readDirIV - read the "gocryptfs.diriv" file from "dir" (absolute ciphertext path)  func (be *CryptFS) ReadDirIV(dir string) (iv []byte, err error) {  	ivfile := filepath.Join(dir, DIRIV_FILENAME) @@ -41,11 +80,23 @@ func (be *CryptFS) EncryptPathDirIV(plainPath string, rootDir string) (string, e  	if plainPath == "" {  		return plainPath, nil  	} +	// Check if the DirIV is cached +	parentDir := filepath.Dir(plainPath) +	found, iv, cParentDir := be.DirIVCacheEnc.lookup(parentDir) +	if found { +		//fmt.Print("h") +		baseName := filepath.Base(plainPath) +		cBaseName := be.encryptName(baseName, iv) +		cPath := cParentDir + "/" + cBaseName +		return cPath, nil +	} +	// Walk the directory tree  	var wd = rootDir  	var encryptedNames []string +	var err error  	plainNames := strings.Split(plainPath, "/")  	for _, plainName := range plainNames { -		iv, err := be.ReadDirIV(wd) +		iv, err = be.ReadDirIV(wd)  		if err != nil {  			return "", err  		} @@ -53,7 +104,11 @@ func (be *CryptFS) EncryptPathDirIV(plainPath string, rootDir string) (string, e  		encryptedNames = append(encryptedNames, encryptedName)  		wd = filepath.Join(wd, encryptedName)  	} -	return filepath.Join(encryptedNames...), nil +	// Cache the final DirIV +	cPath := strings.Join(encryptedNames, "/") +	cParentDir = filepath.Dir(cPath) +	be.DirIVCacheEnc.store(parentDir, iv, cParentDir) +	return cPath, nil  }  // DecryptPathDirIV - encrypt path using CBC with DirIV diff --git a/pathfs_frontend/fs.go b/pathfs_frontend/fs.go index fe9a8b0..736e5dc 100644 --- a/pathfs_frontend/fs.go +++ b/pathfs_frontend/fs.go @@ -251,6 +251,8 @@ func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fu  	if err != nil {  		return fuse.ToStatus(err)  	} +	// The new directory may take the place of an older one that is still in the cache +	fs.CryptFS.DirIVCacheEnc.Clear()  	// Create directory  	fs.dirIVLock.Lock()  	defer fs.dirIVLock.Unlock() @@ -315,7 +317,9 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {  	tmpName := fmt.Sprintf("gocryptfs.diriv.rmdir.%d", st.Ino)  	tmpDirivPath := filepath.Join(parentDir, tmpName)  	cryptfs.Debug.Printf("Rmdir: Renaming %s to %s\n", cryptfs.DIRIV_FILENAME, tmpDirivPath) -	fs.dirIVLock.Lock() // directory will be in an inconsistent state after the rename +	// The directory is in an inconsistent state between rename and rmdir. Protect against +	// concurrent readers. +	fs.dirIVLock.Lock()  	defer fs.dirIVLock.Unlock()  	err = os.Rename(dirivPath, tmpDirivPath)  	if err != nil { @@ -338,7 +342,8 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {  	if err != nil {  		cryptfs.Warn.Printf("Rmdir: Could not clean up %s: %v\n", tmpName, err)  	} - +	// The now-deleted directory may have been in the DirIV cache. Clear it. +	fs.CryptFS.DirIVCacheEnc.Clear()  	return fuse.OK  } @@ -382,6 +387,10 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod  	if err != nil {  		return fuse.ToStatus(err)  	} +	// The Rename may cause a directory to take the place of another directory. +	// That directory may still be in the DirIV cache, clear it. +	fs.CryptFS.DirIVCacheEnc.Clear() +  	return fs.FileSystem.Rename(cOldPath, cNewPath, context)  } diff --git a/performance.txt b/performance.txt index 55678c3..2cd53a7 100644 --- a/performance.txt +++ b/performance.txt @@ -8,3 +8,4 @@ VERSION         UNTAR    LS     RM  v0.4               48     1.5    5  v0.5-rc1           56     7     19  v0.5-rc1-1         54     4.1    9 +v0.5-rc1-2         45     1.7	 3.4  | 
