app-emulation/rkt: Backport overlay mount patch

https://github.com/rkt/rkt/issues/3805
This commit is contained in:
David Michael 2017-09-21 14:07:16 -07:00
parent dd43312b56
commit 0d87959d8c
3 changed files with 111 additions and 0 deletions

View File

@ -0,0 +1,109 @@
From a778cd1b33d191e83178879cd23732f1c106a0ef Mon Sep 17 00:00:00 2001
From: Luca Bruno <lucab@debian.org>
Date: Wed, 20 Sep 2017 10:10:37 +0000
Subject: [PATCH] stage0/gc: try to avoid double overlay mounts
Before Linux 4.13, it used to be possible to perform double overlayfs
mounts in place. This now fails at mount() with EBUSY.
We were abusing this feature to unconditionally ensure that the stage1
image overlay mount was present before calling gc entrypoint.
This improves stage0 logic to perform the stage1 image overlay mount
only if it doesn't already exist.
---
rkt/gc.go | 50 ++++++++++++++++++++++++++++++++++++--------------
1 file changed, 36 insertions(+), 14 deletions(-)
diff --git a/rkt/gc.go b/rkt/gc.go
index 5e025bb96..1ecdd8faf 100644
--- a/rkt/gc.go
+++ b/rkt/gc.go
@@ -26,6 +26,7 @@ import (
"github.com/hashicorp/errwrap"
"github.com/rkt/rkt/common"
+ "github.com/rkt/rkt/pkg/mountinfo"
pkgPod "github.com/rkt/rkt/pkg/pod"
"github.com/rkt/rkt/stage0"
"github.com/rkt/rkt/store/imagestore"
@@ -197,29 +198,51 @@ func emptyGarbage() error {
return nil
}
-func mountPodStage1(ts *treestore.Store, p *pkgPod.Pod) error {
+// mountPodStage1 tries to remount stage1 image overlay in case
+// it is not anymore available in place (e.g. a reboot happened
+// in-between). If an overlay mount is already there, we assume
+// stage1 image is properly in place and we don't perform any
+// further actions. A boolean is returned to signal whether a
+// a new mount was performed.
+func mountPodStage1(ts *treestore.Store, p *pkgPod.Pod) (bool, error) {
if !p.UsesOverlay() {
- return nil
+ return false, nil
}
s1Id, err := p.GetStage1TreeStoreID()
if err != nil {
- return errwrap.Wrap(errors.New("error getting stage1 treeStoreID"), err)
+ return false, errwrap.Wrap(errors.New("error getting stage1 treeStoreID"), err)
}
s1rootfs := ts.GetRootFS(s1Id)
-
stage1Dir := common.Stage1RootfsPath(p.Path())
+
+ if mounts, err := mountinfo.ParseMounts(0); err == nil {
+ for _, m := range mounts {
+ if m.MountPoint == stage1Dir {
+ // stage1 image overlay already in place
+ return false, nil
+ }
+ }
+ }
+
overlayDir := filepath.Join(p.Path(), "overlay")
imgDir := filepath.Join(overlayDir, s1Id)
upperDir := filepath.Join(imgDir, "upper")
workDir := filepath.Join(imgDir, "work")
opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", s1rootfs, upperDir, workDir)
- if err := syscall.Mount("overlay", stage1Dir, "overlay", 0, opts); err != nil {
- return errwrap.Wrap(errors.New("error mounting stage1"), err)
+ err = syscall.Mount("overlay", stage1Dir, "overlay", 0, opts)
+ if err != nil {
+ // -EBUSY means the overlay mount is already present.
+ // This behavior was introduced in Linux 4.13, double-mounts were allowed
+ // in older kernels.
+ if err == syscall.EBUSY {
+ stderr.Println("mount detected on stage1 target, skipping overlay mount")
+ return false, nil
+ }
+ return false, errwrap.Wrap(errors.New("error mounting stage1"), err)
}
-
- return nil
+ return true, nil
}
// deletePod cleans up files and resource associated with the pod
@@ -250,16 +273,15 @@ func deletePod(p *pkgPod.Pod) bool {
stage0.InitDebug()
}
- if err := mountPodStage1(ts, p); err == nil {
+ if newMount, err := mountPodStage1(ts, p); err == nil {
if err = stage0.GC(p.Path(), p.UUID, globalFlags.LocalConfigDir); err != nil {
stderr.PrintE(fmt.Sprintf("problem performing stage1 GC on %q", p.UUID), err)
}
- // an overlay fs can be mounted over itself, let's unmount it here
- // if we mounted it before to avoid problems when running
- // stage0.MountGC
- if p.UsesOverlay() {
+ // Linux <4.13 allows an overlay fs to be mounted over itself, so let's
+ // unmount it here to avoid problems when running stage0.MountGC
+ if p.UsesOverlay() && newMount {
stage1Mnt := common.Stage1RootfsPath(p.Path())
- if err := syscall.Unmount(stage1Mnt, 0); err != nil {
+ if err := syscall.Unmount(stage1Mnt, 0); err != nil && err != syscall.EBUSY {
stderr.PrintE("error unmounting stage1", err)
}
}

View File

@ -76,6 +76,8 @@ function add_stage1() {
} }
src_prepare() { src_prepare() {
epatch "${FILESDIR}/${PN}-1.28.1-avoid-double-overlay-mounts.patch"
# ensure we use a CoreOS PXE image version that matches rkt's expectations. # ensure we use a CoreOS PXE image version that matches rkt's expectations.
local rkt_coreos_version local rkt_coreos_version