From 0e21782de5c038dfa3cfdfc7655b9e6b143baa7b Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Tue, 17 Mar 2015 10:44:42 -0400 Subject: [PATCH] devmapper: storage-opt override for udev sync This provides an override for forcing the daemon to still attempt running the devicemapper driver even when udev sync is not supported. Intended to be a very clear impairment for those choosing to use it. If udev sync is false, there will still be an error in the daemon logs, even when the override is in place. The docs have an explicit WARNING. Including link to the docs for users that encounter this daemon error during an upgrade. Signed-off-by: Vincent Batts --- daemon/graphdriver/devmapper/README.md | 38 +++++++++++- daemon/graphdriver/devmapper/deviceset.go | 62 +++++++++++-------- .../graphdriver/devmapper/devmapper_test.go | 1 + docs/sources/reference/commandline/cli.md | 35 +++++++++++ 4 files changed, 109 insertions(+), 27 deletions(-) diff --git a/daemon/graphdriver/devmapper/README.md b/daemon/graphdriver/devmapper/README.md index 1dc918016d..a090b731fa 100644 --- a/daemon/graphdriver/devmapper/README.md +++ b/daemon/graphdriver/devmapper/README.md @@ -186,7 +186,7 @@ Here is the list of supported options: can be achieved by zeroing the first 4k to indicate empty metadata, like this: - ``dd if=/dev/zero of=$metadata_dev bs=4096 count=1``` + ``dd if=/dev/zero of=$metadata_dev bs=4096 count=1`` Example use: @@ -216,3 +216,39 @@ Here is the list of supported options: Example use: ``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. + diff --git a/daemon/graphdriver/devmapper/deviceset.go b/daemon/graphdriver/devmapper/deviceset.go index 7e0a13a952..4d6ce5a2ae 100644 --- a/daemon/graphdriver/devmapper/deviceset.go +++ b/daemon/graphdriver/devmapper/deviceset.go @@ -30,7 +30,8 @@ var ( DefaultDataLoopbackSize int64 = 100 * 1024 * 1024 * 1024 DefaultMetaDataLoopbackSize int64 = 2 * 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 DeviceIdMapSz int = (MaxDeviceId + 1) / 8 ) @@ -83,20 +84,21 @@ type DeviceSet struct { deviceIdMap []byte // Options - dataLoopbackSize int64 - metaDataLoopbackSize int64 - baseFsSize uint64 - filesystem string - mountOptions string - mkfsArgs []string - dataDevice string // block or loop dev - dataLoopFile string // loopback file, if used - metadataDevice string // block or loop dev - metadataLoopFile string // loopback file, if used - doBlkDiscard bool - thinpBlockSize uint32 - thinPoolDevice string - Transaction `json:"-"` + dataLoopbackSize int64 + metaDataLoopbackSize int64 + baseFsSize uint64 + filesystem string + mountOptions string + mkfsArgs []string + dataDevice string // block or loop dev + dataLoopFile string // loopback file, if used + metadataDevice string // block or loop dev + metadataLoopFile string // loopback file, if used + doBlkDiscard bool + thinpBlockSize uint32 + thinPoolDevice string + Transaction `json:"-"` + overrideUdevSyncCheck bool } type DiskUsage struct { @@ -963,8 +965,10 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error { // https://github.com/docker/docker/issues/4036 if supported := devicemapper.UdevSetSyncSupport(true); !supported { - logrus.Errorf("Udev sync is not supported. This will lead to unexpected behavior, data loss and errors") - return graphdriver.ErrNotSupported + 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) { @@ -1656,15 +1660,16 @@ func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error devicemapper.SetDevDir("/dev") devices := &DeviceSet{ - root: root, - MetaData: MetaData{Devices: make(map[string]*DevInfo)}, - dataLoopbackSize: DefaultDataLoopbackSize, - metaDataLoopbackSize: DefaultMetaDataLoopbackSize, - baseFsSize: DefaultBaseFsSize, - filesystem: "ext4", - doBlkDiscard: true, - thinpBlockSize: DefaultThinpBlockSize, - deviceIdMap: make([]byte, DeviceIdMapSz), + root: root, + MetaData: MetaData{Devices: make(map[string]*DevInfo)}, + dataLoopbackSize: DefaultDataLoopbackSize, + metaDataLoopbackSize: DefaultMetaDataLoopbackSize, + baseFsSize: DefaultBaseFsSize, + overrideUdevSyncCheck: DefaultUdevSyncOverride, + filesystem: "ext4", + doBlkDiscard: true, + thinpBlockSize: DefaultThinpBlockSize, + deviceIdMap: make([]byte, DeviceIdMapSz), } foundBlkDiscard := false @@ -1721,6 +1726,11 @@ func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error } // convert to 512b sectors devices.thinpBlockSize = uint32(size) >> 9 + case "dm.override_udev_sync_check": + devices.overrideUdevSyncCheck, err = strconv.ParseBool(val) + if err != nil { + return nil, err + } default: return nil, fmt.Errorf("Unknown option %s\n", key) } diff --git a/daemon/graphdriver/devmapper/devmapper_test.go b/daemon/graphdriver/devmapper/devmapper_test.go index 6cb7572384..60006af5a5 100644 --- a/daemon/graphdriver/devmapper/devmapper_test.go +++ b/daemon/graphdriver/devmapper/devmapper_test.go @@ -13,6 +13,7 @@ func init() { DefaultDataLoopbackSize = 300 * 1024 * 1024 DefaultMetaDataLoopbackSize = 200 * 1024 * 1024 DefaultBaseFsSize = 300 * 1024 * 1024 + DefaultUdevSyncOverride = true if err := graphtest.InitLoopbacks(); err != nil { panic(err) } diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 2d59a64bb1..b71360a9fa 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -370,6 +370,41 @@ Currently supported options are: $ 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 exec-driver option The Docker daemon uses a specifically built `libcontainer` execution driver as its