Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide same Node instance for same file not to make overlayfs confused. #19

Merged
merged 6 commits into from Oct 6, 2019

Conversation

ktock
Copy link
Contributor

@ktock ktock commented Sep 13, 2019

Fixes: #16

CRFS currently doesn't support to merge the layers using overlayfs.

CRFS generates different "Node" instance every time "Lookup" is called. This behaviour makes bazil/fuse assign different "Node IDs"(used by FUSE) to inodes every time even if these "Lookups" point to same file because bazil/fuse caches "Node IDs" keyed by a "Node" instance (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.

This commit solves this issue and make CRFS support overlayfs by cache node
instances in CRFS once it looked-up and using it when the same name is looked
up.

Currently, CRFS returns different "Node" instances everytime "Lookup" is
called. This behaviour makes bazil/fuse assign different "Node ID"(used by FUSE)
to inodes everytime even if these inodes are describing same file.(The reason is
that 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, but
overlayfs doesn't allow this behaviour when it revalidates dentry cache, so
returns ESTALE.

As a result, CRFS currently doesn't support to merge the layers using overlayfs.

This commit solves this issue and make CRFS support overlayfs by cache node
instances in CRFS once it lookedup and useing it when the same name is looked
up.

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
@googlebot googlebot added the cla: yes Signed a CLA label Sep 13, 2019
Copy link
Contributor

@bradfitz bradfitz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

crfs.go Outdated
@@ -901,6 +903,7 @@ type node struct {
te *stargz.TOCEntry
sr *stargz.Reader
f *os.File // non-nil if root & in debug mode
children map[string]fspkg.Node // Remenber child nodes once looked up.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: remember

But more important is to document what the keys look like. It might make sense to use a before-line comment and spell it all out:

// children maps from previously-looked up base names (like "foo.txt") to
// the *node that was previously returned. This prevents FUSE inode numbers
// from getting out of sync
child map[string]*node

Also, I'd make the value type just be *node. It's slightly faster and smaller, but it's also more clear because that's the only type we'll have there, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review. I fixed it on b076f18.

crfs.go Outdated
e, ok := n.te.LookupChild(name)
if !ok {
return nil, fuse.ENOENT
}
return &node{n.fs, e, n.sr, nil}, nil

c := &node{n.fs, e, n.sr, nil, make(map[string]fspkg.Node)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arguably positional initializing was already overdue before, but now it really is. Switch these to named fields here and drop the nil entry.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review. I fixed it on b076f18.

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
crfs.go Outdated
@@ -966,11 +973,24 @@ func (h *nodeHandle) ReadDirAll(ctx context.Context) (ents []fuse.Dirent, err er
//
// See https://godoc.org/bazil.org/fuse/fs#NodeStringLookuper
func (n *node) Lookup(ctx context.Context, name string) (fspkg.Node, error) {
if c, ok := n.child[name] ; ok {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a data race. The node.Lookup can be called from concurrent goroutines and no mutex is protecting this map read/write.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I added mutex to protect children maps in e18ee07.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not enough. This read is also a race.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review. I fixed it on 39ae89f.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Run gofmt. No space before ;.

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
@ktock
Copy link
Contributor Author

ktock commented Sep 19, 2019

@bradfitz Could I get any comments?

@ktock ktock requested a review from bradfitz September 20, 2019 08:55
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
crfs.go Outdated
@@ -901,6 +903,12 @@ type node struct {
te *stargz.TOCEntry
sr *stargz.Reader
f *os.File // non-nil if root & in debug mode

mu sync.Mutex // For children maps.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mu sync.Mutex // guards child, below

crfs.go Outdated
@@ -901,6 +903,12 @@ type node struct {
te *stargz.TOCEntry
sr *stargz.Reader
f *os.File // non-nil if root & in debug mode

mu sync.Mutex // For children maps.
// children maps from previously-looked up base names (like "foo.txt") to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// child maps ...

(The field is named "child", not "children")

crfs.go Outdated
@@ -966,11 +973,24 @@ func (h *nodeHandle) ReadDirAll(ctx context.Context) (ents []fuse.Dirent, err er
//
// See https://godoc.org/bazil.org/fuse/fs#NodeStringLookuper
func (n *node) Lookup(ctx context.Context, name string) (fspkg.Node, error) {
if c, ok := n.child[name] ; ok {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Run gofmt. No space before ;.

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
@ktock ktock requested a review from bradfitz September 26, 2019 05:03
@ktock
Copy link
Contributor Author

ktock commented Oct 6, 2019

@bradfitz Could I get any comments?

@bradfitz bradfitz merged commit ed98e0b into google:master Oct 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes Signed a CLA
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support merging layers using Overlayfs
3 participants