Browse Source

Merge pull request #38026 from kolyshkin/btrfs-propagation

Fix mount propagation for btrfs
Yong Tang 6 years ago
parent
commit
70204b8721
2 changed files with 36 additions and 9 deletions
  1. 24 1
      daemon/graphdriver/btrfs/btrfs.go
  2. 12 8
      pkg/mount/sharedsubtree_linux.go

+ 24 - 1
daemon/graphdriver/btrfs/btrfs.go

@@ -29,10 +29,12 @@ import (
 	"github.com/docker/docker/daemon/graphdriver"
 	"github.com/docker/docker/daemon/graphdriver"
 	"github.com/docker/docker/pkg/containerfs"
 	"github.com/docker/docker/pkg/containerfs"
 	"github.com/docker/docker/pkg/idtools"
 	"github.com/docker/docker/pkg/idtools"
+	"github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/go-units"
 	"github.com/docker/go-units"
 	"github.com/opencontainers/selinux/go-selinux/label"
 	"github.com/opencontainers/selinux/go-selinux/label"
+	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/sys/unix"
 	"golang.org/x/sys/unix"
 )
 )
@@ -81,6 +83,15 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
 		return nil, err
 		return nil, err
 	}
 	}
 
 
+	// For some reason shared mount propagation between a container
+	// and the host does not work for btrfs, and a remedy is to bind
+	// mount graphdriver home to itself (even without changing the
+	// propagation mode).
+	err = mount.MakeMount(home)
+	if err != nil {
+		return nil, errors.Wrapf(err, "failed to make %s a mount", home)
+	}
+
 	driver := &Driver{
 	driver := &Driver{
 		home:    home,
 		home:    home,
 		uidMaps: uidMaps,
 		uidMaps: uidMaps,
@@ -158,7 +169,19 @@ func (d *Driver) GetMetadata(id string) (map[string]string, error) {
 
 
 // Cleanup unmounts the home directory.
 // Cleanup unmounts the home directory.
 func (d *Driver) Cleanup() error {
 func (d *Driver) Cleanup() error {
-	return d.subvolDisableQuota()
+	err := d.subvolDisableQuota()
+	umountErr := mount.Unmount(d.home)
+
+	// in case we have two errors, prefer the one from disableQuota()
+	if err != nil {
+		return err
+	}
+
+	if umountErr != nil {
+		return errors.Wrapf(umountErr, "error unmounting %s", d.home)
+	}
+
+	return nil
 }
 }
 
 
 func free(p *C.char) {
 func free(p *C.char) {

+ 12 - 8
pkg/mount/sharedsubtree_linux.go

@@ -48,18 +48,22 @@ func MakeRUnbindable(mountPoint string) error {
 	return ensureMountedAs(mountPoint, "runbindable")
 	return ensureMountedAs(mountPoint, "runbindable")
 }
 }
 
 
-func ensureMountedAs(mountPoint, options string) error {
-	mounted, err := Mounted(mountPoint)
+// MakeMount ensures that the file or directory given is a mount point,
+// bind mounting it to itself it case it is not.
+func MakeMount(mnt string) error {
+	mounted, err := Mounted(mnt)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-
-	if !mounted {
-		if err := Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil {
-			return err
-		}
+	if mounted {
+		return nil
 	}
 	}
-	if _, err = Mounted(mountPoint); err != nil {
+
+	return Mount(mnt, mnt, "none", "bind")
+}
+
+func ensureMountedAs(mountPoint, options string) error {
+	if err := MakeMount(mountPoint); err != nil {
 		return err
 		return err
 	}
 	}