diff --git a/daemon/graphdriver/btrfs/btrfs.go b/daemon/graphdriver/btrfs/btrfs.go index 4c14191d46..7ce7edef36 100644 --- a/daemon/graphdriver/btrfs/btrfs.go +++ b/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) { diff --git a/pkg/mount/sharedsubtree_linux.go b/pkg/mount/sharedsubtree_linux.go index 538f6637a0..8a100f0bc8 100644 --- a/pkg/mount/sharedsubtree_linux.go +++ b/pkg/mount/sharedsubtree_linux.go @@ -48,18 +48,22 @@ func MakeRUnbindable(mountPoint string) error { 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 { 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 }