Browse code

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 <vbatts@redhat.com>

Vincent Batts authored on 2015/03/17 23:44:42
Showing 4 changed files
... ...
@@ -186,7 +186,7 @@ Here is the list of supported options:
186 186
     can be achieved by zeroing the first 4k to indicate empty
187 187
     metadata, like this:
188 188
 
189
-    ``dd if=/dev/zero of=$metadata_dev bs=4096 count=1```
189
+    ``dd if=/dev/zero of=$metadata_dev bs=4096 count=1``
190 190
 
191 191
     Example use:
192 192
 
... ...
@@ -216,3 +216,39 @@ Here is the list of supported options:
216 216
     Example use:
217 217
 
218 218
     ``docker -d --storage-opt dm.blkdiscard=false``
219
+
220
+ *  `dm.override_udev_sync_check`
221
+
222
+    Overrides the `udev` synchronization checks between `devicemapper` and `udev`.
223
+    `udev` is the device manager for the Linux kernel.
224
+
225
+    To view the `udev` sync support of a Docker daemon that is using the
226
+    `devicemapper` driver, run:
227
+
228
+        $ docker info
229
+	[...]
230
+	 Udev Sync Supported: true
231
+	[...]
232
+
233
+    When `udev` sync support is `true`, then `devicemapper` and udev can
234
+    coordinate the activation and deactivation of devices for containers.
235
+
236
+    When `udev` sync support is `false`, a race condition occurs between
237
+    the`devicemapper` and `udev` during create and cleanup. The race condition
238
+    results in errors and failures. (For information on these failures, see
239
+    [docker#4036](https://github.com/docker/docker/issues/4036))
240
+
241
+    To allow the `docker` daemon to start, regardless of `udev` sync not being
242
+    supported, set `dm.override_udev_sync_check` to true:
243
+
244
+        $ docker -d --storage-opt dm.override_udev_sync_check=true
245
+
246
+    When this value is `true`, the  `devicemapper` continues and simply warns
247
+    you the errors are happening.
248
+
249
+    > **Note**: The ideal is to pursue a `docker` daemon and environment that
250
+    > does support synchronizing with `udev`. For further discussion on this
251
+    > topic, see [docker#4036](https://github.com/docker/docker/issues/4036).
252
+    > Otherwise, set this flag for migrating existing Docker daemons to a
253
+    > daemon with a supported environment.
254
+
... ...
@@ -30,7 +30,8 @@ var (
30 30
 	DefaultDataLoopbackSize     int64  = 100 * 1024 * 1024 * 1024
31 31
 	DefaultMetaDataLoopbackSize int64  = 2 * 1024 * 1024 * 1024
32 32
 	DefaultBaseFsSize           uint64 = 10 * 1024 * 1024 * 1024
33
-	DefaultThinpBlockSize       uint32 = 128      // 64K = 128 512b sectors
33
+	DefaultThinpBlockSize       uint32 = 128 // 64K = 128 512b sectors
34
+	DefaultUdevSyncOverride     bool   = false
34 35
 	MaxDeviceId                 int    = 0xffffff // 24 bit, pool limit
35 36
 	DeviceIdMapSz               int    = (MaxDeviceId + 1) / 8
36 37
 )
... ...
@@ -83,20 +84,21 @@ type DeviceSet struct {
83 83
 	deviceIdMap   []byte
84 84
 
85 85
 	// Options
86
-	dataLoopbackSize     int64
87
-	metaDataLoopbackSize int64
88
-	baseFsSize           uint64
89
-	filesystem           string
90
-	mountOptions         string
91
-	mkfsArgs             []string
92
-	dataDevice           string // block or loop dev
93
-	dataLoopFile         string // loopback file, if used
94
-	metadataDevice       string // block or loop dev
95
-	metadataLoopFile     string // loopback file, if used
96
-	doBlkDiscard         bool
97
-	thinpBlockSize       uint32
98
-	thinPoolDevice       string
99
-	Transaction          `json:"-"`
86
+	dataLoopbackSize      int64
87
+	metaDataLoopbackSize  int64
88
+	baseFsSize            uint64
89
+	filesystem            string
90
+	mountOptions          string
91
+	mkfsArgs              []string
92
+	dataDevice            string // block or loop dev
93
+	dataLoopFile          string // loopback file, if used
94
+	metadataDevice        string // block or loop dev
95
+	metadataLoopFile      string // loopback file, if used
96
+	doBlkDiscard          bool
97
+	thinpBlockSize        uint32
98
+	thinPoolDevice        string
99
+	Transaction           `json:"-"`
100
+	overrideUdevSyncCheck bool
100 101
 }
101 102
 
102 103
 type DiskUsage struct {
... ...
@@ -963,8 +965,10 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
963 963
 
964 964
 	// https://github.com/docker/docker/issues/4036
965 965
 	if supported := devicemapper.UdevSetSyncSupport(true); !supported {
966
-		logrus.Errorf("Udev sync is not supported. This will lead to unexpected behavior, data loss and errors")
967
-		return graphdriver.ErrNotSupported
966
+		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")
967
+		if !devices.overrideUdevSyncCheck {
968
+			return graphdriver.ErrNotSupported
969
+		}
968 970
 	}
969 971
 
970 972
 	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
1656 1656
 	devicemapper.SetDevDir("/dev")
1657 1657
 
1658 1658
 	devices := &DeviceSet{
1659
-		root:                 root,
1660
-		MetaData:             MetaData{Devices: make(map[string]*DevInfo)},
1661
-		dataLoopbackSize:     DefaultDataLoopbackSize,
1662
-		metaDataLoopbackSize: DefaultMetaDataLoopbackSize,
1663
-		baseFsSize:           DefaultBaseFsSize,
1664
-		filesystem:           "ext4",
1665
-		doBlkDiscard:         true,
1666
-		thinpBlockSize:       DefaultThinpBlockSize,
1667
-		deviceIdMap:          make([]byte, DeviceIdMapSz),
1659
+		root:                  root,
1660
+		MetaData:              MetaData{Devices: make(map[string]*DevInfo)},
1661
+		dataLoopbackSize:      DefaultDataLoopbackSize,
1662
+		metaDataLoopbackSize:  DefaultMetaDataLoopbackSize,
1663
+		baseFsSize:            DefaultBaseFsSize,
1664
+		overrideUdevSyncCheck: DefaultUdevSyncOverride,
1665
+		filesystem:            "ext4",
1666
+		doBlkDiscard:          true,
1667
+		thinpBlockSize:        DefaultThinpBlockSize,
1668
+		deviceIdMap:           make([]byte, DeviceIdMapSz),
1668 1669
 	}
1669 1670
 
1670 1671
 	foundBlkDiscard := false
... ...
@@ -1721,6 +1726,11 @@ func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error
1721 1721
 			}
1722 1722
 			// convert to 512b sectors
1723 1723
 			devices.thinpBlockSize = uint32(size) >> 9
1724
+		case "dm.override_udev_sync_check":
1725
+			devices.overrideUdevSyncCheck, err = strconv.ParseBool(val)
1726
+			if err != nil {
1727
+				return nil, err
1728
+			}
1724 1729
 		default:
1725 1730
 			return nil, fmt.Errorf("Unknown option %s\n", key)
1726 1731
 		}
... ...
@@ -13,6 +13,7 @@ func init() {
13 13
 	DefaultDataLoopbackSize = 300 * 1024 * 1024
14 14
 	DefaultMetaDataLoopbackSize = 200 * 1024 * 1024
15 15
 	DefaultBaseFsSize = 300 * 1024 * 1024
16
+	DefaultUdevSyncOverride = true
16 17
 	if err := graphtest.InitLoopbacks(); err != nil {
17 18
 		panic(err)
18 19
 	}
... ...
@@ -370,6 +370,41 @@ Currently supported options are:
370 370
 
371 371
         $ docker -d --storage-opt dm.blkdiscard=false
372 372
 
373
+ *  `dm.override_udev_sync_check`
374
+
375
+    Overrides the `udev` synchronization checks between `devicemapper` and `udev`.
376
+    `udev` is the device manager for the Linux kernel.
377
+
378
+    To view the `udev` sync support of a Docker daemon that is using the
379
+    `devicemapper` driver, run:
380
+
381
+        $ docker info
382
+	[...]
383
+	 Udev Sync Supported: true
384
+	[...]
385
+
386
+    When `udev` sync support is `true`, then `devicemapper` and udev can
387
+    coordinate the activation and deactivation of devices for containers.
388
+
389
+    When `udev` sync support is `false`, a race condition occurs between
390
+    the`devicemapper` and `udev` during create and cleanup. The race condition
391
+    results in errors and failures. (For information on these failures, see
392
+    [docker#4036](https://github.com/docker/docker/issues/4036))
393
+
394
+    To allow the `docker` daemon to start, regardless of `udev` sync not being
395
+    supported, set `dm.override_udev_sync_check` to true:
396
+
397
+        $ docker -d --storage-opt dm.override_udev_sync_check=true
398
+
399
+    When this value is `true`, the  `devicemapper` continues and simply warns
400
+    you the errors are happening.
401
+
402
+    > **Note**: The ideal is to pursue a `docker` daemon and environment that
403
+    > does support synchronizing with `udev`. For further discussion on this
404
+    > topic, see [docker#4036](https://github.com/docker/docker/issues/4036).
405
+    > Otherwise, set this flag for migrating existing Docker daemons to a
406
+    > daemon with a supported environment.
407
+
373 408
 ### Docker exec-driver option
374 409
 
375 410
 The Docker daemon uses a specifically built `libcontainer` execution driver as its