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

overlay[2] graphdriver: Fix/improve overlayfs support check for rootless #40194

Merged
merged 2 commits into from
Nov 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 5 additions & 32 deletions daemon/graphdriver/overlay/overlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
package overlay // import "github.com/docker/docker/daemon/graphdriver/overlay"

import (
"bufio"
"fmt"
"io"
"io/ioutil"
Expand Down Expand Up @@ -123,10 +122,6 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, err
}

if err := supportsOverlay(); err != nil {
return nil, graphdriver.ErrNotSupported
}

// Perform feature detection on /var/lib/docker/overlay if it's an existing directory.
// This covers situations where /var/lib/docker/overlay is a mount, and on a different
// filesystem than /var/lib/docker.
Expand All @@ -136,6 +131,11 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
testdir = filepath.Dir(testdir)
}

if err := overlayutils.SupportsOverlay(testdir, false); err != nil {
logrus.WithField("storage-driver", "overlay").Error(err)
return nil, graphdriver.ErrNotSupported
}

fsMagic, err := graphdriver.GetFSMagic(testdir)
if err != nil {
return nil, err
Expand Down Expand Up @@ -199,33 +199,6 @@ func parseOptions(options []string) (*overlayOptions, error) {
return o, nil
}

func supportsOverlay() error {
// Access overlay filesystem so that Linux loads it (if possible).
mountTarget, err := ioutil.TempDir("", "supportsOverlay")
if err != nil {
logrus.WithError(err).WithField("storage-driver", "overlay2").Error("could not create temporary directory, so assuming that 'overlay' is not supported")
return graphdriver.ErrNotSupported
}
/* The mounting will fail--after the module has been loaded.*/
defer os.RemoveAll(mountTarget)
unix.Mount("overlay", mountTarget, "overlay", 0, "")

f, err := os.Open("/proc/filesystems")
if err != nil {
return err
}
defer f.Close()

s := bufio.NewScanner(f)
for s.Scan() {
if s.Text() == "nodev\toverlay" {
return nil
}
}
logrus.WithField("storage-driver", "overlay").Error("'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
return graphdriver.ErrNotSupported
}

func (d *Driver) String() string {
return "overlay"
}
Expand Down
32 changes: 0 additions & 32 deletions daemon/graphdriver/overlay2/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,35 +99,3 @@ func doesSupportNativeDiff(d string) error {

return nil
}

// supportsMultipleLowerDir checks if the system supports multiple lowerdirs,
// which is required for the overlay2 driver. On 4.x kernels, multiple lowerdirs
// are always available (so this check isn't needed), and backported to RHEL and
// CentOS 3.x kernels (3.10.0-693.el7.x86_64 and up). This function is to detect
// support on those kernels, without doing a kernel version compare.
func supportsMultipleLowerDir(d string) error {
td, err := ioutil.TempDir(d, "multiple-lowerdir-check")
if err != nil {
return err
}
defer func() {
if err := os.RemoveAll(td); err != nil {
logger.Warnf("Failed to remove check directory %v: %v", td, err)
}
}()

for _, dir := range []string{"lower1", "lower2", "upper", workDirName, mergedDirName} {
if err := os.Mkdir(filepath.Join(td, dir), 0755); err != nil {
return err
}
}

opts := fmt.Sprintf("lowerdir=%s:%s,upperdir=%s,workdir=%s", path.Join(td, "lower2"), path.Join(td, "lower1"), path.Join(td, "upper"), path.Join(td, workDirName))
if err := unix.Mount("overlay", filepath.Join(td, mergedDirName), "overlay", 0, opts); err != nil {
return errors.Wrap(err, "failed to mount overlay")
}
if err := unix.Unmount(filepath.Join(td, mergedDirName), 0); err != nil {
logger.Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, mergedDirName), err)
}
return nil
}
47 changes: 5 additions & 42 deletions daemon/graphdriver/overlay2/overlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
package overlay2 // import "github.com/docker/docker/daemon/graphdriver/overlay2"

import (
"bufio"
"context"
"errors"
"fmt"
Expand Down Expand Up @@ -133,10 +132,6 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, err
}

if err := supportsOverlay(); err != nil {
return nil, graphdriver.ErrNotSupported
}

// require kernel 4.0.0 to ensure multiple lower dirs are supported
v, err := kernel.GetKernelVersion()
if err != nil {
Expand All @@ -152,6 +147,11 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
testdir = filepath.Dir(testdir)
}

if err := overlayutils.SupportsOverlay(testdir, true); err != nil {
logger.Error(err)
return nil, graphdriver.ErrNotSupported
}

fsMagic, err := graphdriver.GetFSMagic(testdir)
if err != nil {
return nil, err
Expand All @@ -176,16 +176,6 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
}
}

if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: 4, Major: 0, Minor: 0}) < 0 {
if opts.overrideKernelCheck {
logger.Warn("Using pre-4.0.0 kernel for overlay2, mount failures may require kernel update")
} else {
if err := supportsMultipleLowerDir(testdir); err != nil {
logger.Debugf("Multiple lower dirs not supported: %v", err)
return nil, graphdriver.ErrNotSupported
}
}
}
supportsDType, err := fsutils.SupportsDType(testdir)
if err != nil {
return nil, err
Expand Down Expand Up @@ -274,33 +264,6 @@ func parseOptions(options []string) (*overlayOptions, error) {
return o, nil
}

func supportsOverlay() error {
// Access overlay filesystem so that Linux loads it (if possible).
mountTarget, err := ioutil.TempDir("", "supportsOverlay2")
if err != nil {
logrus.WithError(err).WithField("storage-driver", "overlay2").Error("could not create temporary directory, so assuming that 'overlay' is not supported")
return graphdriver.ErrNotSupported
}
/* The mounting will fail--after the module has been loaded.*/
defer os.RemoveAll(mountTarget)
unix.Mount("overlay", mountTarget, "overlay", 0, "")

f, err := os.Open("/proc/filesystems")
if err != nil {
return err
}
defer f.Close()

s := bufio.NewScanner(f)
for s.Scan() {
if s.Text() == "nodev\toverlay" {
return nil
}
}
logger.Error("'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
return graphdriver.ErrNotSupported
}

func useNaiveDiff(home string) bool {
useNaiveDiffLock.Do(func() {
if err := doesSupportNativeDiff(home); err != nil {
Expand Down
44 changes: 44 additions & 0 deletions daemon/graphdriver/overlayutils/overlayutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@ package overlayutils // import "github.com/docker/docker/daemon/graphdriver/over

import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"

"github.com/docker/docker/daemon/graphdriver"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)

// ErrDTypeNotSupported denotes that the backing filesystem doesn't support d_type.
Expand All @@ -23,3 +30,40 @@ func ErrDTypeNotSupported(driver, backingFs string) error {

return graphdriver.NotSupportedError(msg)
}

// SupportsOverlay checks if the system supports overlay filesystem
// by performing an actual overlay mount.
//
// checkMultipleLowers parameter enables check for multiple lowerdirs,
// which is required for the overlay2 driver.
func SupportsOverlay(d string, checkMultipleLowers bool) error {
td, err := ioutil.TempDir(d, "check-overlayfs-support")
if err != nil {
return err
}
defer func() {
if err := os.RemoveAll(td); err != nil {
logrus.Warnf("Failed to remove check directory %v: %v", td, err)
}
}()

for _, dir := range []string{"lower1", "lower2", "upper", "work", "merged"} {
if err := os.Mkdir(filepath.Join(td, dir), 0755); err != nil {
return err
}
}

mnt := filepath.Join(td, "merged")
lowerDir := path.Join(td, "lower2")
if checkMultipleLowers {
lowerDir += ":" + path.Join(td, "lower1")
}
opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, path.Join(td, "upper"), path.Join(td, "work"))
if err := unix.Mount("overlay", mnt, "overlay", 0, opts); err != nil {
return errors.Wrap(err, "failed to mount overlay")
}
if err := unix.Unmount(mnt, 0); err != nil {
logrus.Warnf("Failed to unmount check directory %v: %v", mnt, err)
}
return nil
}