Support merging layers using Overlayfs
ktock opened this issue · comments
Enabling to merge CRFS layers using overlayfs is valuable (I know currently fuse-overlayfs trying to support CRFS).
But currently CRFS has a cache related issue to achive it.
Issue Reproduction
On terminal A, run crfs:
# ./crfs -fuse_debug
On terminal B, mount crfs as overlayfs and access on it every second:
# mkdir merged upper work
# CRFS_PATH=/crfs/layers/gcr.io/reasonablek8s/ubuntu/18.04 ; mount -t overlay overlay -o lowerdir=${CRFS_PATH}/3:${CRFS_PATH}/2:${CRFS_PATH}/1:${CRFS_PATH}/0,upperdir=upper,workdir=work merged
# for i in $(seq 0 100) ; do echo -n "${i}: " && ls $(pwd)/merged/lib ; sleep 1 ; done
Then, on terminal B, we see ESTALE after 1 min:
0: init lsb systemd terminfo udev x86_64-linux-gnu
1: init lsb systemd terminfo udev x86_64-linux-gnu
2: init lsb systemd terminfo udev x86_64-linux-gnu
...
60: ls: cannot access '/home/kohei/local/experiment/lazypull/crfs/merged/lib': Stale file handle
61: ls: cannot access '/home/kohei/local/experiment/lazypull/crfs/merged/lib': Stale file handle
63: ls: cannot access '/home/kohei/local/experiment/lazypull/crfs/merged/lib': Stale file handle
On terminal A, kernel seems not to be satisfied with inode returned by "Lookup".
2019/09/12 12:17:05 fuse debug: <- Lookup [ID=0x31f Node=0x9 Uid=0 Gid=0 Pid=27867] "lib"
2019/09/12 12:17:05 fuse debug: -> [ID=0x31f] Lookup 0x11 gen=4 valid=1m0s attr={valid=720h0m0s ino=824640017696 size=0 mode=drwxr-xr-x}
2019/09/12 12:17:05 fuse debug: <- Forget [ID=0x320 Node=0x11 Uid=0 Gid=0 Pid=0] 1
2019/09/12 12:17:05 fuse debug: -> [ID=0x320] Forget
The cause of issue
CRFS generates different "Node" instance everytime "Lookup" is called. This behavior makes bazil/fuse assign different "Node IDs"(used by FUSE) to inodes everytime even if these "Lookups" point to same file because bazil/fuse caches "Node IDs" keyed by a "Node" insatance (not an inode number etc.). Most time (when we don't use overlayfs etc.) it is fine.
However, when dentry cache revalidation is executed and the dentry is expired (by default, set to 1 min in bazil/fuse.), FUSE "lookups" the original inode and it doesn't allow different Node IDs to same inode and concludes the cache as invalid. Unfortunately, overlayfs doesn't allow dentry caches being invalid and returns ESTALE.
As a result, CRFS currently doesn't support to merge the layers with overlayfs.
Solution
Cache "node" instances in CRFS once it lookedup, and use it when the same name is looked up.
I'll submit the patch as PR.