Description
gocryptfs currently doesn't play well with btrfs subvolumes due to pathfs's inode mapping:
Steps to reproduce
Assume the following setup:
/foo
<-- btrfs filesystem and cipherdir
/foo/M6LB0sjNfK2HT2c0UbAaMw
<--- subvolume (btrfs subvol create .....)
/foo/cULkSfhPk6LTWKsPPYO2Sw
<--- another subvolume
M6LB0sjNfK2HT2c0UbAaMw
and cULkSfhPk6LTWKsPPYO2Sw
are the encrypted names of two directories in the root of the encrypted filesystem. Let's call them dir1
and dir2
in cleartext.
Mounting such a setup with gocryptfs /foo /bar
will serve a filesystem at /bar
with 2 subfolders, just as expected:
$ ls /bar
dir1 dir2
However: The issue with such a setup is that M6LB0sjNfK2HT2c0UbAaMw
and cULkSfhPk6LTWKsPPYO2Sw
are considered to be separated devices by BTRFS / VFS and therefore may use the same inodes (this is not exclusive to btrfs subvolumes: ZFS or a mount within the cipherdir would have the same eissue).
When this happens (inode collision in the 2 folders), gocryptfs logs
2019/11/04 21:24:22 Found linked inode, but Nlink == 1, ino=8191, fullPath="...
and the client sees various fun errors (usually '..not a directory..').
Looking at the go-fuse code shows that the error comes from here:
https://github.com/hanwen/go-fuse/blob/master/fuse/pathfs/pathfs.go#L570
..after it detected that something is fishy with its clientInodeMap - which is not surprising as the code only tracks the inode but omits the device id - therefore making it easy to have 'bogus' data in the cache.
My current workaround is to use the --sharedstorage
flag which disables pathFSOpts.ClientInodes - but also disables all caching, which isn't really needed in this situation.
It would therefore be great to have a flag/option to only disable pathFSOpts.ClientInodes
while still keeping the caching functionality.
(Also: it may make sense to disable ClientInodes on BTRFS and ZFS by default? .. not sure :-) )
Oh: and thanks a lot for writing gocryptfs!