OpenDir performance: Read DirIV once and reuse it for all names

Formerly, we called decryptPath for every name.
That resulted in a directory walk that reads in all diriv files
on the way.

Massive improvement for RM and LS (check performance.txt for details)

VERSION         UNTAR   RM   LS
v0.4               48    5    1.5
v0.5-rc1           56   19    7
v0.5-rc1-1         54    9    4.1   <---- THIS VERSION
This commit is contained in:
Jakob Unterwurzacher 2015-11-29 19:57:48 +01:00
parent 6f764b3867
commit 1d0a442405
4 changed files with 51 additions and 35 deletions

View File

@ -17,7 +17,7 @@ const (
) )
// DecryptName - decrypt base64-encoded encrypted filename "cipherName" // DecryptName - decrypt base64-encoded encrypted filename "cipherName"
func (be *CryptFS) decryptName(cipherName string, iv []byte) (string, error) { func (be *CryptFS) DecryptName(cipherName string, iv []byte) (string, error) {
// Make sure relative symlinks still work after encryption // Make sure relative symlinks still work after encryption
// by passing these through unchanged // by passing these through unchanged
@ -91,7 +91,7 @@ func (be *CryptFS) TranslatePathZeroIV(path string, op int) (string, error) {
if op == OpEncrypt { if op == OpEncrypt {
newPart = be.encryptName(part, zeroIV) newPart = be.encryptName(part, zeroIV)
} else { } else {
newPart, err = be.decryptName(part, zeroIV) newPart, err = be.DecryptName(part, zeroIV)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -7,8 +7,8 @@ import (
"strings" "strings"
) )
// readDirIV - read the "gocryptfs.diriv" file from "dir" (absolute path) // readDirIV - read the "gocryptfs.diriv" file from "dir" (absolute ciphertext path)
func (be *CryptFS) readDirIV(dir string) (iv []byte, err error) { func (be *CryptFS) ReadDirIV(dir string) (iv []byte, err error) {
ivfile := filepath.Join(dir, DIRIV_FILENAME) ivfile := filepath.Join(dir, DIRIV_FILENAME)
Debug.Printf("readDirIV: reading %s\n", ivfile) Debug.Printf("readDirIV: reading %s\n", ivfile)
iv, err = ioutil.ReadFile(ivfile) iv, err = ioutil.ReadFile(ivfile)
@ -22,7 +22,7 @@ func (be *CryptFS) readDirIV(dir string) (iv []byte, err error) {
return iv, nil return iv, nil
} }
// WriteDirIV - create diriv file inside "dir" (absolute path) // WriteDirIV - create diriv file inside "dir" (absolute ciphertext path)
// This function is exported because it is used from pathfs_frontend, main, // This function is exported because it is used from pathfs_frontend, main,
// and also the automated tests. // and also the automated tests.
func WriteDirIV(dir string) error { func WriteDirIV(dir string) error {
@ -45,7 +45,7 @@ func (be *CryptFS) EncryptPathDirIV(plainPath string, rootDir string) (string, e
var encryptedNames []string var encryptedNames []string
plainNames := strings.Split(plainPath, "/") plainNames := strings.Split(plainPath, "/")
for _, plainName := range plainNames { for _, plainName := range plainNames {
iv, err := be.readDirIV(wd) iv, err := be.ReadDirIV(wd)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -66,11 +66,11 @@ func (be *CryptFS) DecryptPathDirIV(encryptedPath string, rootDir string) (strin
encryptedNames := strings.Split(encryptedPath, "/") encryptedNames := strings.Split(encryptedPath, "/")
Debug.Printf("DecryptPathDirIV: decrypting %v\n", encryptedNames) Debug.Printf("DecryptPathDirIV: decrypting %v\n", encryptedNames)
for _, encryptedName := range encryptedNames { for _, encryptedName := range encryptedNames {
iv, err := be.readDirIV(wd) iv, err := be.ReadDirIV(wd)
if err != nil { if err != nil {
return "", err return "", err
} }
plainName, err := be.decryptName(encryptedName, iv) plainName, err := be.DecryptName(encryptedName, iv)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -75,36 +75,42 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f
if err != nil { if err != nil {
return nil, fuse.ToStatus(err) return nil, fuse.ToStatus(err)
} }
// Read ciphertext directory
cipherEntries, status := fs.FileSystem.OpenDir(cDirName, context) cipherEntries, status := fs.FileSystem.OpenDir(cDirName, context)
var plain []fuse.DirEntry if cipherEntries == nil {
if cipherEntries != nil { return nil, status
for i := range cipherEntries { }
cName := cipherEntries[i].Name // Get DirIV (stays zero if DirIV if off)
if dirName == "" && cName == cryptfs.ConfDefaultName { cachedIV := make([]byte, cryptfs.DIRIV_LEN)
// silently ignore "gocryptfs.conf" in the top level dir if fs.args.DirIV {
continue // Read the DirIV once and use it for all later name decryptions
} cDirAbsPath := filepath.Join(fs.args.Cipherdir, cDirName)
if fs.args.DirIV && cName == cryptfs.DIRIV_FILENAME { cachedIV, err = fs.CryptFS.ReadDirIV(cDirAbsPath)
// silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled if err != nil {
continue return nil, fuse.ToStatus(err)
}
var name string
if !fs.args.DirIV {
name, err = fs.decryptPath(cName)
} else {
// When dirIV is enabled we need the full path to be able to decrypt it
cPath := filepath.Join(cDirName, cName)
name, err = fs.decryptPath(cPath)
name = filepath.Base(name)
}
if err != nil {
cryptfs.Warn.Printf("Invalid name \"%s\" in dir \"%s\": %s\n", cName, dirName, err)
continue
}
cipherEntries[i].Name = name
plain = append(plain, cipherEntries[i])
} }
} }
// Decrypt filenames
var plain []fuse.DirEntry
for i := range cipherEntries {
cName := cipherEntries[i].Name
if dirName == "" && cName == cryptfs.ConfDefaultName {
// silently ignore "gocryptfs.conf" in the top level dir
continue
}
if fs.args.DirIV && cName == cryptfs.DIRIV_FILENAME {
// silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled
continue
}
var name string
name, err = fs.CryptFS.DecryptName(cName, cachedIV)
if err != nil {
cryptfs.Warn.Printf("Invalid name \"%s\" in dir \"%s\": %s\n", cName, dirName, err)
continue
}
cipherEntries[i].Name = name
plain = append(plain, cipherEntries[i])
}
return plain, status return plain, status
} }

10
performance.txt Normal file
View File

@ -0,0 +1,10 @@
All test performed on tmpfs, /tmp/a mounted on /tmp/b.
UNTAR: tar xfz ../linux-3.0.tar.gz
LS: ls -lR > /dev/null
RM: rm -rf linux-3.0
VERSION UNTAR LS RM
v0.4 48 1.5 5
v0.5-rc1 56 7 19
v0.5-rc1-1 54 4.1 9