From d60ca9f834c27070097bbdf02906d9579d6cc480 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Fri, 19 Mar 2021 15:44:14 +0900 Subject: [PATCH] overlay: support "userxattr" option (kernel 5.11) ref: https://github.com/containerd/containerd/pull/5076 Signed-off-by: Akihiro Suda --- fs/fs.go | 19 ++++++++++++------- fs/fs_test.go | 9 ++++++--- snapshot/snapshot.go | 14 +++++++++++++- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/fs/fs.go b/fs/fs.go index 6bc7b299a..681faa471 100644 --- a/fs/fs.go +++ b/fs/fs.go @@ -69,11 +69,12 @@ import ( "golang.org/x/sys/unix" ) +var opaqueXattrs = []string{"trusted.overlay.opaque", "user.overlay.opaque"} + const ( blockSize = 4096 whiteoutPrefix = ".wh." whiteoutOpaqueDir = whiteoutPrefix + whiteoutPrefix + ".opq" - opaqueXattr = "trusted.overlay.opaque" opaqueXattrValue = "y" stateDirName = ".stargz-snapshotter" defaultMaxConcurrency = 2 @@ -545,12 +546,14 @@ func (n *node) Getattr(ctx context.Context, f fusefs.FileHandle, out *fuse.AttrO var _ = (fusefs.NodeGetxattrer)((*node)(nil)) func (n *node) Getxattr(ctx context.Context, attr string, dest []byte) (uint32, syscall.Errno) { - if attr == opaqueXattr && n.opaque { - // This node is an opaque directory so give overlayfs-compliant indicator. - if len(dest) < len(opaqueXattrValue) { - return uint32(len(opaqueXattrValue)), syscall.ERANGE + for _, opaqueXattr := range opaqueXattrs { + if attr == opaqueXattr && n.opaque { + // This node is an opaque directory so give overlayfs-compliant indicator. + if len(dest) < len(opaqueXattrValue) { + return uint32(len(opaqueXattrValue)), syscall.ERANGE + } + return uint32(copy(dest, opaqueXattrValue)), 0 } - return uint32(copy(dest, opaqueXattrValue)), 0 } if v, ok := n.e.Xattrs[attr]; ok { if len(dest) < len(v) { @@ -567,7 +570,9 @@ func (n *node) Listxattr(ctx context.Context, dest []byte) (uint32, syscall.Errn var attrs []byte if n.opaque { // This node is an opaque directory so add overlayfs-compliant indicator. - attrs = append(attrs, []byte(opaqueXattr+"\x00")...) + for _, opaqueXattr := range opaqueXattrs { + attrs = append(attrs, []byte(opaqueXattr+"\x00")...) + } } for k := range n.e.Xattrs { attrs = append(attrs, []byte(k+"\x00")...) diff --git a/fs/fs_test.go b/fs/fs_test.go index 11d27acf6..57b30c6f5 100644 --- a/fs/fs_test.go +++ b/fs/fs_test.go @@ -238,7 +238,8 @@ func TestExistence(t *testing.T) { testutil.File("foo/.wh..wh..opq", ""), }, want: []check{ - hasNodeXattrs("foo/", opaqueXattr, opaqueXattrValue), + hasNodeXattrs("foo/", opaqueXattrs[0], opaqueXattrValue), + hasNodeXattrs("foo/", opaqueXattrs[1], opaqueXattrValue), fileNotExist("foo/.wh..wh..opq"), }, }, @@ -250,7 +251,8 @@ func TestExistence(t *testing.T) { testutil.File("foo/bar.txt", "test"), }, want: []check{ - hasNodeXattrs("foo/", opaqueXattr, opaqueXattrValue), + hasNodeXattrs("foo/", opaqueXattrs[0], opaqueXattrValue), + hasNodeXattrs("foo/", opaqueXattrs[1], opaqueXattrValue), hasFileDigest("foo/bar.txt", digestFor("test")), fileNotExist("foo/.wh..wh..opq"), }, @@ -262,7 +264,8 @@ func TestExistence(t *testing.T) { testutil.File("foo/.wh..wh..opq", ""), }, want: []check{ - hasNodeXattrs("foo/", opaqueXattr, opaqueXattrValue), + hasNodeXattrs("foo/", opaqueXattrs[0], opaqueXattrValue), + hasNodeXattrs("foo/", opaqueXattrs[1], opaqueXattrValue), hasNodeXattrs("foo/", "foo", "bar"), fileNotExist("foo/.wh..wh..opq"), }, diff --git a/snapshot/snapshot.go b/snapshot/snapshot.go index 0f5fc962b..7c18d3164 100644 --- a/snapshot/snapshot.go +++ b/snapshot/snapshot.go @@ -29,10 +29,12 @@ import ( "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/snapshots" + "github.com/containerd/containerd/snapshots/overlay/overlayutils" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/continuity/fs" "github.com/moby/sys/mountinfo" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "golang.org/x/sync/errgroup" ) @@ -91,7 +93,8 @@ type snapshotter struct { asyncRemove bool // fs is a filesystem that this snapshotter recognizes. - fs FileSystem + fs FileSystem + userxattr bool // whether to enable "userxattr" mount option } // NewSnapshotter returns a Snapshotter which can use unpacked remote layers @@ -129,11 +132,17 @@ func NewSnapshotter(ctx context.Context, root string, targetFs FileSystem, opts return nil, err } + userxattr, err := overlayutils.NeedsUserXAttr(root) + if err != nil { + logrus.WithError(err).Warnf("cannot detect whether \"userxattr\" option needs to be used, assuming to be %v", userxattr) + } + o := &snapshotter{ root: root, ms: ms, asyncRemove: config.asyncRemove, fs: targetFs, + userxattr: userxattr, } if err := o.restoreRemoteSnapshot(ctx); err != nil { @@ -598,6 +607,9 @@ func (o *snapshotter) mounts(ctx context.Context, s storage.Snapshot, checkKey s } options = append(options, fmt.Sprintf("lowerdir=%s", strings.Join(parentPaths, ":"))) + if o.userxattr { + options = append(options, "userxattr") + } return []mount.Mount{ { Type: "overlay",