b0eee6
From f09346578021c12069b6deb9487a1462b8d28a83 Mon Sep 17 00:00:00 2001
b0eee6
From: Nalin Dahyabhai <nalin@redhat.com>
b0eee6
Date: Thu, 21 Nov 2019 15:32:41 -0500
b0eee6
Subject: [PATCH 1/3] bind: don't complain about missing mountpoints
b0eee6
b0eee6
When we go to unmount a tree of mounts, if one of the directories isn't
b0eee6
there, instead of returning an error as before, log a debug message and
b0eee6
keep going.
b0eee6
b0eee6
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
b0eee6
---
b0eee6
 bind/mount.go | 4 ++++
b0eee6
 1 file changed, 4 insertions(+)
b0eee6
b0eee6
diff --git a/bind/mount.go b/bind/mount.go
b0eee6
index e1ae323b9..adde901fd 100644
b0eee6
--- a/bind/mount.go
b0eee6
+++ b/bind/mount.go
b0eee6
@@ -264,6 +264,10 @@ func UnmountMountpoints(mountpoint string, mountpointsToRemove []string) error {
b0eee6
 		mount := getMountByID(id)
b0eee6
 		// check if this mountpoint is mounted
b0eee6
 		if err := unix.Lstat(mount.Mountpoint, &st); err != nil {
b0eee6
+			if os.IsNotExist(err) {
b0eee6
+				logrus.Debugf("mountpoint %q is not present(?), skipping", mount.Mountpoint)
b0eee6
+				continue
b0eee6
+			}
b0eee6
 			return errors.Wrapf(err, "error checking if %q is mounted", mount.Mountpoint)
b0eee6
 		}
b0eee6
 		if mount.Major != int(unix.Major(st.Dev)) || mount.Minor != int(unix.Minor(st.Dev)) {
b0eee6
b0eee6
From c5fb681a6082b78c422eb3531667dc6d607a9355 Mon Sep 17 00:00:00 2001
b0eee6
From: Nalin Dahyabhai <nalin@redhat.com>
b0eee6
Date: Fri, 22 Nov 2019 14:22:26 -0500
b0eee6
Subject: [PATCH 2/3] chroot: Unmount with MNT_DETACH instead of
b0eee6
 UnmountMountpoints()
b0eee6
b0eee6
Unmounting the rootfs with MNT_DETACH should unmount everything below
b0eee6
it, so we don't need to use the more exhaustive method that our bind
b0eee6
package uses for its bind mounts.
b0eee6
b0eee6
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
b0eee6
---
b0eee6
 chroot/run.go | 25 +++++++++++++++----------
b0eee6
 1 file changed, 15 insertions(+), 10 deletions(-)
b0eee6
b0eee6
diff --git a/chroot/run.go b/chroot/run.go
b0eee6
index fbccbcdb0..76ac78d1f 100644
b0eee6
--- a/chroot/run.go
b0eee6
+++ b/chroot/run.go
b0eee6
@@ -15,6 +15,7 @@ import (
b0eee6
 	"strings"
b0eee6
 	"sync"
b0eee6
 	"syscall"
b0eee6
+	"time"
b0eee6
 	"unsafe"
b0eee6
 
b0eee6
 	"github.com/containers/buildah/bind"
b0eee6
@@ -1002,12 +1003,19 @@ func isDevNull(dev os.FileInfo) bool {
b0eee6
 // callback that will clean up its work.
b0eee6
 func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func() error, err error) {
b0eee6
 	var fs unix.Statfs_t
b0eee6
-	removes := []string{}
b0eee6
 	undoBinds = func() error {
b0eee6
-		if err2 := bind.UnmountMountpoints(spec.Root.Path, removes); err2 != nil {
b0eee6
-			logrus.Warnf("pkg/chroot: error unmounting %q: %v", spec.Root.Path, err2)
b0eee6
-			if err == nil {
b0eee6
-				err = err2
b0eee6
+		if err2 := unix.Unmount(spec.Root.Path, unix.MNT_DETACH); err2 != nil {
b0eee6
+			retries := 0
b0eee6
+			for (err2 == unix.EBUSY || err2 == unix.EAGAIN) && retries < 50 {
b0eee6
+				time.Sleep(50 * time.Millisecond)
b0eee6
+				err2 = unix.Unmount(spec.Root.Path, unix.MNT_DETACH)
b0eee6
+				retries++
b0eee6
+			}
b0eee6
+			if err2 != nil {
b0eee6
+				logrus.Warnf("pkg/chroot: error unmounting %q (retried %d times): %v", spec.Root.Path, retries, err2)
b0eee6
+				if err == nil {
b0eee6
+					err = err2
b0eee6
+				}
b0eee6
 			}
b0eee6
 		}
b0eee6
 		return err
b0eee6
@@ -1096,6 +1104,7 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
b0eee6
 	// Add /sys/fs/selinux to the set of masked paths, to ensure that we don't have processes
b0eee6
 	// attempting to interact with labeling, when they aren't allowed to do so.
b0eee6
 	spec.Linux.MaskedPaths = append(spec.Linux.MaskedPaths, "/sys/fs/selinux")
b0eee6
+
b0eee6
 	// Bind mount in everything we've been asked to mount.
b0eee6
 	for _, m := range spec.Mounts {
b0eee6
 		// Skip anything that we just mounted.
b0eee6
@@ -1141,13 +1150,11 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
b0eee6
 			if !os.IsNotExist(err) {
b0eee6
 				return undoBinds, errors.Wrapf(err, "error examining %q for mounting in mount namespace", target)
b0eee6
 			}
b0eee6
-			// The target isn't there yet, so create it, and make a
b0eee6
-			// note to remove it later.
b0eee6
+			// The target isn't there yet, so create it.
b0eee6
 			if srcinfo.IsDir() {
b0eee6
 				if err = os.MkdirAll(target, 0111); err != nil {
b0eee6
 					return undoBinds, errors.Wrapf(err, "error creating mountpoint %q in mount namespace", target)
b0eee6
 				}
b0eee6
-				removes = append(removes, target)
b0eee6
 			} else {
b0eee6
 				if err = os.MkdirAll(filepath.Dir(target), 0111); err != nil {
b0eee6
 					return undoBinds, errors.Wrapf(err, "error ensuring parent of mountpoint %q (%q) is present in mount namespace", target, filepath.Dir(target))
b0eee6
@@ -1157,7 +1164,6 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
b0eee6
 					return undoBinds, errors.Wrapf(err, "error creating mountpoint %q in mount namespace", target)
b0eee6
 				}
b0eee6
 				file.Close()
b0eee6
-				removes = append(removes, target)
b0eee6
 			}
b0eee6
 		}
b0eee6
 		requestFlags := bindFlags
b0eee6
@@ -1266,7 +1272,6 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
b0eee6
 		if err := os.Mkdir(roEmptyDir, 0700); err != nil {
b0eee6
 			return undoBinds, errors.Wrapf(err, "error creating empty directory %q", roEmptyDir)
b0eee6
 		}
b0eee6
-		removes = append(removes, roEmptyDir)
b0eee6
 	}
b0eee6
 
b0eee6
 	// Set up any masked paths that we need to.  If we're running inside of
b0eee6
b0eee6
From ec1be6a51941e10b5316c911ef97c88940f7c095 Mon Sep 17 00:00:00 2001
b0eee6
From: Nalin Dahyabhai <nalin@redhat.com>
b0eee6
Date: Fri, 22 Nov 2019 14:52:25 -0500
b0eee6
Subject: [PATCH 3/3] overlay.bats typo: fuse-overlays should be fuse-overlayfs
b0eee6
b0eee6
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
b0eee6
---
b0eee6
 tests/overlay.bats | 4 ++--
b0eee6
 1 file changed, 2 insertions(+), 2 deletions(-)
b0eee6
b0eee6
diff --git a/tests/overlay.bats b/tests/overlay.bats
b0eee6
index 04056f680..7cc2d0c62 100644
b0eee6
--- a/tests/overlay.bats
b0eee6
+++ b/tests/overlay.bats
b0eee6
@@ -3,14 +3,14 @@
b0eee6
 load helpers
b0eee6
 
b0eee6
 @test "overlay specific level" {
b0eee6
-  if test \! -e /usr/bin/fuse-overlays -a  "$BUILDAH_ISOLATION" = "rootless"; then
b0eee6
+  if test \! -e /usr/bin/fuse-overlayfs -a "$BUILDAH_ISOLATION" = "rootless"; then
b0eee6
     skip "BUILDAH_ISOLATION = $BUILDAH_ISOLATION" and no /usr/bin/fuse-overlayfs present
b0eee6
   fi
b0eee6
   image=alpine
b0eee6
   mkdir ${TESTDIR}/lower
b0eee6
   touch ${TESTDIR}/lower/foo
b0eee6
 
b0eee6
-cid=$(buildah --log-level=error from -v ${TESTDIR}/lower:/lower:O --quiet --signature-policy ${TESTSDIR}/policy.json $image)
b0eee6
+  cid=$(buildah --log-level=error from -v ${TESTDIR}/lower:/lower:O --quiet --signature-policy ${TESTSDIR}/policy.json $image)
b0eee6
 
b0eee6
   # This should succeed
b0eee6
   run_buildah --log-level=error run $cid ls /lower/foo