main: add "-sharedstorage" flag
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 https://github.com/rfjakob/gocryptfs/issues/156
This commit is contained in:
parent
9ab6cdb9b9
commit
e36a0ebf18
@ -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"
|
||||
|
36
Documentation/duplicate-inodes.txt
Normal file
36
Documentation/duplicate-inodes.txt
Normal file
@ -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
|
@ -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
|
||||
@ -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")
|
||||
|
25
mount.go
25
mount.go
@ -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
|
||||
@ -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{
|
||||
|
Loading…
Reference in New Issue
Block a user