Ver Fonte

btrfs: ensure graphdriver home is bind mount

For some reason, shared mount propagation between the host
and a container does not work for btrfs, unless container
root directory (i.e. graphdriver home) is a bind mount.

The above issue was reproduced on SLES 12sp3 + btrfs using
the following script:

	#!/bin/bash
	set -eux -o pipefail

	# DIR should not be under a subvolume
	DIR=${DIR:-/lib}
	MNT=$DIR/my-mnt
	FILE=$MNT/file

	ID=$(docker run -d --privileged -v $DIR:$DIR:rshared ubuntu sleep 24h)
	docker exec $ID mkdir -p $MNT
	docker exec $ID mount -t tmpfs tmpfs $MNT
	docker exec $ID touch $FILE
	ls -l $FILE
	umount $MNT
	docker rm -f $ID

which fails this way:

	+ ls -l /lib/my-mnt/file
	ls: cannot access '/lib/my-mnt/file': No such file or directory

meaning the mount performed inside a priviledged container is not
propagated back to the host (even if all the mounts have "shared"
propagation mode).

The remedy to the above is to make graphdriver home a bind mount.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Kir Kolyshkin há 6 anos atrás
pai
commit
16d822bba8
1 ficheiros alterados com 24 adições e 1 exclusões
  1. 24 1
      daemon/graphdriver/btrfs/btrfs.go

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

@@ -29,10 +29,12 @@ import (
 	"github.com/docker/docker/daemon/graphdriver"
 	"github.com/docker/docker/pkg/containerfs"
 	"github.com/docker/docker/pkg/idtools"
+	"github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/go-units"
 	"github.com/opencontainers/selinux/go-selinux/label"
+	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/sys/unix"
 )
@@ -81,6 +83,15 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
 		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{
 		home:    home,
 		uidMaps: uidMaps,
@@ -158,7 +169,19 @@ func (d *Driver) GetMetadata(id string) (map[string]string, error) {
 
 // Cleanup unmounts the home directory.
 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) {