Skip to content

Commit

Permalink
main: add "-sharedstorage" flag
Browse files Browse the repository at this point in the history
At the moment, it does two things:

1. Disable stat() caching so changes to the backing storage show up
   immediately.
2. Disable hard link tracking, as the inode numbers on the backing
   storage are not stable when files are deleted and re-created behind
   our back. This would otherwise produce strange "file does not exist"
   and other errors.

Mitigates #156
  • Loading branch information
rfjakob committed Nov 12, 2017
1 parent 9ab6cdb commit e36a0eb
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 7 deletions.
24 changes: 24 additions & 0 deletions Documentation/MANPAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,30 @@ These factors will limit throughput to below 70MB/s.

For more details visit https://github.com/rfjakob/gocryptfs/issues/92 .

#### -sharedstorage
Enable work-arounds so gocryptfs works better when the backing
storage directory is concurrently accessed by multiple gocryptfs
instances.

At the moment, it does two things:

1. Disable stat() caching so changes to the backing storage show up
immediately.
2. Disable hard link tracking, as the inode numbers on the backing
storage are not stable when files are deleted and re-created behind
our back. This would otherwise produce strange "file does not exist"
and other errors.

When "-sharedstorage" is active, performance is reduced and hard
links cannot be created.

Even with this flag set, you may hit occasional problems. Running
gocryptfs on shared storage does not receive as much testing as the
usual (exclusive) use-case. Please test your workload in advance
and report any problems you may hit.

More info: https://github.com/rfjakob/gocryptfs/issues/156

#### -speed
Run crypto speed test. Benchmark Go's built-in GCM against OpenSSL
(if available). The library that will be selected on "-openssl=auto"
Expand Down
36 changes: 36 additions & 0 deletions Documentation/duplicate-inodes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
ls: cannot access foo: No such file or directory
ls: cannot access foo: No such file or directory
ls: cannot access foo: No such file or directory
ls: cannot access foo: No such file or directory
36962337 -rwxrwxrwx 1 u1026 users 0 Nov 11 18:00 foo
36962337 -rwxrwxrwx 1 u1026 users 0 Nov 11 18:00 foo
36962337 -rwxrwxrwx 1 u1026 users 0 Nov 11 18:00 foo
36962337 -rwxrwxrwx 1 u1026 users 0 Nov 11 18:00 foo


u1026@d8min:/mnt/synology/public/tmp/g1$ strace -e lstat -p 8899 -f
Process 8899 attached with 10 threads
2017/11/11 18:12:21 Dispatch 238: LOOKUP, NodeId: 1. names: [foo] 4 bytes
[pid 10539] lstat("/mnt/synology/public/tmp/g1/a/4DZNVle_txclugO7n_FRIg", 0xc4241adbe8) = -1 ENOENT (No such file or directory)
2017/11/11 18:12:21 Serialize 238: LOOKUP code: OK value: {NodeId: 0 Generation=0 EntryValid=1.000 AttrValid=0.000 Attr={M00 SZ=0 L=0 0:0 B0*0 i0:0 A 0.000000000 M 0.000000000 C 0.000000000}}
2017/11/11 18:12:22 Dispatch 239: LOOKUP, NodeId: 1. names: [foo] 4 bytes
[pid 8903] lstat("/mnt/synology/public/tmp/g1/a/Xsy8mhdcIh0u9aiI7-iLiw", {st_mode=S_IFREG|0777, st_size=0, ...}) = 0
2017/11/11 18:12:22 Serialize 239: LOOKUP code: OK value: {NodeId: 3 Generation=4 EntryValid=1.000 AttrValid=1.000 Attr={M0100777 SZ=0 L=1 1026:100 B0*16384 i0:36962337 A 1510419642.457639700 M 1510419642.457639700 C 1510419702.353712800}}


Call Trace:

nodefs/fsops.go (c *rawBridge) Lookup
nodefs/fsops.go (c *FileSystemConnector) internalLookup
nodefs/inode.go (n *Inode) GetChild
pathfs/pathfs.go (n *pathInode) GetAttr
pathfs/pathfs.go (n *pathInode) GetPath
nodefs/inode.go (n *Inode) Parent()
pathfs/loopback.go (fs *loopbackFileSystem) GetAttr

Call Trace 2 (new child):

nodefs/fsops.go (c *rawBridge) Lookup
nodefs/fsops.go (c *FileSystemConnector) internalLookup
pathfs/pathfs.go (n *pathInode) Lookup
pathfs/pathfs.go (n *pathInode) findChild
4 changes: 3 additions & 1 deletion cli_args.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ type argContainer struct {
debug, init, zerokey, fusedebug, openssl, passwd, fg, version,
plaintextnames, quiet, nosyslog, wpanic,
longnames, allow_other, ro, reverse, aessiv, nonempty, raw64,
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info bool
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info,
sharedstorage bool
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
memprofile, ko, passfile, ctlsock, fsname, force_owner, trace string
// Configuration file name override
Expand Down Expand Up @@ -130,6 +131,7 @@ func parseCliOpts() (args argContainer) {
" Requires gocryptfs to be compiled with openssl support and implies -openssl true")
flagSet.BoolVar(&args.hh, "hh", false, "Show this long help text")
flagSet.BoolVar(&args.info, "info", false, "Display information about CIPHERDIR")
flagSet.BoolVar(&args.sharedstorage, "sharedstorage", false, "Make concurrent access to a shared CIPHERDIR safer")
flagSet.StringVar(&args.masterkey, "masterkey", "", "Mount with explicit master key")
flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file")
flagSet.StringVar(&args.memprofile, "memprofile", "", "Write memory profile to specified file")
Expand Down
25 changes: 19 additions & 6 deletions mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,12 @@ func initFuseFrontend(masterkey []byte, args *argContainer, confFile *configfile
var ctlSockBackend ctlsock.Interface
// pathFsOpts are passed into go-fuse/pathfs
pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true}
if args.sharedstorage {
// shared storage mode disables hard link tracking as the backing inode
// numbers may change behind our back:
// https://github.com/rfjakob/gocryptfs/issues/156
pathFsOpts.ClientInodes = false
}
if args.reverse {
// The dance with the intermediate variables is because we need to
// cast the FS into pathfs.FileSystem *and* ctlsock.Interface. This
Expand Down Expand Up @@ -257,12 +263,19 @@ func initFuseFrontend(masterkey []byte, args *argContainer, confFile *configfile
go ctlsock.Serve(args._ctlsockFd, ctlSockBackend)
}
pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts)
fuseOpts := &nodefs.Options{
// These options are to be compatible with libfuse defaults,
// making benchmarking easier.
NegativeTimeout: time.Second,
AttrTimeout: time.Second,
EntryTimeout: time.Second,
var fuseOpts *nodefs.Options
if args.sharedstorage {
// sharedstorage mode sets all cache timeouts to zero so changes to the
// backing shared storage show up immediately.
fuseOpts = &nodefs.Options{}
} else {
fuseOpts = &nodefs.Options{
// These options are to be compatible with libfuse defaults,
// making benchmarking easier.
NegativeTimeout: time.Second,
AttrTimeout: time.Second,
EntryTimeout: time.Second,
}
}
conn := nodefs.NewFileSystemConnector(pathFs.Root(), fuseOpts)
mOpts := fuse.MountOptions{
Expand Down

0 comments on commit e36a0eb

Please sign in to comment.