mirror of
https://github.com/containers/podman.git
synced 2025-12-12 09:50:25 +08:00
Use storage that better supports rootless overlayfs
overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned
(as of linux 5.16.0, I believe) how to support rootless users. Previously,
rootless users had to use these storage.conf(5) settings:
* storage.driver=vfs (aka STORAGE_DRIVER=vfs), or
* storage.driver=overlay (aka STORAGE_DRIVER=overlay),
storage.options.overlay.mount_program=/usr/bin/fuse-overlayfs
(aka STORAGE_OPTS=/usr/bin/fuse-overlayfs)
Now that a third backend is available, setting only:
* storage.driver=overlay (aka STORAGE_DRIVER=overlay)
https://github.com/containers/podman/issues/13123 reported EXDEV errors
during the normal operation of their container. Tracing it out, the
problem turned out to be that their container was being mounted without
'userxattr'; I don't fully understand why, but mount(8) mentions this is
needed for rootless users:
> userxattr
>
> Use the "user.overlay." xattr namespace instead of "trusted.overlay.".
> This is useful for unprivileged mounting of overlayfs.
https://github.com/containers/storage/pull/1156 found and fixed the issue
in podman, and this just pulls in that via
go get github.com/containers/storage@ebc90ab
go mod vendor
make vendor
Closes https://github.com/containers/podman/issues/13123
Signed-off-by: Nick Guenther <nick.guenther@polymtl.ca>
This commit is contained in:
5
vendor/github.com/containers/storage/drivers/chown.go
generated
vendored
5
vendor/github.com/containers/storage/drivers/chown.go
generated
vendored
@@ -50,11 +50,14 @@ func chownByMapsMain() {
|
||||
if len(toHost.UIDs()) == 0 && len(toHost.GIDs()) == 0 {
|
||||
toHost = nil
|
||||
}
|
||||
|
||||
chowner := newLChowner()
|
||||
|
||||
chown := func(path string, info os.FileInfo, _ error) error {
|
||||
if path == "." {
|
||||
return nil
|
||||
}
|
||||
return platformLChown(path, info, toHost, toContainer)
|
||||
return chowner.LChown(path, info, toHost, toContainer)
|
||||
}
|
||||
if err := pwalk.Walk(".", chown); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error during chown: %v", err)
|
||||
|
||||
36
vendor/github.com/containers/storage/drivers/chown_unix.go
generated
vendored
36
vendor/github.com/containers/storage/drivers/chown_unix.go
generated
vendored
@@ -1,3 +1,4 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package graphdriver
|
||||
@@ -6,17 +7,50 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
"github.com/containers/storage/pkg/system"
|
||||
)
|
||||
|
||||
func platformLChown(path string, info os.FileInfo, toHost, toContainer *idtools.IDMappings) error {
|
||||
type inode struct {
|
||||
Dev uint64
|
||||
Ino uint64
|
||||
}
|
||||
|
||||
type platformChowner struct {
|
||||
mutex sync.Mutex
|
||||
inodes map[inode]bool
|
||||
}
|
||||
|
||||
func newLChowner() *platformChowner {
|
||||
return &platformChowner{
|
||||
inodes: make(map[inode]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *platformChowner) LChown(path string, info os.FileInfo, toHost, toContainer *idtools.IDMappings) error {
|
||||
st, ok := info.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
i := inode{
|
||||
Dev: uint64(st.Dev),
|
||||
Ino: uint64(st.Ino),
|
||||
}
|
||||
c.mutex.Lock()
|
||||
_, found := c.inodes[i]
|
||||
if !found {
|
||||
c.inodes[i] = true
|
||||
}
|
||||
c.mutex.Unlock()
|
||||
|
||||
if found {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Map an on-disk UID/GID pair from host to container
|
||||
// using the first map, then back to the host using the
|
||||
// second map. Skip that first step if they're 0, to
|
||||
|
||||
10
vendor/github.com/containers/storage/drivers/chown_windows.go
generated
vendored
10
vendor/github.com/containers/storage/drivers/chown_windows.go
generated
vendored
@@ -1,3 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package graphdriver
|
||||
@@ -9,6 +10,13 @@ import (
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
)
|
||||
|
||||
func platformLChown(path string, info os.FileInfo, toHost, toContainer *idtools.IDMappings) error {
|
||||
type platformChowner struct {
|
||||
}
|
||||
|
||||
func newLChowner() *platformChowner {
|
||||
return &platformChowner{}
|
||||
}
|
||||
|
||||
func (c *platformChowner) LChown(path string, info os.FileInfo, toHost, toContainer *idtools.IDMappings) error {
|
||||
return &os.PathError{"lchown", path, syscall.EWINDOWS}
|
||||
}
|
||||
|
||||
50
vendor/github.com/containers/storage/drivers/overlay/overlay.go
generated
vendored
50
vendor/github.com/containers/storage/drivers/overlay/overlay.go
generated
vendored
@@ -920,7 +920,9 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disable
|
||||
defer func() {
|
||||
// Clean up on failure
|
||||
if retErr != nil {
|
||||
os.RemoveAll(dir)
|
||||
if err2 := os.RemoveAll(dir); err2 != nil {
|
||||
logrus.Errorf("While recovering from a failure creating a layer, error deleting %#v: %v", dir, err2)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -1253,6 +1255,8 @@ func (d *Driver) recreateSymlinks() error {
|
||||
linkFile := filepath.Join(d.dir(targetID), "link")
|
||||
data, err := ioutil.ReadFile(linkFile)
|
||||
if err != nil || string(data) != link.Name() {
|
||||
// NOTE: If two or more links point to the same target, we will update linkFile
|
||||
// with every value of link.Name(), and set madeProgress = true every time.
|
||||
if err := ioutil.WriteFile(linkFile, []byte(link.Name()), 0644); err != nil {
|
||||
errs = multierror.Append(errs, errors.Wrapf(err, "correcting link for layer %s", targetID))
|
||||
continue
|
||||
@@ -1458,6 +1462,21 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||
|
||||
workdir := path.Join(dir, "work")
|
||||
|
||||
if d.options.mountProgram == "" && unshare.IsRootless() {
|
||||
optsList = append(optsList, "userxattr")
|
||||
}
|
||||
|
||||
if options.Volatile && !hasVolatileOption(optsList) {
|
||||
supported, err := d.getSupportsVolatile()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// If "volatile" is not supported by the file system, just ignore the request
|
||||
if supported {
|
||||
optsList = append(optsList, "volatile")
|
||||
}
|
||||
}
|
||||
|
||||
var opts string
|
||||
if readWrite {
|
||||
opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(absLowers, ":"), diffDir, workdir)
|
||||
@@ -1465,22 +1484,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||
opts = fmt.Sprintf("lowerdir=%s:%s", diffDir, strings.Join(absLowers, ":"))
|
||||
}
|
||||
if len(optsList) > 0 {
|
||||
opts = fmt.Sprintf("%s,%s", strings.Join(optsList, ","), opts)
|
||||
}
|
||||
|
||||
if d.options.mountProgram == "" && unshare.IsRootless() {
|
||||
opts = fmt.Sprintf("%s,userxattr", opts)
|
||||
}
|
||||
|
||||
// If "volatile" is not supported by the file system, just ignore the request
|
||||
if options.Volatile && !hasVolatileOption(strings.Split(opts, ",")) {
|
||||
supported, err := d.getSupportsVolatile()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if supported {
|
||||
opts = fmt.Sprintf("%s,volatile", opts)
|
||||
}
|
||||
opts = fmt.Sprintf("%s,%s", opts, strings.Join(optsList, ","))
|
||||
}
|
||||
|
||||
mountData := label.FormatMountLabel(opts, options.MountLabel)
|
||||
@@ -1489,10 +1493,6 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||
|
||||
pageSize := unix.Getpagesize()
|
||||
|
||||
// Use relative paths and mountFrom when the mount data has exceeded
|
||||
// the page size. The mount syscall fails if the mount data cannot
|
||||
// fit within a page and relative links make the mount data much
|
||||
// smaller at the expense of requiring a fork exec to chroot.
|
||||
if d.options.mountProgram != "" {
|
||||
mountFunc = func(source string, target string, mType string, flags uintptr, label string) error {
|
||||
if !disableShifting {
|
||||
@@ -1519,6 +1519,11 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||
return nil
|
||||
}
|
||||
} else if len(mountData) > pageSize {
|
||||
// Use relative paths and mountFrom when the mount data has exceeded
|
||||
// the page size. The mount syscall fails if the mount data cannot
|
||||
// fit within a page and relative links make the mount data much
|
||||
// smaller at the expense of requiring a fork exec to chroot.
|
||||
|
||||
workdir = path.Join(id, "work")
|
||||
//FIXME: We need to figure out to get this to work with additional stores
|
||||
if readWrite {
|
||||
@@ -1527,6 +1532,9 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||
} else {
|
||||
opts = fmt.Sprintf("lowerdir=%s", strings.Join(absLowers, ":"))
|
||||
}
|
||||
if len(optsList) > 0 {
|
||||
opts = fmt.Sprintf("%s,%s", opts, strings.Join(optsList, ","))
|
||||
}
|
||||
mountData = label.FormatMountLabel(opts, options.MountLabel)
|
||||
if len(mountData) > pageSize {
|
||||
return "", fmt.Errorf("cannot mount layer, mount label %q too large %d > page size %d", options.MountLabel, len(mountData), pageSize)
|
||||
|
||||
Reference in New Issue
Block a user