Sfoglia il codice sorgente

Detect overlay2 support on pre-4.0 kernels

The overlay2 storage-driver requires multiple lower dir
support for overlayFs. Support for this feature was added
in kernel 4.x, but some distros (RHEL 7.4, CentOS 7.4) ship with
an older kernel with this feature backported.

This patch adds feature-detection for multiple lower dirs,
and will perform this feature-detection on pre-4.x kernels
with overlayFS support.

With this patch applied, daemons running on a kernel
with multiple lower dir support will now select "overlay2"
as storage-driver, instead of falling back to "overlay".

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 7 anni fa
parent
commit
955c1f881a
2 ha cambiato i file con 45 aggiunte e 10 eliminazioni
  1. 32 0
      daemon/graphdriver/overlay2/check.go
  2. 13 10
      daemon/graphdriver/overlay2/overlay.go

+ 32 - 0
daemon/graphdriver/overlay2/check.go

@@ -100,3 +100,35 @@ 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 {
+			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
+		}
+	}
+
+	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, "work"))
+	if err := unix.Mount("overlay", filepath.Join(td, "merged"), "overlay", 0, opts); err != nil {
+		return errors.Wrap(err, "failed to mount overlay")
+	}
+	if err := unix.Unmount(filepath.Join(td, "merged"), 0); err != nil {
+		logrus.Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err)
+	}
+	return nil
+}

+ 13 - 10
daemon/graphdriver/overlay2/overlay.go

@@ -16,8 +16,6 @@ import (
 	"strings"
 	"sync"
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/docker/docker/daemon/graphdriver"
 	"github.com/docker/docker/daemon/graphdriver/overlayutils"
 	"github.com/docker/docker/daemon/graphdriver/quota"
@@ -32,9 +30,9 @@ import (
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/parsers/kernel"
 	"github.com/docker/docker/pkg/system"
-	units "github.com/docker/go-units"
-
+	"github.com/docker/go-units"
 	"github.com/opencontainers/selinux/go-selinux/label"
+	"github.com/sirupsen/logrus"
 	"golang.org/x/sys/unix"
 )
 
@@ -134,12 +132,6 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
 	if err != nil {
 		return nil, err
 	}
-	if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: 4, Major: 0, Minor: 0}) < 0 {
-		if !opts.overrideKernelCheck {
-			return nil, graphdriver.ErrNotSupported
-		}
-		logrus.Warn("Using pre-4.0.0 kernel for overlay2, mount failures may require kernel update")
-	}
 
 	fsMagic, err := graphdriver.GetFSMagic(home)
 	if err != nil {
@@ -166,6 +158,17 @@ 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 {
+			logrus.Warn("Using pre-4.0.0 kernel for overlay2, mount failures may require kernel update")
+		} else {
+			if err := supportsMultipleLowerDir(filepath.Dir(home)); err != nil {
+				logrus.Debugf("Multiple lower dirs not supported: %v", err)
+				return nil, graphdriver.ErrNotSupported
+			}
+		}
+	}
+
 	rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
 	if err != nil {
 		return nil, err