Revert "Fix implicit DeviceMapper selection"

This reverts commit 0a376291b2.

Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
David Calavera 2015-07-07 12:27:19 -07:00
parent a14b1f1e9d
commit 9af7afb9eb
5 changed files with 164 additions and 77 deletions

View file

@ -31,6 +31,7 @@ var (
DefaultMetaDataLoopbackSize int64 = 2 * 1024 * 1024 * 1024 DefaultMetaDataLoopbackSize int64 = 2 * 1024 * 1024 * 1024
DefaultBaseFsSize uint64 = 10 * 1024 * 1024 * 1024 DefaultBaseFsSize uint64 = 10 * 1024 * 1024 * 1024
DefaultThinpBlockSize uint32 = 128 // 64K = 128 512b sectors DefaultThinpBlockSize uint32 = 128 // 64K = 128 512b sectors
DefaultUdevSyncOverride bool = false
MaxDeviceId int = 0xffffff // 24 bit, pool limit MaxDeviceId int = 0xffffff // 24 bit, pool limit
DeviceIdMapSz int = (MaxDeviceId + 1) / 8 DeviceIdMapSz int = (MaxDeviceId + 1) / 8
// We retry device removal so many a times that even error messages // We retry device removal so many a times that even error messages
@ -103,6 +104,7 @@ type DeviceSet struct {
thinpBlockSize uint32 thinpBlockSize uint32
thinPoolDevice string thinPoolDevice string
Transaction `json:"-"` Transaction `json:"-"`
overrideUdevSyncCheck bool
deferredRemove bool // use deferred removal deferredRemove bool // use deferred removal
BaseDeviceUUID string //save UUID of base device BaseDeviceUUID string //save UUID of base device
} }
@ -1104,7 +1106,10 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
// https://github.com/docker/docker/issues/4036 // https://github.com/docker/docker/issues/4036
if supported := devicemapper.UdevSetSyncSupport(true); !supported { if supported := devicemapper.UdevSetSyncSupport(true); !supported {
logrus.Warn("Udev sync is not supported. This will lead to unexpected behavior, data loss and errors. For more information, see https://docs.docker.com/reference/commandline/cli/#daemon-storage-driver-option") logrus.Errorf("Udev sync is not supported. This will lead to unexpected behavior, data loss and errors. For more information, see https://docs.docker.com/reference/commandline/cli/#daemon-storage-driver-option")
if !devices.overrideUdevSyncCheck {
return graphdriver.ErrNotSupported
}
} }
if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil && !os.IsExist(err) { if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil && !os.IsExist(err) {
@ -1791,6 +1796,7 @@ func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error
dataLoopbackSize: DefaultDataLoopbackSize, dataLoopbackSize: DefaultDataLoopbackSize,
metaDataLoopbackSize: DefaultMetaDataLoopbackSize, metaDataLoopbackSize: DefaultMetaDataLoopbackSize,
baseFsSize: DefaultBaseFsSize, baseFsSize: DefaultBaseFsSize,
overrideUdevSyncCheck: DefaultUdevSyncOverride,
filesystem: "ext4", filesystem: "ext4",
doBlkDiscard: true, doBlkDiscard: true,
thinpBlockSize: DefaultThinpBlockSize, thinpBlockSize: DefaultThinpBlockSize,
@ -1851,6 +1857,12 @@ func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error
} }
// convert to 512b sectors // convert to 512b sectors
devices.thinpBlockSize = uint32(size) >> 9 devices.thinpBlockSize = uint32(size) >> 9
case "dm.override_udev_sync_check":
devices.overrideUdevSyncCheck, err = strconv.ParseBool(val)
if err != nil {
return nil, err
}
case "dm.use_deferred_removal": case "dm.use_deferred_removal":
EnableDeferredRemoval, err = strconv.ParseBool(val) EnableDeferredRemoval, err = strconv.ParseBool(val)
if err != nil { if err != nil {

View file

@ -13,6 +13,7 @@ func init() {
DefaultDataLoopbackSize = 300 * 1024 * 1024 DefaultDataLoopbackSize = 300 * 1024 * 1024
DefaultMetaDataLoopbackSize = 200 * 1024 * 1024 DefaultMetaDataLoopbackSize = 200 * 1024 * 1024
DefaultBaseFsSize = 300 * 1024 * 1024 DefaultBaseFsSize = 300 * 1024 * 1024
DefaultUdevSyncOverride = true
if err := graphtest.InitLoopbacks(); err != nil { if err := graphtest.InitLoopbacks(); err != nil {
panic(err) panic(err)
} }

View file

@ -8,7 +8,6 @@ import (
"strings" "strings"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
) )
@ -26,7 +25,6 @@ var (
ErrNotSupported = errors.New("driver not supported") ErrNotSupported = errors.New("driver not supported")
ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)") ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)")
ErrIncompatibleFS = fmt.Errorf("backing file system is unsupported for this graph driver") ErrIncompatibleFS = fmt.Errorf("backing file system is unsupported for this graph driver")
ErrDeviceMapperWithStaticDocker = fmt.Errorf("devicemapper storage driver cannot reliably be used with a statically linked docker binary: please either pick a different storage driver, install a dynamically linked docker binary, or force this unreliable setup anyway by specifying --storage-driver=devicemapper")
) )
type InitFunc func(root string, options []string) (Driver, error) type InitFunc func(root string, options []string) (Driver, error)
@ -115,35 +113,36 @@ func New(root string, options []string) (driver Driver, err error) {
} }
// Guess for prior driver // Guess for prior driver
priorDriver, err := scanPriorDrivers(root) priorDrivers := scanPriorDrivers(root)
if err != nil { for _, name := range priority {
return nil, err if name == "vfs" {
// don't use vfs even if there is state present.
continue
} }
for _, prior := range priorDrivers {
if len(priorDriver) != 0 { // of the state found from prior drivers, check in order of our priority
// Do not allow devicemapper when it's not explicit and the Docker binary was built statically. // which we would prefer
if staticWithDeviceMapper(priorDriver) { if prior == name {
return nil, ErrDeviceMapperWithStaticDocker driver, err = GetDriver(name, root, options)
}
driver, err = GetDriver(priorDriver, root, options)
if err != nil { if err != nil {
// unlike below, we will return error here, because there is prior // unlike below, we will return error here, because there is prior
// state, and now it is no longer supported/prereq/compatible, so // state, and now it is no longer supported/prereq/compatible, so
// something changed and needs attention. Otherwise the daemon's // something changed and needs attention. Otherwise the daemon's
// images would just "disappear". // images would just "disappear".
logrus.Errorf("[graphdriver] prior storage driver %q failed: %s", priorDriver, err) logrus.Errorf("[graphdriver] prior storage driver %q failed: %s", name, err)
return nil, err return nil, err
} }
logrus.Infof("[graphdriver] using prior storage driver %q", priorDriver) if err := checkPriorDriver(name, root); err != nil {
return nil, err
}
logrus.Infof("[graphdriver] using prior storage driver %q", name)
return driver, nil return driver, nil
} }
}
}
// Check for priority drivers first // Check for priority drivers first
for _, name := range priority { for _, name := range priority {
if staticWithDeviceMapper(name) {
continue
}
driver, err = GetDriver(name, root, options) driver, err = GetDriver(name, root, options)
if err != nil { if err != nil {
if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS {
@ -155,10 +154,7 @@ func New(root string, options []string) (driver Driver, err error) {
} }
// Check all registered drivers if no priority driver is found // Check all registered drivers if no priority driver is found
for name, initFunc := range drivers { for _, initFunc := range drivers {
if staticWithDeviceMapper(name) {
continue
}
if driver, err = initFunc(root, options); err != nil { if driver, err = initFunc(root, options); err != nil {
if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS {
continue continue
@ -170,31 +166,31 @@ func New(root string, options []string) (driver Driver, err error) {
return nil, fmt.Errorf("No supported storage backend found") return nil, fmt.Errorf("No supported storage backend found")
} }
// scanPriorDrivers returns a previosly used driver. // scanPriorDrivers returns an un-ordered scan of directories of prior storage drivers
// it returns an error when there are several drivers scanned. func scanPriorDrivers(root string) []string {
func scanPriorDrivers(root string) (string, error) { priorDrivers := []string{}
var priorDrivers []string
for driver := range drivers { for driver := range drivers {
p := filepath.Join(root, driver) p := filepath.Join(root, driver)
if _, err := os.Stat(p); err == nil && driver != "vfs" { if _, err := os.Stat(p); err == nil {
priorDrivers = append(priorDrivers, driver) priorDrivers = append(priorDrivers, driver)
} }
} }
return priorDrivers
}
if len(priorDrivers) > 1 { func checkPriorDriver(name, root string) error {
return "", multipleDriversError(root, priorDrivers) priorDrivers := []string{}
for _, prior := range scanPriorDrivers(root) {
if prior != name && prior != "vfs" {
if _, err := os.Stat(filepath.Join(root, prior)); err == nil {
priorDrivers = append(priorDrivers, prior)
}
}
} }
if len(priorDrivers) == 0 { if len(priorDrivers) > 0 {
return "", nil
return errors.New(fmt.Sprintf("%q contains other graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s <DRIVER>)", root, strings.Join(priorDrivers, ",")))
} }
return priorDrivers[0], nil return nil
}
func multipleDriversError(root string, drivers []string) error {
return fmt.Errorf("%q contains several graphdrivers: %s; Please cleanup or explicitly choose storage driver (--storage-driver <DRIVER>)", root, strings.Join(drivers, ", "))
}
func staticWithDeviceMapper(name string) bool {
return name == "devicemapper" && dockerversion.IAMSTATIC == "true"
} }

View file

@ -323,6 +323,45 @@ options for `zfs` start with `zfs`.
$ docker -d --storage-opt dm.blkdiscard=false $ docker -d --storage-opt dm.blkdiscard=false
* `dm.override_udev_sync_check`
Overrides the `udev` synchronization checks between `devicemapper` and `udev`.
`udev` is the device manager for the Linux kernel.
To view the `udev` sync support of a Docker daemon that is using the
`devicemapper` driver, run:
$ docker info
[...]
Udev Sync Supported: true
[...]
When `udev` sync support is `true`, then `devicemapper` and udev can
coordinate the activation and deactivation of devices for containers.
When `udev` sync support is `false`, a race condition occurs between
the`devicemapper` and `udev` during create and cleanup. The race condition
results in errors and failures. (For information on these failures, see
[docker#4036](https://github.com/docker/docker/issues/4036))
To allow the `docker` daemon to start, regardless of `udev` sync not being
supported, set `dm.override_udev_sync_check` to true:
$ docker -d --storage-opt dm.override_udev_sync_check=true
When this value is `true`, the `devicemapper` continues and simply warns
you the errors are happening.
> **Note:**
> The ideal is to pursue a `docker` daemon and environment that does
> support synchronizing with `udev`. For further discussion on this
> topic, see [docker#4036](https://github.com/docker/docker/issues/4036).
> Otherwise, set this flag for migrating existing Docker daemons to
> a daemon with a supported environment.
## Docker execdriver option
Currently supported options of `zfs`: Currently supported options of `zfs`:
* `zfs.fsname` * `zfs.fsname`

View file

@ -451,6 +451,45 @@ removed.
Example use: `docker -d --storage-opt dm.blkdiscard=false` Example use: `docker -d --storage-opt dm.blkdiscard=false`
#### dm.override_udev_sync_check
By default, the devicemapper backend attempts to synchronize with the
`udev` device manager for the Linux kernel. This option allows
disabling that synchronization, to continue even though the
configuration may be buggy.
To view the `udev` sync support of a Docker daemon that is using the
`devicemapper` driver, run:
$ docker info
[...]
Udev Sync Supported: true
[...]
When `udev` sync support is `true`, then `devicemapper` and `udev` can
coordinate the activation and deactivation of devices for containers.
When `udev` sync support is `false`, a race condition occurs between
the`devicemapper` and `udev` during create and cleanup. The race
condition results in errors and failures. (For information on these
failures, see
[docker#4036](https://github.com/docker/docker/issues/4036))
To allow the `docker` daemon to start, regardless of whether `udev` sync is
`false`, set `dm.override_udev_sync_check` to true:
$ docker -d --storage-opt dm.override_udev_sync_check=true
When this value is `true`, the driver continues and simply warns you
the errors are happening.
**Note**: The ideal is to pursue a `docker` daemon and environment
that does support synchronizing with `udev`. For further discussion on
this topic, see
[docker#4036](https://github.com/docker/docker/issues/4036).
Otherwise, set this flag for migrating existing Docker daemons to a
daemon with a supported environment.
# EXEC DRIVER OPTIONS # EXEC DRIVER OPTIONS
Use the **--exec-opt** flags to specify options to the exec-driver. The only Use the **--exec-opt** flags to specify options to the exec-driver. The only